]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/omap/rfbi.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / drivers / video / omap / rfbi.c
index ebb317623b56e4f09e0328e6a5adb73a20ff8262..4f1f4be91d130ec83cf196e7ed0316e58809cd1e 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * File: drivers/video/omap/omap2/rfbi.c
- *
  * OMAP2 Remote Frame Buffer Interface support
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrj�l� <juha.yrjola@nokia.com>
  *        Imre Deak <imre.deak@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <asm/arch/omapfb.h>
 
 #include "dispc.h"
 
+/* To work around an RFBI transfer rate limitation */
+#define OMAP_RFBI_RATE_LIMIT   1
+
 #define RFBI_BASE              0x48050800
 #define RFBI_REVISION          0x0000
 #define RFBI_SYSCONFIG         0x0010
@@ -67,6 +67,8 @@ static struct {
        struct omapfb_device *fbdev;
        struct clk      *dss_ick;
        struct clk      *dss1_fck;
+       unsigned        tearsync_pin_cnt;
+       unsigned        tearsync_mode;
 } rfbi;
 
 static inline void rfbi_write_reg(int idx, u32 val)
@@ -82,12 +84,12 @@ static inline u32 rfbi_read_reg(int idx)
 static int rfbi_get_clocks(void)
 {
        if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) {
-               dev_err(rfbi.fbdev->dev, "can't get dss_ick");
+               dev_err(rfbi.fbdev->dev, "can't get dss_ick\n");
                return PTR_ERR(rfbi.dss_ick);
        }
 
        if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) {
-               dev_err(rfbi.fbdev->dev, "can't get dss1_fck");
+               dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
                clk_put(rfbi.dss_ick);
                return PTR_ERR(rfbi.dss1_fck);
        }
@@ -181,6 +183,61 @@ static int ps_to_rfbi_ticks(int time, int div)
        return ret;
 }
 
+#ifdef OMAP_RFBI_RATE_LIMIT
+static unsigned long rfbi_get_max_tx_rate(void)
+{
+       unsigned long   l4_rate, dss1_rate;
+       int             min_l4_ticks = 0;
+       int             i;
+
+       /* According to TI this can't be calculated so make the
+        * adjustments for a couple of known frequencies and warn for
+        * others.
+        */
+       static const struct {
+               unsigned long l4_clk;           /* HZ */
+               unsigned long dss1_clk;         /* HZ */
+               unsigned long min_l4_ticks;
+       } ftab[] = {
+               { 55,   132,    7, },           /* 7.86 MPix/s */
+               { 110,  110,    12, },          /* 9.16 MPix/s */
+               { 110,  132,    10, },          /* 11   Mpix/s */
+               { 120,  120,    10, },          /* 12   Mpix/s */
+               { 133,  133,    10, },          /* 13.3 Mpix/s */
+       };
+
+       l4_rate = rfbi.l4_khz / 1000;
+       dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000;
+
+       for (i = 0; i < ARRAY_SIZE(ftab); i++) {
+               /* Use a window instead of an exact match, to account
+                * for different DPLL multiplier / divider pairs.
+                */
+               if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
+                   abs(ftab[i].dss1_clk - dss1_rate) < 3) {
+                       min_l4_ticks = ftab[i].min_l4_ticks;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(ftab)) {
+               /* Can't be sure, return anyway the maximum not
+                * rate-limited. This might cause a problem only for the
+                * tearing synchronisation.
+                */
+               dev_err(rfbi.fbdev->dev,
+                       "can't determine maximum RFBI transfer rate\n");
+               return rfbi.l4_khz * 1000;
+       }
+       return rfbi.l4_khz * 1000 / min_l4_ticks;
+}
+#else
+static int rfbi_get_max_tx_rate(void)
+{
+       return rfbi.l4_khz * 1000;
+}
+#endif
+
+
 static int rfbi_convert_timings(struct extif_timings *t)
 {
        u32 l;
@@ -269,6 +326,76 @@ static int rfbi_convert_timings(struct extif_timings *t)
        return 0;
 }
 
