Blame view

drivers/video/s3c-fb.c 49.8 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
   * @enabled: A bitmask of enabled hardware windows.
f4f514734   Mark Brown   video: s3c-fb: Ta...
189
   * @output_on: Flag if the physical output is enabled.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
190
191
   * @pdata: The platform configuration data passed with the device.
   * @windows: The hardware windows that have been claimed.
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
192
193
194
   * @irq_no: IRQ line number
   * @irq_flags: irq flags
   * @vsync_info: VSYNC-related information (count, queues...)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
195
196
   */
  struct s3c_fb {
b07f3bbee   Jingoo Han   video: s3c-fb: ad...
197
  	spinlock_t		slock;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
198
199
200
  	struct device		*dev;
  	struct resource		*regs_res;
  	struct clk		*bus_clk;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
201
  	struct clk		*lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
202
  	void __iomem		*regs;
50a5503a9   Ben Dooks   s3c-fb: initial m...
203
  	struct s3c_fb_variant	 variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
204
205
  
  	unsigned char		 enabled;
f4f514734   Mark Brown   video: s3c-fb: Ta...
206
  	bool			 output_on;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
207
208
209
  
  	struct s3c_fb_platdata	*pdata;
  	struct s3c_fb_win	*windows[S3C_FB_MAX_WIN];
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
210
211
212
213
  
  	int			 irq_no;
  	unsigned long		 irq_flags;
  	struct s3c_fb_vsync	 vsync_info;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
214
215
216
  };
  
  /**
50a5503a9   Ben Dooks   s3c-fb: initial m...
217
218
219
   * 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...
220
   */
50a5503a9   Ben Dooks   s3c-fb: initial m...
221
  static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
222
  {
50a5503a9   Ben Dooks   s3c-fb: initial m...
223
  	return win->variant.valid_bpp & VALID_BPP(bpp);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  }
  
  /**
   * 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...
238
239
240
241
  	struct s3c_fb *sfb = win->parent;
  
  	dev_dbg(sfb->dev, "checking parameters
  ");
13e6af888   Jingoo Han   video: s3c-fb: fi...
242
243
  	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...
244

50a5503a9   Ben Dooks   s3c-fb: initial m...
245
  	if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  		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...
261
  		if (sfb->variant.palette[win->index] != 0) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
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
302
303
  			/* 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...
304
  	case 32:
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
305
306
307
308
309
310
311
312
  	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...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  		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...
339
  static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
340
  {
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
341
  	unsigned long clk;
eb29a5cc0   Mark Brown   revert "drivers/v...
342
  	unsigned long long tmp;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
343
  	unsigned int result;
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
344
345
346
347
  	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...
348
349
350
351
352
  	tmp = (unsigned long long)clk;
  	tmp *= pixclk;
  
  	do_div(tmp, 1000000000UL);
  	result = (unsigned int)tmp / 1000;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
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
379
380
  
  	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...
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
409
410
   * 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...
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
439
440
   * 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);
  		}
  	}
  }
  
  /**
a2b77dceb   Mark Brown   video: s3c-fb: Us...
441
442
443
444
445
446
447
   * 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);
f4f514734   Mark Brown   video: s3c-fb: Ta...
448
449
450
451
  	if (enable && !sfb->output_on)
  		pm_runtime_get_sync(sfb->dev);
  
  	if (enable) {
a2b77dceb   Mark Brown   video: s3c-fb: Us...
452
  		vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
f4f514734   Mark Brown   video: s3c-fb: Ta...
453
  	} else {
a2b77dceb   Mark Brown   video: s3c-fb: Us...
454
455
456
  		/* see the note in the framebuffer datasheet about
  		 * why you cannot take both of these bits down at the
  		 * same time. */
f4f514734   Mark Brown   video: s3c-fb: Ta...
457
458
459
460
  		if (vidcon0 & VIDCON0_ENVID) {
  			vidcon0 |= VIDCON0_ENVID;
  			vidcon0 &= ~VIDCON0_ENVID_F;
  		}
