Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91cf7698 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm9x35: display: qpic: enable interrupt for sending command"

parents ea8fa11f 65ded36c
Loading
Loading
Loading
Loading
+177 −69
Original line number Diff line number Diff line
@@ -40,14 +40,14 @@

static int mdss_qpic_probe(struct platform_device *pdev);
static int mdss_qpic_remove(struct platform_device *pdev);
static void qpic_interrupt_en(u32 en);

struct qpic_data_type *qpic_res;

/* for tuning */
/* for debugging */
static u32 use_bam = true;
static u32 use_irq;
static u32 use_irq = true;
static u32 use_vsync;
static u32 bus_handle;

static const struct of_device_id mdss_qpic_dt_match[] = {
	{ .compatible = "qcom,mdss_qpic",},
@@ -79,6 +79,8 @@ int qpic_off(struct msm_fb_data_type *mfd)
{
	int ret;
	ret = mdss_qpic_panel_off(qpic_res->panel_data, &qpic_res->panel_io);
	if (use_irq)
		qpic_interrupt_en(false);
	return ret;
}

@@ -86,13 +88,13 @@ static int msm_qpic_bus_set_vote(u32 vote)
{
	int ret;

	if (!bus_handle)
	if (!qpic_res->bus_handle)
		return 0;
	ret = msm_bus_scale_client_update_request(bus_handle,
	ret = msm_bus_scale_client_update_request(qpic_res->bus_handle,
			vote);
	if (ret)
		pr_err("msm_bus_scale_client_update_request() failed, bus_handle=0x%x, vote=%d, err=%d\n",
			bus_handle, vote, ret);
			qpic_res->bus_handle, vote, ret);
	return ret;
}

@@ -119,13 +121,16 @@ static void mdss_qpic_pan_display(struct msm_fb_data_type *mfd)
		       offset, fbi->fix.smem_len);
		return;
	}
	if (use_bam)
		fb_offset = (u32)fbi->fix.smem_start + offset;
	else
		fb_offset = (u32)mfd->fbi->screen_base + offset;

	msm_qpic_bus_set_vote(1);
	mdss_qpic_panel_on(qpic_res->panel_data, &qpic_res->panel_io);
	size = fbi->var.xres * fbi->var.yres * bpp;

	qpic_send_frame(0, 0, fbi->var.xres, fbi->var.yres,
	qpic_send_frame(0, 0, fbi->var.xres - 1, fbi->var.yres - 1,
		(u32 *)fb_offset, size);
	msm_qpic_bus_set_vote(0);
}
@@ -328,7 +333,8 @@ void mdss_qpic_reset(void)
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_RESET, 1 << 0);
	/* wait 100 us after reset as suggested by hw */
	usleep(100);
	time_end = (u32)ktime_to_ms(ktime_get()) + QPIC_MAX_VSYNC_WAIT_TIME;
	time_end = (u32)ktime_to_ms(ktime_get()) +
		QPIC_MAX_VSYNC_WAIT_TIME;
	while (((QPIC_INP(QPIC_REG_QPIC_LCDC_STTS) & (1 << 8)) == 0)) {
		if ((u32)ktime_to_ms(ktime_get()) > time_end) {
			pr_err("%s reset not finished", __func__);
@@ -339,15 +345,14 @@ void mdss_qpic_reset(void)
	}
}

void qpic_interrupt_en(u32 en)
static void qpic_interrupt_en(u32 en)
{
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
	if (en) {
		if (!qpic_res->irq_ena) {
			init_completion(&qpic_res->fifo_eof_comp);
			qpic_res->irq_ena = true;
			enable_irq(qpic_res->irq);
			QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN,
				(1 << 0) | (1 << 2));
		}
	} else {
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
@@ -361,20 +366,25 @@ static irqreturn_t qpic_irq_handler(int irq, void *ptr)
	u32 data;
	data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
	return 0;
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);

	if (data & ((1 << 2) | (1 << 4)))
		complete(&qpic_res->fifo_eof_comp);
	return IRQ_HANDLED;
}

