OMAP: DSS2: DSI: Print an error message if DSI clock calc fails
[pandora-kernel.git] / drivers / video / omap2 / dss / dsi.c
index 3af207b..04d84d1 100644 (file)
@@ -238,6 +238,8 @@ static struct
 
        bool te_enabled;
 
+       struct workqueue_struct *workqueue;
+
        struct work_struct framedone_work;
        void (*framedone_callback)(int, void *);
        void *framedone_data;
@@ -1098,6 +1100,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
        if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
                DSSERR("PLL not coming out of reset.\n");
                r = -ENODEV;
+               dispc_pck_free_enable(0);
                goto err1;
        }
 
@@ -1854,19 +1857,19 @@ static u16 dsi_vc_flush_receive_data(int channel)
                u32 val;
                u8 dt;
                val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
-               DSSDBG("\trawval %#08x\n", val);
+               DSSERR("\trawval %#08x\n", val);
                dt = FLD_GET(val, 5, 0);
                if (dt == DSI_DT_RX_ACK_WITH_ERR) {
                        u16 err = FLD_GET(val, 23, 8);
                        dsi_show_rx_ack_with_err(err);
                } else if (dt == DSI_DT_RX_SHORT_READ_1) {
-                       DSSDBG("\tDCS short response, 1 byte: %#x\n",
+                       DSSERR("\tDCS short response, 1 byte: %#x\n",
                                        FLD_GET(val, 23, 8));
                } else if (dt == DSI_DT_RX_SHORT_READ_2) {
-                       DSSDBG("\tDCS short response, 2 byte: %#x\n",
+                       DSSERR("\tDCS short response, 2 byte: %#x\n",
                                        FLD_GET(val, 23, 8));
                } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
-                       DSSDBG("\tDCS long response, len %d\n",
+                       DSSERR("\tDCS long response, len %d\n",
                                        FLD_GET(val, 23, 8));
                        dsi_vc_flush_long_data(channel);
                } else {
@@ -2087,6 +2090,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len)
        if (r)
                goto err;
 
+       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {    /* RX_FIFO_NOT_EMPTY */
+               DSSERR("rx fifo not empty after write, dumping data:\n");
+               dsi_vc_flush_receive_data(channel);
+               r = -EIO;
+               goto err;
+       }
+
        return 0;
 err:
        DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
@@ -2233,11 +2243,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_1);
 
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
+int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
 {
+       u8 buf[2];
        int r;
 
-       r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
+       r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2);
 
        if (r < 0)
                return r;
@@ -2245,6 +2256,9 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
        if (r != 2)
                return -EIO;
 
+       *data1 = buf[0];
+       *data2 = buf[1];
+
        return 0;
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_2);
@@ -2264,212 +2278,108 @@ int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
 }
 EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
 
-static void dsi_set_lp_rx_timeout(unsigned long ns)
+static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
 {
-       u32 r;
-       unsigned x4, x16;
        unsigned long fck;
-       unsigned long ticks;
+       unsigned long total_ticks;
+       u32 r;
 
-       /* ticks in DSI_FCK */
+       BUG_ON(ticks > 0x1fff);
 
+       /* ticks in DSI_FCK */
        fck = dsi_fclk_rate();
-       ticks = (fck / 1000 / 1000) * ns / 1000;
-       x4 = 0;
-       x16 = 0;
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
-               x4 = 1;
-               x16 = 0;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
-               x4 = 0;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
-               x4 = 1;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               DSSWARN("LP_TX_TO over limit, setting it to max\n");
-               ticks = 0x1fff;
-               x4 = 1;
-               x16 = 1;
-       }
 
        r = dsi_read_reg(DSI_TIMING2);
        r = FLD_MOD(r, 1, 15, 15);      /* LP_RX_TO */
-       r = FLD_MOD(r, x16, 14, 14);    /* LP_RX_TO_X16 */
-       r = FLD_MOD(r, x4, 13, 13);     /* LP_RX_TO_X4 */
+       r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* LP_RX_TO_X16 */
+       r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* LP_RX_TO_X4 */
        r = FLD_MOD(r, ticks, 12, 0);   /* LP_RX_COUNTER */
        dsi_write_reg(DSI_TIMING2, r);
 