a2b77dceb   Mark Brown   video: s3c-fb: Us...
461
462
463
  	}
  
  	writel(vidcon0, sfb->regs + VIDCON0);
f4f514734   Mark Brown   video: s3c-fb: Ta...
464
465
466
467
468
  
  	if (!enable && sfb->output_on)
  		pm_runtime_put_sync(sfb->dev);
  
  	sfb->output_on = enable;
a2b77dceb   Mark Brown   video: s3c-fb: Us...
469
470
471
  }
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
472
473
474
475
476
477
478
479
480
481
482
   * 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...
483
  	void __iomem *buf = regs;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
484
  	int win_no = win->index;
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
485
  	u32 alpha = 0;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
486
487
488
489
490
491
  	u32 data;
  	u32 pagewidth;
  	int clkdiv;
  
  	dev_dbg(sfb->dev, "setting framebuffer parameters
  ");
5751b23ef   Mark Brown   video: s3c-fb: Ho...
492
  	pm_runtime_get_sync(sfb->dev);
a8bdabca3   Pawel Osciak   s3c-fb: protect w...
493
  	shadow_protect_win(win, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
494
495
496
497
498
499
500
501
  	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...
502
  		if (win->variant.palette_sz >= 256)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
503
504
505
506
507
508
509
510
511
512
513
514
515
  			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...
516
517
  	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...
518
519
  	/* disable the window whilst we update it */
  	writel(0, regs + WINCON(win_no));
ad04490a1   InKi Dae   s3c-fb: add defau...
520
  	/* use platform specified window as the basis for the lcd timings */
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
521

ad04490a1   InKi Dae   s3c-fb: add defau...
522
  	if (win_no == sfb->pdata->default_win) {
eb29a5cc0   Mark Brown   revert "drivers/v...
523
  		clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
524
525
526
527
528
529
530
531
532
533
  
  		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...
534
535
  		if (sfb->variant.is_2443)
  			data |= (1 << 5);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
536
  		writel(data, regs + VIDCON0);
a2b77dceb   Mark Brown   video: s3c-fb: Us...
537
  		s3c_fb_enable(sfb, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
538
539
540
  		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...
541
  		writel(data, regs + sfb->variant.vidtcon);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
542
543
544
545
  
  		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...
546
547
  		/* VIDTCON1 */
  		writel(data, regs + sfb->variant.vidtcon + 4);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
548
549
550
  
  		data = VIDTCON2_LINEVAL(var->yres - 1) |
  		       VIDTCON2_HOZVAL(var->xres - 1);
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
551
  		writel(data, regs + sfb->variant.vidtcon + 8);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
552
553
554
  	}
  
  	/* write the buffer address */
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
555
556
557
558
  	/* 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...
559
560
  
  	data = info->fix.smem_start + info->fix.line_length * var->yres;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
561
  	writel(data, buf + sfb->variant.buf_end);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
562
563
564
565
  
  	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...
566
  	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
567
568
569
570
  
  	/* write 'OSD' registers to control position of framebuffer */
  
  	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
571
  	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
572
573
574
575
  
  	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...
576
  	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
577
578
  
  	data = var->xres * var->yres;
39000d654   InKi Dae   Samsung SoC Frame...
579

f676ec2a3   Pawel Osciak   s3c-fb: correct w...
580
  	alpha = VIDISD14C_ALPHA1_R(0xf) |
39000d654   InKi Dae   Samsung SoC Frame...
581
582
  		VIDISD14C_ALPHA1_G(0xf) |
  		VIDISD14C_ALPHA1_B(0xf);
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
583
584
  	vidosd_set_alpha(win, alpha);
  	vidosd_set_size(win, data);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
585

fab7c5b77   Jingoo Han   video: s3c-fb: mo...
586
587
588
589
590
591
  	/* 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...
592
  	data = WINCONx_ENWIN;
2d9ae7ac4   Jingoo Han   video: s3c-fb: se...
593
  	sfb->enabled |= (1 << win->index);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  
  	/* 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...
638
639
640
  		} else if (var->transp.length == 1)
  			data |= WINCON1_BPPMODE_25BPP_A1888
  				| WINCON1_BLD_PIX;
4420dd2b3   Jingoo Han   video: s3c-fb: fi...
641
642
  		else if ((var->transp.length == 4) ||
  			(var->transp.length == 8))
39000d654   InKi Dae   Samsung SoC Frame...
643
644
  			data |= WINCON1_BPPMODE_28BPP_A4888
  				| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
645
646
  		else
  			data |= WINCON0_BPPMODE_24BPP_888;
dc8498c00   InKi Dae   s3c-fb: fix disto...
647
  		data |= WINCONx_WSWP;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
648
649
650
  		data |= WINCONx_BURSTLEN_16WORD;
  		break;
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
651
  	/* Enable the colour keying for the window below this one */
39000d654   InKi Dae   Samsung SoC Frame...
652
653
  	if (win_no > 0) {
  		u32 keycon0_data = 0, keycon1_data = 0;
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
654
  		void __iomem *keycon = regs + sfb->variant.keycon;
39000d654   InKi Dae   Samsung SoC Frame...
655
656
657
658
659
660
  
  		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...
661
662
663
664
  		keycon += (win_no - 1) * 8;
  
  		writel(keycon0_data, keycon + WKEYCON0);
  		writel(keycon1_data, keycon + WKEYCON1);
39000d654   InKi Dae   Samsung SoC Frame...
665
  	}
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
666
667
  	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...
668

a8bdabca3   Pawel Osciak   s3c-fb: protect w...
669
  	shadow_protect_win(win, 0);
5751b23ef   Mark Brown   video: s3c-fb: Ho...
670
  	pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  	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...
695
  	palreg = sfb->regs + sfb->variant.palette[win->index];
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
696
697
698
699
700
701
702
703
704
  
  	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...
705
706
  	if (win->variant.palette_16bpp)
  		writew(value, palreg + (reg * 2));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
707
  	else
50a5503a9   Ben Dooks   s3c-fb: initial m...
708
  		writel(value, palreg + (reg * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  
  	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);
5751b23ef   Mark Brown   video: s3c-fb: Ho...
741
  	pm_runtime_get_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  	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...
758
  		if (regno < win->variant.palette_sz) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
759
760
761
762
763
764
765
766
767
768
  			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:
5751b23ef   Mark Brown   video: s3c-fb: Ho...
769
  		pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
770
771
  		return 1;	/* unknown type */
  	}
5751b23ef   Mark Brown   video: s3c-fb: Ho...
772
  	pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
773
774
775
776
  	return 0;
  }
  
  /**
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
   * 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);
5751b23ef   Mark Brown   video: s3c-fb: Ho...
792
  	pm_runtime_get_sync(sfb->dev);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
793
  	wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
794
795
796
797
798
799
800
801
802
  
  	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) */
ff8c91072   Jingoo Han   video: s3c-fb: ad...
803
  		shadow_protect_win(win, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
804
  		writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
805
  		       sfb->regs + sfb->variant.winmap + (index * 4));
ff8c91072   Jingoo Han   video: s3c-fb: ad...
806
  		shadow_protect_win(win, 0);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
807
808
809
  		break;
  
  	case FB_BLANK_UNBLANK:
ff8c91072   Jingoo Han   video: s3c-fb: ad...
810
  		shadow_protect_win(win, 1);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
811
  		writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
ff8c91072   Jingoo Han   video: s3c-fb: ad...
812
  		shadow_protect_win(win, 0);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
813
814
815
816
817
818
819
  		wincon |= WINCONx_ENWIN;
  		sfb->enabled |= (1 << index);
  		break;
  
  	case FB_BLANK_VSYNC_SUSPEND:
  	case FB_BLANK_HSYNC_SUSPEND:
  	default:
5751b23ef   Mark Brown   video: s3c-fb: Ho...
820
  		pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
821
822
  		return 1;
  	}
ff8c91072   Jingoo Han   video: s3c-fb: ad...
823
  	shadow_protect_win(win, 1);
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
824
  	writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
ff8c91072   Jingoo Han   video: s3c-fb: ad...
825
  	shadow_protect_win(win, 0);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
  
  	/* 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.
  	 */
ff8c91072   Jingoo Han   video: s3c-fb: ad...
844
845
  	if (index == sfb->pdata->default_win) {
  		shadow_protect_win(win, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
846
  		s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
ff8c91072   Jingoo Han   video: s3c-fb: ad...
847
848
  		shadow_protect_win(win, 0);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
849

5751b23ef   Mark Brown   video: s3c-fb: Ho...
850
  	pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
851
852
  	return 0;
  }
067b226b9   Pawel Osciak   s3c-fb: add suppo...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  /**
   * 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;
5751b23ef   Mark Brown   video: s3c-fb: Ho...
871
  	pm_runtime_get_sync(sfb->dev);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  	/* 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
  ");
5751b23ef   Mark Brown   video: s3c-fb: Ho...
891
  			pm_runtime_put_sync(sfb->dev);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
892
893
894
895
  			return -EINVAL;
  		}
  	}
  	/* Offset in bytes to the end of the displayed area */
d8e7a74bf   Laurent Pinchart   s3c-fb: use displ...
896
  	end_boff = start_boff + info->var.yres * info->fix.line_length;
067b226b9   Pawel Osciak   s3c-fb: add suppo...
897
898
899
  
  	/* 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...
900
  	shadow_protect_win(win, 1);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
901
902
903
  
  	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...
904
  	shadow_protect_win(win, 0);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
905

5751b23ef   Mark Brown   video: s3c-fb: Ho...
906
  	pm_runtime_put_sync(sfb->dev);
067b226b9   Pawel Osciak   s3c-fb: add suppo...
907
908
  	return 0;
  }
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
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
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  /**
   * 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...
959
  	spin_lock(&sfb->slock);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  	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...
975
  	spin_unlock(&sfb->slock);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  	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;
5751b23ef   Mark Brown   video: s3c-fb: Ho...
991
  	pm_runtime_get_sync(sfb->dev);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
992
993
994
995
996
  	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));
5751b23ef   Mark Brown   video: s3c-fb: Ho...
997
998
  
  	pm_runtime_put_sync(sfb->dev);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
  	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;
  }
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1028
1029
1030
1031
1032
1033
1034
1035
1036
  static struct fb_ops s3c_fb_ops = {
  	.owner		= THIS_MODULE,
  	.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...
1037
  	.fb_pan_display	= s3c_fb_pan_display,
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1038
  	.fb_ioctl	= s3c_fb_ioctl,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1039
1040
1041
  };
  
  /**
2bb567a38   Maurus Cuelenaere   s3c-fb: automatic...
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
   * 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...
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
1118
1119
1120
1121
1122
1123
   * 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...
1124
1125
  	if (fbi->screen_base)
  		dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  			      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...
1138
  	u32 data;
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1139
  	if (win->fbinfo) {
04ab9ef97   Pawel Osciak   s3c-fb: add suppo...
1140
1141
1142
1143
1144
1145
  		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...
1146
  		unregister_framebuffer(win->fbinfo);
cd7d7e024   Pawel Osciak   s3c-fb: fix vario...
1147
1148
  		if (win->fbinfo->cmap.len)
  			fb_dealloc_cmap(&win->fbinfo->cmap);
ddc518d9f   Krzysztof Helt   s3c-fb: fix resou...
1149
1150
1151
  		s3c_fb_free_memory(sfb, win);
  		framebuffer_release(win->fbinfo);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1152
1153
1154
1155
1156
  }
  
  /**
   * s3c_fb_probe_win() - register an hardware window
   * @sfb: The base resources for the hardware
50a5503a9   Ben Dooks   s3c-fb: initial m...
1157
   * @variant: The variant information for this window.
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1158
1159
1160
1161
1162
1163
   * @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...
1164
  				      struct s3c_fb_win_variant *variant,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1165
1166
1167
1168
1169
1170
1171
1172
1173
  				      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...
1174
1175
  	dev_dbg(sfb->dev, "probing window %d, variant %p
  ", win_no, variant);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1176

efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1177
  	init_waitqueue_head(&sfb->vsync_info.wait);
50a5503a9   Ben Dooks   s3c-fb: initial m...
1178
  	palette_size = variant->palette_sz * 4;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
  
  	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...
1196
  	*res = win;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1197
  	var = &fbinfo->var;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1198
  	win->variant = *variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  	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...
1209
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1210
1211
1212
  	}
  
  	/* setup the r/b/g positions for the window's palette */
bc2da1b6f   Ben Dooks   s3c-fb: integrate...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
  	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...
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  
  	/* 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...
1250
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1251
1252
1253
  	}
  
  	/* create initial colour map */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1254
  	ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
  	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...
1272
  		return ret;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1273
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1274
1275
1276
1277
  	dev_info(sfb->dev, "window %d: fb %s
  ", win_no, fbinfo->fix.id);
  
  	return 0;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
  }
  
  /**
   * 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...
1290
  	u32 reg;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1291

c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1292
1293
1294
1295
  	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...
1296
1297
  	reg = readl(regs + SHADOWCON);
  	writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1298
1299
1300
1301
  }
  
  static int __devinit s3c_fb_probe(struct platform_device *pdev)
  {
b73a21fc6   Jingoo Han   video: s3c-fb: fi...
1302
  	const struct platform_device_id *platid;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1303
  	struct s3c_fb_driverdata *fbdrv;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1304
1305
1306
1307
1308
1309
  	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...
1310
1311
  	platid = platform_get_device_id(pdev);
  	fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1312
1313
1314
1315
1316
1317
  
  	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...
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  	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...
1331
1332
  	dev_dbg(dev, "allocate new framebuffer %p
  ", sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1333
1334
  	sfb->dev = dev;
  	sfb->pdata = pd;
50a5503a9   Ben Dooks   s3c-fb: initial m...
1335
  	sfb->variant = fbdrv->variant;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1336

b07f3bbee   Jingoo Han   video: s3c-fb: ad...
1337
  	spin_lock_init(&sfb->slock);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1338
1339
1340
1341
  	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...
1342
  		ret = PTR_ERR(sfb->bus_clk);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1343
1344
1345
1346
  		goto err_sfb;
  	}
  
  	clk_enable(sfb->bus_clk);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
  	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...
1358
  	pm_runtime_enable(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1359
1360
1361
1362
1363
  	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...
1364
  		goto err_lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1365
1366
1367
1368
1369
1370
1371
1372
  	}
  
  	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...
1373
  		goto err_lcd_clk;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1374
1375
1376
1377
1378
1379
1380
1381
1382
  	}
  
  	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 ...
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
  	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...
1398
1399
  	dev_dbg(dev, "got resources (regs %p), probing windows
  ", sfb->regs);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1400
1401
  	platform_set_drvdata(pdev, sfb);
  	pm_runtime_get_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1402
1403
1404
1405
1406
1407
1408
  	/* 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...
1409
  	for (win = 0; win < fbdrv->variant.nr_windows; win++)
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1410
  		s3c_fb_clear_win(sfb, win);
949470375   Ben Dooks   s3c-fb: only init...
1411
  	/* initialise colour key controls */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1412
  	for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1413
1414
1415
1416
1417
  		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...
1418
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1419
  	/* we have the register setup, start allocating framebuffers */
50a5503a9   Ben Dooks   s3c-fb: initial m...
1420
  	for (win = 0; win < fbdrv->variant.nr_windows; win++) {
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1421
1422
  		if (!pd->win[win])
  			continue;
2bb567a38   Maurus Cuelenaere   s3c-fb: automatic...
1423
1424
  		if (!pd->win[win]->win_mode.pixclock)
  			s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
50a5503a9   Ben Dooks   s3c-fb: initial m...
1425
1426
  		ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
  				       &sfb->windows[win]);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1427
1428
1429
1430
1431
  		if (ret < 0) {
  			dev_err(dev, "failed to create window %d
  ", win);
  			for (; win >= 0; win--)
  				s3c_fb_release_win(sfb, sfb->windows[win]);
3500b0be6   Mark Brown   video: s3c-fb: Di...
1432
  			goto err_pm_runtime;
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1433
1434
1435
1436
  		}
  	}
  
  	platform_set_drvdata(pdev, sfb);
fe05f8b1c   Mark Brown   video: s3c-fb: Ma...
1437
  	pm_runtime_put_sync(sfb->dev);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1438
1439
  
  	return 0;
3500b0be6   Mark Brown   video: s3c-fb: Di...
1440
1441
  err_pm_runtime:
  	pm_runtime_put_sync(sfb->dev);
efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1442
  	free_irq(sfb->irq_no, sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1443
1444
1445
1446
  err_ioremap:
  	iounmap(sfb->regs);
  
  err_req_region:
683e7cdc2   Julia Lawall   drivers/video: Co...
1447
  	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1448

b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1449
  err_lcd_clk:
3500b0be6   Mark Brown   video: s3c-fb: Di...
1450
  	pm_runtime_disable(sfb->dev);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1451
1452
1453
1454
1455
1456
  	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...
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  	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;
fe05f8b1c   Mark Brown   video: s3c-fb: Ma...
1476
  	pm_runtime_get_sync(sfb->dev);
c42b110ca   Pawel Osciak   s3c-fb: fix off-b...
1477
  	for (win = 0; win < S3C_FB_MAX_WIN; win++)
17663e597   Marek Szyprowski   S3C-fb: PM fix
1478
1479
  		if (sfb->windows[win])
  			s3c_fb_release_win(sfb, sfb->windows[win]);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1480

efdc846d2   Pawel Osciak   s3c-fb: add wait ...
1481
  	free_irq(sfb->irq_no, sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1482
  	iounmap(sfb->regs);
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1483
1484
1485
1486
  	if (!sfb->variant.has_clksel) {
  		clk_disable(sfb->lcd_clk);
  		clk_put(sfb->lcd_clk);
  	}
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1487
1488
  	clk_disable(sfb->bus_clk);
  	clk_put(sfb->bus_clk);
683e7cdc2   Julia Lawall   drivers/video: Co...
1489
  	release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1490

4959212c1   Jingoo Han   s3c-fb: add suppo...
1491
1492
  	pm_runtime_put_sync(sfb->dev);
  	pm_runtime_disable(sfb->dev);
72ba4cb60   Jingoo Han   video: s3c-fb: fi...
1493
  	kfree(sfb);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1494
1495
  	return 0;
  }
f4f514734   Mark Brown   video: s3c-fb: Ta...
1496
  #ifdef CONFIG_PM_SLEEP
4959212c1   Jingoo Han   s3c-fb: add suppo...
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  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...
1512
1513
  	if (!sfb->variant.has_clksel)
  		clk_disable(sfb->lcd_clk);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
  	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...
1527
1528
  	if (!sfb->variant.has_clksel)
  		clk_enable(sfb->lcd_clk);
6aa968110   Jingoo Han   video: s3c-fb: ad...
1529
1530
  	/* setup gpio and output polarity controls */
  	pd->setup_gpio();
4959212c1   Jingoo Han   s3c-fb: add suppo...
1531
1532
1533
1534
1535
1536
1537
1538
  	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;
ff8c91072   Jingoo Han   video: s3c-fb: ad...
1539
1540
1541
  		win = sfb->windows[win_no];
  		if (!win)
  			continue;
4959212c1   Jingoo Han   s3c-fb: add suppo...
1542

ff8c91072   Jingoo Han   video: s3c-fb: ad...
1543
  		shadow_protect_win(win, 1);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1544
1545
1546
  		regs += (win_no * 8);
  		writel(0xffffff, regs + WKEYCON0);
  		writel(0xffffff, regs + WKEYCON1);
ff8c91072   Jingoo Han   video: s3c-fb: ad...
1547
  		shadow_protect_win(win, 0);
4959212c1   Jingoo Han   s3c-fb: add suppo...
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  	}
  
  	/* 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;
  }
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1563
  #endif
f4f514734   Mark Brown   video: s3c-fb: Ta...
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
  #ifdef CONFIG_PM_RUNTIME
  static int s3c_fb_runtime_suspend(struct device *dev)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct s3c_fb *sfb = platform_get_drvdata(pdev);
  
  	if (!sfb->variant.has_clksel)
  		clk_disable(sfb->lcd_clk);
  
  	clk_disable(sfb->bus_clk);
  
  	return 0;
  }
  
  static int s3c_fb_runtime_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;
  
  	clk_enable(sfb->bus_clk);
  
  	if (!sfb->variant.has_clksel)
  		clk_enable(sfb->lcd_clk);
  
  	/* setup gpio and output polarity controls */
  	pd->setup_gpio();
  	writel(pd->vidcon1, sfb->regs + VIDCON1);
  
  	return 0;
  }
  #endif
50a5503a9   Ben Dooks   s3c-fb: initial m...
1596
1597
1598
  
  #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...
1599
  static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1600
1601
  	[0] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1602
  		.osd_size_off	= 0x8,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1603
  		.palette_sz	= 256,
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1604
1605
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(24)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1606
1607
1608
1609
  	},
  	[1] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
