Below is the Call Flow for PinePhone p-boot main in dtest.c, test_display.c and p-boot.zip, based on the logs...
Based on the above logs, we have implemented the PinePhone Display Driver in Zig, as described below.
(Why does PinePhone Display flicker sometimes?)
Now implemented in Zig. See pinephone-nuttx/render.zig
Original Call Flow based on p-boot main in dtest.c...
- (pmic_init not needed. Maybe already done by uboot?)
- Calls display_init (Done in Zig)
- Calls backlight_enable (Done in Zig)
- Calls test_render (Done in Zig)
Now implemented in Zig. See pinephone-nuttx/render.zig
Original Call Flow based on p-boot display_init...
- Calls tcon0_init (Done in Zig)
- Calls dsi_init (Done in Zig)
- Calls de2_init (Done in Zig)
Now implemented in Zig. See "Enable MIPI DSI Block"
Original Log captured from p-boot dsi_init...
enable_dsi_block: start
mipi dsi bus enable
setbits 0x1c20060, 0x2 (DMB)
setbits 0x1c202c0, 0x2 (DMB)
Enable the DSI block
struct reg_inst dsi_init_seq[] = {
.{ 0x1ca0000 + 0x0000, 0x00000001 }, // DMB
0x1ca0000 = 0x1 (DMB)
.{ 0x1ca0000 + 0x0010, 0x00030000 }, // DMB
0x1ca0010 = 0x30000 (DMB)
.{ 0x1ca0000 + 0x0060, 0x0000000a }, // DMB
0x1ca0060 = 0xa (DMB)
.{ 0x1ca0000 + 0x0078, 0x00000000 }, // DMB
0x1ca0078 = 0x0 (DMB)
inst_init
.{ 0x1ca0000 + 0x0020, 0x0000001f }, // DMB
0x1ca0020 = 0x1f (DMB)
.{ 0x1ca0000 + 0x0024, 0x10000001 }, // DMB
0x1ca0024 = 0x10000001 (DMB)
.{ 0x1ca0000 + 0x0028, 0x20000010 }, // DMB
0x1ca0028 = 0x20000010 (DMB)
.{ 0x1ca0000 + 0x002c, 0x2000000f }, // DMB
0x1ca002c = 0x2000000f (DMB)
.{ 0x1ca0000 + 0x0030, 0x30100001 }, // DMB
0x1ca0030 = 0x30100001 (DMB)
.{ 0x1ca0000 + 0x0034, 0x40000010 }, // DMB
0x1ca0034 = 0x40000010 (DMB)
.{ 0x1ca0000 + 0x0038, 0x0000000f }, // DMB
0x1ca0038 = 0xf (DMB)
.{ 0x1ca0000 + 0x003c, 0x5000001f }, // DMB
0x1ca003c = 0x5000001f (DMB)
.{ 0x1ca0000 + 0x004c, 0x00560001 }, // DMB
0x1ca004c = 0x560001 (DMB)
.{ 0x1ca0000 + 0x02f8, 0x000000ff }, // DMB
0x1ca02f8 = 0xff (DMB)
get_video_start_delay
.{ 0x1ca0000 + 0x0014, 0x00005bc7 }, // DMB
0x1ca0014 = 0x5bc7 (DMB)
setup_burst
.{ 0x1ca0000 + 0x007c, 0x10000007 }, // DMB
0x1ca007c = 0x10000007 (DMB)
setup_inst_loop
.{ 0x1ca0000 + 0x0040, 0x30000002 }, // DMB
0x1ca0040 = 0x30000002 (DMB)
.{ 0x1ca0000 + 0x0044, 0x00310031 }, // DMB
0x1ca0044 = 0x310031 (DMB)
.{ 0x1ca0000 + 0x0054, 0x00310031 }, // DMB
0x1ca0054 = 0x310031 (DMB)
setup_format
.{ 0x1ca0000 + 0x0090, 0x1308703e }, // DMB
0x1ca0090 = 0x1308703e (DMB)
.{ 0x1ca0000 + 0x0098, 0x0000ffff }, // DMB
0x1ca0098 = 0xffff (DMB)
.{ 0x1ca0000 + 0x009c, 0xffffffff }, // DMB
0x1ca009c = 0xffffffff (DMB)
.{ 0x1ca0000 + 0x0080, 0x00010008 }, // DMB
0x1ca0080 = 0x10008 (DMB)
setup_timings
display_malloc: size=2330
.{ 0x1ca0000 + 0x000c, 0x00000000 }, // DMB
0x1ca000c = 0x0 (DMB)
.{ 0x1ca0000 + 0x00b0, 0x12000021 }, // DMB
0x1ca00b0 = 0x12000021 (DMB)
.{ 0x1ca0000 + 0x00b4, 0x01000031 }, // DMB
0x1ca00b4 = 0x1000031 (DMB)
.{ 0x1ca0000 + 0x00b8, 0x07000001 }, // DMB
0x1ca00b8 = 0x7000001 (DMB)
.{ 0x1ca0000 + 0x00bc, 0x14000011 }, // DMB
0x1ca00bc = 0x14000011 (DMB)
.{ 0x1ca0000 + 0x0018, 0x0011000a }, // DMB
0x1ca0018 = 0x11000a (DMB)
.{ 0x1ca0000 + 0x001c, 0x05cd05a0 }, // DMB
0x1ca001c = 0x5cd05a0 (DMB)
.{ 0x1ca0000 + 0x00c0, 0x09004a19 }, // DMB
0x1ca00c0 = 0x9004a19 (DMB)
.{ 0x1ca0000 + 0x00c4, 0x50b40000 }, // DMB
0x1ca00c4 = 0x50b40000 (DMB)
.{ 0x1ca0000 + 0x00c8, 0x35005419 }, // DMB
0x1ca00c8 = 0x35005419 (DMB)
.{ 0x1ca0000 + 0x00cc, 0x757a0000 }, // DMB
0x1ca00cc = 0x757a0000 (DMB)
.{ 0x1ca0000 + 0x00d0, 0x09004a19 }, // DMB
0x1ca00d0 = 0x9004a19 (DMB)
.{ 0x1ca0000 + 0x00d4, 0x50b40000 }, // DMB
0x1ca00d4 = 0x50b40000 (DMB)
.{ 0x1ca0000 + 0x00e0, 0x0c091a19 }, // DMB
0x1ca00e0 = 0xc091a19 (DMB)
.{ 0x1ca0000 + 0x00e4, 0x72bd0000 }, // DMB
0x1ca00e4 = 0x72bd0000 (DMB)
.{ 0x1ca0000 + 0x00e8, 0x1a000019 }, // DMB
0x1ca00e8 = 0x1a000019 (DMB)
.{ 0x1ca0000 + 0x00ec, 0xffff0000 }, // DMB
0x1ca00ec = 0xffff0000 (DMB)
};
enable_dsi_block: end
Now implemented in Zig. See "Enable MIPI Display Physical Layer (DPHY)"
Original Log captured from p-boot dphy_enable...
dphy_enable: start
150MHz (600 / 4)
0x1c20168 = 0x8203 (DMB)
0x1ca1004 = 0x10000000 (DMB)
0x1ca1010 = 0xa06000e (DMB)
0x1ca1014 = 0xa033207 (DMB)
0x1ca1018 = 0x1e (DMB)
0x1ca101c = 0x0 (DMB)
0x1ca1020 = 0x303 (DMB)
0x1ca1000 = 0x31 (DMB)
0x1ca104c = 0x9f007f00 (DMB)
0x1ca1050 = 0x17000000 (DMB)
0x1ca105c = 0x1f01555 (DMB)
0x1ca1054 = 0x2 (DMB)
udelay 5
0x1ca1058 = 0x3040000 (DMB)
udelay 1
update_bits addr=0x1ca1058, mask=0xf8000000, val=0xf8000000 (DMB)
udelay 1
update_bits addr=0x1ca1058, mask=0x4000000, val=0x4000000 (DMB)
udelay 1
update_bits addr=0x1ca1054, mask=0x10, val=0x10 (DMB)
udelay 1
update_bits addr=0x1ca1050, mask=0x80000000, val=0x80000000 (DMB)
update_bits addr=0x1ca1054, mask=0xf000000, val=0xf000000 (DMB)
dphy_enable: end
Now implemented in Zig. See "Reset LCD Panel"
Original Log captured from p-boot dsi_init...
panel_reset: start
deassert reset: GPD(23), 1 // PD23 - LCD-RST (active low)
sunxi_gpio_set_cfgpin: pin=0x77, val=1
sunxi_gpio_set_cfgbank: bank_offset=119, val=1
clrsetbits 0x1c20874, 0xf0000000, 0x10000000
sunxi_gpio_output: pin=0x77, val=1
before: 0x1c2087c = 0x1c0000
after: 0x1c2087c = 0x9c0000 (DMB)
wait for initialization
udelay 15000
panel_reset: end
Now implemented in Zig. See "Start MIPI DSI HSC and HSD"
Original Log captured from p-boot dsi_init...
start_dsi: start
dsi_start DSI_START_HSC
.{ 0x1ca0000 + 0x0048, 0x00000f02 }, // DMB
0x1ca0048 = 0xf02 (DMB)
.{ MAGIC_COMMIT, 0 }, // DMB
dsi_update_bits: 0x01ca0010 : 00030000 -> (00000001) 00000001 (DMB)
addr=0x1ca0010, mask=0x1, val=0x1 (DMB)
dsi_update_bits: 0x01ca0020 : 0000001f -> (00000010) 00000000 (DMB)
addr=0x1ca0020, mask=0x10, val=0x0 (DMB)
udelay 1000
dsi_start DSI_START_HSD
.{ 0x1ca0000 + 0x0048, 0x63f07006 }, // DMB
0x1ca0048 = 0x63f07006 (DMB)
.{ MAGIC_COMMIT, 0 }, // DMB
dsi_update_bits: 0x01ca0010 : 00030000 -> (00000001) 00000001 (DMB)
addr=0x1ca0010, mask=0x1, val=0x1 (DMB)
start_dsi: end
Now implemented in Zig. See pinephone-nuttx/render.zig
Original Log captured from p-boot dsi_init...
- Calls display_board_init (Done in Zig)
- Calls enable_dsi_block
- Calls dphy_enable
- Calls panel_reset
- Calls panel_init (Done in Zig)
- Calls start_dsi
display_board_init: start
assert reset: GPD(23), 0 // PD23 - LCD-RST (active low)
sunxi_gpio_set_cfgpin: pin=0x77, val=1
sunxi_gpio_set_cfgbank: bank_offset=119, val=1
clrsetbits 0x1c20874, 0xf0000000, 0x10000000
sunxi_gpio_output: pin=0x77, val=0
before: 0x1c2087c = 0x1c0000
after: 0x1c2087c = 0x1c0000 (DMB)
dldo1 3.3V
pmic_write: reg=0x15, val=0x1a
rsb_write: rt_addr=0x2d, reg_addr=0x15, value=0x1a
pmic_clrsetbits: reg=0x12, clr_mask=0x0, set_mask=0x8
rsb_read: rt_addr=0x2d, reg_addr=0x12
rsb_write: rt_addr=0x2d, reg_addr=0x12, value=0xd9
ldo_io0 3.3V
pmic_write: reg=0x91, val=0x1a
rsb_write: rt_addr=0x2d, reg_addr=0x91, value=0x1a
pmic_write: reg=0x90, val=0x3
rsb_write: rt_addr=0x2d, reg_addr=0x90, value=0x3
dldo2 1.8V
pmic_write: reg=0x16, val=0xb
rsb_write: rt_addr=0x2d, reg_addr=0x16, value=0xb
pmic_clrsetbits: reg=0x12, clr_mask=0x0, set_mask=0x10
rsb_read: rt_addr=0x2d, reg_addr=0x12
rsb_write: rt_addr=0x2d, reg_addr=0x12, value=0xd9
wait for power supplies and power-on init
udelay 15000
display_board_init: end
enable_dsi_block: start
mipi dsi bus enable
setbits 0x1c20060, 0x2 (DMB)
setbits 0x1c202c0, 0x2 (DMB)
Enable the DSI block
struct reg_inst dsi_init_seq[] = {
.{ 0x0000, 0x00000001 }, // DMB
.{ 0x0010, 0x00030000 }, // DMB
.{ 0x0060, 0x0000000a }, // DMB
.{ 0x0078, 0x00000000 }, // DMB
inst_init
.{ 0x0020, 0x0000001f }, // DMB
.{ 0x0024, 0x10000001 }, // DMB
.{ 0x0028, 0x20000010 }, // DMB
.{ 0x002c, 0x2000000f }, // DMB
.{ 0x0030, 0x30100001 }, // DMB
.{ 0x0034, 0x40000010 }, // DMB
.{ 0x0038, 0x0000000f }, // DMB
.{ 0x003c, 0x5000001f }, // DMB
.{ 0x004c, 0x00560001 }, // DMB
.{ 0x02f8, 0x000000ff }, // DMB
get_video_start_delay
.{ 0x0014, 0x00005bc7 }, // DMB
setup_burst
.{ 0x007c, 0x10000007 }, // DMB
setup_inst_loop
.{ 0x0040, 0x30000002 }, // DMB
.{ 0x0044, 0x00310031 }, // DMB
.{ 0x0054, 0x00310031 }, // DMB
setup_format
.{ 0x0090, 0x1308703e }, // DMB
.{ 0x0098, 0x0000ffff }, // DMB
.{ 0x009c, 0xffffffff }, // DMB
.{ 0x0080, 0x00010008 }, // DMB
setup_timings
display_malloc: size=2330
.{ 0x000c, 0x00000000 }, // DMB
.{ 0x00b0, 0x12000021 }, // DMB
.{ 0x00b4, 0x01000031 }, // DMB
.{ 0x00b8, 0x07000001 }, // DMB
.{ 0x00bc, 0x14000011 }, // DMB
.{ 0x0018, 0x0011000a }, // DMB
.{ 0x001c, 0x05cd05a0 }, // DMB
.{ 0x00c0, 0x09004a19 }, // DMB
.{ 0x00c4, 0x50b40000 }, // DMB
.{ 0x00c8, 0x35005419 }, // DMB
.{ 0x00cc, 0x757a0000 }, // DMB
.{ 0x00d0, 0x09004a19 }, // DMB
.{ 0x00d4, 0x50b40000 }, // DMB
.{ 0x00e0, 0x0c091a19 }, // DMB
.{ 0x00e4, 0x72bd0000 }, // DMB
.{ 0x00e8, 0x1a000019 }, // DMB
.{ 0x00ec, 0xffff0000 }, // DMB
};
enable_dsi_block: end
dphy_enable: start
150MHz (600 / 4)
0x1c20168 = 0x8203 (DMB)
0x1ca1004 = 0x10000000 (DMB)
0x1ca1010 = 0xa06000e (DMB)
0x1ca1014 = 0xa033207 (DMB)
0x1ca1018 = 0x1e (DMB)
0x1ca101c = 0x0 (DMB)
0x1ca1020 = 0x303 (DMB)
0x1ca1000 = 0x31 (DMB)
0x1ca104c = 0x9f007f00 (DMB)
0x1ca1050 = 0x17000000 (DMB)
0x1ca105c = 0x1f01555 (DMB)
0x1ca1054 = 0x2 (DMB)
udelay 5
0x1ca1058 = 0x3040000 (DMB)
udelay 1
update_bits 0x1ca1058, 0xf8000000, 0xf8000000 (DMB)
udelay 1
update_bits 0x1ca1058, 0x4000000, 0x4000000 (DMB)
udelay 1
update_bits 0x1ca1054, 0x10, 0x10 (DMB)
udelay 1
update_bits 0x1ca1050, 0x80000000, 0x80000000 (DMB)
update_bits 0x1ca1054, 0xf000000, 0xf000000 (DMB)
dphy_enable: end
panel_reset: start
deassert reset: GPD(23), 1 // PD23 - LCD-RST (active low)
sunxi_gpio_set_cfgpin: pin=0x77, val=1
sunxi_gpio_set_cfgbank: bank_offset=119, val=1
clrsetbits 0x1c20874, 0xf0000000, 0x10000000
sunxi_gpio_output: pin=0x77, val=1
before: 0x1c2087c = 0x1c0000
after: 0x1c2087c = 0x9c0000 (DMB)
wait for initialization
udelay 15000
panel_reset: end
panel_init: start
...
panel_init: end
start_dsi: start
dsi_start DSI_START_HSC
.{ 0x0048, 0x00000f02 }, // DMB
.{ MAGIC_COMMIT, 0 }, // DMB
dsi_update_bits: 0x01ca0020 : 0000001f -> (00000010) 00000000 (DMB)
udelay 1000
dsi_start DSI_START_HSD
.{ 0x0048, 0x63f07006 }, // DMB
.{ MAGIC_COMMIT, 0 }, // DMB
start_dsi: end
Now implemented in Zig. See "Timing Controller (TCON0)"
Original Log captured from p-boot tcon0_init...
tcon0_init: start
PLL_VIDEO0
0x1c20010 = 0x81006207 (DMB)
PLL_MIPI
0x1c20040 = 0xc00000 (DMB)
udelay 100
0x1c20040 = 0x80c0071a (DMB)
TCON0 source MIPI_PLL
0x1c20118 = 0x80000000 (DMB)
Clock on
0x1c20064 = 0x8 (DMB)
Reset off
0x1c202c4 = 0x8 (DMB)
Init lcdc: Disable tcon, Disable all interrupts
0x1c0c000 = 0x0 (DMB)
0x1c0c004 = 0x0
0x1c0c008 = 0x0
Set all io lines to tristate
0x1c0c08c = 0xffffffff
0x1c0c0f4 = 0xffffffff
mode set: DCLK = MIPI_PLL / 6
0x1c0c044 = 0x80000006
0x1c0c040 = 0x81000000
0x1c0c048 = 0x2cf059f
0x1c0c0f8 = 0x8
0x1c0c060 = 0x10010005
The datasheet says that this should be set higher than 20 * pixel cycle, but it's not clear what a pixel cycle is.
0x1c0c160 = 0x2f02cf
0x1c0c164 = 0x59f
0x1c0c168 = 0x1bc2000a
The Allwinner BSP has a comment that the period should be the display clock * 15, but uses an hardcoded 3000
0x1c0c1f0 = 0xbb80003
Enable the output on the pins
0x1c0c08c = 0xe0000000 (DMB)
enable tcon as a whole
setbits 0x1c0c000, 0x80000000 (DMB)
tcon0_init: end
Now implemented in Zig. See "Power Management Integrated Circuit"
Original Log captured from p-boot display_board_init...
display_board_init: start
assert reset: GPD(23), 0 // PD23 - LCD-RST (active low)
sunxi_gpio_set_cfgpin: pin=0x77, val=1
sunxi_gpio_set_cfgbank: bank_offset=119, val=1
clrsetbits 0x1c20874, 0xf0000000, 0x10000000
sunxi_gpio_output: pin=0x77, val=0
before: 0x1c2087c = 0x1c0000
after: 0x1c2087c = 0x1c0000 (DMB)
dldo1 3.3V
pmic_write: reg=0x15, val=0x1a
rsb_write: rt_addr=0x2d, reg_addr=0x15, value=0x1a
pmic_clrsetbits: reg=0x12, clr_mask=0x0, set_mask=0x8
rsb_read: rt_addr=0x2d, reg_addr=0x12
rsb_write: rt_addr=0x2d, reg_addr=0x12, value=0xd9
ldo_io0 3.3V
pmic_write: reg=0x91, val=0x1a
rsb_write: rt_addr=0x2d, reg_addr=0x91, value=0x1a
pmic_write: reg=0x90, val=0x3
rsb_write: rt_addr=0x2d, reg_addr=0x90, value=0x3
dldo2 1.8V
pmic_write: reg=0x16, val=0xb
rsb_write: rt_addr=0x2d, reg_addr=0x16, value=0xb
pmic_clrsetbits: reg=0x12, clr_mask=0x0, set_mask=0x10
rsb_read: rt_addr=0x2d, reg_addr=0x12
rsb_write: rt_addr=0x2d, reg_addr=0x12, value=0xd9
wait for power supplies and power-on init
udelay 15000
display_board_init: end
Now implemented in Zig. See "Display Backlight"
Original Log captured from p-boot backlight_enable...
backlight_enable: pct=0x5a
1.0 has incorrectly documented non-presence of PH10, the circuit is in fact the same as on 1.1+
configure pwm: GPL(10), GPL_R_PWM
sunxi_gpio_set_cfgpin: pin=0x16a, val=2
sunxi_gpio_set_cfgbank: bank_offset=362, val=2
clrsetbits 0x1f02c04, 0xf00, 0x200
clrbits 0x1f03800, 0x40
0x1f03804 = 0x4af0437
0x1f03800 = 0x5f
enable backlight: GPH(10), 1
sunxi_gpio_set_cfgpin: pin=0xea, val=1
sunxi_gpio_set_cfgbank: bank_offset=234, val=1
clrsetbits 0x1c20900, 0xf00, 0x100
sunxi_gpio_output: pin=0xea, val=1
Decoding the above addresses based on Allwinner A64 User Manual...
sunxi_gpio_set_cfgbank: bank_offset=362 (0x16a), val=2
- clrsetbits 0x1f02c04, 0xf00, 0x200
- 0x1f02c04 = R_PIO Base Address + 4
- Register PL_CFG1 (Port L Configure Register 1, Offset 4): To configure PL10 for PWM (Bits 8 to 10, Page 412)
clrbits 0x1f03800, 0x40
- 0x1f03800 = R_PWM Base Address + 0
- Register R_PWM_CTRL_REG? (R_PWM Control Register?, Offset 0): To control R_PWM? (Page 194?)
- Clear 0x40 = SCLK_CH0_GATING (0=mask)
- Undocumented??? (pwm->ctrl)
0x1f03804 = 0x4af0437
- 0x1f03804 = R_PWM Base Address + 4
- Register R_PWM_CH0_PERIOD? (R_PWM Channel 0 Period Register?, Offset 4): To configure R_PWM period? (Page 195?)
- PWM_CH0_ENTIRE_CYS = 0x4af = Period
- PWM_CH0_ENTIRE_ACT_CYS = 0x0437 = Period * Percent / 100
- Period = 0x4af (1199)
- Percent = 0x5a
- Undocumented??? (pwm->ch0_period)
0x1f03800 = 0x5f
- 0x1f03800 = R_PWM Base Address + 0
- Register R_PWM_CTRL_REG? (R_PWM Control Register?, Offset 0): To control R_PWM? (Page 194?)
- 0x5f = SCLK_CH0_GATING (1=pass) + PWM_CH0_EN (1=enable) + PWM_CH0_PRESCAL (Prescalar 1)
- Undocumented??? (pwm->ctrl)
sunxi_gpio_set_cfgbank: bank_offset=234 (0xea), val=1
- clrsetbits 0x1c20900, 0xf00, 0x100
- 0x1c20900 = PIO Base Address + 0x100
- Register PH_CFG1 (Offset 0x100): To configure PH10 (Bits 8 to 10)
sunxi_gpio_output: pin=0xea, val=1
- 0x1c2090c = PIO Base Address + 0x10C
- Register PH_DATA (Offset 0x10C): To set PH10 (Bit 10)
PIO (CPUx-PORT) Base Address: 0x01C2 0800 (Page 376)
PWM (CPUx-PWM?) Base Address: 0x01C2 1400 (Page 194)
R_PIO (CPUs-PORT) Base Address: 0x01F0 2C00 (Page 410)
R_PWM (CPUs-PWM?) Base Address: 0x01F0 3800 (CPUs Domain, Page 256)
Now implemented in Zig. See "Initialising the Allwinner A64 Display Engine"
Original Log captured from p-boot de2_init...
- Calls clock_set_pll_de (Done in Zig)
de2_init
Set SRAM for video use
0x1c00004 = 0x0 (DMB)
Setup DE2 PLL
clock_set_pll_de: clk=297000000
PLL10 rate = 24000000 * n / m
0x1c20048 = 0x81001701 (DMB)
while (!(readl(0x1c20048) & 0x10000000))
Enable DE2 special clock
clrsetbits 0x1c20104, 0x3000000, 0x81000000
Enable DE2 ahb
setbits 0x1c202c4, 0x1000
setbits 0x1c20064, 0x1000
Enable clock for mixer 0, set route MIXER0->TCON0
setbits 0x1000000, 0x1
setbits 0x1000008, 0x1
setbits 0x1000004, 0x1
clrbits 0x1000010, 0x1
Clear all registers
0x1100000 to 0x1105fff = 0x0
0x1120000 = 0x0
0x1130000 = 0x0
0x1140000 = 0x0
0x1150000 = 0x0
0x11a0000 = 0x0
0x11a2000 = 0x0
0x11a4000 = 0x0
0x11a6000 = 0x0
0x11a8000 = 0x0
0x11aa000 = 0x0
0x11b0000 = 0x0
Enable mixer
0x1100000 = 0x1 (DMB)
Now implemented in Zig. See "Initialising the Allwinner A64 Display Engine"
Original Log captured from p-boot clock_set_pll_de...
Setup DE2 PLL
clock_set_pll_de: clk=297000000
PLL10 rate = 24000000 * n / m
0x1c20048 = 0x81001701 (DMB)
while (!(readl(0x1c20048) & 0x10000000))