~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/video/s3c-fb.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* linux/drivers/video/s3c-fb.c
 
2
 *
 
3
 * Copyright 2008 Openmoko Inc.
 
4
 * Copyright 2008-2010 Simtec Electronics
 
5
 *      Ben Dooks <ben@simtec.co.uk>
 
6
 *      http://armlinux.simtec.co.uk/
 
7
 *
 
8
 * Samsung SoC Framebuffer driver
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License version 2 as
 
12
 * published by the Free Software FoundatIon.
 
13
*/
 
14
 
 
15
#include <linux/kernel.h>
 
16
#include <linux/module.h>
 
17
#include <linux/platform_device.h>
 
18
#include <linux/dma-mapping.h>
 
19
#include <linux/slab.h>
 
20
#include <linux/init.h>
 
21
#include <linux/clk.h>
 
22
#include <linux/fb.h>
 
23
#include <linux/io.h>
 
24
#include <linux/uaccess.h>
 
25
#include <linux/interrupt.h>
 
26
#include <linux/pm_runtime.h>
 
27
 
 
28
#include <mach/map.h>
 
29
#include <plat/regs-fb-v4.h>
 
30
#include <plat/fb.h>
 
31
 
 
32
/* This driver will export a number of framebuffer interfaces depending
 
33
 * on the configuration passed in via the platform data. Each fb instance
 
34
 * maps to a hardware window. Currently there is no support for runtime
 
35
 * setting of the alpha-blending functions that each window has, so only
 
36
 * window 0 is actually useful.
 
37
 *
 
38
 * Window 0 is treated specially, it is used for the basis of the LCD
 
39
 * output timings and as the control for the output power-down state.
 
40
*/
 
41
 
 
42
/* note, the previous use of <mach/regs-fb.h> to get platform specific data
 
43
 * has been replaced by using the platform device name to pick the correct
 
44
 * configuration data for the system.
 
45
*/
 
46
 
 
47
#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
 
48
#undef writel
 
49
#define writel(v, r) do { \
 
50
        printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
 
51
        __raw_writel(v, r); } while (0)
 
52
#endif /* FB_S3C_DEBUG_REGWRITE */
 
53
 
 
54
/* irq_flags bits */
 
55
#define S3C_FB_VSYNC_IRQ_EN     0
 
56
 
 
57
#define VSYNC_TIMEOUT_MSEC 50
 
58
 
 
59
struct s3c_fb;
 
60
 
 
61
#define VALID_BPP(x) (1 << ((x) - 1))
 
62
 
 
63
#define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
 
64
#define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
 
65
#define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
 
66
#define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
 
67
#define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
 
68
 
 
69
/**
 
70
 * struct s3c_fb_variant - fb variant information
 
71
 * @is_2443: Set if S3C2443/S3C2416 style hardware.
 
72
 * @nr_windows: The number of windows.
 
73
 * @vidtcon: The base for the VIDTCONx registers
 
74
 * @wincon: The base for the WINxCON registers.
 
75
 * @winmap: The base for the WINxMAP registers.
 
76
 * @keycon: The abse for the WxKEYCON registers.
 
77
 * @buf_start: Offset of buffer start registers.
 
78
 * @buf_size: Offset of buffer size registers.
 
79
 * @buf_end: Offset of buffer end registers.
 
80
 * @osd: The base for the OSD registers.
 
81
 * @palette: Address of palette memory, or 0 if none.
 
82
 * @has_prtcon: Set if has PRTCON register.
 
83
 * @has_shadowcon: Set if has SHADOWCON register.
 
84
 * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
 
85
 */
 
86
struct s3c_fb_variant {
 
87
        unsigned int    is_2443:1;
 
88
        unsigned short  nr_windows;
 
89
        unsigned short  vidtcon;
 
90
        unsigned short  wincon;
 
91
        unsigned short  winmap;
 
92
        unsigned short  keycon;
 
93
        unsigned short  buf_start;
 
94
        unsigned short  buf_end;
 
95
        unsigned short  buf_size;
 
96
        unsigned short  osd;
 
97
        unsigned short  osd_stride;
 
98
        unsigned short  palette[S3C_FB_MAX_WIN];
 
99
 
 
100
        unsigned int    has_prtcon:1;
 
101
        unsigned int    has_shadowcon:1;
 
102
        unsigned int    has_clksel:1;
 
103
};
 
104
 
 
105
/**
 
106
 * struct s3c_fb_win_variant
 
107
 * @has_osd_c: Set if has OSD C register.
 
108
 * @has_osd_d: Set if has OSD D register.
 
109
 * @has_osd_alpha: Set if can change alpha transparency for a window.
 
110
 * @palette_sz: Size of palette in entries.
 
111
 * @palette_16bpp: Set if palette is 16bits wide.
 
112
 * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
 
113
 *                register is located at the given offset from OSD_BASE.
 
114
 * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
 
115
 *
 
116
 * valid_bpp bit x is set if (x+1)BPP is supported.
 
117
 */
 
118
struct s3c_fb_win_variant {
 
119
        unsigned int    has_osd_c:1;
 
120
        unsigned int    has_osd_d:1;
 
121
        unsigned int    has_osd_alpha:1;
 
122
        unsigned int    palette_16bpp:1;
 
123
        unsigned short  osd_size_off;
 
124
        unsigned short  palette_sz;
 
125
        u32             valid_bpp;
 
126
};
 
127
 
 
128
/**
 
129
 * struct s3c_fb_driverdata - per-device type driver data for init time.
 
130
 * @variant: The variant information for this driver.
 
131
 * @win: The window information for each window.
 
132
 */
 
133
struct s3c_fb_driverdata {
 
134
        struct s3c_fb_variant   variant;
 
135
        struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
 
136
};
 
137
 
 
138
/**
 
139
 * struct s3c_fb_palette - palette information
 
140
 * @r: Red bitfield.
 
141
 * @g: Green bitfield.
 
142
 * @b: Blue bitfield.
 
143
 * @a: Alpha bitfield.
 
144
 */
 
145
struct s3c_fb_palette {
 
146
        struct fb_bitfield      r;
 
147
        struct fb_bitfield      g;
 
148
        struct fb_bitfield      b;
 
149
        struct fb_bitfield      a;
 
150
};
 
151
 
 
152
/**
 
153
 * struct s3c_fb_win - per window private data for each framebuffer.
 
154
 * @windata: The platform data supplied for the window configuration.
 
155
 * @parent: The hardware that this window is part of.
 
156
 * @fbinfo: Pointer pack to the framebuffer info for this window.
 
157
 * @varint: The variant information for this window.
 
158
 * @palette_buffer: Buffer/cache to hold palette entries.
 
159
 * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
 
160
 * @index: The window number of this window.
 
161
 * @palette: The bitfields for changing r/g/b into a hardware palette entry.
 
162
 */
 
163
struct s3c_fb_win {
 
164
        struct s3c_fb_pd_win    *windata;
 
165
        struct s3c_fb           *parent;
 
166
        struct fb_info          *fbinfo;
 
167
        struct s3c_fb_palette    palette;
 
168
        struct s3c_fb_win_variant variant;
 
169
 
 
170
        u32                     *palette_buffer;
 
171
        u32                      pseudo_palette[16];
 
172
        unsigned int             index;
 
173
};
 
174
 
 
175
/**
 
176
 * struct s3c_fb_vsync - vsync information
 
177
 * @wait:       a queue for processes waiting for vsync
 
178
 * @count:      vsync interrupt count
 
179
 */
 
180
struct s3c_fb_vsync {
 
181
        wait_queue_head_t       wait;
 
182
        unsigned int            count;
 
183
};
 
184
 
 
185
/**
 
186
 * struct s3c_fb - overall hardware state of the hardware
 
187
 * @slock: The spinlock protection for this data sturcture.
 
188
 * @dev: The device that we bound to, for printing, etc.
 
189
 * @regs_res: The resource we claimed for the IO registers.
 
190
 * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
 
191
 * @lcd_clk: The clk (sclk) feeding pixclk.
 
192
 * @regs: The mapped hardware registers.
 
193
 * @variant: Variant information for this hardware.
 
194
 * @enabled: A bitmask of enabled hardware windows.
 
195
 * @pdata: The platform configuration data passed with the device.
 
196
 * @windows: The hardware windows that have been claimed.
 
197
 * @irq_no: IRQ line number
 
198
 * @irq_flags: irq flags
 
199
 * @vsync_info: VSYNC-related information (count, queues...)
 
200
 */
 
201
struct s3c_fb {
 
202
        spinlock_t              slock;
 
203
        struct device           *dev;
 
204
        struct resource         *regs_res;
 
205
        struct clk              *bus_clk;
 
206
        struct clk              *lcd_clk;
 
207
        void __iomem            *regs;
 
208
        struct s3c_fb_variant    variant;
 
209
 
 
210
        unsigned char            enabled;
 
211
 
 
212
        struct s3c_fb_platdata  *pdata;
 
213
        struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
 
214
 
 
215
        int                      irq_no;
 
216
        unsigned long            irq_flags;
 
217
        struct s3c_fb_vsync      vsync_info;
 
218
};
 
219
 
 
220
/**
 
221
 * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
 
222
 * @win: The device window.
 
223
 * @bpp: The bit depth.
 
224
 */
 
225
static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
 
226
{
 
227
        return win->variant.valid_bpp & VALID_BPP(bpp);
 
228
}
 
229
 
 
230
/**
 
231
 * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
 
232
 * @var: The screen information to verify.
 
233
 * @info: The framebuffer device.
 
234
 *
 
235
 * Framebuffer layer call to verify the given information and allow us to
 
236
 * update various information depending on the hardware capabilities.
 
237
 */
 
238
static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 
239
                            struct fb_info *info)
 
240
{
 
241
        struct s3c_fb_win *win = info->par;
 
242
        struct s3c_fb *sfb = win->parent;
 
243
 
 
244
        dev_dbg(sfb->dev, "checking parameters\n");
 
245
 
 
246
        var->xres_virtual = max(var->xres_virtual, var->xres);
 
247
        var->yres_virtual = max(var->yres_virtual, var->yres);
 
248
 
 
249
        if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
 
250
                dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
 
251
                        win->index, var->bits_per_pixel);
 