-       DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
-                       (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
-                       (fck / 1000 / 1000),
-                       ticks, x4 ? " x4" : "", x16 ? " x16" : "");
+       total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+       DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
+                       total_ticks,
+                       ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+                       (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_ta_timeout(unsigned long ns)
+static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
 {
-       u32 r;
-       unsigned x8, x16;
        unsigned long fck;
-       unsigned long ticks;
+       unsigned long total_ticks;
+       u32 r;
+
+       BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
        fck = dsi_fclk_rate();
-       ticks = (fck / 1000 / 1000) * ns / 1000;
-       x8 = 0;
-       x16 = 0;
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 8;
-               x8 = 1;
-               x16 = 0;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
-               x8 = 0;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16);
-               x8 = 1;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               DSSWARN("TA_TO over limit, setting it to max\n");
-               ticks = 0x1fff;
-               x8 = 1;
-               x16 = 1;
-       }
 
        r = dsi_read_reg(DSI_TIMING1);
        r = FLD_MOD(r, 1, 31, 31);      /* TA_TO */
-       r = FLD_MOD(r, x16, 30, 30);    /* TA_TO_X16 */
-       r = FLD_MOD(r, x8, 29, 29);     /* TA_TO_X8 */
+       r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* TA_TO_X16 */
+       r = FLD_MOD(r, x8 ? 1 : 0, 29, 29);     /* TA_TO_X8 */
        r = FLD_MOD(r, ticks, 28, 16);  /* TA_TO_COUNTER */
        dsi_write_reg(DSI_TIMING1, r);
 
