Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/video/fbdev/omap2/omapfb/dss/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 137 kB image not shown  

Quelle  dsi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/drivers/video/omap2/dss/dsi.c
 *
 * Copyright (C) 2009 Nokia Corporation
 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
 */


#define DSS_SUBSYS_NAME "DSI"

#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/component.h>

#include <video/omapfb_dss.h>
#include <video/mipi_display.h>

#include "dss.h"
#include "dss_features.h"

#define DSI_CATCH_MISSING_TE

struct dsi_reg { u16 module; u16 idx; };

#define DSI_REG(mod, idx)  ((const struct dsi_reg) { mod, idx })

/* DSI Protocol Engine */

#define DSI_PROTO   0
#define DSI_PROTO_SZ   0x200

#define DSI_REVISION   DSI_REG(DSI_PROTO, 0x0000)
#define DSI_SYSCONFIG   DSI_REG(DSI_PROTO, 0x0010)
#define DSI_SYSSTATUS   DSI_REG(DSI_PROTO, 0x0014)
#define DSI_IRQSTATUS   DSI_REG(DSI_PROTO, 0x0018)
#define DSI_IRQENABLE   DSI_REG(DSI_PROTO, 0x001C)
#define DSI_CTRL   DSI_REG(DSI_PROTO, 0x0040)
#define DSI_GNQ    DSI_REG(DSI_PROTO, 0x0044)
#define DSI_COMPLEXIO_CFG1  DSI_REG(DSI_PROTO, 0x0048)
#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(DSI_PROTO, 0x004C)
#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(DSI_PROTO, 0x0050)
#define DSI_CLK_CTRL   DSI_REG(DSI_PROTO, 0x0054)
#define DSI_TIMING1   DSI_REG(DSI_PROTO, 0x0058)
#define DSI_TIMING2   DSI_REG(DSI_PROTO, 0x005C)
#define DSI_VM_TIMING1   DSI_REG(DSI_PROTO, 0x0060)
#define DSI_VM_TIMING2   DSI_REG(DSI_PROTO, 0x0064)
#define DSI_VM_TIMING3   DSI_REG(DSI_PROTO, 0x0068)
#define DSI_CLK_TIMING   DSI_REG(DSI_PROTO, 0x006C)
#define DSI_TX_FIFO_VC_SIZE  DSI_REG(DSI_PROTO, 0x0070)
#define DSI_RX_FIFO_VC_SIZE  DSI_REG(DSI_PROTO, 0x0074)
#define DSI_COMPLEXIO_CFG2  DSI_REG(DSI_PROTO, 0x0078)
#define DSI_RX_FIFO_VC_FULLNESS  DSI_REG(DSI_PROTO, 0x007C)
#define DSI_VM_TIMING4   DSI_REG(DSI_PROTO, 0x0080)
#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(DSI_PROTO, 0x0084)
#define DSI_VM_TIMING5   DSI_REG(DSI_PROTO, 0x0088)
#define DSI_VM_TIMING6   DSI_REG(DSI_PROTO, 0x008C)
#define DSI_VM_TIMING7   DSI_REG(DSI_PROTO, 0x0090)
#define DSI_STOPCLK_TIMING  DSI_REG(DSI_PROTO, 0x0094)
#define DSI_VC_CTRL(n)   DSI_REG(DSI_PROTO, 0x0100 + (n * 0x20))
#define DSI_VC_TE(n)   DSI_REG(DSI_PROTO, 0x0104 + (n * 0x20))
#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0108 + (n * 0x20))
#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(DSI_PROTO, 0x010C + (n * 0x20))
#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0110 + (n * 0x20))
#define DSI_VC_IRQSTATUS(n)  DSI_REG(DSI_PROTO, 0x0118 + (n * 0x20))
#define DSI_VC_IRQENABLE(n)  DSI_REG(DSI_PROTO, 0x011C + (n * 0x20))

/* DSIPHY_SCP */

#define DSI_PHY    1
#define DSI_PHY_OFFSET   0x200
#define DSI_PHY_SZ   0x40

#define DSI_DSIPHY_CFG0   DSI_REG(DSI_PHY, 0x0000)
#define DSI_DSIPHY_CFG1   DSI_REG(DSI_PHY, 0x0004)
#define DSI_DSIPHY_CFG2   DSI_REG(DSI_PHY, 0x0008)
#define DSI_DSIPHY_CFG5   DSI_REG(DSI_PHY, 0x0014)
#define DSI_DSIPHY_CFG10  DSI_REG(DSI_PHY, 0x0028)

/* DSI_PLL_CTRL_SCP */

#define DSI_PLL    2
#define DSI_PLL_OFFSET   0x300
#define DSI_PLL_SZ   0x20

#define DSI_PLL_CONTROL   DSI_REG(DSI_PLL, 0x0000)
#define DSI_PLL_STATUS   DSI_REG(DSI_PLL, 0x0004)
#define DSI_PLL_GO   DSI_REG(DSI_PLL, 0x0008)
#define DSI_PLL_CONFIGURATION1  DSI_REG(DSI_PLL, 0x000C)
#define DSI_PLL_CONFIGURATION2  DSI_REG(DSI_PLL, 0x0010)

#define REG_GET(dsidev, idx, start, end) \
 FLD_GET(dsi_read_reg(dsidev, idx), start, end)

#define REG_FLD_MOD(dsidev, idx, val, start, end) \
 dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))

/* Global interrupts */
#define DSI_IRQ_VC0  (1 << 0)
#define DSI_IRQ_VC1  (1 << 1)
#define DSI_IRQ_VC2  (1 << 2)
#define DSI_IRQ_VC3  (1 << 3)
#define DSI_IRQ_WAKEUP  (1 << 4)
#define DSI_IRQ_RESYNC  (1 << 5)
#define DSI_IRQ_PLL_LOCK (1 << 7)
#define DSI_IRQ_PLL_UNLOCK (1 << 8)
#define DSI_IRQ_PLL_RECALL (1 << 9)
#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
#define DSI_IRQ_TE_TRIGGER (1 << 16)
#define DSI_IRQ_ACK_TRIGGER (1 << 17)
#define DSI_IRQ_SYNC_LOST (1 << 18)
#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
#define DSI_IRQ_TA_TIMEOUT (1 << 20)
#define DSI_IRQ_ERROR_MASK \
 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
 DSI_IRQ_TA_TIMEOUT)
#define DSI_IRQ_CHANNEL_MASK 0xf

/* Virtual channel interrupts */
#define DSI_VC_IRQ_CS  (1 << 0)
#define DSI_VC_IRQ_ECC_CORR (1 << 1)
#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
#define DSI_VC_IRQ_BTA  (1 << 5)
#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
#define DSI_VC_IRQ_ERROR_MASK \
 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
 DSI_VC_IRQ_FIFO_TX_UDF)

/* ComplexIO interrupts */
#define DSI_CIO_IRQ_ERRSYNCESC1  (1 << 0)
#define DSI_CIO_IRQ_ERRSYNCESC2  (1 << 1)
#define DSI_CIO_IRQ_ERRSYNCESC3  (1 << 2)
#define DSI_CIO_IRQ_ERRSYNCESC4  (1 << 3)
#define DSI_CIO_IRQ_ERRSYNCESC5  (1 << 4)
#define DSI_CIO_IRQ_ERRESC1  (1 << 5)
#define DSI_CIO_IRQ_ERRESC2  (1 << 6)
#define DSI_CIO_IRQ_ERRESC3  (1 << 7)
#define DSI_CIO_IRQ_ERRESC4  (1 << 8)
#define DSI_CIO_IRQ_ERRESC5  (1 << 9)
#define DSI_CIO_IRQ_ERRCONTROL1  (1 << 10)
#define DSI_CIO_IRQ_ERRCONTROL2  (1 << 11)
#define DSI_CIO_IRQ_ERRCONTROL3  (1 << 12)
#define DSI_CIO_IRQ_ERRCONTROL4  (1 << 13)
#define DSI_CIO_IRQ_ERRCONTROL5  (1 << 14)
#define DSI_CIO_IRQ_STATEULPS1  (1 << 15)
#define DSI_CIO_IRQ_STATEULPS2  (1 << 16)
#define DSI_CIO_IRQ_STATEULPS3  (1 << 17)
#define DSI_CIO_IRQ_STATEULPS4  (1 << 18)
#define DSI_CIO_IRQ_STATEULPS5  (1 << 19)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
#define DSI_CIO_IRQ_ERROR_MASK \
 (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
  DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
  DSI_CIO_IRQ_ERRSYNCESC5 | \
  DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
  DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
  DSI_CIO_IRQ_ERRESC5 | \
  DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
  DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
  DSI_CIO_IRQ_ERRCONTROL5 | \
  DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
  DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
  DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
  DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
  DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)

typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);

static int dsi_display_init_dispc(struct platform_device *dsidev,
 struct omap_overlay_manager *mgr);
static void dsi_display_uninit_dispc(struct platform_device *dsidev,
 struct omap_overlay_manager *mgr);

static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);

/* DSI PLL HSDIV indices */
#define HSDIV_DISPC 0
#define HSDIV_DSI 1

#define DSI_MAX_NR_ISRS                2
#define DSI_MAX_NR_LANES 5

enum dsi_lane_function {
 DSI_LANE_UNUSED = 0,
 DSI_LANE_CLK,
 DSI_LANE_DATA1,
 DSI_LANE_DATA2,
 DSI_LANE_DATA3,
 DSI_LANE_DATA4,
};

struct dsi_lane_config {
 enum dsi_lane_function function;
 u8 polarity;
};

struct dsi_isr_data {
 omap_dsi_isr_t isr;
 void  *arg;
 u32  mask;
};

enum fifo_size {
 DSI_FIFO_SIZE_0  = 0,
 DSI_FIFO_SIZE_32 = 1,
 DSI_FIFO_SIZE_64 = 2,
 DSI_FIFO_SIZE_96 = 3,
 DSI_FIFO_SIZE_128 = 4,
};

enum dsi_vc_source {
 DSI_VC_SOURCE_L4 = 0,
 DSI_VC_SOURCE_VP,
};

struct dsi_irq_stats {
 unsigned long last_reset;
 unsigned irq_count;
 unsigned dsi_irqs[32];
 unsigned vc_irqs[4][32];
 unsigned cio_irqs[32];
};

struct dsi_isr_tables {
 struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
 struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
 struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
};

struct dsi_clk_calc_ctx {
 struct platform_device *dsidev;
 struct dss_pll *pll;

 /* inputs */

 const struct omap_dss_dsi_config *config;

 unsigned long req_pck_min, req_pck_nom, req_pck_max;

 /* outputs */

 struct dss_pll_clock_info dsi_cinfo;
 struct dispc_clock_info dispc_cinfo;

 struct omap_video_timings dispc_vm;
 struct omap_dss_dsi_videomode_timings dsi_vm;
};

struct dsi_lp_clock_info {
 unsigned long lp_clk;
 u16 lp_clk_div;
};

struct dsi_data {
 struct platform_device *pdev;
 void __iomem *proto_base;
 void __iomem *phy_base;
 void __iomem *pll_base;

 int module_id;

 int irq;

 bool is_enabled;

 struct clk *dss_clk;

 struct dispc_clock_info user_dispc_cinfo;
 struct dss_pll_clock_info user_dsi_cinfo;

 struct dsi_lp_clock_info user_lp_cinfo;
 struct dsi_lp_clock_info current_lp_cinfo;

 struct dss_pll pll;

 bool vdds_dsi_enabled;
 struct regulator *vdds_dsi_reg;

 struct {
  enum dsi_vc_source source;
  struct omap_dss_device *dssdev;
  enum fifo_size tx_fifo_size;
  enum fifo_size rx_fifo_size;
  int vc_id;
 } vc[4];

 struct mutex lock;
 struct semaphore bus_lock;

 spinlock_t irq_lock;
 struct dsi_isr_tables isr_tables;
 /* space for a copy used by the interrupt handler */
 struct dsi_isr_tables isr_tables_copy;

 int update_channel;
#ifdef DSI_PERF_MEASURE
 unsigned update_bytes;
#endif

 bool te_enabled;
 bool ulps_enabled;

 void (*framedone_callback)(intvoid *);
 void *framedone_data;

 struct delayed_work framedone_timeout_work;

#ifdef DSI_CATCH_MISSING_TE
 struct timer_list te_timer;
#endif

 unsigned long cache_req_pck;
 unsigned long cache_clk_freq;
 struct dss_pll_clock_info cache_cinfo;

 u32  errors;
 spinlock_t errors_lock;
#ifdef DSI_PERF_MEASURE
 ktime_t perf_setup_time;
 ktime_t perf_start_time;
#endif
 int debug_read;
 int debug_write;

#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
 spinlock_t irq_stats_lock;
 struct dsi_irq_stats irq_stats;
#endif

 unsigned num_lanes_supported;
 unsigned line_buffer_size;

 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
 unsigned num_lanes_used;

 unsigned scp_clk_refcount;

 struct dss_lcd_mgr_config mgr_config;
 struct omap_video_timings timings;
 enum omap_dss_dsi_pixel_format pix_fmt;
 enum omap_dss_dsi_mode mode;
 struct omap_dss_dsi_videomode_timings vm_timings;

 struct omap_dss_device output;
};

struct dsi_packet_sent_handler_data {
 struct platform_device *dsidev;
 struct completion *completion;
};

struct dsi_module_id_data {
 u32 address;
 int id;
};

static const struct of_device_id dsi_of_match[];

#ifdef DSI_PERF_MEASURE
static bool dsi_perf;
module_param(dsi_perf, bool, 0644);
#endif

static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
{
 return platform_get_drvdata(dsidev);
}

static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
{
 return to_platform_device(dssdev->dev);
}

static struct platform_device *dsi_get_dsidev_from_id(int module)
{
 struct omap_dss_device *out;
 enum omap_dss_output_id id;

 switch (module) {
 case 0:
  id = OMAP_DSS_OUTPUT_DSI1;
  break;
 case 1:
  id = OMAP_DSS_OUTPUT_DSI2;
  break;
 default:
  return NULL;
 }

 out = omap_dss_get_output(id);

 return out ? to_platform_device(out->dev) : NULL;
}

static inline void dsi_write_reg(struct platform_device *dsidev,
  const struct dsi_reg idx, u32 val)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 void __iomem *base;

 switch(idx.module) {
  case DSI_PROTO: base = dsi->proto_base; break;
  case DSI_PHY: base = dsi->phy_base; break;
  case DSI_PLL: base = dsi->pll_base; break;
  defaultreturn;
 }

 __raw_writel(val, base + idx.idx);
}

static inline u32 dsi_read_reg(struct platform_device *dsidev,
  const struct dsi_reg idx)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 void __iomem *base;

 switch(idx.module) {
  case DSI_PROTO: base = dsi->proto_base; break;
  case DSI_PHY: base = dsi->phy_base; break;
  case DSI_PLL: base = dsi->pll_base; break;
  defaultreturn 0;
 }

 return __raw_readl(base + idx.idx);
}

static void dsi_bus_lock(struct omap_dss_device *dssdev)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 down(&dsi->bus_lock);
}

static void dsi_bus_unlock(struct omap_dss_device *dssdev)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 up(&dsi->bus_lock);
}

static bool dsi_bus_is_locked(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 return dsi->bus_lock.count == 0;
}

static void dsi_completion_handler(void *data, u32 mask)
{
 complete((struct completion *)data);
}

static inline int wait_for_bit_change(struct platform_device *dsidev,
  const struct dsi_reg idx, int bitnum, int value)
{
 unsigned long timeout;
 ktime_t wait;
 int t;

 /* first busyloop to see if the bit changes right away */
 t = 100;
 while (t-- > 0) {
  if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
   return value;
 }

 /* then loop for 500ms, sleeping for 1ms in between */
 timeout = jiffies + msecs_to_jiffies(500);
 while (time_before(jiffies, timeout)) {
  if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
   return value;

  wait = ns_to_ktime(1000 * 1000);
  set_current_state(TASK_UNINTERRUPTIBLE);
  schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
 }

 return !value;
}

