|
66 | 66 | #include <asm/arch-suniv/common.h> |
67 | 67 |
|
68 | 68 | //#define DEBUG |
| 69 | +#define TIMEOUT_NS 1000000 |
69 | 70 | #define PALETTE_SIZE 256 |
70 | 71 | #define DRIVER_NAME "ST7789S-fb" |
71 | 72 | #define MIYOO_FB0_PUT_OSD _IOWR(0x100, 0, unsigned long) |
@@ -131,9 +132,8 @@ struct timer_list mytimer; |
131 | 132 | static struct suniv_iomm iomm={0}; |
132 | 133 | static struct myfb_par *mypar=NULL; |
133 | 134 | static struct fb_var_screeninfo myfb_var={0}; |
134 | | -static uint16_t lastScanLine = 120; |
135 | | -static uint16_t firstScanLine = 5; |
136 | | -uint16_t x, i, scanline, vsync; |
| 135 | +ktime_t start; |
| 136 | +uint16_t x, i, scanline, vsync, bporch=9, fporch=10; |
137 | 137 | uint32_t mycpu_clock; |
138 | 138 | uint32_t video_clock; |
139 | 139 |
|
@@ -288,49 +288,60 @@ static irqreturn_t gpio_irq_handler(int irq, void *arg) |
288 | 288 | return IRQ_HANDLED; |
289 | 289 | } |
290 | 290 |
|
| 291 | +uint16_t st7789_get_scanline(void) { |
| 292 | + uint8_t buf[3] = {0}; |
| 293 | + lcdc_wr_cmd(0x45); |
| 294 | + buf[0] = lcdc_rd_dat(); |
| 295 | + buf[1] = lcdc_rd_dat(); |
| 296 | + buf[2] = lcdc_rd_dat(); |
| 297 | + //printk("ST7789 scanline bytes: %u\n", ((uint16_t)buf[2] << 8) | buf[0]); |
| 298 | + |
| 299 | + return ((uint16_t)buf[2] << 8) | buf[0]; |
| 300 | +} |
| 301 | + |
291 | 302 | static irqreturn_t lcdc_irq_handler(int irq, void *arg) |
292 | 303 | { |
293 | 304 | if (tefix != 0) { |
294 | | - suniv_clrbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
295 | | - lcdc_wr_cmd(0x45); |
296 | | - lcdc_rd_dat(); |
297 | | - lcdc_rd_dat(); |
298 | | - mycpu_clock = readl(iomm.ccm + PLL_CPU_CTRL_REG); |
299 | | - switch (mycpu_clock) { |
300 | | - case 0x90001110: case 0x90001210: case 0x90000C20: case 0x90001310: case 0x90001410: //==[864, 912, 936, 960, 1008]MHz |
301 | | - lastScanLine = 280; |
| 305 | + suniv_clrbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
| 306 | + lcdc_wr_cmd(0x45); |
| 307 | + lcdc_rd_dat(); |
| 308 | + lcdc_rd_dat(); |
| 309 | + start = ktime_get(); |
| 310 | + while (true) { |
| 311 | + |
| 312 | + // Read the current scanline from the panel |
| 313 | + scanline = st7789_get_scanline(); |
| 314 | + |
| 315 | + // Ignore scanline 0 and 1 - vblank |
| 316 | + if (scanline == 0 || scanline == 1) |
| 317 | + continue; |
| 318 | + |
| 319 | + // Exit the loop if scanline is outside of visible area to avoid tearing |
| 320 | + // flow: |
| 321 | + // vblank - 1 frame |
| 322 | + // bporch - configured by 0xb2 |
| 323 | + // visible area - 240 frames |
| 324 | + // fporch - configured by 0xb2 |
| 325 | + if (scanline <= bporch + 1 || scanline >= 240 + bporch + 1) |
302 | 326 | break; |
303 | | - case 0x90000A20: case 0x90001010: //==[792, 816]MHz |
304 | | - lastScanLine = 240; |
305 | | - break; |
306 | | - case 0x90001E00: case 0x90001F00: //==[744, 768]MHz |
307 | | - lastScanLine = 200; |
308 | | - break; |
309 | | - case 0x90001C00: case 0x90001D00: //==[696, 720]MHz |
310 | | - lastScanLine = 164; |
311 | | - break; |
312 | | - default: // < 696Mhz |
313 | | - lastScanLine = 120; |
314 | | - } |
315 | | - for (i = firstScanLine; i <= lastScanLine; i++) { |
316 | | - lcdc_wr_cmd(0x45); |
317 | | - lcdc_rd_dat(); |
318 | | - lcdc_rd_dat(); |
319 | | - vsync = lcdc_rd_dat(); |
320 | | - if (vsync > 0) { |
321 | | - refresh_lcd(arg); |
322 | | - suniv_setbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
323 | | - suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
324 | | - return IRQ_HANDLED; |
325 | | - } |
326 | | - } |
327 | | - suniv_setbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
328 | | - suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
329 | | - return IRQ_HANDLED; |
| 327 | + |
| 328 | + // If timeout expires, re-enable CPU interface and clear interrupt bit |
| 329 | + if (ktime_to_ns(ktime_sub(ktime_get(), start)) > TIMEOUT_NS) { |
| 330 | + suniv_setbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
| 331 | + suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
| 332 | + return IRQ_HANDLED; |
| 333 | + } |
| 334 | + // Relax CPU to reduce busy-wait load |
| 335 | + cpu_relax(); |
| 336 | + } |
| 337 | + refresh_lcd(arg); |
| 338 | + suniv_setbits(iomm.lcdc + TCON0_CPU_IF_REG, (1 << 28)); |
| 339 | + suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
| 340 | + return IRQ_HANDLED; |
330 | 341 | } |
331 | | - refresh_lcd(arg); |
332 | | - suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
333 | | - return IRQ_HANDLED; |
| 342 | + refresh_lcd(arg); |
| 343 | + suniv_clrbits(iomm.lcdc + TCON_INT_REG0, (1 << 15)); |
| 344 | + return IRQ_HANDLED; |
334 | 345 | } |
335 | 346 |
|
336 | 347 | static void init_lcd(void) |
@@ -367,22 +378,11 @@ static void init_lcd(void) |
367 | 378 |
|
368 | 379 | // ST7789S Frame rate setting |
369 | 380 | lcdc_wr_cmd(0xb2); |
370 | | - if (tefix == 3) { |
371 | | - lcdc_wr_dat(8); // bp 0x0a |
372 | | - lcdc_wr_dat(122); // fp 0x0b |
373 | | - } else if (tefix == 2) { |
374 | | - lcdc_wr_dat(8); // bp 0x0a |
375 | | - lcdc_wr_dat(120); // fp 0x0b |
376 | | - } else if (tefix == 1) { |
377 | | - lcdc_wr_dat(90); // bp 0x0a |
378 | | - lcdc_wr_dat(20); // fp 0x0b |
379 | | - } else { |
380 | | - lcdc_wr_dat(9); // bp 0x0a |
381 | | - lcdc_wr_dat(10); // fp 0x0b |
382 | | - } |
383 | | - lcdc_wr_dat(0x00); |
384 | | - lcdc_wr_dat(0x33); |
385 | | - lcdc_wr_dat(0x33); |
| 381 | + lcdc_wr_dat(bporch); // bp 0x0a |
| 382 | + lcdc_wr_dat(fporch); // fp 0x0b |
| 383 | + lcdc_wr_dat(0x00); |
| 384 | + lcdc_wr_dat(0x33); |
| 385 | + lcdc_wr_dat(0x33); |
386 | 386 |
|
387 | 387 | // // Gate Control |
388 | 388 | // lcdc_wr_cmd(0xb7); |
@@ -418,9 +418,9 @@ static void init_lcd(void) |
418 | 418 |
|
419 | 419 | lcdc_wr_cmd(0xc6); |
420 | 420 | if (tefix == 3) |
421 | | - lcdc_wr_dat(0x03); // 0x04, 0x1f |
| 421 | + lcdc_wr_dat(0x04); // 0x04, 0x1f |
422 | 422 | else if (tefix == 2) |
423 | | - lcdc_wr_dat(0x04); |
| 423 | + lcdc_wr_dat(0x05); |
424 | 424 | else if (tefix == 1) |
425 | 425 | lcdc_wr_dat(0x03); |
426 | 426 | else |
@@ -496,26 +496,27 @@ static void suniv_fb_addr_init(struct myfb_par *par) |
496 | 496 |
|
497 | 497 | static void suniv_lcdc_init(unsigned long xres, unsigned long yres) |
498 | 498 | { |
499 | | - uint32_t ret=0, bp=0, total=0; |
500 | | - uint32_t h_front_porch = 8; |
501 | | - uint32_t h_back_porch = 8; |
502 | | - uint32_t h_sync_len = 1; |
503 | | - uint32_t v_front_porch = 8; |
504 | | - uint32_t v_back_porch = 8; |
505 | | - uint32_t v_sync_len = 1; |
506 | | - if (tefix == 3) { |
507 | | - v_front_porch = 10; |
508 | | - v_back_porch = 110; |
509 | | - } else if (tefix == 2) { |
510 | | - v_front_porch = 10; |
511 | | - v_back_porch = 110; |
512 | | - } else if (tefix == 1) { |
513 | | - h_front_porch = 45; |
514 | | - h_back_porch = 45; |
515 | | - v_front_porch = 4; |
516 | | - v_back_porch = 16; |
517 | | - v_sync_len = 3; |
518 | | - h_sync_len = 3; |
| 499 | + uint32_t ret = 0, bp = 0, total = 0; |
| 500 | + uint32_t h_front_porch = 7; |
| 501 | + uint32_t h_back_porch = 7; |
| 502 | + uint32_t h_sync_len = 1; |
| 503 | + uint32_t v_front_porch = 8; |
| 504 | + uint32_t v_back_porch = 8; |
| 505 | + uint32_t v_sync_len = 1; |
| 506 | + if (tefix == 3 || tefix == 2) { |
| 507 | + bporch = 90; |
| 508 | + fporch = 50; |
| 509 | + v_front_porch = fporch - 1; |
| 510 | + v_back_porch = bporch - 1; |
| 511 | + } else if (tefix == 1) { |
| 512 | + bporch = 90; |
| 513 | + fporch = 20; |
| 514 | + h_front_porch = 45; |
| 515 | + h_back_porch = 45; |
| 516 | + v_front_porch = 4; |
| 517 | + v_back_porch = 16; |
| 518 | + v_sync_len = 3; |
| 519 | + h_sync_len = 3; |
519 | 520 | } |
520 | 521 |
|
521 | 522 | writel(0, iomm.lcdc + TCON_CTRL_REG); |
@@ -603,10 +604,42 @@ static void suniv_enable_irq(struct myfb_par *par) |
603 | 604 | static void suniv_cpu_init(struct myfb_par *par) |
604 | 605 | { |
605 | 606 | uint32_t ret, i; |
606 | | - if (tefix == 3 || tefix == 2) { |
607 | | - writel(0x91001303, iomm.ccm + PLL_VIDEO_CTRL_REG); |
608 | | - } else { |
609 | | - writel(0x91001107, iomm.ccm + PLL_VIDEO_CTRL_REG); |
| 607 | + if (tefix == 3) { |
| 608 | + writel( |
| 609 | + (1 << 31) | // PLL_ENABLE = 1 |
| 610 | + (0 << 30) | // PLL_MODE = 0 (manual) |
| 611 | + (1 << 28) | // LOCK = 1 |
| 612 | + (0 << 25) | // FRAC_CLK_OUT = 0 |
| 613 | + (1 << 24) | // PLL_MODE_SEL = 1 (Integer mode) |
| 614 | + (0 << 20) | // PLL_SDM_EN = 0 |
| 615 | + (18 << 8) | // PLL_FACTOR_N = 18 |
| 616 | + (3 << 0), // PLL_PREDIV_M = 3 |
| 617 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 618 | + ); |
| 619 | + } else if (tefix == 2) { |
| 620 | + writel( |
| 621 | + (1 << 31) | // PLL_ENABLE = 1 |
| 622 | + (0 << 30) | // PLL_MODE = 0 (manual) |
| 623 | + (1 << 28) | // LOCK = 1 |
| 624 | + (0 << 25) | // FRAC_CLK_OUT = 0 |
| 625 | + (1 << 24) | // PLL_MODE_SEL = 1 (Integer mode) |
| 626 | + (0 << 20) | // PLL_SDM_EN = 0 |
| 627 | + (17 << 8) | // PLL_FACTOR_N = 17 |
| 628 | + (3 << 0), // PLL_PREDIV_M = 3 |
| 629 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 630 | + ); |
| 631 | + } else { |
| 632 | + writel( |
| 633 | + (1 << 31) | // Bit 31: PLL_ENABLE = 1 |
| 634 | + (0 << 30) | // Bit 30: PLL_MODE = 0 (Manual) |
| 635 | + (1 << 28) | // Bit 28: LOCK = 1 |
| 636 | + (0 << 25) | // Bit 25: FRAC_CLK_OUT = 0 (270 MHz) |
| 637 | + (1 << 24) | // Bit 24: PLL_MODE_SEL = 1 (Integer mode) |
| 638 | + (0 << 20) | // Bit 20: PLL_SDM_EN = 0 (Disabled) |
| 639 | + (17 << 8) | // Bits 14:8: PLL_FACTOR_N = 17 |
| 640 | + (7 << 0), // Bits 3:0: PLL_PREDIV_M = 7 |
| 641 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 642 | + ); |
610 | 643 | } |
611 | 644 | while ((readl(iomm.ccm + PLL_VIDEO_CTRL_REG) & (1 << 28)) == 0){} |
612 | 645 | while ((readl(iomm.ccm + PLL_PERIPH_CTRL_REG) & (1 << 28)) == 0){} |
@@ -943,14 +976,46 @@ static long myioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
943 | 976 | #if defined(DEBUG) |
944 | 977 | printk("st7789sfb: set TE fix to: %d", (int)tefix); |
945 | 978 | #endif |
946 | | - if (tefix == 3 || tefix == 2) { |
947 | | - writel(0x91001303, iomm.ccm + PLL_VIDEO_CTRL_REG); |
948 | | - } else { |
949 | | - writel(0x91001107, iomm.ccm + PLL_VIDEO_CTRL_REG); |
950 | | - } |
951 | | - while ((readl(iomm.ccm + PLL_VIDEO_CTRL_REG) & (1 << 28)) == 0){}; |
952 | | - suniv_lcdc_init(320, 240); |
953 | | - break; |
| 979 | + if (tefix == 3) { |
| 980 | + writel( |
| 981 | + (1 << 31) | // PLL_ENABLE = 1 |
| 982 | + (0 << 30) | // PLL_MODE = 0 (manual) |
| 983 | + (1 << 28) | // LOCK = 1 |
| 984 | + (0 << 25) | // FRAC_CLK_OUT = 0 |
| 985 | + (1 << 24) | // PLL_MODE_SEL = 1 (Integer mode) |
| 986 | + (0 << 20) | // PLL_SDM_EN = 0 |
| 987 | + (18 << 8) | // PLL_FACTOR_N = 18 |
| 988 | + (3 << 0), // PLL_PREDIV_M = 3 |
| 989 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 990 | + ); |
| 991 | + } else if (tefix == 2) { |
| 992 | + writel( |
| 993 | + (1 << 31) | // PLL_ENABLE = 1 |
| 994 | + (0 << 30) | // PLL_MODE = 0 (manual) |
| 995 | + (1 << 28) | // LOCK = 1 |
| 996 | + (0 << 25) | // FRAC_CLK_OUT = 0 |
| 997 | + (1 << 24) | // PLL_MODE_SEL = 1 (Integer mode) |
| 998 | + (0 << 20) | // PLL_SDM_EN = 0 |
| 999 | + (17 << 8) | // PLL_FACTOR_N = 17 |
| 1000 | + (3 << 0), // PLL_PREDIV_M = 3 |
| 1001 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 1002 | + ); |
| 1003 | + } else { |
| 1004 | + writel( |
| 1005 | + (1 << 31) | // Bit 31: PLL_ENABLE = 1 |
| 1006 | + (0 << 30) | // Bit 30: PLL_MODE = 0 (Manual) |
| 1007 | + (1 << 28) | // Bit 28: LOCK = 1 |
| 1008 | + (0 << 25) | // Bit 25: FRAC_CLK_OUT = 0 (270 MHz) |
| 1009 | + (1 << 24) | // Bit 24: PLL_MODE_SEL = 1 (Integer mode) |
| 1010 | + (0 << 20) | // Bit 20: PLL_SDM_EN = 0 (Disabled) |
| 1011 | + (17 << 8) | // Bits 14:8: PLL_FACTOR_N = 17 |
| 1012 | + (7 << 0), // Bits 3:0: PLL_PREDIV_M = 7 |
| 1013 | + iomm.ccm + PLL_VIDEO_CTRL_REG |
| 1014 | + ); |
| 1015 | + } |
| 1016 | + while ((readl(iomm.ccm + PLL_VIDEO_CTRL_REG) & (1 << 28)) == 0) {}; |
| 1017 | + suniv_lcdc_init(320, 240); |
| 1018 | + break; |
954 | 1019 | case MIYOO_FB0_GET_TEFIX: |
955 | 1020 | ret = copy_to_user((void*)arg, &tefix, sizeof(unsigned long)); |
956 | 1021 | #if defined(DEBUG) |
|
0 commit comments