blob: c6dc2d89cf93370ff1acad23ae56ae90cb93e62a [file] [log] [blame]
/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
#include <linux/kthread.h>
#include "mdss_dsi_cmd.h"
#include "mdss_dsi.h"
#include "mdss_smmu.h"
static DEFINE_MUTEX(boost_mode_lock);
/*
* mipi dsi buf mechanism
*/
char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len)
{
dp->data += len;
return dp->data;
}
char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len)
{
dp->data -= len;
return dp->data;
}
char *mdss_dsi_buf_push(struct dsi_buf *dp, int len)
{
dp->data -= len;
dp->len += len;
return dp->data;
}
char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
{
dp->hdr = (u32 *)dp->data;
return mdss_dsi_buf_reserve(dp, hlen);
}
char *mdss_dsi_buf_init(struct dsi_buf *dp)
{
int off;
dp->data = dp->start;
off = (int) (unsigned long) dp->data;
/* 8 byte align */
off &= 0x07;
if (off)
off = 8 - off;
dp->data += off;
dp->len = 0;
dp->read_cnt = 0;
return dp->data;
}
int mdss_dsi_buf_alloc(struct device *ctrl_dev, struct dsi_buf *dp, int size)
{
dp->start = mdss_smmu_dsi_alloc_buf(ctrl_dev, size, &dp->dmap,
GFP_KERNEL);
if (dp->start == NULL) {
pr_err("%s:%u\n", __func__, __LINE__);
return -ENOMEM;
}
dp->end = dp->start + size;
dp->size = size;
if ((int) (unsigned long) dp->start & 0x07)
pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
dp->data = dp->start;
dp->len = 0;
dp->read_cnt = 0;
return size;
}
/*
* mipi dsi generic long write
*/
static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len = 0;
dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/* fill up payload */
if (cm->payload) {
len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
for (; i < len; i++)
*bp++ = 0xff;
dp->len += len;
}
/* fill up header */
hp = dp->hdr;
*hp = 0;
*hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
len += DSI_HOST_HDR_SIZE;
return len;
}
/*
* mipi dsi generic short write with 0, 1 2 parameters
*/
static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
dchdr = &cm->dchdr;
if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(0);
} else if (len == 2) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(cm->payload[1]);
} else {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
*hp |= DSI_HDR_DATA1(0);
*hp |= DSI_HDR_DATA2(0);
}
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* mipi dsi gerneric read with 0, 1 2 parameters
*/
static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
dchdr = &cm->dchdr;
if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
if (dchdr->last)
*hp |= DSI_HDR_LAST;
len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(0);
} else if (len == 2) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(cm->payload[1]);
} else {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
*hp |= DSI_HDR_DATA1(0);
*hp |= DSI_HDR_DATA2(0);
}
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* mipi dsi dcs long write
*/
static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len = 0;
dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/*
* fill up payload
* dcs command byte (first byte) followed by payload
*/
if (cm->payload) {
len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
for (; i < len; i++)
*bp++ = 0xff;
dp->len += len;
}
/* fill up header */
hp = dp->hdr;
*hp = 0;
*hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
len += DSI_HOST_HDR_SIZE;
return len;
}
/*
* mipi dsi dcs short write with 0 parameters
*/
static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
if (dchdr->last)
*hp |= DSI_HDR_LAST;
len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
*hp |= DSI_HDR_DATA2(0);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* mipi dsi dcs short write with 1 parameters
*/
static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
if (dchdr->dlen < 2 || cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */
*hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* mipi dsi dcs read with 0 parameters
*/
static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
*hp |= DSI_HDR_DATA2(0);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_dsc_pps(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len = 0;
dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/*
* fill up payload
* dcs command byte (first byte) followed by payload
*/
if (cm->payload) {
len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
for (; i < len; i++)
*bp++ = 0xff;
dp->len += len;
}
/* fill up header */
hp = dp->hdr;
*hp = 0;
*hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_PPS);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
len += DSI_HOST_HDR_SIZE;
return len;
}
static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(cm->payload[1]);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_compression_mode(struct dsi_buf *dp,
struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_COMPRESSION_MODE);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]);
*hp |= DSI_HDR_DATA2(cm->payload[1]);
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
u32 *hp;
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
*hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
return DSI_HOST_HDR_SIZE; /* 4 bytes */
}
/*
* prepare cmd buffer to be txed
*/
int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
struct dsi_ctrl_hdr *dchdr;
int len = 0;
dchdr = &cm->dchdr;
switch (dchdr->dtype) {
case DTYPE_GEN_WRITE:
case DTYPE_GEN_WRITE1:
case DTYPE_GEN_WRITE2:
len = mdss_dsi_generic_swrite(dp, cm);
break;
case DTYPE_GEN_LWRITE:
len = mdss_dsi_generic_lwrite(dp, cm);
break;
case DTYPE_GEN_READ:
case DTYPE_GEN_READ1:
case DTYPE_GEN_READ2:
len = mdss_dsi_generic_read(dp, cm);
break;
case DTYPE_DCS_LWRITE:
len = mdss_dsi_dcs_lwrite(dp, cm);
break;
case DTYPE_DCS_WRITE:
len = mdss_dsi_dcs_swrite(dp, cm);
break;
case DTYPE_DCS_WRITE1:
len = mdss_dsi_dcs_swrite1(dp, cm);
break;
case DTYPE_DCS_READ:
len = mdss_dsi_dcs_read(dp, cm);
break;
case DTYPE_MAX_PKTSIZE:
len = mdss_dsi_set_max_pktsize(dp, cm);
break;
case DTYPE_PPS:
len = mdss_dsi_dsc_pps(dp, cm);
break;
case DTYPE_COMPRESSION_MODE:
len = mdss_dsi_compression_mode(dp, cm);
break;
case DTYPE_NULL_PKT:
len = mdss_dsi_null_pkt(dp, cm);
break;
case DTYPE_BLANK_PKT:
len = mdss_dsi_blank_pkt(dp, cm);
break;
case DTYPE_CM_ON:
len = mdss_dsi_cm_on(dp, cm);
break;
case DTYPE_CM_OFF:
len = mdss_dsi_cm_off(dp, cm);
break;
case DTYPE_PERIPHERAL_ON:
len = mdss_dsi_peripheral_on(dp, cm);
break;
case DTYPE_PERIPHERAL_OFF:
len = mdss_dsi_peripheral_off(dp, cm);
break;
default:
pr_debug("%s: dtype=%x NOT supported\n",
__func__, dchdr->dtype);
break;
}
return len;
}
/*
* mdss_dsi_short_read1_resp: 1 parameter
*/
int mdss_dsi_short_read1_resp(struct dsi_buf *rp)
{
/* strip out dcs type */
rp->data++;
rp->len = 1;
/* 1 byte for dcs type + 1 byte for ECC + 1 byte for 2nd data byte */
rp->read_cnt -= 3;
return rp->len;
}
/*
* mdss_dsi_short_read2_resp: 2 parameter
*/
int mdss_dsi_short_read2_resp(struct dsi_buf *rp)
{
/* strip out dcs type */
rp->data++;
rp->len = 2;
rp->read_cnt -= 2; /* 1 byte for dcs type + 1 byte for ECC */
return rp->len;
}
int mdss_dsi_long_read_resp(struct dsi_buf *rp)
{
/* strip out dcs header */
rp->data += 4;
rp->len -= 4;
rp->read_cnt -= 6; /* 4 bytes for dcs header + 2 bytes for CRC */
return rp->len;
}
static char set_tear_on[2] = {0x35, 0x00};
static struct dsi_cmd_desc dsi_tear_on_cmd = {
{DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
static char set_tear_off[2] = {0x34, 0x00};
static struct dsi_cmd_desc dsi_tear_off_cmd = {
{DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off)}, set_tear_off};
void mdss_dsi_set_tear_on(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if (pinfo->dcs_cmd_by_left && ctrl->ndx != DSI_CTRL_LEFT)
return;
if (pinfo->tear_disable)
return;
cmdreq.cmds = &dsi_tear_on_cmd;
cmdreq.cmds_cnt = 1;
cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
void mdss_dsi_set_tear_off(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if (pinfo->dcs_cmd_by_left && ctrl->ndx != DSI_CTRL_LEFT)
return;
if (pinfo->tear_disable)
return;
cmdreq.cmds = &dsi_tear_off_cmd;
cmdreq.cmds_cnt = 1;
cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
static char switch_page[2] = {0xFE, 0x00};
static struct dsi_cmd_desc dsi_switch_page_cmd = {
{DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(switch_page)}, switch_page};
void mdss_dsi_switch_page(struct mdss_dsi_ctrl_pdata *ctrl, char page)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if (pinfo->dcs_cmd_by_left && ctrl->ndx != DSI_CTRL_LEFT)
return;
switch_page[1] = page;
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = &dsi_switch_page_cmd;
cmdreq.cmds_cnt = 1;
cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
/*
* mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
*/
struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl,
int from_mdp)
{
struct dcs_cmd_list *clist;
struct dcs_cmd_req *req = NULL;
mutex_lock(&ctrl->cmdlist_mutex);
clist = &ctrl->cmdlist;
if (clist->get != clist->put) {
req = &clist->list[clist->get];
/*dont let commit thread steal ESD thread's
* command
*/
if (from_mdp && (req->flags & CMD_REQ_COMMIT)) {
mutex_unlock(&ctrl->cmdlist_mutex);
return NULL;
}
clist->get++;
clist->get %= CMD_REQ_MAX;
clist->tot--;
pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
clist->tot, clist->put, clist->get);
}
mutex_unlock(&ctrl->cmdlist_mutex);
return req;
}
int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
struct dcs_cmd_req *cmdreq)
{
struct dcs_cmd_req *req;
struct dcs_cmd_list *clist;
int ret = 0;
mutex_lock(&ctrl->cmd_mutex);
mutex_lock(&ctrl->cmdlist_mutex);
clist = &ctrl->cmdlist;
req = &clist->list[clist->put];
*req = *cmdreq;
clist->put++;
clist->put %= CMD_REQ_MAX;
clist->tot++;
if (clist->put == clist->get) {
/* drop the oldest one */
pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
clist->tot, clist->put, clist->get);
clist->get++;
clist->get %= CMD_REQ_MAX;
clist->tot--;
}
pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
clist->tot, clist->put, clist->get);
mutex_unlock(&ctrl->cmdlist_mutex);
if (req->flags & CMD_REQ_COMMIT) {
if (!ctrl->cmdlist_commit)
pr_err("cmdlist_commit not implemented!\n");
else
ret = ctrl->cmdlist_commit(ctrl, 0);
}
mutex_unlock(&ctrl->cmd_mutex);
return ret;
}
void mdss_dsi_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_panel_cmds *pcmds, u32 flags)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if (pinfo->dcs_cmd_by_left) {
if (ctrl->ndx != DSI_CTRL_LEFT)
return;
}
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = pcmds->cmds;
cmdreq.cmds_cnt = pcmds->cmd_cnt;
cmdreq.flags = flags;
if (pcmds->link_state == DSI_LP_MODE)
cmdreq.flags |= CMD_REQ_LP_MODE;
else if (pcmds->link_state == DSI_HS_MODE)
cmdreq.flags |= CMD_REQ_HS_MODE;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
static char _dcs_cmd[2] = {0x00, 0x00};
static struct dsi_cmd_desc _dcs_read_cmd = {
{DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(_dcs_cmd)}, _dcs_cmd};
int mdss_dsi_raydium_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char page,
char addr, void (*fxn)(int), char *rbuf, int len)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if (pinfo->dcs_cmd_by_left) {
if (ctrl->ndx != DSI_CTRL_LEFT)
return -EINVAL;
}
//switch to the correct page prior to reading
mdss_dsi_switch_page(ctrl, page);
_dcs_cmd[0] = addr;
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = &_dcs_read_cmd;
cmdreq.cmds_cnt = 1;
cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
cmdreq.rlen = len;
cmdreq.rbuf = rbuf;
cmdreq.cb = fxn; /* call back */
/*
* blocked here, until call back called
*/
return mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
void mdss_dsi_brightness_boost_on(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct dsi_panel_cmds *hbm_on_cmds = NULL;
if (ctrl->hbm_on_cmds.blen > 0) {
hbm_on_cmds = &ctrl->hbm_on_cmds;
} else {
switch (ctrl->id3_code[0]) {
case 0x01:
hbm_on_cmds = &ctrl->hbm0_on_cmds;
break;
case 0x03:
hbm_on_cmds = &ctrl->hbm1_on_cmds;
break;
case 0x04:
hbm_on_cmds = &ctrl->hbm1_on_cmds;
break;
default:
/*
* technically speaking, we won't get here since
* the value would be set anyway during boot phase
*/
pr_info("%s: HBM err: default case (%d)\n", __func__,
ctrl->id3_code[0]);
if (hbm_on_cmds == NULL)
hbm_on_cmds = &ctrl->hbm1_on_cmds;
break;
}
}
if (hbm_on_cmds != NULL && hbm_on_cmds->cmd_cnt) {
mdss_dsi_cmds_send(ctrl, hbm_on_cmds, CMD_REQ_COMMIT);
pr_info("%s: boost on!\n", __func__);
}
}
void mdss_dsi_brightness_boost_off(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct dsi_panel_cmds *hbm_off_cmds = NULL;
hbm_off_cmds = &ctrl->hbm_off_cmds;
if (ctrl->hbm1_on_cmds.blen > 0) {
pr_info("%s: read_back_param[0] = 0x%02x\n", __func__,
ctrl->read_back_param[0]);
//write back to HBM off command flow
hbm_off_cmds->cmds[9].payload[1] = ctrl->read_back_param[0];
}
if (hbm_off_cmds->cmd_cnt) {
mdss_dsi_cmds_send(ctrl, hbm_off_cmds, CMD_REQ_COMMIT);
pr_info("%s: boost off!\n", __func__);
}
}
void mdss_dsi_boost_mode_enable(struct mdss_dsi_ctrl_pdata *ctrl, u32 enabled)
{
mutex_lock(&boost_mode_lock);
if (ctrl->boost_mode_state != enabled) {
if (enabled != 0) {
mdss_dsi_brightness_boost_on(ctrl);
ctrl->boost_mode_state = 1;
} else {
mdss_dsi_brightness_boost_off(ctrl);
ctrl->boost_mode_state = 0;
}
}
mutex_unlock(&boost_mode_lock);
}