u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
{
 switch (fmt) {
 case OMAP_DSS_DSI_FMT_RGB888:
 case OMAP_DSS_DSI_FMT_RGB666:
  return 24;
 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
  return 18;
 case OMAP_DSS_DSI_FMT_RGB565:
  return 16;
 default:
  BUG();
  return 0;
 }
}

#ifdef DSI_PERF_MEASURE
static void dsi_perf_mark_setup(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 dsi->perf_setup_time = ktime_get();
}

static void dsi_perf_mark_start(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 dsi->perf_start_time = ktime_get();
}

static void dsi_perf_show(struct platform_device *dsidev, const char *name)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 ktime_t t, setup_time, trans_time;
 u32 total_bytes;
 u32 setup_us, trans_us, total_us;

 if (!dsi_perf)
  return;

 t = ktime_get();

 setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
 setup_us = (u32)ktime_to_us(setup_time);
 if (setup_us == 0)
  setup_us = 1;

 trans_time = ktime_sub(t, dsi->perf_start_time);
 trans_us = (u32)ktime_to_us(trans_time);
 if (trans_us == 0)
  trans_us = 1;

 total_us = setup_us + trans_us;

 total_bytes = dsi->update_bytes;

 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
   "%u bytes, %u kbytes/sec\n",
   name,
   setup_us,
   trans_us,
   total_us,
   1000*1000 / total_us,
   total_bytes,
   total_bytes * 1000 / total_us);
}
#else
static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
{
}

static inline void dsi_perf_mark_start(struct platform_device *dsidev)
{
}

static inline void dsi_perf_show(struct platform_device *dsidev,
  const char *name)
{
}
#endif

static int verbose_irq;

static void print_irq_status(u32 status)
{
 if (status == 0)
  return;

 if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0)
  return;

#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : ""

 pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
  status,
  verbose_irq ? PIS(VC0) : "",
  verbose_irq ? PIS(VC1) : "",
  verbose_irq ? PIS(VC2) : "",
  verbose_irq ? PIS(VC3) : "",
  PIS(WAKEUP),
  PIS(RESYNC),
  PIS(PLL_LOCK),
  PIS(PLL_UNLOCK),
  PIS(PLL_RECALL),
  PIS(COMPLEXIO_ERR),
  PIS(HS_TX_TIMEOUT),
  PIS(LP_RX_TIMEOUT),
  PIS(TE_TRIGGER),
  PIS(ACK_TRIGGER),
  PIS(SYNC_LOST),
  PIS(LDO_POWER_GOOD),
  PIS(TA_TIMEOUT));
#undef PIS
}

static void print_irq_status_vc(int channel, u32 status)
{
 if (status == 0)
  return;

 if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
  return;

#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : ""

 pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n",
  channel,
  status,
  PIS(CS),
  PIS(ECC_CORR),
  PIS(ECC_NO_CORR),
  verbose_irq ? PIS(PACKET_SENT) : "",
  PIS(BTA),
  PIS(FIFO_TX_OVF),
  PIS(FIFO_RX_OVF),
  PIS(FIFO_TX_UDF),
  PIS(PP_BUSY_CHANGE));
#undef PIS
}

static void print_irq_status_cio(u32 status)
{
 if (status == 0)
  return;

#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : ""

 pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
  status,
  PIS(ERRSYNCESC1),
  PIS(ERRSYNCESC2),
  PIS(ERRSYNCESC3),
  PIS(ERRESC1),
  PIS(ERRESC2),
  PIS(ERRESC3),
  PIS(ERRCONTROL1),
  PIS(ERRCONTROL2),
  PIS(ERRCONTROL3),
  PIS(STATEULPS1),
  PIS(STATEULPS2),
  PIS(STATEULPS3),
  PIS(ERRCONTENTIONLP0_1),
  PIS(ERRCONTENTIONLP1_1),
  PIS(ERRCONTENTIONLP0_2),
  PIS(ERRCONTENTIONLP1_2),
  PIS(ERRCONTENTIONLP0_3),
  PIS(ERRCONTENTIONLP1_3),
  PIS(ULPSACTIVENOT_ALL0),
  PIS(ULPSACTIVENOT_ALL1));
#undef PIS
}

#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
  u32 *vcstatus, u32 ciostatus)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int i;

 spin_lock(&dsi->irq_stats_lock);

 dsi->irq_stats.irq_count++;
 dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);

 for (i = 0; i < 4; ++i)
  dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);

 dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);

 spin_unlock(&dsi->irq_stats_lock);
}
#else
#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
#endif

static int debug_irq;

static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
  u32 *vcstatus, u32 ciostatus)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int i;

 if (irqstatus & DSI_IRQ_ERROR_MASK) {
  DSSERR("DSI error, irqstatus %x\n", irqstatus);
  print_irq_status(irqstatus);
  spin_lock(&dsi->errors_lock);
  dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
  spin_unlock(&dsi->errors_lock);
 } else if (debug_irq) {
  print_irq_status(irqstatus);
 }

 for (i = 0; i < 4; ++i) {
  if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
   DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
           i, vcstatus[i]);
   print_irq_status_vc(i, vcstatus[i]);
  } else if (debug_irq) {
   print_irq_status_vc(i, vcstatus[i]);
  }
 }

 if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
  DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
  print_irq_status_cio(ciostatus);
 } else if (debug_irq) {
  print_irq_status_cio(ciostatus);
 }
}

static void dsi_call_isrs(struct dsi_isr_data *isr_array,
  unsigned isr_array_size, u32 irqstatus)
{
 struct dsi_isr_data *isr_data;
 int i;

 for (i = 0; i < isr_array_size; i++) {
  isr_data = &isr_array[i];
  if (isr_data->isr && isr_data->mask & irqstatus)
   isr_data->isr(isr_data->arg, irqstatus);
 }
}

static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
  u32 irqstatus, u32 *vcstatus, u32 ciostatus)
{
 int i;

 dsi_call_isrs(isr_tables->isr_table,
   ARRAY_SIZE(isr_tables->isr_table),
   irqstatus);

 for (i = 0; i < 4; ++i) {
  if (vcstatus[i] == 0)
   continue;
  dsi_call_isrs(isr_tables->isr_table_vc[i],
    ARRAY_SIZE(isr_tables->isr_table_vc[i]),
    vcstatus[i]);
 }

 if (ciostatus != 0)
  dsi_call_isrs(isr_tables->isr_table_cio,
    ARRAY_SIZE(isr_tables->isr_table_cio),
    ciostatus);
}

static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
{
 struct platform_device *dsidev;
 struct dsi_data *dsi;
 u32 irqstatus, vcstatus[4], ciostatus;
 int i;

 dsidev = (struct platform_device *) arg;
 dsi = dsi_get_dsidrv_data(dsidev);

 if (!dsi->is_enabled)
  return IRQ_NONE;

 spin_lock(&dsi->irq_lock);

 irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);

 /* IRQ is not for us */
 if (!irqstatus) {
  spin_unlock(&dsi->irq_lock);
  return IRQ_NONE;
 }

 dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
 /* flush posted write */
 dsi_read_reg(dsidev, DSI_IRQSTATUS);

 for (i = 0; i < 4; ++i) {
  if ((irqstatus & (1 << i)) == 0) {
   vcstatus[i] = 0;
   continue;
  }

  vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));

  dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
  /* flush posted write */
  dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
 }

 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
  ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);

  dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
  /* flush posted write */
  dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
 } else {
  ciostatus = 0;
 }

#ifdef DSI_CATCH_MISSING_TE
 if (irqstatus & DSI_IRQ_TE_TRIGGER)
  timer_delete(&dsi->te_timer);
#endif

 /* make a copy and unlock, so that isrs can unregister
 * themselves */

 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
  sizeof(dsi->isr_tables));

 spin_unlock(&dsi->irq_lock);

 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);

 dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);

 dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);

 return IRQ_HANDLED;
}