252
                return -EINVAL;
 
253
        }
 
254
 
 
255
        /* always ensure these are zero, for drop through cases below */
 
256
        var->transp.offset = 0;
 
257
        var->transp.length = 0;
 
258
 
 
259
        switch (var->bits_per_pixel) {
 
260
        case 1:
 
261
        case 2:
 
262
        case 4:
 
263
        case 8:
 
264
                if (sfb->variant.palette[win->index] != 0) {
 
265
                        /* non palletised, A:1,R:2,G:3,B:2 mode */
 
266
                        var->red.offset         = 4;
 
267
                        var->green.offset       = 2;
 
268
                        var->blue.offset        = 0;
 
269
                        var->red.length         = 5;
 
270
                        var->green.length       = 3;
 
271
                        var->blue.length        = 2;
 
272
                        var->transp.offset      = 7;
 
273
                        var->transp.length      = 1;
 
274
                } else {
 
275
                        var->red.offset = 0;
 
276
                        var->red.length = var->bits_per_pixel;
 
277
                        var->green      = var->red;
 
278
                        var->blue       = var->red;
 
279
                }
 
280
                break;
 
281
 
 
282
        case 19:
 
283
                /* 666 with one bit alpha/transparency */
 
284
                var->transp.offset      = 18;
 
285
                var->transp.length      = 1;
 
286
        case 18:
 
287
                var->bits_per_pixel     = 32;
 
288
 
 
289
                /* 666 format */
 
290
                var->red.offset         = 12;
 
291
                var->green.offset       = 6;
 
292
                var->blue.offset        = 0;
 
293
                var->red.length         = 6;
 
294
                var->green.length       = 6;
 
295
                var->blue.length        = 6;
 
296
                break;
 
297
 
 
298
        case 16:
 
299
                /* 16 bpp, 565 format */
 
300
                var->red.offset         = 11;
 
301
                var->green.offset       = 5;
 
302
                var->blue.offset        = 0;
 
303
                var->red.length         = 5;
 
304
                var->green.length       = 6;
 
305
                var->blue.length        = 5;
 
306
                break;
 
307
 
 
308
        case 32:
 
309
        case 28:
 
310
        case 25:
 
311
                var->transp.length      = var->bits_per_pixel - 24;
 
312
                var->transp.offset      = 24;
 
313
                /* drop through */
 
314
        case 24:
 
315
                /* our 24bpp is unpacked, so 32bpp */
 
316
                var->bits_per_pixel     = 32;
 
317
                var->red.offset         = 16;
 
318
                var->red.length         = 8;
 
319
                var->green.offset       = 8;
 
320
                var->green.length       = 8;
 
321
                var->blue.offset        = 0;
 
322
                var->blue.length        = 8;
 
323
                break;
 
324
 
 
325
        default:
 
326
                dev_err(sfb->dev, "invalid bpp\n");
 
327
        }
 
328
 
 
329
        dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
 
330
        return 0;
 
331
}
 
332
 
 
333
/**
 
334
 * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
 
335
 * @sfb: The hardware state.
 
336
 * @pixclock: The pixel clock wanted, in picoseconds.
 
337
 *
 
338
 * Given the specified pixel clock, work out the necessary divider to get
 
339
 * close to the output frequency.
 
340
 */
 
341
static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
 
342
{
 
343
        unsigned long clk;
 
344
        unsigned long long tmp;
 
345
        unsigned int result;
 
346
 
 
347
        if (sfb->variant.has_clksel)
 
348
                clk = clk_get_rate(sfb->bus_clk);
 
349
        else
 
350
                clk = clk_get_rate(sfb->lcd_clk);
 
351
 
 
352
        tmp = (unsigned long long)clk;
 
353
        tmp *= pixclk;
 
354
 
 
355
        do_div(tmp, 1000000000UL);
 
356
        result = (unsigned int)tmp / 1000;
 
357
 
 
358
        dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
 
359
                pixclk, clk, result, clk / result);
 
360
 
 
361
        return result;
 
362
}
 
363
 
 
364
/**
 
365
 * s3c_fb_align_word() - align pixel count to word boundary
 
366
 * @bpp: The number of bits per pixel
 
367
 * @pix: The value to be aligned.
 
368
 *
 
369
 * Align the given pixel count so that it will start on an 32bit word
 
370
 * boundary.
 
371
 */
 
372
static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
 
373
{
 
374
        int pix_per_word;
 
375
 
 
376
        if (bpp > 16)
 
377
                return pix;
 
378
 
 
379
        pix_per_word = (8 * 32) / bpp;
 
380
        return ALIGN(pix, pix_per_word);
 
381
}
 
382
 
 
383
/**
 
384
 * vidosd_set_size() - set OSD size for a window
 
385
 *
 
386
 * @win: the window to set OSD size for
 
387
 * @size: OSD size register value
 
388
 */
 
389
static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
 
390
{
 
391
        struct s3c_fb *sfb = win->parent;
 
392
 
 
393
        /* OSD can be set up if osd_size_off != 0 for this window */
 
394
        if (win->variant.osd_size_off)
 
395
                writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
 
396
                                + win->variant.osd_size_off);
 
397
}
 
398
 
 
399
/**
 
400
 * vidosd_set_alpha() - set alpha transparency for a window
 
401
 *
 
402
 * @win: the window to set OSD size for
 
403
 * @alpha: alpha register value
 
404
 */
 
405
static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
 
406
{
 
407
        struct s3c_fb *sfb = win->parent;
 
408
 
 
409
        if (win->variant.has_osd_alpha)
 
410
                writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
 
411
}
 
412
 
 
413
/**
 
414
 * shadow_protect_win() - disable updating values from shadow registers at vsync
 
415
 *
 
416
 * @win: window to protect registers for
 
417
 * @protect: 1 to protect (disable updates)
 
418
 */
 
419
static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
 
420
{
 
421
        struct s3c_fb *sfb = win->parent;
 
422
        u32 reg;
 
423
 
 
424
        if (protect) {
 
425
                if (sfb->variant.has_prtcon) {
 
426
                        writel(PRTCON_PROTECT, sfb->regs + PRTCON);
 
427
                } else if (sfb->variant.has_shadowcon) {
 
428
                        reg = readl(sfb->regs + SHADOWCON);
 
429
                        writel(reg | SHADOWCON_WINx_PROTECT(win->index),
 
430
                                sfb->regs + SHADOWCON);
 
431
                }
 
432
        } else {
 
433
                if (sfb->variant.has_prtcon) {
 
434
                        writel(0, sfb->regs + PRTCON);
 
435
                } else if (sfb->variant.has_shadowcon) {
 
436
                        reg = readl(sfb->regs + SHADOWCON);
 
437
                        writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
 
438
                                sfb->regs + SHADOWCON);
 
439
                }
 
440
        }
 
441
}
 
442
 
 
443
/**
 
444
 * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
 
445
 * @info: The framebuffer to change.
 
446
 *
 
447
 * Framebuffer layer request to set a new mode for the specified framebuffer
 
448
 */
 
449
static int s3c_fb_set_par(struct fb_info *info)
 
450
{
 
451
        struct fb_var_screeninfo *var = &info->var;
 
452
        struct s3c_fb_win *win = info->par;
 
453
        struct s3c_fb *sfb = win->parent;
 
454
        void __iomem *regs = sfb->regs;
 
455
        void __iomem *buf = regs;
 
456
        int win_no = win->index;
 
457
        u32 alpha = 0;
 
458
        u32 data;
 
459
        u32 pagewidth;
 
460
        int clkdiv;
 
461
 
 
462
        dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
463
 
 
464
        shadow_protect_win(win, 1);
 
465
 
 
466
        switch (var->bits_per_pixel) {
 
467
        case 32:
 
468
        case 24:
 
469
        case 16:
 
470
        case 12:
 
471
                info->fix.visual = FB_VISUAL_TRUECOLOR;
 
472
                break;
 
473
        case 8:
 
474
                if (win->variant.palette_sz >= 256)
 
475
                        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 
476
                else
 
477
                        info->fix.visual = FB_VISUAL_TRUECOLOR;
 
478
                break;
 
479
        case 1:
 
480
                info->fix.visual = FB_VISUAL_MONO01;
 
481
                break;
 
482
        default:
 
483
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 
484
                break;
 
485
        }
 
486
 
 
487
        info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
 
488
 
 
489
        info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
 
490
        info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
 
491
 
 
492
        /* disable the window whilst we update it */
 
493
        writel(0, regs + WINCON(win_no));
 
494
 
 
495
        /* use platform specified window as the basis for the lcd timings */
 
496
 
 
497
        if (win_no == sfb->pdata->default_win) {
 
498
                clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
 
499
 
 
500
                data = sfb->pdata->vidcon0;
 
501
                data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
 
502
 
 
503
                if (clkdiv > 1)
 
504
                        data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
 
505
                else
 
506
                        data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
 
507
 
 
508
                /* write the timing data to the panel */
 
509
 
 
510
                if (sfb->variant.is_2443)
 
511
                        data |= (1 << 5);
 
512
 
 
513
                data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
 
514
                writel(data, regs + VIDCON0);
 
515
 
 
516
                data = VIDTCON0_VBPD(var->upper_margin - 1) |
 
517
                       VIDTCON0_VFPD(var->lower_margin - 1) |
 
518
                       VIDTCON0_VSPW(var->vsync_len - 1);
 
519
 
 
520
                writel(data, regs + sfb->variant.vidtcon);
 
521
 
 
522
                data = VIDTCON1_HBPD(var->left_margin - 1) |
 
523
                       VIDTCON1_HFPD(var->right_margin - 1) |
 
524
                       VIDTCON1_HSPW(var->hsync_len - 1);
 
525
 
 
526
                /* VIDTCON1 */
 
527
                writel(data, regs + sfb->variant.vidtcon + 4);
 
528
 
 
529
                data = VIDTCON2_LINEVAL(var->yres - 1) |
 
530
                       VIDTCON2_HOZVAL(var->xres - 1);
 
531
                writel(data, regs + sfb->variant.vidtcon + 8);
 
532
        }
 
533
 
 
534
        /* write the buffer address */
 
535
 
 
536
        /* start and end registers stride is 8 */
 
537
        buf = regs + win_no * 8;
 
538
 
 
539
        writel(info->fix.smem_start, buf + sfb->variant.buf_start);
 
540
 
 
541
        data = info->fix.smem_start + info->fix.line_length * var->yres;
 
542
        writel(data, buf + sfb->variant.buf_end);
 
543
 
 
544
        pagewidth = (var->xres * var->bits_per_pixel) >> 3;
 
545
        data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
 
546
               VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
 
547
        writel(data, regs + sfb->variant.buf_size + (win_no * 4));
 
548
 
 
549
        /* write 'OSD' registers to control position of framebuffer */
 
550
 
 
551
        data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
 
552
        writel(data, regs + VIDOSD_A(win_no, sfb->variant));
 
553
 
 
554
        data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
 
555
                                                     var->xres - 1)) |
 