+static int rfbi_setup_tearsync(unsigned pin_cnt,
+                              unsigned hs_pulse_time, unsigned vs_pulse_time,
+                              int hs_pol_inv, int vs_pol_inv, int extif_div)
+{
+       int hs, vs;
+       int min;
+       u32 l;
+
+       if (pin_cnt != 1 && pin_cnt != 2)
+               return -EINVAL;
+
+       hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
+       vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
+       if (hs < 2)
+               return -EDOM;
+       if (pin_cnt == 2)
+               min = 2;
+       else
+               min = 4;
+       if (vs < min)
+               return -EDOM;
+       if (vs == hs)
+               return -EINVAL;
+       rfbi.tearsync_pin_cnt = pin_cnt;
+       dev_dbg(rfbi.fbdev->dev,
+               "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n",
+               pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv);
+
+       rfbi_enable_clocks(1);
+       rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
+       rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
+
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       if (hs_pol_inv)
+               l &= ~(1 << 21);
+       else
+               l |= 1 << 21;
+       if (vs_pol_inv)
+               l &= ~(1 << 20);
+       else
+               l |= 1 << 20;
+       rfbi_enable_clocks(0);
+
+       return 0;
+}
+
+static int rfbi_enable_tearsync(int enable, unsigned line)
+{
+       u32 l;
+
+       dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n",
+               enable, line, rfbi.tearsync_mode);
+       if (line > (1 << 11) - 1)
+               return -EINVAL;
+
+       rfbi_enable_clocks(1);
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       l &= ~(0x3 << 2);
+       if (enable) {
+               rfbi.tearsync_mode = rfbi.tearsync_pin_cnt;
+               l |= rfbi.tearsync_mode << 2;
+       } else
+               rfbi.tearsync_mode = 0;
+       rfbi_write_reg(RFBI_CONFIG0, l);
+       rfbi_write_reg(RFBI_LINE_NUMBER, line);
+       rfbi_enable_clocks(0);
+
+       return 0;
+}
+
 static void rfbi_write_command(const void *buf, unsigned int len)
 {
        rfbi_enable_clocks(1);
@@ -340,8 +467,10 @@ static void rfbi_transfer_area(int width, int height,
        rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
 
        w = rfbi_read_reg(RFBI_CONTROL);
-       /* Enable, Internal trigger */
-       rfbi_write_reg(RFBI_CONTROL, w | (1 << 0) | (1 << 4));
+       w |= 1;                         /* enable */
+       if (!rfbi.tearsync_mode)
+               w |= 1 << 4;            /* internal trigger, reset by HW */
+       rfbi_write_reg(RFBI_CONTROL, w);
 
        omap_dispc_enable_lcd_out(1);
 }
@@ -368,8 +497,8 @@ static void rfbi_set_bits_per_cycle(int bpc)
        rfbi_enable_clocks(1);
        l = rfbi_read_reg(RFBI_CONFIG0);
        l &= ~(0x03 << 0);
-       switch (bpc)
-       {
+
+       switch (bpc) {
        case 8:
                break;
        case 16:
@@ -443,6 +572,7 @@ const struct lcd_ctrl_extif omap2_ext_if = {
        .init                   = rfbi_init,
        .cleanup                = rfbi_cleanup,
        .get_clk_info           = rfbi_get_clk_info,
+       .get_max_tx_rate        = rfbi_get_max_tx_rate,
        .set_bits_per_cycle     = rfbi_set_bits_per_cycle,
        .convert_timings        = rfbi_convert_timings,
        .set_timings            = rfbi_set_timings,
@@ -450,7 +580,9 @@ const struct lcd_ctrl_extif omap2_ext_if = {
        .read_data              = rfbi_read_data,
        .write_data             = rfbi_write_data,
        .transfer_area          = rfbi_transfer_area,
+       .setup_tearsync         = rfbi_setup_tearsync,
+       .enable_tearsync        = rfbi_enable_tearsync,
 
-       .max_transmit_size      = (u32)~0,
+       .max_transmit_size      = (u32) ~0,
 };