/* dsi->irq_lock has to be locked by the caller */
static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
  struct dsi_isr_data *isr_array,
  unsigned isr_array_size, u32 default_mask,
  const struct dsi_reg enable_reg,
  const struct dsi_reg status_reg)
{
 struct dsi_isr_data *isr_data;
 u32 mask;
 u32 old_mask;
 int i;

 mask = default_mask;

 for (i = 0; i < isr_array_size; i++) {
  isr_data = &isr_array[i];

  if (isr_data->isr == NULL)
   continue;

  mask |= isr_data->mask;
 }

 old_mask = dsi_read_reg(dsidev, enable_reg);
 /* clear the irqstatus for newly enabled irqs */
 dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
 dsi_write_reg(dsidev, enable_reg, mask);

 /* flush posted writes */
 dsi_read_reg(dsidev, enable_reg);
 dsi_read_reg(dsidev, status_reg);
}

/* dsi->irq_lock has to be locked by the caller */
static void _omap_dsi_set_irqs(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 u32 mask = DSI_IRQ_ERROR_MASK;
#ifdef DSI_CATCH_MISSING_TE
 mask |= DSI_IRQ_TE_TRIGGER;
#endif
 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
   ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
   DSI_IRQENABLE, DSI_IRQSTATUS);
}

/* dsi->irq_lock has to be locked by the caller */
static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
   ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
   DSI_VC_IRQ_ERROR_MASK,
   DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
}

/* dsi->irq_lock has to be locked by the caller */
static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
   ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
   DSI_CIO_IRQ_ERROR_MASK,
   DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
}

static void _dsi_initialize_irq(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int vc;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));

 _omap_dsi_set_irqs(dsidev);
 for (vc = 0; vc < 4; ++vc)
  _omap_dsi_set_irqs_vc(dsidev, vc);
 _omap_dsi_set_irqs_cio(dsidev);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);
}

static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
  struct dsi_isr_data *isr_array, unsigned isr_array_size)
{
 struct dsi_isr_data *isr_data;
 int free_idx;
 int i;

 BUG_ON(isr == NULL);

 /* check for duplicate entry and find a free slot */
 free_idx = -1;
 for (i = 0; i < isr_array_size; i++) {
  isr_data = &isr_array[i];

  if (isr_data->isr == isr && isr_data->arg == arg &&
    isr_data->mask == mask) {
   return -EINVAL;
  }

  if (isr_data->isr == NULL && free_idx == -1)
   free_idx = i;
 }

 if (free_idx == -1)
  return -EBUSY;

 isr_data = &isr_array[free_idx];
 isr_data->isr = isr;
 isr_data->arg = arg;
 isr_data->mask = mask;

 return 0;
}

static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
  struct dsi_isr_data *isr_array, unsigned isr_array_size)
{
 struct dsi_isr_data *isr_data;
 int i;

 for (i = 0; i < isr_array_size; i++) {
  isr_data = &isr_array[i];
  if (isr_data->isr != isr || isr_data->arg != arg ||
    isr_data->mask != mask)
   continue;

  isr_data->isr = NULL;
  isr_data->arg = NULL;
  isr_data->mask = 0;

  return 0;
 }

 return -EINVAL;
}

static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
  void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
   ARRAY_SIZE(dsi->isr_tables.isr_table));

 if (r == 0)
  _omap_dsi_set_irqs(dsidev);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static int dsi_unregister_isr(struct platform_device *dsidev,
  omap_dsi_isr_t isr, void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
   ARRAY_SIZE(dsi->isr_tables.isr_table));

 if (r == 0)
  _omap_dsi_set_irqs(dsidev);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
  omap_dsi_isr_t isr, void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_register_isr(isr, arg, mask,
   dsi->isr_tables.isr_table_vc[channel],
   ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));

 if (r == 0)
  _omap_dsi_set_irqs_vc(dsidev, channel);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
  omap_dsi_isr_t isr, void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_unregister_isr(isr, arg, mask,
   dsi->isr_tables.isr_table_vc[channel],
   ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));

 if (r == 0)
  _omap_dsi_set_irqs_vc(dsidev, channel);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static int dsi_register_isr_cio(struct platform_device *dsidev,
  omap_dsi_isr_t isr, void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
   ARRAY_SIZE(dsi->isr_tables.isr_table_cio));

 if (r == 0)
  _omap_dsi_set_irqs_cio(dsidev);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static int dsi_unregister_isr_cio(struct platform_device *dsidev,
  omap_dsi_isr_t isr, void *arg, u32 mask)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 int r;

 spin_lock_irqsave(&dsi->irq_lock, flags);

 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
   ARRAY_SIZE(dsi->isr_tables.isr_table_cio));

 if (r == 0)
  _omap_dsi_set_irqs_cio(dsidev);

 spin_unlock_irqrestore(&dsi->irq_lock, flags);

 return r;
}

static u32 dsi_get_errors(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 u32 e;
 spin_lock_irqsave(&dsi->errors_lock, flags);
 e = dsi->errors;
 dsi->errors = 0;
 spin_unlock_irqrestore(&dsi->errors_lock, flags);
 return e;
}

static int dsi_runtime_get(struct platform_device *dsidev)
{
 int r;
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 DSSDBG("dsi_runtime_get\n");

 r = pm_runtime_resume_and_get(&dsi->pdev->dev);
 if (WARN_ON(r < 0))
  return r;
 return 0;
}

static void dsi_runtime_put(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int r;

 DSSDBG("dsi_runtime_put\n");

 r = pm_runtime_put_sync(&dsi->pdev->dev);
 WARN_ON(r < 0 && r != -ENOSYS);
}

static int dsi_regulator_init(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 struct regulator *vdds_dsi;

 if (dsi->vdds_dsi_reg != NULL)
  return 0;

 vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd");

 if (IS_ERR(vdds_dsi)) {
  if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
   DSSERR("can't get DSI VDD regulator\n");
  return PTR_ERR(vdds_dsi);
 }

 dsi->vdds_dsi_reg = vdds_dsi;

 return 0;
}

static void _dsi_print_reset_status(struct platform_device *dsidev)
{
 int b0, b1, b2;

 /* A dummy read using the SCP interface to any DSIPHY register is
 * required after DSIPHY reset to complete the reset of the DSI complex
 * I/O. */

 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);

 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
  b0 = 28;
  b1 = 27;
  b2 = 26;
 } else {
  b0 = 24;
  b1 = 25;
  b2 = 26;
 }

#define DSI_FLD_GET(fld, start, end)\
 FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end)

 pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n",
  DSI_FLD_GET(PLL_STATUS, 0, 0),
  DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29),
  DSI_FLD_GET(DSIPHY_CFG5, b0, b0),
  DSI_FLD_GET(DSIPHY_CFG5, b1, b1),
  DSI_FLD_GET(DSIPHY_CFG5, b2, b2),
  DSI_FLD_GET(DSIPHY_CFG5, 29, 29),
  DSI_FLD_GET(DSIPHY_CFG5, 30, 30),
  DSI_FLD_GET(DSIPHY_CFG5, 31, 31));

#undef DSI_FLD_GET
}

static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
{
 DSSDBG("dsi_if_enable(%d)\n", enable);

 enable = enable ? 1 : 0;
 REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */

 if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
   DSSERR("Failed to set dsi_if_enable to %d\n", enable);
   return -EIO;
 }

 return 0;
}

static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 return dsi->pll.cinfo.clkout[HSDIV_DISPC];
}

static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 return dsi->pll.cinfo.clkout[HSDIV_DSI];
}

static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 return dsi->pll.cinfo.clkdco / 16;
}

static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
{
 unsigned long r;
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
  /* DSI FCLK source is DSS_CLK_FCK */
  r = clk_get_rate(dsi->dss_clk);
 } else {
  /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
  r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
 }

 return r;
}

static int dsi_lp_clock_calc(unsigned long dsi_fclk,
  unsigned long lp_clk_min, unsigned long lp_clk_max,
  struct dsi_lp_clock_info *lp_cinfo)
{
 unsigned lp_clk_div;
 unsigned long lp_clk;

 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
 lp_clk = dsi_fclk / 2 / lp_clk_div;

 if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
  return -EINVAL;

 lp_cinfo->lp_clk_div = lp_clk_div;
 lp_cinfo->lp_clk = lp_clk;

 return 0;
}