556
               VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
 
557
 
 
558
        writel(data, regs + VIDOSD_B(win_no, sfb->variant));
 
559
 
 
560
        data = var->xres * var->yres;
 
561
 
 
562
        alpha = VIDISD14C_ALPHA1_R(0xf) |
 
563
                VIDISD14C_ALPHA1_G(0xf) |
 
564
                VIDISD14C_ALPHA1_B(0xf);
 
565
 
 
566
        vidosd_set_alpha(win, alpha);
 
567
        vidosd_set_size(win, data);
 
568
 
 
569
        /* Enable DMA channel for this window */
 
570
        if (sfb->variant.has_shadowcon) {
 
571
                data = readl(sfb->regs + SHADOWCON);
 
572
                data |= SHADOWCON_CHx_ENABLE(win_no);
 
573
                writel(data, sfb->regs + SHADOWCON);
 
574
        }
 
575
 
 
576
        data = WINCONx_ENWIN;
 
577
 
 
578
        /* note, since we have to round up the bits-per-pixel, we end up
 
579
         * relying on the bitfield information for r/g/b/a to work out
 
580
         * exactly which mode of operation is intended. */
 
581
 
 
582
        switch (var->bits_per_pixel) {
 
583
        case 1:
 
584
                data |= WINCON0_BPPMODE_1BPP;
 
585
                data |= WINCONx_BITSWP;
 
586
                data |= WINCONx_BURSTLEN_4WORD;
 
587
                break;
 
588
        case 2:
 
589
                data |= WINCON0_BPPMODE_2BPP;
 
590
                data |= WINCONx_BITSWP;
 
591
                data |= WINCONx_BURSTLEN_8WORD;
 
592
                break;
 
593
        case 4:
 
594
                data |= WINCON0_BPPMODE_4BPP;
 
595
                data |= WINCONx_BITSWP;
 
596
                data |= WINCONx_BURSTLEN_8WORD;
 
597
                break;
 
598
        case 8:
 
599
                if (var->transp.length != 0)
 
600
                        data |= WINCON1_BPPMODE_8BPP_1232;
 
601
                else
 
602
                        data |= WINCON0_BPPMODE_8BPP_PALETTE;
 
603
                data |= WINCONx_BURSTLEN_8WORD;
 
604
                data |= WINCONx_BYTSWP;
 
605
                break;
 
606
        case 16:
 
607
                if (var->transp.length != 0)
 
608
                        data |= WINCON1_BPPMODE_16BPP_A1555;
 
609
                else
 
610
                        data |= WINCON0_BPPMODE_16BPP_565;
 
611
                data |= WINCONx_HAWSWP;
 
612
                data |= WINCONx_BURSTLEN_16WORD;
 
613
                break;
 
614
        case 24:
 
615
        case 32:
 
616
                if (var->red.length == 6) {
 
617
                        if (var->transp.length != 0)
 
618
                                data |= WINCON1_BPPMODE_19BPP_A1666;
 
619
                        else
 
620
                                data |= WINCON1_BPPMODE_18BPP_666;
 
621
                } else if (var->transp.length == 1)
 
622
                        data |= WINCON1_BPPMODE_25BPP_A1888
 
623
                                | WINCON1_BLD_PIX;
 
624
                else if (var->transp.length == 4)
 
625
                        data |= WINCON1_BPPMODE_28BPP_A4888
 
626
                                | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
 
627
                else
 
628
                        data |= WINCON0_BPPMODE_24BPP_888;
 
629
 
 
630
                data |= WINCONx_WSWP;
 
631
                data |= WINCONx_BURSTLEN_16WORD;
 
632
                break;
 
633
        }
 
634
 
 
635
        /* Enable the colour keying for the window below this one */
 
636
        if (win_no > 0) {
 
637
                u32 keycon0_data = 0, keycon1_data = 0;
 
638
                void __iomem *keycon = regs + sfb->variant.keycon;
 
639
 
 
640
                keycon0_data = ~(WxKEYCON0_KEYBL_EN |
 
641
                                WxKEYCON0_KEYEN_F |
 
642
                                WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
 
643
 
 
644
                keycon1_data = WxKEYCON1_COLVAL(0xffffff);
 
645
 
 
646
                keycon += (win_no - 1) * 8;
 
647
 
 
648
                writel(keycon0_data, keycon + WKEYCON0);
 
649
                writel(keycon1_data, keycon + WKEYCON1);
 
650
        }
 
651
 
 
652
        writel(data, regs + sfb->variant.wincon + (win_no * 4));
 
653
        writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
 
654
 
 
655
        shadow_protect_win(win, 0);
 
656
 
 
657
        return 0;
 
658
}
 
659
 
 
660
/**
 
661
 * s3c_fb_update_palette() - set or schedule a palette update.
 
662
 * @sfb: The hardware information.
 
663
 * @win: The window being updated.
 
664
 * @reg: The palette index being changed.
 
665
 * @value: The computed palette value.
 
666
 *
 
667
 * Change the value of a palette register, either by directly writing to
 
668
 * the palette (this requires the palette RAM to be disconnected from the
 
669
 * hardware whilst this is in progress) or schedule the update for later.
 
670
 *
 
671
 * At the moment, since we have no VSYNC interrupt support, we simply set
 
672
 * the palette entry directly.
 
673
 */
 
674
static void s3c_fb_update_palette(struct s3c_fb *sfb,
 
675
                                  struct s3c_fb_win *win,
 
676
                                  unsigned int reg,
 
677
                                  u32 value)
 
678
{
 
679
        void __iomem *palreg;
 
680
        u32 palcon;
 
681
 
 
682
        palreg = sfb->regs + sfb->variant.palette[win->index];
 
683
 
 
684
        dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
 
685
                __func__, win->index, reg, palreg, value);
 
686
 
 
687
        win->palette_buffer[reg] = value;
 
688
 
 
689
        palcon = readl(sfb->regs + WPALCON);
 
690
        writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
 
691
 
 
692
        if (win->variant.palette_16bpp)
 
693
                writew(value, palreg + (reg * 2));
 
694
        else
 
695
                writel(value, palreg + (reg * 4));
 
696
 
 
697
        writel(palcon, sfb->regs + WPALCON);
 
698
}
 
699
 
 
700
static inline unsigned int chan_to_field(unsigned int chan,
 
701
                                         struct fb_bitfield *bf)
 
702
{
 
703
        chan &= 0xffff;
 
704
        chan >>= 16 - bf->length;
 
705
        return chan << bf->offset;
 
706
}
 
707
 
 
708
/**
 
709
 * s3c_fb_setcolreg() - framebuffer layer request to change palette.
 
710
 * @regno: The palette index to change.
 
711
 * @red: The red field for the palette data.
 
712
 * @green: The green field for the palette data.
 
713
 * @blue: The blue field for the palette data.
 
714
 * @trans: The transparency (alpha) field for the palette data.
 
715
 * @info: The framebuffer being changed.
 
716
 */
 
717
static int s3c_fb_setcolreg(unsigned regno,
 
718
                            unsigned red, unsigned green, unsigned blue,
 
719
                            unsigned transp, struct fb_info *info)
 
720
{
 
721
        struct s3c_fb_win *win = info->par;
 
722
        struct s3c_fb *sfb = win->parent;
 
723
        unsigned int val;
 
724
 
 
725
        dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
 
726
                __func__, win->index, regno, red, green, blue);
 
727
 
 
728
        switch (info->fix.visual) {
 
729
        case FB_VISUAL_TRUECOLOR:
 
730
                /* true-colour, use pseudo-palette */
 
731
 
 
732
                if (regno < 16) {
 
733
                        u32 *pal = info->pseudo_palette;
 
734
 
 
735
                        val  = chan_to_field(red,   &info->var.red);
 
736
                        val |= chan_to_field(green, &info->var.green);
 
737
                        val |= chan_to_field(blue,  &info->var.blue);
 
738
 
 
739
                        pal[regno] = val;
 
740
                }
 
741
                break;
 
742
 
 
743
        case FB_VISUAL_PSEUDOCOLOR:
 
744
                if (regno < win->variant.palette_sz) {
 
745
                        val  = chan_to_field(red, &win->palette.r);
 
746
                        val |= chan_to_field(green, &win->palette.g);
 
747
                        val |= chan_to_field(blue, &win->palette.b);
 
748
 
 
749
                        s3c_fb_update_palette(sfb, win, regno, val);
 
750
                }
 
751
 
 
752
                break;
 
753
 
 
754
        default:
 
755
                return 1;       /* unknown type */
 
756
        }
 
757
 
 
758
        return 0;
 
759
}
 
760
 
 
761
/**
 
762
 * s3c_fb_enable() - Set the state of the main LCD output
 
763
 * @sfb: The main framebuffer state.
 
764
 * @enable: The state to set.
 
765
 */
 
