diff options
author | Jaume Delclòs Coll <cosa@cosarara.me> | 2023-05-22 10:26:52 +0000 |
---|---|---|
committer | Jaume Delclòs Coll <cosa@cosarara.me> | 2023-05-22 10:26:52 +0000 |
commit | b9e0b5b8958c8b92321dcc6f5820b7459392e97f (patch) | |
tree | cd22c2048a8fb740ba7f926afa52f0be0c919a86 /sys/src | |
parent | 278caaf11931ec0c71fc13fd4c4794fae325c404 (diff) |
WIP qemu virt platform kernel
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/virt/cache.v8.s | 212 | ||||
-rw-r--r-- | sys/src/9/virt/ccm.c | 1444 | ||||
-rw-r--r-- | sys/src/9/virt/clock.c | 142 | ||||
-rw-r--r-- | sys/src/9/virt/dat.h | 224 | ||||
-rw-r--r-- | sys/src/9/virt/devrtc.c | 349 | ||||
-rw-r--r-- | sys/src/9/virt/fns.h | 171 | ||||
-rw-r--r-- | sys/src/9/virt/fpu.c | 92 | ||||
-rw-r--r-- | sys/src/9/virt/gic.c | 295 | ||||
-rw-r--r-- | sys/src/9/virt/gic_reform.c | 321 | ||||
-rw-r--r-- | sys/src/9/virt/init9.s | 4 | ||||
-rw-r--r-- | sys/src/9/virt/io.h | 11 | ||||
-rw-r--r-- | sys/src/9/virt/iomux.c | 1139 | ||||
-rw-r--r-- | sys/src/9/virt/l.s | 717 | ||||
-rw-r--r-- | sys/src/9/virt/main.c | 455 | ||||
-rw-r--r-- | sys/src/9/virt/mem.h | 144 | ||||
-rw-r--r-- | sys/src/9/virt/mkfile | 101 | ||||
-rw-r--r-- | sys/src/9/virt/mmu.c | 526 | ||||
-rw-r--r-- | sys/src/9/virt/rebootcode.s | 48 | ||||
-rw-r--r-- | sys/src/9/virt/sysreg.c | 58 | ||||
-rw-r--r-- | sys/src/9/virt/sysreg.h | 90 | ||||
-rw-r--r-- | sys/src/9/virt/trap.c | 711 | ||||
-rw-r--r-- | sys/src/9/virt/uartpl011.c | 400 | ||||
-rw-r--r-- | sys/src/9/virt/virt64 | 45 |
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 |