Skip to content

Commit f31e12c

Browse files
authored
video: improve vsync (#94)
* video: improve vsync
1 parent dd535fd commit f31e12c

1 file changed

Lines changed: 156 additions & 91 deletions

File tree

drivers/video/fbdev/st7789sfb.c

Lines changed: 156 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include <asm/arch-suniv/common.h>
6767

6868
//#define DEBUG
69+
#define TIMEOUT_NS 1000000
6970
#define PALETTE_SIZE 256
7071
#define DRIVER_NAME "ST7789S-fb"
7172
#define MIYOO_FB0_PUT_OSD _IOWR(0x100, 0, unsigned long)
@@ -131,9 +132,8 @@ struct timer_list mytimer;
131132
static struct suniv_iomm iomm={0};
132133
static struct myfb_par *mypar=NULL;
133134
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;
137137
uint32_t mycpu_clock;
138138
uint32_t video_clock;
139139

@@ -288,49 +288,60 @@ static irqreturn_t gpio_irq_handler(int irq, void *arg)
288288
return IRQ_HANDLED;
289289
}
290290

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+
291302
static irqreturn_t lcdc_irq_handler(int irq, void *arg)
292303
{
293304
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)
302326
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;
330341
}
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;
334345
}
335346

336347
static void init_lcd(void)
@@ -367,22 +378,11 @@ static void init_lcd(void)
367378

368379
// ST7789S Frame rate setting
369380
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);
386386

387387
// // Gate Control
388388
// lcdc_wr_cmd(0xb7);
@@ -418,9 +418,9 @@ static void init_lcd(void)
418418

419419
lcdc_wr_cmd(0xc6);
420420
if (tefix == 3)
421-
lcdc_wr_dat(0x03); // 0x04, 0x1f
421+
lcdc_wr_dat(0x04); // 0x04, 0x1f
422422
else if (tefix == 2)
423-
lcdc_wr_dat(0x04);
423+
lcdc_wr_dat(0x05);
424424
else if (tefix == 1)
425425
lcdc_wr_dat(0x03);
426426
else
@@ -496,26 +496,27 @@ static void suniv_fb_addr_init(struct myfb_par *par)
496496

497497
static void suniv_lcdc_init(unsigned long xres, unsigned long yres)
498498
{
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;
519520
}
520521

521522
writel(0, iomm.lcdc + TCON_CTRL_REG);
@@ -603,10 +604,42 @@ static void suniv_enable_irq(struct myfb_par *par)
603604
static void suniv_cpu_init(struct myfb_par *par)
604605
{
605606
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+
);
610643
}
611644
while ((readl(iomm.ccm + PLL_VIDEO_CTRL_REG) & (1 << 28)) == 0){}
612645
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)
943976
#if defined(DEBUG)
944977
printk("st7789sfb: set TE fix to: %d", (int)tefix);
945978
#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;
9541019
case MIYOO_FB0_GET_TEFIX:
9551020
ret = copy_to_user((void*)arg, &tefix, sizeof(unsigned long));
9561021
#if defined(DEBUG)

0 commit comments

Comments
 (0)