766
static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
 
767
{
 
768
        u32 vidcon0 = readl(sfb->regs + VIDCON0);
 
769
 
 
770
        if (enable)
 
771
                vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
 
772
        else {
 
773
                /* see the note in the framebuffer datasheet about
 
774
                 * why you cannot take both of these bits down at the
 
775
                 * same time. */
 
776
 
 
777
                if (!(vidcon0 & VIDCON0_ENVID))
 
778
                        return;
 
779
 
 
780
                vidcon0 |= VIDCON0_ENVID;
 
781
                vidcon0 &= ~VIDCON0_ENVID_F;
 
782
        }
 
783
 
 
784
        writel(vidcon0, sfb->regs + VIDCON0);
 
785
}
 
786
 
 
787
/**
 
788
 * s3c_fb_blank() - blank or unblank the given window
 
789
 * @blank_mode: The blank state from FB_BLANK_*
 
790
 * @info: The framebuffer to blank.
 
791
 *
 
792
 * Framebuffer layer request to change the power state.
 
793
 */
 
794
static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
795
{
 
796
        struct s3c_fb_win *win = info->par;
 
797
        struct s3c_fb *sfb = win->parent;
 
798
        unsigned int index = win->index;
 
799
        u32 wincon;
 
800
 
 
801
        dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
 
802
 
 
803
        wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
 
804
 
 
805
        switch (blank_mode) {
 
806
        case FB_BLANK_POWERDOWN:
 
807
                wincon &= ~WINCONx_ENWIN;
 
808
                sfb->enabled &= ~(1 << index);
 
809
                /* fall through to FB_BLANK_NORMAL */
 
810
 
 
811
        case FB_BLANK_NORMAL:
 
812
                /* disable the DMA and display 0x0 (black) */
 
813
                writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
 
814
                       sfb->regs + sfb->variant.winmap + (index * 4));
 
815
                break;
 
816
 
 
817
        case FB_BLANK_UNBLANK:
 
818
                writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
 
819
                wincon |= WINCONx_ENWIN;
 
820
                sfb->enabled |= (1 << index);
 
821
                break;
 
822
 
 
823
        case FB_BLANK_VSYNC_SUSPEND:
 
824
        case FB_BLANK_HSYNC_SUSPEND:
 
825
        default:
 
826
                return 1;
 
827
        }
 
828
 
 
829
        writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
 
830
 
 
831
        /* Check the enabled state to see if we need to be running the
 
832
         * main LCD interface, as if there are no active windows then
 
833
         * it is highly likely that we also do not need to output
 
834
         * anything.
 
835
         */
 
836
 
 
837
        /* We could do something like the following code, but the current
 
838
         * system of using framebuffer events means that we cannot make
 
839
         * the distinction between just window 0 being inactive and all
 
840
         * the windows being down.
 
841
         *
 
842
         * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
 
843
        */
 
844
 
 
845
        /* we're stuck with this until we can do something about overriding
 
846
         * the power control using the blanking event for a single fb.
 
847
         */
 
848
        if (index == sfb->pdata->default_win)
 
849
                s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
 
850
 
 
851
        return 0;
 
852
}
 
853
 
 
854
/**
 
855
 * s3c_fb_pan_display() - Pan the display.
 
856
 *
 
857
 * Note that the offsets can be written to the device at any time, as their
 
858
 * values are latched at each vsync automatically. This also means that only
 
859
 * the last call to this function will have any effect on next vsync, but
 
860
 * there is no need to sleep waiting for it to prevent tearing.
 
861
 *
 
862
 * @var: The screen information to verify.
 
863
 * @info: The framebuffer device.
 
864
 */
 
865
static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
 
866
                              struct fb_info *info)
 
867
{
 
868
        struct s3c_fb_win *win  = info->par;
 
869
        struct s3c_fb *sfb      = win->parent;
 
870
        void __iomem *buf       = sfb->regs + win->index * 8;
 
871
        unsigned int start_boff, end_boff;
 
872
 
 
873
        /* Offset in bytes to the start of the displayed area */
 
874
        start_boff = var->yoffset * info->fix.line_length;
 
875
        /* X offset depends on the current bpp */
 
876
        if (info->var.bits_per_pixel >= 8) {
 
877
                start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
 
878
        } else {
 
879
                switch (info->var.bits_per_pixel) {
 
880
                case 4:
 
881
                        start_boff += var->xoffset >> 1;
 
882
                        break;
 
883
                case 2:
 
884
                        start_boff += var->xoffset >> 2;
 
885
                        break;
 
886
                case 1:
 
887
                        start_boff += var->xoffset >> 3;
 
888
                        break;
 
889
                default:
 
890
                        dev_err(sfb->dev, "invalid bpp\n");
 
891
                        return -EINVAL;
 
892
                }
 
893
        }
 
894
        /* Offset in bytes to the end of the displayed area */
 
895
        end_boff = start_boff + info->var.yres * info->fix.line_length;
 
896
 
 
897
        /* Temporarily turn off per-vsync update from shadow registers until
 
898
         * both start and end addresses are updated to prevent corruption */
 
899
        shadow_protect_win(win, 1);
 
900
 
 
901
        writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
 
902
        writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
 
903
 
 
904
        shadow_protect_win(win, 0);
 
905
 
 
906
        return 0;
 
907
}
 
908
 
 
909
/**
 
910
 * s3c_fb_enable_irq() - enable framebuffer interrupts
 
911
 * @sfb: main hardware state
 
912
 */
 
913
static void s3c_fb_enable_irq(struct s3c_fb *sfb)
 
914
{
 
915
        void __iomem *regs = sfb->regs;
 
916
        u32 irq_ctrl_reg;
 
917
 
 
918
        if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
 
919
                /* IRQ disabled, enable it */
 
920
                irq_ctrl_reg = readl(regs + VIDINTCON0);
 
921
 
 
922
                irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
 
923
                irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
 
924
 
 
925
                irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
 
926
                irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
 
927
                irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
 
928
                irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
 
929
 
 
930
                writel(irq_ctrl_reg, regs + VIDINTCON0);
 
931
        }
 
932
}
 
933
 
 
934
/**
 
935
 * s3c_fb_disable_irq() - disable framebuffer interrupts
 
936
 * @sfb: main hardware state
 
937
 */
 
938
static void s3c_fb_disable_irq(struct s3c_fb *sfb)
 
939
{
 
940
        void __iomem *regs = sfb->regs;
 
941
        u32 irq_ctrl_reg;
 
942
 
 
943
        if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
 
944
                /* IRQ enabled, disable it */
 
945
                irq_ctrl_reg = readl(regs + VIDINTCON0);
 
946
 
 
947
                irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
 
948
                irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
 
949
 
 
950
                writel(irq_ctrl_reg, regs + VIDINTCON0);
 
951
        }
 
952
}
 
953
 
 
954
static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
 
955
{
 
956
        struct s3c_fb *sfb = dev_id;
 
957
        void __iomem  *regs = sfb->regs;
 
958
        u32 irq_sts_reg;
 
959
 
 
960
        spin_lock(&sfb->slock);
 
961
 
 
962
        irq_sts_reg = readl(regs + VIDINTCON1);
 
963
 
 
964
        if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
 
965
 
 
966
                /* VSYNC interrupt, accept it */
 
967
                writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
 
968
 
 
969
                sfb->vsync_info.count++;
 
970
                wake_up_interruptible(&sfb->vsync_info.wait);
 
971
        }
 
972
 
 
973
        /* We only support waiting for VSYNC for now, so it's safe
 
974
         * to always disable irqs here.
 
975
         */
 
976
        s3c_fb_disable_irq(sfb);
 
977
 
 
978
        spin_unlock(&sfb->slock);
 
979
        return IRQ_HANDLED;
 
980
}
 
981
 
 
982
/**
 
983
 * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
 
984
 * @sfb: main hardware state
 
985
 * @crtc: head index.
 
986
 */
 
987
static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
 
988
{
 
989
        unsigned long count;
 
990
        int ret;
 
991
 
 
992
        if (crtc != 0)
 
993
                return -ENODEV;
 
994
 
 
995
        count = sfb->vsync_info.count;
 
996
        s3c_fb_enable_irq(sfb);
 
997
        ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
 
998
                                       count != sfb->vsync_info.count,
 
999
                                       msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
 
1000
        if (ret == 0)
 
1001
                return -ETIMEDOUT;
 
1002
 
 
1003
        return 0;
 
1004
}
 
1005
 
 
1006
static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
 
1007
                        unsigned long arg)
 
1008
{
 
1009
        struct s3c_fb_win *win = info->par;
 
1010
        struct s3c_fb *sfb = win->parent;
 
1011
        int ret;
 
1012
        u32 crtc;
 
1013
 
 
1014
        switch (cmd) {
 
1015
        case FBIO_WAITFORVSYNC:
 
1016
                if (get_user(crtc, (u32 __user *)arg)) {
 
1017
                        ret = -EFAULT;
 
1018
                        break;
 
1019
                }
 
1020
 
 
1021
                ret = s3c_fb_wait_for_vsync(sfb, crtc);
 
1022
                break;
 
1023
        default:
 
1024
                ret = -ENOTTY;
 
1025
        }
 
1026
 
 
1027
        return ret;
 
1028
}
 
1029
 
 
1030
static int s3c_fb_open(struct fb_info *info, int user)
 
1031
{
 
1032
        struct s3c_fb_win *win = info->par;
 
1033
        struct s3c_fb *sfb = win->parent;
 
1034
 
 
1035
        pm_runtime_get_sync(sfb->dev);
 
1036
 
 
1037
        return 0;
 
1038
}
 
1039
 
 
1040
static int s3c_fb_release(struct fb_info *info, int user)
 
1041
{
 
1042
        struct s3c_fb_win *win = info->par;
 
1043
        struct s3c_fb *sfb = win->parent;
 
1044
 
 
1045
        pm_runtime_put_sync(sfb->dev);
 
1046
 
 
1047
        return 0;
 
1048
}
 
