ref: 7ff0da30e392aaf9e395ee43b252c47e1a947788
parent: 2370a41cd25286a586e27de2adf5c810c7d7bca3
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Mon Sep 5 13:25:23 EDT 2022
imx8/lcd: rework screen blanking The previously reverted change has been reworked - things get shut down in the right order, with clocks gated. A lock is no longer needed either. The combined effect is ~25mA saved when screen is off, compared to no changes.
--- a/sys/src/9/imx8/lcd.c
+++ b/sys/src/9/imx8/lcd.c
@@ -356,6 +356,12 @@
static u32int *lcdif = (u32int*)(VIRTIO + 0x320000);
+static I2Cdev *bridge;
+
+static struct {
+ int blank;
+}lcdifirq;
+
/* shift and mask */
static u32int
sm(u32int v, u32int m)
@@ -464,7 +470,8 @@
/* enable underflow recovery to fix image shift */
wr(lcdif, LCDIF_CTRL1,
sm(7, CTRL1_BYTE_PACKING_FORMAT) |
- CTRL1_RECOVER_ON_UNDERFLOW);
+ CTRL1_RECOVER_ON_UNDERFLOW |
+ CTRL1_CUR_FRAME_DONE_IRQ_EN);
wr(lcdif, LCDIF_CTRL,
CTRL_BYPASS_COUNT |
@@ -508,13 +515,13 @@
}
static void
-bridgeinit(I2Cdev *dev, struct video_mode *mode, struct dsi_cfg *cfg)
+bridgeinit(struct video_mode *mode, struct dsi_cfg *cfg)
{
int n;
// soft reset
- i2cwritebyte(dev, 0x09, 1);
- while(i2creadbyte(dev, 0x09) & 1)
+ i2cwritebyte(bridge, 0x09, 1);
+ while(i2creadbyte(bridge, 0x09) & 1)
;
// clock derived from dsi clock
@@ -526,56 +533,56 @@
case 486: n = 3 << 1; break;
case 461: n = 4 << 1; break;
}
- i2cwritebyte(dev, 0x0a, n);
+ i2cwritebyte(bridge, 0x0a, n);
// single channel A
n = 1<<5 | (cfg->lanes-4)<<3 | 3<<1;
- i2cwritebyte(dev, 0x10, n);
+ i2cwritebyte(bridge, 0x10, n);
// Enhanced framing and ASSR
- i2cwritebyte(dev, 0x5a, 0x05);
+ i2cwritebyte(bridge, 0x5a, 0x05);
// 2 DP lanes w/o SSC
- i2cwritebyte(dev, 0x93, 0x20);
+ i2cwritebyte(bridge, 0x93, 0x20);
// 2.7Gbps DP data rate
- i2cwritebyte(dev, 0x94, 0x80);
+ i2cwritebyte(bridge, 0x94, 0x80);
// Enable PLL and confirm PLL is locked
- i2cwritebyte(dev, 0x0d, 0x01);
+ i2cwritebyte(bridge, 0x0d, 0x01);
// wait for PLL to lock
- while((i2creadbyte(dev, 0x0a) & 0x80) == 0)
+ while((i2creadbyte(bridge, 0x0a) & 0x80) == 0)
;
// Enable ASSR on display
- i2cwritebyte(dev, 0x64, 0x01);
- i2cwritebyte(dev, 0x75, 0x01);
- i2cwritebyte(dev, 0x76, 0x0a);
- i2cwritebyte(dev, 0x77, 0x01);
- i2cwritebyte(dev, 0x78, 0x81);
+ i2cwritebyte(bridge, 0x64, 0x01);
+ i2cwritebyte(bridge, 0x75, 0x01);
+ i2cwritebyte(bridge, 0x76, 0x0a);
+ i2cwritebyte(bridge, 0x77, 0x01);
+ i2cwritebyte(bridge, 0x78, 0x81);
// Train link and confirm trained
- i2cwritebyte(dev, 0x96, 0x0a);
- while(i2creadbyte(dev, 0x96) != 1)
+ i2cwritebyte(bridge, 0x96, 0x0a);
+ while(i2creadbyte(bridge, 0x96) != 1)
;
// video timings
- i2cwritebyte(dev, 0x20, mode->hactive & 0xFF);
- i2cwritebyte(dev, 0x21, mode->hactive >> 8);
- i2cwritebyte(dev, 0x24, mode->vactive & 0xFF);
- i2cwritebyte(dev, 0x25, mode->vactive >> 8);
- i2cwritebyte(dev, 0x2c, mode->hspw);
- i2cwritebyte(dev, 0x2d, mode->hspw>>8 | (mode->hsync_pol=='-')<<7);
- i2cwritebyte(dev, 0x30, mode->vspw);
- i2cwritebyte(dev, 0x31, mode->vspw>>8 | (mode->vsync_pol=='-')<<7);
- i2cwritebyte(dev, 0x34, mode->hblank - mode->hspw - mode->hso);
- i2cwritebyte(dev, 0x36, mode->vblank - mode->vspw - mode->vso);
- i2cwritebyte(dev, 0x38, mode->hso);
- i2cwritebyte(dev, 0x3a, mode->vso);
+ i2cwritebyte(bridge, 0x20, mode->hactive & 0xFF);
+ i2cwritebyte(bridge, 0x21, mode->hactive >> 8);
+ i2cwritebyte(bridge, 0x24, mode->vactive & 0xFF);
+ i2cwritebyte(bridge, 0x25, mode->vactive >> 8);
+ i2cwritebyte(bridge, 0x2c, mode->hspw);
+ i2cwritebyte(bridge, 0x2d, mode->hspw>>8 | (mode->hsync_pol=='-')<<7);
+ i2cwritebyte(bridge, 0x30, mode->vspw);
+ i2cwritebyte(bridge, 0x31, mode->vspw>>8 | (mode->vsync_pol=='-')<<7);
+ i2cwritebyte(bridge, 0x34, mode->hblank - mode->hspw - mode->hso);
+ i2cwritebyte(bridge, 0x36, mode->vblank - mode->vspw - mode->vso);
+ i2cwritebyte(bridge, 0x38, mode->hso);
+ i2cwritebyte(bridge, 0x3a, mode->vso);
// Enable video stream, ASSR, enhanced framing
- i2cwritebyte(dev, 0x5a, 0x0d);
+ i2cwritebyte(bridge, 0x5a, 0x0d);
}
static char*
@@ -629,18 +636,18 @@
}
static char*
-getmode(I2Cdev *dev, struct video_mode *mode)
+getmode(struct video_mode *mode)
{
static uchar edid[128];
static I2Cdev aux;
- aux.bus = dev->bus;
+ aux.bus = bridge->bus;
aux.addr = 0x50;
aux.subaddr = 1;
aux.size = sizeof(edid);
/* enable passthru mode for address 0x50 (EDID) */
- i2cwritebyte(dev, 0x60, aux.addr<<1 | 1);
+ i2cwritebyte(bridge, 0x60, aux.addr<<1 | 1);
addi2cdev(&aux);
if(i2crecv(&aux, edid, sizeof(edid), 0) != sizeof(edid))
@@ -828,15 +835,41 @@
gpioout(GPIO_PIN(1, 10), 1);
}
+static void
+blankirq(Ureg *, void *)
+{
+ wr(lcdif, LCDIF_CTRL1_CLR, CTRL1_CUR_FRAME_DONE_IRQ);
+
+ if(lcdifirq.blank != 0){
+ lcdifirq.blank = 0;
+ wr(lcdif, LCDIF_CTRL_CLR, CTRL_DOTCLK_MODE);
+ }
+}
+
void
blankscreen(int blank)
{
+ if(blank == 0){
+ setclkgate("disp.axi_clk", 1);
+ setclkgate("sim_display.mainclk", 1);
+ wr(lcdif, LCDIF_CTRL_SET, CTRL_DOTCLK_MODE);
+ wr(lcdif, LCDIF_CTRL_SET, CTRL_RUN);
+ }
+
/* panel backlight */
gpioout(GPIO_PIN(1, 10), blank == 0);
/* PWM2 */
mr(pwm2, PWMCR, (blank == 0)*CR_EN, CR_EN);
/* bridge output */
- i2cwritebyte(i2cdev(i2cbus("i2c4"), 0x2c), 0x5a, blank == 0 ? 0x0d : 0x05);
+ i2cwritebyte(bridge, 0x5a, blank == 0 ? 0x0d : 0x05);
+
+ if(blank){
+ lcdifirq.blank = 1;
+ while(rr(lcdif, LCDIF_CTRL) & CTRL_RUN)
+ ;
+ setclkgate("sim_display.mainclk", 0);
+ setclkgate("disp.axi_clk", 0);
+ }
}
static void
@@ -857,9 +890,10 @@
{
struct dsi_cfg dsi_cfg;
struct video_mode mode;
- I2Cdev *bridge;
char *err;
+ intrenable(IRQlcdif, blankirq, nil, BUSUNKNOWN, "lcdif");
+
/* GPR13[MIPI_MUX_SEL]: 0 = LCDIF, 1 = DCSS */
iomuxgpr(13, 0, 1<<2);
@@ -922,7 +956,7 @@
* get mode information from EDID, this can only be done after the clocks
* are generated by the DPHY and the clock resets have been released.
*/
- err = getmode(bridge, &mode);
+ err = getmode(&mode);
if(err != nil)
goto out;
@@ -943,7 +977,7 @@
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_DPI_RESET_N, RCR_MIPI_DSI_DPI_RESET_N);
/* enable display port bridge */
- bridgeinit(bridge, &mode, &dsi_cfg);
+ bridgeinit(&mode, &dsi_cfg);
/* send the pixels */
lcdifinit(&mode);