2 * File: drivers/video/omap/omap2/dispc.c
4 * OMAP2 display controller support
6 * Copyright (C) 2005 Nokia Corporation
7 * Author: Imre Deak <imre.deak@nokia.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <linux/kernel.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/vmalloc.h>
27 #include <linux/clk.h>
31 #include <asm/arch/sram.h>
32 #include <asm/arch/omapfb.h>
33 #include <asm/arch/board.h>
37 /* #define OMAPFB_DBG 1 */
41 #define MODULE_NAME "omapfb-dispc"
43 #define DISPC_BASE 0x48050400
46 #define DISPC_REVISION 0x0000
47 #define DISPC_SYSCONFIG 0x0010
48 #define DISPC_SYSSTATUS 0x0014
49 #define DISPC_IRQSTATUS 0x0018
50 #define DISPC_IRQENABLE 0x001C
51 #define DISPC_CONTROL 0x0040
52 #define DISPC_CONFIG 0x0044
53 #define DISPC_CAPABLE 0x0048
54 #define DISPC_DEFAULT_COLOR0 0x004C
55 #define DISPC_DEFAULT_COLOR1 0x0050
56 #define DISPC_TRANS_COLOR0 0x0054
57 #define DISPC_TRANS_COLOR1 0x0058
58 #define DISPC_LINE_STATUS 0x005C
59 #define DISPC_LINE_NUMBER 0x0060
60 #define DISPC_TIMING_H 0x0064
61 #define DISPC_TIMING_V 0x0068
62 #define DISPC_POL_FREQ 0x006C
63 #define DISPC_DIVISOR 0x0070
64 #define DISPC_SIZE_DIG 0x0078
65 #define DISPC_SIZE_LCD 0x007C
67 #define DISPC_DATA_CYCLE1 0x01D4
68 #define DISPC_DATA_CYCLE2 0x01D8
69 #define DISPC_DATA_CYCLE3 0x01DC
72 #define DISPC_GFX_BA0 0x0080
73 #define DISPC_GFX_BA1 0x0084
74 #define DISPC_GFX_POSITION 0x0088
75 #define DISPC_GFX_SIZE 0x008C
76 #define DISPC_GFX_ATTRIBUTES 0x00A0
77 #define DISPC_GFX_FIFO_THRESHOLD 0x00A4
78 #define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8
79 #define DISPC_GFX_ROW_INC 0x00AC
80 #define DISPC_GFX_PIXEL_INC 0x00B0
81 #define DISPC_GFX_WINDOW_SKIP 0x00B4
82 #define DISPC_GFX_TABLE_BA 0x00B8
84 /* DISPC Video plane 1/2 */
85 #define DISPC_VID1_BASE 0x00BC
86 #define DISPC_VID2_BASE 0x014C
88 /* Offsets into DISPC_VID1/2_BASE */
89 #define DISPC_VID_BA0 0x0000
90 #define DISPC_VID_BA1 0x0004
91 #define DISPC_VID_POSITION 0x0008
92 #define DISPC_VID_SIZE 0x000C
93 #define DISPC_VID_ATTRIBUTES 0x0010
94 #define DISPC_VID_FIFO_THRESHOLD 0x0014
95 #define DISPC_VID_FIFO_SIZE_STATUS 0x0018
96 #define DISPC_VID_ROW_INC 0x001C
97 #define DISPC_VID_PIXEL_INC 0x0020
98 #define DISPC_VID_FIR 0x0024
99 #define DISPC_VID_PICTURE_SIZE 0x0028
100 #define DISPC_VID_ACCU0 0x002C
101 #define DISPC_VID_ACCU1 0x0030
103 /* 8 elements in 8 byte increments */
104 #define DISPC_VID_FIR_COEF_H0 0x0034
105 /* 8 elements in 8 byte increments */
106 #define DISPC_VID_FIR_COEF_HV0 0x0038
107 /* 5 elements in 4 byte increments */
108 #define DISPC_VID_CONV_COEF0 0x0074
110 #define DISPC_IRQ_FRAMEMASK 0x0001
111 #define DISPC_IRQ_VSYNC 0x0002
112 #define DISPC_IRQ_EVSYNC_EVEN 0x0004
113 #define DISPC_IRQ_EVSYNC_ODD 0x0008
114 #define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010
115 #define DISPC_IRQ_PROG_LINE_NUM 0x0020
116 #define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040
117 #define DISPC_IRQ_GFX_END_WIN 0x0080
118 #define DISPC_IRQ_PAL_GAMMA_MASK 0x0100
119 #define DISPC_IRQ_OCP_ERR 0x0200
120 #define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400
121 #define DISPC_IRQ_VID1_END_WIN 0x0800
122 #define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000
123 #define DISPC_IRQ_VID2_END_WIN 0x2000
124 #define DISPC_IRQ_SYNC_LOST 0x4000
126 #define DISPC_IRQ_MASK_ALL 0x7fff
128 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
129 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
130 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
133 #define RFBI_CONTROL 0x48050040
135 #define MAX_PALETTE_SIZE (256 * 16)
137 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
139 #define FLD_MASK(pos, len) (((1 << len) - 1) << pos)
141 #define MOD_REG_FLD(reg, mask, val) \
142 dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
147 dma_addr_t fb_sram_paddr;
151 dma_addr_t fb_sdram_paddr;
152 void *fb_sdram_vaddr;
156 dma_addr_t palette_paddr;
166 unsigned long enabled_irqs;
167 void (*irq_callback)(void *);
168 void *irq_callback_data;
169 struct completion frame_done;
171 struct clk *dss_ick, *dss1_fck;
172 struct clk *dss_54m_fck;
174 enum omapfb_update_mode update_mode;
175 struct omapfb_device *fbdev;
178 static void inline dispc_write_reg(int idx, u32 val)
180 __raw_writel(val, dispc.base + idx);
183 static u32 inline dispc_read_reg(int idx)
185 u32 l = __raw_readl(dispc.base + idx);
189 /* Select RFBI or bypass mode */
190 static void enable_rfbi_mode(int enable)
194 l = dispc_read_reg(DISPC_CONTROL);
195 /* Enable RFBI, GPIO0/1 */
196 l &= ~((1 << 11) | (1 << 15) | (1 << 16));
197 l |= enable ? (1 << 11) : 0;
198 /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */
200 l |= enable ? 0 : (1 << 16);
201 dispc_write_reg(DISPC_CONTROL, l);
203 /* Set bypass mode in RFBI module */
204 l = __raw_readl(io_p2v(RFBI_CONTROL));
205 l |= enable ? 0 : (1 << 1);
206 __raw_writel(l, io_p2v(RFBI_CONTROL));
209 static void set_lcd_data_lines(int data_lines)
214 switch (data_lines) {
231 l = dispc_read_reg(DISPC_CONTROL);
234 dispc_write_reg(DISPC_CONTROL, l);
237 static void set_load_mode(int mode)
239 BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
240 DISPC_LOAD_CLUT_ONCE_FRAME));
241 MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
244 void omap_dispc_set_lcd_size(int x, int y)
246 BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
247 MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
248 ((y - 1) << 16) | (x - 1));
250 EXPORT_SYMBOL(omap_dispc_set_lcd_size);
252 void omap_dispc_set_digit_size(int x, int y)
254 BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
255 MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
256 ((y - 1) << 16) | (x - 1));
258 EXPORT_SYMBOL(omap_dispc_set_digit_size);
260 static void setup_plane_fifo(int plane)
262 const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
263 DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
264 DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
265 const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
266 DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
267 DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
273 l = dispc_read_reg(fsz_reg[plane]);
275 /* HIGH=3/4 LOW=1/4 */
276 MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
277 ((l * 3 / 4) << 16) | (l / 4));
280 void omap_dispc_enable_lcd_out(int enable)
282 MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
284 EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
286 void omap_dispc_enable_digit_out(int enable)
288 MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
290 EXPORT_SYMBOL(omap_dispc_enable_digit_out);
292 static inline int _setup_plane(int plane, int channel_out,
293 u32 paddr, int screen_width,
294 int pos_x, int pos_y, int width, int height,
297 const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
298 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
299 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
300 const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
301 DISPC_VID2_BASE + DISPC_VID_BA0 };
302 const u32 ps_reg[] = { DISPC_GFX_POSITION,
303 DISPC_VID1_BASE + DISPC_VID_POSITION,
304 DISPC_VID2_BASE + DISPC_VID_POSITION };
305 const u32 sz_reg[] = { DISPC_GFX_SIZE, DISPC_VID1_BASE + DISPC_VID_SIZE,
306 DISPC_VID2_BASE + DISPC_VID_SIZE };
307 const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
308 DISPC_VID1_BASE + DISPC_VID_ROW_INC,
309 DISPC_VID2_BASE + DISPC_VID_ROW_INC };
310 int chout_shift, burst_shift;
316 DBGPRINT(2, "plane %d channel %d paddr %u scr_width %d pos_x %d pos_y %d "
317 "width %d height %d color_mode %d\n",
318 plane, channel_out, paddr, screen_width, pos_x, pos_y,
319 width, height, color_mode);
322 case OMAPFB_PLANE_GFX:
326 case OMAPFB_PLANE_VID1:
327 case OMAPFB_PLANE_VID2:
335 switch (channel_out) {
336 case OMAPFB_CHANNEL_OUT_LCD:
339 case OMAPFB_CHANNEL_OUT_DIGIT:
346 switch (color_mode) {
347 case OMAPFB_COLOR_RGB565:
348 color_code = DISPC_RGB_16_BPP;
351 case OMAPFB_COLOR_YUV422:
354 color_code = DISPC_UYVY_422;
357 case OMAPFB_COLOR_YUV420:
360 color_code = DISPC_YUV2_422;
367 l = dispc_read_reg(at_reg[plane]);
370 l |= color_code << 1;
372 l &= ~(0x03 << burst_shift);
373 l |= DISPC_BURST_8x32 << burst_shift;
375 l &= ~(1 << chout_shift);
376 l |= chout_val << chout_shift;
378 dispc_write_reg(at_reg[plane], l);
380 dispc_write_reg(ba_reg[plane], paddr);
381 MOD_REG_FLD(ps_reg[plane],
382 FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
384 MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
385 ((height - 1) << 16) | (width - 1));
387 dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
389 return height * screen_width * bpp / 8;
392 static int omap_dispc_setup_plane(int plane, int channel_out,
393 unsigned long offset, int screen_width,
394 int pos_x, int pos_y, int width, int height,
402 if (offset > dispc.fb_sram_size + dispc.fb_sdram_size)
405 if (offset < dispc.fb_sram_size) {
406 paddr = dispc.fb_sram_paddr + offset;
407 yspan = min_t(int, height, dispc.fb_sram_lines);
409 if ((r = _setup_plane(plane, channel_out, paddr,
410 screen_width, pos_x, pos_y,
411 width, height, color_mode)) < 0)
418 plane = OMAPFB_PLANE_GFX;
422 offset -= dispc.fb_sram_size;
423 paddr = dispc.fb_sdram_paddr + offset;
424 yspan = min_t(int, height, dispc.fb_sdram_lines);
426 if ((r = _setup_plane(plane, channel_out, paddr,
427 screen_width, pos_x, pos_y,
428 width, height, color_mode)) < 0)
431 dispc.multiplane_head = mp_head;
438 static int omap_dispc_enable_plane(int plane, int enable)
440 const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
441 DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
442 DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
445 if ((unsigned int)plane > 2)
447 MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
448 if (plane == dispc.multiplane_head) {
450 plane = OMAPFB_PLANE_GFX;
451 MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
457 static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
462 switch (ck->channel_out) {
463 case OMAPFB_CHANNEL_OUT_LCD:
464 df_reg = DISPC_DEFAULT_COLOR0;
465 tr_reg = DISPC_TRANS_COLOR0;
468 case OMAPFB_CHANNEL_OUT_DIGIT:
469 df_reg = DISPC_DEFAULT_COLOR1;
470 tr_reg = DISPC_TRANS_COLOR1;
476 switch (ck->key_type) {
477 case OMAPFB_COLOR_KEY_DISABLED:
480 case OMAPFB_COLOR_KEY_GFX_DST:
483 case OMAPFB_COLOR_KEY_VID_SRC:
489 MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
492 dispc_write_reg(tr_reg, ck->trans_key);
493 dispc_write_reg(df_reg, ck->background);
498 static void load_palette(void)
502 static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
508 if (mode != dispc.update_mode) {
510 case OMAPFB_AUTO_UPDATE:
511 case OMAPFB_MANUAL_UPDATE:
512 omap_dispc_enable_lcd_out(1);
513 dispc.update_mode = mode;
515 case OMAPFB_UPDATE_DISABLED:
516 init_completion(&dispc.frame_done);
517 omap_dispc_enable_lcd_out(0);
518 if (!wait_for_completion_timeout(&dispc.frame_done,
519 msecs_to_jiffies(500))) {
520 pr_err("timeout waiting for FRAME DONE\n");
522 dispc.update_mode = mode;
534 static enum omapfb_update_mode omap_dispc_get_update_mode(void)
536 return dispc.update_mode;
539 static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
541 unsigned long fck, lck;
545 fck = clk_get_rate(dispc.dss1_fck);
547 *pck_div = (lck + pck - 1) / pck;
549 *pck_div = max(2, *pck_div);
551 *pck_div = max(3, *pck_div);
552 if (*pck_div > 255) {
554 lck = pck * *pck_div;
555 *lck_div = fck / lck;
556 BUG_ON(*lck_div < 1);
557 if (*lck_div > 255) {
560 MODULE_NAME ": pixclock %d kHz too low.\n",
566 static void set_lcd_tft_mode(int enable)
571 MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
574 static void set_lcd_timings(void)
577 int lck_div, pck_div;
578 struct lcd_panel *panel = dispc.fbdev->panel;
579 int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
584 l = dispc_read_reg(DISPC_TIMING_H);
585 l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
586 l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0;
587 l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
588 l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
589 dispc_write_reg(DISPC_TIMING_H, l);
591 l = dispc_read_reg(DISPC_TIMING_V);
592 l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
593 l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0;
594 l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
595 l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
596 dispc_write_reg(DISPC_TIMING_V, l);
598 l = dispc_read_reg(DISPC_POL_FREQ);
599 l &= ~FLD_MASK(12, 6);
600 l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
601 l |= panel->acb & 0xff;
602 dispc_write_reg(DISPC_POL_FREQ, l);
604 calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
606 l = dispc_read_reg(DISPC_DIVISOR);
607 l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
608 l |= (lck_div << 16) | (pck_div << 0);
609 dispc_write_reg(DISPC_DIVISOR, l);
611 /* update panel info with the exact clock */
612 fck = clk_get_rate(dispc.dss1_fck);
613 panel->pixel_clock = fck / lck_div / pck_div / 1000;
616 int omap_dispc_request_irq(void (*callback)(void *data), void *data)
620 BUG_ON(callback == NULL);
622 if (dispc.irq_callback)
625 dispc.irq_callback = callback;
626 dispc.irq_callback_data = data;
631 EXPORT_SYMBOL(omap_dispc_request_irq);
633 void omap_dispc_enable_irqs(int irq_mask)
635 dispc.enabled_irqs = irq_mask;
636 irq_mask |= DISPC_IRQ_MASK_ERROR;
637 MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
639 EXPORT_SYMBOL(omap_dispc_enable_irqs);
641 void omap_dispc_disable_irqs(int irq_mask)
643 dispc.enabled_irqs &= ~irq_mask;
644 irq_mask &= ~DISPC_IRQ_MASK_ERROR;
645 MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
647 EXPORT_SYMBOL(omap_dispc_disable_irqs);
649 void omap_dispc_free_irq(void)
651 omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
652 dispc.irq_callback = NULL;
653 dispc.irq_callback_data = NULL;
655 EXPORT_SYMBOL(omap_dispc_free_irq);
657 static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *regs)
659 u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
664 if (stat & DISPC_IRQ_FRAMEMASK)
665 complete(&dispc.frame_done);
667 if (stat & DISPC_IRQ_MASK_ERROR) {
669 pr_err("irq error status %04x\n", stat & 0x7fff);
671 pr_err("disable irq\n");
672 dispc_write_reg(DISPC_IRQENABLE, 0);
676 if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
677 dispc.irq_callback(dispc.irq_callback_data);
679 dispc_write_reg(DISPC_IRQSTATUS, stat);
684 static int get_dss_clocks(void)
686 if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
687 pr_err("can't get dss_ick");
688 return PTR_ERR(dispc.dss_ick);
691 if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
692 pr_err("can't get dss1_fck");
693 clk_put(dispc.dss_ick);
694 return PTR_ERR(dispc.dss1_fck);
697 if (IS_ERR((dispc.dss_54m_fck =
698 clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
699 pr_err("can't get dss_54m_fck");
700 clk_put(dispc.dss_ick);
701 clk_put(dispc.dss1_fck);
702 return PTR_ERR(dispc.dss_54m_fck);
708 static void put_dss_clocks(void)
710 clk_put(dispc.dss_54m_fck);
711 clk_put(dispc.dss1_fck);
712 clk_put(dispc.dss_ick);
715 static void enable_lcd_clocks(int enable)
718 clk_enable(dispc.dss_ick);
719 clk_enable(dispc.dss1_fck);
721 clk_disable(dispc.dss1_fck);
722 clk_disable(dispc.dss_ick);
726 static void enable_digit_clocks(int enable)
729 clk_enable(dispc.dss_54m_fck);
731 clk_disable(dispc.dss_54m_fck);
734 static void omap_dispc_suspend(void)
738 if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
739 init_completion(&dispc.frame_done);
740 omap_dispc_enable_lcd_out(0);
741 if (!wait_for_completion_timeout(&dispc.frame_done,
742 msecs_to_jiffies(500))) {
743 pr_err("timeout waiting for FRAME DONE\n");
745 enable_lcd_clocks(0);
751 static void omap_dispc_resume(void)
755 if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
756 enable_lcd_clocks(1);
759 omap_dispc_enable_lcd_out(1);
766 static int omap_dispc_update_window(struct omapfb_update_window *win,
767 void (*complete_callback)(void *arg),
768 void *complete_callback_data)
770 return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
773 /* Greatest common divisor */
774 static int calc_gcd(int a, int b)
795 /* Least common multiple */
796 static int calc_lcm(int a, int b)
798 return a * b / calc_gcd(a, b);
801 static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
804 *size = dispc.fb_sram_size + dispc.fb_sdram_size;
805 *virt = dispc.fb_kern_vaddr;
806 /* Physical vram might not be contiguous. No one except own mmap
807 * should use this addr.
812 static int omap_dispc_mmap_user(struct vm_area_struct *vma)
815 unsigned long offset;
819 DBGPRINT(1, "vm_pgoff 0x%08lx vm_start 0x%08lx vm_end 0x%08lx\n",
820 vma->vm_pgoff, vma->vm_start, vma->vm_end);
822 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
824 offset = vma->vm_pgoff << PAGE_SHIFT;
826 if (offset >= dispc.fb_sram_size + dispc.fb_sdram_size)
829 len = vma->vm_end - vma->vm_start;
830 if (offset + len > dispc.fb_sram_size + dispc.fb_sdram_size)
833 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
834 vma->vm_flags |= VM_PFNMAP;
836 vaddr = vma->vm_start;
838 if (dispc.fb_sram_size) {
839 if (offset < dispc.fb_sram_size) {
840 int chunk = min_t(int, dispc.fb_sram_size - offset, len);
841 DBGPRINT(1, "map sram va %08lx pa %08lx size %d\n",
842 vaddr, dispc.fb_sram_paddr + offset, chunk);
843 r = io_remap_pfn_range(vma, vaddr,
844 (dispc.fb_sram_paddr +
845 offset) >> PAGE_SHIFT, chunk,
856 offset -= dispc.fb_sram_size;
860 DBGPRINT(1, "map sdram va %08lx pa %08lx size %ld\n",
861 vaddr, dispc.fb_sdram_paddr + offset, len);
862 BUG_ON(offset > dispc.fb_sdram_size ||
863 offset + len > dispc.fb_sdram_size ||
864 vma->vm_end - vaddr != len);
865 r = io_remap_pfn_range(vma, vaddr, (dispc.fb_sdram_paddr +
866 offset) >> PAGE_SHIFT, len,
868 /* no teardown of the previous mapping here.
869 * do_mmap_pgoff will take core of that. */
879 static int mmap_kern(void)
881 struct vm_struct *kvma;
882 struct vm_area_struct vma;
888 kvma = get_vm_area(dispc.fb_sram_size + dispc.fb_sdram_size, VM_IOREMAP);
890 pr_err("can't get kernel vm area\n");
893 vma.vm_mm = &init_mm;
895 dispc.fb_kern_vaddr = kvma->addr;
896 vaddr = (unsigned long)kvma->addr;
898 pgprot = pgprot_writecombine(pgprot_kernel);
899 if (dispc.fb_sram_size) {
900 vma.vm_start = vaddr;
901 vma.vm_end = vaddr + dispc.fb_sram_size;
902 if (io_remap_pfn_range(&vma, vaddr,
903 dispc.fb_sram_paddr >> PAGE_SHIFT,
904 dispc.fb_sram_size, pgprot) < 0) {
905 pr_err("kernel mmap for FBMEM failed\n");
908 vaddr += dispc.fb_sram_size;
910 if (dispc.fb_sdram_size) {
911 vma.vm_start = vaddr;
912 vma.vm_end = vaddr + dispc.fb_sdram_size;
913 if (io_remap_pfn_range(&vma, vaddr,
914 dispc.fb_sdram_paddr >> PAGE_SHIFT,
915 dispc.fb_sdram_size, pgprot) < 0) {
916 pr_err("kernel mmap for FBMEM failed\n");
926 static void unmap_kern(void)
928 vunmap(dispc.fb_kern_vaddr);
931 static int alloc_palette_ram(void)
933 dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
934 MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
935 if (dispc.palette_vaddr == NULL) {
936 pr_err("failed to alloc palette memory\n");
943 static void free_palette_ram(void)
945 dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
946 dispc.palette_vaddr, dispc.palette_paddr);
949 static int alloc_fbmem(int req_size)
952 struct lcd_panel *panel = dispc.fbdev->panel;
954 frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
955 if (req_size > frame_size)
956 frame_size = req_size;
957 dispc.fb_sdram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
958 dispc.fb_kern_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
959 dispc.fb_sdram_size, &dispc.fb_sdram_paddr, GFP_KERNEL);
961 if (dispc.fb_kern_vaddr == 0) {
962 pr_err("unable to allocate fb DMA memory\n");
969 static void free_fbmem(void)
971 dma_free_writecombine(dispc.fbdev->dev, dispc.fb_sdram_size,
972 dispc.fb_kern_vaddr, dispc.fb_sdram_paddr);
975 static int setup_fbmem(int req_size)
977 struct lcd_panel *panel = dispc.fbdev->panel;
978 struct omapfb_platform_data *conf;
979 unsigned long size_align;
985 conf = dispc.fbdev->dev->platform_data;
987 if (conf->fbmem.fb_sram_size + conf->fbmem.fb_sdram_size == 0) {
988 if ((r = alloc_fbmem(req_size)) < 0)
990 dispc.fbmem_allocated = 1;
991 dispc.fb_sdram_lines = panel->y_res;
995 dispc.fb_sram_paddr = conf->fbmem.fb_sram_start;
996 dispc.fb_sram_size = conf->fbmem.fb_sram_size;
997 dispc.fb_sdram_paddr = conf->fbmem.fb_sdram_start;
998 dispc.fb_sdram_size = conf->fbmem.fb_sdram_size;
1000 line_size = panel->x_res * panel->bpp / 8;
1001 frame_size = PAGE_ALIGN(line_size * panel->y_res);
1003 size_align = calc_lcm(line_size, PAGE_SIZE);
1005 if (dispc.fb_sram_size + dispc.fb_sdram_size < frame_size ||
1006 (dispc.fb_sdram_size && (dispc.fb_sram_size % size_align))) {
1007 pr_err("Invalid FB memory configuration\n");
1011 if (dispc.fb_sram_size + dispc.fb_sdram_size < req_size) {
1012 pr_err("%d vram was requested, but only %u is available\n",
1013 req_size, dispc.fb_sram_size + dispc.fb_sdram_size);
1016 lines = dispc.fb_sram_size / line_size;
1017 lines = min_t(int, panel->y_res, lines);
1018 dispc.fb_sram_lines = lines;
1019 lines = panel->y_res - lines;
1020 dispc.fb_sdram_lines = lines;
1022 if ((r = mmap_kern()) < 0)
1025 DBGPRINT(1, "fb_sram %08x size %08x fb_sdram %08x size %08x\n",
1026 dispc.fb_sram_paddr, dispc.fb_sram_size,
1027 dispc.fb_sdram_paddr, dispc.fb_sdram_size);
1032 static void cleanup_fbmem(void)
1034 if (dispc.fbmem_allocated)
1040 static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1045 struct lcd_panel *panel = fbdev->panel;
1051 memset(&dispc, 0, sizeof(dispc));
1053 dispc.base = io_p2v(DISPC_BASE);
1054 dispc.fbdev = fbdev;
1055 dispc.ext_mode = ext_mode;
1057 dispc.multiplane_head = -1;
1059 if (fbdev->dev->platform_data == NULL) {
1060 pr_err("missing FB configuration\n");
1064 init_completion(&dispc.frame_done);
1066 if ((r = get_dss_clocks()) < 0)
1069 enable_lcd_clocks(1);
1071 l = dispc_read_reg(DISPC_REVISION);
1072 pr_info(MODULE_NAME ": version %d.%d\n", l >> 4 & 0x0f, l & 0x0f);
1074 #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
1075 l = dispc_read_reg(DISPC_CONTROL);
1078 pr_info(MODULE_NAME ": skipping hardware initialization\n");
1084 /* Reset monitoring works only w/ the 54M clk */
1085 enable_digit_clocks(1);
1088 MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
1090 while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
1092 pr_err("soft reset failed\n");
1094 enable_digit_clocks(0);
1099 enable_digit_clocks(0);
1102 l = dispc_read_reg(DISPC_IRQSTATUS);
1103 dispc_write_reg(l, DISPC_IRQSTATUS);
1105 /* Enable those that we handle always */
1106 omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
1108 if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
1109 0, MODULE_NAME, NULL)) < 0) {
1110 pr_err("can't get DSS IRQ\n");
1114 /* L3 firewall setting: enable access to OCM RAM */
1115 __raw_writel(0x402000b0, io_p2v(0x680050a0));
1117 if ((r = alloc_palette_ram()) < 0)
1120 if ((r = setup_fbmem(req_vram_size)) < 0)
1124 memset(dispc.fb_kern_vaddr, 0,
1125 dispc.fb_sram_size + dispc.fb_sdram_size);
1127 /* Set logic clock to fck, pixel clock to fck/2 for now */
1128 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
1129 MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
1131 setup_plane_fifo(0);
1132 setup_plane_fifo(1);
1133 setup_plane_fifo(2);
1135 set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
1136 set_lcd_data_lines(panel->data_lines);
1137 set_load_mode(DISPC_LOAD_FRAME_ONLY);
1140 omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
1143 enable_rfbi_mode(ext_mode);
1150 free_irq(INT_24XX_DSS_IRQ, NULL);
1152 enable_lcd_clocks(0);
1158 static void omap_dispc_cleanup(void)
1162 free_irq(INT_24XX_DSS_IRQ, NULL);
1163 enable_lcd_clocks(0);
1167 static unsigned long omap_dispc_get_caps(void)
1172 struct lcd_ctrl omap2_int_ctrl = {
1174 .init = omap_dispc_init,
1175 .cleanup = omap_dispc_cleanup,
1176 .get_vram_layout = omap_dispc_get_vram_layout,
1177 .mmap = omap_dispc_mmap_user,
1178 .get_caps = omap_dispc_get_caps,
1179 .set_update_mode = omap_dispc_set_update_mode,
1180 .get_update_mode = omap_dispc_get_update_mode,
1181 .update_window = omap_dispc_update_window,
1182 .suspend = omap_dispc_suspend,
1183 .resume = omap_dispc_resume,
1184 .setup_plane = omap_dispc_setup_plane,
1185 .enable_plane = omap_dispc_enable_plane,
1186 .set_color_key = omap_dispc_set_color_key,
1189 MODULE_DESCRIPTION("TI OMAP LCDC controller");
1190 MODULE_LICENSE("GPL");