1049
 
 
1050
static struct fb_ops s3c_fb_ops = {
 
1051
        .owner          = THIS_MODULE,
 
1052
        .fb_open        = s3c_fb_open,
 
1053
        .fb_release     = s3c_fb_release,
 
1054
        .fb_check_var   = s3c_fb_check_var,
 
1055
        .fb_set_par     = s3c_fb_set_par,
 
1056
        .fb_blank       = s3c_fb_blank,
 
1057
        .fb_setcolreg   = s3c_fb_setcolreg,
 
1058
        .fb_fillrect    = cfb_fillrect,
 
1059
        .fb_copyarea    = cfb_copyarea,
 
1060
        .fb_imageblit   = cfb_imageblit,
 
1061
        .fb_pan_display = s3c_fb_pan_display,
 
1062
        .fb_ioctl       = s3c_fb_ioctl,
 
1063
};
 
1064
 
 
1065
/**
 
1066
 * s3c_fb_missing_pixclock() - calculates pixel clock
 
1067
 * @mode: The video mode to change.
 
1068
 *
 
1069
 * Calculate the pixel clock when none has been given through platform data.
 
1070
 */
 
1071
static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
 
1072
{
 
1073
        u64 pixclk = 1000000000000ULL;
 
1074
        u32 div;
 
1075
 
 
1076
        div  = mode->left_margin + mode->hsync_len + mode->right_margin +
 
1077
               mode->xres;
 
1078
        div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
 
1079
               mode->yres;
 
1080
        div *= mode->refresh ? : 60;
 
1081
 
 
1082
        do_div(pixclk, div);
 
1083
 
 
1084
        mode->pixclock = pixclk;
 
1085
}
 
1086
 
 
1087
/**
 
1088
 * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
 
1089
 * @sfb: The base resources for the hardware.
 
1090
 * @win: The window to initialise memory for.
 
1091
 *
 
1092
 * Allocate memory for the given framebuffer.
 
1093
 */
 
1094
static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
 
1095
                                         struct s3c_fb_win *win)
 
1096
{
 
1097
        struct s3c_fb_pd_win *windata = win->windata;
 
1098
        unsigned int real_size, virt_size, size;
 
1099
        struct fb_info *fbi = win->fbinfo;
 
1100
        dma_addr_t map_dma;
 
1101
 
 
1102
        dev_dbg(sfb->dev, "allocating memory for display\n");
 
1103
 
 
1104
        real_size = windata->win_mode.xres * windata->win_mode.yres;
 
1105
        virt_size = windata->virtual_x * windata->virtual_y;
 
1106
 
 
1107
        dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
 
1108
                real_size, windata->win_mode.xres, windata->win_mode.yres,
 
1109
                virt_size, windata->virtual_x, windata->virtual_y);
 
1110
 
 
1111
        size = (real_size > virt_size) ? real_size : virt_size;
 
1112
        size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
 
1113
        size /= 8;
 
1114
 
 
1115
        fbi->fix.smem_len = size;
 
1116
        size = PAGE_ALIGN(size);
 
1117
 
 
1118
        dev_dbg(sfb->dev, "want %u bytes for window\n", size);
 
1119
 
 
1120
        fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
 
1121
                                                  &map_dma, GFP_KERNEL);
 
1122
        if (!fbi->screen_base)
 
1123
                return -ENOMEM;
 
1124
 
 
1125
        dev_dbg(sfb->dev, "mapped %x to %p\n",
 
1126
                (unsigned int)map_dma, fbi->screen_base);
 
1127
 
 
1128
        memset(fbi->screen_base, 0x0, size);
 
1129
        fbi->fix.smem_start = map_dma;
 
1130
 
 
1131
        return 0;
 
1132
}
 
1133
 
 
1134
/**
 
1135
 * s3c_fb_free_memory() - free the display memory for the given window
 
1136
 * @sfb: The base resources for the hardware.
 
1137
 * @win: The window to free the display memory for.
 
1138
 *
 
1139
 * Free the display memory allocated by s3c_fb_alloc_memory().
 
1140
 */
 
1141
static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
 
1142
{
 
1143
        struct fb_info *fbi = win->fbinfo;
 
1144
 
 
1145
        if (fbi->screen_base)
 
1146
                dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
 
1147
                              fbi->screen_base, fbi->fix.smem_start);
 
1148
}
 
1149
 
 
1150
/**
 
1151
 * s3c_fb_release_win() - release resources for a framebuffer window.
 
1152
 * @win: The window to cleanup the resources for.
 
1153
 *
 
1154
 * Release the resources that where claimed for the hardware window,
 
1155
 * such as the framebuffer instance and any memory claimed for it.
 
1156
 */
 
1157
static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
 
1158
{
 
1159
        u32 data;
 
1160
 
 
1161
        if (win->fbinfo) {
 
1162
                if (sfb->variant.has_shadowcon) {
 
1163
                        data = readl(sfb->regs + SHADOWCON);
 
1164
                        data &= ~SHADOWCON_CHx_ENABLE(win->index);
 
1165
                        data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
 
1166
                        writel(data, sfb->regs + SHADOWCON);
 
1167
                }
 
1168
                unregister_framebuffer(win->fbinfo);
 
1169
                if (win->fbinfo->cmap.len)
 
1170
                        fb_dealloc_cmap(&win->fbinfo->cmap);
 
1171
                s3c_fb_free_memory(sfb, win);
 
1172
                framebuffer_release(win->fbinfo);
 
1173
        }
 
1174
}
 
1175
 
 
1176
/**
 
1177
 * s3c_fb_probe_win() - register an hardware window
 
1178
 * @sfb: The base resources for the hardware
 
1179
 * @variant: The variant information for this window.
 
1180
 * @res: Pointer to where to place the resultant window.
 
1181
 *
 
1182
 * Allocate and do the basic initialisation for one of the hardware's graphics
 
1183
 * windows.
 
1184
 */
 
1185
static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
 
1186
                                      struct s3c_fb_win_variant *variant,
 
1187
                                      struct s3c_fb_win **res)
 
1188
{
 
1189
        struct fb_var_screeninfo *var;
 
1190
        struct fb_videomode *initmode;
 
1191
        struct s3c_fb_pd_win *windata;
 
1192
        struct s3c_fb_win *win;
 
1193
        struct fb_info *fbinfo;
 
1194
        int palette_size;
 
1195
        int ret;
 
1196
 
 
1197
        dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
 
1198
 
 
1199
        init_waitqueue_head(&sfb->vsync_info.wait);
 
1200
 
 
1201
        palette_size = variant->palette_sz * 4;
 
1202
 
 
1203
        fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
 
1204
                                   palette_size * sizeof(u32), sfb->dev);
 
1205
        if (!fbinfo) {
 
1206
                dev_err(sfb->dev, "failed to allocate framebuffer\n");
 
1207
                return -ENOENT;
 
1208
        }
 
1209
 
 
1210
        windata = sfb->pdata->win[win_no];
 
1211
        initmode = &windata->win_mode;
 
1212
 
 
1213
        WARN_ON(windata->max_bpp == 0);
 
1214
        WARN_ON(windata->win_mode.xres == 0);
 
1215
        WARN_ON(windata->win_mode.yres == 0);
 
1216
 
 
1217
        win = fbinfo->par;
 
1218
        *res = win;
 
1219
        var = &fbinfo->var;
 
1220
        win->variant = *variant;
 
1221
        win->fbinfo = fbinfo;
 
1222
        win->parent = sfb;
 
1223
        win->windata = windata;
 
1224
        win->index = win_no;
 
1225
        win->palette_buffer = (u32 *)(win + 1);
 
1226
 
 
1227
        ret = s3c_fb_alloc_memory(sfb, win);
 
1228
        if (ret) {
 
1229
                dev_err(sfb->dev, "failed to allocate display memory\n");
 
1230
                return ret;
 
1231
        }
 
1232
 
 
1233
        /* setup the r/b/g positions for the window's palette */
 
1234
        if (win->variant.palette_16bpp) {
 
1235
                /* Set RGB 5:6:5 as default */
 
1236
                win->palette.r.offset = 11;
 
1237
                win->palette.r.length = 5;
 
1238
                win->palette.g.offset = 5;
 
1239
                win->palette.g.length = 6;
 
1240
                win->palette.b.offset = 0;
 
1241
                win->palette.b.length = 5;
 
1242
 
 
1243
        } else {
 
1244
                /* Set 8bpp or 8bpp and 1bit alpha */
 
1245
                win->palette.r.offset = 16;
 
1246
                win->palette.r.length = 8;
 
1247
                win->palette.g.offset = 8;
 
1248
                win->palette.g.length = 8;
 
1249
                win->palette.b.offset = 0;
 
1250
                win->palette.b.length = 8;
 
1251
        }
 
1252
 
 
1253
        /* setup the initial video mode from the window */
 
1254
        fb_videomode_to_var(&fbinfo->var, initmode);
 
1255
 
 
1256
        fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
 
1257
        fbinfo->fix.accel       = FB_ACCEL_NONE;
 
1258
        fbinfo->var.activate    = FB_ACTIVATE_NOW;
 
1259
        fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
 
1260
        fbinfo->var.bits_per_pixel = windata->default_bpp;
 
1261
        fbinfo->fbops           = &s3c_fb_ops;
 
1262
        fbinfo->flags           = FBINFO_FLAG_DEFAULT;
 
1263
        fbinfo->pseudo_palette  = &win->pseudo_palette;
 
1264
 
 
1265
        /* prepare to actually start the framebuffer */
 
1266
 
 
1267
        ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
 
1268
        if (ret < 0) {
 
1269
                dev_err(sfb->dev, "check_var failed on initial video params\n");
 
1270
                return ret;
 
1271
        }
 
1272
 
 
1273
        /* create initial colour map */
 
1274
 
 
1275
        ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
 
1276
        if (ret == 0)
 
1277
                fb_set_cmap(&fbinfo->cmap, fbinfo);
 
