shithub: riscv

Download patch

ref: 931ae0cfebeb46892406efc7468636e59f8110a9
parent: 276f2039a9bceb4bc23b0fa1ce3169057aac405e
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Jun 11 17:12:04 EDT 2022

imx8: mainscreen turn on!

supports the lcd panel and adds alot of infrastructure
like for the ccm clock module and the i2c controllers.

--- /dev/null
+++ b/sys/src/9/imx8/ccm.c
@@ -1,0 +1,1357 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+static u32int *regs = (u32int*)(VIRTIO + 0x380000);
+static u32int *anatop = (u32int*)(VIRTIO + 0x360000);
+
+enum {
+	/* input clocks */
+	ARM_PLL_CLK = 12,
+	GPU_PLL_CLK,
+	VPU_PLL_CLK,
+	DRAM_PLL1_CLK,
+	SYSTEM_PLL1_CLK,
+	SYSTEM_PLL1_DIV2,
+	SYSTEM_PLL1_DIV3,
+	SYSTEM_PLL1_DIV4,
+	SYSTEM_PLL1_DIV5,
+	SYSTEM_PLL1_DIV6,
+	SYSTEM_PLL1_DIV8,
+	SYSTEM_PLL1_DIV10,
+	SYSTEM_PLL1_DIV20,
+	SYSTEM_PLL2_CLK,
+	SYSTEM_PLL2_DIV2,
+	SYSTEM_PLL2_DIV3,
+	SYSTEM_PLL2_DIV4,
+	SYSTEM_PLL2_DIV5,
+	SYSTEM_PLL2_DIV6,
+	SYSTEM_PLL2_DIV8,
+	SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL2_DIV20,
+	SYSTEM_PLL3_CLK,
+	AUDIO_PLL1_CLK,
+	AUDIO_PLL2_CLK,
+	VIDEO_PLL1_CLK,
+	VIDEO_PLL2_CLK,
+
+	OSC_32K_REF_CLK,
+	OSC_25M_REF_CLK,
+	OSC_27M_REF_CLK,
+	EXT_CLK_1,
+	EXT_CLK_2,
+	EXT_CLK_3,
+	EXT_CLK_4,
+
+	/* root clocks (slices) */
+	ARM_A53_CLK_ROOT = 0,
+	ARM_M4_CLK_ROOT = 1,
+	VPU_A53_CLK_ROOT = 2,
+	GPU_CORE_CLK_ROOT = 3,
+	GPU_SHADER_CLK_ROOT = 4,
+
+	MAIN_AXI_CLK_ROOT = 16,
+	ENET_AXI_CLK_ROOT = 17,
+	NAND_USDHC_BUS_CLK_ROOT = 18,
+	VPU_BUS_CLK_ROOT = 19,
+	DISPLAY_AXI_CLK_ROOT = 20,
+	DISPLAY_APB_CLK_ROOT = 21,
+	DISPLAY_RTRM_CLK_ROOT = 22,
+	USB_BUS_CLK_ROOT = 23,
+	GPU_AXI_CLK_ROOT = 24,
+	GPU_AHB_CLK_ROOT = 25,
+	NOC_CLK_ROOT = 26,
+	NOC_APB_CLK_ROOT = 27,
+
+	AHB_CLK_ROOT = 32,
+		IPG_CLK_ROOT = 33,
+	AUDIO_AHB_CLK_ROOT = 34,
+		AUDIO_IPG_CLK_ROOT = 35,
+	MIPI_DSI_ESC_RX_CLK_ROOT = 36,
+		MIPI_DSI_ESC_CLK_ROOT = 37,
+
+	DRAM_ALT_CLK_ROOT = 64,
+	DRAM_APB_CLK_ROOT = 65,
+	VPU_G1_CLK_ROOT = 66,
+	VPU_G2_CLK_ROOT = 67,
+	DISPLAY_DTRC_CLK_ROOT = 68,
+	DISPLAY_DC8000_CLK_ROOT = 69,
+	PCIE1_CTRL_CLK_ROOT = 70,
+	PCIE1_PHY_CLK_ROOT = 71,
+	PCIE1_AUX_CLK_ROOT = 72,
+	DC_PIXEL_CLK_ROOT = 73,
+	LCDIF_PIXEL_CLK_ROOT = 74,
+	SAI1_CLK_ROOT = 75,
+	SAI2_CLK_ROOT = 76,
+	SAI3_CLK_ROOT = 77,
+	SAI4_CLK_ROOT = 78,
+	SAI5_CLK_ROOT = 79,
+	SAI6_CLK_ROOT = 80,
+	SPDIF1_CLK_ROOT = 81,
+	SPDIF2_CLK_ROOT = 82,
+	ENET_REF_CLK_ROOT = 83,
+	ENET_TIMER_CLK_ROOT = 84,
+	ENET_PHY_REF_CLK_ROOT = 85,
+	NAND_CLK_ROOT = 86,
+	QSPI_CLK_ROOT = 87,
+	USDHC1_CLK_ROOT = 88,
+	USDHC2_CLK_ROOT = 89,
+	I2C1_CLK_ROOT = 90,
+	I2C2_CLK_ROOT = 91,
+	I2C3_CLK_ROOT = 92,
+	I2C4_CLK_ROOT = 93,
+	UART1_CLK_ROOT = 94,
+	UART2_CLK_ROOT = 95,
+	UART3_CLK_ROOT = 96,
+	UART4_CLK_ROOT = 97,
+	USB_CORE_REF_CLK_ROOT = 98,
+	USB_PHY_REF_CLK_ROOT = 99,
+	GIC_CLK_ROOT = 100,
+	ECSPI1_CLK_ROOT = 101,
+	ECSPI2_CLK_ROOT = 102,
+	PWM1_CLK_ROOT = 103,
+	PWM2_CLK_ROOT = 104,
+	PWM3_CLK_ROOT = 105,
+	PWM4_CLK_ROOT = 106,
+	GPT1_CLK_ROOT = 107,
+	GPT2_CLK_ROOT = 108,
+	GPT3_CLK_ROOT = 109,
+	GPT4_CLK_ROOT = 110,
+	GPT5_CLK_ROOT = 111,
+	GPT6_CLK_ROOT = 112,
+	TRACE_CLK_ROOT = 113,
+	WDOG_CLK_ROOT = 114,
+	WRCLK_CLK_ROOT = 115,
+	IPP_DO_CLKO1 = 116,
+	IPP_DO_CLKO2 = 117,
+	MIPI_DSI_CORE_CLK_ROOT = 118,
+	MIPI_DSI_PHY_REF_CLK_ROOT = 119,
+	MIPI_DSI_DBI_CLK_ROOT = 120,
+	OLD_MIPI_DSI_ESC_CLK_ROOT = 121,
+	MIPI_CSI1_CORE_CLK_ROOT = 122,
+	MIPI_CSI1_PHY_REF_CLK_ROOT = 123,
+	MIPI_CSI1_ESC_CLK_ROOT = 124,
+	MIPI_CSI2_CORE_CLK_ROOT = 125,
+	MIPI_CSI2_PHY_REF_CLK_ROOT = 126,
+	MIPI_CSI2_ESC_CLK_ROOT = 127,
+	PCIE2_CTRL_CLK_ROOT = 128,
+	PCIE2_PHY_CLK_ROOT = 129,
+	PCIE2_AUX_CLK_ROOT = 130,
+	ECSPI3_CLK_ROOT = 131,
+	OLD_MIPI_DSI_ESC_RX_CLK_ROOT = 132,
+	DISPLAY_HDMI_CLK_ROOT = 133,
+};
+
+static int input_clk_freq[] = {
+	[ARM_PLL_CLK] 1600*Mhz, 
+	[GPU_PLL_CLK] 1600*Mhz,
+	[VPU_PLL_CLK] 800*Mhz,
+	[DRAM_PLL1_CLK] 800*Mhz,
+	[SYSTEM_PLL1_CLK] 800*Mhz,
+	[SYSTEM_PLL1_DIV2] 400*Mhz,
+	[SYSTEM_PLL1_DIV3] 266*Mhz,
+	[SYSTEM_PLL1_DIV4] 200*Mhz,
+	[SYSTEM_PLL1_DIV5] 160*Mhz,
+	[SYSTEM_PLL1_DIV6] 133*Mhz,
+	[SYSTEM_PLL1_DIV8] 100*Mhz,
+	[SYSTEM_PLL1_DIV10] 80*Mhz,
+	[SYSTEM_PLL1_DIV20] 40*Mhz,
+	[SYSTEM_PLL2_CLK] 1000*Mhz,
+	[SYSTEM_PLL2_DIV2] 500*Mhz,
+	[SYSTEM_PLL2_DIV3] 333*Mhz,
+	[SYSTEM_PLL2_DIV4] 250*Mhz,
+	[SYSTEM_PLL2_DIV5] 200*Mhz,
+	[SYSTEM_PLL2_DIV6] 166*Mhz,
+	[SYSTEM_PLL2_DIV8] 125*Mhz,
+	[SYSTEM_PLL2_DIV10] 100*Mhz,
+	[SYSTEM_PLL2_DIV20] 50*Mhz,
+	[SYSTEM_PLL3_CLK] 1000*Mhz,
+	[AUDIO_PLL1_CLK] 650*Mhz,
+	[AUDIO_PLL2_CLK] 650*Mhz,
+	[VIDEO_PLL1_CLK] 594*Mhz,
+	[VIDEO_PLL2_CLK] 600*Mhz,
+	[OSC_32K_REF_CLK] 32000,
+	[OSC_25M_REF_CLK] 25*Mhz,
+	[OSC_27M_REF_CLK] 27*Mhz,
+	[EXT_CLK_1] 133*Mhz,
+	[EXT_CLK_2] 133*Mhz,
+	[EXT_CLK_3] 133*Mhz,
+	[EXT_CLK_4] 133*Mhz,
+};
+
+static char *input_clk_name[] = {
+	[ARM_PLL_CLK] "arm_pll_clk",
+	[GPU_PLL_CLK] "gpu_pll_clk",
+	[VPU_PLL_CLK] "vpu_pll_clk",
+	[DRAM_PLL1_CLK] "dram_pll1_clk",
+	[SYSTEM_PLL1_CLK] "system_pll1_clk",
+	[SYSTEM_PLL1_DIV2] "system_pll1_div2",
+	[SYSTEM_PLL1_DIV3] "system_pll1_div3",
+	[SYSTEM_PLL1_DIV4] "system_pll1_div4",
+	[SYSTEM_PLL1_DIV5] "system_pll1_div5",
+	[SYSTEM_PLL1_DIV6] "system_pll1_div6",
+	[SYSTEM_PLL1_DIV8] "system_pll1_div8",
+	[SYSTEM_PLL1_DIV10] "system_pll1_div10",
+	[SYSTEM_PLL1_DIV20] "system_pll1_div20",
+	[SYSTEM_PLL2_CLK] "system_pll2_clk",
+	[SYSTEM_PLL2_DIV2] "system_pll2_div2",
+	[SYSTEM_PLL2_DIV3] "system_pll2_div3",
+	[SYSTEM_PLL2_DIV4] "system_pll2_div4",
+	[SYSTEM_PLL2_DIV5] "system_pll2_div5",
+	[SYSTEM_PLL2_DIV6] "system_pll2_div6",
+	[SYSTEM_PLL2_DIV8] "system_pll2_div8",
+	[SYSTEM_PLL2_DIV10] "system_pll2_div10",
+	[SYSTEM_PLL2_DIV20] "system_pll2_div20",
+	[SYSTEM_PLL3_CLK] "system_pll3_clk",
+	[AUDIO_PLL1_CLK] "audio_pll1_clk",
+	[AUDIO_PLL2_CLK] "audio_pll2_clk",
+	[VIDEO_PLL1_CLK] "video_pll1_clk",
+	[VIDEO_PLL2_CLK] "video_pll2_clk",
+	[OSC_32K_REF_CLK] "osc_32k_ref_clk",
+	[OSC_25M_REF_CLK] "osc_25m_ref_clk",
+	[OSC_27M_REF_CLK] "osc_27m_ref_clk",
+	[EXT_CLK_1] "ext_clk_1",
+	[EXT_CLK_2] "ext_clk_2",
+	[EXT_CLK_3] "ext_clk_3",
+	[EXT_CLK_4] "ext_clk_4",
+};
+
+static char *root_clk_name[] = {
+	[ARM_A53_CLK_ROOT] "ccm_arm_a53_clk_root",
+	[ARM_M4_CLK_ROOT] "ccm_arm_m4_clk_root",
+	[VPU_A53_CLK_ROOT] "ccm_vpu_a53_clk_root",
+	[GPU_CORE_CLK_ROOT] "ccm_gpu_core_clk_root",
+	[GPU_SHADER_CLK_ROOT] "ccm_gpu_shader_clk_root",
+	[MAIN_AXI_CLK_ROOT] "ccm_main_axi_clk_root",
+	[ENET_AXI_CLK_ROOT] "ccm_enet_axi_clk_root",
+	[NAND_USDHC_BUS_CLK_ROOT] "ccm_nand_usdhc_bus_clk_root",
+	[VPU_BUS_CLK_ROOT] "ccm_vpu_bus_clk_root",
+	[DISPLAY_AXI_CLK_ROOT] "ccm_display_axi_clk_root",
+	[DISPLAY_APB_CLK_ROOT] "ccm_display_apb_clk_root",
+	[DISPLAY_RTRM_CLK_ROOT] "ccm_display_rtrm_clk_root",
+	[USB_BUS_CLK_ROOT] "ccm_usb_bus_clk_root",
+	[GPU_AXI_CLK_ROOT] "ccm_gpu_axi_clk_root",
+	[GPU_AHB_CLK_ROOT] "ccm_gpu_ahb_clk_root",
+	[NOC_CLK_ROOT] "ccm_noc_clk_root",
+	[NOC_APB_CLK_ROOT] "ccm_noc_apb_clk_root",
+	[AHB_CLK_ROOT] "ccm_ahb_clk_root",
+	[IPG_CLK_ROOT] "ccm_ipg_clk_root",
+	[AUDIO_AHB_CLK_ROOT] "ccm_audio_ahb_clk_root",
+	[AUDIO_IPG_CLK_ROOT] "ccm_audio_ipg_clk_root",
+	[MIPI_DSI_ESC_RX_CLK_ROOT] "ccm_mipi_dsi_esc_rx_clk_root",
+	[MIPI_DSI_ESC_CLK_ROOT] "ccm_mipi_dsi_esc_clk_root",
+	[DRAM_ALT_CLK_ROOT] "ccm_dram_alt_clk_root",
+	[DRAM_APB_CLK_ROOT] "ccm_dram_apb_clk_root",
+	[VPU_G1_CLK_ROOT] "ccm_vpu_g1_clk_root",
+	[VPU_G2_CLK_ROOT] "ccm_vpu_g2_clk_root",
+	[DISPLAY_DTRC_CLK_ROOT] "ccm_display_dtrc_clk_root",
+	[DISPLAY_DC8000_CLK_ROOT] "ccm_display_dc8000_clk_root",
+	[PCIE1_CTRL_CLK_ROOT] "ccm_pcie1_ctrl_clk_root",
+	[PCIE1_PHY_CLK_ROOT] "ccm_pcie1_phy_clk_root",
+	[PCIE1_AUX_CLK_ROOT] "ccm_pcie1_aux_clk_root",
+	[DC_PIXEL_CLK_ROOT] "ccm_dc_pixel_clk_root",
+	[LCDIF_PIXEL_CLK_ROOT] "ccm_lcdif_pixel_clk_root",
+	[SAI1_CLK_ROOT] "ccm_sai1_clk_root",
+	[SAI2_CLK_ROOT] "ccm_sai2_clk_root",
+	[SAI3_CLK_ROOT] "ccm_sai3_clk_root",
+	[SAI4_CLK_ROOT] "ccm_sai4_clk_root",
+	[SAI5_CLK_ROOT] "ccm_sai5_clk_root",
+	[SAI6_CLK_ROOT] "ccm_sai6_clk_root",
+	[SPDIF1_CLK_ROOT] "ccm_spdif1_clk_root",
+	[SPDIF2_CLK_ROOT] "ccm_spdif2_clk_root",
+	[ENET_REF_CLK_ROOT] "ccm_enet_ref_clk_root",
+	[ENET_TIMER_CLK_ROOT] "ccm_enet_timer_clk_root",
+	[ENET_PHY_REF_CLK_ROOT] "ccm_enet_phy_ref_clk_root",
+	[NAND_CLK_ROOT] "ccm_nand_clk_root",
+	[QSPI_CLK_ROOT] "ccm_qspi_clk_root",
+	[USDHC1_CLK_ROOT] "ccm_usdhc1_clk_root",
+	[USDHC2_CLK_ROOT] "ccm_usdhc2_clk_root",
+	[I2C1_CLK_ROOT] "ccm_i2c1_clk_root",
+	[I2C2_CLK_ROOT] "ccm_i2c2_clk_root",
+	[I2C3_CLK_ROOT] "ccm_i2c3_clk_root",
+	[I2C4_CLK_ROOT] "ccm_i2c4_clk_root",
+	[UART1_CLK_ROOT] "ccm_uart1_clk_root",
+	[UART2_CLK_ROOT] "ccm_uart2_clk_root",
+	[UART3_CLK_ROOT] "ccm_uart3_clk_root",
+	[UART4_CLK_ROOT] "ccm_uart4_clk_root",
+	[USB_CORE_REF_CLK_ROOT] "ccm_usb_core_ref_clk_root",
+	[USB_PHY_REF_CLK_ROOT] "ccm_usb_phy_ref_clk_root",
+	[GIC_CLK_ROOT] "ccm_gic_clk_root",
+	[ECSPI1_CLK_ROOT] "ccm_ecspi1_clk_root",
+	[ECSPI2_CLK_ROOT] "ccm_ecspi2_clk_root",
+	[PWM1_CLK_ROOT] "ccm_pwm1_clk_root",
+	[PWM2_CLK_ROOT] "ccm_pwm2_clk_root",
+	[PWM3_CLK_ROOT] "ccm_pwm3_clk_root",
+	[PWM4_CLK_ROOT] "ccm_pwm4_clk_root",
+	[GPT1_CLK_ROOT] "ccm_gpt1_clk_root",
+	[GPT2_CLK_ROOT] "ccm_gpt2_clk_root",
+	[GPT3_CLK_ROOT] "ccm_gpt3_clk_root",
+	[GPT4_CLK_ROOT] "ccm_gpt4_clk_root",
+	[GPT5_CLK_ROOT] "ccm_gpt5_clk_root",
+	[GPT6_CLK_ROOT] "ccm_gpt6_clk_root",
+	[TRACE_CLK_ROOT] "ccm_trace_clk_root",
+	[WDOG_CLK_ROOT] "ccm_wdog_clk_root",
+	[WRCLK_CLK_ROOT] "ccm_wrclk_clk_root",
+	[IPP_DO_CLKO1] "ccm_ipp_do_clko1",
+	[IPP_DO_CLKO2] "ccm_ipp_do_clko2",
+	[MIPI_DSI_CORE_CLK_ROOT] "ccm_mipi_dsi_core_clk_root",
+	[MIPI_DSI_PHY_REF_CLK_ROOT] "ccm_mipi_dsi_phy_ref_clk_root",
+	[MIPI_DSI_DBI_CLK_ROOT] "ccm_mipi_dsi_dbi_clk_root",
+	[OLD_MIPI_DSI_ESC_CLK_ROOT] "ccm_old_mipi_dsi_esc_clk_root",
+	[MIPI_CSI1_CORE_CLK_ROOT] "ccm_mipi_csi1_core_clk_root",
+	[MIPI_CSI1_PHY_REF_CLK_ROOT] "ccm_mipi_csi1_phy_ref_clk_root",
+	[MIPI_CSI1_ESC_CLK_ROOT] "ccm_mipi_csi1_esc_clk_root",
+	[MIPI_CSI2_CORE_CLK_ROOT] "ccm_mipi_csi2_core_clk_root",
+	[MIPI_CSI2_PHY_REF_CLK_ROOT] "ccm_mipi_csi2_phy_ref_clk_root",
+	[MIPI_CSI2_ESC_CLK_ROOT] "ccm_mipi_csi2_esc_clk_root",
+	[PCIE2_CTRL_CLK_ROOT] "ccm_pcie2_ctrl_clk_root",
+	[PCIE2_PHY_CLK_ROOT] "ccm_pcie2_phy_clk_root",
+	[PCIE2_AUX_CLK_ROOT] "ccm_pcie2_aux_clk_root",
+	[ECSPI3_CLK_ROOT] "ccm_ecspi3_clk_root",
+	[OLD_MIPI_DSI_ESC_RX_CLK_ROOT] "ccm_old_mipi_dsi_esc_rx_clk_root",
+	[DISPLAY_HDMI_CLK_ROOT] "ccm_display_hdmi_clk_root",
+};
+
+static uchar root_clk_input_mux[] = {
+[ARM_A53_CLK_ROOT*8]
+	OSC_25M_REF_CLK, ARM_PLL_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL1_DIV2, AUDIO_PLL1_CLK, SYSTEM_PLL3_CLK,
+[ARM_M4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV4, SYSTEM_PLL1_DIV3,
+	SYSTEM_PLL1_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, SYSTEM_PLL3_CLK,
+[VPU_A53_CLK_ROOT*8]
+	OSC_25M_REF_CLK, ARM_PLL_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL1_DIV2, AUDIO_PLL1_CLK, VPU_PLL_CLK,
+[GPU_CORE_CLK_ROOT*8]
+	OSC_25M_REF_CLK, GPU_PLL_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[GPU_SHADER_CLK_ROOT*8]
+	OSC_25M_REF_CLK, GPU_PLL_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[MAIN_AXI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV3, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV4,
+	SYSTEM_PLL2_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV8,
+[ENET_AXI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV4,
+	SYSTEM_PLL2_DIV5, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, SYSTEM_PLL3_CLK,
+[NAND_USDHC_BUS_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV5,
+	SYSTEM_PLL1_DIV6, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, AUDIO_PLL1_CLK,
+[VPU_BUS_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, VPU_PLL_CLK, AUDIO_PLL2_CLK,
+	SYSTEM_PLL3_CLK, SYSTEM_PLL2_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV8,
+[DISPLAY_AXI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV8, SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL1_DIV20, AUDIO_PLL2_CLK, EXT_CLK_1, EXT_CLK_4,
+[DISPLAY_APB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV8, SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL1_DIV20, AUDIO_PLL2_CLK, EXT_CLK_1, EXT_CLK_3,
+[DISPLAY_RTRM_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV2,
+	AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, EXT_CLK_2, EXT_CLK_3,
+[USB_BUS_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL2_DIV5, EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK,
+[GPU_AXI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, GPU_PLL_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[GPU_AHB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, GPU_PLL_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[NOC_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL2_DIV2, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[NOC_APB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV2, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV3,
+	SYSTEM_PLL2_DIV5, SYSTEM_PLL1_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK,
+[AHB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV6, SYSTEM_PLL1_CLK, SYSTEM_PLL1_DIV2,
+	SYSTEM_PLL2_DIV8, SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK,
+[AUDIO_AHB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL2_DIV6, SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK,
+[MIPI_DSI_ESC_RX_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_3, AUDIO_PLL2_CLK,
+[DRAM_ALT_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL1_DIV8, SYSTEM_PLL2_DIV2,
+	SYSTEM_PLL2_DIV4, SYSTEM_PLL1_DIV2, AUDIO_PLL1_CLK, SYSTEM_PLL1_DIV3,
+[DRAM_APB_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV20, SYSTEM_PLL1_DIV5,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, AUDIO_PLL2_CLK,
+[VPU_G1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VPU_PLL_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_DIV8, SYSTEM_PLL2_DIV8, SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK,
+[VPU_G2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VPU_PLL_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_DIV8, SYSTEM_PLL2_DIV8, SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK,
+[DISPLAY_DTRC_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VIDEO_PLL2_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_DIV5, VIDEO_PLL1_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK,
+[DISPLAY_DC8000_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VIDEO_PLL2_CLK, SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK,
+	SYSTEM_PLL1_DIV5, VIDEO_PLL1_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK,
+[PCIE1_CTRL_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV4, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV3,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL2_DIV3, SYSTEM_PLL3_CLK,
+[PCIE1_PHY_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL2_DIV2, EXT_CLK_1,
+	EXT_CLK_2, EXT_CLK_3, EXT_CLK_4, SYSTEM_PLL1_DIV2,
+[PCIE1_AUX_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV4,
+[DC_PIXEL_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, AUDIO_PLL1_CLK,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_4,
+[LCDIF_PIXEL_CLK_ROOT*8]
+	OSC_25M_REF_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, AUDIO_PLL1_CLK,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_4,
+[SAI1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_1, EXT_CLK_2,
+[SAI2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_2, EXT_CLK_3,
+[SAI3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_3, EXT_CLK_4,
+[SAI4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_1, EXT_CLK_2,
+[SAI5_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_2, EXT_CLK_3,
+[SAI6_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_3, EXT_CLK_4,
+[SPDIF1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_2, EXT_CLK_3,
+[SPDIF2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, AUDIO_PLL1_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+	SYSTEM_PLL1_DIV6, OSC_27M_REF_CLK, EXT_CLK_3, EXT_CLK_4,
+[ENET_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV8, SYSTEM_PLL2_DIV20, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL1_DIV5, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, EXT_CLK_4,
+[ENET_TIMER_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, AUDIO_PLL1_CLK, EXT_CLK_1,
+	EXT_CLK_2, EXT_CLK_3, EXT_CLK_4, VIDEO_PLL1_CLK,
+[ENET_PHY_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV20, SYSTEM_PLL2_DIV8, SYSTEM_PLL2_DIV5,
+	SYSTEM_PLL2_DIV2, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK,
+[NAND_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV2, AUDIO_PLL1_CLK, SYSTEM_PLL1_DIV2,
+	AUDIO_PLL2_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, VIDEO_PLL1_CLK,
+[QSPI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV2,
+	AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL3_CLK, SYSTEM_PLL1_DIV8,
+[USDHC1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV2,
+	SYSTEM_PLL3_CLK, SYSTEM_PLL1_DIV3, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV8,
+[USDHC2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV2,
+	SYSTEM_PLL3_CLK, SYSTEM_PLL1_DIV3, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV8,
+[I2C1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV6,
+[I2C2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV6,
+[I2C3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV6,
+[I2C4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, AUDIO_PLL2_CLK, SYSTEM_PLL1_DIV6,
+[UART1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV10, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK,
+[UART2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV10, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK,
+[UART3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV10, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK,
+[UART4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV10, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK,
+[USB_CORE_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV8, SYSTEM_PLL1_DIV20, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL2_DIV5, EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK,
+[USB_PHY_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV8, SYSTEM_PLL1_DIV20, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL2_DIV5, EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK,
+[GIC_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV20, SYSTEM_PLL2_DIV10,
+	SYSTEM_PLL1_CLK, EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK,
+[ECSPI1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV20, SYSTEM_PLL1_DIV5,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, AUDIO_PLL2_CLK,
+[ECSPI2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV20, SYSTEM_PLL1_DIV5,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, AUDIO_PLL2_CLK,
+[PWM1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV20,
+	SYSTEM_PLL3_CLK, EXT_CLK_1, SYSTEM_PLL1_DIV10, VIDEO_PLL1_CLK,
+[PWM2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV20,
+	SYSTEM_PLL3_CLK, EXT_CLK_1, SYSTEM_PLL1_DIV10, VIDEO_PLL1_CLK,
+[PWM3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV20,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, SYSTEM_PLL1_DIV10, VIDEO_PLL1_CLK,
+[PWM4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV20,
+	SYSTEM_PLL3_CLK, EXT_CLK_2, SYSTEM_PLL1_DIV10, VIDEO_PLL1_CLK,
+[GPT1_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_1,
+[GPT2_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_2,
+[GPT3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_3,
+[GPT4_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_1,
+[GPT5_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_2,
+[GPT6_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV2, SYSTEM_PLL1_DIV20,
+	VIDEO_PLL1_CLK, SYSTEM_PLL1_DIV10, AUDIO_PLL1_CLK, EXT_CLK_3,
+[TRACE_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV6, SYSTEM_PLL1_DIV5, VPU_PLL_CLK,
+	SYSTEM_PLL2_DIV8, SYSTEM_PLL3_CLK, EXT_CLK_1, EXT_CLK_3,
+[WDOG_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV6, SYSTEM_PLL1_DIV5, VPU_PLL_CLK,
+	SYSTEM_PLL2_DIV8, SYSTEM_PLL3_CLK, SYSTEM_PLL1_DIV10, SYSTEM_PLL2_DIV6,
+[WRCLK_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV20, VPU_PLL_CLK, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV3, SYSTEM_PLL2_DIV2, SYSTEM_PLL1_DIV8,
+[IPP_DO_CLKO1*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_CLK, OSC_27M_REF_CLK, SYSTEM_PLL1_DIV4,
+	AUDIO_PLL2_CLK, SYSTEM_PLL2_DIV2, VPU_PLL_CLK, SYSTEM_PLL1_DIV10,
+[IPP_DO_CLKO2*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV2, SYSTEM_PLL2_DIV6,
+	SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK, VIDEO_PLL1_CLK, OSC_32K_REF_CLK,
+[MIPI_DSI_CORE_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL2_DIV4, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_DSI_PHY_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV8, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, EXT_CLK_2, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_DSI_DBI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_CSI1_CORE_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL2_DIV4, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_CSI1_PHY_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV3, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, EXT_CLK_2, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_CSI1_ESC_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_3, AUDIO_PLL2_CLK,
+[MIPI_CSI2_CORE_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV3, SYSTEM_PLL2_DIV4, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_CSI2_PHY_REF_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV3, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, EXT_CLK_2, AUDIO_PLL2_CLK, VIDEO_PLL1_CLK,
+[MIPI_CSI2_ESC_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_3, AUDIO_PLL2_CLK,
+[PCIE2_CTRL_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV4, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV3,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL2_DIV2, SYSTEM_PLL2_DIV3, SYSTEM_PLL3_CLK,
+[PCIE2_PHY_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL2_DIV2, EXT_CLK_1,
+	EXT_CLK_2, EXT_CLK_3, EXT_CLK_4, SYSTEM_PLL1_DIV2,
+[PCIE2_AUX_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL2_DIV20, SYSTEM_PLL3_CLK,
+	SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_DIV5, SYSTEM_PLL1_DIV4,
+[ECSPI3_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV5, SYSTEM_PLL1_DIV20, SYSTEM_PLL1_DIV5,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL3_CLK, SYSTEM_PLL2_DIV4, AUDIO_PLL2_CLK,
+[OLD_MIPI_DSI_ESC_RX_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL2_DIV10, SYSTEM_PLL1_DIV10, SYSTEM_PLL1_CLK,
+	SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_3, AUDIO_PLL2_CLK,
+[DISPLAY_HDMI_CLK_ROOT*8]
+	OSC_25M_REF_CLK, SYSTEM_PLL1_DIV4, SYSTEM_PLL2_DIV5, VPU_PLL_CLK,
+	SYSTEM_PLL1_CLK, SYSTEM_PLL2_CLK, SYSTEM_PLL3_CLK, EXT_CLK_4,
+};
+
+typedef struct Clock Clock;
+struct Clock {
+	char	*name;	/* clock instance name */
+	int	root;	/* root clock slice */
+	int	ccgr;	/* clock gating register */
+};
+
+static Clock clocks[] = {
+	{ "aips_tz1.hclk", AHB_CLK_ROOT, 28 },
+	{ "ipmux1.master_clk", AHB_CLK_ROOT, 28 },
+	{ "ipmux1.slave_clk", IPG_CLK_ROOT, 28 },
+
+	{ "aips_tz2.hclk", AHB_CLK_ROOT, 29 },
+	{ "ipmux2.master_clk", AHB_CLK_ROOT, 29 },
+	{ "ipmux2.slave_clk", AHB_CLK_ROOT, 29 },
+
+	{ "aips_tz3.hclk", AHB_CLK_ROOT, 30 },
+	{ "ipmux3.master_clk", AHB_CLK_ROOT, 30 },
+	{ "ipmux3.slave_clk", IPG_CLK_ROOT, 30 },
+
+	{ "apbhdma.hclk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+	{ "apdhdma_sec.mst_hclk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+	{ "rawnand.u_bch_input_apb_clk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+	{ "u_bch_input_apb_clk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+	{ "rawnand.u_gpmi_bch_input_gpmi_io_clk", NAND_CLK_ROOT, 48 },
+	{ "rawnand.U_gpmi_input_apb_clk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+
+	{ "caam.aclk", AHB_CLK_ROOT },
+	{ "caam.ipg_clk", IPG_CLK_ROOT },
+	{ "caam.ipg_clk_s", IPG_CLK_ROOT },
+	{ "caam_exsc.aclk_exsc", AHB_CLK_ROOT },
+	{ "caam_mem.clk", AHB_CLK_ROOT },
+
+	{ "cm4.cm4_cti_clk", ARM_M4_CLK_ROOT },
+	{ "cm4.cm4_fclk", ARM_M4_CLK_ROOT },
+	{ "cm4.cm4_hclk", ARM_M4_CLK_ROOT },
+	{ "cm4.dap_clk", AHB_CLK_ROOT },
+	{ "cm4.ipg_clk_nic", ARM_M4_CLK_ROOT },
+	{ "cm4.tcmc_hclk", ARM_M4_CLK_ROOT },
+	{ "cm4_mem.tcmc_hclk", ARM_M4_CLK_ROOT },
+	{ "cm4_sec.ipg_clk", IPG_CLK_ROOT },
+	{ "cm4_sec.ipg_clk_s", IPG_CLK_ROOT },
+	{ "cm4_sec.mst_hclk", ARM_M4_CLK_ROOT },
+
+	{ "csi2_1.clk_vid", MIPI_CSI1_PHY_REF_CLK_ROOT },
+	{ "csi2_1.clk", MIPI_CSI1_CORE_CLK_ROOT, 101},
+	{ "csi2_1.clk_esc", MIPI_CSI1_ESC_CLK_ROOT, 101},
+	{ "csi2_1.pclk", MIPI_CSI1_CORE_CLK_ROOT },
+	{ "csi2_1.clk_ui", MIPI_CSI1_PHY_REF_CLK_ROOT, 101},
+
+	{ "csi2_2.clk_vid", MIPI_CSI2_PHY_REF_CLK_ROOT },
+	{ "csi2_2.clk", MIPI_CSI2_CORE_CLK_ROOT, 102 },
+	{ "csi2_2.clk_esc", MIPI_CSI2_ESC_CLK_ROOT, 102 },
+	{ "csi2_2.pclk", MIPI_CSI2_CORE_CLK_ROOT },
+	{ "csi2_2.clk_ui", MIPI_CSI2_PHY_REF_CLK_ROOT, 102 },
+
+	{ "csu.ipg_clk_s", IPG_CLK_ROOT, 3},
+
+	{ "dap.dapclk_2_2", AHB_CLK_ROOT, 4},
+
+	{ "ecspi1.ipg_clk", IPG_CLK_ROOT, 7},
+	{ "ecspi1.ipg_clk_per", ECSPI1_CLK_ROOT, 7},
+	{ "ecspi1.ipg_clk_s", IPG_CLK_ROOT, 7},
+
+	{ "ecspi2.ipg_clk", IPG_CLK_ROOT, 8},
+	{ "ecspi2.ipg_clk_per", ECSPI2_CLK_ROOT, 8},
+	{ "ecspi2.ipg_clk_s", IPG_CLK_ROOT, 8},
+
+	{ "ecspi2.ipg_clk", IPG_CLK_ROOT, 8},
+	{ "ecspi2.ipg_clk_per", ECSPI2_CLK_ROOT, 8},
+	{ "ecspi2.ipg_clk_s", IPG_CLK_ROOT, 8},
+
+	{ "ecspi3.ipg_clk", IPG_CLK_ROOT, 9},
+	{ "ecspi3.ipg_clk_per", ECSPI3_CLK_ROOT, 9},
+	{ "ecspi3.ipg_clk_s", IPG_CLK_ROOT, 9},
+
+	{ "enet1.ipp_ind_mac0_txclk", ENET_REF_CLK_ROOT, 10 },
+	{ "enet1.ipg_clk", ENET_AXI_CLK_ROOT, 10 },
+	{ "enet1.ipg_clk_mac0", ENET_AXI_CLK_ROOT, 10 },
+	{ "enet1.ipg_clk_mac0_s", ENET_AXI_CLK_ROOT, 10 },
+	{ "enet1.ipg_clk_s", ENET_AXI_CLK_ROOT, 10 },
+	{ "enet1.ipg_clk_time", ENET_TIMER_CLK_ROOT, 10 },
+	{ "enet1.mem.mac0_rxmem_clk", ENET_AXI_CLK_ROOT, 10 },
+	{ "enet1.mem.mac0_txmem_clk", ENET_AXI_CLK_ROOT, 10 },
+
+	{ "gpio1.ipg_clk_s", IPG_CLK_ROOT, 11 },
+	{ "gpio2.ipg_clk_s", IPG_CLK_ROOT, 12 },
+	{ "gpio3.ipg_clk_s", IPG_CLK_ROOT, 13 },
+	{ "gpio4.ipg_clk_s", IPG_CLK_ROOT, 14 },
+	{ "gpio5.ipg_clk_s", IPG_CLK_ROOT, 15 },
+
+	{ "gpt1.ipg_clk", GPT1_CLK_ROOT, 16 },
+	{ "gpt1.ipg_clk_highfreq", GPT1_CLK_ROOT, 16 },
+	{ "gpt1.ipg_clk_s", GPT1_CLK_ROOT, 16 },
+
+	{ "gpt2.ipg_clk", GPT2_CLK_ROOT, 17 },
+	{ "gpt2.ipg_clk_highfreq", GPT2_CLK_ROOT, 17 },
+	{ "gpt2.ipg_clk_s", GPT2_CLK_ROOT, 17 },
+
+	{ "gpt3.ipg_clk", GPT3_CLK_ROOT, 18 },
+	{ "gpt3.ipg_clk_highfreq", GPT3_CLK_ROOT, 18 },
+	{ "gpt3.ipg_clk_s", GPT3_CLK_ROOT, 18 },
+
+	{ "gpt4.ipg_clk", GPT4_CLK_ROOT, 19 },
+	{ "gpt4.ipg_clk_highfreq", GPT4_CLK_ROOT, 19 },
+	{ "gpt4.ipg_clk_s", GPT4_CLK_ROOT, 19 },
+
+	{ "gpt5.ipg_clk", GPT5_CLK_ROOT, 20 },
+	{ "gpt5.ipg_clk_highfreq", GPT5_CLK_ROOT, 20 },
+	{ "gpt5.ipg_clk_s", GPT5_CLK_ROOT, 20 },
+
+	{ "gpt6.ipg_clk", GPT6_CLK_ROOT, 21 },
+	{ "gpt6.ipg_clk_highfreq", GPT6_CLK_ROOT, 21 },
+	{ "gpt6.ipg_clk_s", GPT6_CLK_ROOT, 21 },
+
+	{ "i2c1.ipg_clk_patref", I2C1_CLK_ROOT, 23 },
+	{ "i2c1.iph_clk_s", I2C1_CLK_ROOT, 23 },
+
+	{ "i2c2.ipg_clk_patref", I2C2_CLK_ROOT, 24 },
+	{ "i2c2.iph_clk_s", I2C2_CLK_ROOT, 24 },
+
+	{ "i2c3.ipg_clk_patref", I2C3_CLK_ROOT, 25 },
+	{ "i2c3.iph_clk_s", I2C3_CLK_ROOT, 25 },
+
+	{ "i2c4.ipg_clk_patref", I2C4_CLK_ROOT, 26 },
+	{ "i2c4.iph_clk_s", I2C4_CLK_ROOT, 26 },
+
+	{ "iomuxc.ipg_clk_s", IPG_CLK_ROOT, 27 },
+	{ "iomuxc_gpr.ipg_clk_s", IPG_CLK_ROOT, 27 },
+	{ "iomux.ipt_clk_io", IPG_CLK_ROOT, 27 },
+
+	{ "lcdif.pix_clk", LCDIF_PIXEL_CLK_ROOT },
+	{ "lcdif.apb_clk", MAIN_AXI_CLK_ROOT },
+
+	{ "disp.apb_clk", DISPLAY_APB_CLK_ROOT, 93 },
+	{ "disp.axi_clk", DISPLAY_AXI_CLK_ROOT, 93 },
+	{ "disp.rtrm_clk", DISPLAY_RTRM_CLK_ROOT, 93 },
+	{ "disp.dc8000_clk", DISPLAY_DC8000_CLK_ROOT, 93 },
+	{ "disp.dtrc_clk", DISPLAY_DTRC_CLK_ROOT },
+
+	{ "mipi.CLKREF", MIPI_DSI_PHY_REF_CLK_ROOT },
+	{ "mipi.pclk", MAIN_AXI_CLK_ROOT },
+	{ "mipi.RxClkEsc", MIPI_DSI_ESC_RX_CLK_ROOT },
+	{ "mipi.TxClkEsc", MIPI_DSI_ESC_CLK_ROOT },
+	{ "mipi.core", MIPI_DSI_CORE_CLK_ROOT },
+	{ "mipi.ahb", MIPI_DSI_ESC_RX_CLK_ROOT },
+
+	{ "mu.ipg_clk_dsp", IPG_CLK_ROOT, 33 },
+	{ "mu.ipg_clk_mcu", IPG_CLK_ROOT, 33 },
+	{ "mu.ipg_clk_s_dsp", IPG_CLK_ROOT, 33 },
+	{ "mu.ipg_clk_s_mcu", IPG_CLK_ROOT, 33 },
+
+	{ "ocotp.ipg_clk", IPG_CLK_ROOT, 34 },
+	{ "ocotp.ipg_clk_s", IPG_CLK_ROOT, 34 },
+
+	{ "ocram_ctrl.clk", MAIN_AXI_CLK_ROOT, 35 },
+	{ "ocram_excs.aclk_exsc", MAIN_AXI_CLK_ROOT, 35 },
+	{ "ocram_exsc.ipg_clk", IPG_CLK_ROOT, 35 },
+	{ "ocram_mem.clk", MAIN_AXI_CLK_ROOT, 35 },
+
+	{ "ocram_ctrl_s.clk", AHB_CLK_ROOT, 36 },
+	{ "ocram_s_exsc.aclk_exsc", AHB_CLK_ROOT, 36 },
+	{ "ocram_s_exsc.ipg_clk", IPG_CLK_ROOT, 36 },
+	{ "ocram_s.mem_clk", AHB_CLK_ROOT, 36 },
+
+	{ "pcie_clk_rst.auxclk", PCIE1_AUX_CLK_ROOT, 37 },
+	{ "pcie_clk_rst.mstr_axi_clk", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_clk_rst.slv_axi_clk", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_ctrl.mstr_aclk", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_ctrl.slv_aclk", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_exsc.aclk_exsc", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_exsc.ipg_clk", IPG_CLK_ROOT, 37 },
+	{ "pcie_mem.mstr_axi_clk", MAIN_AXI_CLK_ROOT, 37 },
+	{ "pcie_mem.slv_axi_clk", MAIN_AXI_CLK_ROOT, 37 },
+
+	{ "pcie2_clk_rst.auxclk", PCIE2_AUX_CLK_ROOT, 100 },
+	{ "pcie2_clk_rst.mstr_axi_clk", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_clk_rst.slv_axi_clk", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_ctrl.mstr_aclk", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_ctrl.slv_aclk", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_exsc.aclk_exsc", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_exsc.ipg_clk", IPG_CLK_ROOT, 100 },
+	{ "pcie2_mem.mstr_axi_clk", MAIN_AXI_CLK_ROOT, 100 },
+	{ "pcie2_mem.slv_axi_clk", MAIN_AXI_CLK_ROOT, 100 },
+
+	{ "pcie_phy.ref_alt_clk_p", PCIE1_PHY_CLK_ROOT },
+	{ "pcie2_phy.ref_alt_clk_p", PCIE2_PHY_CLK_ROOT },
+
+	{ "perfmon1.apb_clk", IPG_CLK_ROOT, 38 },
+	{ "perfmon1.axi0_ACLK", MAIN_AXI_CLK_ROOT, 38 },
+
+	{ "perfmon2.apb_clk", IPG_CLK_ROOT, 39 },
+	{ "perfmon1.axi0_ACLK", MAIN_AXI_CLK_ROOT, 39 },
+
+	{ "pwm1.ipg_clk", PWM1_CLK_ROOT, 40 },
+	{ "pwm1.ipg_clk_high_freq", PWM1_CLK_ROOT, 40 },
+	{ "pwm1.ipg_clk_s", PWM1_CLK_ROOT, 40 },
+
+	{ "pwm2.ipg_clk", PWM2_CLK_ROOT, 41 },
+	{ "pwm2.ipg_clk_high_freq", PWM2_CLK_ROOT, 41 },
+	{ "pwm2.ipg_clk_s", PWM2_CLK_ROOT, 41 },
+
+	{ "pwm3.ipg_clk", PWM3_CLK_ROOT, 42 },
+	{ "pwm3.ipg_clk_high_freq", PWM3_CLK_ROOT, 42 },
+	{ "pwm3.ipg_clk_s", PWM3_CLK_ROOT, 42 },
+	
+	{ "pwm4.ipg_clk", PWM4_CLK_ROOT, 43 },
+	{ "pwm4.ipg_clk_high_freq", PWM4_CLK_ROOT, 43 },
+	{ "pwm4.ipg_clk_s", PWM4_CLK_ROOT, 43 },
+
+	{ "qspi.ahb_clk", AHB_CLK_ROOT, 47 },
+	{ "qspi.ipg_clk", IPG_CLK_ROOT, 47 },
+	{ "qspi.ipg_clk_4xsfif", QSPI_CLK_ROOT, 47 },
+	{ "qspi.ipg_clk_s", IPG_CLK_ROOT, 47 },
+	{ "qspi_sec.ipg_clk", IPG_CLK_ROOT, 47 },
+	{ "qspi_sec.ipg_clk_s", IPG_CLK_ROOT, 47 },
+	{ "qspi_sec.mst_hclk", AHB_CLK_ROOT, 47 },
+
+	{ "rdc.ipg_clk_s", IPG_CLK_ROOT, 49 },
+	{ "rdc.ipg_clk", IPG_CLK_ROOT, 49 },
+	{ "rdc_mem.ipg_clk", IPG_CLK_ROOT, 49 },
+
+	{ "romcp.hclk", AHB_CLK_ROOT, 50 },
+	{ "romcp.hclk_reg", IPG_CLK_ROOT, 50 },
+	{ "romcp_mem.rom_CLK", AHB_CLK_ROOT, 50 },
+	{ "romcp_sec.mst_hclk", AHB_CLK_ROOT, 50 },
+
+	{ "sai1.ipg_clk", AUDIO_IPG_CLK_ROOT, 51 },
+	{ "sai1.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 51 },
+	{ "sai1.ipg_clk_sai_mclk_1", SAI1_CLK_ROOT, 51 },
+	{ "sai1.ipt_clk_sai_bclk", SAI1_CLK_ROOT, 51 },
+	{ "sai1.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 51 },
+
+	{ "sai2.ipg_clk", AUDIO_IPG_CLK_ROOT, 52 },
+	{ "sai2.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 52 },
+	{ "sai2.ipg_clk_sai_mclk_1", SAI2_CLK_ROOT, 52 },
+	{ "sai2.ipt_clk_sai_bclk", SAI2_CLK_ROOT, 52 },
+	{ "sai2.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 52 },
+
+	{ "sai3.ipg_clk", AUDIO_IPG_CLK_ROOT, 53 },
+	{ "sai3.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 53 },
+	{ "sai3.ipg_clk_sai_mclk_1", SAI3_CLK_ROOT, 53 },
+	{ "sai3.ipt_clk_sai_bclk", SAI3_CLK_ROOT, 53 },
+	{ "sai3.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 53 },
+
+	{ "sai4.ipg_clk", AUDIO_IPG_CLK_ROOT, 54 },
+	{ "sai4.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 54 },
+	{ "sai4.ipg_clk_sai_mclk_1", SAI4_CLK_ROOT, 54 },
+	{ "sai4.ipt_clk_sai_bclk", SAI4_CLK_ROOT, 54 },
+	{ "sai4.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 54 },
+
+	{ "sai5.ipg_clk", AUDIO_IPG_CLK_ROOT, 55 },
+	{ "sai5.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 55 },
+	{ "sai5.ipg_clk_sai_mclk_1", SAI5_CLK_ROOT, 55 },
+	{ "sai5.ipt_clk_sai_bclk", SAI5_CLK_ROOT, 55 },
+	{ "sai5.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 55 },
+
+	{ "sai6.ipg_clk", AUDIO_IPG_CLK_ROOT, 56 },
+	{ "sai6.ipg_clk_s", AUDIO_IPG_CLK_ROOT, 56 },
+	{ "sai6.ipg_clk_sai_mclk_1", SAI6_CLK_ROOT, 56 },
+	{ "sai6.ipt_clk_sai_bclk", SAI6_CLK_ROOT, 56 },
+	{ "sai6.ipt_clk_sai_bclk_b", SAI1_CLK_ROOT, 56 },
+
+	{ "sctr.ipg_clk", IPG_CLK_ROOT, 57 },
+	{ "sctr.ipg_clk_s", IPG_CLK_ROOT, 57 },
+
+	{ "sdma1.ips_hostctrl_clk", IPG_CLK_ROOT, 58 },
+	{ "sdma1.sdma_ap_ahb_clk", AHB_CLK_ROOT, 58 },
+	{ "sdma1.sdma_core_clk", IPG_CLK_ROOT, 58 },
+
+	{ "sdma2.ips_hostctrl_clk", AUDIO_IPG_CLK_ROOT, 59 },
+	{ "sdma2.sdma_ap_ahb_clk", AUDIO_AHB_CLK_ROOT, 59 },
+	{ "sdma2.sdma_core_clk", AUDIO_IPG_CLK_ROOT, 59 },
+
+	{ "sec_wrapper.clk", IPG_CLK_ROOT, 60 },
+
+	{ "sema1.clk", IPG_CLK_ROOT, 61 },
+	{ "sema2.clk", IPG_CLK_ROOT, 62 },
+
+	{ "sim_display.cm4clk", ARM_M4_CLK_ROOT },
+	{ "sim_display.mainclk", MAIN_AXI_CLK_ROOT, 63 },
+	{ "sim_display.mainclk_r", MAIN_AXI_CLK_ROOT, 63 },
+	{ "sim_enet.mainclk", ENET_AXI_CLK_ROOT, 64 },
+	{ "sim_enet.mainclk_r", ENET_AXI_CLK_ROOT, 64 },
+	{ "sim_m.mainclk", AHB_CLK_ROOT, 65 },
+	{ "sim_m.mainclk_r", AHB_CLK_ROOT, 65 },
+	{ "sim_m.usdhcclk", NAND_USDHC_BUS_CLK_ROOT, 65 },
+	{ "sim_m.usdhcclk_r", NAND_USDHC_BUS_CLK_ROOT, 65 },
+	{ "sim_main.cm4clk", ARM_M4_CLK_ROOT },
+	{ "sim_main.enetclk", ENET_AXI_CLK_ROOT, 64 },
+	{ "sim_main.mainclk", MAIN_AXI_CLK_ROOT, 66 },
+	{ "sim_main,mainclk_r", MAIN_AXI_CLK_ROOT, 66 },
+	{ "sim_main.per_mclk", AHB_CLK_ROOT, 65 },
+	{ "sim_main.per_sclk", AHB_CLK_ROOT, 67 },
+	{ "sim_main.usdhcclk", NAND_USDHC_BUS_CLK_ROOT, 65 },
+	{ "sim_main.wakeupclk", AHB_CLK_ROOT, 68 },
+	{ "sim_s.apbhdmaclk", NAND_USDHC_BUS_CLK_ROOT, 48 },
+	{ "sim_s.gpv4clk", ENET_AXI_CLK_ROOT, 64 },
+	{ "sim_s.mainclk", AHB_CLK_ROOT, 67 },
+	{ "sim_s.mainclk_r", AHB_CLK_ROOT, 67 },
+	{ "sim_s.weimclk", AHB_CLK_ROOT },
+	{ "sim_wakeup.mainclk", AHB_CLK_ROOT, 68 },
+	{ "sim_wakeup.mainclk_r", AHB_CLK_ROOT, 68 },
+	{ "pl301_audio.displayclk", MAIN_AXI_CLK_ROOT, 63 },
+
+	{ "snvs_hs_wrapper.ipg_clk", IPG_CLK_ROOT, 71 },
+	{ "snvs_hs.wrapper.ipg_clk_s", IPG_CLK_ROOT, 71 },
+	{ "snvsmix.ipg_clk_root", IPG_CLK_ROOT },
+
+	{ "spba1.ipg_clk", IPG_CLK_ROOT, 30 },
+	{ "spba1.ipg_clk_s", IPG_CLK_ROOT, 30 },
+
+	{ "spba2.ipg_clk", AUDIO_IPG_CLK_ROOT },
+	{ "spba2.ipg_clk_s", AUDIO_IPG_CLK_ROOT },
+
+	{ "spdif1.gclkw_t0", SPDIF1_CLK_ROOT},
+	{ "spdif1.ipg_clk_s", IPG_CLK_ROOT},
+	{ "spdif1.tx_clk", SPDIF1_CLK_ROOT},
+	{ "spdif1.tx_clk1", SPDIF1_CLK_ROOT},
+	{ "spdif1.tx_clk3", SPDIF1_CLK_ROOT},
+	{ "spdif1.tx_clk4", SPDIF1_CLK_ROOT},
+	{ "spdif1.tx_clk5", SPDIF1_CLK_ROOT},
+
+	{ "spdif2.gclkw_t0", SPDIF2_CLK_ROOT},
+	{ "spdif2.ipg_clk_s", IPG_CLK_ROOT},
+	{ "spdif2.tx_clk", SPDIF2_CLK_ROOT},
+	{ "spdif2.tx_clk1", SPDIF2_CLK_ROOT},
+	{ "spdif2.tx_clk3", SPDIF2_CLK_ROOT},
+	{ "spdif2.tx_clk4", SPDIF2_CLK_ROOT},
+	{ "spdif2.tx_clk5", SPDIF2_CLK_ROOT},
+
+	{ "coresight.DBGCLK", MAIN_AXI_CLK_ROOT, 72 },
+	{ "coresight.traceclkin", TRACE_CLK_ROOT, 72 },
+	{ "coresight_mem.cs_etf_clk", MAIN_AXI_CLK_ROOT, 72 },
+
+	{ "uart1.ipg_clk", IPG_CLK_ROOT, 73 },
+	{ "uart1.ipg_clk_s", IPG_CLK_ROOT, 73 },
+	{ "uart1.ipg_perclk", UART1_CLK_ROOT, 73 },
+
+	{ "uart2.ipg_clk", IPG_CLK_ROOT, 74 },
+	{ "uart2.ipg_clk_s", IPG_CLK_ROOT, 74 },
+	{ "uart2.ipg_perclk", UART2_CLK_ROOT, 74 },
+
+	{ "uart3.ipg_clk", IPG_CLK_ROOT, 75 },
+	{ "uart3.ipg_clk_s", IPG_CLK_ROOT, 75 },
+	{ "uart3.ipg_perclk", UART3_CLK_ROOT, 75 },
+
+	{ "uart4.ipg_clk", IPG_CLK_ROOT, 76 },
+	{ "uart4.ipg_clk_s", IPG_CLK_ROOT, 76 },
+	{ "uart4.ipg_perclk", UART4_CLK_ROOT, 76 },
+
+	{ "usb.clk", IPG_CLK_ROOT, 22 },	/* HS */
+
+	{ "usb1.ctrl", IPG_CLK_ROOT, 77 },	/* what is the root clock? */
+	{ "usb2.ctrl", IPG_CLK_ROOT, 78 },
+	{ "usb1.phy", IPG_CLK_ROOT, 79 },	/* what is the root clock? */
+	{ "usb2.phy", IPG_CLK_ROOT, 80 },
+
+	{ "usdhc1.hclk", NAND_USDHC_BUS_CLK_ROOT, 81 },
+	{ "usdhc1.ipg_clk", IPG_CLK_ROOT, 81 },
+	{ "usdhc1.ipg_clk_s", IPG_CLK_ROOT, 81 },
+	{ "usdhc1.ipg_clk_perclk", USDHC1_CLK_ROOT, 81 },
+
+	{ "usdhc2.hclk", NAND_USDHC_BUS_CLK_ROOT, 82 },
+	{ "usdhc2.ipg_clk", IPG_CLK_ROOT, 82 },
+	{ "usdhc2.ipg_clk_s", IPG_CLK_ROOT, 82 },
+	{ "usdhc2.ipg_clk_perclk", USDHC2_CLK_ROOT, 82 },
+
+	{ "wdog1.ipg_clk", WDOG_CLK_ROOT, 83 },
+	{ "wdog1.ipg_clk_s", WDOG_CLK_ROOT, 83 },
+
+	{ "wdog2.ipg_clk", WDOG_CLK_ROOT, 84 },
+	{ "wdog2.ipg_clk_s", WDOG_CLK_ROOT, 84 },
+
+	{ "wdog3.ipg_clk", WDOG_CLK_ROOT, 85 },
+	{ "wdog3.ipg_clk_s", WDOG_CLK_ROOT, 85 },
+
+	{ 0 }
+};
+
+static void
+enablefracpll(u32int *reg, int ref_sel, int ref_freq, int freq)
+{
+	int divq, divr, ref, divfi, divff, pllout, error;
+	u32int cfg0, cfg1;
+	vlong v;
+
+	cfg0 = reg[0];
+	cfg1 = reg[1];
+
+	error = freq;
+	for(divq = 2; divq <= 64; divq += 2){
+		for(divr = 1; divr <= 64; divr++){
+			ref = ref_freq/divr;
+			if(ref < 10*Mhz || ref > 300*Mhz)
+				continue;
+
+			ref *= 8;
+			divfi = ((vlong)freq*divq) / ref;
+			if(divfi < 1 || divfi > 32)
+				continue;
+
+			v = ((vlong)freq*divq) - (vlong)ref*divfi;
+			divff = (v<<24) / ref;
+			if(divff < 1 || divff > (1<<24))
+				continue;
+
+			v = (vlong)ref*(vlong)divff;
+			pllout = (ref*divfi + (v>>24))/divq;
+			if(pllout < 30*Mhz || pllout > 2000*Mhz)
+				continue;
+
+			if(pllout > freq)
+				continue;
+
+			if(freq - pllout > error)
+				continue;
+
+// iprint("%p enablefracpll: freq=%d (actual %d)\n", PADDR(reg), freq, pllout);
+
+			cfg0 = 1<<21 | ref_sel<<16 | 1<<15 | (divr-1)<<5 | (divq/2)-1;
+			cfg1 = divff<<7 | divfi-1;
+
+			error = freq - pllout;
+			if(error == 0)
+				goto Found;
+		}
+	}
+
+Found:
+	/* skip if nothing has changed */
+	if(((reg[0] ^ cfg0) & (1<<21 | 3<<16 | 1<<15 | 0x3F<<5 | 0x1F)) == 0
+	&& ((reg[1] ^ cfg1) & ~(1<<31)) == 0)
+		return;
+
+	reg[0] |= 1<<14;	/* bypass */
+
+// iprint("%p cfg1=%.8ux\n", PADDR(reg), cfg1);
+	reg[1] = cfg1;
+
+// iprint("%p cfg0=%.8ux\n", PADDR(reg), cfg0);
+	reg[0] = cfg0 | (1<<14) | (1<<12);
+
+	/* unbypass */
+	reg[0] &= ~(1<<14);
+
+// iprint("%p wait for lock...", PADDR(reg));
+	while((reg[0] & (1<<31)) == 0)
+		;
+// iprint("locked!\n");
+	reg[0] &= ~(1<<12);
+}
+
+static void
+enablepll(int input)
+{
+	u32int old, val = 2;
+
+	if(input < 0 || input > 38 || input_clk_freq[input] <= 0)
+		return;
+
+	/* CCM_PLL_CTRL */
+	old = regs[(0x800/4) + (16/4)*input] & 3;
+	if(old < val){
+// iprint("ccm: %s PLL_CTRL%d %.ux->%.ux\n", input_clk_name[input], input, old, val);
+		regs[(0x800/4) + (16/4)*input] = val;
+	}
+
+	switch(input){
+	case AUDIO_PLL1_CLK:
+		enablefracpll(&anatop[0x00/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	case AUDIO_PLL2_CLK:
+		enablefracpll(&anatop[0x08/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	case VIDEO_PLL1_CLK:
+		enablefracpll(&anatop[0x10/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	case GPU_PLL_CLK:
+		enablefracpll(&anatop[0x18/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	case VPU_PLL_CLK:
+		enablefracpll(&anatop[0x20/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	case ARM_PLL_CLK:
+		enablefracpll(&anatop[0x28/4], 0, 25*Mhz, input_clk_freq[input]);
+		break;
+	}
+}
+
+static u32int
+clkgate(Clock *gate, u32int val)
+{
+	u32int old;
+
+	if(gate == nil || gate->ccgr == 0)
+		return 0;
+
+	/* CCM_CCGR */
+	old = regs[(0x4000/4) + (16/4)*gate->ccgr] & 3;
+	if(old != val){
+// if(gate->ccgr != 73) iprint("ccm: %s CCGR%d %.ux->%.ux\n", gate->name, gate->ccgr, old, val);
+		regs[(0x4000/4) + (16/4)*gate->ccgr] = val;
+	}
+	return old;
+}
+
+static int
+rootclkisipg(int root)
+{
+	switch(root){
+	case IPG_CLK_ROOT:
+	case AUDIO_IPG_CLK_ROOT:
+	case MIPI_DSI_ESC_CLK_ROOT:
+		return 1;
+	}
+	return 0;
+}
+
+static u32int
+gettarget(int root)
+{
+	u32int val = regs[(0x8000/4) + (128/4)*root];
+// if(root != UART1_CLK_ROOT) iprint("ccm: %s TARGET_ROOT%d -> %.8ux\n", root_clk_name[root], root, val);
+	return val;
+}
+
+static void
+settarget(int root, Clock *gate, u32int val)
+{
+	if(gate != nil){
+		for(; gate->name != nil; gate++){
+			u32int old;
+
+			if(gate->root != root)
+				continue;
+
+			old = clkgate(gate, 0);
+			if(old == 0)
+				continue;
+
+			/* skip restore when root is being disabled */
+			if((val & (1<<28)) == 0)
+				continue;
+
+			/* now change the root clock target */
+			settarget(root, gate+1, val);
+
+			/* restore gate */
+			clkgate(gate, old);
+			return;
+		}
+	}
+
+	if(rootclkisipg(root))
+		val &= ~(1<<28);
+// if(root != UART1_CLK_ROOT) iprint("ccm: %s TARGET_ROOT%d <- %.8ux\n", root_clk_name[root], root, val);
+	regs[(0x8000/4) + (128/4)*root] = val;
+}
+
+static int
+rootclkgetcfg(int root, int *input)
+{
+	u32int t = gettarget(root);
+	int freq = input_clk_freq[*input = root_clk_input_mux[root*8 + ((t >> 24)&7)]];
+	int pre_podf = (t >> 16)&7;
+	int post_podf = (t >> 0)&0x3F;
+
+	/* return negative frequency if disabled */
+	if((t & (1<<28)) == 0)
+		freq = -freq;
+
+	switch(root){
+	case ARM_A53_CLK_ROOT:
+	case ARM_M4_CLK_ROOT:
+	case VPU_A53_CLK_ROOT:
+	case GPU_CORE_CLK_ROOT:
+	case GPU_SHADER_CLK_ROOT:
+		post_podf &= 7;
+		/* wet floor */
+	case GPU_AXI_CLK_ROOT:
+	case GPU_AHB_CLK_ROOT:
+	case NOC_CLK_ROOT:
+		pre_podf = 0;
+		break;
+	case IPG_CLK_ROOT:
+	case AUDIO_IPG_CLK_ROOT:
+		post_podf &= 1;
+	case MIPI_DSI_ESC_CLK_ROOT:
+		freq = rootclkgetcfg(root-1, input);
+		/* wet floor */
+	case AHB_CLK_ROOT:
+	case AUDIO_AHB_CLK_ROOT:
+	case MIPI_DSI_ESC_RX_CLK_ROOT:
+		pre_podf = 0;
+		break;
+	}
+	freq /= pre_podf+1;
+	freq /= post_podf+1;
+
+	return freq;
+}
+
+static void
+rootclksetcfg(int root, int input, int freq)
+{
+	u32int t = gettarget(root);
+
+	if(!rootclkisipg(root)){
+		int mux;
+
+		for(mux = 0; mux < 8; mux++){
+			if(root_clk_input_mux[root*8 + mux] == input){
+				t = (t & ~(7<<24)) | (mux << 24);
+				goto Muxok;
+			}
+		}
+		panic("rootclksetcfg: invalid input clock %d for TARGET_ROOT%d\n", input, root);
+Muxok:;
+	}
+	/* disable by default */
+	t &= ~(1 << 28);
+
+	if(freq){
+		int pre_mask, pre_podf, post_mask, post_podf;
+		int error, input_freq = input_clk_freq[input];
+
+		if(freq < 0) {
+			/* set dividers but keep disabled */
+			freq = -freq;
+		} else {
+			/* set dividers and enable */
+			t |= (1 << 28);
+		}
+
+		pre_mask = 7;
+		post_mask = 0x3F;
+
+		switch(root){
+		case ARM_A53_CLK_ROOT:
+		case ARM_M4_CLK_ROOT:
+		case VPU_A53_CLK_ROOT:
+		case GPU_CORE_CLK_ROOT:
+		case GPU_SHADER_CLK_ROOT:
+			post_mask = 7;
+			/* wet floor */
+		case GPU_AXI_CLK_ROOT:
+		case GPU_AHB_CLK_ROOT:
+		case NOC_CLK_ROOT:
+			pre_mask = 0;
+			break;
+		case IPG_CLK_ROOT:
+		case AUDIO_IPG_CLK_ROOT:
+			post_mask = 1;
+		case MIPI_DSI_ESC_CLK_ROOT:
+			input_freq = rootclkgetcfg(root-1, &input);
+			/* wet floor */
+		case AHB_CLK_ROOT:
+		case AUDIO_AHB_CLK_ROOT:
+		case MIPI_DSI_ESC_RX_CLK_ROOT:
+			pre_mask = 0;
+			break;
+		}
+		if(input_freq < 0) input_freq = -input_freq;
+
+
+		error = freq;
+		for(pre_podf = 0; pre_podf <= pre_mask; pre_podf++){
+			for(post_podf = 0; post_podf <= post_mask; post_podf++){
+				int f = input_freq;
+				f /= pre_podf+1;
+				f /= post_podf+1;
+				if(f <= freq && (freq - f) < error){
+					t = (t & ~(7<<16)) | (pre_podf << 16);
+					t = (t & ~0x3F) | post_podf;
+					error = freq - f;
+					if(error == 0)
+						break;
+				}
+			}
+		}
+		if(error >= freq)
+			panic("rootclksetcfg: frequency %d invalid for TARGET_ROOT%d\n", freq, root);
+		if(t & (1<<28))
+			enablepll(input);
+	}
+	settarget(root, clocks, t);
+}
+
+static int
+lookinputclk(char *name)
+{
+	int i;
+
+	for(i = 0; i < nelem(input_clk_name); i++){
+		if(input_clk_name[i] != nil
+		&& cistrcmp(name, input_clk_name[i]) == 0)
+			return i;
+	}
+
+	return -1;
+}
+
+static Clock*
+lookmodclk(char *name)
+{
+	Clock *clk;
+
+	for(clk = clocks; clk->name != nil; clk++){
+		if(cistrcmp(name, clk->name) == 0)
+			return clk;
+	}
+
+	return nil;
+}
+
+static int
+lookrootclk(char *name)
+{
+	Clock *clk;
+	int i;
+
+	for(i = 0; i < nelem(root_clk_name); i++){
+		if(root_clk_name[i] != nil
+		&& cistrcmp(name, root_clk_name[i]) == 0)
+			return i;
+	}
+
+	if((clk = lookmodclk(name)) != nil)
+		return clk->root;
+
+	return -1;
+}
+
+void
+setclkgate(char *name, int on)
+{
+	clkgate(lookmodclk(name), on ? 3 : 0);
+}
+
+void
+setclkrate(char *name, char *source, int freq)
+{
+	int root, input;
+
+	if((root = lookrootclk(name)) < 0)
+		panic("setclkrate: clock %s not defined", name);
+	if(source == nil)
+		rootclkgetcfg(root, &input);
+	else {
+		if((input = lookinputclk(source)) < 0)
+			panic("setclkrate: input clock %s not defined", source);
+	}
+	rootclksetcfg(root, input, freq);
+}
+
+int
+getclkrate(char *name)
+{
+	int root, input;
+
+	if((root = lookrootclk(name)) >= 0)
+		return rootclkgetcfg(root, &input);
+
+	if((input = lookinputclk(name)) > 0)
+		return input_clk_freq[input];
+
+	panic("getclkrate: clock %s not defined", name);
+	return -1;
+}
--- a/sys/src/9/imx8/etherimx.c
+++ b/sys/src/9/imx8/etherimx.c
@@ -688,6 +688,16 @@
 	edev->mbps = 1000;
 	edev->maxmtu = Maxtu;
 
+	setclkgate("enet1.ipp_ind_mac0_txclk", 0);
+	setclkgate("sim_enet.mainclk", 0);
+
+	setclkrate("enet1.ipg_clk", "system_pll1_div3", 266*Mhz);
+	setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Moduleclk);
+	setclkrate("enet1.ipg_clk_time", "system_pll2_div10", 25*Mhz);
+
+	setclkgate("enet1.ipp_ind_mac0_txclk", 1);
+	setclkgate("sim_enet.mainclk", 1);
+
 	if(reset(edev) < 0)
 		return -1;
 
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -80,6 +80,7 @@
 extern void putasid(Proc*);
 
 extern void* ucalloc(usize);
+extern void* fbmemalloc(usize);
 
 /* clock */
 extern void clockinit(void);
@@ -138,3 +139,11 @@
 
 extern int isaconfig(char*, int, ISAConf*);
 extern void links(void);
+
+/* ccm */
+extern void setclkgate(char *name, int on);
+extern void setclkrate(char *name, char *source, int freq);
+extern int getclkrate(char *name);
+
+/* lcd */
+extern void lcdinit(void);
--- /dev/null
+++ b/sys/src/9/imx8/lcd.c
@@ -1,0 +1,949 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/i2c.h"
+
+#define	Image	IMAGE
+#include	<draw.h>
+#include	<memdraw.h>
+#include	<cursor.h>
+#include	"screen.h"
+
+extern Memimage *gscreen;
+
+/* pinmux registers */
+enum {
+	IOMUXC_CTL_PAD_SAI5_RXC = 0x144/4,	/* for gpio3 20 */
+	IOMUXC_CTL_PAD_SPDIF_RX = 0x1EC/4,	/* for pwm2 */
+	IOMUXC_CTL_PAD_GPIO1_IO10 = 0x50/4,	/* for gpio1 10 */
+		SION = 1<<4,
+		MUX_MODE = 7,
+
+	IOMUXC_GPR_GPR13	= 0x10034/4,	/* GPR13 for MIPI_MUX_SEL */
+		MIPI_MUX_SEL = 1<<2,
+		MIPI_MUX_INV = 1<<3,
+};
+
+/* gpio registers */
+enum {
+	GPIO_DR = 0x00/4,
+	GPIO_GDIR = 0x04/4,
+	GPIO_PSR = 0x08/4,
+	GPIO_ICR1 = 0x0C/4,
+	GPIO_ICR2 = 0x10/4,
+	GPIO_IMR = 0x14/4,
+	GPIO_ISR = 0x18/4,
+	GPIO_EDGE_SEL = 0x1C/4,
+};
+
+/* power gating controller registers */
+enum {
+	GPC_PGC_CPU_0_1_MAPPING	= 0xEC/4,
+	GPC_PGC_PU_PGC_SW_PUP_REQ = 0xF8/4,
+
+	GPC_A53_PU_PGC_PUP_STATUS0 = 0x1C4/4,
+	GPC_A53_PU_PGC_PUP_STATUS1 = 0x1C8/4,
+	GPC_A53_PU_PGC_PUP_STATUS2 = 0x1CC/4,
+		DISP_SW_PUP_REQ	= 1<<10,
+		HDMI_SW_PUP_REQ	= 1<<9,
+		MIPI_SW_PUP_REQ = 1<<0,
+};
+
+/* system reset controller registers */
+enum {
+	SRC_MIPIPHY_RCR = 0x28/4,
+		RCR_MIPI_DSI_PCLK_RESET_N	= 1<<5,
+		RCR_MIPI_DSI_ESC_RESET_N	= 1<<4,
+		RCR_MIPI_DSI_DPI_RESET_N	= 1<<3,
+		RCR_MIPI_DSI_RESET_N		= 1<<2,
+		RCR_MIPI_DSI_RESET_BYTE_N	= 1<<1,
+
+	SRC_DISP_RCR = 0x34/4,
+};
+
+/* pwm controller registers */
+enum {
+	Pwmsrcclk = 25*Mhz,
+
+	PWMCR = 0x00/4,
+		CR_FWM_1 = 0<<26,
+		CR_FWM_2 = 1<<26,
+		CR_FWM_3 = 2<<26,
+		CR_FWM_4 = 3<<26,
+
+		CR_STOPEN = 1<<25,
+		CR_DOZEN = 1<<24,
+		CR_WAITEN = 1<<23,
+		CR_DBGEN = 1<<22,
+		CR_BCTR = 1<<21,
+		CR_HCTR = 1<<20,
+
+		CR_POUTC = 1<<18,
+
+		CR_CLKSRC_OFF = 0<<16,
+		CR_CLKSRC_IPG = 1<<16,
+		CR_CLKSRC_HIGHFREQ = 2<<16,
+		CR_CLKSRC_32K = 3<<16,
+
+		CR_PRESCALER_SHIFT = 4,
+
+		CR_SWR = 1<<3,
+
+		CR_REPEAT_1 = 0<<1,
+		CR_REPEAT_2 = 1<<1,
+		CR_REPEAT_4 = 2<<1,
+		CR_REPEAT_8 = 3<<1,
+
+		CR_EN = 1<<0,
+
+	PWMSR = 0x04/4,
+	PWMIR = 0x08/4,
+	PWMSAR = 0x0C/4,
+		SAR_MASK = 0xFFFF,
+	PWMPR = 0x10/4,
+		PR_MASK = 0xFFFF,
+	PWMCNR = 0x14/4,
+		CNR_MASK = 0xFFFF,
+};
+
+/* dphy registers */
+enum {
+	DPHY_PD_PHY = 0x0/4,
+	DPHY_M_PRG_HS_PREPARE = 0x4/4,
+	DPHY_MC_PRG_HS_PREPARE = 0x8/4,
+	DPHY_M_PRG_HS_ZERO = 0xc/4,
+	DPHY_MC_PRG_HS_ZERO = 0x10/4,
+	DPHY_M_PRG_HS_TRAIL = 0x14/4,
+	DPHY_MC_PRG_HS_TRAIL = 0x18/4,
+	DPHY_PD_PLL = 0x1c/4,
+	DPHY_TST = 0x20/4,
+	DPHY_CN = 0x24/4,
+	DPHY_CM = 0x28/4,
+	DPHY_CO = 0x2c/4,
+	DPHY_LOCK = 0x30/4,
+	DPHY_LOCK_BYP = 0x34/4,
+	DPHY_RTERM_SEL = 0x38/4,
+	DPHY_AUTO_PD_EN = 0x3c/4,
+	DPHY_RXLPRP = 0x40/4,
+	DPHY_RXCDR = 0x44/4,
+	DPHY_RXHS_SETTLE = 0x48/4,	/* undocumented */
+};
+
+/* dsi-host registers */
+enum {
+	DSI_HOST_CFG_NUM_LANES = 0x0/4,
+	DSI_HOST_CFG_NONCONTINUOUS_CLK = 0x4/4,
+	DSI_HOST_CFG_AUTOINSERT_EOTP = 0x14/4,
+	DSI_HOST_CFG_T_PRE = 0x8/4,
+	DSI_HOST_CFG_T_POST = 0xc/4,
+	DSI_HOST_CFG_TX_GAP = 0x10/4,
+	DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP = 0x18/4,
+	DSI_HOST_CFG_HTX_TO_COUNT = 0x1c/4,
+	DSI_HOST_CFG_LRX_H_TO_COUNT = 0x20/4,
+	DSI_HOST_CFG_BTA_H_TO_COUNT = 0x24/4,
+	DSI_HOST_CFG_TWAKEUP = 0x28/4,
+
+	DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING = 0x208/4,
+	DSI_HOST_CFG_DPI_PIXEL_FORMAT = 0x20c/4,
+	DSI_HOST_CFG_DPI_VSYNC_POLARITY = 0x210/4,
+	DSI_HOST_CFG_DPI_HSYNC_POLARITY = 0x214/4,
+	DSI_HOST_CFG_DPI_VIDEO_MODE = 0x218/4,
+	DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL = 0x204/4,
+	DSI_HOST_CFG_DPI_HFP = 0x21c/4,
+	DSI_HOST_CFG_DPI_HBP = 0x220/4,
+	DSI_HOST_CFG_DPI_HSA = 0x224/4,
+	DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS = 0x228/4,
+	DSI_HOST_CFG_DPI_BLLP_MODE = 0x234/4,
+	DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP = 0x238/4,
+	DSI_HOST_CFG_DPI_VC = 0x240/4,
+	DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE = 0x200/4,
+	DSI_HOST_CFG_DPI_VACTIVE = 0x23c/4,
+	DSI_HOST_CFG_DPI_VBP = 0x22c/4,
+	DSI_HOST_CFG_DPI_VFP = 0x230/4,
+};
+
+/* lcdif registers */
+enum {
+	LCDIF_CTRL	= 0x00/4,
+	LCDIF_CTRL_SET	= 0x04/4,
+	LCDIF_CTRL_CLR	= 0x08/4,
+	LCDIF_CTRL_TOG	= 0x0C/4,
+		CTRL_SFTRST			= 1<<31,
+		CTRL_CLKGATE			= 1<<30,
+		CTRL_YCBCR422_INPUT		= 1<<29,
+		CTRL_READ_WEITEB		= 1<<28,
+		CTRL_WAIT_FOR_VSYNC_EDGE	= 1<<27,
+		CTRL_DATA_SHIFT_DIR		= 1<<26,
+		CTRL_SHIFT_NUM_BITS		= 0x1F<<21,
+		CTRL_DVI_MODE			= 1<<20,
+		CTRL_BYPASS_COUNT		= 1<<19,
+		CTRL_VSYNC_MODE			= 1<<18,
+		CTRL_DOTCLK_MODE		= 1<<17,
+		CTRL_DATA_SELECT		= 1<<16,
+
+		CTRL_INPUT_DATA_NO_SWAP		= 0<<14,
+		CTRL_INPUT_DATA_LITTLE_ENDIAN	= 0<<14,
+		CTRL_INPUT_DATA_BIG_ENDIAB	= 1<<14,
+		CTRL_INPUT_DATA_SWAP_ALL_BYTES	= 1<<14,
+		CTRL_INPUT_DATA_HWD_SWAP	= 2<<14,
+		CTRL_INPUT_DATA_HWD_BYTE_SWAP	= 3<<14,
+
+		CTRL_CSC_DATA_NO_SWAP		= 0<<12,
+		CTRL_CSC_DATA_LITTLE_ENDIAN	= 0<<12,
+		CTRL_CSC_DATA_BIG_ENDIAB	= 1<<12,
+		CTRL_CSC_DATA_SWAP_ALL_BYTES	= 1<<12,
+		CTRL_CSC_DATA_HWD_SWAP		= 2<<12,
+		CTRL_CSC_DATA_HWD_BYTE_SWAP	= 3<<12,
+
+		CTRL_LCD_DATABUS_WIDTH_16_BIT	= 0<<10,
+		CTRL_LCD_DATABUS_WIDTH_8_BIT	= 1<<10,
+		CTRL_LCD_DATABUS_WIDTH_18_BIT	= 2<<10,
+		CTRL_LCD_DATABUS_WIDTH_24_BIT	= 3<<10,
+
+		CTRL_WORD_LENGTH_16_BIT		= 0<<8,
+		CTRL_WORD_LENGTH_8_BIT		= 1<<8,
+		CTRL_WORD_LENGTH_18_BIT		= 2<<8,
+		CTRL_WORD_LENGTH_24_BIT		= 3<<8,
+
+		CTRL_RGB_TO_YCBCR422_CSC	= 1<<7,
+
+		CTRL_MASTER			= 1<<5,
+
+		CTRL_DATA_FORMAT_16_BIT		= 1<<3,
+		CTRL_DATA_FORMAT_18_BIT		= 1<<2,
+		CTRL_DATA_FORMAT_24_BIT		= 1<<1,
+
+		CTRL_RUN			= 1<<0,
+
+	LCDIF_CTRL1	= 0x10/4,
+	LCDIF_CTRL1_SET	= 0x14/4,
+	LCDIF_CTRL1_CLR	= 0x18/4,
+	LCDIF_CTRL1_TOG	= 0x1C/4,
+		CTRL1_COMBINE_MPU_WR_STRB	= 1<<27,
+		CTRL1_BM_ERROR_IRQ_EN		= 1<<26,
+		CTRL1_BM_ERROR_IRQ		= 1<<25,
+		CTRL1_RECOVER_ON_UNDERFLOW	= 1<<24,
+
+		CTRL1_INTERLACE_FIELDS		= 1<<23,
+		CTRL1_START_INTERLACE_FROM_SECOND_FIELD	= 1<<22,
+
+		CTRL1_FIFO_CLEAR		= 1<<21,
+		CTRL1_IRQ_ON_ALTERNATE_FIELDS	= 1<<20,
+
+		CTRL1_BYTE_PACKING_FORMAT	= 0xF<<16,
+
+		CTRL1_OVERFLOW_IRQ_EN		= 1<<15,
+		CTRL1_UNDERFLOW_IRQ_EN		= 1<<14,
+		CTRL1_CUR_FRAME_DONE_IRQ_EN	= 1<<13,
+		CTRL1_VSYNC_EDGE_IRQ_EN		= 1<<12,
+		CTRL1_OVERFLOW_IRQ		= 1<<11,
+		CTRL1_UNDERFLOW_IRQ		= 1<<10,
+		CTRL1_CUR_FRAME_DONE_IRQ	= 1<<9,
+		CTRL1_VSYNC_EDGE_IRQ		= 1<<8,
+
+		CTRL1_BUSY_ENABLE		= 1<<2,
+		CTRL1_MODE86			= 1<<1,
+		CTRL1_RESET			= 1<<0,
+
+	LCDIF_CTRL2	= 0x20/4,
+	LCDIF_CTRL2_SET	= 0x24/4,
+	LCDIF_CTRL2_CLR	= 0x28/4,
+	LCDIF_CTRL2_TOG	= 0x2C/4,
+		CTRL2_OUTSTANDING_REQS_REQ_1	= 0<<21,
+		CTRL2_OUTSTANDING_REQS_REQ_2	= 1<<21,
+		CTRL2_OUTSTANDING_REQS_REQ_4	= 2<<21,
+		CTRL2_OUTSTANDING_REQS_REQ_8	= 3<<21,
+		CTRL2_OUTSTANDING_REQS_REQ_16	= 4<<21,
+
+		CTRL2_BURST_LEN_8		= 1<<20,
+
+		CTRL2_ODD_LINE_PATTERN_RGB	= 0<<16,
+		CTRL2_ODD_LINE_PATTERN_RBG	= 1<<16,
+		CTRL2_ODD_LINE_PATTERN_GBR	= 2<<16,
+		CTRL2_ODD_LINE_PATTERN_GRB	= 3<<16,
+		CTRL2_ODD_LINE_PATTERN_BRG	= 4<<16,
+		CTRL2_ODD_LINE_PATTERN_BGR	= 5<<16,
+
+		CTRL2_EVEN_LINE_PATTERN_RGB	= 0<<12,
+		CTRL2_EVEN_LINE_PATTERN_RBG	= 1<<12,
+		CTRL2_EVEN_LINE_PATTERN_GBR	= 2<<12,
+		CTRL2_EVEN_LINE_PATTERN_GRB	= 3<<12,
+		CTRL2_EVEN_LINE_PATTERN_BRG	= 4<<12,
+		CTRL2_EVEN_LINE_PATTERN_BGR	= 5<<12,
+
+		CTRL2_READ_PACK_DIR		= 1<<10,
+
+		CTRL2_READ_MODE_OUTPUT_IN_RGB_FORMAT = 1<<9,
+		CTRL2_READ_MODE_6_BIT_INPUT	= 1<<8,
+		CTRL2_READ_MODE_NUM_PACKED_SUBWORDS = 7<<4,
+		CTRL2_INITIAL_DUMMY_READS	= 7<<1,
+
+	LCDIF_TRANSFER_COUNT= 0x30/4,
+		TRANSFER_COUNT_V_COUNT		= 0xFFFF<<16,
+		TRANSFER_COUNT_H_COUNT		= 0xFFFF,
+
+	LCDIF_CUR_BUF	= 0x40/4,
+	LCDIF_NEXT_BUF	= 0x50/4,
+
+	LCDIF_TIMING	= 0x60/4,
+		TIMING_CMD_HOLD			= 0xFF<<24,
+		TIMING_CMD_SETUP		= 0xFF<<16,
+		TIMING_DATA_HOLD		= 0xFF<<8,
+		TIMING_DATA_SETUP		= 0xFF<<0,
+
+	LCDIF_VDCTRL0	= 0x70/4,
+		VDCTRL0_VSYNC_OEB		= 1<<29,
+		VDCTRL0_ENABLE_PRESENT		= 1<<28,
+
+		VDCTRL0_VSYNC_POL		= 1<<27,
+		VDCTRL0_HSYNC_POL		= 1<<26,
+		VDCTRL0_DOTCLK_POL		= 1<<25,
+		VDCTRL0_ENABLE_POL		= 1<<24,
+
+		VDCTRL0_VSYNC_PERIOD_UNIT	= 1<<21,
+		VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	= 1<<20,
+		VDCTRL0_HALF_LINE		= 1<<19,
+		VDCTRL0_HALF_LINE_MODE		= 1<<18,
+
+		VDCTRL0_VSYNC_PULSE_WIDTH	= 0x3FFFF,
+
+	LCDIF_VDCTRL1	= 0x80/4,
+		VDCTRL1_VSYNC_PERIOD = 0xFFFFFFFF,
+
+	LCDIF_VDCTRL2	= 0x90/4,
+		VDCTRL2_HSYNC_PERIOD = 0x3FFFF,
+		VDCTRL2_HSYNC_PULSE_WIDTH = 0x3FFF<<18,
+		
+	LCDIF_VDCTRL3	= 0xA0/4,
+		VDCTRL3_VERTICAL_WAIT_CNT = 0xFFFF,
+		VDCTRL3_HORIZONTAL_WAIT_CNT = 0xFFF<<16,
+		VDCTRL3_VSYNC_ONLY = 1<<28,
+		VDCTRL3_MUX_SYNC_SIGNALS = 1<<29,
+
+	LCDIF_VDCTRL4	= 0xB0/4,
+		VDCTRL4_DOTCLK_H_VALID_DATA_CNT = 0x3FFFF,
+		VDCTRL4_SYNC_SIGNALS_ON = 1<<18,
+
+		VDCTRL4_DOTCLK_DLY_2NS = 0<<29,
+		VDCTRL4_DOTCLK_DLY_4NS = 1<<29,
+		VDCTRL4_DOTCLK_DLY_6NS = 2<<29,
+		VDCTRL4_DOTCLK_DLY_8NS = 3<<29,
+
+	LCDIF_DATA	= 0x180/4,
+
+	LCDIF_STAT	= 0x1B0/4,
+
+	LCDIF_AS_CTRL	= 0x210/4,
+};
+
+struct video_mode {
+	int	pixclk;
+	int	hactive;
+	int	vactive;
+	int	hblank;
+	int	vblank;
+	int	hso;
+	int	vso;
+	int	hspw;
+	int	vspw;
+
+	char	vsync_pol;
+	char	hsync_pol;
+};
+
+struct dsi_cfg {
+	int	lanes;
+
+	int	ref_clk;
+	int	hs_clk;
+	int	ui_ps;
+
+	int	byte_clk;
+	int	byte_t_ps;
+
+	int	tx_esc_clk;
+	int	tx_esc_t_ps;
+
+	int	rx_esc_clk;
+
+	int	clk_pre_ps;
+	int	clk_prepare_ps;
+	int	clk_zero_ps;
+
+	int	hs_prepare_ps;
+	int	hs_zero_ps;
+	int	hs_trail_ps;
+	int	hs_exit_ps;
+
+	int	lpx_ps;
+
+	vlong	wakeup_ps;
+};
+
+/* base addresses, VIRTIO is at 0x30000000 physical */
+
+static u32int *iomuxc = (u32int*)(VIRTIO + 0x330000);
+
+static u32int *gpio1 = (u32int*)(VIRTIO + 0x200000);
+static u32int *gpio3 = (u32int*)(VIRTIO + 0x220000);
+
+static u32int *pwm2 = (u32int*)(VIRTIO + 0x670000);
+
+static u32int *resetc= (u32int*)(VIRTIO + 0x390000);
+static u32int *gpc =   (u32int*)(VIRTIO + 0x3A0000);
+
+static u32int *dsi =   (u32int*)(VIRTIO + 0xA00000);
+static u32int *dphy =  (u32int*)(VIRTIO + 0xA00300);
+
+static u32int *lcdif = (u32int*)(VIRTIO + 0x320000);
+
+/* shift and mask */
+static u32int
+sm(u32int v, u32int m)
+{
+	int s;
+
+	if(m == 0)
+		return 0;
+
+	s = 0;
+	while((m & 1) == 0){
+		m >>= 1;
+		s++;
+	}
+
+	return (v & m) << s;
+}
+
+static u32int
+rr(u32int *base, int reg)
+{
+	u32int val = base[reg];
+//	iprint("%#p+%#.4x -> %#.8ux\n", PADDR(base), reg*4, val);
+	return val;
+}
+static void
+wr(u32int *base, int reg, u32int val)
+{
+//	iprint("%#p+%#.4x <- %#.8ux\n", PADDR(base), reg*4, val);
+	base[reg] = val;
+}
+static void
+mr(u32int *base, int reg, u32int val, u32int mask)
+{
+	wr(base, reg, (rr(base, reg) & ~mask) | (val & mask));
+}
+
+static void
+dsiparams(struct dsi_cfg *cfg, int lanes, int hs_clk, int ref_clk, int tx_esc_clk, int rx_esc_clk)
+{
+	cfg->lanes = lanes;
+	cfg->ref_clk = ref_clk;
+
+	cfg->hs_clk = hs_clk;
+	cfg->ui_ps = (1000000000000LL + (cfg->hs_clk-1)) / cfg->hs_clk;
+
+	cfg->byte_clk = cfg->hs_clk / 8;
+	cfg->byte_t_ps = cfg->ui_ps * 8;
+
+	cfg->tx_esc_clk = tx_esc_clk;
+	cfg->tx_esc_t_ps = (1000000000000LL + (cfg->tx_esc_clk-1)) / cfg->tx_esc_clk;
+
+	cfg->rx_esc_clk = rx_esc_clk;
+
+	/* min 8*ui */
+	cfg->clk_pre_ps = 8*cfg->ui_ps;
+
+	/* min 38ns, max 95ns */
+	cfg->clk_prepare_ps = 38*1000;
+
+	/* clk_prepare + clk_zero >= 300ns */
+	cfg->clk_zero_ps = 300*1000 - cfg->clk_prepare_ps;
+
+	/* min 40ns + 4*ui, max 85ns + 6*ui */
+	cfg->hs_prepare_ps = 40*1000 + 4*cfg->ui_ps;
+
+	/* hs_prepae + hs_zero >= 145ns + 10*ui */
+	cfg->hs_zero_ps = (145*1000 + 10*cfg->ui_ps) - cfg->hs_prepare_ps;
+
+	/* min max(n*8*ui, 60ns + n*4*ui); n=1 */
+	cfg->hs_trail_ps = 60*1000 + 1*4*cfg->ui_ps;
+	if(cfg->hs_trail_ps < 1*8*cfg->ui_ps)
+		cfg->hs_trail_ps = 1*8*cfg->ui_ps;
+
+	/* min 100ns */
+	cfg->hs_exit_ps = 100*1000;
+
+	/* min 50ns */
+	cfg->lpx_ps = 50*1000;
+
+	/* min 1ms */
+	cfg->wakeup_ps = 1000000000000LL;
+}
+
+static void
+lcdifinit(struct video_mode *mode)
+{
+	wr(lcdif, LCDIF_CTRL_CLR, CTRL_SFTRST);
+	while(rr(lcdif, LCDIF_CTRL) & CTRL_SFTRST)
+		;
+	wr(lcdif, LCDIF_CTRL_CLR, CTRL_CLKGATE);
+	while(rr(lcdif, LCDIF_CTRL) & (CTRL_SFTRST|CTRL_CLKGATE))
+		;
+
+	wr(lcdif, LCDIF_CTRL1_SET, CTRL1_FIFO_CLEAR);
+	wr(lcdif, LCDIF_AS_CTRL, 0);
+
+	wr(lcdif, LCDIF_CTRL1, sm(7, CTRL1_BYTE_PACKING_FORMAT));
+
+	wr(lcdif, LCDIF_CTRL,
+		CTRL_BYPASS_COUNT |
+		CTRL_MASTER |
+		CTRL_LCD_DATABUS_WIDTH_24_BIT |
+		CTRL_WORD_LENGTH_24_BIT);
+
+	wr(lcdif, LCDIF_TRANSFER_COUNT,
+		sm(mode->vactive, TRANSFER_COUNT_V_COUNT) |
+		sm(mode->hactive, TRANSFER_COUNT_H_COUNT));
+
+	wr(lcdif, LCDIF_VDCTRL0,
+		VDCTRL0_ENABLE_PRESENT |
+		VDCTRL0_VSYNC_POL | VDCTRL0_HSYNC_POL |
+		VDCTRL0_VSYNC_PERIOD_UNIT |
+		VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+		sm(mode->vspw, VDCTRL0_VSYNC_PULSE_WIDTH));
+
+	wr(lcdif, LCDIF_VDCTRL1,
+		sm(mode->vactive + mode->vblank, VDCTRL1_VSYNC_PERIOD));
+
+	wr(lcdif, LCDIF_VDCTRL2,
+		sm(mode->hactive + mode->hblank, VDCTRL2_HSYNC_PERIOD) |
+		sm(mode->hspw, VDCTRL2_HSYNC_PULSE_WIDTH));
+
+	wr(lcdif, LCDIF_VDCTRL3,
+		sm(mode->vblank - mode->vso, VDCTRL3_VERTICAL_WAIT_CNT) |
+		sm(mode->hblank - mode->hso, VDCTRL3_HORIZONTAL_WAIT_CNT));
+
+	wr(lcdif, LCDIF_VDCTRL4,
+		sm(mode->hactive, VDCTRL4_DOTCLK_H_VALID_DATA_CNT));
+
+	wr(lcdif, LCDIF_CUR_BUF, PADDR(gscreen->data->bdata));
+	wr(lcdif, LCDIF_NEXT_BUF, PADDR(gscreen->data->bdata));
+
+	wr(lcdif, LCDIF_CTRL_SET, CTRL_DOTCLK_MODE);
+
+	mr(lcdif, LCDIF_VDCTRL4, VDCTRL4_SYNC_SIGNALS_ON, VDCTRL4_SYNC_SIGNALS_ON);
+
+	wr(lcdif, LCDIF_CTRL_SET, CTRL_RUN);
+}
+
+static void
+bridgeinit(I2Cdev *dev, struct video_mode *mode, struct dsi_cfg *cfg)
+{
+	int n;
+
+	// clock derived from dsi clock
+	switch(cfg->hs_clk/2000000){
+	case 384:
+	default:	n = 1 << 1; break;
+	case 416:	n = 2 << 1; break;
+	case 468:	n = 0 << 1; break;
+	case 486:	n = 3 << 1; break;
+	case 461:	n = 4 << 1; break;
+	}
+	i2cwritebyte(dev, 0x0a, n);
+
+	// single channel A
+	n = 1<<5 | (cfg->lanes-4)<<3 | 3<<1;
+	i2cwritebyte(dev, 0x10, n);
+
+	// Enhanced framing and ASSR
+	i2cwritebyte(dev, 0x5a, 0x05);
+
+	// 2 DP lanes w/o SSC
+	i2cwritebyte(dev, 0x93, 0x20);
+
+	// 2.7Gbps DP data rate
+	i2cwritebyte(dev, 0x94, 0x80);
+
+	// Enable PLL and confirm PLL is locked
+	i2cwritebyte(dev, 0x0d, 0x01);
+
+	// wait for PLL to lock
+	while((i2creadbyte(dev, 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);
+
+	// Train link and confirm trained
+	i2cwritebyte(dev, 0x96, 0x0a);
+	while(i2creadbyte(dev, 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);
+
+	// Enable video stream, ASSR, enhanced framing
+	i2cwritebyte(dev, 0x5a, 0x0d);
+}
+
+static char*
+parseedid128(struct video_mode *mode, uchar edid[128])
+{
+	static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
+	uchar *p, sum;
+	int i;
+
+	if(memcmp(edid, magic, 8) != 0)
+		return "bad edid magic";
+
+	sum = 0;
+	for(i=0; i<128; i++) 
+		sum += edid[i];
+	if(sum != 0)
+		return "bad edid checksum";
+
+	/*
+	 * Detailed Timings
+	 */
+	p = edid+8+10+2+5+10+3+16;
+	for(i=0; i<4; i++, p+=18){
+		if((p[0]|p[1])==0)
+			continue;
+
+		memset(mode, 0, sizeof(*mode));
+
+		mode->pixclk = ((p[1]<<8) | p[0]) * 10000;
+
+		mode->hactive = ((p[4] & 0xF0)<<4) | p[2];		/* horizontal active */
+		mode->hblank = ((p[4] & 0x0F)<<8) | p[3];		/* horizontal blanking */
+		mode->vactive = ((p[7] & 0xF0)<<4) | p[5];		/* vertical active */
+		mode->vblank = ((p[7] & 0x0F)<<8) | p[6];		/* vertical blanking */
+		mode->hso = ((p[11] & 0xC0)<<2) | p[8];			/* horizontal sync offset */
+		mode->hspw = ((p[11] & 0x30)<<4) | p[9];		/* horizontal sync pulse width */
+		mode->vso = ((p[11] & 0x0C)<<2) | ((p[10] & 0xF0)>>4);	/* vertical sync offset */
+		mode->vspw = ((p[11] & 0x03)<<4) | (p[10] & 0x0F);	/* vertical sync pulse width */
+
+		switch((p[17] & 0x18)>>3) {
+		case 3:	/* digital separate sync signal; the norm */
+			mode->vsync_pol = (p[17] & 0x04) ? '+' : '-';
+			mode->hsync_pol = (p[17] & 0x02) ? '+' : '-';
+			break;
+		}
+
+		return nil;
+	}
+
+	return "no edid timings available";
+}
+
+static char*
+getmode(I2Cdev *dev, struct video_mode *mode)
+{
+	static uchar edid[128];
+	static I2Cdev aux;
+
+	aux.bus = dev->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);
+	addi2cdev(&aux);
+
+	if(i2crecv(&aux, edid, sizeof(edid), 0) != sizeof(edid))
+		return "i2crecv failed to get edid bytes";
+
+	return parseedid128(mode, edid);
+}
+
+static void
+dphyinit(struct dsi_cfg *cfg)
+{
+	int n;
+
+	/* powerdown */
+	wr(dphy, DPHY_PD_PLL, 1);
+	wr(dphy, DPHY_PD_PHY, 1);
+
+	/* magic */
+	wr(dphy, DPHY_LOCK_BYP, 0);
+	wr(dphy, DPHY_RTERM_SEL, 1);
+	wr(dphy, DPHY_AUTO_PD_EN, 0);
+	wr(dphy, DPHY_RXLPRP, 2);
+	wr(dphy, DPHY_RXCDR, 2);
+	wr(dphy, DPHY_TST, 0x25);
+
+	/* hs timings */
+	n = (2*cfg->hs_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
+	if(n < 0)
+		n = 0;
+	else if(n > 3)
+		n = 3;
+	wr(dphy, DPHY_M_PRG_HS_PREPARE, n);
+
+	n = (2*cfg->clk_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
+	if(n < 0)
+		n = 0;
+	else if(n > 1)
+		n = 1;
+	wr(dphy, DPHY_MC_PRG_HS_PREPARE, n);
+
+	n = ((cfg->hs_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 6;
+	if(n < 1)
+		n = 1;
+	wr(dphy, DPHY_M_PRG_HS_ZERO, n);
+
+	n = ((cfg->clk_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 3;
+	if(n < 1)
+		n = 1;
+	wr(dphy, DPHY_MC_PRG_HS_ZERO, n);
+
+	n = (cfg->hs_trail_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps;
+	if(n < 1)
+		n = 1;
+	else if(n > 15)
+		n = 15;
+	wr(dphy, DPHY_M_PRG_HS_TRAIL, n);
+	wr(dphy, DPHY_MC_PRG_HS_TRAIL, n);
+
+	if(cfg->hs_clk < 80*Mhz)
+		n = 0xD;
+	else if(cfg->hs_clk < 90*Mhz)
+		n = 0xC;
+	else if(cfg->hs_clk < 125*Mhz)
+		n = 0xB;
+	else if(cfg->hs_clk < 150*Mhz)
+		n = 0xA;
+	else if(cfg->hs_clk < 225*Mhz)
+		n = 0x9;
+	else if(cfg->hs_clk < 500*Mhz)
+		n = 0x8;
+	else
+		n = 0x7;
+	wr(dphy, DPHY_RXHS_SETTLE, n);
+
+	/* hs_clk = ref_clk * (CM / (CN*CO)); just set CN=CO=1 */
+	n = (cfg->hs_clk + cfg->ref_clk-1) / cfg->ref_clk;
+
+	/* strange encoding for CM */
+	if(n < 32)
+		n = 0xE0 | (n - 16);
+	else if(n < 64)
+		n = 0xC0 | (n - 32);
+	else if(n < 128)
+		n = 0x80 | (n - 64);
+	else
+		n = n - 128;
+	wr(dphy, DPHY_CM, n);	
+
+	wr(dphy, DPHY_CN, 0x1F);	/* CN==1 */
+	wr(dphy, DPHY_CO, 0x00);	/* CO==1 */
+}
+
+static void
+dphypowerup(void)
+{
+	wr(dphy, DPHY_PD_PLL, 0);
+	while((rr(dphy, DPHY_LOCK) & 1) == 0)
+		;
+	wr(dphy, DPHY_PD_PHY, 0);
+}
+
+static void
+dsiinit(struct dsi_cfg *cfg)
+{
+	int n;
+
+	wr(dsi, DSI_HOST_CFG_NUM_LANES, cfg->lanes-1);
+
+	wr(dsi, DSI_HOST_CFG_NONCONTINUOUS_CLK, 0x0);
+	wr(dsi, DSI_HOST_CFG_AUTOINSERT_EOTP, 0x0);
+
+	n = (cfg->clk_pre_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
+	wr(dsi, DSI_HOST_CFG_T_PRE, n);
+
+	n = (cfg->clk_pre_ps + cfg->lpx_ps + cfg->clk_prepare_ps + cfg->clk_zero_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
+	wr(dsi, DSI_HOST_CFG_T_POST, n);
+
+	n = (cfg->hs_exit_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
+	wr(dsi, DSI_HOST_CFG_TX_GAP, n);
+
+	wr(dsi, DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP, 0x1);
+
+	wr(dsi, DSI_HOST_CFG_HTX_TO_COUNT, 0x0);
+	wr(dsi, DSI_HOST_CFG_LRX_H_TO_COUNT, 0x0);
+	wr(dsi, DSI_HOST_CFG_BTA_H_TO_COUNT, 0x0);
+
+	n = (cfg->wakeup_ps + cfg->tx_esc_t_ps-1) / cfg->tx_esc_t_ps;
+	wr(dsi, DSI_HOST_CFG_TWAKEUP, n);
+}
+
+static void
+dpiinit(struct video_mode *mode)
+{
+	wr(dsi, DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING, 0x5); // 24-bit
+
+	wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FORMAT, 0x3); // 24-bit
+
+	/* this seems wrong */
+	wr(dsi, DSI_HOST_CFG_DPI_VSYNC_POLARITY, 0);
+	wr(dsi, DSI_HOST_CFG_DPI_HSYNC_POLARITY, 0); 
+
+	wr(dsi, DSI_HOST_CFG_DPI_VIDEO_MODE, 0x1); // non-burst mode with sync events
+
+	wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL, mode->hactive); 
+
+	wr(dsi, DSI_HOST_CFG_DPI_HFP, mode->hso); 
+	wr(dsi, DSI_HOST_CFG_DPI_HBP, mode->hblank - mode->hspw - mode->hso); 
+	wr(dsi, DSI_HOST_CFG_DPI_HSA, mode->hspw); 
+
+	wr(dsi, DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS, 0x0); 
+
+	wr(dsi, DSI_HOST_CFG_DPI_BLLP_MODE, 0x1);
+
+	wr(dsi, DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP, 0x0);
+
+	wr(dsi, DSI_HOST_CFG_DPI_VC, 0x0); 
+	wr(dsi, DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE, mode->hactive); 
+	wr(dsi, DSI_HOST_CFG_DPI_VACTIVE, mode->vactive - 1); 
+	wr(dsi, DSI_HOST_CFG_DPI_VBP, mode->vblank - mode->vspw - mode->vso); 
+	wr(dsi, DSI_HOST_CFG_DPI_VFP, mode->vso); 
+}
+
+void
+lcdinit(void)
+{
+	struct dsi_cfg dsi_cfg;
+	struct video_mode mode;
+	I2Cdev *bridge;
+	char *err;
+
+	/* gpio3 20 for sn65dsi86 bridge */
+	mr(iomuxc, IOMUXC_CTL_PAD_SAI5_RXC, 5, MUX_MODE);
+	/* gpio1 10 pad for panel */
+	mr(iomuxc, IOMUXC_CTL_PAD_GPIO1_IO10, 0, MUX_MODE);
+	/* pwm2 pad */
+	mr(iomuxc, IOMUXC_CTL_PAD_SPDIF_RX, 1, MUX_MODE);
+
+	/* lcdif to dpi=0, dcss=1 */
+	mr(iomuxc, IOMUXC_GPR_GPR13, 0, MIPI_MUX_SEL);
+
+	setclkgate("gpio1.ipg_clk_s", 1);
+	setclkgate("gpio3.ipg_clk_s", 1);
+
+	setclkrate("pwm2.ipg_clk_high_freq", "osc_25m_ref_clk", Pwmsrcclk);
+	setclkgate("pwm2.ipg_clk_high_freq", 1);
+
+	mr(gpio1, GPIO_GDIR, 1<<10, 1<<10);	/* gpio1 10 output */
+	mr(gpio1, GPIO_DR, 0<<10, 1<<10);	/* gpio1 10 low: panel off */
+
+	wr(pwm2, PWMIR, 0);	
+	wr(pwm2, PWMCR, CR_STOPEN | CR_DOZEN | CR_WAITEN | CR_DBGEN | CR_CLKSRC_HIGHFREQ | 0<<CR_PRESCALER_SHIFT);
+	wr(pwm2, PWMSAR, Pwmsrcclk/150000);
+	wr(pwm2, PWMPR, (Pwmsrcclk/100000)-2);
+	mr(pwm2, PWMCR, CR_EN, CR_EN);
+
+	mr(gpio1, GPIO_DR, 1<<10, 1<<10);	/* gpio1 10 high: panel on */
+
+	mr(gpio3, GPIO_GDIR, 1<<20, 1<<20);	/* gpio3 20 output */
+	mr(gpio3, GPIO_DR, 1<<20, 1<<20);	/* gpio3 20 high: bridge on */
+
+	bridge = i2cdev(i2cbus("i2c4"), 0x2C);
+	if(bridge == nil)
+		return;
+	bridge->subaddr = 1;
+
+	/* power on mipi dsi */
+	wr(gpc, GPC_PGC_CPU_0_1_MAPPING, 0x0000FFFF);
+	mr(gpc, GPC_PGC_PU_PGC_SW_PUP_REQ, MIPI_SW_PUP_REQ, MIPI_SW_PUP_REQ);
+	while(rr(gpc, GPC_PGC_PU_PGC_SW_PUP_REQ) & MIPI_SW_PUP_REQ)
+		;
+	wr(gpc, GPC_PGC_CPU_0_1_MAPPING, 0);
+
+	mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_N);
+	mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_PCLK_RESET_N);
+	mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_ESC_RESET_N);
+	mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_BYTE_N);
+	mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_DPI_RESET_N);
+
+	setclkgate("sim_display.mainclk", 0);
+	setclkgate("disp.axi_clk", 0);
+	setclkrate("disp.axi_clk", "system_pll1_clk", 800*Mhz);
+	setclkrate("disp.rtrm_clk", "system_pll1_clk", 400*Mhz);
+	setclkgate("disp.axi_clk", 1);
+	setclkgate("sim_display.mainclk", 1);
+
+	setclkrate("mipi.core", "system_pll1_div3", 266*Mhz);
+	setclkrate("mipi.CLKREF", "system_pll2_clk", 25*Mhz);
+	setclkrate("mipi.RxClkEsc", "system_pll1_clk", 80*Mhz);
+	setclkrate("mipi.TxClkEsc", nil, 20*Mhz);
+
+	/* dsi parameters are fixed for the bridge */
+	dsiparams(&dsi_cfg, 4, 2*486*Mhz,
+		getclkrate("mipi.CLKREF"),
+		getclkrate("mipi.TxClkEsc"),
+		getclkrate("mipi.RxClkEsc"));
+
+	/* release dphy reset */
+	mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_PCLK_RESET_N, RCR_MIPI_DSI_PCLK_RESET_N);
+
+	dphyinit(&dsi_cfg);
+	dsiinit(&dsi_cfg);
+	dphypowerup();
+
+	/* release mipi clock resets (generated by the dphy) */
+	mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_ESC_RESET_N, RCR_MIPI_DSI_ESC_RESET_N);
+	mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_RESET_BYTE_N, RCR_MIPI_DSI_RESET_BYTE_N);
+
+	/*
+	 * 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);
+	if(err != nil)
+		goto out;
+
+	/* allocates the framebuffer (gscreen->data->bdata) */
+	if(screeninit(mode.hactive, mode.vactive, 32) < 0){
+		err = "screeninit failed";
+		goto out;
+	}
+
+	/* start the pixel clock */
+	setclkrate("lcdif.pix_clk", "system_pll1_clk", mode.pixclk);
+	dpiinit(&mode);
+
+	/* release dpi reset */
+	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);
+
+	/* send the pixels */
+	lcdifinit(&mode);
+	return;
+
+out:
+	print("lcdinit: %s\n", err);
+}
--- a/sys/src/9/imx8/main.c
+++ b/sys/src/9/imx8/main.c
@@ -32,6 +32,7 @@
 		poperror();
 	}
 	kproc("alarm", alarmkproc, 0);
+
 	sp = (char**)(USTKTOP-sizeof(Tos) - 8 - sizeof(sp[0])*4);
 	sp[3] = sp[2] = sp[1] = nil;
 	strcpy(sp[1] = (char*)&sp[4], "boot");
@@ -99,14 +100,7 @@
 		+ conf.nswap
 		+ conf.nswppo*sizeof(Page*);
 	mainmem->maxsize = kpages;
-	if(!cpuserver)
-		/*
-		 * give terminals lots of image memory, too; the dynamic
-		 * allocation will balance the load properly, hopefully.
-		 * be careful with 32-bit overflow.
-		 */
-		imagmem->maxsize = kpages;
-
+	imagmem->maxsize = kpages;
 }
 
 void
@@ -149,7 +143,6 @@
 		fpuinit();
 		intrinit();
 		clockinit();
-		print("cpu%d: UP!\n", m->machno);
 		synccycles();
 		timersinit();
 		flushtlb();
@@ -175,6 +168,7 @@
 	initseg();
 	links();
 	chandevreset();
+	lcdinit();
 	userinit();
 	mpinit();
 	mmu0clear((uintptr*)L1);
--- a/sys/src/9/imx8/mem.h
+++ b/sys/src/9/imx8/mem.h
@@ -39,9 +39,9 @@
 #define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
 #define TRAPFRAMESIZE	(38*8)
 
-/* reserved dram for ucalloc() at the end of KZERO (physical) */
+/* reserved dram for ucalloc() and fbmemalloc() at the end of KZERO (physical) */
 #define	UCRAMBASE	(-KZERO - UCRAMSIZE)
-#define	UCRAMSIZE	(1*MiB)
+#define	UCRAMSIZE	(8*MiB)
 
 #define VDRAM		(0xFFFFFFFFC0000000ULL)	/* 0x40000000 - 0x80000000 */
 #define	KTZERO		(VDRAM + 0x100000)	/* kernel text start */
@@ -54,7 +54,7 @@
 #define VMAP		(0xFFFFFFFF00000000ULL)	/* 0x00000000 - 0x40000000 */
 
 #define KMAPEND		(0xFFFFFFFF00000000ULL)	/* 0x140000000 */
-#define KMAP		(0xFFFFFFFE00000000ULL)	/* 0x40000000 */
+#define KMAP		(0xFFFFFFFE00000000ULL)	/*  0x40000000 */
 
 #define KSEG0		(0xFFFFFFFE00000000ULL)
 
--- a/sys/src/9/imx8/mkfile
+++ b/sys/src/9/imx8/mkfile
@@ -58,12 +58,12 @@
 # HFILES=
 
 LIB=\
-#	/$objtype/lib/libmemlayer.a\
-#	/$objtype/lib/libmemdraw.a\
-#	/$objtype/lib/libdraw.a\
+	/$objtype/lib/libmemlayer.a\
+	/$objtype/lib/libmemdraw.a\
+	/$objtype/lib/libdraw.a\
 	/$objtype/lib/libip.a\
 	/$objtype/lib/libsec.a\
-#	/$objtype/lib/libmp.a\
+	/$objtype/lib/libmp.a\
 	/$objtype/lib/libc.a\
 #	/$objtype/lib/libdtracy.a\
 
--- a/sys/src/9/imx8/mmu.c
+++ b/sys/src/9/imx8/mmu.c
@@ -472,21 +472,36 @@
 {
 }
 
-void*
-ucalloc(usize size)
+static void*
+ucramalloc(usize size, uintptr align, uint attr)
 {
 	static uintptr top = UCRAMBASE + UCRAMSIZE;
 	static Lock lk;
-	uintptr va;
+	uintptr va, pg;
 
-	size = PGROUND(size);
-
 	lock(&lk);
 	top -= size;
+	size += top & align-1;
+	top &= -align;
 	if(top < UCRAMBASE)
-		panic("ucalloc: %p needs %zd bytes\n", getcallerpc(&size), size);
+		panic("ucramalloc: need %zd bytes", size);
 	va = KZERO + top;
+	pg = va & -BY2PG;
+	if(pg != ((va+size) & -BY2PG))
+		mmukmap(pg | attr, pg - KZERO, PGROUND(size));
 	unlock(&lk);
 
-	return (void*)mmukmap(va | PTEUNCACHED, PADDR(va), size);
+	return (void*)va;
+}
+
+void*
+ucalloc(usize size)
+{
+	return ucramalloc(size, 8, PTEUNCACHED);
+}
+
+void*
+fbmemalloc(usize size)
+{
+	return ucramalloc(PGROUND(size), BY2PG, PTEWT);
 }
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -14,8 +14,11 @@
 	fs
 	ether	netif
 	ip	arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
+	draw	screen swcursor
+	mouse	screen swcursor
 	uart
 	usb
+	i2c
 
 link
 	usbxhciimx
@@ -22,6 +25,7 @@
 	etherimx	ethermii
 	ethermedium
 	loopbackmedium
+	i2cimx		devi2c
 ip
 	tcp
 	udp
@@ -31,8 +35,10 @@
 	icmp6
 	ipmux
 misc
+	ccm
 	gic
 	uartimx
+	lcd
 port
 	int cpuserver = 0;
 bootdir
--- /dev/null
+++ b/sys/src/9/imx8/screen.c
@@ -1,0 +1,341 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#define	Image	IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+enum {
+	Tabstop		= 4,
+	Scroll		= 8,
+};
+
+Memimage *gscreen;
+
+static Memdata xgdata;
+static Memimage xgscreen;
+static Memimage *conscol;
+static Memimage *back;
+static Memsubfont *memdefont;
+
+static Lock screenlock;
+
+static Point	curpos;
+static int	h, w;
+static Rectangle window;
+
+static void myscreenputs(char *s, int n);
+static void screenputc(char *buf);
+static void screenwin(void);
+
+enum
+{
+	CMaccelerated,
+	CMlinear,
+};
+
+static Cmdtab mousectlmsg[] =
+{
+	CMaccelerated,		"accelerated",		0,
+	CMlinear,		"linear",		1,
+};
+
+void
+mousectl(Cmdbuf *cb)
+{
+	Cmdtab *ct;
+
+	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
+	switch(ct->index){
+	case CMaccelerated:
+		mouseaccelerate(cb->nf == 1? 1: atoi(cb->f[1]));
+		break;
+	case CMlinear:
+		mouseaccelerate(0);
+		break;
+	}
+}
+
+void
+cursoron(void)
+{
+	swcursorhide(0);
+	swcursordraw(mousexy());
+}
+
+void
+cursoroff(void)
+{
+	swcursorhide(0);
+}
+
+void
+setcursor(Cursor* curs)
+{
+	swcursorload(curs);
+}
+
+int
+hwdraw(Memdrawparam *par)
+{
+	Memimage *dst, *src, *mask;
+
+	if((dst = par->dst) == nil || dst->data == nil)
+		return 0;
+	if((src = par->src) && src->data == nil)
+		src = nil;
+	if((mask = par->mask) && mask->data == nil)
+		mask = nil;
+
+	if(dst->data->bdata == xgdata.bdata)
+		swcursoravoid(par->r);
+	if(src && src->data->bdata == xgdata.bdata)
+		swcursoravoid(par->sr);
+	if(mask && mask->data->bdata == xgdata.bdata)
+		swcursoravoid(par->mr);
+
+	return 0;
+}
+
+int
+screeninit(int width, int height, int depth)
+{
+	ulong chan;
+
+	switch(depth){
+	default:
+		return -1;
+	case 32:
+		chan = XRGB32;
+		break;
+	case 24:
+		chan = RGB24;
+		break;
+	case 16:
+		chan = RGB16;
+		break;
+	}
+	memsetchan(&xgscreen, chan);
+	xgscreen.r = Rect(0, 0, width, height);
+	xgscreen.clipr = xgscreen.r;
+	xgscreen.depth = depth;
+	xgscreen.width = wordsperline(xgscreen.r, xgscreen.depth);
+	xgdata.bdata = fbmemalloc(xgscreen.width*sizeof(ulong)*height);
+	xgdata.ref = 1;
+
+	xgscreen.data = &xgdata;
+
+	gscreen = &xgscreen;
+
+	conf.monitor = 1;
+
+	memimageinit();
+	memdefont = getmemdefont();
+	screenwin();
+	myscreenputs(kmesg.buf, kmesg.n);
+	screenputs = myscreenputs;
+	swcursorinit();
+
+	return 0;
+}
+
+void
+flushmemscreen(Rectangle)
+{
+}
+
+Memdata*
+attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
+{
+	if(gscreen == nil)
+		return nil;
+
+	*r = gscreen->r;
+	*d = gscreen->depth;
+	*chan = gscreen->chan;
+	*width = gscreen->width;
+	*softscreen = 0;
+
+	gscreen->data->ref++;
+	return gscreen->data;
+}
+
+void
+getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
+{
+	USED(p, pr, pg, pb);
+}
+
+int
+setcolor(ulong p, ulong r, ulong g, ulong b)
+{
+	USED(p, r, g, b);
+	return 0;
+}
+
+void
+blankscreen(int)
+{
+}
+
+static void
+myscreenputs(char *s, int n)
+{
+	int i;
+	Rune r;
+	char buf[4];
+
+	if(!islo()) {
+		/* don't deadlock trying to print in interrupt */
+		if(!canlock(&screenlock))
+			return;	
+	}
+	else
+		lock(&screenlock);
+
+	while(n > 0){
+		i = chartorune(&r, s);
+		if(i == 0){
+			s++;
+			--n;
+			continue;
+		}
+		memmove(buf, s, i);
+		buf[i] = 0;
+		n -= i;
+		s += i;
+		screenputc(buf);
+	}
+	unlock(&screenlock);
+}
+
+static void
+screenwin(void)
+{
+	char *greet;
+	Memimage *orange;
+	Point p, q;
+	Rectangle r;
+
+	back = memblack;
+	conscol = memwhite;
+
+	orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
+	orange->flags |= Frepl;
+	orange->clipr = gscreen->r;
+	orange->data->bdata[0] = 0x40;		/* magic: colour? */
+	orange->data->bdata[1] = 0xfd;		/* magic: colour? */
+
+	w = memdefont->info[' '].width;
+	h = memdefont->height;
+
+	r = gscreen->r;
+	memimagedraw(gscreen, r, memwhite, ZP, memopaque, ZP, S);
+	window = insetrect(r, 4);
+	memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
+
+	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
+		window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
+
+	freememimage(orange);
+	window = insetrect(window, 5);
+
+	greet = " Plan 9 Console ";
+	p = addpt(window.min, Pt(10, 0));
+	q = memsubfontwidth(memdefont, greet);
+	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
+	flushmemscreen(r);
+	window.min.y += h + 6;
+	curpos = window.min;
+	window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
+}
+
+static void
+scroll(void)
+{
+	int o;
+	Point p;
+	Rectangle r;
+
+	o = Scroll*h;
+	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
+	p = Pt(window.min.x, window.min.y+o);
+	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
+	flushmemscreen(r);
+	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
+	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
+	flushmemscreen(r);
+
+	curpos.y -= o;
+}
+
+static void
+screenputc(char *buf)
+{
+	int w;
+	uint pos;
+	Point p;
+	Rectangle r;
+	static int *xp;
+	static int xbuf[256];
+
+	if (xp < xbuf || xp >= &xbuf[nelem(xbuf)])
+		xp = xbuf;
+
+	switch (buf[0]) {
+	case '\n':
+		if (curpos.y + h >= window.max.y)
+			scroll();
+		curpos.y += h;
+		screenputc("\r");
+		break;
+	case '\r':
+		xp = xbuf;
+		curpos.x = window.min.x;
+		break;
+	case '\t':
+		p = memsubfontwidth(memdefont, " ");
+		w = p.x;
+		if (curpos.x >= window.max.x - Tabstop * w)
+			screenputc("\n");
+
+		pos = (curpos.x - window.min.x) / w;
+		pos = Tabstop - pos % Tabstop;
+		*xp++ = curpos.x;
+		r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		flushmemscreen(r);
+		curpos.x += pos * w;
+		break;
+	case '\b':
+		if (xp <= xbuf)
+			break;
+		xp--;
+		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		flushmemscreen(r);
+		curpos.x = *xp;
+		break;
+	case '\0':
+		break;
+	default:
+		p = memsubfontwidth(memdefont, buf);
+		w = p.x;
+
+		if (curpos.x >= window.max.x - w)
+			screenputc("\n");
+
+		*xp++ = curpos.x;
+		r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
+		flushmemscreen(r);
+		curpos.x += w;
+		break;
+	}
+}
--- /dev/null
+++ b/sys/src/9/imx8/screen.h
@@ -1,0 +1,32 @@
+/* devmouse.c */
+typedef struct Cursor Cursor;
+extern Cursor cursor;
+extern void mousetrack(int, int, int, ulong);
+extern void absmousetrack(int, int, int, ulong);
+extern Point mousexy(void);
+extern void mouseaccelerate(int);
+
+/* screen.c */
+extern int	screeninit(int width, int hight, int depth);
+extern void	blankscreen(int);
+extern void	flushmemscreen(Rectangle);
+extern Memdata*	attachscreen(Rectangle*, ulong*, int*, int*, int*);
+extern void	cursoron(void);
+extern void	cursoroff(void);
+extern void	setcursor(Cursor*);
+
+extern void mousectl(Cmdbuf*);
+extern void mouseresize(void);
+extern void mouseredraw(void);
+
+/* devdraw.c */
+extern QLock	drawlock;
+
+#define ishwimage(i)	1		/* for ../port/devdraw.c */
+
+/* swcursor.c */
+void		swcursorhide(int);
+void		swcursoravoid(Rectangle);
+void		swcursordraw(Point);
+void		swcursorload(Cursor *);
+void		swcursorinit(void);
--- a/sys/src/9/imx8/uartimx.c
+++ b/sys/src/9/imx8/uartimx.c
@@ -315,10 +315,25 @@
 }
 
 static void
+clkenable(Uart *u, int on)
+{
+	char clk[32];
+
+	snprint(clk, sizeof(clk), "%s.ipg_perclk", u->name);
+	if(on) setclkrate(clk, "osc_25m_ref_clk", u->freq);
+	setclkgate(clk, on);
+}
+
+static void
 disable(Uart *u)
 {
 	u32int *regs = u->regs;
+
+	if(u->console)
+		return;	/* avoid glitch */
+
 	regs[UCR1] = 0;
+	clkenable(u, 0);
 }
 
 static void
@@ -325,7 +340,10 @@
 enable(Uart *u, int ie)
 {
 	disable(u);
+	clkenable(u, 1);
+
 	if(ie) intrenable(IRQuart1, interrupt, u, BUSUNKNOWN, u->name);
+
 	config(u);
 }
 
--- a/sys/src/9/imx8/usbxhciimx.c
+++ b/sys/src/9/imx8/usbxhciimx.c
@@ -1774,6 +1774,17 @@
 	return 0;
 }
 
+static void
+clkenable(int i, int on)
+{
+	char clk[32];
+
+	snprint(clk, sizeof(clk), "usb%d.ctrl", i+1);
+	setclkgate(clk, on);
+	snprint(clk, sizeof(clk), "usb%d.phy", i+1);
+	setclkgate(clk, on);
+}
+
 static int
 reset(Hci *hp)
 {
@@ -1796,6 +1807,15 @@
 	return -1;
 
 Found:
+	if(i == 0){
+		for(i = 0; i < nelem(ctlrs); i++) clkenable(i, 0);
+		setclkrate("ccm_usb_bus_clk_root", "system_pll2_div2", 500*Mhz);
+		setclkrate("ccm_usb_core_ref_clk_root", "system_pll1_div8", 100*Mhz);
+		setclkrate("ccm_usb_phy_ref_clk_root", "system_pll1_div8", 100*Mhz);
+		i = 0;
+	}
+	clkenable(i, 1);
+
 	hp->init = init;
 	hp->dump = dump;
 	hp->interrupt = interrupt;