aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2011-09-20 02:49:49 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-02-22 03:55:29 -0500
commit8dc50ec7755650859a7bfc17de8846ef1efa24a4 (patch)
treeaf51e4a1be8cd30bb8f67c40611c74c664a064d4 /drivers/video/omap
parentfdcb68884b3b0def9cc410d07adbafe7c3a9e537 (diff)
OMAPFB: Remove OMAP2/3 support from old omapfb driver
Old omapfb driver (drivers/video/omap/) is no longer used for OMAP2+ devices, and thus we can remove OMAP2+ support from it and make it an OMAP1 omapfb driver. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/omap')
-rw-r--r--drivers/video/omap/Kconfig9
-rw-r--r--drivers/video/omap/Makefile5
-rw-r--r--drivers/video/omap/dispc.c1547
-rw-r--r--drivers/video/omap/dispc.h46
-rw-r--r--drivers/video/omap/omapfb.h4
-rw-r--r--drivers/video/omap/omapfb_main.c16
-rw-r--r--drivers/video/omap/rfbi.c598
7 files changed, 5 insertions, 2220 deletions
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index ab234d597110..1e7536d9a8fc 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,11 +1,10 @@
1config FB_OMAP 1config FB_OMAP
2 tristate "OMAP frame buffer support (EXPERIMENTAL)" 2 tristate "OMAP frame buffer support (EXPERIMENTAL)"
3 depends on FB && (OMAP2_DSS = "n") 3 depends on FB
4 depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3 4 depends on ARCH_OMAP1
5 select FB_CFB_FILLRECT 5 select FB_CFB_FILLRECT
6 select FB_CFB_COPYAREA 6 select FB_CFB_COPYAREA
7 select FB_CFB_IMAGEBLIT 7 select FB_CFB_IMAGEBLIT
8 select TWL4030_CORE if MACH_OMAP_2430SDP
9 help 8 help
10 Frame buffer driver for OMAP based boards. 9 Frame buffer driver for OMAP based boards.
11 10
@@ -42,7 +41,7 @@ config FB_OMAP_LCD_MIPID
42 41
43config FB_OMAP_BOOTLOADER_INIT 42config FB_OMAP_BOOTLOADER_INIT
44 bool "Check bootloader initialization" 43 bool "Check bootloader initialization"
45 depends on FB_OMAP || FB_OMAP2 44 depends on FB_OMAP
46 help 45 help
47 Say Y here if you want to enable checking if the bootloader has 46 Say Y here if you want to enable checking if the bootloader has
48 already initialized the display controller. In this case the 47 already initialized the display controller. In this case the
@@ -61,7 +60,7 @@ config FB_OMAP_CONSISTENT_DMA_SIZE
61 60
62config FB_OMAP_DMA_TUNE 61config FB_OMAP_DMA_TUNE
63 bool "Set DMA SDRAM access priority high" 62 bool "Set DMA SDRAM access priority high"
64 depends on FB_OMAP && ARCH_OMAP1 63 depends on FB_OMAP
65 help 64 help
66 On systems in which video memory is in system memory 65 On systems in which video memory is in system memory
67 (SDRAM) this will speed up graphics DMA operations. 66 (SDRAM) this will speed up graphics DMA operations.
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
index 7042a4ac7072..79653750448a 100644
--- a/drivers/video/omap/Makefile
+++ b/drivers/video/omap/Makefile
@@ -1,5 +1,5 @@
1# 1#
2# Makefile for the new OMAP framebuffer device driver 2# Makefile for the OMAP1 framebuffer device driver
3# 3#
4 4
5obj-$(CONFIG_FB_OMAP) += omapfb.o 5obj-$(CONFIG_FB_OMAP) += omapfb.o
@@ -7,11 +7,8 @@ obj-$(CONFIG_FB_OMAP) += omapfb.o
7objs-yy := omapfb_main.o 7objs-yy := omapfb_main.o
8 8
9objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o 9objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
10objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
11objs-y$(CONFIG_ARCH_OMAP3) += dispc.o
12 10
13objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o 11objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
14objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
15 12
16objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o 13objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
17 14
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
deleted file mode 100644
index 6f61e781f15a..000000000000
--- a/drivers/video/omap/dispc.c
+++ /dev/null
@@ -1,1547 +0,0 @@
1/*
2 * OMAP2 display controller support
3 *
4 * Copyright (C) 2005 Nokia Corporation
5 * Author: Imre Deak <imre.deak@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/dma-mapping.h>
24#include <linux/mm.h>
25#include <linux/vmalloc.h>
26#include <linux/clk.h>
27#include <linux/io.h>
28#include <linux/platform_device.h>
29#include <linux/slab.h>
30
31#include <plat/sram.h>
32#include <plat/board.h>
33
34#include "omapfb.h"
35#include "dispc.h"
36
37#define MODULE_NAME "dispc"
38
39#define DSS_BASE 0x48050000
40#define DSS_SYSCONFIG 0x0010
41
42#define DISPC_BASE 0x48050400
43
44/* DISPC common */
45#define DISPC_REVISION 0x0000
46#define DISPC_SYSCONFIG 0x0010
47#define DISPC_SYSSTATUS 0x0014
48#define DISPC_IRQSTATUS 0x0018
49#define DISPC_IRQENABLE 0x001C
50#define DISPC_CONTROL 0x0040
51#define DISPC_CONFIG 0x0044
52#define DISPC_CAPABLE 0x0048
53#define DISPC_DEFAULT_COLOR0 0x004C
54#define DISPC_DEFAULT_COLOR1 0x0050
55#define DISPC_TRANS_COLOR0 0x0054
56#define DISPC_TRANS_COLOR1 0x0058
57#define DISPC_LINE_STATUS 0x005C
58#define DISPC_LINE_NUMBER 0x0060
59#define DISPC_TIMING_H 0x0064
60#define DISPC_TIMING_V 0x0068
61#define DISPC_POL_FREQ 0x006C
62#define DISPC_DIVISOR 0x0070
63#define DISPC_SIZE_DIG 0x0078
64#define DISPC_SIZE_LCD 0x007C
65
66#define DISPC_DATA_CYCLE1 0x01D4
67#define DISPC_DATA_CYCLE2 0x01D8
68#define DISPC_DATA_CYCLE3 0x01DC
69
70/* DISPC GFX plane */
71#define DISPC_GFX_BA0 0x0080
72#define DISPC_GFX_BA1 0x0084
73#define DISPC_GFX_POSITION 0x0088
74#define DISPC_GFX_SIZE 0x008C
75#define DISPC_GFX_ATTRIBUTES 0x00A0
76#define DISPC_GFX_FIFO_THRESHOLD 0x00A4
77#define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8
78#define DISPC_GFX_ROW_INC 0x00AC
79#define DISPC_GFX_PIXEL_INC 0x00B0
80#define DISPC_GFX_WINDOW_SKIP 0x00B4
81#define DISPC_GFX_TABLE_BA 0x00B8
82
83/* DISPC Video plane 1/2 */
84#define DISPC_VID1_BASE 0x00BC
85#define DISPC_VID2_BASE 0x014C
86
87/* Offsets into DISPC_VID1/2_BASE */
88#define DISPC_VID_BA0 0x0000
89#define DISPC_VID_BA1 0x0004
90#define DISPC_VID_POSITION 0x0008
91#define DISPC_VID_SIZE 0x000C
92#define DISPC_VID_ATTRIBUTES 0x0010
93#define DISPC_VID_FIFO_THRESHOLD 0x0014
94#define DISPC_VID_FIFO_SIZE_STATUS 0x0018
95#define DISPC_VID_ROW_INC 0x001C
96#define DISPC_VID_PIXEL_INC 0x0020
97#define DISPC_VID_FIR 0x0024
98#define DISPC_VID_PICTURE_SIZE 0x0028
99#define DISPC_VID_ACCU0 0x002C
100#define DISPC_VID_ACCU1 0x0030
101
102/* 8 elements in 8 byte increments */
103#define DISPC_VID_FIR_COEF_H0 0x0034
104/* 8 elements in 8 byte increments */
105#define DISPC_VID_FIR_COEF_HV0 0x0038
106/* 5 elements in 4 byte increments */
107#define DISPC_VID_CONV_COEF0 0x0074
108
109#define DISPC_IRQ_FRAMEMASK 0x0001
110#define DISPC_IRQ_VSYNC 0x0002
111#define DISPC_IRQ_EVSYNC_EVEN 0x0004
112#define DISPC_IRQ_EVSYNC_ODD 0x0008
113#define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010
114#define DISPC_IRQ_PROG_LINE_NUM 0x0020
115#define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040
116#define DISPC_IRQ_GFX_END_WIN 0x0080
117#define DISPC_IRQ_PAL_GAMMA_MASK 0x0100
118#define DISPC_IRQ_OCP_ERR 0x0200
119#define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400
120#define DISPC_IRQ_VID1_END_WIN 0x0800
121#define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000
122#define DISPC_IRQ_VID2_END_WIN 0x2000
123#define DISPC_IRQ_SYNC_LOST 0x4000
124
125#define DISPC_IRQ_MASK_ALL 0x7fff
126
127#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
128 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
129 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
130 DISPC_IRQ_SYNC_LOST)
131
132#define RFBI_CONTROL 0x48050040
133
134#define MAX_PALETTE_SIZE (256 * 16)
135
136#define FLD_MASK(pos, len) (((1 << len) - 1) << pos)
137
138#define MOD_REG_FLD(reg, mask, val) \
139 dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
140
141#define OMAP2_SRAM_START 0x40200000
142/* Maximum size, in reality this is smaller if SRAM is partially locked. */
143#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
144
145/* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */
146#define DISPC_MEMTYPE_NUM 2
147
148#define RESMAP_SIZE(_page_cnt) \
149 ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8)
150#define RESMAP_PTR(_res_map, _page_nr) \
151 (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8))
152#define RESMAP_MASK(_page_nr) \
153 (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))
154
155struct resmap {
156 unsigned long start;
157 unsigned page_cnt;
158 unsigned long *map;
159};
160
161#define MAX_IRQ_HANDLERS 4
162
163static struct {
164 void __iomem *base;
165
166 struct omapfb_mem_desc mem_desc;
167 struct resmap *res_map[DISPC_MEMTYPE_NUM];
168 atomic_t map_count[OMAPFB_PLANE_NUM];
169
170 dma_addr_t palette_paddr;
171 void *palette_vaddr;
172
173 int ext_mode;
174
175 struct {
176 u32 irq_mask;
177 void (*callback)(void *);
178 void *data;
179 } irq_handlers[MAX_IRQ_HANDLERS];
180 struct completion frame_done;
181
182 int fir_hinc[OMAPFB_PLANE_NUM];
183 int fir_vinc[OMAPFB_PLANE_NUM];
184
185 struct clk *dss_ick, *dss1_fck;
186 struct clk *dss_54m_fck;
187
188 enum omapfb_update_mode update_mode;
189 struct omapfb_device *fbdev;
190
191 struct omapfb_color_key color_key;
192} dispc;
193
194static void enable_lcd_clocks(int enable);
195
196static void inline dispc_write_reg(int idx, u32 val)
197{
198 __raw_writel(val, dispc.base + idx);
199}
200
201static u32 inline dispc_read_reg(int idx)
202{
203 u32 l = __raw_readl(dispc.base + idx);
204 return l;
205}
206
207/* Select RFBI or bypass mode */
208static void enable_rfbi_mode(int enable)
209{
210 void __iomem *rfbi_control;
211 u32 l;
212
213 l = dispc_read_reg(DISPC_CONTROL);
214 /* Enable RFBI, GPIO0/1 */
215 l &= ~((1 << 11) | (1 << 15) | (1 << 16));
216 l |= enable ? (1 << 11) : 0;
217 /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */
218 l |= 1 << 15;
219 l |= enable ? 0 : (1 << 16);
220 dispc_write_reg(DISPC_CONTROL, l);
221
222 /* Set bypass mode in RFBI module */
223 rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
224 if (!rfbi_control) {
225 pr_err("Unable to ioremap rfbi_control\n");
226 return;
227 }
228 l = __raw_readl(rfbi_control);
229 l |= enable ? 0 : (1 << 1);
230 __raw_writel(l, rfbi_control);
231 iounmap(rfbi_control);
232}
233
234static void set_lcd_data_lines(int data_lines)
235{
236 u32 l;
237 int code = 0;
238
239 switch (data_lines) {
240 case 12:
241 code = 0;
242 break;
243 case 16:
244 code = 1;
245 break;
246 case 18:
247 code = 2;
248 break;
249 case 24:
250 code = 3;
251 break;
252 default:
253 BUG();
254 }
255
256 l = dispc_read_reg(DISPC_CONTROL);
257 l &= ~(0x03 << 8);
258 l |= code << 8;
259 dispc_write_reg(DISPC_CONTROL, l);
260}
261
262static void set_load_mode(int mode)
263{
264 BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
265 DISPC_LOAD_CLUT_ONCE_FRAME));
266 MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
267}
268
269void omap_dispc_set_lcd_size(int x, int y)
270{
271 BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
272 enable_lcd_clocks(1);
273 MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
274 ((y - 1) << 16) | (x - 1));
275 enable_lcd_clocks(0);
276}
277EXPORT_SYMBOL(omap_dispc_set_lcd_size);
278
279void omap_dispc_set_digit_size(int x, int y)
280{
281 BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
282 enable_lcd_clocks(1);
283 MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
284 ((y - 1) << 16) | (x - 1));
285 enable_lcd_clocks(0);
286}
287EXPORT_SYMBOL(omap_dispc_set_digit_size);
288
289static void setup_plane_fifo(int plane, int ext_mode)
290{
291 const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
292 DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
293 DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
294 const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
295 DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
296 DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
297 int low, high;
298 u32 l;
299
300 BUG_ON(plane > 2);
301
302 l = dispc_read_reg(fsz_reg[plane]);
303 l &= FLD_MASK(0, 11);
304 if (ext_mode) {
305 low = l * 3 / 4;
306 high = l;
307 } else {
308 low = l / 4;
309 high = l * 3 / 4;
310 }
311 MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12),
312 (high << 16) | low);
313}
314
315void omap_dispc_enable_lcd_out(int enable)
316{
317 enable_lcd_clocks(1);
318 MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
319 enable_lcd_clocks(0);
320}
321EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
322
323void omap_dispc_enable_digit_out(int enable)
324{
325 enable_lcd_clocks(1);
326 MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
327 enable_lcd_clocks(0);
328}
329EXPORT_SYMBOL(omap_dispc_enable_digit_out);
330
331static inline int _setup_plane(int plane, int channel_out,
332 u32 paddr, int screen_width,
333 int pos_x, int pos_y, int width, int height,
334 int color_mode)
335{
336 const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
337 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
338 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
339 const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
340 DISPC_VID2_BASE + DISPC_VID_BA0 };
341 const u32 ps_reg[] = { DISPC_GFX_POSITION,
342 DISPC_VID1_BASE + DISPC_VID_POSITION,
343 DISPC_VID2_BASE + DISPC_VID_POSITION };
344 const u32 sz_reg[] = { DISPC_GFX_SIZE,
345 DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
346 DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
347 const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
348 DISPC_VID1_BASE + DISPC_VID_ROW_INC,
349 DISPC_VID2_BASE + DISPC_VID_ROW_INC };
350 const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
351 DISPC_VID2_BASE + DISPC_VID_SIZE };
352
353 int chout_shift, burst_shift;
354 int chout_val;
355 int color_code;
356 int bpp;
357 int cconv_en;
358 int set_vsize;
359 u32 l;
360
361#ifdef VERBOSE
362 dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d"
363 " pos_x %d pos_y %d width %d height %d color_mode %d\n",
364 plane, channel_out, paddr, screen_width, pos_x, pos_y,
365 width, height, color_mode);
366#endif
367
368 set_vsize = 0;
369 switch (plane) {
370 case OMAPFB_PLANE_GFX:
371 burst_shift = 6;
372 chout_shift = 8;
373 break;
374 case OMAPFB_PLANE_VID1:
375 case OMAPFB_PLANE_VID2:
376 burst_shift = 14;
377 chout_shift = 16;
378 set_vsize = 1;
379 break;
380 default:
381 return -EINVAL;
382 }
383
384 switch (channel_out) {
385 case OMAPFB_CHANNEL_OUT_LCD:
386 chout_val = 0;
387 break;
388 case OMAPFB_CHANNEL_OUT_DIGIT:
389 chout_val = 1;
390 break;
391 default:
392 return -EINVAL;
393 }
394
395 cconv_en = 0;
396 switch (color_mode) {
397 case OMAPFB_COLOR_RGB565:
398 color_code = DISPC_RGB_16_BPP;
399 bpp = 16;
400 break;
401 case OMAPFB_COLOR_YUV422:
402 if (plane == 0)
403 return -EINVAL;
404 color_code = DISPC_UYVY_422;
405 cconv_en = 1;
406 bpp = 16;
407 break;
408 case OMAPFB_COLOR_YUY422:
409 if (plane == 0)
410 return -EINVAL;
411 color_code = DISPC_YUV2_422;
412 cconv_en = 1;
413 bpp = 16;
414 break;
415 default:
416 return -EINVAL;
417 }
418
419 l = dispc_read_reg(at_reg[plane]);
420
421 l &= ~(0x0f << 1);
422 l |= color_code << 1;
423 l &= ~(1 << 9);
424 l |= cconv_en << 9;
425
426 l &= ~(0x03 << burst_shift);
427 l |= DISPC_BURST_8x32 << burst_shift;
428
429 l &= ~(1 << chout_shift);
430 l |= chout_val << chout_shift;
431
432 dispc_write_reg(at_reg[plane], l);
433
434 dispc_write_reg(ba_reg[plane], paddr);
435 MOD_REG_FLD(ps_reg[plane],
436 FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
437
438 MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
439 ((height - 1) << 16) | (width - 1));
440
441 if (set_vsize) {
442 /* Set video size if set_scale hasn't set it */
443 if (!dispc.fir_vinc[plane])
444 MOD_REG_FLD(vs_reg[plane],
445 FLD_MASK(16, 11), (height - 1) << 16);
446 if (!dispc.fir_hinc[plane])
447 MOD_REG_FLD(vs_reg[plane],
448 FLD_MASK(0, 11), width - 1);
449 }
450
451 dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
452
453 return height * screen_width * bpp / 8;
454}
455
456static int omap_dispc_setup_plane(int plane, int channel_out,
457 unsigned long offset,
458 int screen_width,
459 int pos_x, int pos_y, int width, int height,
460 int color_mode)
461{
462 u32 paddr;
463 int r;
464
465 if ((unsigned)plane > dispc.mem_desc.region_cnt)
466 return -EINVAL;
467 paddr = dispc.mem_desc.region[plane].paddr + offset;
468 enable_lcd_clocks(1);
469 r = _setup_plane(plane, channel_out, paddr,
470 screen_width,
471 pos_x, pos_y, width, height, color_mode);
472 enable_lcd_clocks(0);
473 return r;
474}
475
476static void write_firh_reg(int plane, int reg, u32 value)
477{
478 u32 base;
479
480 if (plane == 1)
481 base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
482 else
483 base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
484 dispc_write_reg(base + reg * 8, value);
485}
486
487static void write_firhv_reg(int plane, int reg, u32 value)
488{
489 u32 base;
490
491 if (plane == 1)
492 base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
493 else
494 base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
495 dispc_write_reg(base + reg * 8, value);
496}
497
498static void set_upsampling_coef_table(int plane)
499{
500 const u32 coef[][2] = {
501 { 0x00800000, 0x00800000 },
502 { 0x0D7CF800, 0x037B02FF },
503 { 0x1E70F5FF, 0x0C6F05FE },
504 { 0x335FF5FE, 0x205907FB },
505 { 0xF74949F7, 0x00404000 },
506 { 0xF55F33FB, 0x075920FE },
507 { 0xF5701EFE, 0x056F0CFF },
508 { 0xF87C0DFF, 0x027B0300 },
509 };
510 int i;
511
512 for (i = 0; i < 8; i++) {
513 write_firh_reg(plane, i, coef[i][0]);
514 write_firhv_reg(plane, i, coef[i][1]);
515 }
516}
517
518static int omap_dispc_set_scale(int plane,
519 int orig_width, int orig_height,
520 int out_width, int out_height)
521{
522 const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
523 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
524 const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
525 DISPC_VID2_BASE + DISPC_VID_SIZE };
526 const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
527 DISPC_VID2_BASE + DISPC_VID_FIR };
528
529 u32 l;
530 int fir_hinc;
531 int fir_vinc;
532
533 if ((unsigned)plane > OMAPFB_PLANE_NUM)
534 return -ENODEV;
535
536 if (plane == OMAPFB_PLANE_GFX &&
537 (out_width != orig_width || out_height != orig_height))
538 return -EINVAL;
539
540 enable_lcd_clocks(1);
541 if (orig_width < out_width) {
542 /*
543 * Upsampling.
544 * Currently you can only scale both dimensions in one way.
545 */
546 if (orig_height > out_height ||
547 orig_width * 8 < out_width ||
548 orig_height * 8 < out_height) {
549 enable_lcd_clocks(0);
550 return -EINVAL;
551 }
552 set_upsampling_coef_table(plane);
553 } else if (orig_width > out_width) {
554 /* Downsampling not yet supported
555 */
556
557 enable_lcd_clocks(0);
558 return -EINVAL;
559 }
560 if (!orig_width || orig_width == out_width)
561 fir_hinc = 0;
562 else
563 fir_hinc = 1024 * orig_width / out_width;
564 if (!orig_height || orig_height == out_height)
565 fir_vinc = 0;
566 else
567 fir_vinc = 1024 * orig_height / out_height;
568 dispc.fir_hinc[plane] = fir_hinc;
569 dispc.fir_vinc[plane] = fir_vinc;
570
571 MOD_REG_FLD(fir_reg[plane],
572 FLD_MASK(16, 12) | FLD_MASK(0, 12),
573 ((fir_vinc & 4095) << 16) |
574 (fir_hinc & 4095));
575
576 dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
577 "orig_height %d fir_hinc %d fir_vinc %d\n",
578 out_width, out_height, orig_width, orig_height,
579 fir_hinc, fir_vinc);
580
581 MOD_REG_FLD(vs_reg[plane],
582 FLD_MASK(16, 11) | FLD_MASK(0, 11),
583 ((out_height - 1) << 16) | (out_width - 1));
584
585 l = dispc_read_reg(at_reg[plane]);
586 l &= ~(0x03 << 5);
587 l |= fir_hinc ? (1 << 5) : 0;
588 l |= fir_vinc ? (1 << 6) : 0;
589 dispc_write_reg(at_reg[plane], l);
590
591 enable_lcd_clocks(0);
592 return 0;
593}
594
595static int omap_dispc_enable_plane(int plane, int enable)
596{
597 const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
598 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
599 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
600 if ((unsigned int)plane > dispc.mem_desc.region_cnt)
601 return -EINVAL;
602
603 enable_lcd_clocks(1);
604 MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
605 enable_lcd_clocks(0);
606
607 return 0;
608}
609
610static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
611{
612 u32 df_reg, tr_reg;
613 int shift, val;
614
615 switch (ck->channel_out) {
616 case OMAPFB_CHANNEL_OUT_LCD:
617 df_reg = DISPC_DEFAULT_COLOR0;
618 tr_reg = DISPC_TRANS_COLOR0;
619 shift = 10;
620 break;
621 case OMAPFB_CHANNEL_OUT_DIGIT:
622 df_reg = DISPC_DEFAULT_COLOR1;
623 tr_reg = DISPC_TRANS_COLOR1;
624 shift = 12;
625 break;
626 default:
627 return -EINVAL;
628 }
629 switch (ck->key_type) {
630 case OMAPFB_COLOR_KEY_DISABLED:
631 val = 0;
632 break;
633 case OMAPFB_COLOR_KEY_GFX_DST:
634 val = 1;
635 break;
636 case OMAPFB_COLOR_KEY_VID_SRC:
637 val = 3;
638 break;
639 default:
640 return -EINVAL;
641 }
642 enable_lcd_clocks(1);
643 MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
644
645 if (val != 0)
646 dispc_write_reg(tr_reg, ck->trans_key);
647 dispc_write_reg(df_reg, ck->background);
648 enable_lcd_clocks(0);
649
650 dispc.color_key = *ck;
651
652 return 0;
653}
654
655static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
656{
657 *ck = dispc.color_key;
658 return 0;
659}
660
661static void load_palette(void)
662{
663}
664
665static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
666{
667 int r = 0;
668
669 if (mode != dispc.update_mode) {
670 switch (mode) {
671 case OMAPFB_AUTO_UPDATE:
672 case OMAPFB_MANUAL_UPDATE:
673 enable_lcd_clocks(1);
674 omap_dispc_enable_lcd_out(1);
675 dispc.update_mode = mode;
676 break;
677 case OMAPFB_UPDATE_DISABLED:
678 init_completion(&dispc.frame_done);
679 omap_dispc_enable_lcd_out(0);
680 if (!wait_for_completion_timeout(&dispc.frame_done,
681 msecs_to_jiffies(500))) {
682 dev_err(dispc.fbdev->dev,
683 "timeout waiting for FRAME DONE\n");
684 }
685 dispc.update_mode = mode;
686 enable_lcd_clocks(0);
687 break;
688 default:
689 r = -EINVAL;
690 }
691 }
692
693 return r;
694}
695
696static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps)
697{
698 caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM;
699 if (plane > 0)
700 caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE;
701 caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) |
702 (1 << OMAPFB_COLOR_YUV422) |
703 (1 << OMAPFB_COLOR_YUY422);
704 if (plane == 0)
705 caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) |
706 (1 << OMAPFB_COLOR_CLUT_4BPP) |
707 (1 << OMAPFB_COLOR_CLUT_2BPP) |
708 (1 << OMAPFB_COLOR_CLUT_1BPP) |
709 (1 << OMAPFB_COLOR_RGB444);
710}
711
712static enum omapfb_update_mode omap_dispc_get_update_mode(void)
713{
714 return dispc.update_mode;
715}
716
717static void setup_color_conv_coef(void)
718{
719 u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
720 int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
721 int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
722 int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
723 int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
724 const struct color_conv_coef {
725 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
726 int full_range;
727 } ctbl_bt601_5 = {
728 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
729 };
730 const struct color_conv_coef *ct;
731#define CVAL(x, y) (((x & 2047) << 16) | (y & 2047))
732
733 ct = &ctbl_bt601_5;
734
735 MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry));
736 MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb));
737 MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
738 MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by));
739 MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb));
740
741 MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry));
742 MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb));
743 MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
744 MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by));
745 MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb));
746#undef CVAL
747
748 MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
749 MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
750}
751
752static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
753{
754 unsigned long fck, lck;
755
756 *lck_div = 1;
757 pck = max(1, pck);
758 fck = clk_get_rate(dispc.dss1_fck);
759 lck = fck;
760 *pck_div = (lck + pck - 1) / pck;
761 if (is_tft)
762 *pck_div = max(2, *pck_div);
763 else
764 *pck_div = max(3, *pck_div);
765 if (*pck_div > 255) {
766 *pck_div = 255;
767 lck = pck * *pck_div;
768 *lck_div = fck / lck;
769 BUG_ON(*lck_div < 1);
770 if (*lck_div > 255) {
771 *lck_div = 255;
772 dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
773 pck / 1000);
774 }
775 }
776}
777
778static void set_lcd_tft_mode(int enable)
779{
780 u32 mask;
781
782 mask = 1 << 3;
783 MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
784}
785
786static void set_lcd_timings(void)
787{
788 u32 l;
789 int lck_div, pck_div;
790 struct lcd_panel *panel = dispc.fbdev->panel;
791 int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
792 unsigned long fck;
793
794 l = dispc_read_reg(DISPC_TIMING_H);
795 l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
796 l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0;
797 l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
798 l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
799 dispc_write_reg(DISPC_TIMING_H, l);
800
801 l = dispc_read_reg(DISPC_TIMING_V);
802 l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
803 l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0;
804 l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
805 l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
806 dispc_write_reg(DISPC_TIMING_V, l);
807
808 l = dispc_read_reg(DISPC_POL_FREQ);
809 l &= ~FLD_MASK(12, 6);
810 l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
811 l |= panel->acb & 0xff;
812 dispc_write_reg(DISPC_POL_FREQ, l);
813
814 calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
815
816 l = dispc_read_reg(DISPC_DIVISOR);
817 l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
818 l |= (lck_div << 16) | (pck_div << 0);
819 dispc_write_reg(DISPC_DIVISOR, l);
820
821 /* update panel info with the exact clock */
822 fck = clk_get_rate(dispc.dss1_fck);
823 panel->pixel_clock = fck / lck_div / pck_div / 1000;
824}
825
826static void recalc_irq_mask(void)
827{
828 int i;
829 unsigned long irq_mask = DISPC_IRQ_MASK_ERROR;
830
831 for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
832 if (!dispc.irq_handlers[i].callback)
833 continue;
834
835 irq_mask |= dispc.irq_handlers[i].irq_mask;
836 }
837
838 enable_lcd_clocks(1);
839 MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
840 enable_lcd_clocks(0);
841}
842
843int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data),
844 void *data)
845{
846 int i;
847
848 BUG_ON(callback == NULL);
849
850 for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
851 if (dispc.irq_handlers[i].callback)
852 continue;
853
854 dispc.irq_handlers[i].irq_mask = irq_mask;
855 dispc.irq_handlers[i].callback = callback;
856 dispc.irq_handlers[i].data = data;
857 recalc_irq_mask();
858
859 return 0;
860 }
861
862 return -EBUSY;
863}
864EXPORT_SYMBOL(omap_dispc_request_irq);
865
866void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data),
867 void *data)
868{
869 int i;
870
871 for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
872 if (dispc.irq_handlers[i].callback == callback &&
873 dispc.irq_handlers[i].data == data) {
874 dispc.irq_handlers[i].irq_mask = 0;
875 dispc.irq_handlers[i].callback = NULL;
876 dispc.irq_handlers[i].data = NULL;
877 recalc_irq_mask();
878 return;
879 }
880 }
881
882 BUG();
883}
884EXPORT_SYMBOL(omap_dispc_free_irq);
885
886static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
887{
888 u32 stat;
889 int i = 0;
890
891 enable_lcd_clocks(1);
892
893 stat = dispc_read_reg(DISPC_IRQSTATUS);
894 if (stat & DISPC_IRQ_FRAMEMASK)
895 complete(&dispc.frame_done);
896
897 if (stat & DISPC_IRQ_MASK_ERROR) {
898 if (printk_ratelimit()) {
899 dev_err(dispc.fbdev->dev, "irq error status %04x\n",
900 stat & 0x7fff);
901 }
902 }
903
904 for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
905 if (unlikely(dispc.irq_handlers[i].callback &&
906 (stat & dispc.irq_handlers[i].irq_mask)))
907 dispc.irq_handlers[i].callback(
908 dispc.irq_handlers[i].data);
909 }
910
911 dispc_write_reg(DISPC_IRQSTATUS, stat);
912
913 enable_lcd_clocks(0);
914
915 return IRQ_HANDLED;
916}
917
918static int get_dss_clocks(void)
919{
920 dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
921 if (IS_ERR(dispc.dss_ick)) {
922 dev_err(dispc.fbdev->dev, "can't get ick\n");
923 return PTR_ERR(dispc.dss_ick);
924 }
925
926 dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck");
927 if (IS_ERR(dispc.dss1_fck)) {
928 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
929 clk_put(dispc.dss_ick);
930 return PTR_ERR(dispc.dss1_fck);
931 }
932
933 dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk");
934 if (IS_ERR(dispc.dss_54m_fck)) {
935 dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
936 clk_put(dispc.dss_ick);
937 clk_put(dispc.dss1_fck);
938 return PTR_ERR(dispc.dss_54m_fck);
939 }
940
941 return 0;
942}
943
944static void put_dss_clocks(void)
945{
946 clk_put(dispc.dss_54m_fck);
947 clk_put(dispc.dss1_fck);
948 clk_put(dispc.dss_ick);
949}
950
951static void enable_lcd_clocks(int enable)
952{
953 if (enable) {
954 clk_enable(dispc.dss_ick);
955 clk_enable(dispc.dss1_fck);
956 } else {
957 clk_disable(dispc.dss1_fck);
958 clk_disable(dispc.dss_ick);
959 }
960}
961
962static void enable_digit_clocks(int enable)
963{
964 if (enable)
965 clk_enable(dispc.dss_54m_fck);
966 else
967 clk_disable(dispc.dss_54m_fck);
968}
969
970static void omap_dispc_suspend(void)
971{
972 if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
973 init_completion(&dispc.frame_done);
974 omap_dispc_enable_lcd_out(0);
975 if (!wait_for_completion_timeout(&dispc.frame_done,
976 msecs_to_jiffies(500))) {
977 dev_err(dispc.fbdev->dev,
978 "timeout waiting for FRAME DONE\n");
979 }
980 enable_lcd_clocks(0);
981 }
982}
983
984static void omap_dispc_resume(void)
985{
986 if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
987 enable_lcd_clocks(1);
988 if (!dispc.ext_mode) {
989 set_lcd_timings();
990 load_palette();
991 }
992 omap_dispc_enable_lcd_out(1);
993 }
994}
995
996
997static int omap_dispc_update_window(struct fb_info *fbi,
998 struct omapfb_update_window *win,
999 void (*complete_callback)(void *arg),
1000 void *complete_callback_data)
1001{
1002 return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
1003}
1004
1005static int mmap_kern(struct omapfb_mem_region *region)
1006{
1007 struct vm_struct *kvma;
1008 struct vm_area_struct vma;
1009 pgprot_t pgprot;
1010 unsigned long vaddr;
1011
1012 kvma = get_vm_area(region->size, VM_IOREMAP);
1013 if (kvma == NULL) {
1014 dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
1015 return -ENOMEM;
1016 }
1017 vma.vm_mm = &init_mm;
1018
1019 vaddr = (unsigned long)kvma->addr;
1020
1021 pgprot = pgprot_writecombine(pgprot_kernel);
1022 vma.vm_start = vaddr;
1023 vma.vm_end = vaddr + region->size;
1024 if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
1025 region->size, pgprot) < 0) {
1026 dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
1027 return -EAGAIN;
1028 }
1029 region->vaddr = (void *)vaddr;
1030
1031 return 0;
1032}
1033
1034static void mmap_user_open(struct vm_area_struct *vma)
1035{
1036 int plane = (int)vma->vm_private_data;
1037
1038 atomic_inc(&dispc.map_count[plane]);
1039}
1040
1041static void mmap_user_close(struct vm_area_struct *vma)
1042{
1043 int plane = (int)vma->vm_private_data;
1044
1045 atomic_dec(&dispc.map_count[plane]);
1046}
1047
1048static const struct vm_operations_struct mmap_user_ops = {
1049 .open = mmap_user_open,
1050 .close = mmap_user_close,
1051};
1052
1053static int omap_dispc_mmap_user(struct fb_info *info,
1054 struct vm_area_struct *vma)
1055{
1056 struct omapfb_plane_struct *plane = info->par;
1057 unsigned long off;
1058 unsigned long start;
1059 u32 len;
1060
1061 if (vma->vm_end - vma->vm_start == 0)
1062 return 0;
1063 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1064 return -EINVAL;
1065 off = vma->vm_pgoff << PAGE_SHIFT;
1066
1067 start = info->fix.smem_start;
1068 len = info->fix.smem_len;
1069 if (off >= len)
1070 return -EINVAL;
1071 if ((vma->vm_end - vma->vm_start + off) > len)
1072 return -EINVAL;
1073 off += start;
1074 vma->vm_pgoff = off >> PAGE_SHIFT;
1075 vma->vm_flags |= VM_IO | VM_RESERVED;
1076 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1077 vma->vm_ops = &mmap_user_ops;
1078 vma->vm_private_data = (void *)plane->idx;
1079 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1080 vma->vm_end - vma->vm_start, vma->vm_page_prot))
1081 return -EAGAIN;
1082 /* vm_ops.open won't be called for mmap itself. */
1083 atomic_inc(&dispc.map_count[plane->idx]);
1084 return 0;
1085}
1086
1087static void unmap_kern(struct omapfb_mem_region *region)
1088{
1089 vunmap(region->vaddr);
1090}
1091
1092static int alloc_palette_ram(void)
1093{
1094 dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1095 MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
1096 if (dispc.palette_vaddr == NULL) {
1097 dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
1098 return -ENOMEM;
1099 }
1100
1101 return 0;
1102}
1103
1104static void free_palette_ram(void)
1105{
1106 dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
1107 dispc.palette_vaddr, dispc.palette_paddr);
1108}
1109
1110static int alloc_fbmem(struct omapfb_mem_region *region)
1111{
1112 region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1113 region->size, &region->paddr, GFP_KERNEL);
1114
1115 if (region->vaddr == NULL) {
1116 dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
1117 return -ENOMEM;
1118 }
1119
1120 return 0;
1121}
1122
1123static void free_fbmem(struct omapfb_mem_region *region)
1124{
1125 dma_free_writecombine(dispc.fbdev->dev, region->size,
1126 region->vaddr, region->paddr);
1127}
1128
1129static struct resmap *init_resmap(unsigned long start, size_t size)
1130{
1131 unsigned page_cnt;
1132 struct resmap *res_map;
1133
1134 page_cnt = PAGE_ALIGN(size) / PAGE_SIZE;
1135 res_map =
1136 kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL);
1137 if (res_map == NULL)
1138 return NULL;
1139 res_map->start = start;
1140 res_map->page_cnt = page_cnt;
1141 res_map->map = (unsigned long *)(res_map + 1);
1142 return res_map;
1143}
1144
1145static void cleanup_resmap(struct resmap *res_map)
1146{
1147 kfree(res_map);
1148}
1149
1150static inline int resmap_mem_type(unsigned long start)
1151{
1152 if (start >= OMAP2_SRAM_START &&
1153 start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
1154 return OMAPFB_MEMTYPE_SRAM;
1155 else
1156 return OMAPFB_MEMTYPE_SDRAM;
1157}
1158
1159static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr)
1160{
1161 return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0;
1162}
1163
1164static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr)
1165{
1166 BUG_ON(resmap_page_reserved(res_map, page_nr));
1167 *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr);
1168}
1169
1170static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr)
1171{
1172 BUG_ON(!resmap_page_reserved(res_map, page_nr));
1173 *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr);
1174}
1175
1176static void resmap_reserve_region(unsigned long start, size_t size)
1177{
1178
1179 struct resmap *res_map;
1180 unsigned start_page;
1181 unsigned end_page;
1182 int mtype;
1183 unsigned i;
1184
1185 mtype = resmap_mem_type(start);
1186 res_map = dispc.res_map[mtype];
1187 dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n",
1188 mtype, start, size);
1189 start_page = (start - res_map->start) / PAGE_SIZE;
1190 end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
1191 for (i = start_page; i < end_page; i++)
1192 resmap_reserve_page(res_map, i);
1193}
1194
1195static void resmap_free_region(unsigned long start, size_t size)
1196{
1197 struct resmap *res_map;
1198 unsigned start_page;
1199 unsigned end_page;
1200 unsigned i;
1201 int mtype;
1202
1203 mtype = resmap_mem_type(start);
1204 res_map = dispc.res_map[mtype];
1205 dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n",
1206 mtype, start, size);
1207 start_page = (start - res_map->start) / PAGE_SIZE;
1208 end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
1209 for (i = start_page; i < end_page; i++)
1210 resmap_free_page(res_map, i);
1211}
1212
1213static unsigned long resmap_alloc_region(int mtype, size_t size)
1214{
1215 unsigned i;
1216 unsigned total;
1217 unsigned start_page;
1218 unsigned long start;
1219 struct resmap *res_map = dispc.res_map[mtype];
1220
1221 BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size);
1222
1223 size = PAGE_ALIGN(size) / PAGE_SIZE;
1224 start_page = 0;
1225 total = 0;
1226 for (i = 0; i < res_map->page_cnt; i++) {
1227 if (resmap_page_reserved(res_map, i)) {
1228 start_page = i + 1;
1229 total = 0;
1230 } else if (++total == size)
1231 break;
1232 }
1233 if (total < size)
1234 return 0;
1235
1236 start = res_map->start + start_page * PAGE_SIZE;
1237 resmap_reserve_region(start, size * PAGE_SIZE);
1238
1239 return start;
1240}
1241
1242/* Note that this will only work for user mappings, we don't deal with
1243 * kernel mappings here, so fbcon will keep using the old region.
1244 */
1245static int omap_dispc_setup_mem(int plane, size_t size, int mem_type,
1246 unsigned long *paddr)
1247{
1248 struct omapfb_mem_region *rg;
1249 unsigned long new_addr = 0;
1250
1251 if ((unsigned)plane > dispc.mem_desc.region_cnt)
1252 return -EINVAL;
1253 if (mem_type >= DISPC_MEMTYPE_NUM)
1254 return -EINVAL;
1255 if (dispc.res_map[mem_type] == NULL)
1256 return -ENOMEM;
1257 rg = &dispc.mem_desc.region[plane];
1258 if (size == rg->size && mem_type == rg->type)
1259 return 0;
1260 if (atomic_read(&dispc.map_count[plane]))
1261 return -EBUSY;
1262 if (rg->size != 0)
1263 resmap_free_region(rg->paddr, rg->size);
1264 if (size != 0) {
1265 new_addr = resmap_alloc_region(mem_type, size);
1266 if (!new_addr) {
1267 /* Reallocate old region. */
1268 resmap_reserve_region(rg->paddr, rg->size);
1269 return -ENOMEM;
1270 }
1271 }
1272 rg->paddr = new_addr;
1273 rg->size = size;
1274 rg->type = mem_type;
1275
1276 *paddr = new_addr;
1277
1278 return 0;
1279}
1280
1281static int setup_fbmem(struct omapfb_mem_desc *req_md)
1282{
1283 struct omapfb_mem_region *rg;
1284 int i;
1285 int r;
1286 unsigned long mem_start[DISPC_MEMTYPE_NUM];
1287 unsigned long mem_end[DISPC_MEMTYPE_NUM];
1288
1289 if (!req_md->region_cnt) {
1290 dev_err(dispc.fbdev->dev, "no memory regions defined\n");
1291 return -ENOENT;
1292 }
1293
1294 rg = &req_md->region[0];
1295 memset(mem_start, 0xff, sizeof(mem_start));
1296 memset(mem_end, 0, sizeof(mem_end));
1297
1298 for (i = 0; i < req_md->region_cnt; i++, rg++) {
1299 int mtype;
1300 if (rg->paddr) {
1301 rg->alloc = 0;
1302 if (rg->vaddr == NULL) {
1303 rg->map = 1;
1304 if ((r = mmap_kern(rg)) < 0)
1305 return r;
1306 }
1307 } else {
1308 if (rg->type != OMAPFB_MEMTYPE_SDRAM) {
1309 dev_err(dispc.fbdev->dev,
1310 "unsupported memory type\n");
1311 return -EINVAL;
1312 }
1313 rg->alloc = rg->map = 1;
1314 if ((r = alloc_fbmem(rg)) < 0)
1315 return r;
1316 }
1317 mtype = rg->type;
1318
1319 if (rg->paddr < mem_start[mtype])
1320 mem_start[mtype] = rg->paddr;
1321 if (rg->paddr + rg->size > mem_end[mtype])
1322 mem_end[mtype] = rg->paddr + rg->size;
1323 }
1324
1325 for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1326 unsigned long start;
1327 size_t size;
1328 if (mem_end[i] == 0)
1329 continue;
1330 start = mem_start[i];
1331 size = mem_end[i] - start;
1332 dispc.res_map[i] = init_resmap(start, size);
1333 r = -ENOMEM;
1334 if (dispc.res_map[i] == NULL)
1335 goto fail;
1336 /* Initial state is that everything is reserved. This
1337 * includes possible holes as well, which will never be
1338 * freed.
1339 */
1340 resmap_reserve_region(start, size);
1341 }
1342
1343 dispc.mem_desc = *req_md;
1344
1345 return 0;
1346fail:
1347 for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1348 if (dispc.res_map[i] != NULL)
1349 cleanup_resmap(dispc.res_map[i]);
1350 }
1351 return r;
1352}
1353
1354static void cleanup_fbmem(void)
1355{
1356 struct omapfb_mem_region *rg;
1357 int i;
1358
1359 for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1360 if (dispc.res_map[i] != NULL)
1361 cleanup_resmap(dispc.res_map[i]);
1362 }
1363 rg = &dispc.mem_desc.region[0];
1364 for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) {
1365 if (rg->alloc)
1366 free_fbmem(rg);
1367 else {
1368 if (rg->map)
1369 unmap_kern(rg);
1370 }
1371 }
1372}
1373
1374static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1375 struct omapfb_mem_desc *req_vram)
1376{
1377 int r;
1378 u32 l;
1379 struct lcd_panel *panel = fbdev->panel;
1380 void __iomem *ram_fw_base;
1381 int tmo = 10000;
1382 int skip_init = 0;
1383 int i;
1384
1385 memset(&dispc, 0, sizeof(dispc));
1386
1387 dispc.base = ioremap(DISPC_BASE, SZ_1K);
1388 if (!dispc.base) {
1389 dev_err(fbdev->dev, "can't ioremap DISPC\n");
1390 return -ENOMEM;
1391 }
1392
1393 dispc.fbdev = fbdev;
1394 dispc.ext_mode = ext_mode;
1395
1396 init_completion(&dispc.frame_done);
1397
1398 if ((r = get_dss_clocks()) < 0)
1399 goto fail0;
1400
1401 enable_lcd_clocks(1);
1402
1403#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
1404 l = dispc_read_reg(DISPC_CONTROL);
1405 /* LCD enabled ? */
1406 if (l & 1) {
1407 pr_info("omapfb: skipping hardware initialization\n");
1408 skip_init = 1;
1409 }
1410#endif
1411
1412 if (!skip_init) {
1413 /* Reset monitoring works only w/ the 54M clk */
1414 enable_digit_clocks(1);
1415
1416 /* Soft reset */
1417 MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
1418
1419 while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
1420 if (!--tmo) {
1421 dev_err(dispc.fbdev->dev, "soft reset failed\n");
1422 r = -ENODEV;
1423 enable_digit_clocks(0);
1424 goto fail1;
1425 }
1426 }
1427
1428 enable_digit_clocks(0);
1429 }
1430
1431 /* Enable smart standby/idle, autoidle and wakeup */
1432 l = dispc_read_reg(DISPC_SYSCONFIG);
1433 l &= ~((3 << 12) | (3 << 3));
1434 l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0);
1435 dispc_write_reg(DISPC_SYSCONFIG, l);
1436 omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
1437
1438 /* Set functional clock autogating */
1439 l = dispc_read_reg(DISPC_CONFIG);
1440 l |= 1 << 9;
1441 dispc_write_reg(DISPC_CONFIG, l);
1442
1443 l = dispc_read_reg(DISPC_IRQSTATUS);
1444 dispc_write_reg(DISPC_IRQSTATUS, l);
1445
1446 recalc_irq_mask();
1447
1448 if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
1449 0, MODULE_NAME, fbdev)) < 0) {
1450 dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
1451 goto fail1;
1452 }
1453
1454 /* L3 firewall setting: enable access to OCM RAM */
1455 ram_fw_base = ioremap(0x68005000, SZ_1K);
1456 if (!ram_fw_base) {
1457 dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
1458 goto fail1;
1459 }
1460 __raw_writel(0x402000b0, ram_fw_base + 0xa0);
1461 iounmap(ram_fw_base);
1462
1463 if ((r = alloc_palette_ram()) < 0)
1464 goto fail2;
1465
1466 if ((r = setup_fbmem(req_vram)) < 0)
1467 goto fail3;
1468
1469 if (!skip_init) {
1470 for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
1471 memset(dispc.mem_desc.region[i].vaddr, 0,
1472 dispc.mem_desc.region[i].size);
1473 }
1474
1475 /* Set logic clock to fck, pixel clock to fck/2 for now */
1476 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
1477 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
1478
1479 setup_plane_fifo(0, ext_mode);
1480 setup_plane_fifo(1, ext_mode);
1481 setup_plane_fifo(2, ext_mode);
1482
1483 setup_color_conv_coef();
1484
1485 set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
1486 set_load_mode(DISPC_LOAD_FRAME_ONLY);
1487
1488 if (!ext_mode) {
1489 set_lcd_data_lines(panel->data_lines);
1490 omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
1491 set_lcd_timings();
1492 } else
1493 set_lcd_data_lines(panel->bpp);
1494 enable_rfbi_mode(ext_mode);
1495 }
1496
1497 l = dispc_read_reg(DISPC_REVISION);
1498 pr_info("omapfb: DISPC version %d.%d initialized\n",
1499 l >> 4 & 0x0f, l & 0x0f);
1500 enable_lcd_clocks(0);
1501
1502 return 0;
1503fail3:
1504 free_palette_ram();
1505fail2:
1506 free_irq(INT_24XX_DSS_IRQ, fbdev);
1507fail1:
1508 enable_lcd_clocks(0);
1509 put_dss_clocks();
1510fail0:
1511 iounmap(dispc.base);
1512 return r;
1513}
1514
1515static void omap_dispc_cleanup(void)
1516{
1517 int i;
1518
1519 omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED);
1520 /* This will also disable clocks that are on */
1521 for (i = 0; i < dispc.mem_desc.region_cnt; i++)
1522 omap_dispc_enable_plane(i, 0);
1523 cleanup_fbmem();
1524 free_palette_ram();
1525 free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
1526 put_dss_clocks();
1527 iounmap(dispc.base);
1528}
1529
1530const struct lcd_ctrl omap2_int_ctrl = {
1531 .name = "internal",
1532 .init = omap_dispc_init,
1533 .cleanup = omap_dispc_cleanup,
1534 .get_caps = omap_dispc_get_caps,
1535 .set_update_mode = omap_dispc_set_update_mode,
1536 .get_update_mode = omap_dispc_get_update_mode,
1537 .update_window = omap_dispc_update_window,
1538 .suspend = omap_dispc_suspend,
1539 .resume = omap_dispc_resume,
1540 .setup_plane = omap_dispc_setup_plane,
1541 .setup_mem = omap_dispc_setup_mem,
1542 .set_scale = omap_dispc_set_scale,
1543 .enable_plane = omap_dispc_enable_plane,
1544 .set_color_key = omap_dispc_set_color_key,
1545 .get_color_key = omap_dispc_get_color_key,
1546 .mmap = omap_dispc_mmap_user,
1547};
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h
deleted file mode 100644
index c15ea77f0604..000000000000
--- a/drivers/video/omap/dispc.h
+++ /dev/null
@@ -1,46 +0,0 @@
1#ifndef _DISPC_H
2#define _DISPC_H
3
4#include <linux/interrupt.h>
5
6#define DISPC_PLANE_GFX 0
7#define DISPC_PLANE_VID1 1
8#define DISPC_PLANE_VID2 2
9
10#define DISPC_RGB_1_BPP 0x00
11#define DISPC_RGB_2_BPP 0x01
12#define DISPC_RGB_4_BPP 0x02
13#define DISPC_RGB_8_BPP 0x03
14#define DISPC_RGB_12_BPP 0x04
15#define DISPC_RGB_16_BPP 0x06
16#define DISPC_RGB_24_BPP 0x08
17#define DISPC_RGB_24_BPP_UNPACK_32 0x09
18#define DISPC_YUV2_422 0x0a
19#define DISPC_UYVY_422 0x0b
20
21#define DISPC_BURST_4x32 0
22#define DISPC_BURST_8x32 1
23#define DISPC_BURST_16x32 2
24
25#define DISPC_LOAD_CLUT_AND_FRAME 0x00
26#define DISPC_LOAD_CLUT_ONLY 0x01
27#define DISPC_LOAD_FRAME_ONLY 0x02
28#define DISPC_LOAD_CLUT_ONCE_FRAME 0x03
29
30#define DISPC_TFT_DATA_LINES_12 0
31#define DISPC_TFT_DATA_LINES_16 1
32#define DISPC_TFT_DATA_LINES_18 2
33#define DISPC_TFT_DATA_LINES_24 3
34
35extern void omap_dispc_set_lcd_size(int width, int height);
36
37extern void omap_dispc_enable_lcd_out(int enable);
38extern void omap_dispc_enable_digit_out(int enable);
39
40extern int omap_dispc_request_irq(unsigned long irq_mask,
41 void (*callback)(void *data), void *data);
42extern void omap_dispc_free_irq(unsigned long irq_mask,
43 void (*callback)(void *data), void *data);
44
45extern const struct lcd_ctrl omap2_int_ctrl;
46#endif
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h
index af3c9e571ec3..3a5ab13845fc 100644
--- a/drivers/video/omap/omapfb.h
+++ b/drivers/video/omap/omapfb.h
@@ -207,11 +207,7 @@ struct omapfb_device {
207 struct platform_device *dssdev; /* dummy dev for clocks */ 207 struct platform_device *dssdev; /* dummy dev for clocks */
208}; 208};
209 209
210#ifdef CONFIG_ARCH_OMAP1
211extern struct lcd_ctrl omap1_lcd_ctrl; 210extern struct lcd_ctrl omap1_lcd_ctrl;
212#else
213extern struct lcd_ctrl omap2_disp_ctrl;
214#endif
215 211
216extern void omapfb_register_panel(struct lcd_panel *panel); 212extern void omapfb_register_panel(struct lcd_panel *panel);
217extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); 213extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 440a5dd06654..73924bc9959e 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -34,7 +34,6 @@
34 34
35#include "omapfb.h" 35#include "omapfb.h"
36#include "lcdc.h" 36#include "lcdc.h"
37#include "dispc.h"
38 37
39#define MODULE_NAME "omapfb" 38#define MODULE_NAME "omapfb"
40 39
@@ -106,11 +105,7 @@ static struct platform_device omapdss_device = {
106extern struct lcd_ctrl hwa742_ctrl; 105extern struct lcd_ctrl hwa742_ctrl;
107 106
108static const struct lcd_ctrl *ctrls[] = { 107static const struct lcd_ctrl *ctrls[] = {
109#ifdef CONFIG_ARCH_OMAP1
110 &omap1_int_ctrl, 108 &omap1_int_ctrl,
111#else
112 &omap2_int_ctrl,
113#endif
114 109
115#ifdef CONFIG_FB_OMAP_LCDC_HWA742 110#ifdef CONFIG_FB_OMAP_LCDC_HWA742
116 &hwa742_ctrl, 111 &hwa742_ctrl,
@@ -118,11 +113,7 @@ static const struct lcd_ctrl *ctrls[] = {
118}; 113};
119 114
120#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 115#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
121#ifdef CONFIG_ARCH_OMAP1
122extern struct lcd_ctrl_extif omap1_ext_if; 116extern struct lcd_ctrl_extif omap1_ext_if;
123#else
124extern struct lcd_ctrl_extif omap2_ext_if;
125#endif
126#endif 117#endif
127 118
128static void omapfb_rqueue_lock(struct omapfb_device *fbdev) 119static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
@@ -1717,17 +1708,10 @@ static int omapfb_do_probe(struct platform_device *pdev,
1717 1708
1718 mutex_init(&fbdev->rqueue_mutex); 1709 mutex_init(&fbdev->rqueue_mutex);
1719 1710
1720#ifdef CONFIG_ARCH_OMAP1
1721 fbdev->int_ctrl = &omap1_int_ctrl; 1711 fbdev->int_ctrl = &omap1_int_ctrl;
1722#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 1712#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1723 fbdev->ext_if = &omap1_ext_if; 1713 fbdev->ext_if = &omap1_ext_if;
1724#endif 1714#endif
1725#else /* OMAP2 */
1726 fbdev->int_ctrl = &omap2_int_ctrl;
1727#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1728 fbdev->ext_if = &omap2_ext_if;
1729#endif
1730#endif
1731 if (omapfb_find_ctrl(fbdev) < 0) { 1715 if (omapfb_find_ctrl(fbdev) < 0) {
1732 dev_err(fbdev->dev, 1716 dev_err(fbdev->dev,
1733 "LCD controller not found, board not supported\n"); 1717 "LCD controller not found, board not supported\n");
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
deleted file mode 100644
index 2c1a3402bef0..000000000000
--- a/drivers/video/omap/rfbi.c
+++ /dev/null
@@ -1,598 +0,0 @@
1/*
2 * OMAP2 Remote Frame Buffer Interface support
3 *
4 * Copyright (C) 2005 Nokia Corporation
5 * Author: Juha Yrjölä <juha.yrjola@nokia.com>
6 * Imre Deak <imre.deak@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/i2c.h>
25#include <linux/err.h>
26#include <linux/interrupt.h>
27#include <linux/clk.h>
28#include <linux/io.h>
29#include <linux/platform_device.h>
30
31#include "omapfb.h"
32#include "dispc.h"
33
34/* To work around an RFBI transfer rate limitation */
35#define OMAP_RFBI_RATE_LIMIT 1
36
37#define RFBI_BASE 0x48050800
38#define RFBI_REVISION 0x0000
39#define RFBI_SYSCONFIG 0x0010
40#define RFBI_SYSSTATUS 0x0014
41#define RFBI_CONTROL 0x0040
42#define RFBI_PIXEL_CNT 0x0044
43#define RFBI_LINE_NUMBER 0x0048
44#define RFBI_CMD 0x004c
45#define RFBI_PARAM 0x0050
46#define RFBI_DATA 0x0054
47#define RFBI_READ 0x0058
48#define RFBI_STATUS 0x005c
49#define RFBI_CONFIG0 0x0060
50#define RFBI_ONOFF_TIME0 0x0064
51#define RFBI_CYCLE_TIME0 0x0068
52#define RFBI_DATA_CYCLE1_0 0x006c
53#define RFBI_DATA_CYCLE2_0 0x0070
54#define RFBI_DATA_CYCLE3_0 0x0074
55#define RFBI_VSYNC_WIDTH 0x0090
56#define RFBI_HSYNC_WIDTH 0x0094
57
58#define DISPC_BASE 0x48050400
59#define DISPC_CONTROL 0x0040
60#define DISPC_IRQ_FRAMEMASK 0x0001
61
62static struct {
63 void __iomem *base;
64 void (*lcdc_callback)(void *data);
65 void *lcdc_callback_data;
66 unsigned long l4_khz;
67 int bits_per_cycle;
68 struct omapfb_device *fbdev;
69 struct clk *dss_ick;
70 struct clk *dss1_fck;
71 unsigned tearsync_pin_cnt;
72 unsigned tearsync_mode;
73} rfbi;
74
75static inline void rfbi_write_reg(int idx, u32 val)
76{
77 __raw_writel(val, rfbi.base + idx);
78}
79
80static inline u32 rfbi_read_reg(int idx)
81{
82 return __raw_readl(rfbi.base + idx);
83}
84
85static int rfbi_get_clocks(void)
86{
87 rfbi.dss_ick = clk_get(&rfbi.fbdev->dssdev->dev, "ick");
88 if (IS_ERR(rfbi.dss_ick)) {
89 dev_err(rfbi.fbdev->dev, "can't get ick\n");
90 return PTR_ERR(rfbi.dss_ick);
91 }
92
93 rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck");
94 if (IS_ERR(rfbi.dss1_fck)) {
95 dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
96 clk_put(rfbi.dss_ick);
97 return PTR_ERR(rfbi.dss1_fck);
98 }
99
100 return 0;
101}
102
103static void rfbi_put_clocks(void)
104{
105 clk_put(rfbi.dss1_fck);
106 clk_put(rfbi.dss_ick);
107}
108
109static void rfbi_enable_clocks(int enable)
110{
111 if (enable) {
112 clk_enable(rfbi.dss_ick);
113 clk_enable(rfbi.dss1_fck);
114 } else {
115 clk_disable(rfbi.dss1_fck);
116 clk_disable(rfbi.dss_ick);
117 }
118}
119
120
121#ifdef VERBOSE
122static void rfbi_print_timings(void)
123{
124 u32 l;
125 u32 time;
126
127 l = rfbi_read_reg(RFBI_CONFIG0);
128 time = 1000000000 / rfbi.l4_khz;
129 if (l & (1 << 4))
130 time *= 2;
131
132 dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time);
133 l = rfbi_read_reg(RFBI_ONOFF_TIME0);
134 dev_dbg(rfbi.fbdev->dev,
135 "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
136 "REONTIME %d, REOFFTIME %d\n",
137 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
138 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
139
140 l = rfbi_read_reg(RFBI_CYCLE_TIME0);
141 dev_dbg(rfbi.fbdev->dev,
142 "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
143 "ACCESSTIME %d\n",
144 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
145 (l >> 22) & 0x3f);
146}
147#else
148static void rfbi_print_timings(void) {}
149#endif
150
151static void rfbi_set_timings(const struct extif_timings *t)
152{
153 u32 l;
154
155 BUG_ON(!t->converted);
156
157 rfbi_enable_clocks(1);
158 rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
159 rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
160
161 l = rfbi_read_reg(RFBI_CONFIG0);
162 l &= ~(1 << 4);
163 l |= (t->tim[2] ? 1 : 0) << 4;
164 rfbi_write_reg(RFBI_CONFIG0, l);
165
166 rfbi_print_timings();
167 rfbi_enable_clocks(0);
168}
169
170static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
171{
172 *clk_period = 1000000000 / rfbi.l4_khz;
173 *max_clk_div = 2;
174}
175
176static int ps_to_rfbi_ticks(int time, int div)
177{
178 unsigned long tick_ps;
179 int ret;
180
181 /* Calculate in picosecs to yield more exact results */
182 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
183
184 ret = (time + tick_ps - 1) / tick_ps;
185
186 return ret;
187}
188
189#ifdef OMAP_RFBI_RATE_LIMIT
190static unsigned long rfbi_get_max_tx_rate(void)
191{
192 unsigned long l4_rate, dss1_rate;
193 int min_l4_ticks = 0;
194 int i;
195
196 /* According to TI this can't be calculated so make the
197 * adjustments for a couple of known frequencies and warn for
198 * others.
199 */
200 static const struct {
201 unsigned long l4_clk; /* HZ */
202 unsigned long dss1_clk; /* HZ */
203 unsigned long min_l4_ticks;
204 } ftab[] = {
205 { 55, 132, 7, }, /* 7.86 MPix/s */
206 { 110, 110, 12, }, /* 9.16 MPix/s */
207 { 110, 132, 10, }, /* 11 Mpix/s */
208 { 120, 120, 10, }, /* 12 Mpix/s */
209 { 133, 133, 10, }, /* 13.3 Mpix/s */
210 };
211
212 l4_rate = rfbi.l4_khz / 1000;
213 dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000;
214
215 for (i = 0; i < ARRAY_SIZE(ftab); i++) {
216 /* Use a window instead of an exact match, to account
217 * for different DPLL multiplier / divider pairs.
218 */
219 if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
220 abs(ftab[i].dss1_clk - dss1_rate) < 3) {
221 min_l4_ticks = ftab[i].min_l4_ticks;
222 break;
223 }
224 }
225 if (i == ARRAY_SIZE(ftab)) {
226 /* Can't be sure, return anyway the maximum not
227 * rate-limited. This might cause a problem only for the
228 * tearing synchronisation.
229 */
230 dev_err(rfbi.fbdev->dev,
231 "can't determine maximum RFBI transfer rate\n");
232 return rfbi.l4_khz * 1000;
233 }
234 return rfbi.l4_khz * 1000 / min_l4_ticks;
235}
236#else
237static int rfbi_get_max_tx_rate(void)
238{
239 return rfbi.l4_khz * 1000;
240}
241#endif
242
243
244static int rfbi_convert_timings(struct extif_timings *t)
245{
246 u32 l;
247 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
248 int actim, recyc, wecyc;
249 int div = t->clk_div;
250
251 if (div <= 0 || div > 2)
252 return -1;
253
254 /* Make sure that after conversion it still holds that:
255 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
256 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
257 */
258 weon = ps_to_rfbi_ticks(t->we_on_time, div);
259 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
260 if (weoff <= weon)
261 weoff = weon + 1;
262 if (weon > 0x0f)
263 return -1;
264 if (weoff > 0x3f)
265 return -1;
266
267 reon = ps_to_rfbi_ticks(t->re_on_time, div);
268 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
269 if (reoff <= reon)
270 reoff = reon + 1;
271 if (reon > 0x0f)
272 return -1;
273 if (reoff > 0x3f)
274 return -1;
275
276 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
277 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
278 if (csoff <= cson)
279 csoff = cson + 1;
280 if (csoff < max(weoff, reoff))
281 csoff = max(weoff, reoff);
282 if (cson > 0x0f)
283 return -1;
284 if (csoff > 0x3f)
285 return -1;
286
287 l = cson;
288 l |= csoff << 4;
289 l |= weon << 10;
290 l |= weoff << 14;
291 l |= reon << 20;
292 l |= reoff << 24;
293
294 t->tim[0] = l;
295
296 actim = ps_to_rfbi_ticks(t->access_time, div);
297 if (actim <= reon)
298 actim = reon + 1;
299 if (actim > 0x3f)
300 return -1;
301
302 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
303 if (wecyc < weoff)
304 wecyc = weoff;
305 if (wecyc > 0x3f)
306 return -1;
307
308 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
309 if (recyc < reoff)
310 recyc = reoff;
311 if (recyc > 0x3f)
312 return -1;
313
314 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
315 if (cs_pulse > 0x3f)
316 return -1;
317
318 l = wecyc;
319 l |= recyc << 6;
320 l |= cs_pulse << 12;
321 l |= actim << 22;
322
323 t->tim[1] = l;
324
325 t->tim[2] = div - 1;
326
327 t->converted = 1;
328
329 return 0;
330}
331
332static int rfbi_setup_tearsync(unsigned pin_cnt,
333 unsigned hs_pulse_time, unsigned vs_pulse_time,
334 int hs_pol_inv, int vs_pol_inv, int extif_div)
335{
336 int hs, vs;
337 int min;
338 u32 l;
339
340 if (pin_cnt != 1 && pin_cnt != 2)
341 return -EINVAL;
342
343 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
344 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
345 if (hs < 2)
346 return -EDOM;
347 if (pin_cnt == 2)
348 min = 2;
349 else
350 min = 4;
351 if (vs < min)
352 return -EDOM;
353 if (vs == hs)
354 return -EINVAL;
355 rfbi.tearsync_pin_cnt = pin_cnt;
356 dev_dbg(rfbi.fbdev->dev,
357 "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n",
358 pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv);
359
360 rfbi_enable_clocks(1);
361 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
362 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
363
364 l = rfbi_read_reg(RFBI_CONFIG0);
365 if (hs_pol_inv)
366 l &= ~(1 << 21);
367 else
368 l |= 1 << 21;
369 if (vs_pol_inv)
370 l &= ~(1 << 20);
371 else
372 l |= 1 << 20;
373 rfbi_enable_clocks(0);
374
375 return 0;
376}
377
378static int rfbi_enable_tearsync(int enable, unsigned line)
379{
380 u32 l;
381
382 dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n",
383 enable, line, rfbi.tearsync_mode);
384 if (line > (1 << 11) - 1)
385 return -EINVAL;
386
387 rfbi_enable_clocks(1);
388 l = rfbi_read_reg(RFBI_CONFIG0);
389 l &= ~(0x3 << 2);
390 if (enable) {
391 rfbi.tearsync_mode = rfbi.tearsync_pin_cnt;
392 l |= rfbi.tearsync_mode << 2;
393 } else
394 rfbi.tearsync_mode = 0;
395 rfbi_write_reg(RFBI_CONFIG0, l);
396 rfbi_write_reg(RFBI_LINE_NUMBER, line);
397 rfbi_enable_clocks(0);
398
399 return 0;
400}
401
402static void rfbi_write_command(const void *buf, unsigned int len)
403{
404 rfbi_enable_clocks(1);
405 if (rfbi.bits_per_cycle == 16) {
406 const u16 *w = buf;
407 BUG_ON(len & 1);
408 for (; len; len -= 2)
409 rfbi_write_reg(RFBI_CMD, *w++);
410 } else {
411 const u8 *b = buf;
412 BUG_ON(rfbi.bits_per_cycle != 8);
413 for (; len; len--)
414 rfbi_write_reg(RFBI_CMD, *b++);
415 }
416 rfbi_enable_clocks(0);
417}
418
419static void rfbi_read_data(void *buf, unsigned int len)
420{
421 rfbi_enable_clocks(1);
422 if (rfbi.bits_per_cycle == 16) {
423 u16 *w = buf;
424 BUG_ON(len & ~1);
425 for (; len; len -= 2) {
426 rfbi_write_reg(RFBI_READ, 0);
427 *w++ = rfbi_read_reg(RFBI_READ);
428 }
429 } else {
430 u8 *b = buf;
431 BUG_ON(rfbi.bits_per_cycle != 8);
432 for (; len; len--) {
433 rfbi_write_reg(RFBI_READ, 0);
434 *b++ = rfbi_read_reg(RFBI_READ);
435 }
436 }
437 rfbi_enable_clocks(0);
438}
439
440static void rfbi_write_data(const void *buf, unsigned int len)
441{
442 rfbi_enable_clocks(1);
443 if (rfbi.bits_per_cycle == 16) {
444 const u16 *w = buf;
445 BUG_ON(len & 1);
446 for (; len; len -= 2)
447 rfbi_write_reg(RFBI_PARAM, *w++);
448 } else {
449 const u8 *b = buf;
450 BUG_ON(rfbi.bits_per_cycle != 8);
451 for (; len; len--)
452 rfbi_write_reg(RFBI_PARAM, *b++);
453 }
454 rfbi_enable_clocks(0);
455}
456
457static void rfbi_transfer_area(int width, int height,
458 void (callback)(void * data), void *data)
459{
460 u32 w;
461
462 BUG_ON(callback == NULL);
463
464 rfbi_enable_clocks(1);
465 omap_dispc_set_lcd_size(width, height);
466
467 rfbi.lcdc_callback = callback;
468 rfbi.lcdc_callback_data = data;
469
470 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
471
472 w = rfbi_read_reg(RFBI_CONTROL);
473 w |= 1; /* enable */
474 if (!rfbi.tearsync_mode)
475 w |= 1 << 4; /* internal trigger, reset by HW */
476 rfbi_write_reg(RFBI_CONTROL, w);
477
478 omap_dispc_enable_lcd_out(1);
479}
480
481static inline void _stop_transfer(void)
482{
483 u32 w;
484
485 w = rfbi_read_reg(RFBI_CONTROL);
486 rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0));
487 rfbi_enable_clocks(0);
488}
489
490static void rfbi_dma_callback(void *data)
491{
492 _stop_transfer();
493 rfbi.lcdc_callback(rfbi.lcdc_callback_data);
494}
495
496static void rfbi_set_bits_per_cycle(int bpc)
497{
498 u32 l;
499
500 rfbi_enable_clocks(1);
501 l = rfbi_read_reg(RFBI_CONFIG0);
502 l &= ~(0x03 << 0);
503
504 switch (bpc) {
505 case 8:
506 break;
507 case 16:
508 l |= 3;
509 break;
510 default:
511 BUG();
512 }
513 rfbi_write_reg(RFBI_CONFIG0, l);
514 rfbi.bits_per_cycle = bpc;
515 rfbi_enable_clocks(0);
516}
517
518static int rfbi_init(struct omapfb_device *fbdev)
519{
520 u32 l;
521 int r;
522
523 rfbi.fbdev = fbdev;
524 rfbi.base = ioremap(RFBI_BASE, SZ_1K);
525 if (!rfbi.base) {
526 dev_err(fbdev->dev, "can't ioremap RFBI\n");
527 return -ENOMEM;
528 }
529
530 if ((r = rfbi_get_clocks()) < 0)
531 return r;
532 rfbi_enable_clocks(1);
533
534 rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000;
535
536 /* Reset */
537 rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1);
538 while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0)));
539
540 l = rfbi_read_reg(RFBI_SYSCONFIG);
541 /* Enable autoidle and smart-idle */
542 l |= (1 << 0) | (2 << 3);
543 rfbi_write_reg(RFBI_SYSCONFIG, l);
544
545 /* 16-bit interface, ITE trigger mode, 16-bit data */
546 l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7);
547 l |= (0 << 9) | (1 << 20) | (1 << 21);
548 rfbi_write_reg(RFBI_CONFIG0, l);
549
550 rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
551
552 l = rfbi_read_reg(RFBI_CONTROL);
553 /* Select CS0, clear bypass mode */
554 l = (0x01 << 2);
555 rfbi_write_reg(RFBI_CONTROL, l);
556
557 r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback,
558 NULL);
559 if (r < 0) {
560 dev_err(fbdev->dev, "can't get DISPC irq\n");
561 rfbi_enable_clocks(0);
562 return r;
563 }
564
565 l = rfbi_read_reg(RFBI_REVISION);
566 pr_info("omapfb: RFBI version %d.%d initialized\n",
567 (l >> 4) & 0x0f, l & 0x0f);
568
569 rfbi_enable_clocks(0);
570
571 return 0;
572}
573
574static void rfbi_cleanup(void)
575{
576 omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL);
577 rfbi_put_clocks();
578 iounmap(rfbi.base);
579}
580
581const struct lcd_ctrl_extif omap2_ext_if = {
582 .init = rfbi_init,
583 .cleanup = rfbi_cleanup,
584 .get_clk_info = rfbi_get_clk_info,
585 .get_max_tx_rate = rfbi_get_max_tx_rate,
586 .set_bits_per_cycle = rfbi_set_bits_per_cycle,
587 .convert_timings = rfbi_convert_timings,
588 .set_timings = rfbi_set_timings,
589 .write_command = rfbi_write_command,
590 .read_data = rfbi_read_data,
591 .write_data = rfbi_write_data,
592 .transfer_area = rfbi_transfer_area,
593 .setup_tearsync = rfbi_setup_tearsync,
594 .enable_tearsync = rfbi_enable_tearsync,
595
596 .max_transmit_size = (u32) ~0,
597};
598