1278
        else
 
1279
                dev_err(sfb->dev, "failed to allocate fb cmap\n");
 
1280
 
 
1281
        s3c_fb_set_par(fbinfo);
 
1282
 
 
1283
        dev_dbg(sfb->dev, "about to register framebuffer\n");
 
1284
 
 
1285
        /* run the check_var and set_par on our configuration. */
 
1286
 
 
1287
        ret = register_framebuffer(fbinfo);
 
1288
        if (ret < 0) {
 
1289
                dev_err(sfb->dev, "failed to register framebuffer\n");
 
1290
                return ret;
 
1291
        }
 
1292
 
 
1293
        dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
 
1294
 
 
1295
        return 0;
 
1296
}
 
1297
 
 
1298
/**
 
1299
 * s3c_fb_clear_win() - clear hardware window registers.
 
1300
 * @sfb: The base resources for the hardware.
 
1301
 * @win: The window to process.
 
1302
 *
 
1303
 * Reset the specific window registers to a known state.
 
1304
 */
 
1305
static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
 
1306
{
 
1307
        void __iomem *regs = sfb->regs;
 
1308
        u32 reg;
 
1309
 
 
1310
        writel(0, regs + sfb->variant.wincon + (win * 4));
 
1311
        writel(0, regs + VIDOSD_A(win, sfb->variant));
 
1312
        writel(0, regs + VIDOSD_B(win, sfb->variant));
 
1313
        writel(0, regs + VIDOSD_C(win, sfb->variant));
 
1314
        reg = readl(regs + SHADOWCON);
 
1315
        writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
 
1316
}
 
1317
 
 
1318
static int __devinit s3c_fb_probe(struct platform_device *pdev)
 
1319
{
 
1320
        const struct platform_device_id *platid;
 
1321
        struct s3c_fb_driverdata *fbdrv;
 
1322
        struct device *dev = &pdev->dev;
 
1323
        struct s3c_fb_platdata *pd;
 
1324
        struct s3c_fb *sfb;
 
1325
        struct resource *res;
 
1326
        int win;
 
1327
        int ret = 0;
 
1328
 
 
1329
        platid = platform_get_device_id(pdev);
 
1330
        fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
 
1331
 
 
1332
        if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
 
1333
                dev_err(dev, "too many windows, cannot attach\n");
 
1334
                return -EINVAL;
 
1335
        }
 
1336
 
 
1337
        pd = pdev->dev.platform_data;
 
1338
        if (!pd) {
 
1339
                dev_err(dev, "no platform data specified\n");
 
1340
                return -EINVAL;
 
1341
        }
 
1342
 
 
1343
        sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
 
1344
        if (!sfb) {
 
1345
                dev_err(dev, "no memory for framebuffers\n");
 
1346
                return -ENOMEM;
 
1347
        }
 
1348
 
 
1349
        dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
 
1350
 
 
1351
        sfb->dev = dev;
 
1352
        sfb->pdata = pd;
 
1353
        sfb->variant = fbdrv->variant;
 
1354
 
 
1355
        spin_lock_init(&sfb->slock);
 
1356
 
 
1357
        sfb->bus_clk = clk_get(dev, "lcd");
 
1358
        if (IS_ERR(sfb->bus_clk)) {
 
1359
                dev_err(dev, "failed to get bus clock\n");
 
1360
                ret = PTR_ERR(sfb->bus_clk);
 
1361
                goto err_sfb;
 
1362
        }
 
1363
 
 
1364
        clk_enable(sfb->bus_clk);
 
1365
 
 
1366
        if (!sfb->variant.has_clksel) {
 
1367
                sfb->lcd_clk = clk_get(dev, "sclk_fimd");
 
1368
                if (IS_ERR(sfb->lcd_clk)) {
 
1369
                        dev_err(dev, "failed to get lcd clock\n");
 
1370
                        ret = PTR_ERR(sfb->lcd_clk);
 
1371
                        goto err_bus_clk;
 
1372
                }
 
1373
 
 
1374
                clk_enable(sfb->lcd_clk);
 
1375
        }
 
1376
 
 
1377
        pm_runtime_enable(sfb->dev);
 
1378
 
 
1379
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
1380
        if (!res) {
 
1381
                dev_err(dev, "failed to find registers\n");
 
1382
                ret = -ENOENT;
 
1383
                goto err_lcd_clk;
 
1384
        }
 
1385
 
 
1386
        sfb->regs_res = request_mem_region(res->start, resource_size(res),
 
1387
                                           dev_name(dev));
 
1388
        if (!sfb->regs_res) {
 
1389
                dev_err(dev, "failed to claim register region\n");
 
1390
                ret = -ENOENT;
 
1391
                goto err_lcd_clk;
 
1392
        }
 
1393
 
 
1394
        sfb->regs = ioremap(res->start, resource_size(res));
 
1395
        if (!sfb->regs) {
 
1396
                dev_err(dev, "failed to map registers\n");
 
1397
                ret = -ENXIO;
 
1398
                goto err_req_region;
 
1399
        }
 
1400
 
 
1401
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
1402
        if (!res) {
 
1403
                dev_err(dev, "failed to acquire irq resource\n");
 
1404
                ret = -ENOENT;
 
1405
                goto err_ioremap;
 
1406
        }
 
1407
        sfb->irq_no = res->start;
 
1408
        ret = request_irq(sfb->irq_no, s3c_fb_irq,
 
1409
                          0, "s3c_fb", sfb);
 
1410
        if (ret) {
 
1411
                dev_err(dev, "irq request failed\n");
 
1412
                goto err_ioremap;
 
1413
        }
 
1414
 
 
1415
        dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
 
1416
 
 
1417
        platform_set_drvdata(pdev, sfb);
 
1418
        pm_runtime_get_sync(sfb->dev);
 
1419
 
 
1420
        /* setup gpio and output polarity controls */
 
1421
 
 
1422
        pd->setup_gpio();
 
1423
 
 
1424
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
1425
 
 
1426
        /* zero all windows before we do anything */
 
1427
 
 
1428
        for (win = 0; win < fbdrv->variant.nr_windows; win++)
 
1429
                s3c_fb_clear_win(sfb, win);
 
1430
 
 
1431
        /* initialise colour key controls */
 
1432
        for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
 
1433
                void __iomem *regs = sfb->regs + sfb->variant.keycon;
 
1434
 
 
1435
                regs += (win * 8);
 
1436
                writel(0xffffff, regs + WKEYCON0);
 
1437
                writel(0xffffff, regs + WKEYCON1);
 
1438
        }
 
1439
 
 
1440
        /* we have the register setup, start allocating framebuffers */
 
1441
 
 
1442
        for (win = 0; win < fbdrv->variant.nr_windows; win++) {
 
1443
                if (!pd->win[win])
 
1444
                        continue;
 
1445
 
 
1446
                if (!pd->win[win]->win_mode.pixclock)
 
1447
                        s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
 
1448
 
 
1449
                ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
 
1450
                                       &sfb->windows[win]);
 
1451
                if (ret < 0) {
 
1452
                        dev_err(dev, "failed to create window %d\n", win);
 
1453
                        for (; win >= 0; win--)
 
1454
                                s3c_fb_release_win(sfb, sfb->windows[win]);
 
1455
                        goto err_irq;
 
1456
                }
 
1457
        }
 
1458
 
 
1459
        platform_set_drvdata(pdev, sfb);
 
1460
        pm_runtime_put_sync(sfb->dev);
 
1461
 
 
1462
        return 0;
 
1463
 
 
1464
err_irq:
 
1465
        free_irq(sfb->irq_no, sfb);
 
1466
 
 
1467
err_ioremap:
 
1468
        iounmap(sfb->regs);
 
1469
 
 
1470
err_req_region:
 
1471
        release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
1472
 
 
1473
err_lcd_clk:
 
1474
        if (!sfb->variant.has_clksel) {
 
1475
                clk_disable(sfb->lcd_clk);
 
1476
                clk_put(sfb->lcd_clk);
 
1477
        }
 
1478
 
 
1479
err_bus_clk:
 
1480
        clk_disable(sfb->bus_clk);
 
1481
        clk_put(sfb->bus_clk);
 
1482
 
 
1483
err_sfb:
 
1484
        kfree(sfb);
 
1485
        return ret;
 
1486
}
 
1487
 
 
1488
/**
 
1489
 * s3c_fb_remove() - Cleanup on module finalisation
 
1490
 * @pdev: The platform device we are bound to.
 
1491
 *
 
1492
 * Shutdown and then release all the resources that the driver allocated
 
1493
 * on initialisation.
 
1494
 */
 
1495
static int __devexit s3c_fb_remove(struct platform_device *pdev)
 
1496
{
 
1497
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
 
1498
        int win;
 
1499
 
 
1500
        pm_runtime_get_sync(sfb->dev);
 
1501
 
 
1502
        for (win = 0; win < S3C_FB_MAX_WIN; win++)
 
1503
                if (sfb->windows[win])
 
1504
                        s3c_fb_release_win(sfb, sfb->windows[win]);
 
1505
 
 
1506
        free_irq(sfb->irq_no, sfb);
 
1507
 
 
1508
        iounmap(sfb->regs);
 
1509
 
 
1510
        if (!sfb->variant.has_clksel) {
 
1511
                clk_disable(sfb->lcd_clk);
 
1512
                clk_put(sfb->lcd_clk);
 
1513
        }
 
1514
 
 
1515
        clk_disable(sfb->bus_clk);
 
1516
        clk_put(sfb->bus_clk);
 
1517
 
 
1518
        release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
1519
 
 
1520
        pm_runtime_put_sync(sfb->dev);
 
1521
        pm_runtime_disable(sfb->dev);
 
1522
 
 
1523
        kfree(sfb);
 
1524
        return 0;
 
1525
}
 
1526
 
 
1527
#ifdef CONFIG_PM
 
1528
static int s3c_fb_suspend(struct device *dev)
 