c9d503e93   Jingoo Han   video: s3c-fb: co...
1610
  		.osd_size_off	= 0xc,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1611
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1612
1613
1614
  		.palette_sz	= 256,
  		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
  				   VALID_BPP(18) | VALID_BPP(19) |
cd74ebaf7   Jingoo Han   video: s3c-fb: ad...
1615
1616
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1617
1618
1619
1620
  	},
  	[2] = {
  		.has_osd_c	= 1,
  		.has_osd_d	= 1,
c9d503e93   Jingoo Han   video: s3c-fb: co...
1621
  		.osd_size_off	= 0xc,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1622
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1623
1624
1625
1626
  		.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...
1627
1628
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1629
1630
1631
  	},
  	[3] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1632
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1633
1634
1635
1636
  		.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...
1637
1638
  				   VALID_BPP(24) | VALID_BPP(25) |
  				   VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1639
1640
1641
  	},
  	[4] = {
  		.has_osd_c	= 1,
f676ec2a3   Pawel Osciak   s3c-fb: correct w...
1642
  		.has_osd_alpha	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1643
1644
1645
1646
  		.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...
1647
1648
  				   VALID_BPP(19) | VALID_BPP(24) |
  				   VALID_BPP(25) | VALID_BPP(28)),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1649
1650
  	},
  };
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
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
  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...