-       DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
-                       (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
-                       (fck / 1000 / 1000),
-                       ticks, x8 ? " x8" : "", x16 ? " x16" : "");
+       total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
+
+       DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
+                       total_ticks,
+                       ticks, x8 ? " x8" : "", x16 ? " x16" : "",
+                       (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_stop_state_counter(unsigned long ns)
+static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
 {
-       u32 r;
-       unsigned x4, x16;
        unsigned long fck;
-       unsigned long ticks;
+       unsigned long total_ticks;
+       u32 r;
 
-       /* ticks in DSI_FCK */
+       BUG_ON(ticks > 0x1fff);
 
+       /* ticks in DSI_FCK */
        fck = dsi_fclk_rate();
-       ticks = (fck / 1000 / 1000) * ns / 1000;
-       x4 = 0;
-       x16 = 0;
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
-               x4 = 1;
-               x16 = 0;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
-               x4 = 0;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
-               x4 = 1;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               DSSWARN("STOP_STATE_COUNTER_IO over limit, "
-                               "setting it to max\n");
-               ticks = 0x1fff;
-               x4 = 1;
-               x16 = 1;
-       }
 
        r = dsi_read_reg(DSI_TIMING1);
        r = FLD_MOD(r, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
-       r = FLD_MOD(r, x16, 14, 14);    /* STOP_STATE_X16_IO */
-       r = FLD_MOD(r, x4, 13, 13);     /* STOP_STATE_X4_IO */
+       r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* STOP_STATE_X16_IO */
+       r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* STOP_STATE_X4_IO */
        r = FLD_MOD(r, ticks, 12, 0);   /* STOP_STATE_COUNTER_IO */
        dsi_write_reg(DSI_TIMING1, r);
 
-       DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
-                       (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
-                       (fck / 1000 / 1000),
-                       ticks, x4 ? " x4" : "", x16 ? " x16" : "");
+       total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+       DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
+                       total_ticks,
+                       ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+                       (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_hs_tx_timeout(unsigned long ns)
+static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
 {
-       u32 r;
-       unsigned x4, x16;
        unsigned long fck;
-       unsigned long ticks;
+       unsigned long total_ticks;
+       u32 r;
 
-       /* ticks in TxByteClkHS */
+       BUG_ON(ticks > 0x1fff);
 
+       /* ticks in TxByteClkHS */
        fck = dsi_get_txbyteclkhs();
-       ticks = (fck / 1000 / 1000) * ns / 1000;
-       x4 = 0;
-       x16 = 0;
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
-               x4 = 1;
-               x16 = 0;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
-               x4 = 0;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
-               x4 = 1;
-               x16 = 1;
-       }
-
-       if (ticks > 0x1fff) {
-               DSSWARN("HS_TX_TO over limit, setting it to max\n");
-               ticks = 0x1fff;
-               x4 = 1;
-               x16 = 1;
-       }
 
        r = dsi_read_reg(DSI_TIMING2);
        r = FLD_MOD(r, 1, 31, 31);      /* HS_TX_TO */
-       r = FLD_MOD(r, x16, 30, 30);    /* HS_TX_TO_X16 */
-       r = FLD_MOD(r, x4, 29, 29);     /* HS_TX_TO_X8 (4 really) */
+       r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* HS_TX_TO_X16 */
+       r = FLD_MOD(r, x4 ? 1 : 0, 29, 29);     /* HS_TX_TO_X8 (4 really) */
        r = FLD_MOD(r, ticks, 28, 16);  /* HS_TX_TO_COUNTER */
        dsi_write_reg(DSI_TIMING2, r);
 
-       DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
-                       (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
-                       (fck / 1000 / 1000),
-                       ticks, x4 ? " x4" : "", x16 ? " x16" : "");
+       total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
+
+       DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
+                       total_ticks,
+                       ticks, x4 ? " x4" : "", x16 ? " x16" : "",
+                       (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
@@ -2487,10 +2397,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
                        DSI_FIFO_SIZE_32);
 
        /* XXX what values for the timeouts? */
-       dsi_set_stop_state_counter(1000);
-       dsi_set_ta_timeout(6400000);
-       dsi_set_lp_rx_timeout(48000);
-       dsi_set_hs_tx_timeout(1000000);
+       dsi_set_stop_state_counter(0x1000, false, false);
+       dsi_set_ta_timeout(0x1fff, true, true);
+       dsi_set_lp_rx_timeout(0x1fff, true, true);
+       dsi_set_hs_tx_timeout(0x1fff, true, true);
 
        switch (dssdev->ctrl.pixel_size) {
        case 16:
@@ -2759,6 +2669,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        unsigned packet_payload;
        unsigned packet_len;
        u32 l;
+       int r;
        const unsigned channel = dsi.update_channel;
        /* line buffer is 1024 x 24bits */
        /* XXX: for some reason using full buffer size causes considerable TX
@@ -2809,8 +2720,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
 
        dsi_perf_mark_start();
 
-       schedule_delayed_work(&dsi.framedone_timeout_work,
+       r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work,
                        msecs_to_jiffies(250));
+       BUG_ON(r == 0);
 
        dss_start_update(dssdev);
 
@@ -2841,6 +2753,11 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 
        DSSERR("Framedone not received for 250ms!\n");
 
+       /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
+        * 250ms which would conflict with this timeout work. What should be
+        * done is first cancel the transfer on the HW, and then cancel the
+        * possibly scheduled framedone work */
+
        /* SIDLEMODE back to smart-idle */
        dispc_enable_sidle();
 
@@ -2873,6 +2790,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 
 static void dsi_framedone_irq_callback(void *data, u32 mask)
 {
+       int r;
        /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
         * turns itself off. However, DSI still has the pixels in its buffers,
         * and is sending the data.
@@ -2881,7 +2799,8 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
        /* SIDLEMODE back to smart-idle */
        dispc_enable_sidle();
 
-       schedule_work(&dsi.framedone_work);
+       r = queue_work(dsi.workqueue, &dsi.framedone_work);
+       BUG_ON(r == 0);
 }
 
 static void dsi_handle_framedone(void)
@@ -3048,8 +2967,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
        cinfo.regm3 = dssdev->phy.dsi.div.regm3;
        cinfo.regm4 = dssdev->phy.dsi.div.regm4;
        r = dsi_calc_clock_rates(&cinfo);
-       if (r)
+       if (r) {
+               DSSERR("Failed to calc dsi clocks\n");
                return r;
+       }
 
        r = dsi_pll_set_clock_div(&cinfo);
        if (r) {
@@ -3292,6 +3213,10 @@ int dsi_init(struct platform_device *pdev)
        mutex_init(&dsi.lock);
        sema_init(&dsi.bus_lock, 1);
 
+       dsi.workqueue = create_singlethread_workqueue("dsi");
+       if (dsi.workqueue == NULL)
+               return -ENOMEM;
+
        INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
        INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
                        dsi_framedone_timeout_work_callback);
@@ -3328,6 +3253,7 @@ int dsi_init(struct platform_device *pdev)
 err2:
        iounmap(dsi.base);
 err1:
+       destroy_workqueue(dsi.workqueue);
        return r;
 }
 
@@ -3335,6 +3261,8 @@ void dsi_exit(void)
 {
        iounmap(dsi.base);
 
+       destroy_workqueue(dsi.workqueue);
+
        DSSDBG("omap_dsi_exit\n");
 }