static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long dsi_fclk;
 unsigned lp_clk_div;
 unsigned long lp_clk;
 unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);


 lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;

 if (lp_clk_div == 0 || lp_clk_div > lpdiv_max)
  return -EINVAL;

 dsi_fclk = dsi_fclk_rate(dsidev);

 lp_clk = dsi_fclk / 2 / lp_clk_div;

 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
 dsi->current_lp_cinfo.lp_clk = lp_clk;
 dsi->current_lp_cinfo.lp_clk_div = lp_clk_div;

 /* LP_CLK_DIVISOR */
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);

 /* LP_RX_SYNCHRO_ENABLE */
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);

 return 0;
}

static void dsi_enable_scp_clk(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 if (dsi->scp_clk_refcount++ == 0)
  REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
}

static void dsi_disable_scp_clk(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 WARN_ON(dsi->scp_clk_refcount == 0);
 if (--dsi->scp_clk_refcount == 0)
  REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
}

enum dsi_pll_power_state {
 DSI_PLL_POWER_OFF = 0x0,
 DSI_PLL_POWER_ON_HSCLK = 0x1,
 DSI_PLL_POWER_ON_ALL = 0x2,
 DSI_PLL_POWER_ON_DIV = 0x3,
};

static int dsi_pll_power(struct platform_device *dsidev,
  enum dsi_pll_power_state state)
{
 int t = 0;

 /* DSI-PLL power command 0x3 is not working */
 if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
   state == DSI_PLL_POWER_ON_DIV)
  state = DSI_PLL_POWER_ON_ALL;

 /* PLL_PWR_CMD */
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);

 /* PLL_PWR_STATUS */
 while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
  if (++t > 1000) {
   DSSERR("Failed to set DSI PLL power mode to %d\n",
     state);
   return -ENODEV;
  }
  udelay(1);
 }

 return 0;
}


static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo)
{
 unsigned long max_dsi_fck;

 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);

 cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
 cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
}

static int dsi_pll_enable(struct dss_pll *pll)
{
 struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
 struct platform_device *dsidev = dsi->pdev;
 int r = 0;

 DSSDBG("PLL init\n");

 r = dsi_regulator_init(dsidev);
 if (r)
  return r;

 r = dsi_runtime_get(dsidev);
 if (r)
  return r;

 /*
 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
 */

 dsi_enable_scp_clk(dsidev);

 if (!dsi->vdds_dsi_enabled) {
  r = regulator_enable(dsi->vdds_dsi_reg);
  if (r)
   goto err0;
  dsi->vdds_dsi_enabled = true;
 }

 /* XXX PLL does not come out of reset without this... */
 dispc_pck_free_enable(1);

 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
  DSSERR("PLL not coming out of reset.\n");
  r = -ENODEV;
  dispc_pck_free_enable(0);
  goto err1;
 }

 /* XXX ... but if left on, we get problems when planes do not
 * fill the whole display. No idea about this */

 dispc_pck_free_enable(0);

 r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL);

 if (r)
  goto err1;

 DSSDBG("PLL init done\n");

 return 0;
err1:
 if (dsi->vdds_dsi_enabled) {
  regulator_disable(dsi->vdds_dsi_reg);
  dsi->vdds_dsi_enabled = false;
 }
err0:
 dsi_disable_scp_clk(dsidev);
 dsi_runtime_put(dsidev);
 return r;
}

static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
 if (disconnect_lanes) {
  WARN_ON(!dsi->vdds_dsi_enabled);
  regulator_disable(dsi->vdds_dsi_reg);
  dsi->vdds_dsi_enabled = false;
 }

 dsi_disable_scp_clk(dsidev);
 dsi_runtime_put(dsidev);

 DSSDBG("PLL uninit done\n");
}

static void dsi_pll_disable(struct dss_pll *pll)
{
 struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
 struct platform_device *dsidev = dsi->pdev;

 dsi_pll_uninit(dsidev, true);
}

static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
  struct seq_file *s)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
 enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
 int dsi_module = dsi->module_id;
 struct dss_pll *pll = &dsi->pll;

 dispc_clk_src = dss_get_dispc_clk_source();
 dsi_clk_src = dss_get_dsi_clk_source(dsi_module);

 if (dsi_runtime_get(dsidev))
  return;

 seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);

 seq_printf(s, "dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin));

 seq_printf(s, "Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n);

 seq_printf(s, "CLKIN4DDR\t%-16lum %u\n",
   cinfo->clkdco, cinfo->m);

 seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n",
   dss_feat_get_clk_source_name(dsi_module == 0 ?
    OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
    OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
   cinfo->clkout[HSDIV_DISPC],
   cinfo->mX[HSDIV_DISPC],
   dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
   "off" : "on");

 seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n",
   dss_feat_get_clk_source_name(dsi_module == 0 ?
    OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
    OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
   cinfo->clkout[HSDIV_DSI],
   cinfo->mX[HSDIV_DSI],
   dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
   "off" : "on");

 seq_printf(s, "- DSI%d -\n", dsi_module + 1);

 seq_printf(s, "dsi fclk source = %s (%s)\n",
   dss_get_generic_clk_source_name(dsi_clk_src),
   dss_feat_get_clk_source_name(dsi_clk_src));

 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));

 seq_printf(s, "DDR_CLK\t\t%lu\n",
   cinfo->clkdco / 4);

 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));

 seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);

 dsi_runtime_put(dsidev);
}

void dsi_dump_clocks(struct seq_file *s)
{
 struct platform_device *dsidev;
 int i;

 for  (i = 0; i < MAX_NUM_DSI; i++) {
  dsidev = dsi_get_dsidev_from_id(i);
  if (dsidev)
   dsi_dump_dsidev_clocks(dsidev, s);
 }
}

#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
  struct seq_file *s)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned long flags;
 struct dsi_irq_stats *stats;

 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
 if (!stats) {
  seq_printf(s, "out of memory\n");
  return;
 }

 spin_lock_irqsave(&dsi->irq_stats_lock, flags);

 *stats = dsi->irq_stats;
 memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
 dsi->irq_stats.last_reset = jiffies;

 spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);

 seq_printf(s, "period %u ms\n",
   jiffies_to_msecs(jiffies - stats->last_reset));

 seq_printf(s, "irqs %d\n", stats->irq_count);
#define PIS(x) \
 seq_printf(s, "%-20s %10d\n"#x, stats->dsi_irqs[ffs(DSI_IRQ_##x)-1])

 seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
 PIS(VC0);
 PIS(VC1);
 PIS(VC2);
 PIS(VC3);
 PIS(WAKEUP);
 PIS(RESYNC);
 PIS(PLL_LOCK);
 PIS(PLL_UNLOCK);
 PIS(PLL_RECALL);
 PIS(COMPLEXIO_ERR);
 PIS(HS_TX_TIMEOUT);
 PIS(LP_RX_TIMEOUT);
 PIS(TE_TRIGGER);
 PIS(ACK_TRIGGER);
 PIS(SYNC_LOST);
 PIS(LDO_POWER_GOOD);
 PIS(TA_TIMEOUT);
#undef PIS

#define PIS(x) \
 seq_printf(s, "%-20s %10d %10d %10d %10d\n"#x, \
   stats->vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
   stats->vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
   stats->vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
   stats->vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);

 seq_printf(s, "-- VC interrupts --\n");
 PIS(CS);
 PIS(ECC_CORR);
 PIS(PACKET_SENT);
 PIS(FIFO_TX_OVF);
 PIS(FIFO_RX_OVF);
 PIS(BTA);
 PIS(ECC_NO_CORR);
 PIS(FIFO_TX_UDF);
 PIS(PP_BUSY_CHANGE);
#undef PIS

#define PIS(x) \
 seq_printf(s, "%-20s %10d\n"#x, \
   stats->cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);

 seq_printf(s, "-- CIO interrupts --\n");
 PIS(ERRSYNCESC1);
 PIS(ERRSYNCESC2);
 PIS(ERRSYNCESC3);
 PIS(ERRESC1);
 PIS(ERRESC2);
 PIS(ERRESC3);
 PIS(ERRCONTROL1);
 PIS(ERRCONTROL2);
 PIS(ERRCONTROL3);
 PIS(STATEULPS1);
 PIS(STATEULPS2);
 PIS(STATEULPS3);
 PIS(ERRCONTENTIONLP0_1);
 PIS(ERRCONTENTIONLP1_1);
 PIS(ERRCONTENTIONLP0_2);
 PIS(ERRCONTENTIONLP1_2);
 PIS(ERRCONTENTIONLP0_3);
 PIS(ERRCONTENTIONLP1_3);
 PIS(ULPSACTIVENOT_ALL0);
 PIS(ULPSACTIVENOT_ALL1);
#undef PIS

 kfree(stats);
}