int qpic_flush_buffer_bam(u32 cmd, u32 len, u32 *param, u32 is_cmd)
static int qpic_send_pkt_bam(u32 cmd, u32 len, u8 *param)
{
	int  ret = 0;
	u32 phys_addr, cfg2, block_len , flags;
	if (is_cmd) {

	if ((cmd != OP_WRITE_MEMORY_START) &&
		(cmd != OP_WRITE_MEMORY_CONTINUE)) {
		memcpy((u8 *)qpic_res->cmd_buf_virt, param, len);
		phys_addr = qpic_res->cmd_buf_phys;
	} else {
		phys_addr = (u32)param;
	}

	cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
	cfg2 &= ~0xFF;
	cfg2 |= cmd;
@@ -405,55 +415,155 @@ int qpic_flush_buffer_bam(u32 cmd, u32 len, u32 *param, u32 is_cmd)
	return ret;
}

int qpic_flush_buffer_sw(u32 cmd, u32 len, u32 *param, u32 is_cmd)
void qpic_dump_reg(void)
{
	pr_info("%s\n", __func__);
	pr_info("QPIC_REG_QPIC_LCDC_CTRL = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL));
	pr_info("QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT));
	pr_info("QPIC_REG_QPIC_LCDC_CFG0 = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG0));
	pr_info("QPIC_REG_QPIC_LCDC_CFG1 = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG1));
	pr_info("QPIC_REG_QPIC_LCDC_CFG2 = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2));
	pr_info("QPIC_REG_QPIC_LCDC_IRQ_EN = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_EN));
	pr_info("QPIC_REG_QPIC_LCDC_IRQ_STTS = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS));
	pr_info("QPIC_REG_QPIC_LCDC_STTS = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_STTS));
	pr_info("QPIC_REG_QPIC_LCDC_FIFO_SOF = %x\n",
		QPIC_INP(QPIC_REG_QPIC_LCDC_FIFO_SOF));
}

static int qpic_wait_for_fifo(void)
{
	u32 data, time_end;
	int ret = 0;

	if (use_irq) {
		data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
		data &= 0x3F;
		if (data == 0)
			return ret;
		INIT_COMPLETION(qpic_res->fifo_eof_comp);
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, (1 << 4));
		ret = wait_for_completion_timeout(&qpic_res->fifo_eof_comp,
				msecs_to_jiffies(QPIC_MAX_VSYNC_WAIT_TIME));
		if (ret > 0) {
			ret = 0;
		} else {
			pr_err("%s timeout %x\n", __func__, ret);
			ret = -ETIMEDOUT;
		}
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
	} else {
		time_end = (u32)ktime_to_ms(ktime_get()) +
			QPIC_MAX_VSYNC_WAIT_TIME;
		while (1) {
			data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
			data &= 0x3F;
			if (data == 0)
				break;
			/* yield 10 us for next polling by experiment*/
			usleep(10);
			if (ktime_to_ms(ktime_get()) > time_end) {
				pr_err("%s time out", __func__);
				ret = -EBUSY;
				break;
			}
		}
	}
	return ret;
}

static int qpic_wait_for_eof(void)
{
	u32 data, time_end;
	int ret = 0;
	if (use_irq) {
		data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
		if (data & (1 << 2))
			return ret;
		INIT_COMPLETION(qpic_res->fifo_eof_comp);
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, (1 << 2));
		ret = wait_for_completion_timeout(&qpic_res->fifo_eof_comp,
				msecs_to_jiffies(QPIC_MAX_VSYNC_WAIT_TIME));
		if (ret > 0) {
			ret = 0;
		} else {
			pr_err("%s timeout %x\n", __func__, ret);
			ret = -ETIMEDOUT;
		}
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
	} else {
		time_end = (u32)ktime_to_ms(ktime_get()) +
			QPIC_MAX_VSYNC_WAIT_TIME;
		while (1) {
			data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
			if (data & (1 << 2))
				break;
			/* yield 10 us for next polling by experiment*/
			usleep(10);
			if (ktime_to_ms(ktime_get()) > time_end) {
				pr_err("%s wait for eof time out\n", __func__);
				qpic_dump_reg();
				ret = -EBUSY;
				break;
			}
		}
	}
	return ret;
}

static int qpic_send_pkt_sw(u32 cmd, u32 len, u8 *param)
{
	u32 bytes_left, space, data, cfg2, time_end;
	u32 bytes_left, space, data, cfg2;
	int i, ret = 0;
	if ((len <= (sizeof(u32) * 4)) && (is_cmd)) {
		len >>= 2;/* len in dwords */
	if (len <= 4) {
		len = (len + 3) / 4; /* len in dwords */
		data = 0;
		for (i = 0; i < len; i++)
			data |= param[i] << (8 * i);
			data |= (u32)param[i] << (8 * i);
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, len);
		QPIC_OUTP(QPIC_REG_LCD_DEVICE_CMD0 + (4 * cmd), data);
		return 0;
	}

	if ((len & 0x1) != 0) {
		pr_err("%s: number of bytes needs be even", __func__);
		pr_debug("%s: number of bytes needs be even", __func__);
		len = (len + 1) & (~0x1);
	}
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, 0);
	cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
	if ((cmd != OP_WRITE_MEMORY_START) &&
		(cmd != OP_WRITE_MEMORY_CONTINUE))
		cfg2 |= (1 << 24); /* transparent mode */
	else
		cfg2 &= ~(1 << 24);

	cfg2 &= ~0xFF;
	cfg2 |= cmd;
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_SOF, 0x0);
	bytes_left = len;

	while (bytes_left > 0) {
		time_end = (u32)ktime_to_ms(ktime_get()) +
			QPIC_MAX_VSYNC_WAIT_TIME;
		while (1) {
			data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
			data &= 0x3F;
			if (data == 0)
				break;
			/* yield 10 us for next polling by experiment*/
			usleep(10);
			if (ktime_to_ms(ktime_get()) > time_end) {
				pr_err("%s time out", __func__);
				ret = -EBUSY;
		ret = qpic_wait_for_fifo();
		if (ret)
			goto exit_send_cmd_sw;
			}
		}
		space = (16 - data);

		space = 16;

		while ((space > 0) && (bytes_left > 0)) {
			/* write to fifo */
			if (bytes_left >= 4) {
				QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0,
					param[0]);
				param++;
					*(u32 *)param);
				param += 4;
				bytes_left -= 4;
				space--;
			} else if (bytes_left == 2) {
@@ -465,36 +575,20 @@ int qpic_flush_buffer_sw(u32 cmd, u32 len, u32 *param, u32 is_cmd)
	}
	/* finished */
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_EOF, 0x0);

	time_end = (u32)ktime_to_ms(ktime_get()) + QPIC_MAX_VSYNC_WAIT_TIME;
	while (1) {
		data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
		if (data & (1 << 2))
			break;
		/* yield 10 us for next polling by experiment*/
		usleep(10);
		if (ktime_to_ms(ktime_get()) > time_end) {
			pr_err("%s wait for eof time out", __func__);
			ret = -EBUSY;
			goto exit_send_cmd_sw;
		}
	}
	ret = qpic_wait_for_eof();
exit_send_cmd_sw:
	cfg2 &= ~(1 << 24);
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
	return ret;
}

int qpic_flush_buffer(u32 cmd, u32 len, u32 *param, u32 is_cmd)
int qpic_send_pkt(u32 cmd, u8 *param, u32 len)
{
	if (use_bam) {
		if (is_cmd)
			return qpic_flush_buffer_sw(cmd, len, param, is_cmd);
	if (!use_bam || ((cmd != OP_WRITE_MEMORY_CONTINUE) &&
		(cmd != OP_WRITE_MEMORY_START)))
		return qpic_send_pkt_sw(cmd, len, param);
	else
			return qpic_flush_buffer_bam(cmd, len, param, is_cmd);
	} else {
		return qpic_flush_buffer_sw(cmd, len, param, is_cmd);
	}
		return qpic_send_pkt_bam(cmd, len, param);
}

int mdss_qpic_init(void)
@@ -514,18 +608,21 @@ int mdss_qpic_init(void)
	data |= (1 << 9); /* threshold */
	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);

	if (use_irq && qpic_res->irq_requested) {
	if (use_irq && (!qpic_res->irq_requested)) {
		ret = devm_request_irq(&qpic_res->pdev->dev,
			qpic_res->irq, qpic_irq_handler,
			IRQF_DISABLED,	"QPIC", qpic_res);
		if (ret) {
			pr_err("qpic request_irq() failed!\n");
			use_irq = false;
		} else {
			disable_irq(qpic_res->irq);
		}
		qpic_res->irq_requested = true;
	}

	qpic_interrupt_en(use_irq);

	QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG0, 0x02108501);
	data = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
	data &= ~(0xFFF);
@@ -549,6 +646,16 @@ int mdss_qpic_init(void)
	return ret;
}

u32 qpic_read_data(u32 cmd_index, u32 size)
{
	u32 data = 0;
	if (size <= 4) {
		QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, size);
		data = QPIC_INP(QPIC_REG_LCD_DEVICE_CMD0 + (cmd_index * 4));
	}
	return data;
}

static int msm_qpic_bus_register(struct platform_device *pdev)
{
	int ret = 0;
@@ -559,9 +666,9 @@ static int msm_qpic_bus_register(struct platform_device *pdev)
		pr_err("msm_bus_cl_get_pdata failed\n");
		return -EINVAL;
	}
	bus_handle =
	qpic_res->bus_handle =
		msm_bus_scale_register_client(use_cases);
	if (!bus_handle) {
	if (!qpic_res->bus_handle) {
		ret = -EINVAL;
		pr_err("msm_bus_scale_register_client failed\n");
	}
@@ -645,8 +752,9 @@ probe_done:

static int mdss_qpic_remove(struct platform_device *pdev)
{
	if (bus_handle)
		msm_bus_scale_unregister_client(bus_handle);
	if (qpic_res->bus_handle)
		msm_bus_scale_unregister_client(qpic_res->bus_handle);
	qpic_res->bus_handle = 0;
	return 0;
}

+4 −2
Original line number Diff line number Diff line
@@ -48,8 +48,8 @@
#define QPIC_MAX_CMD_BUF_SIZE				512

int mdss_qpic_init(void);
int qpic_flush_buffer(u32 cmd, u32 len, u32 *param, u32 is_cmd);

int qpic_send_pkt(u32 cmd, u8 *param, u32 len);
u32 qpic_read_data(u32 cmd_index, u32 size);
u32 msm_qpic_get_bam_hdl(struct sps_bam_props *bam);
int mdss_qpic_panel_on(struct mdss_panel_data *pdata,
	struct qpic_panel_io_desc *panel_io);
@@ -83,6 +83,8 @@ struct qpic_data_type {
	u32 irq_requested;
	struct mdss_panel_data *panel_data;
	struct qpic_panel_io_desc panel_io;
	u32 bus_handle;
	struct completion fifo_eof_comp;
};

u32 qpic_send_frame(
+29 −51
Original line number Diff line number Diff line
@@ -41,44 +41,6 @@ u32 qpic_panel_get_framerate(void)
	return panel_refresh_rate;
}

u32 qpic_send_panel_cmd(u32 cmd, u32 *val, u32 length)
{
	u32 ret;
	u32 cmd_index;
	u32 size;
	u32 buffer[LCDC_INTERNAL_BUFFER_SIZE];
	u32 i;

	cmd_index = LCDC_EXTRACT_OP_CMD(cmd);
	size = LCDC_EXTRACT_OP_SIZE(cmd);
	if (size == INV_SIZE)
		size = length;
	/* short or pixel data commands need not conversion */
	if ((cmd == OP_WRITE_MEMORY_CONTINUE) ||
		(cmd == OP_WRITE_MEMORY_START)) {
		ret = qpic_flush_buffer(cmd_index, size, val, false);
	} else {
		if (size > LCDC_INTERNAL_BUFFER_SIZE)
			size = LCDC_INTERNAL_BUFFER_SIZE;
		/* correcting for encoding issues */
		for (i = 0; i < size; i += sizeof(u32)) {
			buffer[i] = (val[(i>>2)] >> 0) & 0xff;
			buffer[i+1] = (val[(i>>2)] >> 8) & 0xff;
			buffer[i+2] = (val[(i>>2)] >> 16) & 0xff;
			buffer[i+3] = (val[(i>>2)] >> 24) & 0xff;
		}
		ret = qpic_flush_buffer(cmd_index,
				size * sizeof(u32), buffer, true);
	}
	return ret;
}

u32 qpic_panel_set_cmd_only(u32 command)
{
	u32 param;
	return qpic_send_panel_cmd(command, &param, 0);
}

/* write a frame of pixels to a MIPI screen */
u32 qpic_send_frame(u32 x_start,
				u32 y_start,
@@ -87,7 +49,7 @@ u32 qpic_send_frame(u32 x_start,
				u32 *data,
				u32 total_bytes)
{
	u32 param;
	u8 param[4];
	u32 status;
	u32 start_0_7;
	u32 end_0_7;
@@ -105,9 +67,11 @@ u32 qpic_send_frame(u32 x_start,
	end_0_7 = x_end & 0xff;
	start_8_15 = (x_start >> 8) & 0xff;
	end_8_15 = (x_end >> 8) & 0xff;
	param = (start_8_15 << 0) | (start_0_7 << 8) |
		(end_8_15 << 16) | (end_0_7 << 24U);
	status = qpic_send_panel_cmd(OP_SET_COLUMN_ADDRESS, &param, 0);
	param[0] = start_8_15;
	param[1] = start_0_7;
	param[2] = end_8_15;
	param[3] = end_0_7;
	status = qpic_send_pkt(OP_SET_COLUMN_ADDRESS, param, 4);
	if (status) {
		pr_err("Failed to set column address");
		return status;
@@ -117,16 +81,17 @@ u32 qpic_send_frame(u32 x_start,
	end_0_7 = y_end & 0xff;
	start_8_15 = (y_start >> 8) & 0xff;
	end_8_15 = (y_end >> 8) & 0xff;
	param = (start_8_15 << 0) | (start_0_7 << 8) |
		(end_8_15 << 16) | (end_0_7 << 24U);
	status = qpic_send_panel_cmd(OP_SET_PAGE_ADDRESS, &param, 0);
	param[0] = start_8_15;
	param[1] = start_0_7;
	param[2] = end_8_15;
	param[3] = end_0_7;
	status = qpic_send_pkt(OP_SET_PAGE_ADDRESS, param, 4);
	if (status) {
		pr_err("Failed to set page address");
		return status;
	}

	status = qpic_send_panel_cmd(OP_WRITE_MEMORY_START,
		&(data[0]), total_bytes);
	status = qpic_send_pkt(OP_WRITE_MEMORY_START, (u8 *)data, total_bytes);
	if (status) {
		pr_err("Failed to start memory write");
		return status;
@@ -262,13 +227,26 @@ static int mdss_qpic_panel_probe(struct platform_device *pdev)
	else
		pr_info("%s: Panel Name = %s\n", __func__, panel_name);

	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
	if (rc)
		return rc;

	/* select panel according to label */
	if (!strcmp(panel_name, "ili qvga lcdc panel")) {
		qpic_panel_on = ili9341_on;
		qpic_panel_off = ili9341_off;
	} else {
		/* select default panel driver */
		pr_info("%s: select default panel driver\n", __func__);
		qpic_panel_on = ili9341_on;
		qpic_panel_off = ili9341_off;
	}

	if (qpic_panel_on == ili9341_on) {
		vendor_pdata.panel_info.xres = 240;
		vendor_pdata.panel_info.yres = 320;
	}

	rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
	if (rc)
		return rc;
	rc = qpic_register_panel(&vendor_pdata);
	if (rc)
		return rc;
+42 −39
Original line number Diff line number Diff line
@@ -67,43 +67,47 @@
/**
 * LDCc MIPI Type B supported commands
 */
enum {
	OP_ENTER_IDLE_MODE        = OP_SIZE_PAIR(0x39, 0),
	OP_ENTER_INVERT_MODE      = OP_SIZE_PAIR(0x21, 0),
	OP_ENTER_NORMAL_MODE      = OP_SIZE_PAIR(0x13, 0),
	OP_ENTER_PARTIAL_MODE     = OP_SIZE_PAIR(0x12, 0),
	OP_ENTER_SLEEP_MODE       = OP_SIZE_PAIR(0x10, 0),
	OP_EXIT_INVERT_MODE       = OP_SIZE_PAIR(0x20, 0),
	OP_EXIT_SLEEP_MODE        = OP_SIZE_PAIR(0x11, 0),
	OP_EXIT_IDLE_MODE         = OP_SIZE_PAIR(0x38, 0),
	OP_GET_ADDRESS_MODE       = OP_SIZE_PAIR(0x0B, 1),
	OP_GET_BLUE_CHANNEL       = OP_SIZE_PAIR(0x08, 1),
	OP_GET_DIAGNOSTIC_RESULT  = OP_SIZE_PAIR(0x0F, 2),
	OP_GET_DISPLAY_MODE       = OP_SIZE_PAIR(0x0D, 1),
	OP_GET_GREEN_CHANNEL      = OP_SIZE_PAIR(0x07, 1),
	OP_GET_PIXEL_FORMAT       = OP_SIZE_PAIR(0x0C, 1),
	OP_GET_POWER_MODE         = OP_SIZE_PAIR(0x0A, 1),
	OP_GET_RED_CHANNEL        = OP_SIZE_PAIR(0x06, 1),
	OP_GET_SCANLINE           = OP_SIZE_PAIR(0x45, 2),
	OP_GET_SIGNAL_MODE        = OP_SIZE_PAIR(0x0E, 1),
	OP_NOP                    = OP_SIZE_PAIR(0x00, 0),
	OP_READ_DDB_CONTINUE      = OP_SIZE_PAIR(0xA8, INV_SIZE),
	OP_READ_DDB_START         = OP_SIZE_PAIR(0xA1, INV_SIZE),
	OP_READ_MEMORY_CONTINUE   = OP_SIZE_PAIR(0x3E, INV_SIZE),
	OP_READ_MEMORY_START      = OP_SIZE_PAIR(0x2E, INV_SIZE),
	OP_SET_ADDRESS_MODE       = OP_SIZE_PAIR(0x36, 1),
	OP_SET_COLUMN_ADDRESS     = OP_SIZE_PAIR(0x2A, 4),
	OP_SET_DISPLAY_OFF        = OP_SIZE_PAIR(0x28, 0),
	OP_SET_DISPLAY_ON         = OP_SIZE_PAIR(0x29, 0),
	OP_SET_GAMMA_CURVE        = OP_SIZE_PAIR(0x26, 1),
	OP_SET_PAGE_ADDRESS       = OP_SIZE_PAIR(0x2B, 4),
	OP_SET_PARTIAL_COLUMNS    = OP_SIZE_PAIR(0x31, 4),
	OP_SET_PARTIAL_ROWS       = OP_SIZE_PAIR(0x30, 4),
	OP_SET_PIXEL_FORMAT       = OP_SIZE_PAIR(0x3A, 1),
	OP_SOFT_RESET             = OP_SIZE_PAIR(0x01, 0),
	OP_WRITE_MEMORY_CONTINUE  = OP_SIZE_PAIR(0x3C, INV_SIZE),
	OP_WRITE_MEMORY_START     = OP_SIZE_PAIR(0x2C, INV_SIZE),
};
#define	OP_ENTER_IDLE_MODE      0x39
#define	OP_ENTER_INVERT_MODE    0x21
#define	OP_ENTER_NORMAL_MODE    0x13
#define	OP_ENTER_PARTIAL_MODE   0x12
#define	OP_ENTER_SLEEP_MODE     0x10
#define	OP_EXIT_INVERT_MODE     0x20
#define	OP_EXIT_SLEEP_MODE      0x11
#define	OP_EXIT_IDLE_MODE       0x38
#define	OP_GET_ADDRESS_MODE     0x0B /* size 1 */
#define	OP_GET_BLUE_CHANNEL     0x08 /* size 1 */
#define	OP_GET_DIAGNOSTIC       0x0F /* size 2 */
#define	OP_GET_DISPLAY_MODE     0x0D /* size 1 */
#define	OP_GET_GREEN_CHANNEL    0x07 /* size 1 */
#define	OP_GET_PIXEL_FORMAT     0x0C /* size 1 */
#define	OP_GET_POWER_MODE       0x0A /* size 1 */
#define	OP_GET_RED_CHANNEL      0x06 /* size 1 */
#define	OP_GET_SCANLINE         0x45 /* size 1 */
#define	OP_GET_SIGNAL_MODE      0x0E /* size 1 */
#define	OP_NOP                  0x00
#define	OP_READ_DDB_CONTINUE    0xA8 /* size not fixed */
#define	OP_READ_DDB_START       0xA1 /* size not fixed */
#define	OP_READ_MEMORY_CONTINUE 0x3E /* size not fixed */
#define	OP_READ_MEMORY_START    0x2E /* size not fixed */
#define	OP_SET_ADDRESS_MODE     0x36 /* size 1 */
#define	OP_SET_COLUMN_ADDRESS   0x2A /* size 4 */
#define	OP_SET_DISPLAY_OFF      0x28
#define	OP_SET_DISPLAY_ON       0x29
#define	OP_SET_GAMMA_CURVE      0x26 /* size 1 */
#define	OP_SET_PAGE_ADDRESS     0x2B /* size 4 */
#define	OP_SET_PARTIAL_COLUMNS  0x31 /* size 4 */
#define	OP_SET_PARTIAL_ROWS     0x30 /* size 4 */
#define	OP_SET_PIXEL_FORMAT     0x3A /* size 1 */
#define	OP_SOFT_RESET           0x01
#define	OP_WRITE_MEMORY_CONTINUE  0x3C /* size not fixed */
#define	OP_WRITE_MEMORY_START   0x2C /* size not fixed */

/**
 * ILI9341 commands
 */
#define OP_ILI9341_INTERFACE_CONTROL	0xf6
#define OP_ILI9341_TEARING_EFFECT_LINE_ON	0x35

struct qpic_panel_io_desc {
	int rst_gpio;
@@ -118,8 +122,7 @@ struct qpic_panel_io_desc {

int mdss_qpic_panel_io_init(struct platform_device *pdev,
	struct qpic_panel_io_desc *qpic_panel_io);
u32 qpic_panel_set_cmd_only(u32 command);
u32 qpic_send_panel_cmd(u32 cmd, u32 *val, u32 length);
u32 qpic_panel_get_cmd(u32 command, u32 size);
int ili9341_on(struct qpic_panel_io_desc *qpic_panel_io);
void ili9341_off(struct qpic_panel_io_desc *qpic_panel_io);

+31 −51
Original line number Diff line number Diff line
@@ -29,34 +29,7 @@
#include "mdss_qpic.h"
#include "mdss_qpic_panel.h"

enum {
	OP_ILI9341_TEARING_EFFECT_LINE_ON = OP_SIZE_PAIR(0x35, 1),
	OP_ILI9341_INTERFACE_CONTROL = OP_SIZE_PAIR(0xf6, 3),
	OP_ILI9341_WRITE_CTRL_DISPLAY  = OP_SIZE_PAIR(0x53, 1),
	OP_ILI9341_POWER_CONTROL_A  = OP_SIZE_PAIR(0xcb, 5),
	OP_ILI9341_POWER_CONTROL_B  = OP_SIZE_PAIR(0xcf, 3),
	OP_ILI9341_DRIVER_TIMING_CONTROL_A  = OP_SIZE_PAIR(0xe8, 3),
	OP_ILI9341_DRIVER_TIMING_CONTROL_B  = OP_SIZE_PAIR(0xea, 3),
	OP_ILI9341_POWER_ON_SEQUENCE_CONTROL  = OP_SIZE_PAIR(0xed, 4),
	OP_ILI9341_PUMP_RATIO_CONTROL  = OP_SIZE_PAIR(0xf7, 1),
	OP_ILI9341_POWER_CONTROL_1  = OP_SIZE_PAIR(0xc0, 1),
	OP_ILI9341_POWER_CONTROL_2  = OP_SIZE_PAIR(0xc1, 1),
	OP_ILI9341_VCOM_CONTROL_1  = OP_SIZE_PAIR(0xc5, 2),
	OP_ILI9341_VCOM_CONTROL_2  = OP_SIZE_PAIR(0xc7, 1),
	OP_ILI9341_MEMORY_ACCESS_CONTROL  = OP_SIZE_PAIR(0x36, 1),
	OP_ILI9341_FRAME_RATE_CONTROL  = OP_SIZE_PAIR(0xb1, 2),
	OP_ILI9341_DISPLAY_FUNCTION_CONTROL = OP_SIZE_PAIR(0xb6, 4),
	OP_ILI9341_ENABLE_3G = OP_SIZE_PAIR(0xf2, 1),
	OP_ILI9341_COLMOD_PIXEL_FORMAT_SET = OP_SIZE_PAIR(0x3a, 1),
	OP_ILI9341_GAMMA_SET = OP_SIZE_PAIR(0x26, 1),
	OP_ILI9341_POSITIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe0, 15),
	OP_ILI9341_NEGATIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe1, 15),
	OP_ILI9341_READ_DISPLAY_ID = OP_SIZE_PAIR(0x04, 4),
	OP_ILI9341_READ_DISPLAY_POWER_MODE = OP_SIZE_PAIR(0x0a, 2),
	OP_ILI9341_READ_DISPLAY_MADCTL = OP_SIZE_PAIR(0x0b, 2),
};

static int ili9341_init(struct qpic_panel_io_desc *panel_io)
static int panel_io_init(struct qpic_panel_io_desc *panel_io)
{
	int rc;
	if (panel_io->vdd_vreg) {
@@ -78,7 +51,7 @@ static int ili9341_init(struct qpic_panel_io_desc *panel_io)
	return 0;
}

void ili9341_off(struct qpic_panel_io_desc *qpic_panel_io)
static void panel_io_off(struct qpic_panel_io_desc *qpic_panel_io)
{
	if (qpic_panel_io->ad8_gpio)
		gpio_free(qpic_panel_io->ad8_gpio);
@@ -96,7 +69,12 @@ void ili9341_off(struct qpic_panel_io_desc *qpic_panel_io)
		regulator_disable(qpic_panel_io->avdd_vreg);
}

static int ili9341_panel_power_on(struct qpic_panel_io_desc *qpic_panel_io)
void ili9341_off(struct qpic_panel_io_desc *qpic_panel_io)
{
	panel_io_off(qpic_panel_io);
}

static int panel_io_on(struct qpic_panel_io_desc *qpic_panel_io)
{
	int rc;
	if (qpic_panel_io->vdd_vreg) {
@@ -148,66 +126,68 @@ static int ili9341_panel_power_on(struct qpic_panel_io_desc *qpic_panel_io)
	msleep(20);
	return 0;
power_on_error:
	ili9341_off(qpic_panel_io);
	panel_io_off(qpic_panel_io);
	return -EINVAL;
}

int ili9341_on(struct qpic_panel_io_desc *qpic_panel_io)
{
	u32 param[20];
	u8 param[4];
	int ret;
	if (!qpic_panel_io->init) {
		ili9341_init(qpic_panel_io);
		panel_io_init(qpic_panel_io);
		qpic_panel_io->init = true;
	}
	ret = ili9341_panel_power_on(qpic_panel_io);
	ret = panel_io_on(qpic_panel_io);
	if (ret)
		return ret;
	qpic_panel_set_cmd_only(OP_SOFT_RESET);
	qpic_send_pkt(OP_SOFT_RESET, NULL, 0);
	/* wait for 120 ms after reset as panel spec suggests */
	msleep(120);
	qpic_panel_set_cmd_only(OP_SET_DISPLAY_OFF);
	qpic_send_pkt(OP_SET_DISPLAY_OFF, NULL, 0);
	/* wait for 20 ms after disply off */
	msleep(20);

	/* set memory access control */
	param[0] = ((0x48)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
	qpic_send_panel_cmd(OP_ILI9341_MEMORY_ACCESS_CONTROL, param, 0);
	param[0] = 0x48;
	qpic_send_pkt(OP_SET_ADDRESS_MODE, param, 1);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);

	/* set COLMOD: Pixel Format Set */
	param[0] = ((0x66)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
	qpic_send_panel_cmd(OP_ILI9341_COLMOD_PIXEL_FORMAT_SET, param, 0);
	param[0] = 0x66;
	qpic_send_pkt(OP_SET_PIXEL_FORMAT, param, 1);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);

	/* set interface */
	param[0] = ((0x01)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
	qpic_send_panel_cmd(OP_ILI9341_INTERFACE_CONTROL, &param[0], 0);
	param[0] = 1;
	param[1] = 0;
	param[2] = 0;
	qpic_send_pkt(OP_ILI9341_INTERFACE_CONTROL, param, 3);
	/* wait for 20 ms after command sent */
	msleep(20);

	/* exit sleep mode */
	qpic_panel_set_cmd_only(OP_EXIT_SLEEP_MODE);
	qpic_send_pkt(OP_EXIT_SLEEP_MODE, NULL, 0);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);

	/* normal mode */
	qpic_panel_set_cmd_only(OP_ENTER_NORMAL_MODE);
	qpic_send_pkt(OP_ENTER_NORMAL_MODE, NULL, 0);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);

	/* display on */
	qpic_panel_set_cmd_only(OP_SET_DISPLAY_ON);
	qpic_send_pkt(OP_SET_DISPLAY_ON, NULL, 0);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);

	/* tearing effect  */
	param[0] = ((0x00)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
	qpic_send_panel_cmd(OP_ILI9341_TEARING_EFFECT_LINE_ON, param, 0);
	/* wait for 20 ms after command sent as panel spec suggests */
	msleep(20);
	param[0] = 0;
	qpic_send_pkt(OP_ILI9341_TEARING_EFFECT_LINE_ON, param, 1);

	/* test */
	param[0] = qpic_read_data(OP_GET_PIXEL_FORMAT, 1);
	pr_debug("Pixel format =%x", param[0]);

	return 0;
}