1707
  static struct s3c_fb_driverdata s3c_fb_data_64xx = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1708
1709
  	.variant = {
  		.nr_windows	= 5,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1710
1711
1712
1713
1714
1715
1716
1717
1718
  		.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...
1719
1720
1721
1722
1723
1724
1725
1726
  
  		.palette = {
  			[0] = 0x400,
  			[1] = 0x800,
  			[2] = 0x300,
  			[3] = 0x320,
  			[4] = 0x340,
  		},
067b226b9   Pawel Osciak   s3c-fb: add suppo...
1727
1728
  
  		.has_prtcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1729
  		.has_clksel	= 1,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1730
1731
1732
1733
1734
1735
1736
  	},
  	.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...
1737
  static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
  	.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...
1757
1758
  
  		.has_prtcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1759
  		.has_clksel	= 1,
4e591ac62   Pawel Osciak   s3c-fb: separate ...
1760
  	},
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1761
1762
1763
1764
1765
  	.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 ...
1766
  };
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1767
  static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
50a5503a9   Ben Dooks   s3c-fb: initial m...
1768
1769
  	.variant = {
  		.nr_windows	= 5,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1770
1771
1772
1773
1774
1775
1776
1777
1778
  		.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...
1779
1780
1781
1782
1783
1784
1785
1786
  
  		.palette = {
  			[0] = 0x2400,
  			[1] = 0x2800,
  			[2] = 0x2c00,
  			[3] = 0x3000,
  			[4] = 0x3400,
  		},
f5ec546f1   Pawel Osciak   s3c-fb: add SHADO...
1787
1788
  
  		.has_shadowcon	= 1,
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  		.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...
1820
  	},