static void dsi1_dump_irqs(struct seq_file *s)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);

 dsi_dump_dsidev_irqs(dsidev, s);
}

static void dsi2_dump_irqs(struct seq_file *s)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);

 dsi_dump_dsidev_irqs(dsidev, s);
}
#endif

static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
  struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n"#r, dsi_read_reg(dsidev, r))

 if (dsi_runtime_get(dsidev))
  return;
 dsi_enable_scp_clk(dsidev);

 DUMPREG(DSI_REVISION);
 DUMPREG(DSI_SYSCONFIG);
 DUMPREG(DSI_SYSSTATUS);
 DUMPREG(DSI_IRQSTATUS);
 DUMPREG(DSI_IRQENABLE);
 DUMPREG(DSI_CTRL);
 DUMPREG(DSI_COMPLEXIO_CFG1);
 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
 DUMPREG(DSI_CLK_CTRL);
 DUMPREG(DSI_TIMING1);
 DUMPREG(DSI_TIMING2);
 DUMPREG(DSI_VM_TIMING1);
 DUMPREG(DSI_VM_TIMING2);
 DUMPREG(DSI_VM_TIMING3);
 DUMPREG(DSI_CLK_TIMING);
 DUMPREG(DSI_TX_FIFO_VC_SIZE);
 DUMPREG(DSI_RX_FIFO_VC_SIZE);
 DUMPREG(DSI_COMPLEXIO_CFG2);
 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
 DUMPREG(DSI_VM_TIMING4);
 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
 DUMPREG(DSI_VM_TIMING5);
 DUMPREG(DSI_VM_TIMING6);
 DUMPREG(DSI_VM_TIMING7);
 DUMPREG(DSI_STOPCLK_TIMING);

 DUMPREG(DSI_VC_CTRL(0));
 DUMPREG(DSI_VC_TE(0));
 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
 DUMPREG(DSI_VC_IRQSTATUS(0));
 DUMPREG(DSI_VC_IRQENABLE(0));

 DUMPREG(DSI_VC_CTRL(1));
 DUMPREG(DSI_VC_TE(1));
 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
 DUMPREG(DSI_VC_IRQSTATUS(1));
 DUMPREG(DSI_VC_IRQENABLE(1));

 DUMPREG(DSI_VC_CTRL(2));
 DUMPREG(DSI_VC_TE(2));
 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
 DUMPREG(DSI_VC_IRQSTATUS(2));
 DUMPREG(DSI_VC_IRQENABLE(2));

 DUMPREG(DSI_VC_CTRL(3));
 DUMPREG(DSI_VC_TE(3));
 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
 DUMPREG(DSI_VC_IRQSTATUS(3));
 DUMPREG(DSI_VC_IRQENABLE(3));

 DUMPREG(DSI_DSIPHY_CFG0);
 DUMPREG(DSI_DSIPHY_CFG1);
 DUMPREG(DSI_DSIPHY_CFG2);
 DUMPREG(DSI_DSIPHY_CFG5);

 DUMPREG(DSI_PLL_CONTROL);
 DUMPREG(DSI_PLL_STATUS);
 DUMPREG(DSI_PLL_GO);
 DUMPREG(DSI_PLL_CONFIGURATION1);
 DUMPREG(DSI_PLL_CONFIGURATION2);

 dsi_disable_scp_clk(dsidev);
 dsi_runtime_put(dsidev);
#undef DUMPREG
}

static void dsi1_dump_regs(struct seq_file *s)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);

 dsi_dump_dsidev_regs(dsidev, s);
}

static void dsi2_dump_regs(struct seq_file *s)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);

 dsi_dump_dsidev_regs(dsidev, s);
}

enum dsi_cio_power_state {
 DSI_COMPLEXIO_POWER_OFF  = 0x0,
 DSI_COMPLEXIO_POWER_ON  = 0x1,
 DSI_COMPLEXIO_POWER_ULPS = 0x2,
};

static int dsi_cio_power(struct platform_device *dsidev,
  enum dsi_cio_power_state state)
{
 int t = 0;

 /* PWR_CMD */
 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);

 /* PWR_STATUS */
 while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
   26, 25) != state) {
  if (++t > 1000) {
   DSSERR("failed to set complexio power state to "
     "%d\n", state);
   return -ENODEV;
  }
  udelay(1);
 }

 return 0;
}

static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
{
 int val;

 /* line buffer on OMAP3 is 1024 x 24bits */
 /* XXX: for some reason using full buffer size causes
 * considerable TX slowdown with update sizes that fill the
 * whole buffer */

 if (!dss_has_feature(FEAT_DSI_GNQ))
  return 1023 * 3;

 val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */

 switch (val) {
 case 1:
  return 512 * 3;  /* 512x24 bits */
 case 2:
  return 682 * 3;  /* 682x24 bits */
 case 3:
  return 853 * 3;  /* 853x24 bits */
 case 4:
  return 1024 * 3; /* 1024x24 bits */
 case 5:
  return 1194 * 3; /* 1194x24 bits */
 case 6:
  return 1365 * 3; /* 1365x24 bits */
 case 7:
  return 1920 * 3; /* 1920x24 bits */
 default:
  BUG();
  return 0;
 }
}

static int dsi_set_lane_config(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 static const u8 offsets[] = { 0, 4, 8, 12, 16 };
 static const enum dsi_lane_function functions[] = {
  DSI_LANE_CLK,
  DSI_LANE_DATA1,
  DSI_LANE_DATA2,
  DSI_LANE_DATA3,
  DSI_LANE_DATA4,
 };
 u32 r;
 int i;

 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);

 for (i = 0; i < dsi->num_lanes_used; ++i) {
  unsigned offset = offsets[i];
  unsigned polarity, lane_number;
  unsigned t;

  for (t = 0; t < dsi->num_lanes_supported; ++t)
   if (dsi->lanes[t].function == functions[i])
    break;

  if (t == dsi->num_lanes_supported)
   return -EINVAL;

  lane_number = t;
  polarity = dsi->lanes[t].polarity;

  r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
  r = FLD_MOD(r, polarity, offset + 3, offset + 3);
 }

 /* clear the unused lanes */
 for (; i < dsi->num_lanes_supported; ++i) {
  unsigned offset = offsets[i];

  r = FLD_MOD(r, 0, offset + 2, offset);
  r = FLD_MOD(r, 0, offset + 3, offset + 3);
 }

 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);

 return 0;
}

static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 /* convert time in ns to ddr ticks, rounding up */
 unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
}

static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
 return ddr * 1000 * 1000 / (ddr_clk / 1000);
}

static void dsi_cio_timings(struct platform_device *dsidev)
{
 u32 r;
 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
 u32 tlpx_half, tclk_trail, tclk_zero;
 u32 tclk_prepare;

 /* calculate timings */

 /* 1 * DDR_CLK = 2 * UI */

 /* min 40ns + 4*UI max 85ns + 6*UI */
 ths_prepare = ns2ddr(dsidev, 70) + 2;

 /* min 145ns + 10*UI */
 ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;

 /* min max(8*UI, 60ns+4*UI) */
 ths_trail = ns2ddr(dsidev, 60) + 5;

 /* min 100ns */
 ths_exit = ns2ddr(dsidev, 145);

 /* tlpx min 50n */
 tlpx_half = ns2ddr(dsidev, 25);

 /* min 60ns */
 tclk_trail = ns2ddr(dsidev, 60) + 2;

 /* min 38ns, max 95ns */
 tclk_prepare = ns2ddr(dsidev, 65);

 /* min tclk-prepare + tclk-zero = 300ns */
 tclk_zero = ns2ddr(dsidev, 260);

 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
  ths_prepare, ddr2ns(dsidev, ths_prepare),
  ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
   ths_trail, ddr2ns(dsidev, ths_trail),
   ths_exit, ddr2ns(dsidev, ths_exit));

 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
   "tclk_zero %u (%uns)\n",
   tlpx_half, ddr2ns(dsidev, tlpx_half),
   tclk_trail, ddr2ns(dsidev, tclk_trail),
   tclk_zero, ddr2ns(dsidev, tclk_zero));
 DSSDBG("tclk_prepare %u (%uns)\n",
   tclk_prepare, ddr2ns(dsidev, tclk_prepare));

 /* program timings */

 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
 r = FLD_MOD(r, ths_prepare, 31, 24);
 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
 r = FLD_MOD(r, ths_trail, 15, 8);
 r = FLD_MOD(r, ths_exit, 7, 0);
 dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);

 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
 r = FLD_MOD(r, tlpx_half, 20, 16);
 r = FLD_MOD(r, tclk_trail, 15, 8);
 r = FLD_MOD(r, tclk_zero, 7, 0);

 if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
  r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
  r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
  r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
 }

 dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);

 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
 r = FLD_MOD(r, tclk_prepare, 7, 0);
 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
}