1529
{
 
1530
        struct platform_device *pdev = to_platform_device(dev);
 
1531
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
 
1532
        struct s3c_fb_win *win;
 
1533
        int win_no;
 
1534
 
 
1535
        for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
 
1536
                win = sfb->windows[win_no];
 
1537
                if (!win)
 
1538
                        continue;
 
1539
 
 
1540
                /* use the blank function to push into power-down */
 
1541
                s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
 
1542
        }
 
1543
 
 
1544
        if (!sfb->variant.has_clksel)
 
1545
                clk_disable(sfb->lcd_clk);
 
1546
 
 
1547
        clk_disable(sfb->bus_clk);
 
1548
        return 0;
 
1549
}
 
1550
 
 
1551
static int s3c_fb_resume(struct device *dev)
 
1552
{
 
1553
        struct platform_device *pdev = to_platform_device(dev);
 
1554
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
 
1555
        struct s3c_fb_platdata *pd = sfb->pdata;
 
1556
        struct s3c_fb_win *win;
 
1557
        int win_no;
 
1558
 
 
1559
        clk_enable(sfb->bus_clk);
 
1560
 
 
1561
        if (!sfb->variant.has_clksel)
 
1562
                clk_enable(sfb->lcd_clk);
 
1563
 
 
1564
        /* setup gpio and output polarity controls */
 
1565
        pd->setup_gpio();
 
1566
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
1567
 
 
1568
        /* zero all windows before we do anything */
 
1569
        for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
 
1570
                s3c_fb_clear_win(sfb, win_no);
 
1571
 
 
1572
        for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
 
1573
                void __iomem *regs = sfb->regs + sfb->variant.keycon;
 
1574
 
 
1575
                regs += (win_no * 8);
 
1576
                writel(0xffffff, regs + WKEYCON0);
 
1577
                writel(0xffffff, regs + WKEYCON1);
 
1578
        }
 
1579
 
 
1580
        /* restore framebuffers */
 
1581
        for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
 
1582
                win = sfb->windows[win_no];
 
1583
                if (!win)
 
1584
                        continue;
 
1585
 
 
1586
                dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
 
1587
                s3c_fb_set_par(win->fbinfo);
 
1588
        }
 
1589
 
 
1590
        return 0;
 
1591
}
 
1592
 
 
1593
static int s3c_fb_runtime_suspend(struct device *dev)
 
1594
{
 
1595
        struct platform_device *pdev = to_platform_device(dev);
 
1596
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
 
1597
        struct s3c_fb_win *win;
 
1598
        int win_no;
 
1599
 
 
1600
        for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
 
1601
                win = sfb->windows[win_no];
 
1602
                if (!win)
 
1603
                        continue;
 
1604
 
 
1605
                /* use the blank function to push into power-down */
 
1606
                s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
 
1607
        }
 
1608
 
 
1609
        if (!sfb->variant.has_clksel)
 
1610
                clk_disable(sfb->lcd_clk);
 
1611
 
 
1612
        clk_disable(sfb->bus_clk);
 
1613
        return 0;
 
1614
}
 
1615
 
 
1616
static int s3c_fb_runtime_resume(struct device *dev)
 
1617
{
 
1618
        struct platform_device *pdev = to_platform_device(dev);
 
1619
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
 
1620
        struct s3c_fb_platdata *pd = sfb->pdata;
 
1621
        struct s3c_fb_win *win;
 
1622
        int win_no;
 
1623
 
 
1624
        clk_enable(sfb->bus_clk);
 
1625
 
 
1626
        if (!sfb->variant.has_clksel)
 
1627
                clk_enable(sfb->lcd_clk);
 
1628
 
 
1629
        /* setup gpio and output polarity controls */
 
1630
        pd->setup_gpio();
 
1631
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
1632
 
 
1633
        /* zero all windows before we do anything */
 
1634
        for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
 
1635
                s3c_fb_clear_win(sfb, win_no);
 
1636
 
 
1637
        for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
 
1638
                void __iomem *regs = sfb->regs + sfb->variant.keycon;
 
1639
 
 
1640
                regs += (win_no * 8);
 
1641
                writel(0xffffff, regs + WKEYCON0);
 
1642
                writel(0xffffff, regs + WKEYCON1);
 
1643
        }
 
1644
 
 
1645
        /* restore framebuffers */
 
1646
        for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
 
1647
                win = sfb->windows[win_no];
 
1648
                if (!win)
 
1649
                        continue;
 
1650
 
 
1651
                dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
 
1652
                s3c_fb_set_par(win->fbinfo);
 
1653
        }
 
1654
 
 
1655
        return 0;
 
1656
}
 
1657
 
 
1658
#else
 
1659
#define s3c_fb_suspend NULL
 
1660
#define s3c_fb_resume  NULL
 
1661
#define s3c_fb_runtime_suspend NULL
 
1662
#define s3c_fb_runtime_resume NULL
 
1663
#endif
 
1664
 
 
1665
 
 
1666
#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
 
1667
#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
 
1668
 
 
1669
static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
 
1670
        [0] = {
 
1671
                .has_osd_c      = 1,
 
1672
                .osd_size_off   = 0x8,
 
1673
                .palette_sz     = 256,
 
1674
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
 
1675
                                   VALID_BPP(18) | VALID_BPP(24)),
 
1676
        },
 
1677
        [1] = {
 
1678
                .has_osd_c      = 1,
 
1679
                .has_osd_d      = 1,
 
1680
                .osd_size_off   = 0xc,
 
1681
                .has_osd_alpha  = 1,
 
1682
                .palette_sz     = 256,
 
1683
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
 
1684
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1685
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1686
                                   VALID_BPP(28)),
 
1687
        },
 
1688
        [2] = {
 
1689
                .has_osd_c      = 1,
 
1690
                .has_osd_d      = 1,
 
1691
                .osd_size_off   = 0xc,
 
1692
                .has_osd_alpha  = 1,
 
1693
                .palette_sz     = 16,
 
1694
                .palette_16bpp  = 1,
 
1695
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
 
1696
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1697
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1698
                                   VALID_BPP(28)),
 
1699
        },
 
1700
        [3] = {
 
1701
                .has_osd_c      = 1,
 
1702
                .has_osd_alpha  = 1,
 
1703
                .palette_sz     = 16,
 
1704
                .palette_16bpp  = 1,
 
1705
                .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
 
1706
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1707
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1708
                                   VALID_BPP(28)),
 
1709
        },
 
1710
        [4] = {
 
1711
                .has_osd_c      = 1,
 
1712
                .has_osd_alpha  = 1,
 
1713
                .palette_sz     = 4,
 
1714
                .palette_16bpp  = 1,
 
1715
                .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
 
1716
                                   VALID_BPP(16) | VALID_BPP(18) |
 
1717
                                   VALID_BPP(19) | VALID_BPP(24) |
 
1718
                                   VALID_BPP(25) | VALID_BPP(28)),
 
1719
        },
 
1720
};
 
1721
 
 
1722
static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
 
1723
        [0] = {
 
1724
                .has_osd_c      = 1,
 
1725
                .osd_size_off   = 0x8,
 
1726
                .palette_sz     = 256,
 
1727
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
 
1728
                                   VALID_BPP(15) | VALID_BPP(16) |
 
1729
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1730
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1731
                                   VALID_BPP(32)),
 
1732
        },
 
1733
        [1] = {
 
1734
                .has_osd_c      = 1,
 
1735
                .has_osd_d      = 1,
 
1736
                .osd_size_off   = 0xc,
 
1737
                .has_osd_alpha  = 1,
 
1738
                .palette_sz     = 256,
 
1739
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
 
1740
                                   VALID_BPP(15) | VALID_BPP(16) |
 
1741
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1742
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1743
                                   VALID_BPP(32)),
 
1744
        },
 
1745
        [2] = {
 
1746
                .has_osd_c      = 1,
 
1747
                .has_osd_d      = 1,
 
1748
                .osd_size_off   = 0xc,
 
1749
                .has_osd_alpha  = 1,
 
1750
                .palette_sz     = 256,
 
1751
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
 
1752
                                   VALID_BPP(15) | VALID_BPP(16) |
 
1753
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1754
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1755
                                   VALID_BPP(32)),
 
1756
        },
 
1757
        [3] = {
 
1758
                .has_osd_c      = 1,
 
1759
                .has_osd_alpha  = 1,
 
1760
                .palette_sz     = 256,
 
1761
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
 
1762
                                   VALID_BPP(15) | VALID_BPP(16) |
 
1763
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1764
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1765
                                   VALID_BPP(32)),
 
1766
        },
 
1767
        [4] = {
 
1768
                .has_osd_c      = 1,
 
1769
                .has_osd_alpha  = 1,
 
1770
                .palette_sz     = 256,
 
1771
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
 
1772
                                   VALID_BPP(15) | VALID_BPP(16) |
 
1773
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1774
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1775
                                   VALID_BPP(32)),
 
1776
        },
 
1777
};
 
1778
 
 
1779
static struct s3c_fb_driverdata s3c_fb_data_64xx = {
 
1780
        .variant = {
 
1781
                .nr_windows     = 5,
 
1782
                .vidtcon        = VIDTCON0,
 
1783
                .wincon         = WINCON(0),
 
1784
                .winmap         = WINxMAP(0),
 
1785
                .keycon         = WKEYCON,
 
1786
                .osd            = VIDOSD_BASE,
 
1787
                .osd_stride     = 16,
 
1788
                .buf_start      = VIDW_BUF_START(0),
 
1789
                .buf_size       = VIDW_BUF_SIZE(0),
 
1790
                .buf_end        = VIDW_BUF_END(0),
 
1791
 
 
1792
                .palette = {
 
1793
                        [0] = 0x400,
 
1794
                        [1] = 0x800,
 
1795
                        [2] = 0x300,
 
1796
                        [3] = 0x320,
 
1797
                        [4] = 0x340,
 
1798
                },
 
1799
 
 
1800
                .has_prtcon     = 1,
 
1801
                .has_clksel     = 1,
 
1802
        },
 
1803
        .win[0] = &s3c_fb_data_64xx_wins[0],
 
1804
        .win[1] = &s3c_fb_data_64xx_wins[1],
 
1805
        .win[2] = &s3c_fb_data_64xx_wins[2],
 
1806
        .win[3] = &s3c_fb_data_64xx_wins[3],
 
1807
        .win[4] = &s3c_fb_data_64xx_wins[4],
 
1808
};
 