af4a835bb   Jingoo Han   video: s3c-fb: ad...
1821
1822
1823
1824
1825
  	.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...
1826
  };
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1827
  /* S3C2443/S3C2416 style hardware */
8cfdcb239   Marek Szyprowski   s3c-fb: fix secti...
1828
  static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
  	.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...
1847
  		.has_clksel	= 1,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1848
1849
1850
1851
1852
1853
1854
  	},
  	.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...
1855
  		.has_osd_alpha	= 1,
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1856
1857
1858
1859
1860
1861
1862
  		.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...
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
  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...
1886
1887
1888
1889
1890
  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 ...
1891
1892
1893
1894
1895
  		.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...
1896
  	}, {
b5480ed72   Jingoo Han   video: s3c-fb: Ad...
1897
1898
1899
  		.name		= "exynos4-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_exynos4,
  	}, {
c4bb6ffa7   Ben Dooks   s3c-fb: udpate to...
1900
1901
  		.name		= "s3c2443-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s3c2443,
21b5a3adf   Ajay Kumar   video: s3c-fb: Ad...
1902
1903
1904
  	}, {
  		.name		= "s5p64x0-fb",
  		.driver_data	= (unsigned long)&s3c_fb_data_s5p64x0,
50a5503a9   Ben Dooks   s3c-fb: initial m...
1905
1906
1907
1908
  	},
  	{},
  };
  MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
f4f514734   Mark Brown   video: s3c-fb: Ta...
1909
1910
1911
1912
1913
  static const struct dev_pm_ops s3cfb_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
  	SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
  			   NULL)
  };
4959212c1   Jingoo Han   s3c-fb: add suppo...
1914

ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1915
1916
  static struct platform_driver s3c_fb_driver = {
  	.probe		= s3c_fb_probe,
3163eaba3   Peter Korsgaard   video: s3c_fb.c: ...
1917
  	.remove		= __devexit_p(s3c_fb_remove),
50a5503a9   Ben Dooks   s3c-fb: initial m...
1918
  	.id_table	= s3c_fb_driver_ids,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1919
1920
1921
  	.driver		= {
  		.name	= "s3c-fb",
  		.owner	= THIS_MODULE,
fe05f8b1c   Mark Brown   video: s3c-fb: Ma...
1922
  		.pm	= &s3cfb_pm_ops,
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1923
1924
  	},
  };
4277f2c46   Axel Lin   video: convert dr...
1925
  module_platform_driver(s3c_fb_driver);
ec549a0fd   Ben Dooks   fb: add s3c-fb dr...
1926
1927
1928
1929
1930
  
  MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
  MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:s3c-fb");