/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
  unsigned mask_p, unsigned mask_n)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int i;
 u32 l;
 u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;

 l = 0;

 for (i = 0; i < dsi->num_lanes_supported; ++i) {
  unsigned p = dsi->lanes[i].polarity;

  if (mask_p & (1 << i))
   l |= 1 << (i * 2 + (p ? 0 : 1));

  if (mask_n & (1 << i))
   l |= 1 << (i * 2 + (p ? 1 : 0));
 }

 /*
 * Bits in REGLPTXSCPDAT4TO0DXDY:
 * 17: DY0 18: DX0
 * 19: DY1 20: DX1
 * 21: DY2 22: DX2
 * 23: DY3 24: DX3
 * 25: DY4 26: DX4
 */


 /* Set the lane override configuration */

 /* REGLPTXSCPDAT4TO0DXDY */
 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);

 /* Enable lane override */

 /* ENLPTXSCPDAT */
 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
}

static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
{
 /* Disable lane override */
 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
 /* Reset the lane override configuration */
 /* REGLPTXSCPDAT4TO0DXDY */
 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
}

static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int t, i;
 bool in_use[DSI_MAX_NR_LANES];
 static const u8 offsets_old[] = { 28, 27, 26 };
 static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
 const u8 *offsets;

 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
  offsets = offsets_old;
 else
  offsets = offsets_new;

 for (i = 0; i < dsi->num_lanes_supported; ++i)
  in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;

 t = 100000;
 while (true) {
  u32 l;
  int ok;

  l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);

  ok = 0;
  for (i = 0; i < dsi->num_lanes_supported; ++i) {
   if (!in_use[i] || (l & (1 << offsets[i])))
    ok++;
  }

  if (ok == dsi->num_lanes_supported)
   break;

  if (--t == 0) {
   for (i = 0; i < dsi->num_lanes_supported; ++i) {
    if (!in_use[i] || (l & (1 << offsets[i])))
     continue;

    DSSERR("CIO TXCLKESC%d domain not coming " \
      "out of reset\n", i);
   }
   return -EIO;
  }
 }

 return 0;
}

/* return bitmask of enabled lanes, lane0 being the lsb */
static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 unsigned mask = 0;
 int i;

 for (i = 0; i < dsi->num_lanes_supported; ++i) {
  if (dsi->lanes[i].function != DSI_LANE_UNUSED)
   mask |= 1 << i;
 }

 return mask;
}

static int dsi_cio_init(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 int r;
 u32 l;

 DSSDBG("DSI CIO init starts");

 r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
 if (r)
  return r;

 dsi_enable_scp_clk(dsidev);

 /* A dummy read using the SCP interface to any DSIPHY register is
 * required after DSIPHY reset to complete the reset of the DSI complex
 * I/O. */

 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);

 if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
  DSSERR("CIO SCP Clock domain not coming out of reset.\n");
  r = -EIO;
  goto err_scp_clk_dom;
 }

 r = dsi_set_lane_config(dsidev);
 if (r)
  goto err_scp_clk_dom;

 /* set TX STOP MODE timer to maximum for this operation */
 l = dsi_read_reg(dsidev, DSI_TIMING1);
 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
 dsi_write_reg(dsidev, DSI_TIMING1, l);

 if (dsi->ulps_enabled) {
  unsigned mask_p;
  int i;

  DSSDBG("manual ulps exit\n");

  /* ULPS is exited by Mark-1 state for 1ms, followed by
 * stop state. DSS HW cannot do this via the normal
 * ULPS exit sequence, as after reset the DSS HW thinks
 * that we are not in ULPS mode, and refuses to send the
 * sequence. So we need to send the ULPS exit sequence
 * manually by setting positive lines high and negative lines
 * low for 1ms.
 */


  mask_p = 0;

  for (i = 0; i < dsi->num_lanes_supported; ++i) {
   if (dsi->lanes[i].function == DSI_LANE_UNUSED)
    continue;
   mask_p |= 1 << i;
  }

  dsi_cio_enable_lane_override(dsidev, mask_p, 0);
 }

 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
 if (r)
  goto err_cio_pwr;

 if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
  DSSERR("CIO PWR clock domain not coming out of reset.\n");
  r = -ENODEV;
  goto err_cio_pwr_dom;
 }

 dsi_if_enable(dsidev, true);
 dsi_if_enable(dsidev, false);
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */

 r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
 if (r)
  goto err_tx_clk_esc_rst;

 if (dsi->ulps_enabled) {
  /* Keep Mark-1 state for 1ms (as per DSI spec) */
  ktime_t wait = ns_to_ktime(1000 * 1000);
  set_current_state(TASK_UNINTERRUPTIBLE);
  schedule_hrtimeout(&wait, HRTIMER_MODE_REL);

  /* Disable the override. The lanes should be set to Mark-11
 * state by the HW */

  dsi_cio_disable_lane_override(dsidev);
 }

 /* FORCE_TX_STOP_MODE_IO */
 REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);

 dsi_cio_timings(dsidev);

 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
  /* DDR_CLK_ALWAYS_ON */
  REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
   dsi->vm_timings.ddr_clk_always_on, 13, 13);
 }

 dsi->ulps_enabled = false;

 DSSDBG("CIO init done\n");

 return 0;

err_tx_clk_esc_rst:
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
err_cio_pwr_dom:
 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
err_cio_pwr:
 if (dsi->ulps_enabled)
  dsi_cio_disable_lane_override(dsidev);
err_scp_clk_dom:
 dsi_disable_scp_clk(dsidev);
 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
 return r;
}

static void dsi_cio_uninit(struct platform_device *dsidev)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 /* DDR_CLK_ALWAYS_ON */
 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);

 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
 dsi_disable_scp_clk(dsidev);
 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
}

static void dsi_config_tx_fifo(struct platform_device *dsidev,
  enum fifo_size size1, enum fifo_size size2,
  enum fifo_size size3, enum fifo_size size4)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 u32 r = 0;
 int add = 0;
 int i;

 dsi->vc[0].tx_fifo_size = size1;
 dsi->vc[1].tx_fifo_size = size2;
 dsi->vc[2].tx_fifo_size = size3;
 dsi->vc[3].tx_fifo_size = size4;

 for (i = 0; i < 4; i++) {
  u8 v;
  int size = dsi->vc[i].tx_fifo_size;

  if (add + size > 4) {
   DSSERR("Illegal FIFO configuration\n");
   BUG();
   return;
  }

  v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
  r |= v << (8 * i);
  /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
  add += size;
 }

 dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
}

static void dsi_config_rx_fifo(struct platform_device *dsidev,
  enum fifo_size size1, enum fifo_size size2,
  enum fifo_size size3, enum fifo_size size4)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 u32 r = 0;
 int add = 0;
 int i;

 dsi->vc[0].rx_fifo_size = size1;
 dsi->vc[1].rx_fifo_size = size2;
 dsi->vc[2].rx_fifo_size = size3;
 dsi->vc[3].rx_fifo_size = size4;

 for (i = 0; i < 4; i++) {
  u8 v;
  int size = dsi->vc[i].rx_fifo_size;

  if (add + size > 4) {
   DSSERR("Illegal FIFO configuration\n");
   BUG();
   return;
  }

  v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
  r |= v << (8 * i);
  /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
  add += size;
 }

 dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
}

