Blame view

drivers/video/s3c-fb.c 50.3 KB
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1
2
3
  /* linux/drivers/video/s3c-fb.c
   *
   * Copyright 2008 Openmoko Inc.
50a5503a9   Ben Dooks   s3c-fb: initial m...
4
   * Copyright 2008-2010 Simtec Electronics
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
5
6
7
8
9
10
11
   *      Ben Dooks <ben@simtec.co.uk>
   *      http://armlinux.simtec.co.uk/
   *
   * Samsung SoC Framebuffer driver
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
12
   * published by the Free Software FoundatIon.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
13
14
15
16
17
18
  */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/dma-mapping.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
20
  #include <linux/init.h>
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
21
22
23
  #include <linux/clk.h>
  #include <linux/fb.h>
  #include <linux/io.h>
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
24
25
  #include <linux/uaccess.h>
  #include <linux/interrupt.h>
4959212c1   Jingoo Han   s3c-fb: add suppo...
26
  #include <linux/pm_runtime.h>
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
27
28
  
  #include <mach/map.h>
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
29
  #include <plat/regs-fb-v4.h>
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
30
31
32
33
34
35
36
37
38
39
40
  #include <plat/fb.h>
  
  /* This driver will export a number of framebuffer interfaces depending
   * on the configuration passed in via the platform data. Each fb instance
   * maps to a hardware window. Currently there is no support for runtime
   * setting of the alpha-blending functions that each window has, so only
   * window 0 is actually useful.
   *
   * Window 0 is treated specially, it is used for the basis of the LCD
   * output timings and as the control for the output power-down state.
  */
50a5503a9   Ben Dooks   s3c-fb: initial m...
41
42
43
  /* note, the previous use of <mach/regs-fb.h> to get platform specific data
   * has been replaced by using the platform device name to pick the correct
   * configuration data for the system.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
44
45
46
47
48
49
50
  */
  
  #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
  #undef writel
  #define writel(v, r) do { \
  	printk(KERN_DEBUG "%s: %08x => %p
  ", __func__, (unsigned int)v, r); \
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
51
  	__raw_writel(v, r); } while (0)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
52
  #endif /* FB_S3C_DEBUG_REGWRITE */
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
53
54
55
56
  /* irq_flags bits */
  #define S3C_FB_VSYNC_IRQ_EN	0
  
  #define VSYNC_TIMEOUT_MSEC 50
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
57
  struct s3c_fb;
50a5503a9   Ben Dooks   s3c-fb: initial m...
58
  #define VALID_BPP(x) (1 << ((x) - 1))
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
59
60
61
62
63
  #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
  #define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
  #define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
  #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
  #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
50a5503a9   Ben Dooks   s3c-fb: initial m...
64
65
  /**
   * struct s3c_fb_variant - fb variant information
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
66
   * @is_2443: Set if S3C2443/S3C2416 style hardware.
50a5503a9   Ben Dooks   s3c-fb: initial m...
67
   * @nr_windows: The number of windows.
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
68
69
70
71
72
73
74
75
   * @vidtcon: The base for the VIDTCONx registers
   * @wincon: The base for the WINxCON registers.
   * @winmap: The base for the WINxMAP registers.
   * @keycon: The abse for the WxKEYCON registers.
   * @buf_start: Offset of buffer start registers.
   * @buf_size: Offset of buffer size registers.
   * @buf_end: Offset of buffer end registers.
   * @osd: The base for the OSD registers.
50a5503a9   Ben Dooks   s3c-fb: initial m...
76
   * @palette: Address of palette memory, or 0 if none.
067b226b9   Pawel Osciak   s3c-fb: add suppo...
77
   * @has_prtcon: Set if has PRTCON register.
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
78
   * @has_shadowcon: Set if has SHADOWCON register.
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
79
   * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
50a5503a9   Ben Dooks   s3c-fb: initial m...
80
81
   */
  struct s3c_fb_variant {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
82
  	unsigned int	is_2443:1;
50a5503a9   Ben Dooks   s3c-fb: initial m...
83
  	unsigned short	nr_windows;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
84
85
86
87
88
89
90
91
92
  	unsigned short	vidtcon;
  	unsigned short	wincon;
  	unsigned short	winmap;
  	unsigned short	keycon;
  	unsigned short	buf_start;
  	unsigned short	buf_end;
  	unsigned short	buf_size;
  	unsigned short	osd;
  	unsigned short	osd_stride;
50a5503a9   Ben Dooks   s3c-fb: initial m...
93
  	unsigned short	palette[S3C_FB_MAX_WIN];
067b226b9   Pawel Osciak   s3c-fb: add suppo...
94
95
  
  	unsigned int	has_prtcon:1;
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
96
  	unsigned int	has_shadowcon:1;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
97
  	unsigned int	has_clksel:1;
50a5503a9   Ben Dooks   s3c-fb: initial m...
98
99
100
101
102
103
  };
  
  /**
   * struct s3c_fb_win_variant
   * @has_osd_c: Set if has OSD C register.
   * @has_osd_d: Set if has OSD D register.
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
104
   * @has_osd_alpha: Set if can change alpha transparency for a window.
50a5503a9   Ben Dooks   s3c-fb: initial m...
105
106
   * @palette_sz: Size of palette in entries.
   * @palette_16bpp: Set if palette is 16bits wide.
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
107
108
   * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
   *                register is located at the given offset from OSD_BASE.
50a5503a9   Ben Dooks   s3c-fb: initial m...
109
110
111
112
113
114
115
   * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
   *
   * valid_bpp bit x is set if (x+1)BPP is supported.
   */
  struct s3c_fb_win_variant {
  	unsigned int	has_osd_c:1;
  	unsigned int	has_osd_d:1;
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
116
  	unsigned int	has_osd_alpha:1;
50a5503a9   Ben Dooks   s3c-fb: initial m...
117
  	unsigned int	palette_16bpp:1;
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
118
  	unsigned short	osd_size_off;
50a5503a9   Ben Dooks   s3c-fb: initial m...
119
120
121
122
123
124
125
126
127
128
129
130
131
  	unsigned short	palette_sz;
  	u32		valid_bpp;
  };
  
  /**
   * struct s3c_fb_driverdata - per-device type driver data for init time.
   * @variant: The variant information for this driver.
   * @win: The window information for each window.
   */
  struct s3c_fb_driverdata {
  	struct s3c_fb_variant	variant;
  	struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
  };
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
132
  /**
bc2da1b6f   Ben Dooks   s3c-fb: integrate...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
   * struct s3c_fb_palette - palette information
   * @r: Red bitfield.
   * @g: Green bitfield.
   * @b: Blue bitfield.
   * @a: Alpha bitfield.
   */
  struct s3c_fb_palette {
  	struct fb_bitfield	r;
  	struct fb_bitfield	g;
  	struct fb_bitfield	b;
  	struct fb_bitfield	a;
  };
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
147
148
149
150
   * struct s3c_fb_win - per window private data for each framebuffer.
   * @windata: The platform data supplied for the window configuration.
   * @parent: The hardware that this window is part of.
   * @fbinfo: Pointer pack to the framebuffer info for this window.
50a5503a9   Ben Dooks   s3c-fb: initial m...
151
   * @varint: The variant information for this window.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
152
153
154
155
156
157
158
159
160
161
   * @palette_buffer: Buffer/cache to hold palette entries.
   * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
   * @index: The window number of this window.
   * @palette: The bitfields for changing r/g/b into a hardware palette entry.
   */
  struct s3c_fb_win {
  	struct s3c_fb_pd_win	*windata;
  	struct s3c_fb		*parent;
  	struct fb_info		*fbinfo;
  	struct s3c_fb_palette	 palette;
50a5503a9   Ben Dooks   s3c-fb: initial m...
162
  	struct s3c_fb_win_variant variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
163
164
165
166
167
168
169
  
  	u32			*palette_buffer;
  	u32			 pseudo_palette[16];
  	unsigned int		 index;
  };
  
  /**
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
170
171
172
173
174
175
176
177
178
179
   * struct s3c_fb_vsync - vsync information
   * @wait:	a queue for processes waiting for vsync
   * @count:	vsync interrupt count
   */
  struct s3c_fb_vsync {
  	wait_queue_head_t	wait;
  	unsigned int		count;
  };
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
180
   * struct s3c_fb - overall hardware state of the hardware
b07f3bbee   Jingoo Han   video: s3c-fb: ad...
181
   * @slock: The spinlock protection for this data sturcture.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
182
183
184
   * @dev: The device that we bound to, for printing, etc.
   * @regs_res: The resource we claimed for the IO registers.
   * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
185
   * @lcd_clk: The clk (sclk) feeding pixclk.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
186
   * @regs: The mapped hardware registers.
50a5503a9   Ben Dooks   s3c-fb: initial m...
187
   * @variant: Variant information for this hardware.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
188
189
190
   * @enabled: A bitmask of enabled hardware windows.
   * @pdata: The platform configuration data passed with the device.
   * @windows: The hardware windows that have been claimed.
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
191
192
193
   * @irq_no: IRQ line number
   * @irq_flags: irq flags
   * @vsync_info: VSYNC-related information (count, queues...)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
