Loading drivers/video/msm/mdss/mdss_qpic.c +177 −69 Original line number Diff line number Diff line Loading @@ -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",}, Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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__); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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) Loading @@ -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); Loading @@ -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; Loading @@ -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"); } Loading Loading @@ -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; } Loading drivers/video/msm/mdss/mdss_qpic.h +4 −2 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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( Loading drivers/video/msm/mdss/mdss_qpic_panel.c +29 −51 Original line number Diff line number Diff line Loading @@ -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, ¶m, 0); } /* write a frame of pixels to a MIPI screen */ u32 qpic_send_frame(u32 x_start, u32 y_start, Loading @@ -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; Loading @@ -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, ¶m, 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; Loading @@ -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, ¶m, 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; Loading Loading @@ -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; Loading drivers/video/msm/mdss/mdss_qpic_panel.h +42 −39 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading drivers/video/msm/mdss/qpic_panel_ili_qvga.c +31 −51 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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, ¶m[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; } Loading
drivers/video/msm/mdss/mdss_qpic.c +177 −69 Original line number Diff line number Diff line Loading @@ -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",}, Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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__); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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) Loading @@ -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); Loading @@ -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; Loading @@ -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"); } Loading Loading @@ -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; } Loading
drivers/video/msm/mdss/mdss_qpic.h +4 −2 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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( Loading
drivers/video/msm/mdss/mdss_qpic_panel.c +29 −51 Original line number Diff line number Diff line Loading @@ -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, ¶m, 0); } /* write a frame of pixels to a MIPI screen */ u32 qpic_send_frame(u32 x_start, u32 y_start, Loading @@ -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; Loading @@ -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, ¶m, 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; Loading @@ -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, ¶m, 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; Loading Loading @@ -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; Loading
drivers/video/msm/mdss/mdss_qpic_panel.h +42 −39 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading
drivers/video/msm/mdss/qpic_panel_ili_qvga.c +31 −51 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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, ¶m[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; }