summaryrefslogtreecommitdiff
path: root/sys/src/9
diff options
context:
space:
mode:
authorJaume Delclòs Coll <cosa@cosarara.me>2023-05-22 10:26:52 +0000
committerJaume Delclòs Coll <cosa@cosarara.me>2023-05-22 10:26:52 +0000
commitb9e0b5b8958c8b92321dcc6f5820b7459392e97f (patch)
treecd22c2048a8fb740ba7f926afa52f0be0c919a86 /sys/src/9
parent278caaf11931ec0c71fc13fd4c4794fae325c404 (diff)
WIP qemu virt platform kernel
Diffstat (limited to 'sys/src/9')
-rw-r--r--sys/src/9/virt/cache.v8.s212
-rw-r--r--sys/src/9/virt/ccm.c1444
-rw-r--r--sys/src/9/virt/clock.c142
-rw-r--r--sys/src/9/virt/dat.h224
-rw-r--r--sys/src/9/virt/devrtc.c349
-rw-r--r--sys/src/9/virt/fns.h171
-rw-r--r--sys/src/9/virt/fpu.c92
-rw-r--r--sys/src/9/virt/gic.c295
-rw-r--r--sys/src/9/virt/gic_reform.c321
-rw-r--r--sys/src/9/virt/init9.s4
-rw-r--r--sys/src/9/virt/io.h11
-rw-r--r--sys/src/9/virt/iomux.c1139
-rw-r--r--sys/src/9/virt/l.s717
-rw-r--r--sys/src/9/virt/main.c455
-rw-r--r--sys/src/9/virt/mem.h144
-rw-r--r--sys/src/9/virt/mkfile101
-rw-r--r--sys/src/9/virt/mmu.c526
-rw-r--r--sys/src/9/virt/rebootcode.s48
-rw-r--r--sys/src/9/virt/sysreg.c58
-rw-r--r--sys/src/9/virt/sysreg.h90
-rw-r--r--sys/src/9/virt/trap.c711
-rw-r--r--sys/src/9/virt/uartpl011.c400
-rw-r--r--sys/src/9/virt/virt6445
23 files changed, 7699 insertions, 0 deletions
diff --git a/sys/src/9/virt/cache.v8.s b/sys/src/9/virt/cache.v8.s
new file mode 100644
index 000000000..20ecf2f5e
--- /dev/null
+++ b/sys/src/9/virt/cache.v8.s
@@ -0,0 +1,212 @@
+#include "sysreg.h"
+
+#undef SYSREG
+#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
+
+/*
+ * instruction cache operations
+ */
+TEXT cacheiinvse(SB), 1, $-4
+ MOVWU len+8(FP), R2
+ ADD R0, R2
+
+ MRS DAIF, R11
+ MSR $0x2, DAIFSet
+ MOVWU $1, R10
+ MSR R10, CSSELR_EL1
+ ISB $SY
+ MRS CCSIDR_EL1, R4
+
+ ANDW $7, R4
+ ADDW $4, R4 // log2(linelen)
+ LSL R4, R10
+ LSR R4, R0
+ LSL R4, R0
+
+_iinvse:
+ IC R0, 3,7,5,1 // IVAU
+ ADD R10, R0
+ CMP R0, R2
+ BGT _iinvse
+ DSB $NSH
+ ISB $SY
+ MSR R11, DAIF
+ RETURN
+
+TEXT cacheiinv(SB), 1, $-4
+ IC R0, 0,7,5,0 // IALLU
+ DSB $NSH
+ ISB $SY
+ RETURN
+
+TEXT cacheuwbinv(SB), 1, $0
+ BL cachedwbinv(SB)
+ BL cacheiinv(SB)
+ RETURN
+
+/*
+ * data cache operations
+ */
+TEXT cachedwbse(SB), 1, $-4
+ MOV LR, R29
+ BL cachedva<>(SB)
+TEXT dccvac(SB), 1, $-4
+ DC R0, 3,7,10,1 // CVAC
+ RETURN
+
+TEXT cacheduwbse(SB), 1, $-4
+ MOV LR, R29
+ BL cachedva<>(SB)
+TEXT dccvau(SB), 1, $-4
+ DC R0, 3,7,11,1 // CVAU
+ RETURN
+
+TEXT cachedinvse(SB), 1, $-4
+ MOV LR, R29
+ BL cachedva<>(SB)
+TEXT dcivac(SB), 1, $-4
+ DC R0, 0,7,6,1 // IVAC
+ RETURN
+
+TEXT cachedwbinvse(SB), 1, $-4
+ MOV LR, R29
+ BL cachedva<>(SB)
+TEXT dccivac(SB), 1, $-4
+ DC R0, 3,7,14,1 // CIVAC
+ RETURN
+
+TEXT cachedva<>(SB), 1, $-4
+ MOV LR, R1
+ MOVWU len+8(FP), R2
+ ADD R0, R2
+
+ MRS DAIF, R11
+ MSR $0x2, DAIFSet
+ MOVWU $0, R10
+ MSR R10, CSSELR_EL1
+ ISB $SY
+ MRS CCSIDR_EL1, R4
+
+ ANDW $7, R4
+ ADDW $4, R4 // log2(linelen)
+ MOVWU $1, R10
+ LSL R4, R10
+ LSR R4, R0
+ LSL R4, R0
+
+ DSB $SY
+ ISB $SY
+_cachedva:
+ BL (R1)
+ ADD R10, R0
+ CMP R0, R2
+ BGT _cachedva
+ DSB $SY
+ ISB $SY
+ MSR R11, DAIF
+ RET R29
+
+/*
+ * l1 cache operations
+ */
+TEXT cachedwb(SB), 1, $-4
+ MOVWU $0, R0
+_cachedwb:
+ MOV LR, R29
+ BL cachedsw<>(SB)
+TEXT dccsw(SB), 1, $-4
+ DC R0, 0,7,10,2 // CSW
+ RETURN
+
+TEXT cachedinv(SB), 1, $-4
+ MOVWU $0, R0
+_cachedinv:
+ MOV LR, R29
+ BL cachedsw<>(SB)
+TEXT dcisw(SB), 1, $-4
+ DC R0, 0,7,6,2 // ISW
+ RETURN
+
+TEXT cachedwbinv(SB), 1, $-4
+ MOVWU $0, R0
+_cachedwbinv:
+ MOV LR, R29
+ BL cachedsw<>(SB)
+TEXT dccisw(SB), 1, $-4
+ DC R0, 0,7,14,2 // CISW
+ RETURN
+
+/*
+ * l2 cache operations
+ */
+TEXT l2cacheuwb(SB), 1, $-4
+ MOVWU $1, R0
+ B _cachedwb
+TEXT l2cacheuinv(SB), 1, $-4
+ MOVWU $1, R0
+ B _cachedinv
+TEXT l2cacheuwbinv(SB), 1, $-4
+ MOVWU $1, R0
+ B _cachedwbinv
+
+TEXT cachesize(SB), 1, $-4
+ MRS DAIF, R11
+ MSR $0x2, DAIFSet
+ MSR R0, CSSELR_EL1
+ ISB $SY
+ MRS CCSIDR_EL1, R0
+ MSR R11, DAIF
+ RETURN
+
+TEXT cachedsw<>(SB), 1, $-4
+ MOV LR, R1
+
+ MRS DAIF, R11
+ MSR $0x2, DAIFSet
+ ADDW R0, R0, R8
+ MSR R8, CSSELR_EL1
+ ISB $SY
+ MRS CCSIDR_EL1, R4
+
+ LSR $3, R4, R7
+ ANDW $1023, R7 // lastway
+ ADDW $1, R7, R5 // #ways
+
+ LSR $13, R4, R2
+ ANDW $32767, R2 // lastset
+ ADDW $1, R2 // #sets
+
+ ANDW $7, R4
+ ADDW $4, R4 // log2(linelen)
+
+ MOVWU $32, R3 // wayshift = 32 - log2(#ways)
+_countlog2ways:
+ CBZ R7, _loop // lastway == 0?
+ LSR $1, R7 // lastway >>= 1
+ SUB $1, R3 // wayshift--
+ B _countlog2ways
+_loop:
+ DSB $SY
+ ISB $SY
+_nextway:
+ MOVWU $0, R6 // set
+_nextset:
+ LSL R3, R7, R0 // way<<wayshift
+ LSL R4, R6, R9 // set<<log2(linelen)
+ ORRW R8, R0 // level
+ ORRW R9, R0 // setway
+
+ BL (R1) // op(setway)
+
+ ADDW $1, R6 // set++
+ CMPW R2, R6
+ BLT _nextset
+
+ ADDW $1, R7 // way++
+ CMPW R5, R7
+ BLT _nextway
+
+ DSB $SY
+ ISB $SY
+ MSR R11, DAIF
+ RET R29
diff --git a/sys/src/9/virt/ccm.c b/sys/src/9/virt/ccm.c
new file mode 100644
index 000000000..f0a529fcc
--- /dev/null
+++ b/sys/src/9/virt/ccm.c
@@ -0,0 +1,1444 @@
+#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 },
+
+ { "tmu.clk", IPG_CLK_ROOT, 98 },
+
+ { "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", SAI2_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", SAI3_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", SAI4_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", SAI5_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", SAI6_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 = 2; divr <= 64; divr++){
+ ref = ref_freq/divr;
+
+ v = (vlong)freq*divq;
+ v <<= 24;
+ v /= ref * 8;
+
+ divfi = v >> 24;
+ divff = v & 0xFFFFFF;
+ if(divfi < 1 || divfi > 128)
+ continue;
+
+ v *= (vlong)ref * 8;
+ v /= (vlong)divq << 24;
+ pllout = v;
+
+ if(pllout > freq)
+ continue;
+
+ if(freq - pllout > error)
+ continue;
+
+ 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;
+ }
+ }
+ panic("enablefracpll: %#p freq %d: out of range", PADDR(reg), freq);
+
+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;
+
+ /* bypass */
+ reg[0] |= 1<<14;
+
+ reg[1] = cfg1;
+
+ reg[0] = cfg0 | (1<<14) | (1<<12);
+
+ /* unbypass */
+ reg[0] &= ~(1<<14);
+
+ while((reg[0] & (1<<31)) == 0)
+ ;
+
+ 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;
+ }
+}
+
+enum {
+ CCM_ANALOG_PLLOUT_MONITOR_CFG = 0x74/4,
+ PLLOUT_MONITOR_CLK_CKE = 1<<4,
+ CCM_ANALOG_FRAC_PLLOUT_DIV_CFG = 0x78/4,
+ CCM_ANALOG_SCCG_PLLOUT_DIV_CFG = 0x7C/4,
+};
+
+static struct {
+ uchar input;
+ uchar reg; /* divider register */
+ uchar shift; /* divider shift */
+} anapllout_input[16] = {
+[0] OSC_25M_REF_CLK,
+[1] OSC_27M_REF_CLK,
+/* [2] HDMI_PHY_27M_CLK */
+/* [3] CLK1_P_N */
+[4] OSC_32K_REF_CLK,
+[5] AUDIO_PLL1_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 0,
+[6] AUDIO_PLL2_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 4,
+[7] GPU_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 12,
+[8] VPU_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 16,
+[9] VIDEO_PLL1_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 8,
+[10] ARM_PLL_CLK, CCM_ANALOG_FRAC_PLLOUT_DIV_CFG, 20,
+[11] SYSTEM_PLL1_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 0,
+[12] SYSTEM_PLL2_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 4,
+[13] SYSTEM_PLL3_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 8,
+[14] VIDEO_PLL2_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 16,
+[15] DRAM_PLL1_CLK, CCM_ANALOG_SCCG_PLLOUT_DIV_CFG, 12,
+};
+
+static void
+setanapllout(int input, int freq)
+{
+ int mux, div, reg;
+
+ for(mux = 0; mux < nelem(anapllout_input); mux++)
+ if(anapllout_input[mux].input == input)
+ goto Muxok;
+ panic("setanapllout: bad input clock\n");
+ return;
+Muxok:
+ anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG] = mux;
+ if(freq <= 0)
+ return;
+ div = input_clk_freq[input] / freq;
+ if(div < 1 || div > 8){
+ panic("setanapllout: divider out of range\n");
+ return;
+ }
+ enablepll(input);
+ reg = anapllout_input[mux].reg;
+ if(reg){
+ int shift = anapllout_input[mux].shift;
+ anatop[reg] = (anatop[reg] & ~(7<<shift)) | ((div-1)<<shift);
+ } else if(div != 1){
+ panic("setanapllout: bad frequency\n");
+ return;
+ }
+ anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG] |= PLLOUT_MONITOR_CLK_CKE;
+}
+
+static int
+getanapllout(void)
+{
+ int mux, input, freq, reg, div;
+ u32int cfg = anatop[CCM_ANALOG_PLLOUT_MONITOR_CFG];
+
+ mux = cfg & 0xF;
+ input = anapllout_input[mux].input;
+ if(input == 0)
+ return 0;
+ freq = input_clk_freq[input];
+ if((cfg & PLLOUT_MONITOR_CLK_CKE) == 0)
+ freq = -freq;
+ reg = anapllout_input[mux].reg;
+ if(reg){
+ int shift = anapllout_input[mux].shift;
+ div = ((anatop[reg] >> shift) & 7)+1;
+ } else {
+ div = 1;
+ }
+ return freq / div;
+}
+
+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(cistrcmp(name, "ccm_analog_pllout") == 0){
+ setanapllout(lookinputclk(source), freq);
+ return;
+ }
+
+ 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(cistrcmp(name, "ccm_analog_pllout") == 0)
+ return getanapllout();
+
+ 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;
+}
diff --git a/sys/src/9/virt/clock.c b/sys/src/9/virt/clock.c
new file mode 100644
index 000000000..bd28531e1
--- /dev/null
+++ b/sys/src/9/virt/clock.c
@@ -0,0 +1,142 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "sysreg.h"
+
+static uvlong freq;
+
+enum {
+ Enable = 1<<0,
+ Imask = 1<<1,
+ Istatus = 1<<2,
+};
+
+void
+clockshutdown(void)
+{
+}
+
+static void
+localclockintr(Ureg *ureg, void *)
+{
+ timerintr(ureg, 0);
+}
+
+void
+clockinit(void)
+{
+ uvlong tstart, tend;
+ ulong t0, t1;
+
+ syswr(PMCR_EL0, 1<<6 | 7);
+ syswr(PMCNTENSET, 1<<31);
+ syswr(PMUSERENR_EL0, 1<<2);
+ syswr(CNTKCTL_EL1, 1<<1);
+
+ syswr(CNTP_TVAL_EL0, ~0UL);
+ syswr(CNTP_CTL_EL0, Enable);
+
+ if(m->machno == 0){
+ freq = sysrd(CNTFRQ_EL0);
+ print("timer frequency %lld Hz\n", freq);
+
+ /* TURBO! */
+ //setclkrate("ccm_arm_a53_clk_root", "osc_25m_ref_clk", 25*Mhz);
+ //setclkrate("ccm_arm_a53_clk_root", "arm_pll_clk", 1600*Mhz);
+ }
+ print("plz 1");
+ tstart = sysrd(CNTPCT_EL0);
+ do{
+ t0 = lcycles();
+ }while(sysrd(CNTPCT_EL0) == tstart);
+ print("plz 2");
+ tend = tstart + (freq/100);
+ do{
+ t1 = lcycles();
+ }while(sysrd(CNTPCT_EL0) < tend);
+ print("plz 3");
+ t1 -= t0;
+ m->cpuhz = 100 * t1;
+ m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
+
+ /*
+ * we are using virtual counter register CNTVCT_EL0
+ * instead of the performance counter in userspace.
+ */
+ m->cyclefreq = freq;
+
+ print("plz 4");
+ intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
+}
+
+void
+timerset(uvlong next)
+{
+ uvlong now;
+ long period;
+
+ now = fastticks(nil);
+ period = next - now;
+ syswr(CNTP_TVAL_EL0, period);
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ if(hz)
+ *hz = freq;
+ return sysrd(CNTPCT_EL0);
+}
+
+ulong
+perfticks(void)
+{
+ return fastticks(nil);
+}
+
+ulong
+µs(void)
+{
+ uvlong hz;
+ uvlong t = fastticks(&hz);
+ return (t * 1000000ULL) / hz;
+}
+
+void
+microdelay(int n)
+{
+ ulong now;
+
+ now = µs();
+ while(µs() - now < n);
+}
+
+void
+delay(int n)
+{
+ while(--n >= 0)
+ microdelay(1000);
+}
+
+void
+synccycles(void)
+{
+ static Ref r1, r2;
+ int s;
+
+ s = splhi();
+ r2.ref = 0;
+ incref(&r1);
+ while(r1.ref != conf.nmach)
+ ;
+// syswr(PMCR_EL0, 1<<6 | 7);
+ incref(&r2);
+ while(r2.ref != conf.nmach)
+ ;
+ r1.ref = 0;
+ splx(s);
+}
diff --git a/sys/src/9/virt/dat.h b/sys/src/9/virt/dat.h
new file mode 100644
index 000000000..03d2d7e67
--- /dev/null
+++ b/sys/src/9/virt/dat.h
@@ -0,0 +1,224 @@
+/*
+ * Time.
+ *
+ * HZ should divide 1000 evenly, ideally.
+ * 100, 125, 200, 250 and 333 are okay.
+ */
+#define HZ 100 /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+
+enum {
+ Mhz = 1000 * 1000,
+
+ GpioLow = 0,
+ GpioHigh,
+ GpioRising,
+ GpioFalling,
+ GpioEdge,
+};
+
+typedef struct Conf Conf;
+typedef struct Confmem Confmem;
+typedef struct FPsave FPsave;
+typedef struct PFPU PFPU;
+typedef struct ISAConf ISAConf;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Memcache Memcache;
+typedef struct MMMU MMMU;
+typedef struct Mach Mach;
+typedef struct Page Page;
+typedef struct PhysUart PhysUart;
+typedef struct Pcidev Pcidev;
+typedef struct PMMU PMMU;
+typedef struct Proc Proc;
+typedef u64int PTE;
+typedef struct Soc Soc;
+typedef struct Uart Uart;
+typedef struct Ureg Ureg;
+typedef uvlong Tval;
+typedef void KMap;
+
+#pragma incomplete Pcidev
+#pragma incomplete Ureg
+
+#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */
+
+/*
+ * parameters for sysproc.c
+ */
+#define AOUT_MAGIC (R_MAGIC)
+
+struct Lock
+{
+ ulong key;
+ u32int sr;
+ uintptr pc;
+ Proc* p;
+ Mach* m;
+ int isilock;
+};
+
+struct Label
+{
+ uintptr sp;
+ uintptr pc;
+};
+
+struct FPsave
+{
+ uvlong regs[32][2];
+
+ ulong control;
+ ulong status;
+};
+
+struct PFPU
+{
+ FPsave fpsave[1];
+
+ int fpstate;
+};
+
+enum
+{
+ FPinit,
+ FPactive,
+ FPinactive,
+
+ /* bits or'd with the state */
+ FPillegal= 0x100,
+};
+
+struct Confmem
+{
+ uintptr base;
+ ulong npage;
+ uintptr limit;
+ uintptr kbase;
+ uintptr klimit;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ Confmem mem[3]; /* physical memory */
+ ulong npage; /* total physical pages of memory */
+ ulong upages; /* user page pool */
+ ulong copymode; /* 0 is copy on write, 1 is copy on reference */
+ ulong ialloc; /* max interrupt time allocation in bytes */
+ ulong pipeqsize; /* size in bytes of pipe queues */
+ ulong nimage; /* number of page cache image headers */
+ ulong nswap; /* number of swap pages */
+ int nswppo; /* max # of pageouts per segment pass */
+ ulong hz; /* processor cycle freq */
+ ulong mhz;
+ int monitor; /* flag */
+};
+
+/*
+ * MMU stuff in Mach.
+ */
+struct MMMU
+{
+ PTE* mmutop; /* first level user page table */
+};
+
+/*
+ * MMU stuff in proc
+ */
+#define NCOLOR 1 /* 1 level cache, don't worry about VCE's */
+
+struct PMMU
+{
+ union {
+ Page *mmufree; /* mmuhead[0] is freelist head */
+ Page *mmuhead[PTLEVELS];
+ };
+ Page *mmutail[PTLEVELS];
+ int asid;
+ uintptr tpidr;
+};
+
+#include "../port/portdat.h"
+
+struct Mach
+{
+ int machno; /* physical id of processor */
+ uintptr splpc; /* pc of last caller to splhi */
+ Proc* proc; /* current process on this processor */
+ /* end of offsets known to asm */
+
+ MMMU;
+
+ PMach;
+
+ int cputype;
+ ulong delayloop;
+ int cpumhz;
+ uvlong cpuhz; /* speed of cpu */
+
+ int stack[1];
+};
+
+struct
+{
+ char machs[MAXMACH]; /* active CPUs */
+ int exiting; /* shutdown */
+}active;
+
+#define MACHP(n) ((Mach*)MACHADDR(n))
+
+extern register Mach* m; /* R27 */
+extern register Proc* up; /* R26 */
+extern int normalprint;
+
+/*
+ * a parsed plan9.ini line
+ */
+#define NISAOPT 8
+
+struct ISAConf {
+ char *type;
+ uvlong port;
+ int irq;
+ ulong dma;
+ ulong mem;
+ ulong size;
+ ulong freq;
+
+ int nopt;
+ char *opt[NISAOPT];
+};
+
+/*
+ * Horrid. But the alternative is 'defined'.
+ */
+#ifdef _DBGC_
+#define DBGFLG (dbgflg[_DBGC_])
+#else
+#define DBGFLG (0)
+#endif /* _DBGC_ */
+
+int vflag;
+extern char dbgflg[256];
+
+#define dbgprint print /* for now */
+
+/*
+ * hardware info about a device
+ */
+typedef struct {
+ ulong port;
+ int size;
+} Devport;
+
+struct DevConf
+{
+ ulong intnum; /* interrupt number */
+ char *type; /* card type, malloced */
+ int nports; /* Number of ports */
+ Devport *ports; /* The ports themselves */
+};
diff --git a/sys/src/9/virt/devrtc.c b/sys/src/9/virt/devrtc.c
new file mode 100644
index 000000000..a30c6cfef
--- /dev/null
+++ b/sys/src/9/virt/devrtc.c
@@ -0,0 +1,349 @@
+/*
+ * NXP PCF8523 real time clock
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "../port/i2c.h"
+
+enum {
+ Seconds= 0x03,
+ Minutes= 0x04,
+ Hours= 0x05,
+ Mday= 0x06,
+ Wday= 0x07,
+ Month= 0x08,
+ Year= 0x09,
+ Nbcd= 1+Year-Seconds,
+};
+
+typedef struct Rtc Rtc;
+struct Rtc
+{
+ int sec;
+ int min;
+ int hour;
+ int mday;
+ int wday;
+ int mon;
+ int year;
+};
+
+enum{
+ Qdir = 0,
+ Qrtc,
+};
+
+Dirtab rtcdir[]={
+ ".", {Qdir, 0, QTDIR}, 0, 0555,
+ "rtc", {Qrtc, 0}, 0, 0664,
+};
+
+static ulong rtc2sec(Rtc*);
+static void sec2rtc(ulong, Rtc*);
+static I2Cdev *i2c;
+
+static Chan*
+rtcattach(char* spec)
+{
+ i2c = i2cdev(i2cbus("i2c3"), 0x68);
+ if(i2c == nil)
+ error(Enonexist);
+
+ i2c->subaddr = 1;
+ i2c->size = 0x14;
+
+ return devattach('r', spec);
+}
+
+static Walkqid*
+rtcwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+ return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
+}
+
+static int
+rtcstat(Chan* c, uchar* dp, int n)
+{
+ return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
+}
+
+static Chan*
+rtcopen(Chan* c, int omode)
+{
+ omode = openmode(omode);
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ if(strcmp(up->user, eve)!=0 && omode!=OREAD)
+ error(Eperm);
+ break;
+ }
+ return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
+}
+
+static void
+rtcclose(Chan*)
+{
+}
+
+#define GETBCD(o) (((bcdclock[o]&0xf)%10) + 10*((bcdclock[o]>>4)%10))
+
+static long
+_rtctime(void)
+{
+ uchar bcdclock[Nbcd];
+ Rtc rtc;
+
+ /* read clock values */
+ i2crecv(i2c, bcdclock, Nbcd, Seconds);
+
+ /*
+ * convert from BCD
+ */
+ rtc.sec = GETBCD(Seconds-Seconds) % 60;
+ rtc.min = GETBCD(Minutes-Seconds) % 60;
+ rtc.hour = GETBCD(Hours-Seconds) % 24;
+ rtc.mday = GETBCD(Mday-Seconds);
+ rtc.wday = GETBCD(Wday-Seconds) % 7;
+ rtc.mon = GETBCD(Month-Seconds);
+ rtc.year = GETBCD(Year-Seconds) % 100;
+
+ /*
+ * the world starts jan 1 1970
+ */
+ if(rtc.year < 70)
+ rtc.year += 2000;
+ else
+ rtc.year += 1900;
+ return rtc2sec(&rtc);
+}
+
+long
+rtctime(void)
+{
+ int i;
+ long t, ot;
+
+ /* loop till we get two reads in a row the same */
+ t = _rtctime();
+ for(i = 0; i < 100; i++){
+ ot = t;
+ t = _rtctime();
+ if(ot == t)
+ break;
+ }
+ if(i == 100) print("we are boofheads\n");
+
+ return t;
+}
+
+static long
+rtcread(Chan* c, void* buf, long n, vlong off)
+{
+ ulong offset = off;
+
+ if(c->qid.type & QTDIR)
+ return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ return readnum(offset, buf, n, rtctime(), 12);
+ }
+ error(Ebadarg);
+ return 0;
+}
+
+#define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
+
+static long
+rtcwrite(Chan* c, void* buf, long n, vlong off)
+{
+ Rtc rtc;
+ ulong secs;
+ char *cp, sbuf[32];
+ uchar bcdclock[Nbcd];
+ ulong offset = off;
+
+ if(offset!=0)
+ error(Ebadarg);
+
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ if(n >= sizeof(sbuf))
+ error(Ebadarg);
+ strncpy(sbuf, buf, n);
+ sbuf[n] = '\0';
+ for(cp = sbuf; *cp != '\0'; cp++)
+ if(*cp >= '0' && *cp <= '9')
+ break;
+ secs = strtoul(cp, 0, 0);
+
+ /*
+ * convert to bcd
+ */
+ sec2rtc(secs, &rtc);
+
+ PUTBCD(rtc.sec, Seconds-Seconds);
+ PUTBCD(rtc.min, Minutes-Seconds);
+ PUTBCD(rtc.hour, Hours-Seconds);
+ PUTBCD(rtc.mday, Mday-Seconds);
+ PUTBCD(rtc.wday, Wday-Seconds);
+ PUTBCD(rtc.mon, Month-Seconds);
+ PUTBCD(rtc.year, Year-Seconds);
+
+ /*
+ * write the clock
+ */
+ i2csend(i2c, bcdclock, Nbcd, Seconds);
+
+ return n;
+ }
+ error(Ebadarg);
+ return 0;
+}
+
+Dev rtcdevtab = {
+ 'r',
+ "rtc",
+
+ devreset,
+ devinit,
+ devshutdown,
+ rtcattach,
+ rtcwalk,
+ rtcstat,
+ rtcopen,
+ devcreate,
+ rtcclose,
+ rtcread,
+ devbread,
+ rtcwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
+
+#define SEC2MIN 60L
+#define SEC2HOUR (60L*SEC2MIN)
+#define SEC2DAY (24L*SEC2HOUR)
+
+/*
+ * days per month plus days/year
+ */
+static int dmsize[] =
+{
+ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+static int ldmsize[] =
+{
+ 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * return the days/month for the given year
+ */
+static int*
+yrsize(int y)
+{
+ if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
+ return ldmsize;
+ else
+ return dmsize;
+}
+
+/*
+ * compute seconds since Jan 1 1970
+ */
+static ulong
+rtc2sec(Rtc *rtc)
+{
+ ulong secs;
+ int i;
+ int *d2m;
+
+ secs = 0;
+
+ /*
+ * seconds per year
+ */
+ for(i = 1970; i < rtc->year; i++){
+ d2m = yrsize(i);
+ secs += d2m[0] * SEC2DAY;
+ }
+
+ /*
+ * seconds per month
+ */
+ d2m = yrsize(rtc->year);
+ for(i = 1; i < rtc->mon; i++)
+ secs += d2m[i] * SEC2DAY;
+
+ secs += (rtc->mday-1) * SEC2DAY;
+ secs += rtc->hour * SEC2HOUR;
+ secs += rtc->min * SEC2MIN;
+ secs += rtc->sec;
+
+ return secs;
+}
+
+/*
+ * compute rtc from seconds since Jan 1 1970
+ */
+static void
+sec2rtc(ulong secs, Rtc *rtc)
+{
+ int d;
+ long hms, day;
+ int *d2m;
+
+ /*
+ * break initial number into days
+ */
+ hms = secs % SEC2DAY;
+ day = secs / SEC2DAY;
+ if(hms < 0) {
+ hms += SEC2DAY;
+ day -= 1;
+ }
+
+ /*
+ * 19700101 was thursday
+ */
+ rtc->wday = (day + 7340036L) % 7;
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ rtc->sec = hms % 60;
+ d = hms / 60;
+ rtc->min = d % 60;
+ d /= 60;
+ rtc->hour = d;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d = 1970; day >= *yrsize(d); d++)
+ day -= *yrsize(d);
+ else
+ for (d = 1970; day < 0; d--)
+ day += *yrsize(d-1);
+ rtc->year = d;
+
+ /*
+ * generate month
+ */
+ d2m = yrsize(rtc->year);
+ for(d = 1; day >= d2m[d]; d++)
+ day -= d2m[d];
+ rtc->mday = day + 1;
+ rtc->mon = d;
+
+ return;
+}
diff --git a/sys/src/9/virt/fns.h b/sys/src/9/virt/fns.h
new file mode 100644
index 000000000..59622d693
--- /dev/null
+++ b/sys/src/9/virt/fns.h
@@ -0,0 +1,171 @@
+#include "../port/portfns.h"
+
+/* l.s */
+extern void sev(void);
+extern int tas(void *);
+extern int cmpswap(long*, long, long);
+extern void coherence(void);
+extern void idlehands(void);
+extern uvlong vcycles(void);
+#define cycles(ip) *(ip) = vcycles()
+extern int splfhi(void);
+extern void splflo(void);
+extern void touser(uintptr sp);
+extern void forkret(void);
+extern void noteret(void);
+extern void returnto(void*);
+extern void fpsaveregs(void*);
+extern void fploadregs(void*);
+extern void smccall(Ureg*);
+
+extern void setttbr(uintptr pa);
+extern uintptr getfar(void);
+
+extern void flushasidva(uintptr asidva);
+extern void tlbivae1is(uintptr asidva);
+
+extern void flushasidvall(uintptr asidva);
+extern void tlbivale1is(uintptr asidva);
+
+extern void flushasid(uintptr asid);
+extern void tlbiaside1is(uintptr asid);
+
+extern void flushtlb(void);
+extern void tlbivmalle1(void);
+
+extern void flushlocaltlb(void);
+extern void tlbivmalle1(void);
+
+/* cache */
+extern ulong cachesize(int level);
+
+extern void cacheiinvse(void*, int);
+extern void cacheuwbinv(void);
+extern void cacheiinv(void);
+
+extern void cachedwbse(void*, int);
+extern void cacheduwbse(void*, int);
+extern void cachedinvse(void*, int);
+extern void cachedwbinvse(void*, int);
+
+extern void cachedwb(void);
+extern void cachedinv(void);
+extern void cachedwbinv(void);
+
+extern void l2cacheuwb(void);
+extern void l2cacheuinv(void);
+extern void l2cacheuwbinv(void);
+
+/* mmu */
+#define getpgcolor(a) 0
+extern uintptr paddr(void*);
+#define PADDR(a) paddr((void*)(a))
+extern uintptr cankaddr(uintptr);
+extern void* kaddr(uintptr);
+#define KADDR(a) kaddr(a)
+extern void kmapinval(void);
+#define VA(k) ((uintptr)(k))
+extern KMap *kmap(Page*);
+extern void kunmap(KMap*);
+extern uintptr mmukmap(uintptr, uintptr, usize);
+extern void* vmap(uvlong, vlong);
+extern void vunmap(void*, vlong);
+
+extern void mmu0init(uintptr*);
+extern void mmu0clear(uintptr*);
+extern void mmuidmap(uintptr*);
+extern void mmu1init(void);
+extern void meminit(void);
+
+extern void putasid(Proc*);
+
+extern void* ucalloc(usize);
+extern void* fbmemalloc(usize);
+
+/* clock */
+extern void clockinit(void);
+extern void synccycles(void);
+extern void armtimerset(int);
+extern void clockshutdown(void);
+
+/* fpu */
+extern void fpuinit(void);
+extern void fpoff(void);
+extern void fpinit(void);
+extern void fpclear(void);
+extern void fpsave(FPsave*);
+extern void fprestore(FPsave*);
+extern void mathtrap(Ureg*);
+
+/* trap */
+extern void trapinit(void);
+extern int userureg(Ureg*);
+extern void evenaddr(uintptr);
+extern void setkernur(Ureg*, Proc*);
+extern void procfork(Proc*);
+extern void procsetup(Proc*);
+extern void procsave(Proc*);
+extern void procrestore(Proc *);
+extern void trap(Ureg*);
+extern void syscall(Ureg*);
+extern void noted(Ureg*, ulong);
+extern void faultarm64(Ureg*);
+extern void dumpstack(void);
+extern void dumpregs(Ureg*);
+
+/* irq */
+extern void intrinit(void);
+extern void intrcpushutdown(void);
+extern void intrsoff(void);
+extern void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+extern void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*);
+extern int irq(Ureg*);
+extern void fiq(Ureg*);
+
+/* sysreg */
+extern uvlong sysrd(ulong);
+extern void syswr(ulong, uvlong);
+
+/* uartimx */
+extern void uartconsinit(void);
+
+/* dma */
+extern void dmaflush(int, void*, ulong);
+
+/* main */
+extern char *getconf(char *name);
+extern void setconfenv(void);
+extern void writeconf(void);
+
+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);
+
+/* gpc */
+extern void powerup(char *dom);
+
+/* lcd */
+extern void lcdinit(void);
+
+/* iomux */
+extern void iomuxpad(char *pads, char *sel, char *cfg);
+extern uint iomuxgpr(int gpr, uint set, uint mask);
+
+/* gpio */
+#define GPIO_PIN(n, m) ((n)<<5 | (m))
+extern void gpioout(uint pin, int set);
+extern int gpioin(uint pin);
+void gpiointrenable(uint pin, int mode, void (*f)(uint pin, void *a), void *a);
+void gpiointrdisable(uint pin);
+void gpioinit(void);
+
+/* pciimx */
+extern int pcicfgrw8(int tbdf, int rno, int data, int read);
+extern int pcicfgrw16(int tbdf, int rno, int data, int read);
+extern int pcicfgrw32(int tbdf, int rno, int data, int read);
+extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
+extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
diff --git a/sys/src/9/virt/fpu.c b/sys/src/9/virt/fpu.c
new file mode 100644
index 000000000..163678294
--- /dev/null
+++ b/sys/src/9/virt/fpu.c
@@ -0,0 +1,92 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#include "ureg.h"
+#include "sysreg.h"
+
+/* libc */
+extern ulong getfcr(void);
+extern void setfcr(ulong fcr);
+extern ulong getfsr(void);
+extern void setfsr(ulong fsr);
+
+void
+fpuinit(void)
+{
+ fpoff();
+}
+
+void
+fpon(void)
+{
+ syswr(CPACR_EL1, 3<<20);
+}
+
+void
+fpoff(void)
+{
+ syswr(CPACR_EL1, 0<<20);
+}
+
+void
+fpinit(void)
+{
+ fpon();
+ setfcr(0);
+ setfsr(0);
+}
+
+void
+fpclear(void)
+{
+ fpoff();
+}
+
+void
+fpsave(FPsave *p)
+{
+ p->control = getfcr();
+ p->status = getfsr();
+ fpsaveregs(p->regs);
+ fpoff();
+}
+
+void
+fprestore(FPsave *p)
+{
+ fpon();
+ setfcr(p->control);
+ setfsr(p->status);
+ fploadregs(p->regs);
+}
+
+void
+mathtrap(Ureg*)
+{
+ int s;
+
+ if((up->fpstate & FPillegal) != 0){
+ postnote(up, 1, "sys: floating point in note handler", NDebug);
+ return;
+ }
+ switch(up->fpstate){
+ case FPinit:
+ s = splhi();
+ fpinit();
+ up->fpstate = FPactive;
+ splx(s);
+ break;
+ case FPinactive:
+ s = splhi();
+ fprestore(up->fpsave);
+ up->fpstate = FPactive;
+ splx(s);
+ break;
+ case FPactive:
+ postnote(up, 1, "sys: floating point error", NDebug);
+ break;
+ }
+}
diff --git a/sys/src/9/virt/gic.c b/sys/src/9/virt/gic.c
new file mode 100644
index 000000000..66da3266a
--- /dev/null
+++ b/sys/src/9/virt/gic.c
@@ -0,0 +1,295 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "ureg.h"
+#include "sysreg.h"
+#include "../port/error.h"
+
+enum {
+ GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
+ GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
+ GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
+
+ GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
+
+ GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
+ GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
+
+ GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
+ GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
+
+ GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
+ GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
+
+ GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
+ GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
+ GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
+
+ GICD_ISR0 = 0xD00/4,
+ GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
+ GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
+ GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
+
+ GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
+ GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
+
+ GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
+ GICD_PIDR5 = 0xFD4/4,
+ GICD_PIDR6 = 0xFD8/4,
+ GICD_PIDR7 = 0xFDC/4,
+ GICD_PIDR0 = 0xFE0/4,
+ GICD_PIDR1 = 0xFE4/4,
+ GICD_PIDR2 = 0xFE8/4,
+ GICD_PIDR3 = 0xFEC/4,
+
+ GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
+ GICD_CIDR1 = 0xFF4/4,
+ GICD_CIDR2 = 0xFF8/4,
+ GICD_CIDR3 = 0xFFC/4,
+
+ GICC_CTLR = 0x000/4, /* RW, CPU Interace Control Register */
+ GICC_PMR = 0x004/4, /* RW, Interrupt Priority Mask Register */
+ GICC_BPR = 0x008/4, /* RW, Binary Point Register */
+ GICC_IAR = 0x00C/4, /* RO, Interrupt Acknowledge Register */
+ GICC_EOIR = 0x010/4, /* WO, End of Interrupt Register */
+ GICC_RPR = 0x014/4, /* RO, Running Priority Register */
+ GICC_HPPIR = 0x018/4, /* RO, Highest Priority Pending Interrupt Register */
+ GICC_ABPR = 0x01C/4, /* RW, Aliased Binary Point Register */
+ GICC_AIAR = 0x020/4, /* RO, Aliased Interrupt Acknowledge Register */
+ GICC_AEOIR = 0x024/4, /* WO, Aliased End of Interrupt Register */
+ GICC_AHPPIR = 0x028/4, /* RO, Aliased Highest Priority Pending Interrupt Register */
+ GICC_APR0 = 0x0D0/4, /* RW, Active Priority Register */
+ GICC_NSAPR0 = 0x0E0/4, /* RW, Non-Secure Active Priority Register */
+ GICC_IIDR = 0x0FC/4, /* RO, CPU Interface Identification Register */
+ GICC_DIR = 0x1000/4, /* WO, Deactivate Interrupt Register */
+
+ GICH_HCR = 0x000/4, /* RW, Hypervisor Control Register */
+ GICH_VTR = 0x004/4, /* RO, VGIC Type Register */
+ GICH_VMCR = 0x008/4, /* RW, Virtual Machine Control Register */
+ GICH_MISR = 0x010/4, /* RO, Maintenance Interrupt Status Register */
+ GICH_EISR0 = 0x020/4, /* RO, End of Interrupt Status Register */
+ GICH_ELSR0 = 0x030/4, /* RO, Empty List Register Status Register */
+ GICH_APR0 = 0x0F0/4, /* RW, Active Priority Register */
+ GICH_LR0 = 0x100/4, /* RW, List Registers (0x100-0x10C) */
+
+ GICV_CTLR = 0x000/4, /* RW, Virtual Machine Control Register */
+ GICV_PMR = 0x004/4, /* RW, VM Priority Mask Register */
+ GICV_BPR = 0x008/4, /* RW, VM Binary Point Register */
+ GICV_IAR = 0x00C/4, /* RO, VM Interrupt Acknowledge Register */
+ GICV_EOIR = 0x010/4, /* WO, VM End of Interrupt Register */
+ GICV_RPR = 0x014/4, /* RO, VM Running Priority Register */
+ GICV_HPPIR = 0x018/4, /* RO, VM Highest Piority Pending Interrupt Register */
+ GICV_ABPR = 0x01C/4, /* RW, VM Aliased Binary Point Register */
+ GICV_AIAR = 0x020/4, /* RO, VM Aliased Interrupt Acknowledge Register */
+ GICV_AEOIR = 0x024/4, /* WO, VM Aliased End of Interrupt Register */
+ GICV_AHPPIR = 0x028/4, /* RO, VM Aliaed Highest Piority Pending Interrupt Register */
+ GICV_APR0 = 0x0D0/4, /* RW, VM Active Priority Register */
+ GICV_IIDR = 0x0FC/4, /* RO, VM CPU Interface Identification Register */
+ GICV_DIR = 0x1000/4, /* WO, VM Deactivate Interrupt Register */
+};
+
+typedef struct Vctl Vctl;
+struct Vctl {
+ Vctl *next;
+ void (*f)(Ureg*, void*);
+ void *a;
+ int irq;
+ u32int intid;
+};
+
+static Lock vctllock;
+static Vctl *vctl[MAXMACH][32], *vfiq;
+static u32int *cregs, *dregs;
+
+void
+intrcpushutdown(void)
+{
+ if(cregs == nil || dregs == nil){
+ uintptr va;
+ va = VIRTIO;
+ dregs = (u32int*)(va);
+ cregs = (u32int*)(va + 0x10000);
+ }
+
+ /* disable cpu interface */
+ cregs[GICC_CTLR] &= ~1;
+ coherence();
+}
+
+void
+intrsoff(void)
+{
+ int i, n;
+
+ intrcpushutdown();
+
+ /* disable distributor */
+ dregs[GICD_CTLR] &= ~1;
+ coherence();
+
+ /* clear all interrupts */
+ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
+ for(i = 0; i < n; i += 32){
+ dregs[GICD_ISENABLER0 + (i/32)] = -1;
+ coherence();
+ dregs[GICD_ICENABLER0 + (i/32)] = -1;
+ coherence();
+ }
+ for(i = 0; i < n; i += 4){
+ dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
+ dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ }
+ for(i = 32; i < n; i += 16)
+ dregs[GICD_ICFGR0 + (i/16)] = 0;
+ coherence();
+}
+
+
+/*
+ * called by trap to handle irq interrupts.
+ * returns true iff a clock interrupt, thus maybe reschedule.
+ */
+int
+irq(Ureg* ureg)
+{
+ Vctl *v;
+ int clockintr;
+ u32int intid;
+
+ m->intr++;
+ intid = cregs[GICC_IAR] & 0xFFFFFF;
+ if((intid & ~3) == 1020)
+ return 0; // spurious
+ clockintr = 0;
+ for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
+ if(v->intid == intid){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
+ clockintr = 1;
+ }
+ coherence();
+ cregs[GICC_EOIR] = intid;
+ return clockintr;
+}
+
+/*
+ * called direct from lexception.s to handle fiq interrupt.
+ */
+void
+fiq(Ureg *ureg)
+{
+ Vctl *v;
+ u32int intid;
+
+ m->intr++;
+ intid = cregs[GICC_IAR] & 0xFFFFFF;
+ if((intid & ~3) == 1020)
+ return; // spurious
+ v = vfiq;
+ if(v != nil && v->intid == intid && m->machno == 0){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ }
+ cregs[GICC_EOIR] = intid;
+}
+
+void
+intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ Vctl *v;
+ u32int intid;
+ int cpu, prio;
+
+ if(BUSTYPE(tbdf) == BusPCI){
+ //pciintrenable(tbdf, f, a);
+ return;
+ }
+ if(tbdf != BUSUNKNOWN)
+ return;
+
+ cpu = 0;
+ prio = 0x80;
+ intid = irq;
+ switch(irq){
+ case IRQcntps:
+ intid = 16 + 13;
+ break;
+ case IRQcntpns:
+ intid = 16 + 14;
+ break;
+
+ case IRQmbox0:
+ case IRQmbox1:
+ case IRQmbox2:
+ case IRQmbox3:
+ case IRQlocaltmr:
+ print("irqenable: missing documentation for local irq %d\n", irq);
+ return;
+
+ default:
+ if(irq < IRQgic){
+ if(irq < 64)
+ intid += IRQgic-64;
+ else if(irq >= IRQbasic)
+ intid += IRQgic-64-32-8-IRQbasic;
+ }
+ }
+ if(intid < 32)
+ cpu = m->machno;
+
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("irqenable: no mem");
+ v->irq = irq;
+ v->intid = intid;
+ v->f = f;
+ v->a = a;
+
+ lock(&vctllock);
+ if(irq == IRQfiq){
+ vfiq = v;
+ prio = 0;
+ }else{
+ v->next = vctl[cpu][intid%32];
+ vctl[cpu][intid%32] = v;
+ }
+
+ /* enable cpu interface */
+ cregs[GICC_PMR] = 0xFF;
+ coherence();
+
+ cregs[GICC_CTLR] |= 1;
+ coherence();
+
+ cregs[GICC_EOIR] = intid;
+
+ /* enable distributor */
+ dregs[GICD_CTLR] |= 1;
+ coherence();
+
+ /* setup */
+ dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
+ coherence();
+
+ /* turn on */
+ dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
+ coherence();
+
+ unlock(&vctllock);
+}
+
+void
+intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ if(BUSTYPE(tbdf) == BusPCI){
+ //pciintrdisable(tbdf, f, a);
+ return;
+ }
+}
diff --git a/sys/src/9/virt/gic_reform.c b/sys/src/9/virt/gic_reform.c
new file mode 100644
index 000000000..ae0ec335a
--- /dev/null
+++ b/sys/src/9/virt/gic_reform.c
@@ -0,0 +1,321 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "ureg.h"
+#include "sysreg.h"
+#include "../port/error.h"
+
+enum {
+ GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
+ GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
+ GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
+
+ GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
+
+ GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
+ GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
+
+ GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
+ GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
+
+ GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
+ GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
+
+ GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
+ GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
+ GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
+
+ GICD_ISR0 = 0xD00/4,
+ GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
+ GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
+ GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
+
+ GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
+ GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
+
+ GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
+ GICD_PIDR5 = 0xFD4/4,
+ GICD_PIDR6 = 0xFD8/4,
+ GICD_PIDR7 = 0xFDC/4,
+ GICD_PIDR0 = 0xFE0/4,
+ GICD_PIDR1 = 0xFE4/4,
+ GICD_PIDR2 = 0xFE8/4,
+ GICD_PIDR3 = 0xFEC/4,
+
+ GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
+ GICD_CIDR1 = 0xFF4/4,
+ GICD_CIDR2 = 0xFF8/4,
+ GICD_CIDR3 = 0xFFC/4,
+
+ RD_base = 0x00000,
+ GICR_CTLR = (RD_base+0x000)/4,
+ GICR_IIDR = (RD_base+0x004)/4,
+ GICR_TYPER = (RD_base+0x008)/4,
+ GICR_STATUSR = (RD_base+0x010)/4,
+ GICR_WAKER = (RD_base+0x014)/4,
+ GICR_SETLPIR = (RD_base+0x040)/4,
+ GICR_CLRLPIR = (RD_base+0x048)/4,
+ GICR_PROPBASER = (RD_base+0x070)/4,
+ GICR_PENDBASER = (RD_base+0x078)/4,
+ GICR_INVLPIR = (RD_base+0x0A0)/4,
+ GICR_INVALLR = (RD_base+0x0B0)/4,
+ GICR_SYNCR = (RD_base+0x0C0)/4,
+
+ SGI_base = 0x10000,
+ GICR_IGROUPR0 = (SGI_base+0x080)/4,
+ GICR_ISENABLER0 = (SGI_base+0x100)/4,
+ GICR_ICENABLER0 = (SGI_base+0x180)/4,
+ GICR_ISPENDR0 = (SGI_base+0x200)/4,
+ GICR_ICPENDR0 = (SGI_base+0x280)/4,
+ GICR_ISACTIVER0 = (SGI_base+0x300)/4,
+ GICR_ICACTIVER0 = (SGI_base+0x380)/4,
+ GICR_IPRIORITYR0= (SGI_base+0x400)/4,
+ GICR_ICFGR0 = (SGI_base+0xC00)/4,
+ GICR_ICFGR1 = (SGI_base+0xC04)/4,
+ GICR_IGRPMODR0 = (SGI_base+0xD00)/4,
+ GICR_NSACR = (SGI_base+0xE00)/4,
+};
+
+typedef struct Vctl Vctl;
+struct Vctl {
+ Vctl *next;
+ void (*f)(Ureg*, void*);
+ void *a;
+ int irq;
+ u32int intid;
+};
+
+static Lock vctllock;
+static Vctl *vctl[MAXMACH][32], *vfiq;
+// distributor
+static u32int *dregs = (u32int*)(VIRTIO + 0x0);
+
+static u32int*
+getrregs(int machno)
+{
+ u32int *rregs = (u32int*)(VIRTIO + 0x10000); // cpu
+
+ for(;;){
+ if((rregs[GICR_TYPER] & 0xFFFF00) == (machno << 8))
+ return rregs;
+ if(rregs[GICR_TYPER] & (1<<4))
+ break;
+ rregs += (0x20000/4);
+ }
+ panic("getrregs: no re-distributor for cpu %d\n", machno);
+ return nil;
+}
+
+void
+intrcpushutdown(void)
+{
+ /* disable cpu interface */
+ syswr(ICC_IGRPEN0_EL1, 0);
+ syswr(ICC_IGRPEN1_EL1, 0);
+ coherence();
+}
+
+void
+intrsoff(void)
+{
+ /* disable distributor */
+ dregs[GICD_CTLR] = 0;
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+}
+
+void
+intrinit(void)
+{
+ u32int *rregs;
+ int i, n;
+
+ if(m->machno == 0){
+ intrsoff();
+
+ /* clear all interrupts */
+ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
+ for(i = 32; i < n; i += 32){
+ dregs[GICD_IGROUPR0 + (i/32)] = -1;
+
+ dregs[GICD_ISENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
+ dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ }
+ for(i = 32; i < n; i += 16){
+ dregs[GICD_ICFGR0 + (i/16)] = 0;
+ }
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_CTLR] = (1<<0) | (1<<1) | (1<<4);
+ }
+
+ rregs = getrregs(m->machno);
+ n = 32;
+ for(i = 0; i < n; i += 32){
+ rregs[GICR_IGROUPR0 + (i/32)] = -1;
+
+ rregs[GICR_ISENABLER0 + (i/32)] = -1;
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ rregs[GICR_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ rregs[GICR_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ rregs[GICR_IPRIORITYR0 + (i/4)] = 0;
+ }
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+
+ coherence();
+
+ /* enable cpu interface */
+ syswr(ICC_CTLR_EL1, 0);
+ syswr(ICC_BPR1_EL1, 7);
+ syswr(ICC_PMR_EL1, 0xFF);
+
+ coherence();
+}
+
+
+/*
+ * called by trap to handle irq interrupts.
+ * returns true iff a clock interrupt, thus maybe reschedule.
+ */
+int
+irq(Ureg* ureg)
+{
+ Vctl *v;
+ int clockintr;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("i<%d>", intid);
+ if((intid & ~3) == 1020)
+ return 0; // spurious
+ clockintr = 0;
+ for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
+ if(v->intid == intid){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ if(v->irq == IRQcntpns)
+ clockintr = 1;
+ }
+ coherence();
+ syswr(ICC_EOIR1_EL1, intid);
+ return clockintr;
+}
+
+/*
+ * called direct from lexception.s to handle fiq interrupt.
+ */
+void
+fiq(Ureg *ureg)
+{
+ Vctl *v;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("f<%d>", intid);
+ if((intid & ~3) == 1020)
+ return; // spurious
+ v = vfiq;
+ if(v != nil && v->intid == intid && m->machno == 0){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ }
+ syswr(ICC_EOIR1_EL1, intid);
+}
+
+void
+intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *)
+{
+ Vctl *v;
+ u32int intid;
+ int cpu, prio;
+
+ if(BUSTYPE(tbdf) == BusPCI){
+ //pciintrenable(tbdf, f, a);
+ return;
+ }
+
+ if(tbdf != BUSUNKNOWN)
+ return;
+
+ prio = 0x80;
+ intid = irq;
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: no mem");
+ v->irq = irq;
+ v->intid = intid;
+ v->f = f;
+ v->a = a;
+
+ lock(&vctllock);
+ if(intid < SPI)
+ cpu = m->machno;
+ else
+ cpu = 0;
+ if(irq == IRQfiq){
+ vfiq = v;
+ prio = 0;
+ }else{
+ v->next = vctl[cpu][intid%32];
+ vctl[cpu][intid%32] = v;
+ }
+ syswr(ICC_IGRPEN1_EL1, sysrd(ICC_IGRPEN1_EL1)|1);
+ coherence();
+
+ syswr(ICC_EOIR1_EL1, intid);
+ coherence();
+
+ /* setup */
+ if(intid < 32){
+ u32int *rregs = getrregs(cpu);
+ rregs[GICR_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ coherence();
+ rregs[GICR_ISENABLER0] = 1 << (intid%32);
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ } else {
+ dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
+ coherence();
+ dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ }
+ unlock(&vctllock);
+}
+
+void
+intrdisable(int tbdf, void (*f)(Ureg*, void*), void *a, int, char*)
+{
+ if(BUSTYPE(tbdf) == BusPCI){
+ //pciintrdisable(tbdf, f, a);
+ return;
+ }
+}
diff --git a/sys/src/9/virt/init9.s b/sys/src/9/virt/init9.s
new file mode 100644
index 000000000..45ae62fea
--- /dev/null
+++ b/sys/src/9/virt/init9.s
@@ -0,0 +1,4 @@
+TEXT main(SB), 1, $8
+ MOV $setSB(SB), R28 /* load the SB */
+ MOV $boot(SB), R0
+ B startboot(SB)
diff --git a/sys/src/9/virt/io.h b/sys/src/9/virt/io.h
new file mode 100644
index 000000000..8b2f9b08e
--- /dev/null
+++ b/sys/src/9/virt/io.h
@@ -0,0 +1,11 @@
+#include "../bcm/io.h"
+
+enum {
+ IRQgic = 160,
+ IRQpci = IRQgic + 20,
+ IRQether = IRQgic + 29,
+ IRQuart1 = IRQgic + 30,
+};
+
+#define PCIWINDOW soc.pcidmawin
+#define PCIWADDR(va) (PADDR(va)+PCIWINDOW)
diff --git a/sys/src/9/virt/iomux.c b/sys/src/9/virt/iomux.c
new file mode 100644
index 000000000..9aed7562c
--- /dev/null
+++ b/sys/src/9/virt/iomux.c
@@ -0,0 +1,1139 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+static u32int *iomuxc = (u32int*)(VIRTIO + 0x330000);
+
+enum {
+ IOMUXC_SW_MUX_CTL_PAD_PMIC_STBY_REQ = 0x014/4,
+ SION = 1<<4,
+ MUX_MODE = 7,
+
+ IOMUXC_SW_PAD_CTL_PAD_TEST_MODE = 0x254/4,
+
+ IOMUXC_CCM_PMIC_READY_SELECT_INPUT = 0x4BC/4,
+
+ IOMUXC_GPR_GPR0 = 0x10000/4,
+};
+
+enum {
+ /* pads without muxes */
+ PAD_TEST_MODE = 0,
+
+ PAD_BOOT_MODE0, PAD_BOOT_MODE1,
+
+ PAD_JTAG_MOD, PAD_JTAG_TRST_B, PAD_JTAG_TDI, PAD_JTAG_TMS,
+ PAD_JTAG_TCK, PAD_JTAG_TDO,
+
+ PAD_RTC,
+
+ PAD_PMIC_STBY_REQ, PAD_PMIC_ON_REQ,
+ PAD_ONOFF, PAD_POR_B, PAD_RTC_RESET_B,
+
+ /* pads with muxes */
+ PAD_GPIO1_IO00, PAD_GPIO1_IO01, PAD_GPIO1_IO02, PAD_GPIO1_IO03,
+ PAD_GPIO1_IO04, PAD_GPIO1_IO05, PAD_GPIO1_IO06, PAD_GPIO1_IO07,
+ PAD_GPIO1_IO08, PAD_GPIO1_IO09, PAD_GPIO1_IO10, PAD_GPIO1_IO11,
+ PAD_GPIO1_IO12, PAD_GPIO1_IO13, PAD_GPIO1_IO14, PAD_GPIO1_IO15,
+
+ PAD_ENET_MDC, PAD_ENET_MDIO,
+ PAD_ENET_TD3, PAD_ENET_TD2, PAD_ENET_TD1, PAD_ENET_TD0,
+ PAD_ENET_TX_CTL, PAD_ENET_TXC, PAD_ENET_RX_CTL, PAD_ENET_RXC,
+ PAD_ENET_RD0, PAD_ENET_RD1, PAD_ENET_RD2, PAD_ENET_RD3,
+
+ PAD_SD1_CLK, PAD_SD1_CMD, PAD_SD1_DATA0, PAD_SD1_DATA1,
+ PAD_SD1_DATA2, PAD_SD1_DATA3, PAD_SD1_DATA4, PAD_SD1_DATA5,
+ PAD_SD1_DATA6, PAD_SD1_DATA7, PAD_SD1_RESET_B, PAD_SD1_STROBE,
+
+ PAD_SD2_CD_B, PAD_SD2_CLK, PAD_SD2_CMD, PAD_SD2_DATA0,
+ PAD_SD2_DATA1, PAD_SD2_DATA2, PAD_SD2_DATA3,
+ PAD_SD2_RESET_B, PAD_SD2_WP,
+
+ PAD_NAND_ALE, PAD_NAND_CE0_B, PAD_NAND_CE1_B, PAD_NAND_CE2_B,
+ PAD_NAND_CE3_B, PAD_NAND_CLE, PAD_NAND_DATA0, PAD_NAND_DATA1,
+ PAD_NAND_DATA2, PAD_NAND_DATA3, PAD_NAND_DATA4,
+ PAD_NAND_DATA5, PAD_NAND_DATA6, PAD_NAND_DATA7, PAD_NAND_DQS,
+ PAD_NAND_RE_B, PAD_NAND_READY_B, PAD_NAND_WE_B, PAD_NAND_WP_B,
+
+ PAD_SAI5_RXFS, PAD_SAI5_RXC, PAD_SAI5_RXD0, PAD_SAI5_RXD1,
+ PAD_SAI5_RXD2, PAD_SAI5_RXD3, PAD_SAI5_MCLK,
+
+ PAD_SAI1_RXFS, PAD_SAI1_RXC, PAD_SAI1_RXD0, PAD_SAI1_RXD1,
+ PAD_SAI1_RXD2, PAD_SAI1_RXD3, PAD_SAI1_RXD4, PAD_SAI1_RXD5,
+ PAD_SAI1_RXD6, PAD_SAI1_RXD7, PAD_SAI1_TXFS, PAD_SAI1_TXC,
+ PAD_SAI1_TXD0, PAD_SAI1_TXD1, PAD_SAI1_TXD2, PAD_SAI1_TXD3,
+ PAD_SAI1_TXD4, PAD_SAI1_TXD5, PAD_SAI1_TXD6, PAD_SAI1_TXD7,
+ PAD_SAI1_MCLK,
+
+ PAD_SAI2_RXFS, PAD_SAI2_RXC, PAD_SAI2_RXD0, PAD_SAI2_TXFS,
+ PAD_SAI2_TXC, PAD_SAI2_TXD0, PAD_SAI2_MCLK,
+
+ PAD_SAI3_RXFS, PAD_SAI3_RXC, PAD_SAI3_RXD, PAD_SAI3_TXFS,
+ PAD_SAI3_TXC, PAD_SAI3_TXD, PAD_SAI3_MCLK,
+
+ PAD_SPDIF_TX, PAD_SPDIF_RX, PAD_SPDIF_EXT_CLK,
+
+ PAD_ECSPI1_SCLK, PAD_ECSPI1_MOSI, PAD_ECSPI1_MISO, PAD_ECSPI1_SS0,
+ PAD_ECSPI2_SCLK, PAD_ECSPI2_MOSI, PAD_ECSPI2_MISO, PAD_ECSPI2_SS0,
+
+ PAD_I2C1_SCL, PAD_I2C1_SDA,
+ PAD_I2C2_SCL, PAD_I2C2_SDA,
+ PAD_I2C3_SCL, PAD_I2C3_SDA,
+ PAD_I2C4_SCL, PAD_I2C4_SDA,
+
+ PAD_UART1_RXD, PAD_UART1_TXD,
+ PAD_UART2_RXD, PAD_UART2_TXD,
+ PAD_UART3_RXD, PAD_UART3_TXD,
+ PAD_UART4_RXD, PAD_UART4_TXD,
+};
+
+enum {
+ /* signals with input muxes (must be first for daisytab) */
+ CCM_PMIC_READY = 0,
+ ENET1_MDIO,
+ PCIE1_CLKREQ_B, PCIE2_CLKREQ_B,
+ SAI1_RX_BCLK, SAI1_RX_SYNC, SAI1_TX_SYNC,
+ SAI5_MCLK, SAI5_RXD0, SAI5_RXD1, SAI5_RXD2, SAI5_RXD3,
+ SAI5_RX_BCLK, SAI5_RX_SYNC, SAI5_TX_BLCK, SAI5_TX_SYNC,
+ SAI6_MCLK, SAI6_RXD0, SAI6_RX_BCLK, SAI6_RX_SYNC,
+ SAI6_TX_BCLK, SAY6_TX_SYNC,
+ UART1_RTS_B, UART1_RXD,
+ UART2_RTS_B, UART2_RXD,
+ UART3_RTS_B, UART3_RXD,
+ UART4_RTS_B, UART4_RXD,
+
+ /* signals without input muxes */
+ ANAMIX_REF_CLK_25M,
+ ANAMIX_REF_CLK_32K,
+ CCM_CLKO1,
+ CCM_CLKO2,
+ CCM_ENET_PHY_REF_CLK_ROOT,
+ CCM_EXT_CLK1,
+ CCM_EXT_CLK2,
+ CCM_EXT_CLK3,
+ CCM_EXT_CLK4,
+
+ CORESIGHT_EVENTI, CORESIGHT_EVENTO, CORESIGHT_TRACE0,
+ CORESIGHT_TRACE1, CORESIGHT_TRACE10, CORESIGHT_TRACE11,
+ CORESIGHT_TRACE12, CORESIGHT_TRACE13, CORESIGHT_TRACE14,
+ CORESIGHT_TRACE15, CORESIGHT_TRACE2, CORESIGHT_TRACE3,
+ CORESIGHT_TRACE4, CORESIGHT_TRACE5, CORESIGHT_TRACE6,
+ CORESIGHT_TRACE7, CORESIGHT_TRACE8, CORESIGHT_TRACE9,
+ CORESIGHT_TRACE_CLK, CORESIGHT_TRACE_CTL,
+
+ ECSPI1_MISO, ECSPI1_MOSI, ECSPI1_SCLK, ECSPI1_SS0,
+ ECSPI2_MISO, ECSPI2_MOSI, ECSPI2_SCLK, ECSPI2_SS0,
+ ECSPI3_MISO, ECSPI3_MOSI, ECSPI3_SCLK, ECSPI3_SS0,
+ ENET1_1588_EVENT0_IN, ENET1_1588_EVENT0_OUT,
+ ENET1_1588_EVENT1_IN, ENET1_1588_EVENT1_OUT,
+ ENET1_MDC, ENET1_RGMII_RD0, ENET1_RGMII_RD1, ENET1_RGMII_RD2,
+ ENET1_RGMII_RD3, ENET1_RGMII_RXC, ENET1_RGMII_RX_CTL,
+ ENET1_RGMII_TD0, ENET1_RGMII_TD1, ENET1_RGMII_TD2,
+ ENET1_RGMII_TD3, ENET1_RGMII_TXC, ENET1_RGMII_TX_CTL,
+ ENET1_RX_ER, ENET1_TX_CLK, ENET1_TX_ER,
+
+ GPIO1_IO00, GPIO1_IO01, GPIO1_IO02, GPIO1_IO03, GPIO1_IO04,
+ GPIO1_IO05, GPIO1_IO06, GPIO1_IO07, GPIO1_IO08, GPIO1_IO09,
+ GPIO1_IO10, GPIO1_IO11, GPIO1_IO12, GPIO1_IO13, GPIO1_IO14,
+ GPIO1_IO15, GPIO1_IO16, GPIO1_IO17, GPIO1_IO18, GPIO1_IO19,
+ GPIO1_IO20, GPIO1_IO21, GPIO1_IO22, GPIO1_IO23, GPIO1_IO24,
+ GPIO1_IO25, GPIO1_IO26, GPIO1_IO27, GPIO1_IO28, GPIO1_IO29,
+
+ GPIO2_IO00, GPIO2_IO01, GPIO2_IO02, GPIO2_IO03, GPIO2_IO04,
+ GPIO2_IO05, GPIO2_IO06, GPIO2_IO07, GPIO2_IO08, GPIO2_IO09,
+ GPIO2_IO10, GPIO2_IO11, GPIO2_IO12, GPIO2_IO13, GPIO2_IO14,
+ GPIO2_IO15, GPIO2_IO16, GPIO2_IO17, GPIO2_IO18, GPIO2_IO19,
+ GPIO2_IO20,
+
+ GPIO3_IO00, GPIO3_IO01, GPIO3_IO02, GPIO3_IO03, GPIO3_IO04,
+ GPIO3_IO05, GPIO3_IO06, GPIO3_IO07, GPIO3_IO08, GPIO3_IO09,
+ GPIO3_IO10, GPIO3_IO11, GPIO3_IO12, GPIO3_IO13, GPIO3_IO14,
+ GPIO3_IO15, GPIO3_IO16, GPIO3_IO17, GPIO3_IO18, GPIO3_IO19,
+ GPIO3_IO20, GPIO3_IO21, GPIO3_IO22, GPIO3_IO23, GPIO3_IO24,
+ GPIO3_IO25,
+
+ GPIO4_IO00, GPIO4_IO01, GPIO4_IO02, GPIO4_IO03, GPIO4_IO04,
+ GPIO4_IO05, GPIO4_IO06, GPIO4_IO07, GPIO4_IO08, GPIO4_IO09,
+ GPIO4_IO10, GPIO4_IO11, GPIO4_IO12, GPIO4_IO13, GPIO4_IO14,
+ GPIO4_IO15, GPIO4_IO16, GPIO4_IO17, GPIO4_IO18, GPIO4_IO19,
+ GPIO4_IO20, GPIO4_IO21, GPIO4_IO22, GPIO4_IO23, GPIO4_IO24,
+ GPIO4_IO25, GPIO4_IO26, GPIO4_IO27, GPIO4_IO28, GPIO4_IO29,
+ GPIO4_IO31,
+
+ GPIO5_IO00, GPIO5_IO01, GPIO5_IO02, GPIO5_IO03, GPIO5_IO04,
+ GPIO5_IO05, GPIO5_IO06, GPIO5_IO07, GPIO5_IO08, GPIO5_IO09,
+ GPIO5_IO10, GPIO5_IO11, GPIO5_IO12, GPIO5_IO13, GPIO5_IO14,
+ GPIO5_IO15, GPIO5_IO16, GPIO5_IO17, GPIO5_IO18, GPIO5_IO19,
+ GPIO5_IO20, GPIO5_IO21, GPIO5_IO22, GPIO5_IO23, GPIO5_IO24,
+ GPIO5_IO25, GPIO5_IO26, GPIO5_IO27, GPIO5_IO28, GPIO5_IO29,
+
+ GPT1_CAPTURE1, GPT1_CAPTURE2, GPT1_COMPARE1, GPT1_COMPARE2,
+ GPT1_COMPARE3, GPT1_CLK, GPT2_CLK, GPT3_CLK,
+
+ I2C1_SCL, I2C1_SDA,
+ I2C2_SCL, I2C2_SDA,
+ I2C3_SCL, I2C3_SDA,
+ I2C4_SCL, I2C4_SDA,
+ M4_NMI,
+ PCIE_CLKREQ_B,
+ PWM1_OUT, PWM2_OUT, PWM3_OUT, PWM4_OUT,
+
+ QSPI_A_DATA0, QSPI_A_DATA1, QSPI_A_DATA2, QSPI_A_DATA3,
+ QSPI_A_DQS, QSPI_A_SCLK, QSPI_A_SS0_B, QSPI_A_SS1_B,
+
+ QSPI_B_DATA0, QSPI_B_DATA1, QSPI_B_DATA2, QSPI_B_DATA3,
+ QSPI_B_DQS, QSPI_B_SCLK, QSPI_B_SS0_B, QSPI_B_SS1_B,
+
+ RAWNAND_ALE, RAWNAND_CE0_B, RAWNAND_CE1_B, RAWNAND_CE2_B,
+ RAWNAND_CE3_B, RAWNAND_CLE, RAWNAND_DATA00, RAWNAND_DATA01,
+ RAWNAND_DATA02, RAWNAND_DATA03, RANWNAD_DATA04,
+ RAWNAND_DATA05, RAWNAND_DATA06, RAWNAND_DATA07, RAWNAND_DQS,
+ RAWNAND_READY_B, RAWNAND_RE_B, RAWNAND_WE_B, RAWNAND_WP_B,
+
+ SAI1_MCLK, SAI1_RX_DATA0, SAI1_RX_DATA1, SAI1_RX_DATA2,
+ SAI1_RX_DATA3, SAI1_RX_DATA4, SAI1_RX_DATA5, SAI1_RX_DATA6,
+ SAI1_RX_DATA7, SAI1_TX_BCLK, SAI1_TX_DATA0, SAI1_TX_DATA1,
+ SAI1_TX_DATA2, SAI1_TX_DATA3, SAI1_TX_DATA4, SAI1_TX_DATA5,
+ SAI1_TX_DATA6, SAI1_TX_DATA7,
+
+ SAI2_MCLK, SAI2_RX_BCLK, SAI2_RX_DATA0, SAI2_RX_SYNC,
+ SAI2_TX_BCLK, SAI2_TX_DATA0, SAI2_TX_SYNC,
+ SAI3_MCLK, SAI3_RX_BCLK, SAI3_RX_DATA0, SAI3_RX_SYNC,
+ SAI3_TX_BCLK, SAI3_TX_DATA0, SAI3_TX_SYNC,
+
+ SAI4_MCLK,
+
+ SAI5_RX_DATA0, SAI5_RX_DATA1, SAI5_RX_DATA2, SAI5_RX_DATA3,
+ SAI5_TX_BCLK, SAI5_TX_DATA0, SAI5_TX_DATA1, SAI5_TX_DATA2,
+ SAI5_TX_DATA3,
+
+ SAI6_RC_BCLK, SAI6_RX_DATA0, SAI6_TX_DATA0, SAI6_TX_SYNC,
+
+ SDMA1_EXT_EVENT0, SDMA1_EXT_EVENT1,
+ SDMA2_EXT_EVENT0, SDMA2_EXT_EVENT1,
+
+ SJC_DE_B,
+
+ SPDIF1_EXT_CLK, SPDIF1_IN, SPDIF1_OUT,
+
+ SRC_BOOT_CFG0, SRC_BOOT_CFG1, SRC_BOOT_CFG2, SRC_BOOT_CFG3,
+ SRC_BOOT_CFG4, SRC_BOOT_CFG5, SRC_BOOT_CFG6, SRC_BOOT_CFG7,
+ SRC_BOOT_CFG8, SRC_BOOT_CFG9, SRC_BOOT_CFG10, SRC_BOOT_CFG11,
+ SRC_BOOT_CFG12, SRC_BOOT_CFG13, SRC_BOOT_CFG14, SRC_BOOT_CFG15,
+
+ UART1_CTS_B, UART1_RX, UART1_TX,
+ UART2_CTS_B, UART2_RX, UART2_TX,
+ UART3_CTS_B, UART3_RX, UART3_TX,
+ UART4_CTS_B, UART4_RX, UART4_TX,
+
+ USB1_OTG_ID, USB1_OTG_OC, USB1_OTG_PWR,
+ USB2_OTG_ID, USB2_OTG_OC, USB2_OTG_PWR,
+
+ USDHC1_CD_B, USDHC1_CLK, USDHC1_CMD, USDHC1_DATA0,
+ USDHC1_DATA1, USDHC1_DATA2, USDHC1_DATA3, USDHC1_DATA4,
+ USDHC1_DATA5, USDHC1_DATA6, USDHC1_DATA7, USDHC1_RESET_B,
+ USDHC1_STROBE, USDHC1_VSELECT, USDHC1_WP,
+
+ USDHC2_CD_B, USDHC2_CLK, USDHC2_CMD, USDHC2_DATA0,
+ USDHC2_DATA1, USDHC2_DATA2, USDHC2_DATA3, USDHC2_RESET_B,
+ USDHC2_VSELECT, USDHC2_WP,
+
+ WDOG1_WDOG_ANY, WDOG1_WDOG_B,
+};
+
+#define DAISY(x) (0x8000|(((x)&7)<<12))
+#define DAISY_VAL(x) (((x)>>12)&7)
+#define DAISY_ID(x) ((x) & ~DAISY(7))
+
+static ushort daisytab[] = {
+ [CCM_PMIC_READY] 0 | DAISY(1),
+ [ENET1_MDIO] 1 | DAISY(3),
+ [PCIE1_CLKREQ_B] 26 | DAISY(1),
+ [PCIE2_CLKREQ_B] 27 | DAISY(1),
+ [SAI1_RX_BCLK] 3 | DAISY(3),
+ [SAI1_RX_SYNC] 2 | DAISY(1),
+ [SAI1_TX_SYNC] 4 | DAISY(7),
+ [SAI5_MCLK] 28 | DAISY(3),
+ [SAI5_RXD0] 6 | DAISY(3),
+ [SAI5_RXD1] 7 | DAISY(3),
+ [SAI5_RXD2] 8 | DAISY(3),
+ [SAI5_RXD3] 9 | DAISY(3),
+ [SAI5_RX_BCLK] 5 | DAISY(3),
+ [SAI5_RX_SYNC] 10 | DAISY(3),
+ [SAI5_TX_BLCK] 11 | DAISY(3),
+ [SAI5_TX_SYNC] 12 | DAISY(3),
+ [SAI6_MCLK] 29 | DAISY(1),
+ [SAI6_RXD0] 22 | DAISY(1),
+ [SAI6_RX_BCLK] 21 | DAISY(1),
+ [SAI6_RX_SYNC] 23 | DAISY(1),
+ [SAI6_TX_BCLK] 24 | DAISY(1),
+ [SAY6_TX_SYNC] 25 | DAISY(1),
+ [UART1_RTS_B] 13 | DAISY(1),
+ [UART1_RXD] 14 | DAISY(1),
+ [UART2_RTS_B] 15 | DAISY(1),
+ [UART2_RXD] 16 | DAISY(1),
+ [UART3_RTS_B] 17 | DAISY(1),
+ [UART3_RXD] 18 | DAISY(3),
+ [UART4_RTS_B] 19 | DAISY(1),
+ [UART4_RXD] 20 | DAISY(3),
+};
+
+static ushort padmux[] = {
+ [PAD_GPIO1_IO00*8] GPIO1_IO00, CCM_ENET_PHY_REF_CLK_ROOT, 0, 0, 0, ANAMIX_REF_CLK_32K, CCM_EXT_CLK1, 0,
+ [PAD_GPIO1_IO01*8] GPIO1_IO01, PWM1_OUT, 0, 0, 0, ANAMIX_REF_CLK_25M, CCM_EXT_CLK2, 0,
+ [PAD_GPIO1_IO02*8] GPIO1_IO02, WDOG1_WDOG_B, 0, 0, 0, WDOG1_WDOG_ANY, 0, SJC_DE_B,
+ [PAD_GPIO1_IO03*8] GPIO1_IO03, USDHC1_VSELECT, 0, 0, 0, SDMA1_EXT_EVENT0, 0, 0,
+ [PAD_GPIO1_IO04*8] GPIO1_IO04, USDHC2_VSELECT, 0, 0, 0, SDMA1_EXT_EVENT1, 0, 0,
+ [PAD_GPIO1_IO05*8] GPIO1_IO05, M4_NMI, 0, 0, 0, CCM_PMIC_READY|DAISY(0), 0, 0,
+ [PAD_GPIO1_IO06*8] GPIO1_IO06, ENET1_MDC, 0, 0, 0, USDHC1_CD_B, CCM_EXT_CLK3, 0,
+ [PAD_GPIO1_IO07*8] GPIO1_IO07, ENET1_MDIO|DAISY(0), 0, 0, 0, USDHC1_WP, CCM_EXT_CLK4, 0,
+ [PAD_GPIO1_IO08*8] GPIO1_IO08, ENET1_1588_EVENT0_IN, 0, 0, 0, USDHC2_RESET_B, 0, 0,
+ [PAD_GPIO1_IO09*8] GPIO1_IO09, ENET1_1588_EVENT0_OUT, 0, 0, 0, SDMA2_EXT_EVENT0, 0, 0,
+ [PAD_GPIO1_IO10*8] GPIO1_IO10, USB1_OTG_ID, 0, 0, 0, 0, 0, 0,
+ [PAD_GPIO1_IO11*8] GPIO1_IO11, USB2_OTG_ID, 0, 0, 0, CCM_PMIC_READY|DAISY(1), 0, 0,
+ [PAD_GPIO1_IO12*8] GPIO1_IO12, USB1_OTG_PWR, 0, 0, 0, SDMA2_EXT_EVENT1, 0, 0,
+ [PAD_GPIO1_IO13*8] GPIO1_IO13, USB1_OTG_OC, 0, 0, 0, PWM2_OUT, 0, 0,
+ [PAD_GPIO1_IO14*8] GPIO1_IO14, USB2_OTG_PWR, 0, 0, 0, PWM3_OUT, CCM_CLKO1, 0,
+ [PAD_GPIO1_IO15*8] GPIO1_IO15, USB2_OTG_OC, 0, 0, 0, PWM4_OUT, CCM_CLKO2, 0,
+ [PAD_ENET_MDC*8] ENET1_MDC, 0, 0, 0, 0, GPIO1_IO16, 0, 0,
+ [PAD_ENET_MDIO*8] ENET1_MDIO|DAISY(1), 0, 0, 0, 0, GPIO1_IO17, 0, 0,
+ [PAD_ENET_TD3*8] ENET1_RGMII_TD3, 0, 0, 0, 0, GPIO1_IO18, 0, 0,
+ [PAD_ENET_TD2*8] ENET1_RGMII_TD2, ENET1_TX_CLK, 0, 0, 0, GPIO1_IO19, 0, 0,
+ [PAD_ENET_TD1*8] ENET1_RGMII_TD1, 0, 0, 0, 0, GPIO1_IO20, 0, 0,
+ [PAD_ENET_TD0*8] ENET1_RGMII_TD0, 0, 0, 0, 0, GPIO1_IO21, 0, 0,
+ [PAD_ENET_TX_CTL*8] ENET1_RGMII_TX_CTL, 0, 0, 0, 0, GPIO1_IO22, 0, 0,
+ [PAD_ENET_TXC*8] ENET1_RGMII_TXC, ENET1_TX_ER, 0, 0, 0, GPIO1_IO23, 0, 0,
+ [PAD_ENET_RX_CTL*8] ENET1_RGMII_RX_CTL, 0, 0, 0, 0, GPIO1_IO24, 0, 0,
+ [PAD_ENET_RXC*8] ENET1_RGMII_RXC, ENET1_RX_ER, 0, 0, 0, GPIO1_IO25, 0, 0,
+ [PAD_ENET_RD0*8] ENET1_RGMII_RD0, 0, 0, 0, 0, GPIO1_IO26, 0, 0,
+ [PAD_ENET_RD1*8] ENET1_RGMII_RD1, 0, 0, 0, 0, GPIO1_IO27, 0, 0,
+ [PAD_ENET_RD2*8] ENET1_RGMII_RD2, 0, 0, 0, 0, GPIO1_IO28, 0, 0,
+ [PAD_ENET_RD3*8] ENET1_RGMII_RD3, 0, 0, 0, 0, GPIO1_IO29, 0, 0,
+ [PAD_SD1_CLK*8] USDHC1_CLK, 0, 0, 0, 0, GPIO2_IO00, 0, 0,
+ [PAD_SD1_CMD*8] USDHC1_CMD, 0, 0, 0, 0, GPIO2_IO01, 0, 0,
+ [PAD_SD1_DATA0*8] USDHC1_DATA0, 0, 0, 0, 0, GPIO2_IO02, 0, 0,
+ [PAD_SD1_DATA1*8] USDHC1_DATA1, 0, 0, 0, 0, GPIO2_IO03, 0, 0,
+ [PAD_SD1_DATA2*8] USDHC1_DATA2, 0, 0, 0, 0, GPIO2_IO04, 0, 0,
+ [PAD_SD1_DATA3*8] USDHC1_DATA3, 0, 0, 0, 0, GPIO2_IO05, 0, 0,
+ [PAD_SD1_DATA4*8] USDHC1_DATA4, 0, 0, 0, 0, GPIO2_IO06, 0, 0,
+ [PAD_SD1_DATA5*8] USDHC1_DATA5, 0, 0, 0, 0, GPIO2_IO07, 0, 0,
+ [PAD_SD1_DATA6*8] USDHC1_DATA6, 0, 0, 0, 0, GPIO2_IO08, 0, 0,
+ [PAD_SD1_DATA7*8] USDHC1_DATA7, 0, 0, 0, 0, GPIO2_IO09, 0, 0,
+ [PAD_SD1_RESET_B*8] USDHC1_RESET_B, 0, 0, 0, 0, GPIO2_IO10, 0, 0,
+ [PAD_SD1_STROBE*8] USDHC1_STROBE, 0, 0, 0, 0, GPIO2_IO11, 0, 0,
+ [PAD_SD2_CD_B*8] USDHC2_CD_B, 0, 0, 0, 0, GPIO2_IO12, 0, 0,
+ [PAD_SD2_CLK*8] USDHC2_CLK, 0, 0, 0, 0, GPIO2_IO13, 0, 0,
+ [PAD_SD2_CMD*8] USDHC2_CMD, 0, 0, 0, 0, GPIO2_IO14, 0, 0,
+ [PAD_SD2_DATA0*8] USDHC2_DATA0, 0, 0, 0, 0, GPIO2_IO15, 0, 0,
+ [PAD_SD2_DATA1*8] USDHC2_DATA1, 0, 0, 0, 0, GPIO2_IO16, 0, 0,
+ [PAD_SD2_DATA2*8] USDHC2_DATA2, 0, 0, 0, 0, GPIO2_IO17, 0, 0,
+ [PAD_SD2_DATA3*8] USDHC2_DATA3, 0, 0, 0, 0, GPIO2_IO18, 0, 0,
+ [PAD_SD2_RESET_B*8] USDHC2_RESET_B, 0, 0, 0, 0, GPIO2_IO19, 0, 0,
+ [PAD_SD2_WP*8] USDHC2_WP, 0, 0, 0, 0, GPIO2_IO20, 0, 0,
+ [PAD_NAND_ALE*8] RAWNAND_ALE, QSPI_A_SCLK, 0, 0, 0, GPIO3_IO00, 0, 0,
+ [PAD_NAND_CE0_B*8] RAWNAND_CE0_B, QSPI_A_SS0_B, 0, 0, 0, GPIO3_IO01, 0, 0,
+ [PAD_NAND_CE1_B*8] RAWNAND_CE1_B, QSPI_A_SS1_B, 0, 0, 0, GPIO3_IO02, 0, 0,
+ [PAD_NAND_CE2_B*8] RAWNAND_CE2_B, QSPI_B_SS0_B, 0, 0, 0, GPIO3_IO03, 0, 0,
+ [PAD_NAND_CE3_B*8] RAWNAND_CE3_B, QSPI_B_SS1_B, 0, 0, 0, GPIO3_IO04, 0, 0,
+ [PAD_NAND_CLE*8] RAWNAND_CLE, QSPI_B_SCLK, 0, 0, 0, GPIO3_IO05, 0, 0,
+ [PAD_NAND_DATA0*8] RAWNAND_DATA00, QSPI_A_DATA0, 0, 0, 0, GPIO3_IO06, 0, 0,
+ [PAD_NAND_DATA1*8] RAWNAND_DATA01, QSPI_A_DATA1, 0, 0, 0, GPIO3_IO07, 0, 0,
+ [PAD_NAND_DATA2*8] RAWNAND_DATA02, QSPI_A_DATA2, 0, 0, 0, GPIO3_IO08, 0, 0,
+ [PAD_NAND_DATA3*8] RAWNAND_DATA03, QSPI_A_DATA3, 0, 0, 0, GPIO3_IO09, 0, 0,
+ [PAD_NAND_DATA4*8] RANWNAD_DATA04, QSPI_B_DATA0, 0, 0, 0, GPIO3_IO10, 0, 0,
+ [PAD_NAND_DATA5*8] RAWNAND_DATA05, QSPI_B_DATA1, 0, 0, 0, GPIO3_IO11, 0, 0,
+ [PAD_NAND_DATA6*8] RAWNAND_DATA06, QSPI_B_DATA2, 0, 0, 0, GPIO3_IO12, 0, 0,
+ [PAD_NAND_DATA7*8] RAWNAND_DATA07, QSPI_B_DATA3, 0, 0, 0, GPIO3_IO13, 0, 0,
+ [PAD_NAND_DQS*8] RAWNAND_DQS, QSPI_A_DQS, 0, 0, 0, GPIO3_IO14, 0, 0,
+ [PAD_NAND_RE_B*8] RAWNAND_RE_B, QSPI_B_DQS, 0, 0, 0, GPIO3_IO15, 0, 0,
+ [PAD_NAND_READY_B*8] RAWNAND_READY_B, 0, 0, 0, 0, GPIO3_IO16, 0, 0,
+ [PAD_NAND_WE_B*8] RAWNAND_WE_B, 0, 0, 0, 0, GPIO3_IO17, 0, 0,
+ [PAD_NAND_WP_B*8] RAWNAND_WP_B, 0, 0, 0, 0, GPIO3_IO18, 0, 0,
+ [PAD_SAI5_RXFS*8] SAI5_RX_SYNC|DAISY(0), SAI1_TX_DATA0, 0, 0, 0, GPIO3_IO19, 0, 0,
+ [PAD_SAI5_RXC*8] SAI5_RX_BCLK|DAISY(0), SAI1_TX_DATA1, 0, 0, 0, GPIO3_IO20, 0, 0,
+ [PAD_SAI5_RXD0*8] SAI5_RX_DATA0, SAI1_TX_DATA2, 0, 0, 0, GPIO3_IO21, 0, 0,
+ [PAD_SAI5_RXD1*8] SAI5_RX_DATA1, SAI1_TX_DATA3, SAI1_TX_SYNC|DAISY(0), SAI5_TX_SYNC|DAISY(0), 0, GPIO3_IO22, 0, 0,
+ [PAD_SAI5_RXD2*8] SAI5_RX_DATA2, SAI1_TX_DATA4, SAI1_TX_SYNC|DAISY(1), SAI5_TX_BCLK, 0, GPIO3_IO23, 0, 0,
+ [PAD_SAI5_RXD3*8] SAI5_RX_DATA3, SAI1_TX_DATA5, 0, SAI5_TX_DATA0, 0, GPIO3_IO24, 0, 0,
+ [PAD_SAI5_MCLK*8] SAI5_MCLK|DAISY(0), SAI1_TX_BCLK, SAI4_MCLK, 0, 0, GPIO3_IO25, 0, 0,
+ [PAD_SAI1_RXFS*8] SAI1_RX_SYNC|DAISY(0), SAI5_RX_SYNC|DAISY(1), 0, 0, CORESIGHT_TRACE_CLK, GPIO4_IO00, 0, 0,
+ [PAD_SAI1_RXC*8] SAI1_RX_BCLK, SAI5_RX_BCLK|DAISY(1), 0, 0, CORESIGHT_TRACE_CTL, GPIO4_IO01, 0, 0,
+ [PAD_SAI1_RXD0*8] SAI1_RX_DATA0, SAI5_RX_DATA0, 0, 0, CORESIGHT_TRACE0, GPIO4_IO02, SRC_BOOT_CFG0, 0,
+ [PAD_SAI1_RXD1*8] SAI1_RX_DATA1, SAI5_RX_DATA1, 0, 0, CORESIGHT_TRACE1, GPIO4_IO03, SRC_BOOT_CFG1, 0,
+ [PAD_SAI1_RXD2*8] SAI1_RX_DATA2, SAI5_RX_DATA2, 0, 0, CORESIGHT_TRACE2, GPIO4_IO04, SRC_BOOT_CFG2, 0,
+ [PAD_SAI1_RXD3*8] SAI1_RX_DATA3, SAI5_RX_DATA3, 0, 0, CORESIGHT_TRACE3, GPIO4_IO05, SRC_BOOT_CFG3, 0,
+ [PAD_SAI1_RXD4*8] SAI1_RX_DATA4, SAI6_TX_BCLK|DAISY(0), SAI6_RX_BCLK|DAISY(0), 0, CORESIGHT_TRACE4, GPIO4_IO06, SRC_BOOT_CFG4, 0,
+ [PAD_SAI1_RXD5*8] SAI1_RX_DATA5, SAI6_TX_DATA0, SAI6_RX_DATA0, SAI1_RX_SYNC|DAISY(1), CORESIGHT_TRACE5, GPIO4_IO07, SRC_BOOT_CFG5, 0,
+ [PAD_SAI1_RXD6*8] SAI1_RX_DATA6, SAI6_TX_SYNC, SAI6_RX_SYNC|DAISY(0), 0, CORESIGHT_TRACE6, GPIO4_IO08, SRC_BOOT_CFG6, 0,
+ [PAD_SAI1_RXD7*8] SAI1_RX_DATA7, SAI6_MCLK|DAISY(0), SAI1_TX_SYNC|DAISY(4), SAI1_TX_DATA4, CORESIGHT_TRACE7, GPIO4_IO09, SRC_BOOT_CFG7, 0,
+ [PAD_SAI1_TXFS*8] SAI1_TX_SYNC|DAISY(3), SAI5_TX_SYNC|DAISY(1), 0, 0, CORESIGHT_EVENTO, GPIO4_IO10, 0, 0,
+ [PAD_SAI1_TXC*8] SAI1_TX_BCLK, SAI5_TX_BCLK, 0, 0, CORESIGHT_EVENTI, GPIO4_IO11, 0, 0,
+ [PAD_SAI1_TXD0*8] SAI1_TX_DATA0, SAI5_TX_DATA0, 0, 0, CORESIGHT_TRACE8, GPIO4_IO12, SRC_BOOT_CFG8, 0,
+ [PAD_SAI1_TXD1*8] SAI1_TX_DATA1, SAI5_TX_DATA1, 0, 0, CORESIGHT_TRACE9, GPIO4_IO13, SRC_BOOT_CFG9, 0,
+ [PAD_SAI1_TXD2*8] SAI1_TX_DATA2, SAI5_TX_DATA2, 0, 0, CORESIGHT_TRACE10, GPIO4_IO14, SRC_BOOT_CFG10, 0,
+ [PAD_SAI1_TXD3*8] SAI1_TX_DATA3, SAI5_TX_DATA3, 0, 0, CORESIGHT_TRACE11, GPIO4_IO15, SRC_BOOT_CFG11, 0,
+ [PAD_SAI1_TXD4*8] SAI1_TX_DATA4, SAI6_RC_BCLK, SAI6_TX_BCLK|DAISY(1), 0, CORESIGHT_TRACE12, GPIO4_IO16, SRC_BOOT_CFG12, 0,
+ [PAD_SAI1_TXD5*8] SAI1_TX_DATA5, SAI6_RX_DATA0, SAI6_TX_DATA0, 0, CORESIGHT_TRACE13, GPIO4_IO17, SRC_BOOT_CFG13, 0,
+ [PAD_SAI1_TXD6*8] SAI1_TX_DATA6, SAI6_RX_SYNC|DAISY(1), SAI6_TX_SYNC, 0, CORESIGHT_TRACE14, GPIO4_IO18, SRC_BOOT_CFG14, 0,
+ [PAD_SAI1_TXD7*8] SAI1_TX_DATA7, SAI6_MCLK|DAISY(1), 0, 0, CORESIGHT_TRACE15, GPIO4_IO19, SRC_BOOT_CFG15, 0,
+ [PAD_SAI1_MCLK*8] SAI1_MCLK, SAI5_MCLK|DAISY(1), SAI1_TX_BCLK, 0, 0, GPIO4_IO20, 0, 0,
+ [PAD_SAI2_RXFS*8] SAI2_RX_SYNC, SAI5_TX_SYNC|DAISY(2), 0, 0, 0, GPIO4_IO21, 0, 0,
+ [PAD_SAI2_RXC*8] SAI2_RX_BCLK, SAI5_TX_BCLK, 0, 0, 0, GPIO4_IO22, 0, 0,
+ [PAD_SAI2_RXD0*8] SAI2_RX_DATA0, SAI5_TX_DATA0, 0, 0, 0, GPIO4_IO23, 0, 0,
+ [PAD_SAI2_TXFS*8] SAI2_TX_SYNC, SAI5_TX_DATA1, 0, 0, 0, GPIO4_IO24, 0, 0,
+ [PAD_SAI2_TXC*8] SAI2_TX_BCLK, SAI5_TX_DATA2, 0, 0, 0, GPIO4_IO25, 0, 0,
+ [PAD_SAI2_TXD0*8] SAI2_TX_DATA0, SAI5_TX_DATA3, 0, 0, 0, GPIO4_IO26, 0, 0,
+ [PAD_SAI2_MCLK*8] SAI2_MCLK, SAI5_MCLK|DAISY(2), 0, 0, 0, GPIO4_IO27, 0, 0,
+ [PAD_SAI3_RXFS*8] SAI3_RX_SYNC, GPT1_CAPTURE1, SAI5_RX_SYNC|DAISY(2), 0, 0, GPIO4_IO28, 0, 0,
+ [PAD_SAI3_RXC*8] SAI3_RX_BCLK, GPT1_CAPTURE2, SAI5_RX_BCLK|DAISY(2), 0, 0, GPIO4_IO29, 0, 0,
+ [PAD_SAI3_RXD*8] SAI3_RX_DATA0, GPT1_COMPARE1, 0, 0, 0, 0, 0, 0,
+ [PAD_SAI3_TXFS*8] SAI3_TX_SYNC, GPT1_CLK, SAI5_RX_DATA1, 0, 0, GPIO4_IO31, 0, 0,
+ [PAD_SAI3_TXC*8] SAI3_TX_BCLK, GPT1_COMPARE2, SAI5_RX_DATA2, 0, 0, GPIO5_IO00, 0, 0,
+ [PAD_SAI3_TXD*8] SAI3_TX_DATA0, GPT1_COMPARE3, SAI5_RX_DATA3, 0, 0, GPIO5_IO01, 0, 0,
+ [PAD_SAI3_MCLK*8] SAI3_MCLK, PWM4_OUT, SAI5_MCLK|DAISY(3), 0, 0, GPIO5_IO02, 0, 0,
+ [PAD_SPDIF_TX*8] SPDIF1_OUT, PWM3_OUT, 0, 0, 0, GPIO5_IO03, 0, 0,
+ [PAD_SPDIF_RX*8] SPDIF1_IN, PWM2_OUT, 0, 0, 0, GPIO5_IO04, 0, 0,
+ [PAD_SPDIF_EXT_CLK*8] SPDIF1_EXT_CLK, PWM1_OUT, 0, 0, 0, GPIO5_IO05, 0, 0,
+ [PAD_ECSPI1_SCLK*8] ECSPI1_SCLK, UART3_RX, 0, 0, 0, GPIO5_IO06, 0, 0,
+ [PAD_ECSPI1_MOSI*8] ECSPI1_MOSI, UART3_TX, 0, 0, 0, GPIO5_IO07, 0, 0,
+ [PAD_ECSPI1_MISO*8] ECSPI1_MISO, UART3_CTS_B, 0, 0, 0, GPIO5_IO08, 0, 0,
+ [PAD_ECSPI1_SS0*8] ECSPI1_SS0, UART3_RTS_B|DAISY(1), 0, 0, 0, GPIO5_IO09, 0, 0,
+ [PAD_ECSPI2_SCLK*8] ECSPI2_SCLK, UART4_RX, 0, 0, 0, GPIO5_IO10, 0, 0,
+ [PAD_ECSPI2_MOSI*8] ECSPI2_MOSI, UART4_TX, 0, 0, 0, GPIO5_IO11, 0, 0,
+ [PAD_ECSPI2_MISO*8] ECSPI2_MISO, UART4_CTS_B, 0, 0, 0, GPIO5_IO12, 0, 0,
+ [PAD_ECSPI2_SS0*8] ECSPI2_SS0, UART4_RTS_B|DAISY(1), 0, 0, 0, GPIO5_IO13, 0, 0,
+ [PAD_I2C1_SCL*8] I2C1_SCL, ENET1_MDC, 0, 0, 0, GPIO5_IO14, 0, 0,
+ [PAD_I2C1_SDA*8] I2C1_SDA, ENET1_MDIO|DAISY(2), 0, 0, 0, GPIO5_IO15, 0, 0,
+ [PAD_I2C2_SCL*8] I2C2_SCL, ENET1_1588_EVENT1_IN, 0, 0, 0, GPIO5_IO16, 0, 0,
+ [PAD_I2C2_SDA*8] I2C2_SDA, ENET1_1588_EVENT1_OUT, 0, 0, 0, GPIO5_IO17, 0, 0,
+ [PAD_I2C3_SCL*8] I2C3_SCL, PWM4_OUT, GPT2_CLK, 0, 0, GPIO5_IO18, 0, 0,
+ [PAD_I2C3_SDA*8] I2C3_SDA, PWM3_OUT, GPT3_CLK, 0, 0, GPIO5_IO19, 0, 0,
+ [PAD_I2C4_SCL*8] I2C4_SCL, PWM2_OUT, PCIE_CLKREQ_B, 0, 0, GPIO5_IO20, 0, 0,
+ [PAD_I2C4_SDA*8] I2C4_SDA, PWM1_OUT, PCIE2_CLKREQ_B|DAISY(0), 0, 0, GPIO5_IO21, 0, 0,
+ [PAD_UART1_RXD*8] UART1_RX, ECSPI3_SCLK, 0, 0, 0, GPIO5_IO22, 0, 0,
+ [PAD_UART1_TXD*8] UART1_TX, ECSPI3_MOSI, 0, 0, 0, GPIO5_IO23, 0, 0,
+ [PAD_UART2_RXD*8] UART2_RX, ECSPI3_MISO, 0, 0, 0, GPIO5_IO24, 0, 0,
+ [PAD_UART2_TXD*8] UART2_TX, ECSPI3_SS0, 0, 0, 0, GPIO5_IO25, 0, 0,
+ [PAD_UART3_RXD*8] UART3_RX, UART1_CTS_B, 0, 0, 0, GPIO5_IO26, 0, 0,
+ [PAD_UART3_TXD*8] UART3_TX, UART1_RTS_B|DAISY(1), 0, 0, 0, GPIO5_IO27, 0, 0,
+ [PAD_UART4_RXD*8] UART4_RX, UART2_CTS_B, PCIE1_CLKREQ_B|DAISY(1), 0, 0, GPIO5_IO28, 0, 0,
+ [PAD_UART4_TXD*8] UART4_TX, UART2_RTS_B|DAISY(1), PCIE2_CLKREQ_B|DAISY(1), 0, 0, GPIO5_IO29, 0, 0,
+};
+
+static char *padname[] = {
+ [PAD_TEST_MODE] "pad_test_mode",
+ [PAD_BOOT_MODE0] "pad_boot_mode0",
+ [PAD_BOOT_MODE1] "pad_boot_mode1",
+ [PAD_JTAG_MOD] "pad_jtag_mod",
+ [PAD_JTAG_TRST_B] "pad_jtag_trst_b",
+ [PAD_JTAG_TDI] "pad_jtag_tdi",
+ [PAD_JTAG_TMS] "pad_jtag_tms",
+ [PAD_JTAG_TCK] "pad_jtag_tck",
+ [PAD_JTAG_TDO] "pad_jtag_tdo",
+ [PAD_RTC] "pad_rtc",
+ [PAD_PMIC_STBY_REQ] "pad_pmic_stby_req",
+ [PAD_PMIC_ON_REQ] "pad_pmic_on_req",
+ [PAD_ONOFF] "pad_onoff",
+ [PAD_POR_B] "pad_por_b",
+ [PAD_RTC_RESET_B] "pad_rtc_reset_b",
+ [PAD_GPIO1_IO00] "pad_gpio1_io00",
+ [PAD_GPIO1_IO01] "pad_gpio1_io01",
+ [PAD_GPIO1_IO02] "pad_gpio1_io02",
+ [PAD_GPIO1_IO03] "pad_gpio1_io03",
+ [PAD_GPIO1_IO04] "pad_gpio1_io04",
+ [PAD_GPIO1_IO05] "pad_gpio1_io05",
+ [PAD_GPIO1_IO06] "pad_gpio1_io06",
+ [PAD_GPIO1_IO07] "pad_gpio1_io07",
+ [PAD_GPIO1_IO08] "pad_gpio1_io08",
+ [PAD_GPIO1_IO09] "pad_gpio1_io09",
+ [PAD_GPIO1_IO10] "pad_gpio1_io10",
+ [PAD_GPIO1_IO11] "pad_gpio1_io11",
+ [PAD_GPIO1_IO12] "pad_gpio1_io12",
+ [PAD_GPIO1_IO13] "pad_gpio1_io13",
+ [PAD_GPIO1_IO14] "pad_gpio1_io14",
+ [PAD_GPIO1_IO15] "pad_gpio1_io15",
+ [PAD_ENET_MDC] "pad_enet_mdc",
+ [PAD_ENET_MDIO] "pad_enet_mdio",
+ [PAD_ENET_TD3] "pad_enet_td3",
+ [PAD_ENET_TD2] "pad_enet_td2",
+ [PAD_ENET_TD1] "pad_enet_td1",
+ [PAD_ENET_TD0] "pad_enet_td0",
+ [PAD_ENET_TX_CTL] "pad_enet_tx_ctl",
+ [PAD_ENET_TXC] "pad_enet_txc",
+ [PAD_ENET_RX_CTL] "pad_enet_rx_ctl",
+ [PAD_ENET_RXC] "pad_enet_rxc",
+ [PAD_ENET_RD0] "pad_enet_rd0",
+ [PAD_ENET_RD1] "pad_enet_rd1",
+ [PAD_ENET_RD2] "pad_enet_rd2",
+ [PAD_ENET_RD3] "pad_enet_rd3",
+ [PAD_SD1_CLK] "pad_sd1_clk",
+ [PAD_SD1_CMD] "pad_sd1_cmd",
+ [PAD_SD1_DATA0] "pad_sd1_data0",
+ [PAD_SD1_DATA1] "pad_sd1_data1",
+ [PAD_SD1_DATA2] "pad_sd1_data2",
+ [PAD_SD1_DATA3] "pad_sd1_data3",
+ [PAD_SD1_DATA4] "pad_sd1_data4",
+ [PAD_SD1_DATA5] "pad_sd1_data5",
+ [PAD_SD1_DATA6] "pad_sd1_data6",
+ [PAD_SD1_DATA7] "pad_sd1_data7",
+ [PAD_SD1_RESET_B] "pad_sd1_reset_b",
+ [PAD_SD1_STROBE] "pad_sd1_strobe",
+ [PAD_SD2_CD_B] "pad_sd2_cd_b",
+ [PAD_SD2_CLK] "pad_sd2_clk",
+ [PAD_SD2_CMD] "pad_sd2_cmd",
+ [PAD_SD2_DATA0] "pad_sd2_data0",
+ [PAD_SD2_DATA1] "pad_sd2_data1",
+ [PAD_SD2_DATA2] "pad_sd2_data2",
+ [PAD_SD2_DATA3] "pad_sd2_data3",
+ [PAD_SD2_RESET_B] "pad_sd2_reset_b",
+ [PAD_SD2_WP] "pad_sd2_wp",
+ [PAD_NAND_ALE] "pad_nand_ale",
+ [PAD_NAND_CE0_B] "pad_nand_ce0_b",
+ [PAD_NAND_CE1_B] "pad_nand_ce1_b",
+ [PAD_NAND_CE2_B] "pad_nand_ce2_b",
+ [PAD_NAND_CE3_B] "pad_nand_ce3_b",
+ [PAD_NAND_CLE] "pad_nand_cle",
+ [PAD_NAND_DATA0] "pad_nand_data0",
+ [PAD_NAND_DATA1] "pad_nand_data1",
+ [PAD_NAND_DATA2] "pad_nand_data2",
+ [PAD_NAND_DATA3] "pad_nand_data3",
+ [PAD_NAND_DATA4] "pad_nand_data4",
+ [PAD_NAND_DATA5] "pad_nand_data5",
+ [PAD_NAND_DATA6] "pad_nand_data6",
+ [PAD_NAND_DATA7] "pad_nand_data7",
+ [PAD_NAND_DQS] "pad_nand_dqs",
+ [PAD_NAND_RE_B] "pad_nand_re_b",
+ [PAD_NAND_READY_B] "pad_nand_ready_b",
+ [PAD_NAND_WE_B] "pad_nand_we_b",
+ [PAD_NAND_WP_B] "pad_nand_wp_b",
+ [PAD_SAI5_RXFS] "pad_sai5_rxfs",
+ [PAD_SAI5_RXC] "pad_sai5_rxc",
+ [PAD_SAI5_RXD0] "pad_sai5_rxd0",
+ [PAD_SAI5_RXD1] "pad_sai5_rxd1",
+ [PAD_SAI5_RXD2] "pad_sai5_rxd2",
+ [PAD_SAI5_RXD3] "pad_sai5_rxd3",
+ [PAD_SAI5_MCLK] "pad_sai5_mclk",
+ [PAD_SAI1_RXFS] "pad_sai1_rxfs",
+ [PAD_SAI1_RXC] "pad_sai1_rxc",
+ [PAD_SAI1_RXD0] "pad_sai1_rxd0",
+ [PAD_SAI1_RXD1] "pad_sai1_rxd1",
+ [PAD_SAI1_RXD2] "pad_sai1_rxd2",
+ [PAD_SAI1_RXD3] "pad_sai1_rxd3",
+ [PAD_SAI1_RXD4] "pad_sai1_rxd4",
+ [PAD_SAI1_RXD5] "pad_sai1_rxd5",
+ [PAD_SAI1_RXD6] "pad_sai1_rxd6",
+ [PAD_SAI1_RXD7] "pad_sai1_rxd7",
+ [PAD_SAI1_TXFS] "pad_sai1_txfs",
+ [PAD_SAI1_TXC] "pad_sai1_txc",
+ [PAD_SAI1_TXD0] "pad_sai1_txd0",
+ [PAD_SAI1_TXD1] "pad_sai1_txd1",
+ [PAD_SAI1_TXD2] "pad_sai1_txd2",
+ [PAD_SAI1_TXD3] "pad_sai1_txd3",
+ [PAD_SAI1_TXD4] "pad_sai1_txd4",
+ [PAD_SAI1_TXD5] "pad_sai1_txd5",
+ [PAD_SAI1_TXD6] "pad_sai1_txd6",
+ [PAD_SAI1_TXD7] "pad_sai1_txd7",
+ [PAD_SAI1_MCLK] "pad_sai1_mclk",
+ [PAD_SAI2_RXFS] "pad_sai2_rxfs",
+ [PAD_SAI2_RXC] "pad_sai2_rxc",
+ [PAD_SAI2_RXD0] "pad_sai2_rxd0",
+ [PAD_SAI2_TXFS] "pad_sai2_txfs",
+ [PAD_SAI2_TXC] "pad_sai2_txc",
+ [PAD_SAI2_TXD0] "pad_sai2_txd0",
+ [PAD_SAI2_MCLK] "pad_sai2_mclk",
+ [PAD_SAI3_RXFS] "pad_sai3_rxfs",
+ [PAD_SAI3_RXC] "pad_sai3_rxc",
+ [PAD_SAI3_RXD] "pad_sai3_rxd",
+ [PAD_SAI3_TXFS] "pad_sai3_txfs",
+ [PAD_SAI3_TXC] "pad_sai3_txc",
+ [PAD_SAI3_TXD] "pad_sai3_txd",
+ [PAD_SAI3_MCLK] "pad_sai3_mclk",
+ [PAD_SPDIF_TX] "pad_spdif_tx",
+ [PAD_SPDIF_RX] "pad_spdif_rx",
+ [PAD_SPDIF_EXT_CLK] "pad_spdif_ext_clk",
+ [PAD_ECSPI1_SCLK] "pad_ecspi1_sclk",
+ [PAD_ECSPI1_MOSI] "pad_ecspi1_mosi",
+ [PAD_ECSPI1_MISO] "pad_ecspi1_miso",
+ [PAD_ECSPI1_SS0] "pad_ecspi1_ss0",
+ [PAD_ECSPI2_SCLK] "pad_ecspi2_sclk",
+ [PAD_ECSPI2_MOSI] "pad_ecspi2_mosi",
+ [PAD_ECSPI2_MISO] "pad_ecspi2_miso",
+ [PAD_ECSPI2_SS0] "pad_ecspi2_ss0",
+ [PAD_I2C1_SCL] "pad_i2c1_scl",
+ [PAD_I2C1_SDA] "pad_i2c1_sda",
+ [PAD_I2C2_SCL] "pad_i2c2_scl",
+ [PAD_I2C2_SDA] "pad_i2c2_sda",
+ [PAD_I2C3_SCL] "pad_i2c3_scl",
+ [PAD_I2C3_SDA] "pad_i2c3_sda",
+ [PAD_I2C4_SCL] "pad_i2c4_scl",
+ [PAD_I2C4_SDA] "pad_i2c4_sda",
+ [PAD_UART1_RXD] "pad_uart1_rxd",
+ [PAD_UART1_TXD] "pad_uart1_txd",
+ [PAD_UART2_RXD] "pad_uart2_rxd",
+ [PAD_UART2_TXD] "pad_uart2_txd",
+ [PAD_UART3_RXD] "pad_uart3_rxd",
+ [PAD_UART3_TXD] "pad_uart3_txd",
+ [PAD_UART4_RXD] "pad_uart4_rxd",
+ [PAD_UART4_TXD] "pad_uart4_txd",
+};
+
+static char *signame[] = {
+ [CCM_PMIC_READY] "ccm_pmic_ready",
+ [ENET1_MDIO] "enet1_mdio",
+ [PCIE1_CLKREQ_B] "pcie1_clkreq_b",
+ [PCIE2_CLKREQ_B] "pcie2_clkreq_b",
+ [SAI1_RX_BCLK] "sai1_rx_bclk",
+ [SAI1_RX_SYNC] "sai1_rx_sync",
+ [SAI1_TX_SYNC] "sai1_tx_sync",
+ [SAI5_MCLK] "sai5_mclk",
+ [SAI5_RXD0] "sai5_rxd0",
+ [SAI5_RXD1] "sai5_rxd1",
+ [SAI5_RXD2] "sai5_rxd2",
+ [SAI5_RXD3] "sai5_rxd3",
+ [SAI5_RX_BCLK] "sai5_rx_bclk",
+ [SAI5_RX_SYNC] "sai5_rx_sync",
+ [SAI5_TX_BLCK] "sai5_tx_blck",
+ [SAI5_TX_SYNC] "sai5_tx_sync",
+ [SAI6_MCLK] "sai6_mclk",
+ [SAI6_RXD0] "sai6_rxd0",
+ [SAI6_RX_BCLK] "sai6_rx_bclk",
+ [SAI6_RX_SYNC] "sai6_rx_sync",
+ [SAI6_TX_BCLK] "sai6_tx_bclk",
+ [SAY6_TX_SYNC] "say6_tx_sync",
+ [UART1_RTS_B] "uart1_rts_b",
+ [UART1_RXD] "uart1_rxd",
+ [UART2_RTS_B] "uart2_rts_b",
+ [UART2_RXD] "uart2_rxd",
+ [UART3_RTS_B] "uart3_rts_b",
+ [UART3_RXD] "uart3_rxd",
+ [UART4_RTS_B] "uart4_rts_b",
+ [UART4_RXD] "uart4_rxd",
+ [ANAMIX_REF_CLK_25M] "anamix_ref_clk_25m",
+ [ANAMIX_REF_CLK_32K] "anamix_ref_clk_32k",
+ [CCM_CLKO1] "ccm_clko1",
+ [CCM_CLKO2] "ccm_clko2",
+ [CCM_ENET_PHY_REF_CLK_ROOT] "ccm_enet_phy_ref_clk_root",
+ [CCM_EXT_CLK1] "ccm_ext_clk1",
+ [CCM_EXT_CLK2] "ccm_ext_clk2",
+ [CCM_EXT_CLK3] "ccm_ext_clk3",
+ [CCM_EXT_CLK4] "ccm_ext_clk4",
+ [CORESIGHT_EVENTI] "coresight_eventi",
+ [CORESIGHT_EVENTO] "coresight_evento",
+ [CORESIGHT_TRACE0] "coresight_trace0",
+ [CORESIGHT_TRACE1] "coresight_trace1",
+ [CORESIGHT_TRACE10] "coresight_trace10",
+ [CORESIGHT_TRACE11] "coresight_trace11",
+ [CORESIGHT_TRACE12] "coresight_trace12",
+ [CORESIGHT_TRACE13] "coresight_trace13",
+ [CORESIGHT_TRACE14] "coresight_trace14",
+ [CORESIGHT_TRACE15] "coresight_trace15",
+ [CORESIGHT_TRACE2] "coresight_trace2",
+ [CORESIGHT_TRACE3] "coresight_trace3",
+ [CORESIGHT_TRACE4] "coresight_trace4",
+ [CORESIGHT_TRACE5] "coresight_trace5",
+ [CORESIGHT_TRACE6] "coresight_trace6",
+ [CORESIGHT_TRACE7] "coresight_trace7",
+ [CORESIGHT_TRACE8] "coresight_trace8",
+ [CORESIGHT_TRACE9] "coresight_trace9",
+ [CORESIGHT_TRACE_CLK] "coresight_trace_clk",
+ [CORESIGHT_TRACE_CTL] "coresight_trace_ctl",
+ [ECSPI1_MISO] "ecspi1_miso",
+ [ECSPI1_MOSI] "ecspi1_mosi",
+ [ECSPI1_SCLK] "ecspi1_sclk",
+ [ECSPI1_SS0] "ecspi1_ss0",
+ [ECSPI2_MISO] "ecspi2_miso",
+ [ECSPI2_MOSI] "ecspi2_mosi",
+ [ECSPI2_SCLK] "ecspi2_sclk",
+ [ECSPI2_SS0] "ecspi2_ss0",
+ [ECSPI3_MISO] "ecspi3_miso",
+ [ECSPI3_MOSI] "ecspi3_mosi",
+ [ECSPI3_SCLK] "ecspi3_sclk",
+ [ECSPI3_SS0] "ecspi3_ss0",
+ [ENET1_1588_EVENT0_IN] "enet1_1588_event0_in",
+ [ENET1_1588_EVENT0_OUT] "enet1_1588_event0_out",
+ [ENET1_1588_EVENT1_IN] "enet1_1588_event1_in",
+ [ENET1_1588_EVENT1_OUT] "enet1_1588_event1_out",
+ [ENET1_MDC] "enet1_mdc",
+ [ENET1_RGMII_RD0] "enet1_rgmii_rd0",
+ [ENET1_RGMII_RD1] "enet1_rgmii_rd1",
+ [ENET1_RGMII_RD2] "enet1_rgmii_rd2",
+ [ENET1_RGMII_RD3] "enet1_rgmii_rd3",
+ [ENET1_RGMII_RXC] "enet1_rgmii_rxc",
+ [ENET1_RGMII_RX_CTL] "enet1_rgmii_rx_ctl",
+ [ENET1_RGMII_TD0] "enet1_rgmii_td0",
+ [ENET1_RGMII_TD1] "enet1_rgmii_td1",
+ [ENET1_RGMII_TD2] "enet1_rgmii_td2",
+ [ENET1_RGMII_TD3] "enet1_rgmii_td3",
+ [ENET1_RGMII_TXC] "enet1_rgmii_txc",
+ [ENET1_RGMII_TX_CTL] "enet1_rgmii_tx_ctl",
+ [ENET1_RX_ER] "enet1_rx_er",
+ [ENET1_TX_CLK] "enet1_tx_clk",
+ [ENET1_TX_ER] "enet1_tx_er",
+ [GPIO1_IO00] "gpio1_io00",
+ [GPIO1_IO01] "gpio1_io01",
+ [GPIO1_IO02] "gpio1_io02",
+ [GPIO1_IO03] "gpio1_io03",
+ [GPIO1_IO04] "gpio1_io04",
+ [GPIO1_IO05] "gpio1_io05",
+ [GPIO1_IO06] "gpio1_io06",
+ [GPIO1_IO07] "gpio1_io07",
+ [GPIO1_IO08] "gpio1_io08",
+ [GPIO1_IO09] "gpio1_io09",
+ [GPIO1_IO10] "gpio1_io10",
+ [GPIO1_IO11] "gpio1_io11",
+ [GPIO1_IO12] "gpio1_io12",
+ [GPIO1_IO13] "gpio1_io13",
+ [GPIO1_IO14] "gpio1_io14",
+ [GPIO1_IO15] "gpio1_io15",
+ [GPIO1_IO16] "gpio1_io16",
+ [GPIO1_IO17] "gpio1_io17",
+ [GPIO1_IO18] "gpio1_io18",
+ [GPIO1_IO19] "gpio1_io19",
+ [GPIO1_IO20] "gpio1_io20",
+ [GPIO1_IO21] "gpio1_io21",
+ [GPIO1_IO22] "gpio1_io22",
+ [GPIO1_IO23] "gpio1_io23",
+ [GPIO1_IO24] "gpio1_io24",
+ [GPIO1_IO25] "gpio1_io25",
+ [GPIO1_IO26] "gpio1_io26",
+ [GPIO1_IO27] "gpio1_io27",
+ [GPIO1_IO28] "gpio1_io28",
+ [GPIO1_IO29] "gpio1_io29",
+ [GPIO2_IO00] "gpio2_io00",
+ [GPIO2_IO01] "gpio2_io01",
+ [GPIO2_IO02] "gpio2_io02",
+ [GPIO2_IO03] "gpio2_io03",
+ [GPIO2_IO04] "gpio2_io04",
+ [GPIO2_IO05] "gpio2_io05",
+ [GPIO2_IO06] "gpio2_io06",
+ [GPIO2_IO07] "gpio2_io07",
+ [GPIO2_IO08] "gpio2_io08",
+ [GPIO2_IO09] "gpio2_io09",
+ [GPIO2_IO10] "gpio2_io10",
+ [GPIO2_IO11] "gpio2_io11",
+ [GPIO2_IO12] "gpio2_io12",
+ [GPIO2_IO13] "gpio2_io13",
+ [GPIO2_IO14] "gpio2_io14",
+ [GPIO2_IO15] "gpio2_io15",
+ [GPIO2_IO16] "gpio2_io16",
+ [GPIO2_IO17] "gpio2_io17",
+ [GPIO2_IO18] "gpio2_io18",
+ [GPIO2_IO19] "gpio2_io19",
+ [GPIO2_IO20] "gpio2_io20",
+ [GPIO3_IO00] "gpio3_io00",
+ [GPIO3_IO01] "gpio3_io01",
+ [GPIO3_IO02] "gpio3_io02",
+ [GPIO3_IO03] "gpio3_io03",
+ [GPIO3_IO04] "gpio3_io04",
+ [GPIO3_IO05] "gpio3_io05",
+ [GPIO3_IO06] "gpio3_io06",
+ [GPIO3_IO07] "gpio3_io07",
+ [GPIO3_IO08] "gpio3_io08",
+ [GPIO3_IO09] "gpio3_io09",
+ [GPIO3_IO10] "gpio3_io10",
+ [GPIO3_IO11] "gpio3_io11",
+ [GPIO3_IO12] "gpio3_io12",
+ [GPIO3_IO13] "gpio3_io13",
+ [GPIO3_IO14] "gpio3_io14",
+ [GPIO3_IO15] "gpio3_io15",
+ [GPIO3_IO16] "gpio3_io16",
+ [GPIO3_IO17] "gpio3_io17",
+ [GPIO3_IO18] "gpio3_io18",
+ [GPIO3_IO19] "gpio3_io19",
+ [GPIO3_IO20] "gpio3_io20",
+ [GPIO3_IO21] "gpio3_io21",
+ [GPIO3_IO22] "gpio3_io22",
+ [GPIO3_IO23] "gpio3_io23",
+ [GPIO3_IO24] "gpio3_io24",
+ [GPIO3_IO25] "gpio3_io25",
+ [GPIO4_IO00] "gpio4_io00",
+ [GPIO4_IO01] "gpio4_io01",
+ [GPIO4_IO02] "gpio4_io02",
+ [GPIO4_IO03] "gpio4_io03",
+ [GPIO4_IO04] "gpio4_io04",
+ [GPIO4_IO05] "gpio4_io05",
+ [GPIO4_IO06] "gpio4_io06",
+ [GPIO4_IO07] "gpio4_io07",
+ [GPIO4_IO08] "gpio4_io08",
+ [GPIO4_IO09] "gpio4_io09",
+ [GPIO4_IO10] "gpio4_io10",
+ [GPIO4_IO11] "gpio4_io11",
+ [GPIO4_IO12] "gpio4_io12",
+ [GPIO4_IO13] "gpio4_io13",
+ [GPIO4_IO14] "gpio4_io14",
+ [GPIO4_IO15] "gpio4_io15",
+ [GPIO4_IO16] "gpio4_io16",
+ [GPIO4_IO17] "gpio4_io17",
+ [GPIO4_IO18] "gpio4_io18",
+ [GPIO4_IO19] "gpio4_io19",
+ [GPIO4_IO20] "gpio4_io20",
+ [GPIO4_IO21] "gpio4_io21",
+ [GPIO4_IO22] "gpio4_io22",
+ [GPIO4_IO23] "gpio4_io23",
+ [GPIO4_IO24] "gpio4_io24",
+ [GPIO4_IO25] "gpio4_io25",
+ [GPIO4_IO26] "gpio4_io26",
+ [GPIO4_IO27] "gpio4_io27",
+ [GPIO4_IO28] "gpio4_io28",
+ [GPIO4_IO29] "gpio4_io29",
+ [GPIO4_IO31] "gpio4_io31",
+ [GPIO5_IO00] "gpio5_io00",
+ [GPIO5_IO01] "gpio5_io01",
+ [GPIO5_IO02] "gpio5_io02",
+ [GPIO5_IO03] "gpio5_io03",
+ [GPIO5_IO04] "gpio5_io04",
+ [GPIO5_IO05] "gpio5_io05",
+ [GPIO5_IO06] "gpio5_io06",
+ [GPIO5_IO07] "gpio5_io07",
+ [GPIO5_IO08] "gpio5_io08",
+ [GPIO5_IO09] "gpio5_io09",
+ [GPIO5_IO10] "gpio5_io10",
+ [GPIO5_IO11] "gpio5_io11",
+ [GPIO5_IO12] "gpio5_io12",
+ [GPIO5_IO13] "gpio5_io13",
+ [GPIO5_IO14] "gpio5_io14",
+ [GPIO5_IO15] "gpio5_io15",
+ [GPIO5_IO16] "gpio5_io16",
+ [GPIO5_IO17] "gpio5_io17",
+ [GPIO5_IO18] "gpio5_io18",
+ [GPIO5_IO19] "gpio5_io19",
+ [GPIO5_IO20] "gpio5_io20",
+ [GPIO5_IO21] "gpio5_io21",
+ [GPIO5_IO22] "gpio5_io22",
+ [GPIO5_IO23] "gpio5_io23",
+ [GPIO5_IO24] "gpio5_io24",
+ [GPIO5_IO25] "gpio5_io25",
+ [GPIO5_IO26] "gpio5_io26",
+ [GPIO5_IO27] "gpio5_io27",
+ [GPIO5_IO28] "gpio5_io28",
+ [GPIO5_IO29] "gpio5_io29",
+ [GPT1_CAPTURE1] "gpt1_capture1",
+ [GPT1_CAPTURE2] "gpt1_capture2",
+ [GPT1_COMPARE1] "gpt1_compare1",
+ [GPT1_COMPARE2] "gpt1_compare2",
+ [GPT1_COMPARE3] "gpt1_compare3",
+ [GPT1_CLK] "gpt1_clk",
+ [GPT2_CLK] "gpt2_clk",
+ [GPT3_CLK] "gpt3_clk",
+ [I2C1_SCL] "i2c1_scl",
+ [I2C1_SDA] "i2c1_sda",
+ [I2C2_SCL] "i2c2_scl",
+ [I2C2_SDA] "i2c2_sda",
+ [I2C3_SCL] "i2c3_scl",
+ [I2C3_SDA] "i2c3_sda",
+ [I2C4_SCL] "i2c4_scl",
+ [I2C4_SDA] "i2c4_sda",
+ [M4_NMI] "m4_nmi",
+ [PCIE_CLKREQ_B] "pcie_clkreq_b",
+ [PWM1_OUT] "pwm1_out",
+ [PWM2_OUT] "pwm2_out",
+ [PWM3_OUT] "pwm3_out",
+ [PWM4_OUT] "pwm4_out",
+ [QSPI_A_DATA0] "qspi_a_data0",
+ [QSPI_A_DATA1] "qspi_a_data1",
+ [QSPI_A_DATA2] "qspi_a_data2",
+ [QSPI_A_DATA3] "qspi_a_data3",
+ [QSPI_A_DQS] "qspi_a_dqs",
+ [QSPI_A_SCLK] "qspi_a_sclk",
+ [QSPI_A_SS0_B] "qspi_a_ss0_b",
+ [QSPI_A_SS1_B] "qspi_a_ss1_b",
+ [QSPI_B_DATA0] "qspi_b_data0",
+ [QSPI_B_DATA1] "qspi_b_data1",
+ [QSPI_B_DATA2] "qspi_b_data2",
+ [QSPI_B_DATA3] "qspi_b_data3",
+ [QSPI_B_DQS] "qspi_b_dqs",
+ [QSPI_B_SCLK] "qspi_b_sclk",
+ [QSPI_B_SS0_B] "qspi_b_ss0_b",
+ [QSPI_B_SS1_B] "qspi_b_ss1_b",
+ [RAWNAND_ALE] "rawnand_ale",
+ [RAWNAND_CE0_B] "rawnand_ce0_b",
+ [RAWNAND_CE1_B] "rawnand_ce1_b",
+ [RAWNAND_CE2_B] "rawnand_ce2_b",
+ [RAWNAND_CE3_B] "rawnand_ce3_b",
+ [RAWNAND_CLE] "rawnand_cle",
+ [RAWNAND_DATA00] "rawnand_data00",
+ [RAWNAND_DATA01] "rawnand_data01",
+ [RAWNAND_DATA02] "rawnand_data02",
+ [RAWNAND_DATA03] "rawnand_data03",
+ [RANWNAD_DATA04] "ranwnad_data04",
+ [RAWNAND_DATA05] "rawnand_data05",
+ [RAWNAND_DATA06] "rawnand_data06",
+ [RAWNAND_DATA07] "rawnand_data07",
+ [RAWNAND_DQS] "rawnand_dqs",
+ [RAWNAND_READY_B] "rawnand_ready_b",
+ [RAWNAND_RE_B] "rawnand_re_b",
+ [RAWNAND_WE_B] "rawnand_we_b",
+ [RAWNAND_WP_B] "rawnand_wp_b",
+ [SAI1_MCLK] "sai1_mclk",
+ [SAI1_RX_DATA0] "sai1_rx_data0",
+ [SAI1_RX_DATA1] "sai1_rx_data1",
+ [SAI1_RX_DATA2] "sai1_rx_data2",
+ [SAI1_RX_DATA3] "sai1_rx_data3",
+ [SAI1_RX_DATA4] "sai1_rx_data4",
+ [SAI1_RX_DATA5] "sai1_rx_data5",
+ [SAI1_RX_DATA6] "sai1_rx_data6",
+ [SAI1_RX_DATA7] "sai1_rx_data7",
+ [SAI1_TX_BCLK] "sai1_tx_bclk",
+ [SAI1_TX_DATA0] "sai1_tx_data0",
+ [SAI1_TX_DATA1] "sai1_tx_data1",
+ [SAI1_TX_DATA2] "sai1_tx_data2",
+ [SAI1_TX_DATA3] "sai1_tx_data3",
+ [SAI1_TX_DATA4] "sai1_tx_data4",
+ [SAI1_TX_DATA5] "sai1_tx_data5",
+ [SAI1_TX_DATA6] "sai1_tx_data6",
+ [SAI1_TX_DATA7] "sai1_tx_data7",
+ [SAI2_MCLK] "sai2_mclk",
+ [SAI2_RX_BCLK] "sai2_rx_bclk",
+ [SAI2_RX_DATA0] "sai2_rx_data0",
+ [SAI2_RX_SYNC] "sai2_rx_sync",
+ [SAI2_TX_BCLK] "sai2_tx_bclk",
+ [SAI2_TX_DATA0] "sai2_tx_data0",
+ [SAI2_TX_SYNC] "sai2_tx_sync",
+ [SAI3_MCLK] "sai3_mclk",
+ [SAI3_RX_BCLK] "sai3_rx_bclk",
+ [SAI3_RX_DATA0] "sai3_rx_data0",
+ [SAI3_RX_SYNC] "sai3_rx_sync",
+ [SAI3_TX_BCLK] "sai3_tx_bclk",
+ [SAI3_TX_DATA0] "sai3_tx_data0",
+ [SAI3_TX_SYNC] "sai3_tx_sync",
+ [SAI4_MCLK] "sai4_mclk",
+ [SAI5_RX_DATA0] "sai5_rx_data0",
+ [SAI5_RX_DATA1] "sai5_rx_data1",
+ [SAI5_RX_DATA2] "sai5_rx_data2",
+ [SAI5_RX_DATA3] "sai5_rx_data3",
+ [SAI5_TX_BCLK] "sai5_tx_bclk",
+ [SAI5_TX_DATA0] "sai5_tx_data0",
+ [SAI5_TX_DATA1] "sai5_tx_data1",
+ [SAI5_TX_DATA2] "sai5_tx_data2",
+ [SAI5_TX_DATA3] "sai5_tx_data3",
+ [SAI6_RC_BCLK] "sai6_rc_bclk",
+ [SAI6_RX_DATA0] "sai6_rx_data0",
+ [SAI6_TX_DATA0] "sai6_tx_data0",
+ [SAI6_TX_SYNC] "sai6_tx_sync",
+ [SDMA1_EXT_EVENT0] "sdma1_ext_event0",
+ [SDMA1_EXT_EVENT1] "sdma1_ext_event1",
+ [SDMA2_EXT_EVENT0] "sdma2_ext_event0",
+ [SDMA2_EXT_EVENT1] "sdma2_ext_event1",
+ [SJC_DE_B] "sjc_de_b",
+ [SPDIF1_EXT_CLK] "spdif1_ext_clk",
+ [SPDIF1_IN] "spdif1_in",
+ [SPDIF1_OUT] "spdif1_out",
+ [SRC_BOOT_CFG0] "src_boot_cfg0",
+ [SRC_BOOT_CFG1] "src_boot_cfg1",
+ [SRC_BOOT_CFG2] "src_boot_cfg2",
+ [SRC_BOOT_CFG3] "src_boot_cfg3",
+ [SRC_BOOT_CFG4] "src_boot_cfg4",
+ [SRC_BOOT_CFG5] "src_boot_cfg5",
+ [SRC_BOOT_CFG6] "src_boot_cfg6",
+ [SRC_BOOT_CFG7] "src_boot_cfg7",
+ [SRC_BOOT_CFG8] "src_boot_cfg8",
+ [SRC_BOOT_CFG9] "src_boot_cfg9",
+ [SRC_BOOT_CFG10] "src_boot_cfg10",
+ [SRC_BOOT_CFG11] "src_boot_cfg11",
+ [SRC_BOOT_CFG12] "src_boot_cfg12",
+ [SRC_BOOT_CFG13] "src_boot_cfg13",
+ [SRC_BOOT_CFG14] "src_boot_cfg14",
+ [SRC_BOOT_CFG15] "src_boot_cfg15",
+ [UART1_CTS_B] "uart1_cts_b",
+ [UART1_RX] "uart1_rx",
+ [UART1_TX] "uart1_tx",
+ [UART2_CTS_B] "uart2_cts_b",
+ [UART2_RX] "uart2_rx",
+ [UART2_TX] "uart2_tx",
+ [UART3_CTS_B] "uart3_cts_b",
+ [UART3_RX] "uart3_rx",
+ [UART3_TX] "uart3_tx",
+ [UART4_CTS_B] "uart4_cts_b",
+ [UART4_RX] "uart4_rx",
+ [UART4_TX] "uart4_tx",
+ [USB1_OTG_ID] "usb1_otg_id",
+ [USB1_OTG_OC] "usb1_otg_oc",
+ [USB1_OTG_PWR] "usb1_otg_pwr",
+ [USB2_OTG_ID] "usb2_otg_id",
+ [USB2_OTG_OC] "usb2_otg_oc",
+ [USB2_OTG_PWR] "usb2_otg_pwr",
+ [USDHC1_CD_B] "usdhc1_cd_b",
+ [USDHC1_CLK] "usdhc1_clk",
+ [USDHC1_CMD] "usdhc1_cmd",
+ [USDHC1_DATA0] "usdhc1_data0",
+ [USDHC1_DATA1] "usdhc1_data1",
+ [USDHC1_DATA2] "usdhc1_data2",
+ [USDHC1_DATA3] "usdhc1_data3",
+ [USDHC1_DATA4] "usdhc1_data4",
+ [USDHC1_DATA5] "usdhc1_data5",
+ [USDHC1_DATA6] "usdhc1_data6",
+ [USDHC1_DATA7] "usdhc1_data7",
+ [USDHC1_RESET_B] "usdhc1_reset_b",
+ [USDHC1_STROBE] "usdhc1_strobe",
+ [USDHC1_VSELECT] "usdhc1_vselect",
+ [USDHC1_WP] "usdhc1_wp",
+ [USDHC2_CD_B] "usdhc2_cd_b",
+ [USDHC2_CLK] "usdhc2_clk",
+ [USDHC2_CMD] "usdhc2_cmd",
+ [USDHC2_DATA0] "usdhc2_data0",
+ [USDHC2_DATA1] "usdhc2_data1",
+ [USDHC2_DATA2] "usdhc2_data2",
+ [USDHC2_DATA3] "usdhc2_data3",
+ [USDHC2_RESET_B] "usdhc2_reset_b",
+ [USDHC2_VSELECT] "usdhc2_vselect",
+ [USDHC2_WP] "usdhc2_wp",
+ [WDOG1_WDOG_ANY] "wdog1_wdog_any",
+ [WDOG1_WDOG_B] "wdog1_wdog_b",
+};
+
+struct padopt {
+ char *s;
+ u32int m;
+ u32int v;
+};
+
+static struct padopt padopts[] = {
+ "VSEL_0", 7<<11, 0<<11,
+ "VSEL_1", 7<<11, 1<<11,
+ "VSEL_2", 7<<11, 2<<11,
+ "VSEL_3", 7<<11, 3<<11,
+ "VSEL_4", 7<<11, 4<<11,
+ "VSEL_5", 7<<11, 5<<11,
+ "VSEL_6", 7<<11, 6<<11,
+ "VSEL_7", 7<<11, 7<<11,
+
+ "LVTTL", 1<<8, 1<<8,
+
+ "HYS", 1<<7, 1<<7,
+
+ "PUE", 1<<6, 1<<6,
+
+ "ODE", 1<<5, 1<<5,
+
+ "SLOW", 3<<3, 0<<3,
+ "MEDIUM", 3<<3, 1<<3,
+ "FAST", 3<<3, 2<<3,
+ "MAX", 3<<3, 3<<3,
+
+ "HI-Z", 7, 0,
+ "255_OHM", 7, 1,
+ "105_OHM", 7, 2,
+ "75_OHM", 7, 3,
+ "85_OHM", 7, 4,
+ "65_OHM", 7, 5,
+ "45_OHM", 7, 6,
+ "40_OHM", 7, 7,
+
+ nil,
+};
+
+void
+iomuxpad(char *pads, char *sel, char *cfg)
+{
+ int pad, sig, mux, alt, daisy;
+ u32int val, mask, *reg;
+
+ for(pad = 0; pad < nelem(padname); pad++)
+ if(padname[pad] != nil && cistrcmp(pads, padname[pad]) == 0)
+ goto Padok;
+
+ panic("iomuxpad: %s not defined", pads);
+ return;
+Padok:
+ val = 0;
+ mask = 0;
+ mux = 0;
+ sig = 0;
+
+ if(cfg != nil){
+ struct padopt *o;
+ char *x;
+
+ for(o = padopts; o->s != nil; o++) {
+ x = strstr(cfg, o->s);
+ if(x != nil){
+ if(x > cfg && x[-1] == '~')
+ val &= ~o->v;
+ else
+ val |= o->v;
+ mask |= o->m;
+ }
+ }
+ if(mask != 0){
+ reg = &iomuxc[IOMUXC_SW_PAD_CTL_PAD_TEST_MODE + pad];
+// iprint("iomuxpad: pad_ctl_%s %p <= %.8ux & %.8ux\n", padname[pad], PADDR(reg), val, mask);
+ *reg = (*reg & ~mask) | val;
+ }
+
+ val = 0;
+ mask = 0;
+ x = strstr(cfg, "SION");
+ if(x != nil){
+ if(x > cfg && x[-1] == '~')
+ val &= ~SION;
+ else
+ val |= SION;
+ mask |= SION;
+ }
+ }
+
+ if(sel != nil){
+ if(pad < PAD_GPIO1_IO00 || pad >= nelem(padmux)/8)
+ panic("iomuxpad: %s is not muxed", pads);
+
+ /* find the mux value for the signal */
+ for(alt = 0; alt < 8; alt++){
+ mux = padmux[pad*8 + alt];
+ if(mux == 0)
+ continue;
+
+ sig = mux & ~DAISY(7);
+ if(signame[sig] != nil && cistrcmp(sel, signame[sig]) == 0)
+ goto Muxok;
+ }
+ panic("iomuxpad: %s not muxable to %s", pads, sel);
+ return;
+Muxok:
+ val = (val & ~MUX_MODE) | alt;
+ mask |= MUX_MODE;
+ }
+
+ if(mask == 0)
+ return;
+
+ if(pad < PAD_PMIC_STBY_REQ){
+ panic("iomuxpad: %s has no mux control", pads);
+ return;
+ }
+
+ reg = &iomuxc[IOMUXC_SW_MUX_CTL_PAD_PMIC_STBY_REQ + (pad - PAD_PMIC_STBY_REQ)];
+// iprint("iomuxpad: mux_ctl_%s %p <= %.8ux & %.8ux (%s)\n", padname[pad], PADDR(reg), val, mask, signame[sig]);
+ *reg = (*reg & ~mask) | val;
+
+ if((mux & DAISY(0)) == 0)
+ return;
+
+ val = DAISY_VAL(mux);
+
+ /* configure daisy input mux */
+ assert(sig < nelem(daisytab));
+ daisy = daisytab[sig];
+ assert(daisy != 0);
+ mask = DAISY_VAL(daisy);
+ assert((mask & (mask+1)) == 0);
+ daisy &= ~DAISY(7);
+
+ reg = &iomuxc[IOMUXC_CCM_PMIC_READY_SELECT_INPUT + daisy];
+// iprint("iomuxpad: %s_input_select %p <= %.8ux & %.8ux\n", signame[sig], PADDR(reg), val, mask);
+ *reg = (*reg & ~mask) | val;
+}
+
+uint
+iomuxgpr(int gpr, uint set, uint mask)
+{
+ u32int *reg = &iomuxc[IOMUXC_GPR_GPR0 + gpr];
+
+ if(mask == 0)
+ return *reg;
+
+// iprint("iomuxgpr: gpr%d %p <= %.8ux & %.8ux\n", gpr, PADDR(reg), set, mask);
+ return *reg = (*reg & ~mask) | (set & mask);
+}
diff --git a/sys/src/9/virt/l.s b/sys/src/9/virt/l.s
new file mode 100644
index 000000000..4953e68a6
--- /dev/null
+++ b/sys/src/9/virt/l.s
@@ -0,0 +1,717 @@
+#include "mem.h"
+#include "sysreg.h"
+
+#undef SYSREG
+#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
+
+TEXT _start(SB), 1, $-4
+ MOV R0, R26 /* save */
+
+ MOV $setSB-KZERO(SB), R28
+ BL svcmode<>(SB)
+
+ /* use dedicated stack pointer per exception level */
+ MOVWU $1, R1
+ MSR R1, SPSel
+
+ BL mmudisable<>(SB)
+
+ /* invalidate local caches */
+ BL cachedwbinv(SB)
+ BL l2cacheuwbinv(SB)
+ BL cacheiinv(SB)
+
+ MOV $(MACHADDR(0)-KZERO), R27
+ MRS MPIDR_EL1, R1
+ ANDW $(MAXMACH-1), R1
+ MOVWU $MACHSIZE, R2
+ MULW R1, R2, R2
+ SUB R2, R27
+
+ ADD $(MACHSIZE-16), R27, R2
+ MOV R2, SP
+
+ CBNZ R1, _startup
+
+ /* clear page table and machs */
+ MOV $(L1-KZERO), R1
+ MOV $(MACHADDR(-1)-KZERO), R2
+_zerol1:
+ MOV ZR, (R1)8!
+ CMP R1, R2
+ BNE _zerol1
+
+ /* clear BSS */
+ MOV $edata-KZERO(SB), R1
+ MOV $end-KZERO(SB), R2
+_zerobss:
+ MOV ZR, (R1)8!
+ CMP R1, R2
+ BNE _zerobss
+
+ /* setup page tables */
+ MOV $(L1-KZERO), R0
+ BL mmu0init(SB)
+
+ SEVL
+_startup:
+ WFE
+ BL mmuenable<>(SB)
+
+ MOV R26, R0
+ MOV $0, R26
+ ORR $KZERO, R27
+ MSR R27, TPIDR_EL1
+ MOV $setSB(SB), R28
+
+ BL main(SB)
+
+TEXT stop<>(SB), 1, $-4
+_stop:
+ WFE
+ B _stop
+
+TEXT aaa<>(SB), 1, $-4
+xxx:
+ MOV $(0x860040+VIRTIO), R1
+ MOVW $'A', R2
+ MOVW R2, (R1)
+ B xxx
+
+TEXT sev(SB), 1, $-4
+ SEV
+ WFE
+ RETURN
+
+TEXT svcmode<>(SB), 1, $-4
+ MSR $0xF, DAIFSet
+ MRS CurrentEL, R0
+ ANDW $(3<<2), R0
+ CMPW $(1<<2), R0
+ BEQ el1
+ CMPW $(2<<2), R0
+ BEQ el2
+ B stop<>(SB)
+el2:
+ MOV $0, R0
+ MSR R0, MDCR_EL2
+ ISB $SY
+
+ /* set virtual timer offset to zero */
+ MOV $0, R0
+ MSR R0, CNTVOFF_EL2
+
+ /* HCR = RW, HCD, SWIO, BSU, FB */
+ MOVWU $(1<<31 | 1<<29 | 1<<2 | 0<<10 | 0<<9), R0
+ MSR R0, HCR_EL2
+ ISB $SY
+
+ /* SCTLR = RES1 */
+ MOVWU $(3<<4 | 1<<11 | 1<<16 | 1<<18 | 3<<22 | 3<<28), R0
+ ISB $SY
+ MSR R0, SCTLR_EL2
+ ISB $SY
+
+ /* set VMID to zero */
+ MOV $0, R0
+ MSR R0, VTTBR_EL2
+ ISB $SY
+
+ MOVWU $(0xF<<6 | 4), R0
+ MSR R0, SPSR_EL2
+ MSR LR, ELR_EL2
+ ERET
+el1:
+ RETURN
+
+TEXT mmudisable<>(SB), 1, $-4
+#define SCTLRCLR \
+ /* RES0 */ ( 3<<30 \
+ /* RES0 */ | 1<<27 \
+ /* UCI */ | 1<<26 \
+ /* EE */ | 1<<25 \
+ /* RES0 */ | 1<<21 \
+ /* E0E */ | 1<<24 \
+ /* WXN */ | 1<<19 \
+ /* nTWE */ | 1<<18 \
+ /* RES0 */ | 1<<17 \
+ /* nTWI */ | 1<<16 \
+ /* UCT */ | 1<<15 \
+ /* DZE */ | 1<<14 \
+ /* RES0 */ | 1<<13 \
+ /* RES0 */ | 1<<10 \
+ /* UMA */ | 1<<9 \
+ /* SA0 */ | 1<<4 \
+ /* SA */ | 1<<3 \
+ /* A */ | 1<<1 )
+#define SCTLRSET \
+ /* RES1 */ ( 3<<28 \
+ /* RES1 */ | 3<<22 \
+ /* RES1 */ | 1<<20 \
+ /* RES1 */ | 1<<11 )
+#define SCTLRMMU \
+ /* I */ ( 1<<12 \
+ /* C */ | 1<<2 \
+ /* M */ | 1<<0 )
+
+ /* initialise SCTLR, MMU and caches off */
+ ISB $SY
+ MRS SCTLR_EL1, R0
+ BIC $(SCTLRCLR | SCTLRMMU), R0
+ ORR $SCTLRSET, R0
+ ISB $SY
+ MSR R0, SCTLR_EL1
+ ISB $SY
+
+ B flushlocaltlb(SB)
+
+TEXT mmuenable<>(SB), 1, $-4
+ /* return to virtual */
+ ORR $KZERO, LR
+ MOV LR, -16(RSP)!
+
+ BL flushlocaltlb(SB)
+
+ /* memory attributes */
+#define MAIRINIT \
+ ( 0xFF << MA_MEM_WB*8 \
+ | 0x33 << MA_MEM_WT*8 \
+ | 0x44 << MA_MEM_UC*8 \
+ | 0x00 << MA_DEV_nGnRnE*8 \
+ | 0x04 << MA_DEV_nGnRE*8 \
+ | 0x08 << MA_DEV_nGRE*8 \
+ | 0x0C << MA_DEV_GRE*8 )
+ MOV $MAIRINIT, R1
+ MSR R1, MAIR_EL1
+ ISB $SY
+
+ /* translation control */
+#define TCRINIT \
+ /* TBI1 */ ( 0<<38 \
+ /* TBI0 */ | 0<<37 \
+ /* AS */ | 0<<36 \
+ /* TG1 */ | (((3<<16|1<<14|2<<12)>>PGSHIFT)&3)<<30 \
+ /* SH1 */ | SHARE_INNER<<28 \
+ /* ORGN1 */ | CACHE_WB<<26 \
+ /* IRGN1 */ | CACHE_WB<<24 \
+ /* EPD1 */ | 0<<23 \
+ /* A1 */ | 0<<22 \
+ /* T1SZ */ | (64-EVASHIFT)<<16 \
+ /* TG0 */ | (((1<<16|2<<14|0<<12)>>PGSHIFT)&3)<<14 \
+ /* SH0 */ | SHARE_INNER<<12 \
+ /* ORGN0 */ | CACHE_WB<<10 \
+ /* IRGN0 */ | CACHE_WB<<8 \
+ /* EPD0 */ | 0<<7 \
+ /* T0SZ */ | (64-EVASHIFT)<<0 )
+ MOV $TCRINIT, R1
+ MRS ID_AA64MMFR0_EL1, R2
+ ANDW $0x7, R2 // PARange
+ ADD R2<<32, R1 // IPS
+ MSR R1, TCR_EL1
+ ISB $SY
+
+ /* load the page tables */
+ MOV $(L1TOP-KZERO), R0
+ ISB $SY
+ MSR R0, TTBR0_EL1
+ MSR R0, TTBR1_EL1
+ ISB $SY
+
+ /* enable MMU and caches */
+ MRS SCTLR_EL1, R1
+ ORR $SCTLRMMU, R1
+ ISB $SY
+ MSR R1, SCTLR_EL1
+ ISB $SY
+
+ MOV RSP, R1
+ ORR $KZERO, R1
+ MOV R1, RSP
+ MOV (RSP)16!, LR
+ B cacheiinv(SB)
+
+TEXT touser(SB), 1, $-4
+ MSR $0x3, DAIFSet // interrupts off
+ MOVWU $0x10028, R1 // entry
+ MOVWU $0, R2 // psr
+ MSR R0, SP_EL0 // sp
+ MSR R1, ELR_EL1
+ MSR R2, SPSR_EL1
+ ERET
+
+TEXT cas(SB), 1, $-4
+TEXT cmpswap(SB), 1, $-4
+ MOVWU ov+8(FP), R1
+ MOVWU nv+16(FP), R2
+_cas1:
+ LDXRW (R0), R3
+ CMP R3, R1
+ BNE _cas0
+ STXRW R2, (R0), R4
+ CBNZ R4, _cas1
+ MOVW $1, R0
+ DMB $ISH
+ RETURN
+_cas0:
+ CLREX
+ MOVW $0, R0
+ RETURN
+
+TEXT tas(SB), 1, $-4
+TEXT _tas(SB), 1, $-4
+ MOVW $0xdeaddead, R2
+_tas1:
+ LDXRW (R0), R1
+ STXRW R2, (R0), R3
+ CBNZ R3, _tas1
+ MOVW R1, R0
+
+TEXT coherence(SB), 1, $-4
+ DMB $ISH
+ RETURN
+
+TEXT islo(SB), 1, $-4
+ MRS DAIF, R0
+ AND $(0x2<<6), R0
+ EOR $(0x2<<6), R0
+ RETURN
+
+TEXT splhi(SB), 1, $-4
+ MRS DAIF, R0
+ MSR $0x2, DAIFSet
+ RETURN
+
+TEXT splfhi(SB), 1, $-4
+ MRS DAIF, R0
+ MSR $0x3, DAIFSet
+ RETURN
+
+TEXT spllo(SB), 1, $-4
+ MSR $0x3, DAIFClr
+ RETURN
+
+TEXT splflo(SB), 1, $-4
+ MSR $0x1, DAIFClr
+ RETURN
+
+TEXT splx(SB), 1, $-4
+ MSR R0, DAIF
+ RETURN
+
+TEXT idlehands(SB), 1, $-4
+ DMB $ISH
+ MOV $nrdy(SB), R1
+ LDXRW (R1), R0
+ CBZ R0, _goodnight
+ CLREX
+ SEVL
+_goodnight:
+ WFE
+ RETURN
+
+TEXT vcycles(SB), 1, $-4
+ MRS CNTVCT_EL0, R0
+ RETURN
+
+TEXT lcycles(SB), 1, $-4
+ MRS PMCCNTR_EL0, R0
+ RETURN
+
+TEXT setlabel(SB), 1, $-4
+ MOV LR, 8(R0)
+ MOV SP, R1
+ MOV R1, 0(R0)
+ MOVW $0, R0
+ RETURN
+
+TEXT gotolabel(SB), 1, $-4
+ MOV 8(R0), LR /* link */
+ MOV 0(R0), R1 /* sp */
+ MOV R1, SP
+ MOVW $1, R0
+ RETURN
+
+TEXT returnto(SB), 1, $-4
+ MOV R0, 0(SP)
+ RETURN
+
+TEXT getfar(SB), 1, $-4
+ MRS FAR_EL1, R0
+ RETURN
+
+TEXT setttbr(SB), 1, $-4
+ DSB $ISHST
+ MSR R0, TTBR0_EL1
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+/*
+ * TLB maintenance operations.
+ * these broadcast to all cpu's in the cluser
+ * (inner sharable domain).
+ */
+TEXT flushasidva(SB), 1, $-4
+TEXT tlbivae1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,1 /* VAE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushasidvall(SB), 1, $-4
+TEXT tlbivale1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,5 /* VALE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushasid(SB), 1, $-4
+TEXT tlbiaside1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,2 /* ASIDE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushtlb(SB), 1, $-4
+TEXT tlbivmalle1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,0 /* VMALLE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+/*
+ * flush the tlb of this cpu. no broadcast.
+ */
+TEXT flushlocaltlb(SB), 1, $-4
+TEXT tlbivmalle1(SB), 1, $-4
+ DSB $NSHST
+ TLBI R0, 0,8,7,0 /* VMALLE1 */
+ DSB $NSH
+ ISB $SY
+ RETURN
+
+TEXT fpsaveregs(SB), 1, $-4
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 0) /* MOV { V0, V1, V2, V3 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 4) /* MOV { V4, V5, V6, V7 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 8) /* MOV { V8, V9, V10,V11 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 12) /* MOV { V12,V13,V14,V15 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 16) /* MOV { V16,V17,V18,V19 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 20) /* MOV { V20,V21,V22,V23 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 24) /* MOV { V24,V25,V26,V27 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 28) /* MOV { V28,V29,V30,V31 }, (R0)64! */
+ RETURN
+
+TEXT fploadregs(SB), 1, $-4
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 0) /* MOV (R0)64!, { V0, V1, V2, V3 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 4) /* MOV (R0)64!, { V4, V5, V6, V7 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 8) /* MOV (R0)64!, { V8, V9, V10,V11 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 12) /* MOV (R0)64!, { V12,V13,V14,V15 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 16) /* MOV (R0)64!, { V16,V17,V18,V19 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 20) /* MOV (R0)64!, { V20,V21,V22,V23 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 24) /* MOV (R0)64!, { V24,V25,V26,V27 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 28) /* MOV (R0)64!, { V28,V29,V30,V31 } */
+ RETURN
+
+// syscall or trap from EL0
+TEXT vsys0(SB), 1, $-4
+ LSRW $26, R0, R17 // ec
+ CMPW $0x15, R17 // SVC trap?
+ BNE _itsatrap // nope.
+
+ MOVP R26, R27, 224(RSP)
+ MOVP R28, R29, 240(RSP)
+
+ MRS SP_EL0, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ MOV $setSB(SB), R28
+ MRS TPIDR_EL1, R27
+ MOV 16(R27), R26
+
+ ADD $16, RSP, R0 // ureg
+ BL syscall(SB)
+
+TEXT forkret(SB), 1, $-4
+ MSR $0x3, DAIFSet // interrupts off
+
+ ADD $16, RSP, R0 // ureg
+
+ MOV 16(RSP), R0 // ret
+ MOV 264(RSP), R1 // sp
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R1, SP_EL0
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOVP 224(RSP), R26, R27
+ MOVP 240(RSP), R28, R29
+
+ MOV 256(RSP), R30 // link
+
+ ADD $TRAPFRAMESIZE, RSP
+ ERET
+
+TEXT itsatrap<>(SB), 1, $-4
+_itsatrap:
+ MOVP R1, R2, 24(RSP)
+ MOVP R3, R4, 40(RSP)
+ MOVP R5, R6, 56(RSP)
+ MOVP R7, R8, 72(RSP)
+ MOVP R9, R10, 88(RSP)
+ MOVP R11, R12, 104(RSP)
+ MOVP R13, R14, 120(RSP)
+ MOVP R15, R16, 136(RSP)
+
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+// trap/irq/fiq/serr from EL0
+TEXT vtrap0(SB), 1, $-4
+ MOVP R26, R27, 224(RSP)
+ MOVP R28, R29, 240(RSP)
+
+ MRS SP_EL0, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ MOV $setSB(SB), R28
+ MRS TPIDR_EL1, R27
+ MOV 16(R27), R26
+
+ ADD $16, RSP, R0 // ureg
+ BL trap(SB)
+
+TEXT noteret(SB), 1, $-4
+ MSR $0x3, DAIFSet // interrupts off
+
+ ADD $16, RSP, R0 // ureg
+
+ MOV 264(RSP), R1 // sp
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R1, SP_EL0
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOVP 224(RSP), R26, R27
+ MOVP 240(RSP), R28, R29
+
+_intrreturn:
+ MOVP 16(RSP), R0, R1
+ MOVP 32(RSP), R2, R3
+ MOVP 48(RSP), R4, R5
+ MOVP 64(RSP), R6, R7
+ MOVP 80(RSP), R8, R9
+ MOVP 96(RSP), R10, R11
+ MOVP 112(RSP), R12, R13
+ MOVP 128(RSP), R14, R15
+ MOVP 144(RSP), R16, R17
+ MOVP 160(RSP), R18, R19
+ MOVP 176(RSP), R20, R21
+ MOVP 192(RSP), R22, R23
+ MOVP 208(RSP), R24, R25
+
+ MOV 256(RSP), R30 // link
+
+ ADD $TRAPFRAMESIZE, RSP
+ ERET
+
+// irq/fiq/trap/serr from EL1
+TEXT vtrap1(SB), 1, $-4
+ MOV R29, 248(RSP) // special
+
+ ADD $TRAPFRAMESIZE, RSP, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ ADD $16, RSP, R0 // ureg
+ BL trap(SB)
+
+ MSR $0x3, DAIFSet // interrupts off
+
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOV 248(RSP), R29 // special
+ B _intrreturn
+
+// vector tables
+TEXT vsys(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOV R0, 16(RSP)
+ MOV R30, 256(RSP) // link
+
+ MOV R17, 152(RSP) // temp
+
+ MRS ESR_EL1, R0 // type
+
+_vsyspatch:
+ B _vsyspatch // branch to vsys0() patched in
+
+TEXT vtrap(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MRS ESR_EL1, R0 // type
+
+_vtrappatch:
+ B _vtrappatch // branch to vtrapX() patched in
+
+TEXT virq(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MOV $(1<<32), R0 // type irq
+
+_virqpatch:
+ B _virqpatch // branch to vtrapX() patched in
+
+TEXT vfiq(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+ MOV $(2<<32), R0 // type fiq
+
+_vfiqpatch:
+ B _vfiqpatch // branch to vtrapX() patched in
+
+TEXT vserr(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MRS ESR_EL1, R0
+ ORR $(3<<32), R0 // type
+_vserrpatch:
+ B _vserrpatch // branch to vtrapX() patched in
+
+/* fault-proof memcpy */
+TEXT peek(SB), 1, $-4
+ MOV R0, R1
+ MOV dst+8(FP), R2
+ MOVWU len+16(FP), R0
+TEXT _peekinst(SB), 1, $-4
+_peekloop:
+ MOVBU (R1)1!, R3
+ MOVBU R3, (R2)1!
+ SUBS $1, R0
+ BNE _peekloop
+ RETURN
+
+TEXT smccall(SB), 1, $32
+ /* save extern registers */
+ MOVP R26, R27, (RSP)
+
+ /* R0 = Ureg */
+ MOV R0, R8
+
+ /* save ureg pointer */
+ MOV R8, 16(RSP)
+
+ MOVP 0(R8), R0, R1
+ MOVP 16(R8), R2, R3
+ MOVP 32(R8), R4, R5
+ MOVP 48(R8), R6, R7
+
+ SMC
+
+ /* restore ureg pointer */
+ MOV 16(RSP), R8
+
+ MOVP R0, R1, 0(R8)
+ MOVP R2, R3, 16(R8)
+
+ /* restore extern registers */
+ MOVP (RSP), R26, R27
+
+ RETURN
+
+
+
diff --git a/sys/src/9/virt/main.c b/sys/src/9/virt/main.c
new file mode 100644
index 000000000..5633d92a0
--- /dev/null
+++ b/sys/src/9/virt/main.c
@@ -0,0 +1,455 @@
+#include "u.h"
+#include "tos.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "pool.h"
+#include "io.h"
+#include "sysreg.h"
+#include "ureg.h"
+
+#include "rebootcode.i"
+
+Conf conf;
+
+#define MAXCONF 64
+static char *confname[MAXCONF];
+static char *confval[MAXCONF];
+static int nconf;
+
+void
+bootargsinit(void)
+{
+ int i, j, n;
+ char *cp, *line[MAXCONF], *p, *q;
+
+ /*
+ * parse configuration args from dos file plan9.ini
+ */
+ cp = BOOTARGS; /* where b.com leaves its config */
+ cp[BOOTARGSLEN-1] = 0;
+
+ /*
+ * Strip out '\r', change '\t' -> ' '.
+ */
+ p = cp;
+ for(q = cp; *q; q++){
+ if(*q == -1)
+ break;
+ if(*q == '\r')
+ continue;
+ if(*q == '\t')
+ *q = ' ';
+ *p++ = *q;
+ }
+ *p = 0;
+
+ n = getfields(cp, line, MAXCONF, 1, "\n");
+ for(i = 0; i < n; i++){
+ if(*line[i] == '#')
+ continue;
+ cp = strchr(line[i], '=');
+ if(cp == nil)
+ continue;
+ *cp++ = '\0';
+ for(j = 0; j < nconf; j++){
+ if(cistrcmp(confname[j], line[i]) == 0)
+ break;
+ }
+ confname[j] = line[i];
+ confval[j] = cp;
+ if(j == nconf)
+ nconf++;
+ }
+}
+
+char*
+getconf(char *name)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++)
+ if(cistrcmp(confname[i], name) == 0)
+ return confval[i];
+ return nil;
+}
+
+void
+setconfenv(void)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++){
+ if(confname[i][0] != '*')
+ ksetenv(confname[i], confval[i], 0);
+ ksetenv(confname[i], confval[i], 1);
+ }
+}
+
+void
+writeconf(void)
+{
+ char *p, *q;
+ int n;
+
+ p = getconfenv();
+ if(waserror()) {
+ free(p);
+ nexterror();
+ }
+
+ /* convert to name=value\n format */
+ for(q=p; *q; q++) {
+ q += strlen(q);
+ *q = '=';
+ q += strlen(q);
+ *q = '\n';
+ }
+ n = q - p + 1;
+ if(n >= BOOTARGSLEN)
+ error("kernel configuration too large");
+ memmove(BOOTARGS, p, n);
+ memset(BOOTARGS+n, 0, BOOTARGSLEN-n);
+ poperror();
+ free(p);
+}
+
+int
+isaconfig(char *, int, ISAConf *)
+{
+ return 0;
+}
+
+/*
+ * starting place for first process
+ */
+void
+init0(void)
+{
+ char **sp;
+
+ chandevinit();
+
+ if(!waserror()){
+ ksetenv("cputype", "arm64", 0);
+ if(cpuserver)
+ ksetenv("service", "cpu", 0);
+ else
+ ksetenv("service", "terminal", 0);
+ ksetenv("console", "0", 0);
+ setconfenv();
+ 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");
+ sp[0] = (void*)&sp[1];
+ touser((uintptr)sp);
+}
+
+void
+confinit(void)
+{
+ int userpcnt;
+ ulong kpages;
+ char *p;
+ int i;
+
+ conf.nmach = MAXMACH;
+
+ if(p = getconf("service")){
+ if(strcmp(p, "cpu") == 0)
+ cpuserver = 1;
+ else if(strcmp(p,"terminal") == 0)
+ cpuserver = 0;
+ }
+
+ if(p = getconf("*kernelpercent"))
+ userpcnt = 100 - strtol(p, 0, 0);
+ else
+ userpcnt = 0;
+
+ if(userpcnt < 10)
+ userpcnt = 60 + cpuserver*10;
+
+ conf.npage = 0;
+ for(i = 0; i < nelem(conf.mem); i++)
+ conf.npage += conf.mem[i].npage;
+
+ kpages = conf.npage - (conf.npage*userpcnt)/100;
+ if(kpages > ((uintptr)-VDRAM)/BY2PG)
+ kpages = ((uintptr)-VDRAM)/BY2PG;
+
+ conf.upages = conf.npage - kpages;
+ conf.ialloc = (kpages/2)*BY2PG;
+
+ /* set up other configuration parameters */
+ conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+ if(cpuserver)
+ conf.nproc *= 3;
+ if(conf.nproc > 4000)
+ conf.nproc = 4000;
+ conf.nswap = conf.npage*3;
+ conf.nswppo = 4096;
+ conf.nimage = 200;
+
+ conf.copymode = conf.nmach > 1;
+
+ /*
+ * Guess how much is taken by the large permanent
+ * datastructures. Mntcache and Mntrpc are not accounted for.
+ */
+ kpages = conf.npage - conf.upages;
+ kpages *= BY2PG;
+ kpages -= conf.upages*sizeof(Page)
+ + conf.nproc*sizeof(Proc*)
+ + conf.nimage*sizeof(Image)
+ + conf.nswap
+ + conf.nswppo*sizeof(Page*);
+ mainmem->maxsize = kpages;
+ imagmem->maxsize = kpages;
+}
+
+void
+machinit(void)
+{
+ m->ticks = 1;
+ m->perf.period = 1;
+ active.machs[m->machno] = 1;
+}
+
+void
+mpinit(void)
+{
+ extern void _start(void);
+ int i;
+
+ splhi();
+ for(i = 1; i < conf.nmach; i++){
+ Ureg u = {0};
+
+ MACHP(i)->machno = i;
+ cachedwbinvse(MACHP(i), MACHSIZE);
+
+ u.r0 = 0x84000003; /* CPU_ON */
+ u.r1 = (sysrd(MPIDR_EL1) & ~0xFF) | i;
+ u.r2 = PADDR(_start);
+ u.r3 = i;
+ smccall(&u);
+ }
+ synccycles();
+ spllo();
+}
+
+void
+cpuidprint(void)
+{
+ iprint("cpu%d: %dMHz ARM Cortex A53\n", m->machno, m->cpumhz);
+}
+
+static void
+tmuinit(void)
+{
+ Physseg seg;
+
+ setclkgate("tmu.clk", 1);
+ memset(&seg, 0, sizeof(seg));
+ seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
+ seg.name = "tmu";
+ seg.pa = VIRTIO + 0x260000 - KZERO;
+ seg.size = BY2PG;
+ addphysseg(&seg);
+}
+
+static void
+lpcspiinit(void)
+{
+ Physseg seg;
+
+ iomuxpad("pad_ecspi2_sclk", "ecspi2_sclk", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+ iomuxpad("pad_ecspi2_mosi", "ecspi2_mosi", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+ iomuxpad("pad_ecspi2_miso", "ecspi2_miso", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+ iomuxpad("pad_ecspi2_ss0", "ecspi2_ss0", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
+
+ setclkgate("ecspi2.ipg_clk", 0);
+ setclkgate("ecspi2.ipg_clk_per", 0);
+ setclkrate("ecspi2.ipg_clk_per", "osc_25m_ref_clk", 25*Mhz);
+ setclkgate("ecspi2.ipg_clk_per", 1);
+ setclkgate("ecspi2.ipg_clk", 1);
+
+ memset(&seg, 0, sizeof(seg));
+ seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
+ seg.name = "ecspi2";
+ seg.pa = VIRTIO + 0x830000 - KZERO;
+ seg.size = BY2PG;
+ addphysseg(&seg);
+}
+
+volatile char *easyuart = (char *)(VIRTIO+0x1000000);
+
+void
+main(void)
+{
+ *easyuart = 'p';
+ *easyuart = 'l';
+ *easyuart = 's';
+ *easyuart = '9';
+ *easyuart = '\n';
+
+ machinit();
+ *easyuart = 'a';
+ /*if(m->machno){ // what is this?
+ trapinit();
+ fpuinit();
+ intrinit();
+ clockinit();
+ cpuidprint();
+ synccycles();
+ timersinit();
+ flushtlb();
+ mmu1init();
+ m->ticks = MACHP(0)->ticks;
+ schedinit();
+ return;
+ }*/
+ quotefmtinstall();
+ bootargsinit();
+ meminit();
+ confinit();
+ xinit();
+ uartconsinit();
+ printinit();
+ print("\nPlan 9\n");
+ *easyuart = 'i';
+ trapinit();
+ print("\ntrapinited\n");
+ fpuinit();
+ print("\nfpu\n");
+ //intrinit();
+ print("\nintr\n");
+ clockinit();
+ print("\nclock\n");
+ cpuidprint();
+ print("\ncpuid\n");
+ timersinit();
+ print("\ntimers\n");
+ pageinit();
+ print("\npage\n");
+ procinit0();
+ print("\nproc0\n");
+ initseg();
+ print("\nseg\n");
+ links();
+ print("\nlinks\n");
+ chandevreset();
+ print("\nchandevreset\n");
+ //gpioinit();
+ //lcdinit();
+ //tmuinit();
+ //print("\ntmu\n");
+ //lpcspiinit();
+ //print("\nlpsci\n");
+ userinit();
+ print("\nuser\n");
+ mpinit();
+ print("\nmpinit\n");
+ mmu0clear((uintptr*)L1);
+ flushtlb();
+ mmu1init();
+ schedinit();
+}
+
+void
+exit(int)
+{
+ Ureg u = { .r0 = 0x84000002 }; /* CPU_OFF */
+
+ cpushutdown();
+ splfhi();
+
+ if(m->machno == 0)
+ u.r0 = 0x84000009; /* SYSTEM RESET */
+ smccall(&u);
+}
+
+static void
+rebootjump(void *entry, void *code, ulong size)
+{
+ void (*f)(void*, void*, ulong);
+
+ intrcpushutdown();
+
+ /* redo identity map */
+ mmuidmap((uintptr*)L1);
+
+ /* setup reboot trampoline function */
+ f = (void*)REBOOTADDR;
+ memmove(f, rebootcode, sizeof(rebootcode));
+
+ cachedwbinvse(f, sizeof(rebootcode));
+ cacheiinvse(f, sizeof(rebootcode));
+
+ (*f)(entry, code, size);
+
+ for(;;);
+}
+
+void
+reboot(void*, void *code, ulong size)
+{
+ writeconf();
+ while(m->machno != 0){
+ procwired(up, 0);
+ sched();
+ }
+
+ cpushutdown();
+ delay(2000);
+
+ splfhi();
+
+ /* turn off buffered serial console */
+ serialoq = nil;
+
+ /* shutdown devices */
+ chandevshutdown();
+
+ /* stop the clock */
+ clockshutdown();
+ intrsoff();
+
+ /* off we go - never to return */
+ rebootjump((void*)(KTZERO-KZERO), code, size);
+}
+
+void
+dmaflush(int clean, void *p, ulong len)
+{
+ uintptr s = (uintptr)p;
+ uintptr e = (uintptr)p + len;
+
+ if(clean){
+ s &= ~(BLOCKALIGN-1);
+ e += BLOCKALIGN-1;
+ e &= ~(BLOCKALIGN-1);
+ cachedwbse((void*)s, e - s);
+ return;
+ }
+ if(s & BLOCKALIGN-1){
+ s &= ~(BLOCKALIGN-1);
+ cachedwbinvse((void*)s, BLOCKALIGN);
+ s += BLOCKALIGN;
+ }
+ if(e & BLOCKALIGN-1){
+ e &= ~(BLOCKALIGN-1);
+ if(e < s)
+ return;
+ cachedwbinvse((void*)e, BLOCKALIGN);
+ }
+ if(s < e)
+ cachedinvse((void*)s, e - s);
+}
diff --git a/sys/src/9/virt/mem.h b/sys/src/9/virt/mem.h
new file mode 100644
index 000000000..117722bc1
--- /dev/null
+++ b/sys/src/9/virt/mem.h
@@ -0,0 +1,144 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+#define KiB 1024u /* Kibi 0x0000000000000400 */
+#define MiB 1048576u /* Mebi 0x0000000000100000 */
+#define GiB 1073741824u /* Gibi 000000000040000000 */
+
+/*
+ * Sizes:
+ * L0 L1 L2 L3
+ * 4K 2M 1G 512G
+ * 16K 32M 64G 128T
+ * 64K 512M 4T -
+ */
+#define PGSHIFT 16 /* log(BY2PG) */
+#define BY2PG (1ULL<<PGSHIFT) /* bytes per page */
+#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+
+/* effective virtual address space */
+#define EVASHIFT 34
+#define EVAMASK ((1ULL<<EVASHIFT)-1)
+
+#define PTSHIFT (PGSHIFT-3)
+#define PTLEVELS (((EVASHIFT-PGSHIFT)+PTSHIFT-1)/PTSHIFT)
+#define PTLX(v, l) ((((v) & EVAMASK) >> (PGSHIFT + (l)*PTSHIFT)) & ((1 << PTSHIFT)-1))
+#define PGLSZ(l) (1ULL << (PGSHIFT + (l)*PTSHIFT))
+
+#define PTL1X(v, l) (L1TABLEX(v, l) | PTLX(v, l))
+#define L1TABLEX(v, l) (L1TABLE(v, l) << PTSHIFT)
+#define L1TABLES ((-KSEG0+PGLSZ(2)-1)/PGLSZ(2))
+#define L1TABLE(v, l) (L1TABLES - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
+#define L1TOPSIZE (1ULL << (EVASHIFT - PTLEVELS*PTSHIFT))
+
+#define MAXMACH 4 /* max # cpus system can run */
+#define MACHSIZE (8*KiB)
+
+#define KSTACK (8*KiB)
+#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */
+#define TRAPFRAMESIZE (38*8)
+
+/* reserved dram for ucalloc() and fbmemalloc() at the end of KZERO (physical) */
+#define UCRAMBASE (-KZERO - UCRAMSIZE)
+#define UCRAMSIZE (8*MiB)
+
+#define VDRAM (0xFFFFFFFFC0000000ULL) /* 0x40000000 - 0x80000000 */
+#define KTZERO (VDRAM + 0x100000) /* 0x40100000 - kernel text start */
+
+#define VIRTIO (0xFFFFFFFFB0000000ULL) /* 0x30000000 */
+
+#define KZERO (0xFFFFFFFF80000000ULL) /* 0x00000000 - kernel address space */
+
+#define VMAP (0xFFFFFFFF00000000ULL) /* 0x00000000 - 0x40000000 */
+
+#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
+#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
+
+#define KSEG0 (0xFFFFFFFE00000000ULL)
+
+#define L1 (L1TOP-L1SIZE)
+#define L1SIZE ((L1TABLES+PTLEVELS-2)*BY2PG)
+#define L1TOP ((MACHADDR(MAXMACH-1)-L1TOPSIZE)&-BY2PG)
+
+#define MACHADDR(n) (KTZERO-((n)+1)*MACHSIZE)
+
+#define CONFADDR (VDRAM + 0x10000) /* 0x40010000 */
+
+#define BOOTARGS ((char*)CONFADDR)
+#define BOOTARGSLEN 0x10000
+
+#define REBOOTADDR (VDRAM-KZERO + 0x20000) /* 0x40020000 */
+
+#define UZERO 0ULL /* user segment */
+#define UTZERO (UZERO+0x10000) /* user text start */
+#define USTKTOP ((EVAMASK>>1)-0xFFFF) /* user segment end +1 */
+#define USTKSIZE (16*1024*1024) /* user stack size */
+
+#define BLOCKALIGN 64 /* only used in allocb.c */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BY2SE 4
+#define BY2WD 8
+#define BY2V 8 /* only used in xalloc.c */
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 8192
+#define SSEGMAPSIZE 16
+#define PPN(x) ((x)&~(BY2PG-1))
+
+#define SHARE_NONE 0
+#define SHARE_OUTER 2
+#define SHARE_INNER 3
+
+#define CACHE_UC 0
+#define CACHE_WB 1
+#define CACHE_WT 2
+#define CACHE_WB_NA 3
+
+#define MA_MEM_WB 0
+#define MA_MEM_WT 1
+#define MA_MEM_UC 2
+#define MA_DEV_nGnRnE 3
+#define MA_DEV_nGnRE 4
+#define MA_DEV_nGRE 5
+#define MA_DEV_GRE 6
+
+#define PTEVALID 1
+#define PTEBLOCK 0
+#define PTETABLE 2
+#define PTEPAGE 2
+
+#define PTEMA(x) ((x)<<2)
+#define PTEAP(x) ((x)<<6)
+#define PTESH(x) ((x)<<8)
+
+#define PTEAF (1<<10)
+#define PTENG (1<<11)
+#define PTEPXN (1ULL<<53)
+#define PTEUXN (1ULL<<54)
+
+#define PTEKERNEL PTEAP(0)
+#define PTEUSER PTEAP(1)
+#define PTEWRITE PTEAP(0)
+#define PTERONLY PTEAP(2)
+#define PTENOEXEC (PTEPXN|PTEUXN)
+
+#define PTECACHED PTEMA(MA_MEM_WB)
+#define PTEWT PTEMA(MA_MEM_WT)
+#define PTEUNCACHED PTEMA(MA_MEM_UC)
+#define PTEDEVICE PTEMA(MA_DEV_nGnRE)
+
+/*
+ * Physical machine information from here on.
+ * PHYS addresses as seen from the arm cpu.
+ * BUS addresses as seen from peripherals
+ */
+#define PHYSDRAM 0
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#define MAX(a, b) ((a) > (b)? (a): (b))
diff --git a/sys/src/9/virt/mkfile b/sys/src/9/virt/mkfile
new file mode 100644
index 000000000..fc9519cfb
--- /dev/null
+++ b/sys/src/9/virt/mkfile
@@ -0,0 +1,101 @@
+CONF=virt64
+CONFLIST=virt64
+
+kzero=0xffffffff80000000
+loadaddr=0xffffffffc0100000
+
+objtype=arm64
+</$objtype/mkfile
+p=9
+
+DEVS=`{rc ../port/mkdevlist $CONF}
+
+PORT=\
+ alarm.$O\
+ alloc.$O\
+ allocb.$O\
+ auth.$O\
+ cache.$O\
+ chan.$O\
+ dev.$O\
+ edf.$O\
+ fault.$O\
+ mul64fract.$O\
+ page.$O\
+ parse.$O\
+ pgrp.$O\
+ portclock.$O\
+ print.$O\
+ proc.$O\
+ qio.$O\
+ qlock.$O\
+ rdb.$O\
+ rebootcmd.$O\
+ segment.$O\
+ syscallfmt.$O\
+ sysfile.$O\
+ sysproc.$O\
+ taslock.$O\
+ tod.$O\
+ xalloc.$O\
+ userinit.$O\
+
+OBJ=\
+ l.$O\
+ cache.v8.$O\
+ clock.$O\
+ fpu.$O\
+ main.$O\
+ mmu.$O\
+ sysreg.$O\
+ random.$O\
+ trap.$O\
+ $CONF.root.$O\
+ $CONF.rootc.$O\
+ $DEVS\
+ $PORT\
+
+# HFILES=
+
+LIB=\
+ /$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/libc.a\
+# /$objtype/lib/libdtracy.a\
+
+9:V: $p$CONF $p$CONF.u
+
+$p$CONF.u:D: $p$CONF
+ aux/aout2uimage -Z$kzero $p$CONF
+
+$p$CONF:D: $OBJ $CONF.$O $LIB
+ $LD -o $target -T$loadaddr -l $prereq
+ size $target
+
+$OBJ: $HFILES
+
+install:V: /$objtype/$p$CONF
+
+/$objtype/$p$CONF:D: $p$CONF $p$CONF.u
+ cp -x $p$CONF $p$CONF.u /$objtype/
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+
+main.$O: rebootcode.i
+
+pciimx.$O: ../port/pci.h
+
+initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
+ $LD -l -R1 -s -o $target $prereq
+
+rebootcode.out: rebootcode.$O cache.v8.$O
+ $LD -l -H6 -R1 -T0x40020000 -s -o $target $prereq
+
+$CONF.clean:
+ rm -rf $p$CONF $p$CONF.u errstr.h $CONF.c boot$CONF.c
diff --git a/sys/src/9/virt/mmu.c b/sys/src/9/virt/mmu.c
new file mode 100644
index 000000000..6bae2ed64
--- /dev/null
+++ b/sys/src/9/virt/mmu.c
@@ -0,0 +1,526 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "sysreg.h"
+
+void
+mmu0init(uintptr *l1)
+{
+ uintptr va, pa, pe, attr;
+
+ /* VDRAM */
+ attr = PTEWRITE | PTEAF | PTEKERNEL | PTEUXN | PTESH(SHARE_INNER);
+ pe = -KZERO;
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
+ l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
+ l1[PTL1X(pa, 1)] = pa | PTEVALID | PTEBLOCK | attr;
+ }
+
+ attr = PTEWRITE | PTEAF | PTEKERNEL | PTEUXN | PTEPXN | PTESH(SHARE_OUTER) | PTEDEVICE;
+ //pe = VDRAM - KZERO;
+ pe = 0xa000000;
+ for(pa = 0x8000000, va = VIRTIO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
+ if(((pa|va) & PGLSZ(1)-1) != 0){
+ l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
+ for(; pa < pe && ((va|pa) & PGLSZ(1)-1) != 0; pa += PGLSZ(0), va += PGLSZ(0)){
+ assert(l1[PTLX(va, 0)] == 0);
+ l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
+ }
+ break;
+ }
+ l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
+ }
+
+ if(PTLEVELS > 2)
+ for(va = KSEG0; va != 0; va += PGLSZ(2))
+ l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
+ if(PTLEVELS > 3)
+ for(va = KSEG0; va != 0; va += PGLSZ(3))
+ l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
+}
+
+void
+mmu0clear(uintptr *l1)
+{
+ uintptr va, pa, pe;
+
+ pe = -VDRAM;
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
+ if(PTL1X(pa, 1) != PTL1X(va, 1))
+ l1[PTL1X(pa, 1)] = 0;
+
+ if(PTLEVELS > 2)
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
+ if(PTL1X(pa, 2) != PTL1X(va, 2))
+ l1[PTL1X(pa, 2)] = 0;
+ if(PTLEVELS > 3)
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
+ if(PTL1X(pa, 3) != PTL1X(va, 3))
+ l1[PTL1X(pa, 3)] = 0;
+}
+
+void
+mmuidmap(uintptr *l1)
+{
+ uintptr va, pa, pe;
+
+ pe = -VDRAM;
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
+ l1[PTL1X(pa, 1)] = l1[PTL1X(va, 1)];
+ if(PTLEVELS > 2)
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
+ l1[PTL1X(pa, 2)] = l1[PTL1X(va, 2)];
+ if(PTLEVELS > 3)
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
+ l1[PTL1X(pa, 3)] = l1[PTL1X(va, 3)];
+ setttbr(PADDR(&l1[L1TABLEX(0, PTLEVELS-1)]));
+ flushtlb();
+}
+
+void
+mmu1init(void)
+{
+ m->mmutop = mallocalign(L1TOPSIZE, BY2PG, 0, 0);
+ if(m->mmutop == nil)
+ panic("mmu1init: no memory for mmutop");
+ memset(m->mmutop, 0, L1TOPSIZE);
+ mmuswitch(nil);
+}
+
+/* KZERO maps the first 1GB of ram */
+uintptr
+paddr(void *va)
+{
+ if((uintptr)va >= KZERO)
+ return (uintptr)va-KZERO;
+ panic("paddr: va=%#p pc=%#p", va, getcallerpc(&va));
+ return 0;
+}
+
+uintptr
+cankaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return -KZERO - pa;
+ return 0;
+}
+
+void*
+kaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return (void*)(pa + KZERO);
+ panic("kaddr: pa=%#p pc=%#p", pa, getcallerpc(&pa));
+ return nil;
+}
+
+static void*
+kmapaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return (void*)(pa + KZERO);
+ if(pa < (VDRAM - KZERO) || pa >= (VDRAM - KZERO) + (KMAPEND - KMAP))
+ panic("kmapaddr: pa=%#p pc=%#p", pa, getcallerpc(&pa));
+ return (void*)(pa + KMAP - (VDRAM - KZERO));
+}
+
+KMap*
+kmap(Page *p)
+{
+ return kmapaddr(p->pa);
+}
+
+void
+kunmap(KMap*)
+{
+}
+
+void
+kmapinval(void)
+{
+}
+
+#define INITMAP (ROUND((uintptr)end + BY2PG, PGLSZ(1))-KZERO)
+
+static void*
+rampage(void)
+{
+ uintptr pa;
+
+ if(conf.npage)
+ return mallocalign(BY2PG, BY2PG, 0, 0);
+
+ pa = conf.mem[0].base;
+ assert((pa % BY2PG) == 0);
+ assert(pa < INITMAP);
+ conf.mem[0].base += BY2PG;
+ return KADDR(pa);
+}
+
+static void
+l1map(uintptr va, uintptr pa, uintptr pe, uintptr attr)
+{
+ uintptr *l1, *l0;
+
+ assert(pa < pe);
+
+ va &= -BY2PG;
+ pa &= -BY2PG;
+ pe = PGROUND(pe);
+
+ attr |= PTEKERNEL | PTEAF;
+
+ l1 = (uintptr*)L1;
+
+ while(pa < pe){
+ if(l1[PTL1X(va, 1)] == 0 && (pe-pa) >= PGLSZ(1) && ((va|pa) & PGLSZ(1)-1) == 0){
+ l1[PTL1X(va, 1)] = PTEVALID | PTEBLOCK | pa | attr;
+ va += PGLSZ(1);
+ pa += PGLSZ(1);
+ continue;
+ }
+ if(l1[PTL1X(va, 1)] & PTEVALID) {
+ assert((l1[PTL1X(va, 1)] & PTETABLE) == PTETABLE);
+ l0 = KADDR(l1[PTL1X(va, 1)] & -PGLSZ(0));
+ } else {
+ l0 = rampage();
+ memset(l0, 0, BY2PG);
+ l1[PTL1X(va, 1)] = PTEVALID | PTETABLE | PADDR(l0);
+ }
+ assert(l0[PTLX(va, 0)] == 0);
+ l0[PTLX(va, 0)] = PTEVALID | PTEPAGE | pa | attr;
+ va += BY2PG;
+ pa += BY2PG;
+ }
+}
+
+static void
+kmapram(uintptr base, uintptr limit)
+{
+ if(base < (uintptr)-KZERO && limit > (uintptr)-KZERO){
+ kmapram(base, (uintptr)-KZERO);
+ kmapram((uintptr)-KZERO, limit);
+ return;
+ }
+ if(base < INITMAP)
+ base = INITMAP;
+ if(base >= limit || limit <= INITMAP)
+ return;
+
+ l1map((uintptr)kmapaddr(base), base, limit,
+ PTEWRITE | PTEPXN | PTEUXN | PTESH(SHARE_INNER));
+}
+
+void
+meminit(void)
+{
+ uintptr va, pa;
+
+ /*
+ * now we know the real memory regions, unmap
+ * everything above INITMAP and map again with
+ * the proper sizes.
+ */
+ coherence();
+ for(va = INITMAP+KZERO; va != 0; va += PGLSZ(1)){
+ pa = va-KZERO;
+ ((uintptr*)L1)[PTL1X(pa, 1)] = 0;
+ ((uintptr*)L1)[PTL1X(va, 1)] = 0;
+ }
+ flushtlb();
+
+ /* DDR Memory (All modules) */
+ conf.mem[0].base = PGROUND((uintptr)end - KZERO);
+
+ /* exclude uncached dram for ucalloc() */
+ conf.mem[0].limit = UCRAMBASE;
+ conf.mem[1].base = UCRAMBASE+UCRAMSIZE;
+
+ conf.mem[1].limit = 0x100000000ULL;
+
+ /* DDR Memory (Quad-A53 only) */
+ conf.mem[2].base = 0x100000000ULL;
+ conf.mem[2].limit = 0x140000000ULL;
+
+ kmapram(conf.mem[0].base, conf.mem[0].limit);
+ kmapram(conf.mem[1].base, conf.mem[1].limit);
+ kmapram(conf.mem[2].base, conf.mem[2].limit);
+
+ conf.mem[0].npage = (conf.mem[0].limit - conf.mem[0].base)/BY2PG;
+ conf.mem[1].npage = (conf.mem[1].limit - conf.mem[1].base)/BY2PG;
+ conf.mem[2].npage = (conf.mem[2].limit - conf.mem[2].base)/BY2PG;
+}
+
+uintptr
+mmukmap(uintptr va, uintptr pa, usize size)
+{
+ uintptr attr, off;
+
+ if(va == 0)
+ return 0;
+
+ off = pa & BY2PG-1;
+
+ attr = va & PTEMA(7);
+ attr |= PTEWRITE | PTEUXN | PTEPXN | PTESH(SHARE_OUTER);
+
+ va &= -BY2PG;
+ pa &= -BY2PG;
+
+ l1map(va, pa, pa + off + size, attr);
+ flushtlb();
+
+ return va + off;
+}
+
+void*
+vmap(uvlong pa, vlong size)
+{
+ static uintptr base = VMAP;
+ uvlong pe = pa + size;
+ uintptr va;
+
+ va = base;
+ base += PGROUND(pe) - (pa & -BY2PG);
+
+ return (void*)mmukmap(va | PTEDEVICE, pa, size);
+}
+
+void
+vunmap(void *, vlong)
+{
+}
+
+static uintptr*
+mmuwalk(uintptr va, int level)
+{
+ uintptr *table, pte;
+ Page *pg;
+ int i, x;
+
+ x = PTLX(va, PTLEVELS-1);
+ table = m->mmutop;
+ for(i = PTLEVELS-2; i >= level; i--){
+ pte = table[x];
+ if(pte & PTEVALID) {
+ if(pte & (0xFFFFULL<<48))
+ iprint("strange pte %#p va %#p\n", pte, va);
+ pte &= ~(0xFFFFULL<<48 | BY2PG-1);
+ } else {
+ pg = up->mmufree;
+ if(pg == nil)
+ return nil;
+ up->mmufree = pg->next;
+ pg->va = va & -PGLSZ(i+1);
+ if((pg->next = up->mmuhead[i+1]) == nil)
+ up->mmutail[i+1] = pg;
+ up->mmuhead[i+1] = pg;
+ pte = pg->pa;
+ memset(kmapaddr(pte), 0, BY2PG);
+ coherence();
+ table[x] = pte | PTEVALID | PTETABLE;
+ }
+ table = kmapaddr(pte);
+ x = PTLX(va, (uintptr)i);
+ }
+ return &table[x];
+}
+
+static Proc *asidlist[256];
+
+static int
+allocasid(Proc *p)
+{
+ static Lock lk;
+ Proc *x;
+ int a;
+
+ lock(&lk);
+ a = p->asid;
+ if(a < 0)
+ a = -a;
+ if(a == 0)
+ a = p->pid;
+ for(;; a++){
+ a %= nelem(asidlist);
+ if(a == 0)
+ continue; // reserved
+ x = asidlist[a];
+ if(x == p || x == nil || (x->asid < 0 && x->mach == nil))
+ break;
+ }
+ p->asid = a;
+ asidlist[a] = p;
+ unlock(&lk);
+
+ return x != p;
+}
+
+static void
+freeasid(Proc *p)
+{
+ int a;
+
+ a = p->asid;
+ if(a < 0)
+ a = -a;
+ if(a > 0 && asidlist[a] == p)
+ asidlist[a] = nil;
+ p->asid = 0;
+}
+
+void
+putasid(Proc *p)
+{
+ /*
+ * Prevent the following scenario:
+ * pX sleeps on cpuA, leaving its page tables in mmutop
+ * pX wakes up on cpuB, and exits, freeing its page tables
+ * pY on cpuB allocates a freed page table page and overwrites with data
+ * cpuA takes an interrupt, and is now running with bad page tables
+ * In theory this shouldn't hurt because only user address space tables
+ * are affected, and mmuswitch will clear mmutop before a user process is
+ * dispatched. But empirically it correlates with weird problems, eg
+ * resetting of the core clock at 0x4000001C which confuses local timers.
+ */
+ if(conf.nmach > 1)
+ mmuswitch(nil);
+
+ if(p->asid > 0)
+ p->asid = -p->asid;
+}
+
+void
+putmmu(uintptr va, uintptr pa, Page *pg)
+{
+ uintptr *pte, old;
+ int s;
+
+ s = splhi();
+ while((pte = mmuwalk(va, 0)) == nil){
+ spllo();
+ up->mmufree = newpage(0, nil, 0);
+ splhi();
+ }
+ old = *pte;
+ *pte = 0;
+ if((old & PTEVALID) != 0)
+ flushasidvall((uvlong)up->asid<<48 | va>>12);
+ else
+ flushasidva((uvlong)up->asid<<48 | va>>12);
+ *pte = pa | PTEPAGE | PTEUSER | PTEPXN | PTENG | PTEAF |
+ (((pa & PTEMA(7)) == PTECACHED)? PTESH(SHARE_INNER): PTESH(SHARE_OUTER));
+ if(needtxtflush(pg)){
+ cachedwbinvse(kmap(pg), BY2PG);
+ cacheiinvse((void*)va, BY2PG);
+ donetxtflush(pg);
+ }
+ splx(s);
+}
+
+static void
+mmufree(Proc *p)
+{
+ int i;
+
+ freeasid(p);
+
+ for(i=1; i<PTLEVELS; i++){
+ if(p->mmuhead[i] == nil)
+ break;
+ p->mmutail[i]->next = p->mmufree;
+ p->mmufree = p->mmuhead[i];
+ p->mmuhead[i] = p->mmutail[i] = nil;
+ }
+}
+
+void
+mmuswitch(Proc *p)
+{
+ uintptr va;
+ Page *t;
+
+ for(va = UZERO; va < USTKTOP; va += PGLSZ(PTLEVELS-1))
+ m->mmutop[PTLX(va, PTLEVELS-1)] = 0;
+
+ if(p == nil){
+ setttbr(PADDR(m->mmutop));
+ return;
+ }
+
+ if(p->newtlb){
+ mmufree(p);
+ p->newtlb = 0;
+ }
+
+ if(allocasid(p))
+ flushasid((uvlong)p->asid<<48);
+
+ setttbr((uvlong)p->asid<<48 | PADDR(m->mmutop));
+
+ for(t = p->mmuhead[PTLEVELS-1]; t != nil; t = t->next){
+ va = t->va;
+ m->mmutop[PTLX(va, PTLEVELS-1)] = t->pa | PTEVALID | PTETABLE;
+ }
+}
+
+void
+mmurelease(Proc *p)
+{
+ mmuswitch(nil);
+ mmufree(p);
+ freepages(p->mmufree, nil, 0);
+ p->mmufree = nil;
+}
+
+void
+flushmmu(void)
+{
+ int x;
+
+ x = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(x);
+}
+
+void
+checkmmu(uintptr, uintptr)
+{
+}
+
+static void*
+ucramalloc(usize size, uintptr align, uint attr)
+{
+ static uintptr top = UCRAMBASE + UCRAMSIZE;
+ static Lock lk;
+ uintptr va, pg;
+
+ lock(&lk);
+ top -= size;
+ size += top & align-1;
+ top &= -align;
+ if(top < UCRAMBASE)
+ 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*)va;
+}
+
+void*
+ucalloc(usize size)
+{
+ return ucramalloc(size, 8, PTEUNCACHED);
+}
+
+void*
+fbmemalloc(usize size)
+{
+ return ucramalloc(PGROUND(size), BY2PG, PTEWT);
+}
diff --git a/sys/src/9/virt/rebootcode.s b/sys/src/9/virt/rebootcode.s
new file mode 100644
index 000000000..4406350f2
--- /dev/null
+++ b/sys/src/9/virt/rebootcode.s
@@ -0,0 +1,48 @@
+#include "mem.h"
+#include "sysreg.h"
+
+#undef SYSREG
+#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
+
+TEXT _start(SB), 1, $-4
+ MOV $setSB(SB), R28
+
+ MOV R0, R27
+
+ MOV code+8(FP), R1
+ MOVWU size+16(FP), R2
+ BIC $3, R2
+ ADD R1, R2, R3
+
+_copy:
+ MOVW (R1)4!, R4
+ MOVW R4, (R0)4!
+ CMP R1, R3
+ BNE _copy
+
+ BL cachedwbinv(SB)
+ BL l2cacheuwbinv(SB)
+
+ ISB $SY
+ MRS SCTLR_EL1, R0
+ BIC $(1<<0 | 1<<2 | 1<<12), R0
+ ISB $SY
+ MSR R0, SCTLR_EL1
+ ISB $SY
+
+ DSB $NSHST
+ TLBI R0, 0,8,7,0 /* VMALLE1 */
+ DSB $NSH
+ ISB $SY
+
+ BL cachedwbinv(SB)
+ BL cacheiinv(SB)
+
+ MOVWU $0, R0
+ MOVWU $0, R1
+ MOVWU $0, R2
+ MOVWU $0, R3
+
+ MOV R27, LR
+
+ RETURN
diff --git a/sys/src/9/virt/sysreg.c b/sys/src/9/virt/sysreg.c
new file mode 100644
index 000000000..1d892504e
--- /dev/null
+++ b/sys/src/9/virt/sysreg.c
@@ -0,0 +1,58 @@
+/*
+ * ARMv8 system registers
+ * mainly to cope with arm hard-wiring register numbers into instructions.
+ *
+ * these routines must be callable from KZERO.
+ *
+ * on a multiprocessor, process switching to another cpu is assumed
+ * to be inhibited by the caller as these registers are local to the cpu.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+static void*
+mkinstr(ulong wd)
+{
+ static ulong ib[256], *ep[MAXMACH+1];
+ static Lock lk;
+ ulong *ip, *ie;
+
+ ie = ep[m->machno];
+ for(ip = ib; ip < ie; ip += 2)
+ if(*ip == wd)
+ return ip;
+
+ ilock(&lk);
+ ie = ep[MAXMACH];
+ for(; ip < ie; ip += 2)
+ if(*ip == wd)
+ goto Found;
+ if(ip >= &ib[nelem(ib)])
+ panic("mkinstr: out of instrucuction buffer");
+ ip[0] = wd;
+ ip[1] = 0xd65f03c0; // RETURN
+ ep[MAXMACH] = ie = ip + 2;
+ cachedwbinvse(ip, 2*sizeof(*ip));
+Found:
+ iunlock(&lk);
+ cacheiinv();
+ ep[m->machno] = ie;
+ return ip;
+}
+
+uvlong
+sysrd(ulong spr)
+{
+ uvlong (*fp)(void) = mkinstr(0xd5380000UL | spr);
+ return fp();
+}
+
+void
+syswr(ulong spr, uvlong val)
+{
+ void (*fp)(uvlong) = mkinstr(0xd5180000UL | spr);
+ fp(val);
+}
diff --git a/sys/src/9/virt/sysreg.h b/sys/src/9/virt/sysreg.h
new file mode 100644
index 000000000..b9bbc7142
--- /dev/null
+++ b/sys/src/9/virt/sysreg.h
@@ -0,0 +1,90 @@
+#define MIDR_EL1 SYSREG(3,0,0,0,0)
+#define MPIDR_EL1 SYSREG(3,0,0,0,5)
+#define ID_AA64AFR0_EL1 SYSREG(3,0,0,5,4)
+#define ID_AA64AFR1_EL1 SYSREG(3,0,0,5,5)
+#define ID_AA64DFR0_EL1 SYSREG(3,0,0,5,0)
+#define ID_AA64DFR1_EL1 SYSREG(3,0,0,5,1)
+#define ID_AA64ISAR0_EL1 SYSREG(3,0,0,6,0)
+#define ID_AA64ISAR1_EL1 SYSREG(3,0,0,6,1)
+#define ID_AA64MMFR0_EL1 SYSREG(3,0,0,7,0)
+#define ID_AA64MMFR1_EL1 SYSREG(3,0,0,7,1)
+#define ID_AA64PFR0_EL1 SYSREG(3,0,0,4,0)
+#define ID_AA64PFR1_EL1 SYSREG(3,0,0,4,1)
+#define SCTLR_EL1 SYSREG(3,0,1,0,0)
+#define CPACR_EL1 SYSREG(3,0,1,0,2)
+#define MAIR_EL1 SYSREG(3,0,10,2,0)
+#define TCR_EL1 SYSREG(3,0,2,0,2)
+#define TTBR0_EL1 SYSREG(3,0,2,0,0)
+#define TTBR1_EL1 SYSREG(3,0,2,0,1)
+#define ESR_EL1 SYSREG(3,0,5,2,0)
+#define FAR_EL1 SYSREG(3,0,6,0,0)
+#define VBAR_EL1 SYSREG(3,0,12,0,0)
+#define VTTBR_EL2 SYSREG(3,4,2,1,0)
+#define SP_EL0 SYSREG(3,0,4,1,0)
+#define SP_EL1 SYSREG(3,4,4,1,0)
+#define SP_EL2 SYSREG(3,6,4,1,0)
+#define SCTLR_EL2 SYSREG(3,4,1,0,0)
+#define HCR_EL2 SYSREG(3,4,1,1,0)
+#define MDCR_EL2 SYSREG(3,4,1,1,1)
+#define PMCR_EL0 SYSREG(3,3,9,12,0)
+#define PMCNTENSET SYSREG(3,3,9,12,1)
+#define PMCCNTR_EL0 SYSREG(3,3,9,13,0)
+#define PMUSERENR_EL0 SYSREG(3,3,9,14,0)
+
+#define CNTPCT_EL0 SYSREG(3,3,14,0,1)
+#define CNTVCT_EL0 SYSREG(3,3,14,0,2)
+#define CNTKCTL_EL1 SYSREG(3,0,14,1,0)
+#define CNTFRQ_EL0 SYSREG(3,3,14,0,0)
+#define CNTP_TVAL_EL0 SYSREG(3,3,14,2,0)
+#define CNTP_CTL_EL0 SYSREG(3,3,14,2,1)
+#define CNTP_CVAL_EL0 SYSREG(3,3,14,2,2)
+#define CNTVOFF_EL2 SYSREG(3,4,14,0,3)
+
+#define TPIDR_EL0 SYSREG(3,3,13,0,2)
+#define TPIDR_EL1 SYSREG(3,0,13,0,4)
+
+#define CCSIDR_EL1 SYSREG(3,1,0,0,0)
+#define CSSELR_EL1 SYSREG(3,2,0,0,0)
+
+#define ACTLR_EL2 SYSREG(3,4,1,0,1)
+#define CPUACTLR_EL1 SYSREG(3,1,15,2,0)
+#define CPUECTLR_EL1 SYSREG(3,1,15,2,1)
+#define CBAR_EL1 SYSREG(3,1,15,3,0)
+
+#define ICC_AP0R_EL1(m) SYSREG(3,0,12,8,4|(m))
+#define ICC_AP1R_EL1(m) SYSREG(3,0,12,9,0|(m))
+#define ICC_ASGI1R_EL1 SYSREG(3,0,12,11,6)
+#define ICC_BPR0_EL1 SYSREG(3,0,12,8,3)
+#define ICC_BPR1_EL1 SYSREG(3,0,12,12,3)
+#define ICC_CTLR_EL1 SYSREG(3,0,12,12,4)
+#define ICC_DIR_EL1 SYSREG(3,0,12,11,1)
+#define ICC_EOIR0_EL1 SYSREG(3,0,12,8,1)
+#define ICC_EOIR1_EL1 SYSREG(3,0,12,12,1)
+#define ICC_HPPIR0_EL1 SYSREG(3,0,12,8,2)
+#define ICC_HPPIR1_EL1 SYSREG(3,0,12,12,2)
+#define ICC_IAR0_EL1 SYSREG(3,0,12,8,0)
+#define ICC_IAR1_EL1 SYSREG(3,0,12,12,0)
+#define ICC_IGRPEN0_EL1 SYSREG(3,0,12,12,6)
+#define ICC_IGRPEN1_EL1 SYSREG(3,0,12,12,7)
+#define ICC_NMIAR1_EL1 SYSREG(3,0,12,9,5)
+#define ICC_PMR_EL1 SYSREG(3,0,4,6,0)
+#define ICC_RPR_EL1 SYSREG(3,0,12,11,3)
+#define ICC_SGI0R_EL1 SYSREG(3,0,12,11,7)
+#define ICC_SGI1R_EL1 SYSREG(3,0,12,11,5)
+#define ICC_SRE_EL1 SYSREG(3,0,12,12,5)
+
+/* l.s redefines this for the assembler */
+#define SYSREG(op0,op1,Cn,Cm,op2) ((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5)
+
+#define OSHLD (0<<2 | 1)
+#define OSHST (0<<2 | 2)
+#define OSH (0<<2 | 3)
+#define NSHLD (1<<2 | 1)
+#define NSHST (1<<2 | 2)
+#define NSH (1<<2 | 3)
+#define ISHLD (2<<2 | 1)
+#define ISHST (2<<2 | 2)
+#define ISH (2<<2 | 3)
+#define LD (3<<2 | 1)
+#define ST (3<<2 | 2)
+#define SY (3<<2 | 3)
diff --git a/sys/src/9/virt/trap.c b/sys/src/9/virt/trap.c
new file mode 100644
index 000000000..5e5486c45
--- /dev/null
+++ b/sys/src/9/virt/trap.c
@@ -0,0 +1,711 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "../port/systab.h"
+
+#include <tos.h>
+#include "ureg.h"
+#include "sysreg.h"
+
+int (*buserror)(Ureg*);
+
+/* SPSR bits user can modify */
+#define USPSRMASK (0xFULL<<28)
+
+static void
+setupvector(u32int *v, void (*t)(void), void (*f)(void))
+{
+ int i;
+
+ for(i = 0; i < 0x80/4; i++){
+ v[i] = ((u32int*)t)[i];
+ if(v[i] == 0x14000000){
+ v[i] |= ((u32int*)f - &v[i]) & 0x3ffffff;
+ return;
+ }
+ }
+ panic("bug in vector code");
+}
+
+extern volatile char *easyuart;
+
+void
+trapinit(void)
+{
+ extern void vsys(void);
+ extern void vtrap(void);
+ extern void virq(void);
+ extern void vfiq(void);
+ extern void vserr(void);
+
+ extern void vsys0(void);
+ extern void vtrap0(void);
+ extern void vtrap1(void);
+
+ static u32int *v;
+
+ *easyuart = 'A';
+
+ intrcpushutdown();
+
+ *easyuart = 'B';
+
+ if(v == nil){
+ *easyuart = 'C';
+ /* disable everything */
+ intrsoff();
+ *easyuart = 'D';
+
+ v = mallocalign(0x80*4*4, 1<<11, 0, 0);
+ *easyuart = 'E';
+ if(v == nil)
+ panic("no memory for vector table");
+ *easyuart = 'F';
+
+ setupvector(&v[0x000/4], vtrap, vtrap0);
+ setupvector(&v[0x080/4], virq, vtrap0);
+ setupvector(&v[0x100/4], vfiq, vtrap0);
+ setupvector(&v[0x180/4], vserr, vtrap0);
+ *easyuart = 'G';
+
+ setupvector(&v[0x200/4], vtrap, vtrap1);
+ setupvector(&v[0x280/4], virq, vtrap1);
+ setupvector(&v[0x300/4], vfiq, vtrap1);
+ setupvector(&v[0x380/4], vserr, vtrap1);
+ *easyuart = 'H';
+
+ setupvector(&v[0x400/4], vsys, vsys0);
+ setupvector(&v[0x480/4], virq, vtrap0);
+ setupvector(&v[0x500/4], vfiq, vtrap0);
+ setupvector(&v[0x580/4], vserr, vtrap0);
+ *easyuart = 'I';
+
+ setupvector(&v[0x600/4], vtrap, vtrap0);
+ setupvector(&v[0x680/4], virq, vtrap0);
+ setupvector(&v[0x700/4], vfiq, vtrap0);
+ setupvector(&v[0x780/4], vserr, vtrap0);
+ *easyuart = 'J';
+
+ cacheduwbse(v, 0x80*4*4);
+ *easyuart = 'K';
+ }
+ *easyuart = 'X';
+ cacheiinvse(v, 0x80*4*4);
+ *easyuart = 'Y';
+ syswr(VBAR_EL1, (uintptr)v);
+ *easyuart = 'Z';
+ splx(0x3<<6); // unmask serr and debug
+ *easyuart = 'Z';
+}
+
+static char *traps[64] = {
+ [0x00] "sys: trap: unknown",
+ [0x01] "sys: trap: WFI or WFE instruction execution",
+ [0x0E] "sys: trap: illegal execution state",
+ [0x18] "sys: trap: illegal MSR/MRS access",
+ [0x22] "sys: trap: misaligned pc",
+ [0x26] "sys: trap: stack pointer misaligned",
+ [0x30] "sys: trap: breakpoint",
+ [0x32] "sys: trap: software step",
+ [0x34] "sys: trap: watchpoint",
+ [0x3C] "sys: trap: BRK instruction",
+};
+
+void
+trap(Ureg *ureg)
+{
+ u32int type, intr;
+ int user;
+
+ intr = ureg->type >> 32;
+ if(intr == 2){
+ fiq(ureg);
+ return;
+ }
+ splflo();
+ user = kenter(ureg);
+ type = (u32int)ureg->type >> 26;
+ switch(type){
+ case 0x20: // instruction abort from lower level
+ case 0x21: // instruction abort from same level
+ case 0x24: // data abort from lower level
+ case 0x25: // data abort from same level
+ faultarm64(ureg);
+ break;
+ case 0x07: // SIMD/FP
+ case 0x2C: // FPU exception (A64 only)
+ mathtrap(ureg);
+ break;
+ case 0x00: // unknown
+ if(intr == 1){
+ if(irq(ureg) && up != nil && up->delaysched)
+ sched();
+ break;
+ }
+ if(intr == 3){
+ case 0x2F: // SError interrupt
+ if(buserror != nil && (*buserror)(ureg))
+ break;
+ dumpregs(ureg);
+ panic("SError interrupt");
+ break;
+ }
+ /* wet floor */
+ case 0x01: // WFI or WFE instruction execution
+ case 0x03: // MCR or MRC access to CP15 (A32 only)
+ case 0x04: // MCRR or MRC access to CP15 (A32 only)
+ case 0x05: // MCR or MRC access to CP14 (A32 only)
+ case 0x06: // LDC or STD access to CP14 (A32 only)
+ case 0x08: // MCR or MRC to CP10 (A32 only)
+ case 0x0C: // MRC access to CP14 (A32 only)
+ case 0x0E: // Illegal Execution State
+ case 0x11: // SVC instruction execution (A32 only)
+ case 0x12: // HVC instruction execution (A32 only)
+ case 0x13: // SMC instruction execution (A32 only)
+ case 0x15: // SVC instruction execution (A64 only)
+ case 0x16: // HVC instruction execution (A64 only)
+ case 0x17: // SMC instruction execution (A64 only)
+ case 0x18: // MSR/MRS (A64)
+ case 0x22: // misaligned pc
+ case 0x26: // stack pointer misaligned
+ case 0x28: // FPU exception (A32 only)
+ case 0x30: // breakpoint from lower level
+ case 0x31: // breakpoint from same level
+ case 0x32: // software step from lower level
+ case 0x33: // software step from same level
+ case 0x34: // watchpoint execution from lower level
+ case 0x35: // watchpoint exception from same level
+ case 0x38: // breapoint (A32 only)
+ case 0x3A: // vector catch exception (A32 only)
+ case 0x3C: // BRK instruction (A64 only)
+ default:
+ if(!userureg(ureg)){
+ dumpregs(ureg);
+ panic("unhandled trap");
+ }
+ if(traps[type] == nil) type = 0; // unknown
+ postnote(up, 1, traps[type], NDebug);
+ break;
+ }
+ splhi();
+ if(user){
+ if(up->procctl || up->nnote)
+ notify(ureg);
+ kexit(ureg);
+ }
+}
+
+void
+syscall(Ureg *ureg)
+{
+ vlong startns, stopns;
+ uintptr sp, ret;
+ ulong scallnr;
+ int i, s;
+ char *e;
+
+ if(!kenter(ureg))
+ panic("syscall from kernel");
+
+ m->syscall++;
+ up->insyscall = 1;
+ up->pc = ureg->pc;
+
+ sp = ureg->sp;
+ up->scallnr = scallnr = ureg->r0;
+
+ spllo();
+
+ up->nerrlab = 0;
+ startns = 0;
+ ret = -1;
+ if(!waserror()){
+ if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
+ validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+ evenaddr(sp);
+ }
+ up->s = *((Sargs*) (sp + BY2WD));
+
+ if(up->procctl == Proc_tracesyscall){
+ syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl();
+ splx(s);
+ startns = todget(nil);
+ }
+
+ if(scallnr >= nsyscall || systab[scallnr] == nil){
+ pprint("bad sys call number %lud pc %#p", scallnr, ureg->pc);
+ postnote(up, 1, "sys: bad sys call", NDebug);
+ error(Ebadarg);
+ }
+ up->psstate = sysctab[scallnr];
+ ret = systab[scallnr]((va_list)up->s.args);
+ poperror();
+ }else{
+ e = up->syserrstr;
+ up->syserrstr = up->errstr;
+ up->errstr = e;
+ }
+ if(up->nerrlab){
+ print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
+ for(i = 0; i < NERR; i++)
+ print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc);
+ panic("error stack");
+ }
+ ureg->r0 = ret;
+ if(up->procctl == Proc_tracesyscall){
+ stopns = todget(nil);
+ sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl();
+ splx(s);
+ }
+
+ up->insyscall = 0;
+ up->psstate = 0;
+ if(scallnr == NOTED){
+ noted(ureg, *((ulong*) up->s.args));
+ /*
+ * normally, syscall() returns to forkret()
+ * not restoring general registers when going
+ * to userspace. to completely restore the
+ * interrupted context, we have to return thru
+ * noteret(). we override return pc to jump to
+ * to it when returning form syscall()
+ */
+ returnto(noteret);
+ }
+
+ if(scallnr != RFORK && (up->procctl || up->nnote)){
+ splhi();
+ notify(ureg);
+ }
+ if(up->delaysched)
+ sched();
+ kexit(ureg);
+}
+
+int
+notify(Ureg *ureg)
+{
+ uintptr s, sp;
+ char *msg;
+
+ if(up->procctl)
+ procctl();
+ if(up->nnote == 0)
+ return 0;
+ if(up->fpstate == FPactive){
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPillegal;
+
+ s = spllo();
+ qlock(&up->debug);
+ msg = popnote(ureg);
+ if(msg == nil){
+ qunlock(&up->debug);
+ splhi();
+ return 0;
+ }
+
+ sp = ureg->sp;
+ sp -= 256; /* debugging: preserve context causing problem */
+ sp -= sizeof(Ureg);
+ sp = STACKALIGN(sp);
+
+ if(!okaddr((uintptr)up->notify, 1, 0)
+ || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+ || ((uintptr) up->notify & 3) != 0
+ || (sp & 7) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: bad address in notify: handler=%#p sp=%#p\n",
+ up->notify, sp);
+ pexit("Suicide", 0);
+ }
+
+ memmove((Ureg*)sp, ureg, sizeof(Ureg));
+ *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
+ up->ureg = (void*)sp;
+ sp -= BY2WD+ERRMAX;
+ memmove((char*)sp, msg, ERRMAX);
+ sp -= 3*BY2WD;
+ *(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
+ *(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
+ ureg->r0 = (uintptr) up->ureg;
+ ureg->sp = sp;
+ ureg->pc = (uintptr) up->notify;
+ ureg->link = 0;
+ qunlock(&up->debug);
+ splx(s);
+ return 1;
+}
+
+void
+noted(Ureg *ureg, ulong arg0)
+{
+ Ureg *nureg;
+ uintptr oureg, sp;
+
+ qlock(&up->debug);
+ if(arg0 != NRSTR && !up->notified){
+ qunlock(&up->debug);
+ pprint("call to noted() when not notified\n");
+ pexit("Suicide", 0);
+ }
+ up->notified = 0;
+
+ nureg = up->ureg;
+ up->fpstate &= ~FPillegal;
+
+ oureg = (uintptr) nureg;
+ if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 7) != 0){
+ qunlock(&up->debug);
+ pprint("bad ureg in noted or call to noted when not notified\n");
+ pexit("Suicide", 0);
+ }
+
+ nureg->psr = (nureg->psr & USPSRMASK) | (ureg->psr & ~USPSRMASK);
+ memmove(ureg, nureg, sizeof(Ureg));
+
+ switch(arg0){
+ case NCONT: case NRSTR:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 7) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ up->ureg = (Ureg *) (*(uintptr*) (oureg - BY2WD));
+ qunlock(&up->debug);
+ break;
+
+ case NSAVE:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 7) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ qunlock(&up->debug);
+ sp = oureg - 4 * BY2WD - ERRMAX;
+ splhi();
+ ureg->sp = sp;
+ ureg->r0 = (uintptr) oureg;
+ ((uintptr *) sp)[1] = oureg;
+ ((uintptr *) sp)[0] = 0;
+ break;
+
+ default:
+ up->lastnote->flag = NDebug;
+
+ case NDFLT:
+ qunlock(&up->debug);
+ if(up->lastnote->flag == NDebug)
+ pprint("suicide: %s\n", up->lastnote->msg);
+ pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
+ }
+}
+
+void
+faultarm64(Ureg *ureg)
+{
+ extern void checkpages(void);
+ char buf[ERRMAX];
+ int read, insyscall;
+ uintptr addr;
+
+ insyscall = up->insyscall;
+ up->insyscall = 1;
+
+ if(!userureg(ureg)){
+ extern void _peekinst(void);
+
+ if(ureg->pc == (uintptr)_peekinst){
+ ureg->pc = ureg->link;
+ goto out;
+ }
+
+ if(waserror()){
+ if(up->nerrlab == 0){
+ pprint("suicide: sys: %s\n", up->errstr);
+ pexit(up->errstr, 1);
+ }
+ up->insyscall = insyscall;
+ nexterror();
+ }
+ }
+
+ addr = getfar();
+ read = (ureg->type & (1<<6)) == 0;
+
+ switch((u32int)ureg->type & 0x3F){
+ case 4: case 5: case 6: case 7: // Tanslation fault.
+ case 8: case 9: case 10: case 11: // Access flag fault.
+ case 12: case 13: case 14: case 15: // Permission fault.
+ case 48: // tlb conflict fault.
+ if(fault(addr, ureg->pc, read) == 0)
+ break;
+
+ /* wet floor */
+ case 0: case 1: case 2: case 3: // Address size fault.
+ case 16: // synchronous external abort.
+ case 24: // synchronous parity error on a memory access.
+ case 20: case 21: case 22: case 23: // synchronous external abort on a table walk.
+ case 28: case 29: case 30: case 31: // synchronous parity error on table walk.
+ case 33: // alignment fault.
+ case 52: // implementation defined, lockdown abort.
+ case 53: // implementation defined, unsuppoted exclusive.
+ case 61: // first level domain fault
+ case 62: // second level domain fault
+ default:
+ if(!userureg(ureg)){
+ dumpregs(ureg);
+ panic("fault: %s addr=%#p", read ? "read" : "write", addr);
+ }
+ checkpages();
+ sprint(buf, "sys: trap: fault %s addr=%#p", read ? "read" : "write", addr);
+ postnote(up, 1, buf, NDebug);
+ }
+
+ if(!userureg(ureg))
+ poperror();
+
+out:
+ up->insyscall = insyscall;
+}
+
+int
+userureg(Ureg* ureg)
+{
+ return (ureg->psr & 15) == 0;
+}
+
+uintptr
+userpc(void)
+{
+ Ureg *ur = up->dbgreg;
+ return ur->pc;
+}
+
+uintptr
+dbgpc(Proc *)
+{
+ Ureg *ur = up->dbgreg;
+ if(ur == nil)
+ return 0;
+ return ur->pc;
+}
+
+void
+procfork(Proc *p)
+{
+ int s;
+
+ s = splhi();
+ switch(up->fpstate & ~FPillegal){
+ case FPactive:
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ case FPinactive:
+ memmove(p->fpsave, up->fpsave, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ splx(s);
+
+ p->tpidr = up->tpidr;
+}
+
+void
+procsetup(Proc *p)
+{
+ p->fpstate = FPinit;
+ fpoff();
+
+ p->tpidr = 0;
+ syswr(TPIDR_EL0, p->tpidr);
+}
+
+void
+procsave(Proc *p)
+{
+ if(p->fpstate == FPactive){
+ if(p->state == Moribund)
+ fpclear();
+ else
+ fpsave(p->fpsave);
+ p->fpstate = FPinactive;
+ }
+
+ if(p->kp == 0)
+ p->tpidr = sysrd(TPIDR_EL0);
+
+ putasid(p); // release asid
+}
+
+void
+procrestore(Proc *p)
+{
+ if(p->kp == 0)
+ syswr(TPIDR_EL0, p->tpidr);
+}
+
+void
+kprocchild(Proc *p, void (*entry)(void))
+{
+ p->sched.pc = (uintptr) entry;
+ p->sched.sp = (uintptr) p - 16;
+ *(void**)p->sched.sp = kprocchild; /* fake */
+}
+
+void
+forkchild(Proc *p, Ureg *ureg)
+{
+ Ureg *cureg;
+
+ p->sched.pc = (uintptr) forkret;
+ p->sched.sp = (uintptr) p - TRAPFRAMESIZE;
+
+ cureg = (Ureg*) (p->sched.sp + 16);
+ memmove(cureg, ureg, sizeof(Ureg));
+ cureg->r0 = 0;
+}
+
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
+{
+ uintptr *sp;
+ Ureg *ureg;
+
+ sp = (uintptr*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ureg = up->dbgreg;
+ ureg->sp = (uintptr)sp;
+ ureg->pc = entry;
+ ureg->link = 0;
+ return USTKTOP-sizeof(Tos);
+}
+
+void
+evenaddr(uintptr addr)
+{
+ if(addr & 3){
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+}
+
+void
+callwithureg(void (*f) (Ureg *))
+{
+ Ureg u;
+
+ u.pc = getcallerpc(&f);
+ u.sp = (uintptr) &f;
+ f(&u);
+}
+
+void
+setkernur(Ureg *ureg, Proc *p)
+{
+ ureg->pc = p->sched.pc;
+ ureg->sp = p->sched.sp;
+ ureg->link = (uintptr)sched;
+}
+
+void
+setupwatchpts(Proc*, Watchpt*, int)
+{
+}
+
+void
+setregisters(Ureg* ureg, char* pureg, char* uva, int n)
+{
+ ulong v;
+
+ v = ureg->psr;
+ memmove(pureg, uva, n);
+ ureg->psr = (ureg->psr & USPSRMASK) | (v & ~USPSRMASK);
+}
+
+static void
+dumpstackwithureg(Ureg *ureg)
+{
+ uintptr v, estack, sp;
+ char *s;
+ int i;
+
+ if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
+ iprint("dumpstack disabled\n");
+ return;
+ }
+ iprint("ktrace /kernel/path %#p %#p %#p # pc, sp, link\n",
+ ureg->pc, ureg->sp, ureg->link);
+ delay(2000);
+
+ sp = ureg->sp;
+ if(sp < KZERO || (sp & 7) != 0)
+ sp = (uintptr)&ureg;
+
+ estack = (uintptr)m+MACHSIZE;
+ if(up != nil && sp <= (uintptr)up)
+ estack = (uintptr)up;
+
+ if(sp > estack){
+ if(up != nil)
+ iprint("&up %#p sp %#p\n", up, sp);
+ else
+ iprint("&m %#p sp %#p\n", m, sp);
+ return;
+ }
+
+ i = 0;
+ for(; sp < estack; sp += sizeof(uintptr)){
+ v = *(uintptr*)sp;
+ if(KTZERO < v && v < (uintptr)etext && (v & 3) == 0){
+ iprint("%#8.8lux=%#8.8lux ", (ulong)sp, (ulong)v);
+ i++;
+ }
+ if(i == 4){
+ i = 0;
+ iprint("\n");
+ }
+ }
+ if(i)
+ iprint("\n");
+}
+
+void
+dumpstack(void)
+{
+ callwithureg(dumpstackwithureg);
+}
+
+void
+dumpregs(Ureg *ureg)
+{
+ u64int *r;
+ int i, x;
+
+ x = splhi();
+ if(up != nil)
+ iprint("cpu%d: dumpregs ureg %#p process %lud: %s\n", m->machno, ureg,
+ up->pid, up->text);
+ else
+ iprint("cpu%d: dumpregs ureg %#p\n", m->machno, ureg);
+ r = &ureg->r0;
+ for(i = 0; i < 30; i += 3)
+ iprint("R%d %.16llux R%d %.16llux R%d %.16llux\n", i, r[i], i+1, r[i+1], i+2, r[i+2]);
+ iprint("PC %#p SP %#p LR %#p PSR %llux TYPE %llux\n",
+ ureg->pc, ureg->sp, ureg->link,
+ ureg->psr, ureg->type);
+ splx(x);
+}
diff --git a/sys/src/9/virt/uartpl011.c b/sys/src/9/virt/uartpl011.c
new file mode 100644
index 000000000..ff2765f10
--- /dev/null
+++ b/sys/src/9/virt/uartpl011.c
@@ -0,0 +1,400 @@
+/*
+ * bcm2835 PL011 uart
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ DR = 0x00>>2,
+ RSRECR = 0x04>>2,
+ FR = 0x18>>2,
+ TXFE = 1<<7,
+ RXFF = 1<<6,
+ TXFF = 1<<5,
+ RXFE = 1<<4,
+ BUSY = 1<<3,
+
+ ILPR = 0x20>>2,
+ IBRD = 0x24>>2,
+ FBRD = 0x28>>2,
+ LCRH = 0x2c>>2,
+ WLENM = 3<<5,
+ WLEN8 = 3<<5,
+ WLEN7 = 2<<5,
+ WLEN6 = 1<<5,
+ WLEN5 = 0<<5,
+ FEN = 1<<4, /* fifo enable */
+ STP2 = 1<<3, /* 2 stop bits */
+ EPS = 1<<2, /* even parity select */
+ PEN = 1<<1, /* parity enabled */
+ BRK = 1<<0, /* send break */
+
+ CR = 0x30>>2,
+ CTSEN = 1<<15,
+ RTSEN = 1<<14,
+ RTS = 1<<11,
+ RXE = 1<<9,
+ TXE = 1<<8,
+ LBE = 1<<7,
+ UARTEN = 1<<0,
+
+ IFLS = 0x34>>2,
+ IMSC = 0x38>>2,
+ TXIM = 1<<5,
+ RXIM = 1<<4,
+
+ RIS = 0x3c>>2,
+ MIS = 0x40>>2,
+ ICR = 0x44>>2,
+ DMACR = 0x48>>2,
+ ITCR = 0x80>>2,
+ ITIP = 0x84>>2,
+ ITOP = 0x88>>2,
+ TDR = 0x8c>>2,
+};
+
+extern PhysUart pl011physuart;
+
+static Uart pl011uart = {
+ //.regs = (u32int*)(VIRTIO+0x201000),
+ .regs = (u32int*)(VIRTIO+0x1000000),
+ .name = "uart0",
+ .freq = 250000000, // 24MHz?
+ .baud = 115200,
+ .phys = &pl011physuart,
+};
+
+static Uart*
+pnp(void)
+{
+ return &pl011uart;
+}
+
+static void
+interrupt(Ureg*, void *arg)
+{
+ Uart *uart = arg;
+ u32int *reg = (u32int*)uart->regs;
+
+ coherence();
+ while((reg[FR] & RXFE) == 0)
+ uartrecv(uart, reg[DR] & 0xFF);
+ if((reg[FR] & TXFF) == 0)
+ uartkick(uart);
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
+ coherence();
+}
+
+static void
+disable(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* disable interrupt */
+ reg[IMSC] = 0;
+ coherence();
+
+ /* clear interrupt */
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
+ coherence();
+
+ /* wait for last transmission to complete */
+ while((reg[FR] & BUSY) != 0)
+ delay(1);
+
+ /* disable uart */
+ reg[CR] = 0;
+ coherence();
+
+ /* flush rx fifo */
+ reg[LCRH] &= ~FEN;
+ coherence();
+}
+
+static void
+uartoff(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+ u32int im;
+
+ im = reg[IMSC];
+ disable(uart);
+ reg[IMSC] = im;
+}
+
+static void
+uarton(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* enable fifo */
+ reg[LCRH] |= FEN;
+ coherence();
+
+ /* enable uart */
+ reg[CR] = UARTEN | RXE | TXE;
+ coherence();
+}
+
+static void
+enable(Uart *uart, int ie)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ disable(uart);
+ if(ie){
+ intrenable(IRQuart1, interrupt, uart, BUSUNKNOWN, uart->name);
+ reg[IMSC] = TXIM|RXIM;
+ }
+ uarton(uart);
+}
+
+static void
+linectl(Uart *uart, u32int set, u32int clr)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->enabled)
+ uartoff(uart);
+
+ reg[LCRH] = set | (reg[LCRH] & ~clr);
+
+ if(uart->enabled)
+ uarton(uart);
+}
+
+static void
+kick(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->blocked)
+ return;
+ coherence();
+ while((reg[FR] & TXFF) == 0){
+ if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+ break;
+ reg[DR] = *(uart->op++);
+ }
+ coherence();
+}
+
+static void
+dobreak(Uart *uart, int ms)
+{
+ linectl(uart, BRK, 0);
+ delay(ms);
+ linectl(uart, 0, BRK);
+}
+
+static int
+baud(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->freq <= 0 || n <= 0)
+ return -1;
+
+ if(uart->enabled)
+ uartoff(uart);
+
+ reg[IBRD] = (uart->freq >> 4) / n;
+ reg[FBRD] = (uart->freq >> 4) % n;
+
+ if(uart->enabled)
+ uarton(uart);
+
+ uart->baud = n;
+ return 0;
+}
+
+static int
+bits(Uart *uart, int n)
+{
+ switch(n){
+ case 8:
+ linectl(uart, WLEN8, WLENM);
+ break;
+ case 7:
+ linectl(uart, WLEN7, WLENM);
+ break;
+ case 6:
+ linectl(uart, WLEN6, WLENM);
+ break;
+ case 5:
+ linectl(uart, WLEN5, WLENM);
+ break;
+ default:
+ return -1;
+ }
+ uart->bits = n;
+ return 0;
+}
+
+static int
+stop(Uart *uart, int n)
+{
+ switch(n){
+ case 1:
+ linectl(uart, 0, STP2);
+ break;
+ case 2:
+ linectl(uart, STP2, 0);
+ break;
+ default:
+ return -1;
+ }
+ uart->stop = n;
+ return 0;
+}
+
+static int
+parity(Uart *uart, int n)
+{
+ switch(n){
+ case 'n':
+ linectl(uart, 0, PEN);
+ break;
+ case 'e':
+ linectl(uart, EPS|PEN, 0);
+ break;
+ case 'o':
+ linectl(uart, PEN, EPS);
+ break;
+ default:
+ return -1;
+ }
+ uart->parity = n;
+ return 0;
+}
+
+static void
+modemctl(Uart *uart, int on)
+{
+ uart->modem = on;
+}
+
+static void
+rts(Uart*, int)
+{
+}
+
+static long
+status(Uart *uart, void *buf, long n, long offset)
+{
+ char *p;
+
+ p = malloc(READSTR);
+ if(p == nil)
+ error(Enomem);
+ snprint(p, READSTR,
+ "b%d\n"
+ "dev(%d) type(%d) framing(%d) overruns(%d) "
+ "berr(%d) serr(%d)\n",
+
+ uart->baud,
+ uart->dev,
+ uart->type,
+ uart->ferr,
+ uart->oerr,
+ uart->berr,
+ uart->serr
+ );
+ n = readstr(offset, buf, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+donothing(Uart*, int)
+{
+}
+
+static void
+putc(Uart *uart, int c)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & TXFF) != 0)
+ ;
+ reg[DR] = c & 0xFF;
+}
+
+static int
+getc(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & RXFE) != 0)
+ ;
+ return reg[DR] & 0xFF;
+}
+
+PhysUart pl011physuart = {
+ .name = "pl011",
+ .pnp = pnp,
+ .enable = enable,
+ .disable = disable,
+ .kick = kick,
+ .dobreak = dobreak,
+ .baud = baud,
+ .bits = bits,
+ .stop = stop,
+ .parity = parity,
+ .modemctl = donothing,
+ .rts = rts,
+ .dtr = donothing,
+ .status = status,
+ .fifo = donothing,
+ .getc = getc,
+ .putc = putc,
+};
+
+extern volatile char *easyuart;
+void
+uartconsinit(void)
+{
+ extern PhysUart *physuart[];
+ //char *p, *cmd;
+ Uart *uart;
+ int i, n;
+
+ *easyuart = 'A';
+ /*if((p = getconf("console")) == nil)
+ return;
+ *easyuart = 'B';
+ i = strtoul(p, &cmd, 0);
+ *easyuart = 'C';
+ if(p == cmd)
+ return;*/
+ *easyuart = 'D';
+ /* we only have two possible uarts, the pl011 and aux */
+ for(n = 0; physuart[n] != nil; n++)
+ ;
+ if(i < 0 || i >= n)
+ return;
+ *easyuart = 'E';
+ uart = physuart[i]->pnp();
+ *easyuart = 'F';
+ if(!uart->enabled)
+ (*uart->phys->enable)(uart, 0);
+ *easyuart = 'G';
+ uartctl(uart, "l8 pn s1");
+ *easyuart = 'H';
+ //if(*cmd != '\0')
+ // uartctl(uart, cmd);
+ *easyuart = 'I';
+ uart->console = 1;
+ *easyuart = 'J';
+ consuart = uart;
+ *easyuart = 'K';
+ uartputs(kmesg.buf, kmesg.n);
+ *easyuart = 'L';
+} \ No newline at end of file
diff --git a/sys/src/9/virt/virt64 b/sys/src/9/virt/virt64
new file mode 100644
index 000000000..0af3026dd
--- /dev/null
+++ b/sys/src/9/virt/virt64
@@ -0,0 +1,45 @@
+dev
+ root
+ cons
+ swap
+ env
+ pipe
+ proc
+ mnt
+ srv
+ shr
+ dup
+ tls
+ cap
+ fs
+ bridge log
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
+ uart
+ rtc devi2c
+ sd
+ audio
+
+link
+ loopbackmedium
+ netdevmedium
+
+ip
+ tcp
+ udp
+ il
+ ipifc
+ icmp
+ icmp6
+ ipmux
+misc
+ uartpl011
+ ccm
+ gic
+ iomux
+port
+ int cpuserver = 0;
+bootdir
+ /$objtype/bin/paqfs
+ /$objtype/bin/auth/factotum
+ bootfs.paq
+ boot