194
195
   */
  struct s3c_fb {
b07f3bbee   Jingoo Han   video: s3c-fb: ad...
196
  	spinlock_t		slock;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
197
198
199
  	struct device		*dev;
  	struct resource		*regs_res;
  	struct clk		*bus_clk;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
200
  	struct clk		*lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
201
  	void __iomem		*regs;
50a5503a9   Ben Dooks   s3c-fb: initial m...
202
  	struct s3c_fb_variant	 variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
203
204
205
206
207
  
  	unsigned char		 enabled;
  
  	struct s3c_fb_platdata	*pdata;
  	struct s3c_fb_win	*windows[S3C_FB_MAX_WIN];
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
208
209
210
211
  
  	int			 irq_no;
  	unsigned long		 irq_flags;
  	struct s3c_fb_vsync	 vsync_info;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
212
213
214
  };
  
  /**
50a5503a9   Ben Dooks   s3c-fb: initial m...
215
216
217
   * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
   * @win: The device window.
   * @bpp: The bit depth.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
218
   */
50a5503a9   Ben Dooks   s3c-fb: initial m...
219
  static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
220
  {
50a5503a9   Ben Dooks   s3c-fb: initial m...
221
  	return win->variant.valid_bpp & VALID_BPP(bpp);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  }
  
  /**
   * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
   * @var: The screen information to verify.
   * @info: The framebuffer device.
   *
   * Framebuffer layer call to verify the given information and allow us to
   * update various information depending on the hardware capabilities.
   */
  static int s3c_fb_check_var(struct fb_var_screeninfo *var,
  			    struct fb_info *info)
  {
  	struct s3c_fb_win *win = info->par;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
236
237
238
239
  	struct s3c_fb *sfb = win->parent;
  
  	dev_dbg(sfb->dev, "checking parameters
  ");
13e6af888   Jingoo Han   video: s3c-fb: fi...
240
241
  	var->xres_virtual = max(var->xres_virtual, var->xres);
  	var->yres_virtual = max(var->yres_virtual, var->yres);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
242

50a5503a9   Ben Dooks   s3c-fb: initial m...
243
  	if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  		dev_dbg(sfb->dev, "win %d: unsupported bpp %d
  ",
  			win->index, var->bits_per_pixel);
  		return -EINVAL;
  	}
  
  	/* always ensure these are zero, for drop through cases below */
  	var->transp.offset = 0;
  	var->transp.length = 0;
  
  	switch (var->bits_per_pixel) {
  	case 1:
  	case 2:
  	case 4:
  	case 8:
50a5503a9   Ben Dooks   s3c-fb: initial m...
259
  		if (sfb->variant.palette[win->index] != 0) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  			/* non palletised, A:1,R:2,G:3,B:2 mode */
  			var->red.offset		= 4;
  			var->green.offset	= 2;
  			var->blue.offset	= 0;
  			var->red.length		= 5;
  			var->green.length	= 3;
  			var->blue.length	= 2;
  			var->transp.offset	= 7;
  			var->transp.length	= 1;
  		} else {
  			var->red.offset	= 0;
  			var->red.length	= var->bits_per_pixel;
  			var->green	= var->red;
  			var->blue	= var->red;
  		}
  		break;
  
  	case 19:
  		/* 666 with one bit alpha/transparency */
  		var->transp.offset	= 18;
  		var->transp.length	= 1;
  	case 18:
  		var->bits_per_pixel	= 32;
  
  		/* 666 format */
  		var->red.offset		= 12;
  		var->green.offset	= 6;
  		var->blue.offset	= 0;
  		var->red.length		= 6;
  		var->green.length	= 6;
  		var->blue.length	= 6;
  		break;
  
  	case 16:
  		/* 16 bpp, 565 format */
  		var->red.offset		= 11;
  		var->green.offset	= 5;
  		var->blue.offset	= 0;
  		var->red.length		= 5;
  		var->green.length	= 6;
  		var->blue.length	= 5;
  		break;
af1ce6b2f   Jingoo Han   video: s3c-fb: co...
302
  	case 32:
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
303
304
305
306
307
308
309
310
  	case 28:
  	case 25:
  		var->transp.length	= var->bits_per_pixel - 24;
  		var->transp.offset	= 24;
  		/* drop through */
  	case 24:
  		/* our 24bpp is unpacked, so 32bpp */
  		var->bits_per_pixel	= 32;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  		var->red.offset		= 16;
  		var->red.length		= 8;
  		var->green.offset	= 8;
  		var->green.length	= 8;
  		var->blue.offset	= 0;
  		var->blue.length	= 8;
  		break;
  
  	default:
  		dev_err(sfb->dev, "invalid bpp
  ");
  	}
  
  	dev_dbg(sfb->dev, "%s: verified parameters
  ", __func__);
  	return 0;
  }
  
  /**
   * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
   * @sfb: The hardware state.
   * @pixclock: The pixel clock wanted, in picoseconds.
   *
   * Given the specified pixel clock, work out the necessary divider to get
   * close to the output frequency.
   */
eb29a5cc0   Mark Brown   revert "drivers/v...
337
  static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
338
  {
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
339
  	unsigned long clk;
eb29a5cc0   Mark Brown   revert "drivers/v...
340
  	unsigned long long tmp;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
341
  	unsigned int result;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
342
343
344
345
  	if (sfb->variant.has_clksel)
  		clk = clk_get_rate(sfb->bus_clk);
  	else
  		clk = clk_get_rate(sfb->lcd_clk);
eb29a5cc0   Mark Brown   revert "drivers/v...
346
347
348
349
350
  	tmp = (unsigned long long)clk;
  	tmp *= pixclk;
  
  	do_div(tmp, 1000000000UL);
  	result = (unsigned int)tmp / 1000;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  
  	dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)
  ",
  		pixclk, clk, result, clk / result);
  
  	return result;
  }
  
  /**
   * s3c_fb_align_word() - align pixel count to word boundary
   * @bpp: The number of bits per pixel
   * @pix: The value to be aligned.
   *
   * Align the given pixel count so that it will start on an 32bit word
   * boundary.
   */
  static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
  {
  	int pix_per_word;
  
  	if (bpp > 16)
  		return pix;
  
  	pix_per_word = (8 * 32) / bpp;
  	return ALIGN(pix, pix_per_word);
  }
  
  /**
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
   * vidosd_set_size() - set OSD size for a window
   *
   * @win: the window to set OSD size for
   * @size: OSD size register value
   */
  static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
  {
  	struct s3c_fb *sfb = win->parent;
  
  	/* OSD can be set up if osd_size_off != 0 for this window */
  	if (win->variant.osd_size_off)
  		writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
  				+ win->variant.osd_size_off);
  }
  
  /**
   * vidosd_set_alpha() - set alpha transparency for a window
   *
   * @win: the window to set OSD size for
   * @alpha: alpha register value
   */
  static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
  {
  	struct s3c_fb *sfb = win->parent;
  
  	if (win->variant.has_osd_alpha)
  		writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
  }
  
  /**
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
   * shadow_protect_win() - disable updating values from shadow registers at vsync
   *
   * @win: window to protect registers for
   * @protect: 1 to protect (disable updates)
   */
  static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
  {
  	struct s3c_fb *sfb = win->parent;
  	u32 reg;
  
  	if (protect) {
  		if (sfb->variant.has_prtcon) {
  			writel(PRTCON_PROTECT, sfb->regs + PRTCON);
  		} else if (sfb->variant.has_shadowcon) {
  			reg = readl(sfb->regs + SHADOWCON);
  			writel(reg | SHADOWCON_WINx_PROTECT(win->index),
  				sfb->regs + SHADOWCON);
  		}
  	} else {
  		if (sfb->variant.has_prtcon) {
  			writel(0, sfb->regs + PRTCON);
  		} else if (sfb->variant.has_shadowcon) {
  			reg = readl(sfb->regs + SHADOWCON);
  			writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
  				sfb->regs + SHADOWCON);
  		}
  	}
  }
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
439
440
441
442
443
444
445
446
447
448
449
   * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
   * @info: The framebuffer to change.
   *
   * Framebuffer layer request to set a new mode for the specified framebuffer
   */
  static int s3c_fb_set_par(struct fb_info *info)
  {
  	struct fb_var_screeninfo *var = &info->var;
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  	void __iomem *regs = sfb->regs;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
450
  	void __iomem *buf = regs;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
451
  	int win_no = win->index;
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
452
  	u32 alpha = 0;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
453
454
455
456
457
458
  	u32 data;
  	u32 pagewidth;
  	int clkdiv;
  
  	dev_dbg(sfb->dev, "setting framebuffer parameters
  ");
a8bdabca3   Pawel Osciak   s3c-fb: protect w...
459
  	shadow_protect_win(win, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
460
461
462
463
464
465
466
467
  	switch (var->bits_per_pixel) {
  	case 32:
  	case 24:
  	case 16:
  	case 12:
  		info->fix.visual = FB_VISUAL_TRUECOLOR;
  		break;
  	case 8:
50a5503a9   Ben Dooks   s3c-fb: initial m...
468
  		if (win->variant.palette_sz >= 256)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
469
470
471
472
473
474
475
476
477
478
479
480
481
  			info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  		else
  			info->fix.visual = FB_VISUAL_TRUECOLOR;
  		break;
  	case 1:
  		info->fix.visual = FB_VISUAL_MONO01;
  		break;
  	default:
  		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  		break;
  	}
  
  	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
067b226b9   Pawel Osciak   s3c-fb: add suppo...
482
483
  	info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
  	info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
484
485
  	/* disable the window whilst we update it */
  	writel(0, regs + WINCON(win_no));
ad04490a1   InKi Dae   s3c-fb: add defau...
486
  	/* use platform specified window as the basis for the lcd timings */
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
487

ad04490a1   InKi Dae   s3c-fb: add defau...
488
  	if (win_no == sfb->pdata->default_win) {
eb29a5cc0   Mark Brown   revert "drivers/v...
489
  		clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
490
491
492
493
494
495
496
497
498
499
  
  		data = sfb->pdata->vidcon0;
  		data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
  
  		if (clkdiv > 1)
  			data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
  		else
  			data &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
  
  		/* write the timing data to the panel */
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
500
501
  		if (sfb->variant.is_2443)
  			data |= (1 << 5);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
502
503
504
505
506
507
  		data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
  		writel(data, regs + VIDCON0);
  
  		data = VIDTCON0_VBPD(var->upper_margin - 1) |
  		       VIDTCON0_VFPD(var->lower_margin - 1) |
  		       VIDTCON0_VSPW(var->vsync_len - 1);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
508
  		writel(data, regs + sfb->variant.vidtcon);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
509
510
511
512
  
  		data = VIDTCON1_HBPD(var->left_margin - 1) |
  		       VIDTCON1_HFPD(var->right_margin - 1) |
  		       VIDTCON1_HSPW(var->hsync_len - 1);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
513
514
  		/* VIDTCON1 */
  		writel(data, regs + sfb->variant.vidtcon + 4);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
515
516
517
  
  		data = VIDTCON2_LINEVAL(var->yres - 1) |
  		       VIDTCON2_HOZVAL(var->xres - 1);
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
518
  		writel(data, regs + sfb->variant.vidtcon + 8);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
519
520
521
  	}
  
  	/* write the buffer address */
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
522
523
524
525
  	/* start and end registers stride is 8 */
  	buf = regs + win_no * 8;
  
  	writel(info->fix.smem_start, buf + sfb->variant.buf_start);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
526
527
  
  	data = info->fix.smem_start + info->fix.line_length * var->yres;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
528
  	writel(data, buf + sfb->variant.buf_end);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
529
530
531
532
  
  	pagewidth = (var->xres * var->bits_per_pixel) >> 3;
  	data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
  	       VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
533
  	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
534
535
536
537
  
  	/* write 'OSD' registers to control position of framebuffer */
  
  	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
538
  	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
539
540
541
542
  
  	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
  						     var->xres - 1)) |
  	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
543
  	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
544
545
  
  	data = var->xres * var->yres;
39000d654   InKi Dae   Samsung SoC Frame...
546

f676ec2a3   Pawel Osciak   s3c-fb: correct w...
547
  	alpha = VIDISD14C_ALPHA1_R(0xf) |
39000d654   InKi Dae   Samsung SoC Frame...
548
549
  		VIDISD14C_ALPHA1_G(0xf) |
  		VIDISD14C_ALPHA1_B(0xf);
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
550
551
  	vidosd_set_alpha(win, alpha);
  	vidosd_set_size(win, data);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
552

fab7c5b77   Jingoo Han   video: s3c-fb: mo...
553
554
555
556
557
558
  	/* Enable DMA channel for this window */
  	if (sfb->variant.has_shadowcon) {
  		data = readl(sfb->regs + SHADOWCON);
  		data |= SHADOWCON_CHx_ENABLE(win_no);
  		writel(data, sfb->regs + SHADOWCON);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  	data = WINCONx_ENWIN;
  
  	/* note, since we have to round up the bits-per-pixel, we end up
  	 * relying on the bitfield information for r/g/b/a to work out
  	 * exactly which mode of operation is intended. */
  
  	switch (var->bits_per_pixel) {
  	case 1:
  		data |= WINCON0_BPPMODE_1BPP;
  		data |= WINCONx_BITSWP;
  		data |= WINCONx_BURSTLEN_4WORD;
  		break;
  	case 2:
  		data |= WINCON0_BPPMODE_2BPP;
  		data |= WINCONx_BITSWP;
  		data |= WINCONx_BURSTLEN_8WORD;
  		break;
  	case 4:
  		data |= WINCON0_BPPMODE_4BPP;
  		data |= WINCONx_BITSWP;
  		data |= WINCONx_BURSTLEN_8WORD;
  		break;
  	case 8:
  		if (var->transp.length != 0)
  			data |= WINCON1_BPPMODE_8BPP_1232;
  		else
  			data |= WINCON0_BPPMODE_8BPP_PALETTE;
  		data |= WINCONx_BURSTLEN_8WORD;
  		data |= WINCONx_BYTSWP;
  		break;
  	case 16:
  		if (var->transp.length != 0)
  			data |= WINCON1_BPPMODE_16BPP_A1555;
  		else
  			data |= WINCON0_BPPMODE_16BPP_565;
  		data |= WINCONx_HAWSWP;
  		data |= WINCONx_BURSTLEN_16WORD;
  		break;
  	case 24:
  	case 32:
  		if (var->red.length == 6) {
  			if (var->transp.length != 0)
  				data |= WINCON1_BPPMODE_19BPP_A1666;
  			else
  				data |= WINCON1_BPPMODE_18BPP_666;
39000d654   InKi Dae   Samsung SoC Frame...
604
605
606
607
608
609
  		} else if (var->transp.length == 1)
  			data |= WINCON1_BPPMODE_25BPP_A1888
  				| WINCON1_BLD_PIX;
  		else if (var->transp.length == 4)
  			data |= WINCON1_BPPMODE_28BPP_A4888
  				| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
610
611
  		else
  			data |= WINCON0_BPPMODE_24BPP_888;
dc8498c00   InKi Dae   s3c-fb: fix disto...
612
  		data |= WINCONx_WSWP;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
613
614
615
  		data |= WINCONx_BURSTLEN_16WORD;
  		break;
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
616
  	/* Enable the colour keying for the window below this one */
39000d654   InKi Dae   Samsung SoC Frame...
617
618
  	if (win_no > 0) {
  		u32 keycon0_data = 0, keycon1_data = 0;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
619
  		void __iomem *keycon = regs + sfb->variant.keycon;
39000d654   InKi Dae   Samsung SoC Frame...
620
621
622
623
624
625
  
  		keycon0_data = ~(WxKEYCON0_KEYBL_EN |
  				WxKEYCON0_KEYEN_F |
  				WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
  
  		keycon1_data = WxKEYCON1_COLVAL(0xffffff);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
626
627
628
629
  		keycon += (win_no - 1) * 8;
  
  		writel(keycon0_data, keycon + WKEYCON0);
  		writel(keycon1_data, keycon + WKEYCON1);
39000d654   InKi Dae   Samsung SoC Frame...
630
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
631
632
  	writel(data, regs + sfb->variant.wincon + (win_no * 4));
  	writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
633

a8bdabca3   Pawel Osciak   s3c-fb: protect w...
634
  	shadow_protect_win(win, 0);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  	return 0;
  }
  
  /**
   * s3c_fb_update_palette() - set or schedule a palette update.
   * @sfb: The hardware information.
   * @win: The window being updated.
   * @reg: The palette index being changed.
   * @value: The computed palette value.
   *
   * Change the value of a palette register, either by directly writing to
   * the palette (this requires the palette RAM to be disconnected from the
   * hardware whilst this is in progress) or schedule the update for later.
   *
   * At the moment, since we have no VSYNC interrupt support, we simply set
   * the palette entry directly.
   */
  static void s3c_fb_update_palette(struct s3c_fb *sfb,
  				  struct s3c_fb_win *win,
  				  unsigned int reg,
  				  u32 value)
  {
  	void __iomem *palreg;
  	u32 palcon;
50a5503a9   Ben Dooks   s3c-fb: initial m...
659
  	palreg = sfb->regs + sfb->variant.palette[win->index];
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
660
661
662
663
664
665
666
667
668
  
  	dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x
  ",
  		__func__, win->index, reg, palreg, value);
  
  	win->palette_buffer[reg] = value;
  
  	palcon = readl(sfb->regs + WPALCON);
  	writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
50a5503a9   Ben Dooks   s3c-fb: initial m...
669
670
  	if (win->variant.palette_16bpp)
  		writew(value, palreg + (reg * 2));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
671
  	else
50a5503a9   Ben Dooks   s3c-fb: initial m...
672
  		writel(value, palreg + (reg * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  
  	writel(palcon, sfb->regs + WPALCON);
  }
  
  static inline unsigned int chan_to_field(unsigned int chan,
  					 struct fb_bitfield *bf)
  {
  	chan &= 0xffff;
  	chan >>= 16 - bf->length;
  	return chan << bf->offset;
  }
  
  /**
   * s3c_fb_setcolreg() - framebuffer layer request to change palette.
   * @regno: The palette index to change.
   * @red: The red field for the palette data.
   * @green: The green field for the palette data.
   * @blue: The blue field for the palette data.
   * @trans: The transparency (alpha) field for the palette data.
   * @info: The framebuffer being changed.
   */
  static int s3c_fb_setcolreg(unsigned regno,
  			    unsigned red, unsigned green, unsigned blue,
  			    unsigned transp, struct fb_info *info)
  {
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  	unsigned int val;
  
  	dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d
  ",
  		__func__, win->index, regno, red, green, blue);
  
  	switch (info->fix.visual) {
  	case FB_VISUAL_TRUECOLOR:
  		/* true-colour, use pseudo-palette */
  
  		if (regno < 16) {
  			u32 *pal = info->pseudo_palette;
  
  			val  = chan_to_field(red,   &info->var.red);
  			val |= chan_to_field(green, &info->var.green);
  			val |= chan_to_field(blue,  &info->var.blue);
  
  			pal[regno] = val;
  		}
  		break;
  
  	case FB_VISUAL_PSEUDOCOLOR:
50a5503a9   Ben Dooks   s3c-fb: initial m...
722
  		if (regno < win->variant.palette_sz) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  			val  = chan_to_field(red, &win->palette.r);
  			val |= chan_to_field(green, &win->palette.g);
  			val |= chan_to_field(blue, &win->palette.b);
  
  			s3c_fb_update_palette(sfb, win, regno, val);
  		}
  
  		break;
  
  	default:
  		return 1;	/* unknown type */
  	}
  
  	return 0;
  }
  
  /**
   * s3c_fb_enable() - Set the state of the main LCD output
   * @sfb: The main framebuffer state.
   * @enable: The state to set.
   */
  static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
  {
  	u32 vidcon0 = readl(sfb->regs + VIDCON0);
  
  	if (enable)
  		vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
  	else {
  		/* see the note in the framebuffer datasheet about
  		 * why you cannot take both of these bits down at the
  		 * same time. */
  
  		if (!(vidcon0 & VIDCON0_ENVID))
  			return;
  
  		vidcon0 |= VIDCON0_ENVID;
  		vidcon0 &= ~VIDCON0_ENVID_F;
  	}
  
  	writel(vidcon0, sfb->regs + VIDCON0);
  }
  
  /**
   * s3c_fb_blank() - blank or unblank the given window
   * @blank_mode: The blank state from FB_BLANK_*
   * @info: The framebuffer to blank.
   *
   * Framebuffer layer request to change the power state.
   */
  static int s3c_fb_blank(int blank_mode, struct fb_info *info)
  {
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  	unsigned int index = win->index;
  	u32 wincon;
  
  	dev_dbg(sfb->dev, "blank mode %d
  ", blank_mode);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
781
  	wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
782
783
784
785
786
787
788
789
790
791
  
  	switch (blank_mode) {
  	case FB_BLANK_POWERDOWN:
  		wincon &= ~WINCONx_ENWIN;
  		sfb->enabled &= ~(1 << index);
  		/* fall through to FB_BLANK_NORMAL */
  
  	case FB_BLANK_NORMAL:
  		/* disable the DMA and display 0x0 (black) */
  		writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
792
  		       sfb->regs + sfb->variant.winmap + (index * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
793
794
795
  		break;
  
  	case FB_BLANK_UNBLANK:
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
796
  		writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
797
798
799
800
801
802
803
804
805
  		wincon |= WINCONx_ENWIN;
  		sfb->enabled |= (1 << index);
  		break;
  
  	case FB_BLANK_VSYNC_SUSPEND:
  	case FB_BLANK_HSYNC_SUSPEND:
  	default:
  		return 1;
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
806
  	writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
  
  	/* Check the enabled state to see if we need to be running the
  	 * main LCD interface, as if there are no active windows then
  	 * it is highly likely that we also do not need to output
  	 * anything.
  	 */
  
  	/* We could do something like the following code, but the current
  	 * system of using framebuffer events means that we cannot make
  	 * the distinction between just window 0 being inactive and all
  	 * the windows being down.
  	 *
  	 * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
  	*/
  
  	/* we're stuck with this until we can do something about overriding
  	 * the power control using the blanking event for a single fb.
  	 */
ad04490a1   InKi Dae   s3c-fb: add defau...
825
  	if (index == sfb->pdata->default_win)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
826
827
828
829
  		s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
  
  	return 0;
  }
067b226b9   Pawel Osciak   s3c-fb: add suppo...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  /**
   * s3c_fb_pan_display() - Pan the display.
   *
   * Note that the offsets can be written to the device at any time, as their
   * values are latched at each vsync automatically. This also means that only
   * the last call to this function will have any effect on next vsync, but
   * there is no need to sleep waiting for it to prevent tearing.
   *
   * @var: The screen information to verify.
   * @info: The framebuffer device.
   */
  static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
  			      struct fb_info *info)
  {
  	struct s3c_fb_win *win	= info->par;
  	struct s3c_fb *sfb	= win->parent;
  	void __iomem *buf	= sfb->regs + win->index * 8;
  	unsigned int start_boff, end_boff;
  
  	/* Offset in bytes to the start of the displayed area */
  	start_boff = var->yoffset * info->fix.line_length;
  	/* X offset depends on the current bpp */
  	if (info->var.bits_per_pixel >= 8) {
  		start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
  	} else {
  		switch (info->var.bits_per_pixel) {
  		case 4:
  			start_boff += var->xoffset >> 1;
  			break;
  		case 2:
  			start_boff += var->xoffset >> 2;
  			break;
  		case 1:
  			start_boff += var->xoffset >> 3;
  			break;
  		default:
  			dev_err(sfb->dev, "invalid bpp
  ");
  			return -EINVAL;
  		}
  	}
  	/* Offset in bytes to the end of the displayed area */
d8e7a74bf   Laurent Pinchart   s3c-fb: use displ...
872
  	end_boff = start_boff + info->var.yres * info->fix.line_length;
067b226b9   Pawel Osciak   s3c-fb: add suppo...
873
874
875
  
  	/* Temporarily turn off per-vsync update from shadow registers until
  	 * both start and end addresses are updated to prevent corruption */
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
876
  	shadow_protect_win(win, 1);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
877
878
879
  
  	writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
  	writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
880
  	shadow_protect_win(win, 0);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
881
882
883
  
  	return 0;
  }
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  /**
   * s3c_fb_enable_irq() - enable framebuffer interrupts
   * @sfb: main hardware state
   */
  static void s3c_fb_enable_irq(struct s3c_fb *sfb)
  {
  	void __iomem *regs = sfb->regs;
  	u32 irq_ctrl_reg;
  
  	if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
  		/* IRQ disabled, enable it */
  		irq_ctrl_reg = readl(regs + VIDINTCON0);
  
  		irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
  		irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
  
  		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
  		irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
  		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
  		irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
  
  		writel(irq_ctrl_reg, regs + VIDINTCON0);
  	}
  }
  
  /**
   * s3c_fb_disable_irq() - disable framebuffer interrupts
   * @sfb: main hardware state
   */
  static void s3c_fb_disable_irq(struct s3c_fb *sfb)
  {
  	void __iomem *regs = sfb->regs;
  	u32 irq_ctrl_reg;
  
  	if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
  		/* IRQ enabled, disable it */
  		irq_ctrl_reg = readl(regs + VIDINTCON0);
  
  		irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
  		irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
  
  		writel(irq_ctrl_reg, regs + VIDINTCON0);
  	}
  }
  
  static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
  {
  	struct s3c_fb *sfb = dev_id;
  	void __iomem  *regs = sfb->regs;
  	u32 irq_sts_reg;
b07f3bbee   Jingoo Han   video: s3c-fb: ad...
934
  	spin_lock(&sfb->slock);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  	irq_sts_reg = readl(regs + VIDINTCON1);
  
  	if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
  
  		/* VSYNC interrupt, accept it */
  		writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
  
  		sfb->vsync_info.count++;
  		wake_up_interruptible(&sfb->vsync_info.wait);
  	}
  
  	/* We only support waiting for VSYNC for now, so it's safe
  	 * to always disable irqs here.
  	 */
  	s3c_fb_disable_irq(sfb);
b07f3bbee   Jingoo Han   video: s3c-fb: ad...
950
  	spin_unlock(&sfb->slock);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  	return IRQ_HANDLED;
  }
  
  /**
   * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
   * @sfb: main hardware state
   * @crtc: head index.
   */
  static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
  {
  	unsigned long count;
  	int ret;
  
  	if (crtc != 0)
  		return -ENODEV;
  
  	count = sfb->vsync_info.count;
  	s3c_fb_enable_irq(sfb);
  	ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
  				       count != sfb->vsync_info.count,
  				       msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
  	if (ret == 0)
  		return -ETIMEDOUT;
  
  	return 0;
  }
  
  static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
  			unsigned long arg)
  {
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  	int ret;
  	u32 crtc;
  
  	switch (cmd) {
  	case FBIO_WAITFORVSYNC:
  		if (get_user(crtc, (u32 __user *)arg)) {
  			ret = -EFAULT;
  			break;
  		}
  
  		ret = s3c_fb_wait_for_vsync(sfb, crtc);
  		break;
  	default:
  		ret = -ENOTTY;
  	}
  
  	return ret;
  }
4959212c1   Jingoo Han   s3c-fb: add suppo...
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
  static int s3c_fb_open(struct fb_info *info, int user)
  {
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  
  	pm_runtime_get_sync(sfb->dev);
  
  	return 0;
  }
  
  static int s3c_fb_release(struct fb_info *info, int user)
  {
  	struct s3c_fb_win *win = info->par;
  	struct s3c_fb *sfb = win->parent;
  
  	pm_runtime_put_sync(sfb->dev);
  
  	return 0;
  }
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1020
1021
  static struct fb_ops s3c_fb_ops = {
  	.owner		= THIS_MODULE,
4959212c1   Jingoo Han   s3c-fb: add suppo...
1022
1023
  	.fb_open	= s3c_fb_open,
  	.fb_release	= s3c_fb_release,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1024
1025
1026
1027
1028
1029
1030
  	.fb_check_var	= s3c_fb_check_var,
  	.fb_set_par	= s3c_fb_set_par,
  	.fb_blank	= s3c_fb_blank,
  	.fb_setcolreg	= s3c_fb_setcolreg,
  	.fb_fillrect	= cfb_fillrect,
  	.fb_copyarea	= cfb_copyarea,
  	.fb_imageblit	= cfb_imageblit,
067b226b9   Pawel Osciak   s3c-fb: add suppo...
1031
  	.fb_pan_display	= s3c_fb_pan_display,
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1032
  	.fb_ioctl	= s3c_fb_ioctl,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1033
1034
1035
  };
  
  /**
2bb567a38   Maurus Cuelenaere   s3c-fb: automatic...
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
   * s3c_fb_missing_pixclock() - calculates pixel clock
   * @mode: The video mode to change.
   *
   * Calculate the pixel clock when none has been given through platform data.
   */
  static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
  {
  	u64 pixclk = 1000000000000ULL;
  	u32 div;
  
  	div  = mode->left_margin + mode->hsync_len + mode->right_margin +
  	       mode->xres;
  	div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
  	       mode->yres;
  	div *= mode->refresh ? : 60;
  
  	do_div(pixclk, div);
  
  	mode->pixclock = pixclk;
  }
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
   * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
   * @sfb: The base resources for the hardware.
   * @win: The window to initialise memory for.
   *
   * Allocate memory for the given framebuffer.
   */
  static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
  					 struct s3c_fb_win *win)
  {
  	struct s3c_fb_pd_win *windata = win->windata;
  	unsigned int real_size, virt_size, size;
  	struct fb_info *fbi = win->fbinfo;
  	dma_addr_t map_dma;
  
  	dev_dbg(sfb->dev, "allocating memory for display
  ");
  
  	real_size = windata->win_mode.xres * windata->win_mode.yres;
  	virt_size = windata->virtual_x * windata->virtual_y;
  
  	dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)
  ",
  		real_size, windata->win_mode.xres, windata->win_mode.yres,
  		virt_size, windata->virtual_x, windata->virtual_y);
  
  	size = (real_size > virt_size) ? real_size : virt_size;
  	size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
  	size /= 8;
  
  	fbi->fix.smem_len = size;
  	size = PAGE_ALIGN(size);
  
  	dev_dbg(sfb->dev, "want %u bytes for window
  ", size);
  
  	fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
  						  &map_dma, GFP_KERNEL);
  	if (!fbi->screen_base)
  		return -ENOMEM;
  
  	dev_dbg(sfb->dev, "mapped %x to %p
  ",
  		(unsigned int)map_dma, fbi->screen_base);
  
  	memset(fbi->screen_base, 0x0, size);
  	fbi->fix.smem_start = map_dma;
  
  	return 0;
  }
  
  /**
   * s3c_fb_free_memory() - free the display memory for the given window
   * @sfb: The base resources for the hardware.
   * @win: The window to free the display memory for.
   *
   * Free the display memory allocated by s3c_fb_alloc_memory().
   */
  static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
  {
  	struct fb_info *fbi = win->fbinfo;
cd7d7e024   Pawel Osciak   s3c-fb: fix vario...
1118
1119
  	if (fbi->screen_base)
  		dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  			      fbi->screen_base, fbi->fix.smem_start);
  }
  
  /**
   * s3c_fb_release_win() - release resources for a framebuffer window.
   * @win: The window to cleanup the resources for.
   *
   * Release the resources that where claimed for the hardware window,
   * such as the framebuffer instance and any memory claimed for it.
   */
  static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
  {
04ab9ef97   Pawel Osciak   s3c-fb: add suppo...
1132
  	u32 data;
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1133
  	if (win->fbinfo) {
04ab9ef97   Pawel Osciak   s3c-fb: add suppo...
1134
1135
1136
1137
1138
1139
  		if (sfb->variant.has_shadowcon) {
  			data = readl(sfb->regs + SHADOWCON);
  			data &= ~SHADOWCON_CHx_ENABLE(win->index);
  			data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
  			writel(data, sfb->regs + SHADOWCON);
  		}
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1140
  		unregister_framebuffer(win->fbinfo);
cd7d7e024   Pawel Osciak   s3c-fb: fix vario...
1141
1142
  		if (win->fbinfo->cmap.len)
  			fb_dealloc_cmap(&win->fbinfo->cmap);
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1143
1144
1145
  		s3c_fb_free_memory(sfb, win);
  		framebuffer_release(win->fbinfo);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1146
1147
1148
1149
1150
  }
  
  /**
   * s3c_fb_probe_win() - register an hardware window
   * @sfb: The base resources for the hardware
50a5503a9   Ben Dooks   s3c-fb: initial m...
1151
   * @variant: The variant information for this window.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1152
1153
1154
1155
1156
1157
   * @res: Pointer to where to place the resultant window.
   *
   * Allocate and do the basic initialisation for one of the hardware's graphics
   * windows.
   */
  static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1158
  				      struct s3c_fb_win_variant *variant,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1159
1160
1161
1162
1163
1164
1165
1166
1167
  				      struct s3c_fb_win **res)
  {
  	struct fb_var_screeninfo *var;
  	struct fb_videomode *initmode;
  	struct s3c_fb_pd_win *windata;
  	struct s3c_fb_win *win;
  	struct fb_info *fbinfo;
  	int palette_size;
  	int ret;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1168
1169
  	dev_dbg(sfb->dev, "probing window %d, variant %p
  ", win_no, variant);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1170

efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1171
  	init_waitqueue_head(&sfb->vsync_info.wait);
50a5503a9   Ben Dooks   s3c-fb: initial m...
1172
  	palette_size = variant->palette_sz * 4;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  
  	fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
  				   palette_size * sizeof(u32), sfb->dev);
  	if (!fbinfo) {
  		dev_err(sfb->dev, "failed to allocate framebuffer
  ");
  		return -ENOENT;
  	}
  
  	windata = sfb->pdata->win[win_no];
  	initmode = &windata->win_mode;
  
  	WARN_ON(windata->max_bpp == 0);
  	WARN_ON(windata->win_mode.xres == 0);
  	WARN_ON(windata->win_mode.yres == 0);
  
  	win = fbinfo->par;
cd7d7e024   Pawel Osciak   s3c-fb: fix vario...
1190
  	*res = win;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1191
  	var = &fbinfo->var;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1192
  	win->variant = *variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  	win->fbinfo = fbinfo;
  	win->parent = sfb;
  	win->windata = windata;
  	win->index = win_no;
  	win->palette_buffer = (u32 *)(win + 1);
  
  	ret = s3c_fb_alloc_memory(sfb, win);
  	if (ret) {
  		dev_err(sfb->dev, "failed to allocate display memory
  ");
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1203
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1204
1205
1206
  	}
  
  	/* setup the r/b/g positions for the window's palette */
bc2da1b6f   Ben Dooks   s3c-fb: integrate...
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  	if (win->variant.palette_16bpp) {
  		/* Set RGB 5:6:5 as default */
  		win->palette.r.offset = 11;
  		win->palette.r.length = 5;
  		win->palette.g.offset = 5;
  		win->palette.g.length = 6;
  		win->palette.b.offset = 0;
  		win->palette.b.length = 5;
  
  	} else {
  		/* Set 8bpp or 8bpp and 1bit alpha */
  		win->palette.r.offset = 16;
  		win->palette.r.length = 8;
  		win->palette.g.offset = 8;
  		win->palette.g.length = 8;
  		win->palette.b.offset = 0;
  		win->palette.b.length = 8;
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
  
  	/* setup the initial video mode from the window */
  	fb_videomode_to_var(&fbinfo->var, initmode);
  
  	fbinfo->fix.type	= FB_TYPE_PACKED_PIXELS;
  	fbinfo->fix.accel	= FB_ACCEL_NONE;
  	fbinfo->var.activate	= FB_ACTIVATE_NOW;
  	fbinfo->var.vmode	= FB_VMODE_NONINTERLACED;
  	fbinfo->var.bits_per_pixel = windata->default_bpp;
  	fbinfo->fbops		= &s3c_fb_ops;
  	fbinfo->flags		= FBINFO_FLAG_DEFAULT;
  	fbinfo->pseudo_palette  = &win->pseudo_palette;
  
  	/* prepare to actually start the framebuffer */
  
  	ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
  	if (ret < 0) {
  		dev_err(sfb->dev, "check_var failed on initial video params
  ");
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1244
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1245
1246
1247
  	}
  
  	/* create initial colour map */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1248
  	ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  	if (ret == 0)
  		fb_set_cmap(&fbinfo->cmap, fbinfo);
  	else
  		dev_err(sfb->dev, "failed to allocate fb cmap
  ");
  
  	s3c_fb_set_par(fbinfo);
  
  	dev_dbg(sfb->dev, "about to register framebuffer
  ");
  
  	/* run the check_var and set_par on our configuration. */
  
  	ret = register_framebuffer(fbinfo);
  	if (ret < 0) {
  		dev_err(sfb->dev, "failed to register framebuffer
  ");
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1266
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1267
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1268
1269
1270
1271
  	dev_info(sfb->dev, "window %d: fb %s
  ", win_no, fbinfo->fix.id);
  
  	return 0;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
  }
  
  /**
   * s3c_fb_clear_win() - clear hardware window registers.
   * @sfb: The base resources for the hardware.
   * @win: The window to process.
   *
   * Reset the specific window registers to a known state.
   */
  static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
  {
  	void __iomem *regs = sfb->regs;
a8bdabca3   Pawel Osciak   s3c-fb: protect w...
1284
  	u32 reg;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1285

c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1286
1287
1288
1289
  	writel(0, regs + sfb->variant.wincon + (win * 4));
  	writel(0, regs + VIDOSD_A(win, sfb->variant));
  	writel(0, regs + VIDOSD_B(win, sfb->variant));
  	writel(0, regs + VIDOSD_C(win, sfb->variant));
a8bdabca3   Pawel Osciak   s3c-fb: protect w...
1290
1291
  	reg = readl(regs + SHADOWCON);
  	writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1292
1293
1294
1295
  }
  
  static int __devinit s3c_fb_probe(struct platform_device *pdev)
  {
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
1296
  	const struct platform_device_id *platid;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1297
  	struct s3c_fb_driverdata *fbdrv;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1298
1299
1300
1301
1302
1303
  	struct device *dev = &pdev->dev;
  	struct s3c_fb_platdata *pd;
  	struct s3c_fb *sfb;
  	struct resource *res;
  	int win;
  	int ret = 0;
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
1304
1305
  	platid = platform_get_device_id(pdev);
  	fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1306
1307
1308
1309
1310
1311
  
  	if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
  		dev_err(dev, "too many windows, cannot attach
  ");
  		return -EINVAL;
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  	pd = pdev->dev.platform_data;
  	if (!pd) {
  		dev_err(dev, "no platform data specified
  ");
  		return -EINVAL;
  	}
  
  	sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
  	if (!sfb) {
  		dev_err(dev, "no memory for framebuffers
  ");
  		return -ENOMEM;
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1325
1326
  	dev_dbg(dev, "allocate new framebuffer %p
  ", sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1327
1328
  	sfb->dev = dev;
  	sfb->pdata = pd;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1329
  	sfb->variant = fbdrv->variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1330

b07f3bbee   Jingoo Han   video: s3c-fb: ad...
1331
  	spin_lock_init(&sfb->slock);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1332
1333
1334
1335
  	sfb->bus_clk = clk_get(dev, "lcd");
  	if (IS_ERR(sfb->bus_clk)) {
  		dev_err(dev, "failed to get bus clock
  ");
942b8d05c   Axel Lin   video: s3c-fb: re...
1336
  		ret = PTR_ERR(sfb->bus_clk);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1337
1338
1339
1340
  		goto err_sfb;
  	}
  
  	clk_enable(sfb->bus_clk);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  	if (!sfb->variant.has_clksel) {
  		sfb->lcd_clk = clk_get(dev, "sclk_fimd");
  		if (IS_ERR(sfb->lcd_clk)) {
  			dev_err(dev, "failed to get lcd clock
  ");
  			ret = PTR_ERR(sfb->lcd_clk);
  			goto err_bus_clk;
  		}
  
  		clk_enable(sfb->lcd_clk);
  	}
4959212c1   Jingoo Han   s3c-fb: add suppo...
1352
  	pm_runtime_enable(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1353
1354
1355
1356
1357
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res) {
  		dev_err(dev, "failed to find registers
  ");
  		ret = -ENOENT;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1358
  		goto err_lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1359
1360
1361
1362
1363
1364
1365
1366
  	}
  
  	sfb->regs_res = request_mem_region(res->start, resource_size(res),
  					   dev_name(dev));
  	if (!sfb->regs_res) {
  		dev_err(dev, "failed to claim register region
  ");
  		ret = -ENOENT;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1367
  		goto err_lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1368
1369
1370
1371
1372
1373
1374
1375
1376
  	}
  
  	sfb->regs = ioremap(res->start, resource_size(res));
  	if (!sfb->regs) {
  		dev_err(dev, "failed to map registers
  ");
  		ret = -ENXIO;
  		goto err_req_region;
  	}
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
  	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  	if (!res) {
  		dev_err(dev, "failed to acquire irq resource
  ");
  		ret = -ENOENT;
  		goto err_ioremap;
  	}
  	sfb->irq_no = res->start;
  	ret = request_irq(sfb->irq_no, s3c_fb_irq,
  			  0, "s3c_fb", sfb);
  	if (ret) {
  		dev_err(dev, "irq request failed
  ");
  		goto err_ioremap;
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1392
1393
  	dev_dbg(dev, "got resources (regs %p), probing windows
  ", sfb->regs);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1394
1395
  	platform_set_drvdata(pdev, sfb);
  	pm_runtime_get_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1396
1397
1398
1399
1400
1401
1402
  	/* setup gpio and output polarity controls */
  
  	pd->setup_gpio();
  
  	writel(pd->vidcon1, sfb->regs + VIDCON1);
  
  	/* zero all windows before we do anything */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1403
  	for (win = 0; win < fbdrv->variant.nr_windows; win++)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1404
  		s3c_fb_clear_win(sfb, win);
949470375   Ben Dooks   s3c-fb: only init...
1405
  	/* initialise colour key controls */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1406
  	for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1407
1408
1409
1410
1411
  		void __iomem *regs = sfb->regs + sfb->variant.keycon;
  
  		regs += (win * 8);
  		writel(0xffffff, regs + WKEYCON0);
  		writel(0xffffff, regs + WKEYCON1);
949470375   Ben Dooks   s3c-fb: only init...
1412
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1413
  	/* we have the register setup, start allocating framebuffers */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1414
  	for (win = 0; win < fbdrv->variant.nr_windows; win++) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1415
1416
  		if (!pd->win[win])
  			continue;
2bb567a38   Maurus Cuelenaere   s3c-fb: automatic...
1417
1418
  		if (!pd->win[win]->win_mode.pixclock)
  			s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
50a5503a9   Ben Dooks   s3c-fb: initial m...
1419
1420
  		ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
  				       &sfb->windows[win]);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1421
1422
1423
1424
1425
  		if (ret < 0) {
  			dev_err(dev, "failed to create window %d
  ", win);
  			for (; win >= 0; win--)
  				s3c_fb_release_win(sfb, sfb->windows[win]);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1426
  			goto err_irq;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1427
1428
1429
1430
  		}
  	}
  
  	platform_set_drvdata(pdev, sfb);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1431
  	pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1432
1433
  
  	return 0;
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1434
1435
  err_irq:
  	free_irq(sfb->irq_no, sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1436
1437
1438
1439
  err_ioremap:
  	iounmap(sfb->regs);
  
  err_req_region:
683e7cdc2   Julia Lawall   drivers/video: Co...
1440
  	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1441

b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1442
1443
1444
1445
1446
1447
1448
  err_lcd_clk:
  	if (!sfb->variant.has_clksel) {
  		clk_disable(sfb->lcd_clk);
  		clk_put(sfb->lcd_clk);
  	}
  
  err_bus_clk:
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
  	clk_disable(sfb->bus_clk);
  	clk_put(sfb->bus_clk);
  
  err_sfb:
  	kfree(sfb);
  	return ret;
  }
  
  /**
   * s3c_fb_remove() - Cleanup on module finalisation
   * @pdev: The platform device we are bound to.
   *
   * Shutdown and then release all the resources that the driver allocated
   * on initialisation.
   */
  static int __devexit s3c_fb_remove(struct platform_device *pdev)
  {
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
  	int win;
4959212c1   Jingoo Han   s3c-fb: add suppo...
1468
  	pm_runtime_get_sync(sfb->dev);
c42b110ca   Pawel Osciak   s3c-fb: fix off-b...
1469
  	for (win = 0; win < S3C_FB_MAX_WIN; win++)
17663e597   Marek Szyprowski   S3C-fb: PM fix
1470
1471
  		if (sfb->windows[win])
  			s3c_fb_release_win(sfb, sfb->windows[win]);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1472

efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1473
  	free_irq(sfb->irq_no, sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1474
  	iounmap(sfb->regs);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1475
1476
1477
1478
  	if (!sfb->variant.has_clksel) {
  		clk_disable(sfb->lcd_clk);
  		clk_put(sfb->lcd_clk);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1479
1480
  	clk_disable(sfb->bus_clk);
  	clk_put(sfb->bus_clk);
683e7cdc2   Julia Lawall   drivers/video: Co...
1481
  	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1482

4959212c1   Jingoo Han   s3c-fb: add suppo...
1483
1484
  	pm_runtime_put_sync(sfb->dev);
  	pm_runtime_disable(sfb->dev);
72ba4cb60   Jingoo Han   video: s3c-fb: fi...
1485
  	kfree(sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1486
1487
1488
1489
  	return 0;
  }
  
  #ifdef CONFIG_PM
4959212c1   Jingoo Han   s3c-fb: add suppo...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
  static int s3c_fb_suspend(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
  	struct s3c_fb_win *win;
  	int win_no;
  
  	for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
  		win = sfb->windows[win_no];
  		if (!win)
  			continue;
  
  		/* use the blank function to push into power-down */
  		s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
  	}
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1505
1506
  	if (!sfb->variant.has_clksel)
  		clk_disable(sfb->lcd_clk);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
  	clk_disable(sfb->bus_clk);
  	return 0;
  }
  
  static int s3c_fb_resume(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
  	struct s3c_fb_platdata *pd = sfb->pdata;
  	struct s3c_fb_win *win;
  	int win_no;
  
  	clk_enable(sfb->bus_clk);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1520
1521
  	if (!sfb->variant.has_clksel)
  		clk_enable(sfb->lcd_clk);
6aa968110   Jingoo Han   video: s3c-fb: ad...
1522
1523
  	/* setup gpio and output polarity controls */
  	pd->setup_gpio();
4959212c1   Jingoo Han   s3c-fb: add suppo...
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  	writel(pd->vidcon1, sfb->regs + VIDCON1);
  
  	/* zero all windows before we do anything */
  	for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
  		s3c_fb_clear_win(sfb, win_no);
  
  	for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
  		void __iomem *regs = sfb->regs + sfb->variant.keycon;
  
  		regs += (win_no * 8);
  		writel(0xffffff, regs + WKEYCON0);
  		writel(0xffffff, regs + WKEYCON1);
  	}
  
  	/* restore framebuffers */
  	for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
  		win = sfb->windows[win_no];
  		if (!win)
  			continue;
  
  		dev_dbg(&pdev->dev, "resuming window %d
  ", win_no);
  		s3c_fb_set_par(win->fbinfo);
  	}
  
  	return 0;
  }
0d60b281d   Jingoo Han   video: s3c-fb: ma...
1551
  static int s3c_fb_runtime_suspend(struct device *dev)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1552
  {
4959212c1   Jingoo Han   s3c-fb: add suppo...
1553
  	struct platform_device *pdev = to_platform_device(dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1554
1555
1556
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
  	struct s3c_fb_win *win;
  	int win_no;
c42b110ca   Pawel Osciak   s3c-fb: fix off-b...
1557
  	for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1558
1559
1560
1561
1562
1563
1564
  		win = sfb->windows[win_no];
  		if (!win)
  			continue;
  
  		/* use the blank function to push into power-down */
  		s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
  	}
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1565
1566
  	if (!sfb->variant.has_clksel)
  		clk_disable(sfb->lcd_clk);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1567
1568
1569
  	clk_disable(sfb->bus_clk);
  	return 0;
  }
0d60b281d   Jingoo Han   video: s3c-fb: ma...
1570
  static int s3c_fb_runtime_resume(struct device *dev)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1571
  {
4959212c1   Jingoo Han   s3c-fb: add suppo...
1572
  	struct platform_device *pdev = to_platform_device(dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1573
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
17663e597   Marek Szyprowski   S3C-fb: PM fix
1574
  	struct s3c_fb_platdata *pd = sfb->pdata;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1575
1576
1577
1578
  	struct s3c_fb_win *win;
  	int win_no;
  
  	clk_enable(sfb->bus_clk);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1579
1580
  	if (!sfb->variant.has_clksel)
  		clk_enable(sfb->lcd_clk);
6aa968110   Jingoo Han   video: s3c-fb: ad...
1581
1582
  	/* setup gpio and output polarity controls */
  	pd->setup_gpio();
17663e597   Marek Szyprowski   S3C-fb: PM fix
1583
1584
1585
  	writel(pd->vidcon1, sfb->regs + VIDCON1);
  
  	/* zero all windows before we do anything */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1586
  	for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
17663e597   Marek Szyprowski   S3C-fb: PM fix
1587
  		s3c_fb_clear_win(sfb, win_no);
50a5503a9   Ben Dooks   s3c-fb: initial m...
1588
  	for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1589
1590
1591
1592
1593
  		void __iomem *regs = sfb->regs + sfb->variant.keycon;
  
  		regs += (win_no * 8);
  		writel(0xffffff, regs + WKEYCON0);
  		writel(0xffffff, regs + WKEYCON1);
949470375   Ben Dooks   s3c-fb: only init...
1594
  	}
17663e597   Marek Szyprowski   S3C-fb: PM fix
1595
  	/* restore framebuffers */
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
  	for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
  		win = sfb->windows[win_no];
  		if (!win)
  			continue;
  
  		dev_dbg(&pdev->dev, "resuming window %d
  ", win_no);
  		s3c_fb_set_par(win->fbinfo);
  	}
  
  	return 0;
  }
4959212c1   Jingoo Han   s3c-fb: add suppo...
1608

ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1609
1610
1611
  #else
  #define s3c_fb_suspend NULL
  #define s3c_fb_resume  NULL
4959212c1   Jingoo Han   s3c-fb: add suppo...
1612
1613
  #define s3c_fb_runtime_suspend NULL
  #define s3c_fb_runtime_resume NULL
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1614
  #endif
50a5503a9   Ben Dooks   s3c-fb: initial m...
1615
1616
1617
  
  #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
  #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1618
  static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1619
1620
  	[0] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1621
  		.osd_size_off	= 0x8,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1622
  		.palette_sz	= 256,
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1623
1624
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(24)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1625
1626
1627
1628
  	},
  	[1] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
c9d503e93   Jingoo Han   video: s3c-fb: co...
1629
  		.osd_size_off	= 0xc,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1630
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1631
1632
1633
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1634
1635
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1636
1637
1638
1639
  	},
  	[2] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
c9d503e93   Jingoo Han   video: s3c-fb: co...
1640
  		.osd_size_off	= 0xc,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1641
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1642
1643
1644
1645
  		.palette_sz	= 16,
  		.palette_16bpp	= 1,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1646
1647
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1648
1649
1650
  	},
  	[3] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1651
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1652
1653
1654
1655
  		.palette_sz	= 16,
  		.palette_16bpp	= 1,
  		.valid_bpp	= (VALID_BPP124  | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1656
1657
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1658
1659
1660
  	},
  	[4] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1661
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1662
1663
1664
1665
  		.palette_sz	= 4,
  		.palette_16bpp	= 1,
  		.valid_bpp	= (VALID_BPP(1) | VALID_BPP(2) |
  				   VALID_BPP(16) | VALID_BPP(18) |
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1666
1667
  				   VALID_BPP(19) | VALID_BPP(24) |
  				   VALID_BPP(25) | VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1668
1669
  	},
  };
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
  static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
  	[0] = {
  		.has_osd_c	= 1,
  		.osd_size_off	= 0x8,
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
  				   VALID_BPP(15) | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(32)),
  	},
  	[1] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
  		.osd_size_off	= 0xc,
  		.has_osd_alpha	= 1,
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
  				   VALID_BPP(15) | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(32)),
  	},
  	[2] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
  		.osd_size_off	= 0xc,
  		.has_osd_alpha	= 1,
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
  				   VALID_BPP(15) | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(32)),
  	},
  	[3] = {
  		.has_osd_c	= 1,
  		.has_osd_alpha	= 1,
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
  				   VALID_BPP(15) | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(32)),
  	},
  	[4] = {
  		.has_osd_c	= 1,
  		.has_osd_alpha	= 1,
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(13) |
  				   VALID_BPP(15) | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(32)),
  	},
  };
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1726
  static struct s3c_fb_driverdata s3c_fb_data_64xx = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1727
1728
  	.variant = {
  		.nr_windows	= 5,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1729
1730
1731
1732
1733
1734
1735
1736
1737
  		.vidtcon	= VIDTCON0,
  		.wincon		= WINCON(0),
  		.winmap		= WINxMAP(0),
  		.keycon		= WKEYCON,
  		.osd		= VIDOSD_BASE,
  		.osd_stride	= 16,
  		.buf_start	= VIDW_BUF_START(0),
  		.buf_size	= VIDW_BUF_SIZE(0),
  		.buf_end	= VIDW_BUF_END(0),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1738
1739
1740
1741
1742
1743
1744
1745
  
  		.palette = {
  			[0] = 0x400,
  			[1] = 0x800,
  			[2] = 0x300,
  			[3] = 0x320,
  			[4] = 0x340,
  		},
067b226b9   Pawel Osciak   s3c-fb: add suppo...
1746
1747
  
  		.has_prtcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1748
  		.has_clksel	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1749
1750
1751
1752
1753
1754
1755
  	},
  	.win[0]	= &s3c_fb_data_64xx_wins[0],
  	.win[1]	= &s3c_fb_data_64xx_wins[1],
  	.win[2]	= &s3c_fb_data_64xx_wins[2],
  	.win[3]	= &s3c_fb_data_64xx_wins[3],
  	.win[4]	= &s3c_fb_data_64xx_wins[4],
  };
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1756
  static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  	.variant = {
  		.nr_windows	= 5,
  		.vidtcon	= VIDTCON0,
  		.wincon		= WINCON(0),
  		.winmap		= WINxMAP(0),
  		.keycon		= WKEYCON,
  		.osd		= VIDOSD_BASE,
  		.osd_stride	= 16,
  		.buf_start	= VIDW_BUF_START(0),
  		.buf_size	= VIDW_BUF_SIZE(0),
  		.buf_end	= VIDW_BUF_END(0),
  
  		.palette = {
  			[0] = 0x2400,
  			[1] = 0x2800,
  			[2] = 0x2c00,
  			[3] = 0x3000,
  			[4] = 0x3400,
  		},
067b226b9   Pawel Osciak   s3c-fb: add suppo...
1776
1777
  
  		.has_prtcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1778
  		.has_clksel	= 1,
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1779
  	},
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1780
1781
1782
1783
1784
  	.win[0]	= &s3c_fb_data_s5p_wins[0],
  	.win[1]	= &s3c_fb_data_s5p_wins[1],
  	.win[2]	= &s3c_fb_data_s5p_wins[2],
  	.win[3]	= &s3c_fb_data_s5p_wins[3],
  	.win[4]	= &s3c_fb_data_s5p_wins[4],
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1785
  };
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1786
  static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1787
1788
  	.variant = {
  		.nr_windows	= 5,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1789
1790
1791
1792
1793
1794
1795
1796
1797
  		.vidtcon	= VIDTCON0,
  		.wincon		= WINCON(0),
  		.winmap		= WINxMAP(0),
  		.keycon		= WKEYCON,
  		.osd		= VIDOSD_BASE,
  		.osd_stride	= 16,
  		.buf_start	= VIDW_BUF_START(0),
  		.buf_size	= VIDW_BUF_SIZE(0),
  		.buf_end	= VIDW_BUF_END(0),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1798
1799
1800
1801
1802
1803
1804
1805
  
  		.palette = {
  			[0] = 0x2400,
  			[1] = 0x2800,
  			[2] = 0x2c00,
  			[3] = 0x3000,
  			[4] = 0x3400,
  		},
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
1806
1807
  
  		.has_shadowcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
  		.has_clksel	= 1,
  	},
  	.win[0]	= &s3c_fb_data_s5p_wins[0],
  	.win[1]	= &s3c_fb_data_s5p_wins[1],
  	.win[2]	= &s3c_fb_data_s5p_wins[2],
  	.win[3]	= &s3c_fb_data_s5p_wins[3],
  	.win[4]	= &s3c_fb_data_s5p_wins[4],
  };
  
  static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
  	.variant = {
  		.nr_windows	= 5,
  		.vidtcon	= VIDTCON0,
  		.wincon		= WINCON(0),
  		.winmap		= WINxMAP(0),
  		.keycon		= WKEYCON,
  		.osd		= VIDOSD_BASE,
  		.osd_stride	= 16,
  		.buf_start	= VIDW_BUF_START(0),
  		.buf_size	= VIDW_BUF_SIZE(0),
  		.buf_end	= VIDW_BUF_END(0),
  
  		.palette = {
  			[0] = 0x2400,
  			[1] = 0x2800,
  			[2] = 0x2c00,
  			[3] = 0x3000,
  			[4] = 0x3400,
  		},
  
  		.has_shadowcon	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1839
  	},
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1840
1841
1842
1843
1844
  	.win[0]	= &s3c_fb_data_s5p_wins[0],
  	.win[1]	= &s3c_fb_data_s5p_wins[1],
  	.win[2]	= &s3c_fb_data_s5p_wins[2],
  	.win[3]	= &s3c_fb_data_s5p_wins[3],
  	.win[4]	= &s3c_fb_data_s5p_wins[4],
50a5503a9   Ben Dooks   s3c-fb: initial m...
1845
  };
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1846
  /* S3C2443/S3C2416 style hardware */
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1847
  static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
  	.variant = {
  		.nr_windows	= 2,
  		.is_2443	= 1,
  
  		.vidtcon	= 0x08,
  		.wincon		= 0x14,
  		.winmap		= 0xd0,
  		.keycon		= 0xb0,
  		.osd		= 0x28,
  		.osd_stride	= 12,
  		.buf_start	= 0x64,
  		.buf_size	= 0x94,
  		.buf_end	= 0x7c,
  
  		.palette = {
  			[0] = 0x400,
  			[1] = 0x800,
  		},
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1866
  		.has_clksel	= 1,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1867
1868
1869
1870
1871
1872
1873
  	},
  	.win[0] = &(struct s3c_fb_win_variant) {
  		.palette_sz	= 256,
  		.valid_bpp	= VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
  	},
  	.win[1] = &(struct s3c_fb_win_variant) {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1874
  		.has_osd_alpha	= 1,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1875
1876
1877
1878
1879
1880
1881
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
  	},
  };
21b5a3adf   Ajay Kumar   video: s3c-fb: Ad...
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
  static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
  	.variant = {
  		.nr_windows	= 3,
  		.vidtcon	= VIDTCON0,
  		.wincon		= WINCON(0),
  		.winmap		= WINxMAP(0),
  		.keycon		= WKEYCON,
  		.osd		= VIDOSD_BASE,
  		.osd_stride	= 16,
  		.buf_start	= VIDW_BUF_START(0),
  		.buf_size	= VIDW_BUF_SIZE(0),
  		.buf_end	= VIDW_BUF_END(0),
  
  		.palette = {
  			[0] = 0x2400,
  			[1] = 0x2800,
  			[2] = 0x2c00,
  		},
  	},
  	.win[0] = &s3c_fb_data_s5p_wins[0],
  	.win[1] = &s3c_fb_data_s5p_wins[1],
  	.win[2] = &s3c_fb_data_s5p_wins[2],
  };
50a5503a9   Ben Dooks   s3c-fb: initial m...
1905
1906
1907
1908
1909
  static struct platform_device_id s3c_fb_driver_ids[] = {
  	{
  		.name		= "s3c-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_64xx,
  	}, {
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1910
1911
1912
1913
1914
  		.name		= "s5pc100-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s5pc100,
  	}, {
  		.name		= "s5pv210-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s5pv210,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1915
  	}, {
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1916
1917
1918
  		.name		= "exynos4-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_exynos4,
  	}, {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1919
1920
  		.name		= "s3c2443-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s3c2443,
21b5a3adf   Ajay Kumar   video: s3c-fb: Ad...
1921
1922
1923
  	}, {
  		.name		= "s5p64x0-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s5p64x0,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1924
1925
1926
1927
  	},
  	{},
  };
  MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1928
1929
1930
1931
1932
1933
  static const struct dev_pm_ops s3cfb_pm_ops = {
  	.suspend	= s3c_fb_suspend,
  	.resume		= s3c_fb_resume,
  	.runtime_suspend	= s3c_fb_runtime_suspend,
  	.runtime_resume		= s3c_fb_runtime_resume,
  };
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1934
1935
  static struct platform_driver s3c_fb_driver = {
  	.probe		= s3c_fb_probe,
3163eaba3   Peter Korsgaard   video: s3c_fb.c: ...
1936
  	.remove		= __devexit_p(s3c_fb_remove),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1937
  	.id_table	= s3c_fb_driver_ids,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1938
1939
1940
  	.driver		= {
  		.name	= "s3c-fb",
  		.owner	= THIS_MODULE,
4959212c1   Jingoo Han   s3c-fb: add suppo...
1941
  		.pm	= &s3cfb_pm_ops,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  	},
  };
  
  static int __init s3c_fb_init(void)
  {
  	return platform_driver_register(&s3c_fb_driver);
  }
  
  static void __exit s3c_fb_cleanup(void)
  {
  	platform_driver_unregister(&s3c_fb_driver);
  }
  
  module_init(s3c_fb_init);
  module_exit(s3c_fb_cleanup);
  
  MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
  MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:s3c-fb");