Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 1 | /* Copyright (c) 2014, The Linux Foundation. All rights reserved. |
| 2 | * |
| 3 | * Redistribution and use in source and binary forms, with or without |
| 4 | * modification, are permitted provided that the following conditions |
| 5 | * are met: |
| 6 | * * Redistributions of source code must retain the above copyright |
| 7 | * notice, this list of conditions and the following disclaimer. |
| 8 | * * Redistributions in binary form must reproduce the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer in |
| 10 | * the documentation and/or other materials provided with the |
| 11 | * distribution. |
| 12 | * * Neither the name of The Linux Foundation nor the names of its |
| 13 | * contributors may be used to endorse or promote products derived |
| 14 | * from this software without specific prior written permission. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | #include <debug.h> |
| 31 | #include <err.h> |
| 32 | #include <msm_panel.h> |
| 33 | #include <platform/iomap.h> |
Sridhar Parasuram | c9abcdd | 2014-12-29 13:43:28 -0800 | [diff] [blame] | 34 | #include <platform/timer.h> |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 35 | #include <reg.h> |
Sridhar Parasuram | c9abcdd | 2014-12-29 13:43:28 -0800 | [diff] [blame] | 36 | #include <target.h> |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 37 | |
| 38 | #include "qpic.h" |
| 39 | #include "qpic_panel.h" |
| 40 | |
| 41 | int mdss_qpic_panel_init(struct qpic_panel_io_desc *panel_io); |
| 42 | |
| 43 | struct qpic_data_type qpic_data; |
| 44 | struct qpic_data_type *qpic_res = &qpic_data; |
| 45 | static int qpic_send_pkt_sw(uint32_t cmd, uint32_t len, uint8_t *param); |
| 46 | |
| 47 | /* for debugging */ |
| 48 | static uint32_t use_bam = false; |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 49 | static uint32_t use_vsync; |
| 50 | |
| 51 | /* For compilation */ |
| 52 | void mdp_set_revision(int rev) |
| 53 | { |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | int qpic_on(void) |
| 58 | { |
| 59 | int ret; |
| 60 | ret = mdss_qpic_panel_on(&qpic_res->panel_io); |
| 61 | return ret; |
| 62 | } |
| 63 | |
| 64 | int qpic_off(void) |
| 65 | { |
| 66 | int ret = NO_ERROR; |
| 67 | |
| 68 | if (!target_cont_splash_screen()) { |
| 69 | ret = mdss_qpic_panel_off(&qpic_res->panel_io); |
| 70 | } |
| 71 | |
| 72 | return ret; |
| 73 | } |
| 74 | |
| 75 | void qpic_update() |
| 76 | { |
| 77 | uint32_t fb_offset, size; |
| 78 | |
| 79 | if (use_bam) |
Sridhar Parasuram | c9abcdd | 2014-12-29 13:43:28 -0800 | [diff] [blame] | 80 | fb_offset = qpic_res->fb_phys + (uint32_t) qpic_res->base; |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 81 | else |
Sridhar Parasuram | c9abcdd | 2014-12-29 13:43:28 -0800 | [diff] [blame] | 82 | fb_offset = (uint32_t) qpic_res->fb_virt + (uint32_t) qpic_res->base; |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 83 | |
| 84 | size = qpic_res->fb_xres * qpic_res->fb_yres * qpic_res->fb_bpp; |
| 85 | |
| 86 | qpic_send_frame(0, 0, qpic_res->fb_xres - 1, qpic_res->fb_yres - 1, |
| 87 | (uint32_t *)fb_offset, size); |
| 88 | } |
| 89 | |
| 90 | int mdss_qpic_alloc_fb_mem(struct msm_panel_info *pinfo, int base) |
| 91 | { |
| 92 | qpic_res->fb_virt = 0; |
| 93 | qpic_res->fb_phys = 0; |
| 94 | qpic_res->fb_xres = pinfo->xres; |
| 95 | qpic_res->fb_yres = pinfo->yres; |
| 96 | qpic_res->fb_bpp = pinfo->bpp / 8; |
| 97 | qpic_res->base = base; |
| 98 | |
| 99 | return 0; |
| 100 | } |
| 101 | |
| 102 | void qpic_init(struct msm_panel_info *pinfo, int base) |
| 103 | { |
| 104 | if (qpic_res->res_init) |
| 105 | return; |
| 106 | |
| 107 | qpic_res->qpic_base = QPIC_BASE; |
| 108 | mdss_qpic_panel_init(&qpic_res->panel_io); |
| 109 | mdss_qpic_alloc_fb_mem(pinfo, base); |
| 110 | qpic_res->res_init = true; |
| 111 | } |
| 112 | |
| 113 | int qpic_init_sps(void) |
| 114 | { |
| 115 | return 0; |
| 116 | } |
| 117 | |
| 118 | void mdss_qpic_reset(void) |
| 119 | { |
| 120 | uint32_t cnt = 0; |
| 121 | |
| 122 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_RESET, 1 << 0); |
| 123 | /* wait 100 us after reset as suggested by hw */ |
| 124 | udelay(100); |
| 125 | while (((QPIC_INP(QPIC_REG_QPIC_LCDC_STTS) & (1 << 8)) == 0)) { |
| 126 | if (cnt > QPIC_MAX_WAIT_CNT) { |
| 127 | dprintf(CRITICAL, "%s reset not finished\n", __func__); |
| 128 | break; |
| 129 | } |
| 130 | /* yield 100 us for next polling by experiment*/ |
| 131 | udelay(100); |
| 132 | cnt++; |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | static int qpic_send_pkt_bam(uint32_t cmd, uint32_t len, uint8_t *param) |
| 137 | { |
| 138 | return qpic_send_pkt_sw(cmd, len, param); |
| 139 | } |
| 140 | |
| 141 | static void qpic_dump_reg(void) |
| 142 | { |
| 143 | dprintf(INFO, "%s\n", __func__); |
| 144 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_CTRL = %x\n", |
| 145 | QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL)); |
| 146 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT = %x\n", |
| 147 | QPIC_INP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT)); |
| 148 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_CFG0 = %x\n", |
| 149 | QPIC_INP(QPIC_REG_QPIC_LCDC_CFG0)); |
| 150 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_CFG1 = %x\n", |
| 151 | QPIC_INP(QPIC_REG_QPIC_LCDC_CFG1)); |
| 152 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_CFG2 = %x\n", |
| 153 | QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2)); |
| 154 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_IRQ_EN = %x\n", |
| 155 | QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_EN)); |
| 156 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_IRQ_STTS = %x\n", |
| 157 | QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS)); |
| 158 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_STTS = %x\n", |
| 159 | QPIC_INP(QPIC_REG_QPIC_LCDC_STTS)); |
| 160 | dprintf(INFO, "QPIC_REG_QPIC_LCDC_FIFO_SOF = %x\n", |
| 161 | QPIC_INP(QPIC_REG_QPIC_LCDC_FIFO_SOF)); |
| 162 | } |
| 163 | |
| 164 | static int qpic_wait_for_fifo(void) |
| 165 | { |
| 166 | uint32_t data, cnt = 0; |
| 167 | int ret = 0; |
| 168 | |
| 169 | while (1) { |
| 170 | data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS); |
| 171 | data &= 0x3F; |
| 172 | if (data == 0) |
| 173 | break; |
| 174 | /* yield 10 us for next polling by experiment*/ |
| 175 | udelay(10); |
| 176 | if (cnt > (QPIC_MAX_WAIT_CNT * 10)) { |
| 177 | dprintf(CRITICAL, "%s time out\n", __func__); |
| 178 | ret = -1; |
| 179 | break; |
| 180 | } |
| 181 | cnt++; |
| 182 | } |
| 183 | return ret; |
| 184 | } |
| 185 | |
| 186 | static int qpic_wait_for_eof(void) |
| 187 | { |
| 188 | uint32_t data, cnt = 0; |
| 189 | int ret = 0; |
| 190 | |
| 191 | while (1) { |
| 192 | data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS); |
| 193 | if (data & (1 << 2)) |
| 194 | break; |
| 195 | /* yield 10 us for next polling by experiment*/ |
| 196 | udelay(10); |
| 197 | if (cnt > (QPIC_MAX_WAIT_CNT * 10)) { |
| 198 | dprintf(CRITICAL, "%s wait for eof time out\n", __func__); |
| 199 | qpic_dump_reg(); |
| 200 | ret = -1; |
| 201 | break; |
| 202 | } |
| 203 | cnt++; |
| 204 | } |
| 205 | return ret; |
| 206 | } |
| 207 | |
| 208 | static int qpic_send_pkt_sw(uint32_t cmd, uint32_t len, uint8_t *param) |
| 209 | { |
| 210 | uint32_t bytes_left, space, data, cfg2; |
Sridhar Parasuram | c9abcdd | 2014-12-29 13:43:28 -0800 | [diff] [blame] | 211 | int ret = 0; |
| 212 | uint32_t i; |
Zohaib Alam | b7b677f | 2014-10-24 15:54:42 -0400 | [diff] [blame] | 213 | |
| 214 | if (len && !param) { |
| 215 | dprintf(CRITICAL, "Null Pointer!\n"); |
| 216 | return 0; |
| 217 | } |
| 218 | if (len <= 4) { |
| 219 | len = (len + 3) / 4; /* len in dwords */ |
| 220 | data = 0; |
| 221 | for (i = 0; i < len; i++) |
| 222 | data |= (uint32_t)param[i] << (8 * i); |
| 223 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, len); |
| 224 | QPIC_OUTP(QPIC_REG_LCD_DEVICE_CMD0 + (4 * cmd), data); |
| 225 | return 0; |
| 226 | } |
| 227 | |
| 228 | if ((len & 0x1) != 0) { |
| 229 | dprintf(INFO, "%s: number of bytes needs be even\n", __func__); |
| 230 | len = (len + 1) & (~0x1); |
| 231 | } |
| 232 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff); |
| 233 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, 0); |
| 234 | cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2); |
| 235 | if ((cmd != OP_WRITE_MEMORY_START) && |
| 236 | (cmd != OP_WRITE_MEMORY_CONTINUE)) |
| 237 | cfg2 |= (1 << 24); /* transparent mode */ |
| 238 | else |
| 239 | cfg2 &= ~(1 << 24); |
| 240 | |
| 241 | cfg2 &= ~0xFF; |
| 242 | cfg2 |= cmd; |
| 243 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2); |
| 244 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_SOF, 0x0); |
| 245 | bytes_left = len; |
| 246 | |
| 247 | while (bytes_left > 0) { |
| 248 | ret = qpic_wait_for_fifo(); |
| 249 | if (ret) |
| 250 | goto exit_send_cmd_sw; |
| 251 | |
| 252 | space = 16; |
| 253 | |
| 254 | while ((space > 0) && (bytes_left > 0)) { |
| 255 | /* write to fifo */ |
| 256 | if (bytes_left >= 4) { |
| 257 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0, |
| 258 | *(uint32_t *)param); |
| 259 | param += 4; |
| 260 | bytes_left -= 4; |
| 261 | space--; |
| 262 | } else if (bytes_left == 2) { |
| 263 | QPIC_OUTPW(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0, |
| 264 | *(uint16_t *)param); |
| 265 | bytes_left -= 2; |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | /* finished */ |
| 270 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_EOF, 0x0); |
| 271 | ret = qpic_wait_for_eof(); |
| 272 | exit_send_cmd_sw: |
| 273 | cfg2 &= ~(1 << 24); |
| 274 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2); |
| 275 | return ret; |
| 276 | } |
| 277 | |
| 278 | int qpic_send_pkt(uint32_t cmd, uint8_t *param, uint32_t len) |
| 279 | { |
| 280 | if (!use_bam || ((cmd != OP_WRITE_MEMORY_CONTINUE) && |
| 281 | (cmd != OP_WRITE_MEMORY_START))) |
| 282 | return qpic_send_pkt_sw(cmd, len, param); |
| 283 | else |
| 284 | return qpic_send_pkt_bam(cmd, len, param); |
| 285 | } |
| 286 | |
| 287 | int mdss_qpic_init(void) |
| 288 | { |
| 289 | int ret = 0; |
| 290 | uint32_t data; |
| 291 | mdss_qpic_reset(); |
| 292 | |
| 293 | data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL); |
| 294 | /* clear vsync wait , bam mode = 0 */ |
| 295 | data &= ~(3 << 0); |
| 296 | data &= ~(0x1f << 3); |
| 297 | data |= (1 << 3); /* threshold */ |
| 298 | data |= (1 << 8); /* lcd_en */ |
| 299 | data &= ~(0x1f << 9); |
| 300 | data |= (1 << 9); /* threshold */ |
| 301 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data); |
| 302 | |
| 303 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG0, 0x02108501); |
| 304 | data = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2); |
| 305 | data &= ~(0xFFF); |
| 306 | data |= 0x0; /* 565 */ |
| 307 | data |= 0x2C; |
| 308 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, data); |
| 309 | |
| 310 | /* TE enable */ |
| 311 | if (use_vsync) { |
| 312 | data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL); |
| 313 | data |= (1 << 0); |
| 314 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data); |
| 315 | } |
| 316 | |
| 317 | return ret; |
| 318 | } |
| 319 | |
| 320 | uint32_t qpic_read_data(uint32_t cmd_index, uint32_t size) |
| 321 | { |
| 322 | uint32_t data = 0; |
| 323 | if (size <= 4) { |
| 324 | QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, size); |
| 325 | data = QPIC_INP(QPIC_REG_LCD_DEVICE_CMD0 + (cmd_index * 4)); |
| 326 | } |
| 327 | return data; |
| 328 | } |
| 329 | |