1809
 
 
1810
static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
 
1811
        .variant = {
 
1812
                .nr_windows     = 5,
 
1813
                .vidtcon        = VIDTCON0,
 
1814
                .wincon         = WINCON(0),
 
1815
                .winmap         = WINxMAP(0),
 
1816
                .keycon         = WKEYCON,
 
1817
                .osd            = VIDOSD_BASE,
 
1818
                .osd_stride     = 16,
 
1819
                .buf_start      = VIDW_BUF_START(0),
 
1820
                .buf_size       = VIDW_BUF_SIZE(0),
 
1821
                .buf_end        = VIDW_BUF_END(0),
 
1822
 
 
1823
                .palette = {
 
1824
                        [0] = 0x2400,
 
1825
                        [1] = 0x2800,
 
1826
                        [2] = 0x2c00,
 
1827
                        [3] = 0x3000,
 
1828
                        [4] = 0x3400,
 
1829
                },
 
1830
 
 
1831
                .has_prtcon     = 1,
 
1832
                .has_clksel     = 1,
 
1833
        },
 
1834
        .win[0] = &s3c_fb_data_s5p_wins[0],
 
1835
        .win[1] = &s3c_fb_data_s5p_wins[1],
 
1836
        .win[2] = &s3c_fb_data_s5p_wins[2],
 
1837
        .win[3] = &s3c_fb_data_s5p_wins[3],
 
1838
        .win[4] = &s3c_fb_data_s5p_wins[4],
 
1839
};
 
1840
 
 
1841
static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
 
1842
        .variant = {
 
1843
                .nr_windows     = 5,
 
1844
                .vidtcon        = VIDTCON0,
 
1845
                .wincon         = WINCON(0),
 
1846
                .winmap         = WINxMAP(0),
 
1847
                .keycon         = WKEYCON,
 
1848
                .osd            = VIDOSD_BASE,
 
1849
                .osd_stride     = 16,
 
1850
                .buf_start      = VIDW_BUF_START(0),
 
1851
                .buf_size       = VIDW_BUF_SIZE(0),
 
1852
                .buf_end        = VIDW_BUF_END(0),
 
1853
 
 
1854
                .palette = {
 
1855
                        [0] = 0x2400,
 
1856
                        [1] = 0x2800,
 
1857
                        [2] = 0x2c00,
 
1858
                        [3] = 0x3000,
 
1859
                        [4] = 0x3400,
 
1860
                },
 
1861
 
 
1862
                .has_shadowcon  = 1,
 
1863
                .has_clksel     = 1,
 
1864
        },
 
1865
        .win[0] = &s3c_fb_data_s5p_wins[0],
 
1866
        .win[1] = &s3c_fb_data_s5p_wins[1],
 
1867
        .win[2] = &s3c_fb_data_s5p_wins[2],
 
1868
        .win[3] = &s3c_fb_data_s5p_wins[3],
 
1869
        .win[4] = &s3c_fb_data_s5p_wins[4],
 
1870
};
 
1871
 
 
1872
static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
 
1873
        .variant = {
 
1874
                .nr_windows     = 5,
 
1875
                .vidtcon        = VIDTCON0,
 
1876
                .wincon         = WINCON(0),
 
1877
                .winmap         = WINxMAP(0),
 
1878
                .keycon         = WKEYCON,
 
1879
                .osd            = VIDOSD_BASE,
 
1880
                .osd_stride     = 16,
 
1881
                .buf_start      = VIDW_BUF_START(0),
 
1882
                .buf_size       = VIDW_BUF_SIZE(0),
 
1883
                .buf_end        = VIDW_BUF_END(0),
 
1884
 
 
1885
                .palette = {
 
1886
                        [0] = 0x2400,
 
1887
                        [1] = 0x2800,
 
1888
                        [2] = 0x2c00,
 
1889
                        [3] = 0x3000,
 
1890
                        [4] = 0x3400,
 
1891
                },
 
1892
 
 
1893
                .has_shadowcon  = 1,
 
1894
        },
 
1895
        .win[0] = &s3c_fb_data_s5p_wins[0],
 
1896
        .win[1] = &s3c_fb_data_s5p_wins[1],
 
1897
        .win[2] = &s3c_fb_data_s5p_wins[2],
 
1898
        .win[3] = &s3c_fb_data_s5p_wins[3],
 
1899
        .win[4] = &s3c_fb_data_s5p_wins[4],
 
1900
};
 
1901
 
 
1902
/* S3C2443/S3C2416 style hardware */
 
1903
static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
 
1904
        .variant = {
 
1905
                .nr_windows     = 2,
 
1906
                .is_2443        = 1,
 
1907
 
 
1908
                .vidtcon        = 0x08,
 
1909
                .wincon         = 0x14,
 
1910
                .winmap         = 0xd0,
 
1911
                .keycon         = 0xb0,
 
1912
                .osd            = 0x28,
 
1913
                .osd_stride     = 12,
 
1914
                .buf_start      = 0x64,
 
1915
                .buf_size       = 0x94,
 
1916
                .buf_end        = 0x7c,
 
1917
 
 
1918
                .palette = {
 
1919
                        [0] = 0x400,
 
1920
                        [1] = 0x800,
 
1921
                },
 
1922
                .has_clksel     = 1,
 
1923
        },
 
1924
        .win[0] = &(struct s3c_fb_win_variant) {
 
1925
                .palette_sz     = 256,
 
1926
                .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
 
1927
        },
 
1928
        .win[1] = &(struct s3c_fb_win_variant) {
 
1929
                .has_osd_c      = 1,
 
1930
                .has_osd_alpha  = 1,
 
1931
                .palette_sz     = 256,
 
1932
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
 
1933
                                   VALID_BPP(18) | VALID_BPP(19) |
 
1934
                                   VALID_BPP(24) | VALID_BPP(25) |
 
1935
                                   VALID_BPP(28)),
 
1936
        },
 
1937
};
 
1938
 
 
1939
static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
 
1940
        .variant = {
 
1941
                .nr_windows     = 3,
 
1942
                .vidtcon        = VIDTCON0,
 
1943
                .wincon         = WINCON(0),
 
1944
                .winmap         = WINxMAP(0),
 
1945
                .keycon         = WKEYCON,
 
1946
                .osd            = VIDOSD_BASE,
 
1947
                .osd_stride     = 16,
 
1948
                .buf_start      = VIDW_BUF_START(0),
 
1949
                .buf_size       = VIDW_BUF_SIZE(0),
 
1950
                .buf_end        = VIDW_BUF_END(0),
 
1951
 
 
1952
                .palette = {
 
1953
                        [0] = 0x2400,
 
1954
                        [1] = 0x2800,
 
1955
                        [2] = 0x2c00,
 
1956
                },
 
1957
        },
 
1958
        .win[0] = &s3c_fb_data_s5p_wins[0],
 
1959
        .win[1] = &s3c_fb_data_s5p_wins[1],
 
1960
        .win[2] = &s3c_fb_data_s5p_wins[2],
 
1961
};
 
1962
 
 
1963
static struct platform_device_id s3c_fb_driver_ids[] = {
 
1964
        {
 
1965
                .name           = "s3c-fb",
 
1966
                .driver_data    = (unsigned long)&s3c_fb_data_64xx,
 
1967
        }, {
 
1968
                .name           = "s5pc100-fb",
 
1969
                .driver_data    = (unsigned long)&s3c_fb_data_s5pc100,
 
1970
        }, {
 
1971
                .name           = "s5pv210-fb",
 
1972
                .driver_data    = (unsigned long)&s3c_fb_data_s5pv210,
 
1973
        }, {
 
1974
                .name           = "exynos4-fb",
 
1975
                .driver_data    = (unsigned long)&s3c_fb_data_exynos4,
 
1976
        }, {
 
1977
                .name           = "s3c2443-fb",
 
1978
                .driver_data    = (unsigned long)&s3c_fb_data_s3c2443,
 
1979
        }, {
 
1980
                .name           = "s5p64x0-fb",
 
1981
                .driver_data    = (unsigned long)&s3c_fb_data_s5p64x0,
 
1982
        },
 
1983
        {},
 
1984
};
 
1985
MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
 
1986
 
 
1987
static const struct dev_pm_ops s3cfb_pm_ops = {
 
1988
        .suspend        = s3c_fb_suspend,
 
1989
        .resume         = s3c_fb_resume,
 
1990
        .runtime_suspend        = s3c_fb_runtime_suspend,
 
1991
        .runtime_resume         = s3c_fb_runtime_resume,
 
1992
};
 
1993
 
 
1994
static struct platform_driver s3c_fb_driver = {
 
1995
        .probe          = s3c_fb_probe,
 
1996
        .remove         = __devexit_p(s3c_fb_remove),
 
1997
        .id_table       = s3c_fb_driver_ids,
 
1998
        .driver         = {
 
1999
                .name   = "s3c-fb",
 
2000
                .owner  = THIS_MODULE,
 
2001
                .pm     = &s3cfb_pm_ops,
 
2002
        },
 
2003
};
 
2004
 
 
2005
static int __init s3c_fb_init(void)
 
2006
{
 
2007
        return platform_driver_register(&s3c_fb_driver);
 
2008
}
 
2009
 
 
2010
static void __exit s3c_fb_cleanup(void)
 
2011
{
 
2012
        platform_driver_unregister(&s3c_fb_driver);
 
2013
}
 
2014
 
 
2015
module_init(s3c_fb_init);
 
2016
module_exit(s3c_fb_cleanup);
 
2017
 
 
2018
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 
2019
MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
 
2020
MODULE_LICENSE("GPL");
 
2021
MODULE_ALIAS("platform:s3c-fb");