summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dsi.c
diff options
context:
space:
mode:
authorAnimesh Kishore <ankishore@nvidia.com>2012-07-11 17:55:28 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-07-19 00:52:30 -0700
commit4c93dd529897db120a5b8151e04598ebc864f0d2 (patch)
tree32b593829093c68bff2eae391fdff1643332303f /drivers/video/tegra/dc/dsi.c
parent871f9eb32a6717f595340d95a56c6530f7b1798a (diff)
video: tegra: dsi: Implement dcs video + host
Send host commands to panel during vertical blanking of a frame. Implementation is generic enough to handle both long and short packets. Bug 1009863 Change-Id: I9a80641df2d8b67eb3649d220c028543b246a5f3 Signed-off-by: Animesh Kishore <ankishore@nvidia.com> Reviewed-on: http://git-master/r/114990 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dsi.c')
-rw-r--r--drivers/video/tegra/dc/dsi.c208
1 files changed, 145 insertions, 63 deletions
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 7ee9375f58f1..ba8a451a4b4f 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -2081,7 +2081,6 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
u8 *pdata, u8 data_id, u16 data_len)
{
u8 virtual_channel;
- u8 *pval;
u32 val;
int err;
@@ -2104,10 +2103,9 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
pdata += 4;
} else {
val = 0;
- pval = (u8 *) &val;
- do
- *pval++ = *pdata++;
- while (--data_len);
+ memcpy(&val, pdata, data_len);
+ pdata += data_len;
+ data_len = 0;
}
tegra_dsi_writel(dsi, val, DSI_WR_DATA);
}
@@ -2129,6 +2127,9 @@ int tegra_dsi_write_data(struct tegra_dc *dc,
tegra_dc_io_start(dc);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
init_status = tegra_dsi_prepare_host_transmission(
dc, dsi, DSI_LP_OP_WRITE);
if (IS_ERR_OR_NULL(init_status)) {
@@ -2174,7 +2175,7 @@ static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
return err;
}
-static u8 get_8bit_ecc(u32 header)
+static u8 tegra_dsi_ecc(u32 header)
{
char ecc_parity[24] = {
0x07, 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19,
@@ -2191,75 +2192,156 @@ static u8 get_8bit_ecc(u32 header)
return ecc_byte;
}
-/* This function is written to send DCS short write (1 parameter) only.
- * This means the cmd will contain only 1 byte of index and 1 byte of value.
- * The data type ID is fixed at 0x15 and the ECC is calculated based on the
- * data in pdata.
- * The command will be sent by hardware every frame.
- * pdata should contain both the index + value for each cmd.
- * data_len will be the total number of bytes in pdata.
- */
-int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len)
+static u16 tegra_dsi_cs(char *pdata, u16 data_len)
{
- u8 ecc8bits = 0, data_len_orig = 0;
- u32 val = 0, pkthdr = 0;
- int err = 0, count = 0;
- struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ u16 byte_cnt;
+ u8 bit_cnt;
+ char curr_byte;
+ u16 crc = 0xFFFF;
+ u16 poly = 0x8408;
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
- tegra_dc_host_resume(dc);
+ if (data_len > 0) {
+ for (byte_cnt = 0; byte_cnt < data_len; byte_cnt++) {
+ curr_byte = pdata[byte_cnt];
+ for (bit_cnt = 0; bit_cnt < 8; bit_cnt++) {
+ if (((crc & 0x0001 ) ^
+ (curr_byte & 0x0001)) > 0)
+ crc = ((crc >> 1) & 0x7FFF) ^ poly;
+ else
+ crc = (crc >> 1) & 0x7FFF;
- data_len_orig = data_len;
- if (pdata != NULL) {
- while (data_len) {
- if (data_len >= 2) {
- pkthdr = (CMD_SHORTW |
- (((u16 *)pdata)[0]) << 8 | 0x00 << 24);
- ecc8bits = get_8bit_ecc(pkthdr);
- val = (pkthdr | (ecc8bits << 24));
- data_len -= 2;
- pdata += 2;
- count++;
+ curr_byte = (curr_byte >> 1 ) & 0x7F;
}
- switch (count) {
- case 1:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0);
- break;
- case 2:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_1);
- break;
- case 3:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_2);
- break;
- case 4:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_3);
- break;
- case 5:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_4);
- break;
- case 6:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_5);
- break;
- case 7:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_6);
- break;
- case 8:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_7);
- break;
- default:
- err = 1;
- break;
+ }
+ }
+ return crc;
+}
+
+static int tegra_dsi_dcs_pkt_seq_ctrl_init(struct tegra_dc_dsi_data *dsi,
+ struct tegra_dsi_cmd *cmd)
+{
+ u8 virtual_channel;
+ u32 val;
+ u16 data_len = cmd->sp_len_dly.data_len;
+ u8 seq_ctrl_reg = 0;
+
+ virtual_channel = dsi->info.virtual_channel <<
+ DSI_VIR_CHANNEL_BIT_POSITION;
+
+ val = (virtual_channel | cmd->data_id) << 0 |
+ data_len << 8;
+
+ val |= tegra_dsi_ecc(val) << 24;
+
+ tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0 + seq_ctrl_reg++);
+
+ /* if pdata != NULL, pkt type is long pkt */
+ if (cmd->pdata != NULL) {
+ u8 *pdata;
+ u8 *pdata_mem;
+ /* allocate memory for pdata + 2 bytes checksum */
+ pdata_mem = kzalloc(sizeof(u8) * data_len + 2, GFP_KERNEL);
+ if (!pdata_mem) {
+ dev_err(&dsi->dc->ndev->dev, "dsi: memory err\n");
+ tegra_dsi_soft_reset(dsi);
+ return -ENOMEM;
+ }
+
+ memcpy(pdata_mem, cmd->pdata, data_len);
+ pdata = pdata_mem;
+ *((u16 *)(pdata + data_len)) = tegra_dsi_cs(pdata, data_len);
+
+ /* data_len = length of pdata + 2 byte checksum */
+ data_len += 2;
+
+ while (data_len) {
+ if (data_len >= 4) {
+ val = ((u32 *) pdata)[0];
+ data_len -= 4;
+ pdata += 4;
+ } else {
+ val = 0;
+ memcpy(&val, pdata, data_len);
+ pdata += data_len;
+ data_len = 0;
}
+ tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0 +
+ seq_ctrl_reg++);
}
+ kfree(pdata_mem);
+ }
+
+ return 0;
+}
+
+int tegra_dsi_start_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi,
+ struct tegra_dsi_cmd *cmd)
+{
+#define PKT_HEADER_LEN_BYTE 4
+#define CHECKSUM_LEN_BYTE 2
+
+ int err = 0;
+ u32 val;
+ u16 tot_pkt_len = PKT_HEADER_LEN_BYTE;
+ struct tegra_dc *dc = dsi->dc;
+
+ if (cmd->cmd_type != TEGRA_DSI_PACKET_CMD)
+ return -EINVAL;
+
+ mutex_lock(&dsi->lock);
+ tegra_dc_io_start(dc);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
+ err = tegra_dsi_dcs_pkt_seq_ctrl_init(dsi, cmd);
+ if (err < 0) {
+ dev_err(&dsi->dc->ndev->dev,
+ "dsi: dcs pkt seq ctrl init failed\n");
+ goto fail;
+ }
+
+ if (cmd->pdata) {
+ u16 data_len = cmd->sp_len_dly.data_len;
+ tot_pkt_len += data_len + CHECKSUM_LEN_BYTE;
}
- val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(data_len_orig * 2)
- | DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(1);
+ val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(tot_pkt_len) |
+ DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(
+ TEGRA_DSI_ENABLE);
tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL);
+fail:
+ tegra_dc_io_end(dc);
+ mutex_unlock(&dsi->lock);
return err;
+
+#undef PKT_HEADER_LEN_BYTE
+#undef CHECKSUM_LEN_BYTE
+}
+EXPORT_SYMBOL(tegra_dsi_start_host_cmd_v_blank_dcs);
+
+void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi)
+{
+ struct tegra_dc *dc = dsi->dc;
+ u32 cnt;
+
+ mutex_lock(&dsi->lock);
+ tegra_dc_io_start(dc);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dc_host_resume(dc);
+
+ tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_INIT_SEQ_CONTROL);
+
+ /* clear seq data registers */
+ for (cnt = 0; cnt < 8; cnt++)
+ tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt);
+
+ tegra_dc_io_end(dc);
+ mutex_unlock(&dsi->lock);
}
-EXPORT_SYMBOL(tegra_dsi_send_panel_short_cmd);
+EXPORT_SYMBOL(tegra_dsi_stop_host_cmd_v_blank_dcs);
static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
{