static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
{
 u32 r;

 r = dsi_read_reg(dsidev, DSI_TIMING1);
 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
 dsi_write_reg(dsidev, DSI_TIMING1, r);

 if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
  DSSERR("TX_STOP bit not going down\n");
  return -EIO;
 }

 return 0;
}

static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
{
 return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
}

static void dsi_packet_sent_handler_vp(void *data, u32 mask)
{
 struct dsi_packet_sent_handler_data *vp_data =
  (struct dsi_packet_sent_handler_data *) data;
 struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
 const int channel = dsi->update_channel;
 u8 bit = dsi->te_enabled ? 30 : 31;

 if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
  complete(vp_data->completion);
}

static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 DECLARE_COMPLETION_ONSTACK(completion);
 struct dsi_packet_sent_handler_data vp_data = {
  .dsidev = dsidev,
  .completion = &completion
 };
 int r = 0;
 u8 bit;

 bit = dsi->te_enabled ? 30 : 31;

 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
  &vp_data, DSI_VC_IRQ_PACKET_SENT);
 if (r)
  goto err0;

 /* Wait for completion only if TE_EN/TE_START is still set */
 if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
  if (wait_for_completion_timeout(&completion,
    msecs_to_jiffies(10)) == 0) {
   DSSERR("Failed to complete previous frame transfer\n");
   r = -EIO;
   goto err1;
  }
 }

 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
  &vp_data, DSI_VC_IRQ_PACKET_SENT);

 return 0;
err1:
 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
  &vp_data, DSI_VC_IRQ_PACKET_SENT);
err0:
 return r;
}

static void dsi_packet_sent_handler_l4(void *data, u32 mask)
{
 struct dsi_packet_sent_handler_data *l4_data =
  (struct dsi_packet_sent_handler_data *) data;
 struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
 const int channel = dsi->update_channel;

 if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
  complete(l4_data->completion);
}

static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
{
 DECLARE_COMPLETION_ONSTACK(completion);
 struct dsi_packet_sent_handler_data l4_data = {
  .dsidev = dsidev,
  .completion = &completion
 };
 int r = 0;

 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
  &l4_data, DSI_VC_IRQ_PACKET_SENT);
 if (r)
  goto err0;

 /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
  if (wait_for_completion_timeout(&completion,
    msecs_to_jiffies(10)) == 0) {
   DSSERR("Failed to complete previous l4 transfer\n");
   r = -EIO;
   goto err1;
  }
 }

 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
  &l4_data, DSI_VC_IRQ_PACKET_SENT);

 return 0;
err1:
 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
  &l4_data, DSI_VC_IRQ_PACKET_SENT);
err0:
 return r;
}

static int dsi_sync_vc(struct platform_device *dsidev, int channel)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 WARN_ON(!dsi_bus_is_locked(dsidev));

 if (!dsi_vc_is_enabled(dsidev, channel))
  return 0;

 switch (dsi->vc[channel].source) {
 case DSI_VC_SOURCE_VP:
  return dsi_sync_vc_vp(dsidev, channel);
 case DSI_VC_SOURCE_L4:
  return dsi_sync_vc_l4(dsidev, channel);
 default:
  BUG();
  return -EINVAL;
 }
}

static int dsi_vc_enable(struct platform_device *dsidev, int channel,
  bool enable)
{
 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
   channel, enable);

 enable = enable ? 1 : 0;

 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);

 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
  0, enable) != enable) {
   DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
   return -EIO;
 }

 return 0;
}

static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 u32 r;

 DSSDBG("Initial config of virtual channel %d", channel);

 r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));

 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
  DSSERR("VC(%d) busy when trying to configure it!\n",
    channel);

 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN  */
 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
 if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
  r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */

 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */

 dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);

 dsi->vc[channel].source = DSI_VC_SOURCE_L4;
}

static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
  enum dsi_vc_source source)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 if (dsi->vc[channel].source == source)
  return 0;

 DSSDBG("Source config of virtual channel %d", channel);

 dsi_sync_vc(dsidev, channel);

 dsi_vc_enable(dsidev, channel, 0);

 /* VC_BUSY */
 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
  DSSERR("vc(%d) busy when trying to config for VP\n", channel);
  return -EIO;
 }

 /* SOURCE, 0 = L4, 1 = video port */
 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);

 /* DCS_CMD_ENABLE */
 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
  bool enable = source == DSI_VC_SOURCE_VP;
  REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
 }

 dsi_vc_enable(dsidev, channel, 1);

 dsi->vc[channel].source = source;

 return 0;
}

static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
  bool enable)
{
 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);

 WARN_ON(!dsi_bus_is_locked(dsidev));

 dsi_vc_enable(dsidev, channel, 0);
 dsi_if_enable(dsidev, 0);

 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);

 dsi_vc_enable(dsidev, channel, 1);
 dsi_if_enable(dsidev, 1);

 dsi_force_tx_stop_mode_io(dsidev);

 /* start the DDR clock by sending a NULL packet */
 if (dsi->vm_timings.ddr_clk_always_on && enable)
  dsi_vc_send_null(dssdev, channel);
}

static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
{
 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
  u32 val;
  val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
  DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
    (val >> 0) & 0xff,
    (val >> 8) & 0xff,
    (val >> 16) & 0xff,
    (val >> 24) & 0xff);
 }
}

static void dsi_show_rx_ack_with_err(u16 err)
{
 DSSERR("\tACK with ERROR (%#x):\n", err);
 if (err & (1 << 0))
  DSSERR("\t\tSoT Error\n");
 if (err & (1 << 1))
  DSSERR("\t\tSoT Sync Error\n");
 if (err & (1 << 2))
  DSSERR("\t\tEoT Sync Error\n");
 if (err & (1 << 3))
  DSSERR("\t\tEscape Mode Entry Command Error\n");
 if (err & (1 << 4))
  DSSERR("\t\tLP Transmit Sync Error\n");
 if (err & (1 << 5))
  DSSERR("\t\tHS Receive Timeout Error\n");
 if (err & (1 << 6))
  DSSERR("\t\tFalse Control Error\n");
 if (err & (1 << 7))
  DSSERR("\t\t(reserved7)\n");
 if (err & (1 << 8))
  DSSERR("\t\tECC Error, single-bit (corrected)\n");
 if (err & (1 << 9))
  DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
 if (err & (1 << 10))
  DSSERR("\t\tChecksum Error\n");
 if (err & (1 << 11))
  DSSERR("\t\tData type not recognized\n");
 if (err & (1 << 12))
  DSSERR("\t\tInvalid VC ID\n");
 if (err & (1 << 13))
  DSSERR("\t\tInvalid Transmission Length\n");
 if (err & (1 << 14))
  DSSERR("\t\t(reserved14)\n");
 if (err & (1 << 15))
  DSSERR("\t\tDSI Protocol Violation\n");
}

static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
  int channel)
{
 /* RX_FIFO_NOT_EMPTY */
 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
  u32 val;
  u8 dt;
  val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
  DSSERR("\trawval %#08x\n", val);
  dt = FLD_GET(val, 5, 0);
  if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
   u16 err = FLD_GET(val, 23, 8);
   dsi_show_rx_ack_with_err(err);
  } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
   DSSERR("\tDCS short response, 1 byte: %#x\n",
     FLD_GET(val, 23, 8));
  } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
   DSSERR("\tDCS short response, 2 byte: %#x\n",
     FLD_GET(val, 23, 8));
  } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
   DSSERR("\tDCS long response, len %d\n",
     FLD_GET(val, 23, 8));
   dsi_vc_flush_long_data(dsidev, channel);
  } else {
   DSSERR("\tunknown datatype 0x%02x\n", dt);
  }
 }
 return 0;
}

static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
{
 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);

 if (dsi->debug_write || dsi->debug_read)
  DSSDBG("dsi_vc_send_bta %d\n", channel);

 WARN_ON(!dsi_bus_is_locked(dsidev));

 /* RX_FIFO_NOT_EMPTY */
 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.30 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.