1*41b6ab1fSkettenis /* $OpenBSD: rkclock.c,v 1.91 2024/11/24 22:19:59 kettenis Exp $ */ 2592afca7Skettenis /* 3da841e6eSkettenis * Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org> 4592afca7Skettenis * 5592afca7Skettenis * Permission to use, copy, modify, and distribute this software for any 6592afca7Skettenis * purpose with or without fee is hereby granted, provided that the above 7592afca7Skettenis * copyright notice and this permission notice appear in all copies. 8592afca7Skettenis * 9592afca7Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10592afca7Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11592afca7Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12592afca7Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13592afca7Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14592afca7Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15592afca7Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16592afca7Skettenis */ 17592afca7Skettenis 18592afca7Skettenis #include <sys/param.h> 19592afca7Skettenis #include <sys/systm.h> 20592afca7Skettenis #include <sys/sysctl.h> 21592afca7Skettenis #include <sys/device.h> 22592afca7Skettenis 23592afca7Skettenis #include <machine/intr.h> 24592afca7Skettenis #include <machine/bus.h> 25592afca7Skettenis #include <machine/fdt.h> 26592afca7Skettenis 27592afca7Skettenis #include <dev/ofw/openfirm.h> 28592afca7Skettenis #include <dev/ofw/ofw_clock.h> 292fcaff65Skettenis #include <dev/ofw/ofw_misc.h> 30592afca7Skettenis #include <dev/ofw/fdt.h> 31592afca7Skettenis 32bd903cc4Skettenis /* RK3288 registers */ 33227c6ee3Skettenis #define RK3288_CRU_APLL_CON(i) (0x0000 + (i) * 4) 34bd903cc4Skettenis #define RK3288_CRU_CPLL_CON(i) (0x0020 + (i) * 4) 35bd903cc4Skettenis #define RK3288_CRU_GPLL_CON(i) (0x0030 + (i) * 4) 3672f108a7Skettenis #define RK3288_CRU_NPLL_CON(i) (0x0040 + (i) * 4) 37bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKR_MASK (0x3f << 8) 38bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKR_SHIFT 8 39bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKOD_MASK (0xf << 0) 40bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKOD_SHIFT 0 41bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKF_MASK (0x1fff << 0) 42bf9e0ff8Skettenis #define RK3288_CRU_PLL_CLKF_SHIFT 0 43bf9e0ff8Skettenis #define RK3288_CRU_PLL_RESET (1 << 5) 44bf9e0ff8Skettenis #define RK3288_CRU_MODE_CON 0x0050 45bf9e0ff8Skettenis #define RK3288_CRU_MODE_PLL_WORK_MODE_MASK 0x3 46bf9e0ff8Skettenis #define RK3288_CRU_MODE_PLL_WORK_MODE_SLOW 0x0 47bf9e0ff8Skettenis #define RK3288_CRU_MODE_PLL_WORK_MODE_NORMAL 0x1 48bd903cc4Skettenis #define RK3288_CRU_CLKSEL_CON(i) (0x0060 + (i) * 4) 4949b48721Skettenis #define RK3288_CRU_SOFTRST_CON(i) (0x01b8 + (i) * 4) 50bd903cc4Skettenis 511235808cSjmatthew /* RK3308 registers */ 521235808cSjmatthew #define RK3308_CRU_APLL_CON(i) (0x0000 + (i) * 4) 531235808cSjmatthew #define RK3308_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 541235808cSjmatthew #define RK3308_CRU_VPLL0_CON(i) (0x0040 + (i) * 4) 551235808cSjmatthew #define RK3308_CRU_VPLL1_CON(i) (0x0060 + (i) * 4) 561235808cSjmatthew #define RK3308_CRU_PLL_POSTDIV1_MASK (0x7 << 12) 571235808cSjmatthew #define RK3308_CRU_PLL_POSTDIV1_SHIFT 12 581235808cSjmatthew #define RK3308_CRU_PLL_FBDIV_MASK (0xfff << 0) 591235808cSjmatthew #define RK3308_CRU_PLL_FBDIV_SHIFT 0 601235808cSjmatthew #define RK3308_CRU_PLL_DSMPD (1 << 12) 611235808cSjmatthew #define RK3308_CRU_PLL_PLL_LOCK (1 << 10) 621235808cSjmatthew #define RK3308_CRU_PLL_POSTDIV2_MASK (0x7 << 6) 631235808cSjmatthew #define RK3308_CRU_PLL_POSTDIV2_SHIFT 6 641235808cSjmatthew #define RK3308_CRU_PLL_REFDIV_MASK (0x3f << 0) 651235808cSjmatthew #define RK3308_CRU_PLL_REFDIV_SHIFT 0 661235808cSjmatthew #define RK3308_CRU_PLL_FRACDIV_MASK (0xffffff << 0) 671235808cSjmatthew #define RK3308_CRU_PLL_FRACDIV_SHIFT 0 681235808cSjmatthew #define RK3308_CRU_CRU_MODE 0x00a0 691235808cSjmatthew #define RK3308_CRU_CRU_MODE_MASK 0x3 701235808cSjmatthew #define RK3308_CRU_CRU_MODE_SLOW 0x0 711235808cSjmatthew #define RK3308_CRU_CRU_MODE_NORMAL 0x1 721235808cSjmatthew #define RK3308_CRU_CRU_MODE_DEEP 0x2 731235808cSjmatthew #define RK3308_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 741235808cSjmatthew #define RK3308_CRU_ACLK_CORE_DIV_CON_MASK (0x07 << 12) 751235808cSjmatthew #define RK3308_CRU_ACLK_CORE_DIV_CON_SHIFT 12 761235808cSjmatthew #define RK3308_CRU_CLK_CORE_DBG_DIV_CON_MASK (0x0f << 8) 771235808cSjmatthew #define RK3308_CRU_CLK_CORE_DBG_DIV_CON_SHIFT 8 781235808cSjmatthew #define RK3308_CRU_CORE_CLK_PLL_SEL_MASK (0x03 << 6) 791235808cSjmatthew #define RK3308_CRU_CORE_CLK_PLL_SEL_SHIFT 6 801235808cSjmatthew #define RK3308_CRU_CLK_CORE_DIV_CON_MASK (0x0f << 0) 811235808cSjmatthew #define RK3308_CRU_CLK_CORE_DIV_CON_SHIFT 0 821235808cSjmatthew #define RK3308_CRU_CLKGATE_CON(i) (0x0300 + (i) * 4) 831235808cSjmatthew #define RK3308_CRU_SOFTRST_CON(i) (0x0400 + (i) * 4) 841235808cSjmatthew 85da841e6eSkettenis /* RK3328 registers */ 86a2f8fc4bSkettenis #define RK3328_CRU_APLL_CON(i) (0x0000 + (i) * 4) 87a2f8fc4bSkettenis #define RK3328_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 88da841e6eSkettenis #define RK3328_CRU_CPLL_CON(i) (0x0040 + (i) * 4) 89da841e6eSkettenis #define RK3328_CRU_GPLL_CON(i) (0x0060 + (i) * 4) 90f231fa3aSkettenis #define RK3328_CRU_NPLL_CON(i) (0x00a0 + (i) * 4) 91da841e6eSkettenis #define RK3328_CRU_PLL_POSTDIV1_MASK (0x7 << 12) 92da841e6eSkettenis #define RK3328_CRU_PLL_POSTDIV1_SHIFT 12 93da841e6eSkettenis #define RK3328_CRU_PLL_FBDIV_MASK (0xfff << 0) 94da841e6eSkettenis #define RK3328_CRU_PLL_FBDIV_SHIFT 0 954cecc5e3Skettenis #define RK3328_CRU_PLL_DSMPD (1 << 12) 964cecc5e3Skettenis #define RK3328_CRU_PLL_PLL_LOCK (1 << 10) 97da841e6eSkettenis #define RK3328_CRU_PLL_POSTDIV2_MASK (0x7 << 6) 98da841e6eSkettenis #define RK3328_CRU_PLL_POSTDIV2_SHIFT 6 99da841e6eSkettenis #define RK3328_CRU_PLL_REFDIV_MASK (0x3f << 0) 100da841e6eSkettenis #define RK3328_CRU_PLL_REFDIV_SHIFT 0 1014cecc5e3Skettenis #define RK3328_CRU_PLL_FRACDIV_MASK (0xffffff << 0) 1024cecc5e3Skettenis #define RK3328_CRU_PLL_FRACDIV_SHIFT 0 103f231fa3aSkettenis #define RK3328_CRU_CRU_MODE 0x0080 104f231fa3aSkettenis #define RK3328_CRU_CRU_MODE_MASK 0x1 105f231fa3aSkettenis #define RK3328_CRU_CRU_MODE_SLOW 0x0 106f231fa3aSkettenis #define RK3328_CRU_CRU_MODE_NORMAL 0x1 107f231fa3aSkettenis #define RK3328_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 108f231fa3aSkettenis #define RK3328_CRU_CORE_CLK_PLL_SEL_MASK (0x3 << 6) 109f231fa3aSkettenis #define RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT 6 110f231fa3aSkettenis #define RK3328_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0) 111f231fa3aSkettenis #define RK3328_CRU_CLK_CORE_DIV_CON_SHIFT 0 112f231fa3aSkettenis #define RK3328_CRU_ACLK_CORE_DIV_CON_MASK (0x7 << 4) 113f231fa3aSkettenis #define RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT 4 114f231fa3aSkettenis #define RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK (0xf << 0) 115f231fa3aSkettenis #define RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT 0 1164cecc5e3Skettenis #define RK3328_CRU_VOP_DCLK_SRC_SEL_MASK (0x1 << 1) 1174cecc5e3Skettenis #define RK3328_CRU_VOP_DCLK_SRC_SEL_SHIFT 1 118da841e6eSkettenis #define RK3328_CRU_CLKGATE_CON(i) (0x0200 + (i) * 4) 119da841e6eSkettenis #define RK3328_CRU_SOFTRST_CON(i) (0x0300 + (i) * 4) 120da841e6eSkettenis 121015b970dSkettenis #define RK3328_GRF_SOC_CON4 0x0410 122015b970dSkettenis #define RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN (1 << 14) 1232fcaff65Skettenis #define RK3328_GRF_MAC_CON1 0x0904 124015b970dSkettenis #define RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL (1 << 10) 1252fcaff65Skettenis 126bd903cc4Skettenis /* RK3399 registers */ 12713d6baf8Skettenis #define RK3399_CRU_LPLL_CON(i) (0x0000 + (i) * 4) 12813d6baf8Skettenis #define RK3399_CRU_BPLL_CON(i) (0x0020 + (i) * 4) 12913d6baf8Skettenis #define RK3399_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 130d9457073Skettenis #define RK3399_CRU_CPLL_CON(i) (0x0060 + (i) * 4) 131d9457073Skettenis #define RK3399_CRU_GPLL_CON(i) (0x0080 + (i) * 4) 132f89cc881Skettenis #define RK3399_CRU_NPLL_CON(i) (0x00a0 + (i) * 4) 13398a76083Skettenis #define RK3399_CRU_VPLL_CON(i) (0x00c0 + (i) * 4) 134f8c4fba2Skettenis #define RK3399_CRU_PLL_FBDIV_MASK (0xfff << 0) 135f8c4fba2Skettenis #define RK3399_CRU_PLL_FBDIV_SHIFT 0 136f8c4fba2Skettenis #define RK3399_CRU_PLL_POSTDIV2_MASK (0x7 << 12) 137f8c4fba2Skettenis #define RK3399_CRU_PLL_POSTDIV2_SHIFT 12 138f8c4fba2Skettenis #define RK3399_CRU_PLL_POSTDIV1_MASK (0x7 << 8) 139f8c4fba2Skettenis #define RK3399_CRU_PLL_POSTDIV1_SHIFT 8 140f8c4fba2Skettenis #define RK3399_CRU_PLL_REFDIV_MASK (0x3f << 0) 141f8c4fba2Skettenis #define RK3399_CRU_PLL_REFDIV_SHIFT 0 14269da300fSkettenis #define RK3399_CRU_PLL_PLL_WORK_MODE_MASK (0x3 << 8) 14369da300fSkettenis #define RK3399_CRU_PLL_PLL_WORK_MODE_SLOW (0x0 << 8) 14469da300fSkettenis #define RK3399_CRU_PLL_PLL_WORK_MODE_NORMAL (0x1 << 8) 14569da300fSkettenis #define RK3399_CRU_PLL_PLL_WORK_MODE_DEEP_SLOW (0x2 << 8) 146f8c4fba2Skettenis #define RK3399_CRU_PLL_PLL_LOCK (1U << 31) 147592afca7Skettenis #define RK3399_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 148f8c4fba2Skettenis #define RK3399_CRU_ACLKM_CORE_DIV_CON_MASK (0x1f << 8) 149f8c4fba2Skettenis #define RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT 8 150f8c4fba2Skettenis #define RK3399_CRU_CORE_PLL_SEL_MASK (0x3 << 6) 1511af18cc1Skettenis #define RK3399_CRU_CORE_PLL_SEL_APLL (0x0 << 6) 1521af18cc1Skettenis #define RK3399_CRU_CORE_PLL_SEL_BPLL (0x1 << 6) 1531af18cc1Skettenis #define RK3399_CRU_CORE_PLL_SEL_DPLL (0x2 << 6) 1541af18cc1Skettenis #define RK3399_CRU_CORE_PLL_SEL_GPLL (0x3 << 6) 155f8c4fba2Skettenis #define RK3399_CRU_CORE_PLL_SEL_SHIFT 6 156f8c4fba2Skettenis #define RK3399_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0) 157f8c4fba2Skettenis #define RK3399_CRU_CLK_CORE_DIV_CON_SHIFT 0 158f8c4fba2Skettenis #define RK3399_CRU_PCLK_DBG_DIV_CON_MASK (0x1f << 8) 159f8c4fba2Skettenis #define RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT 8 160f8c4fba2Skettenis #define RK3399_CRU_ATCLK_CORE_DIV_CON_MASK (0x1f << 0) 161f8c4fba2Skettenis #define RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT 0 162dac87a37Skettenis #define RK3399_CRU_CLK_SD_PLL_SEL_MASK (0x7 << 8) 163dac87a37Skettenis #define RK3399_CRU_CLK_SD_PLL_SEL_SHIFT 8 16498a76083Skettenis #define RK3399_CRU_CLK_SD_DIV_CON_MASK (0x7f << 0) 165dac87a37Skettenis #define RK3399_CRU_CLK_SD_DIV_CON_SHIFT 0 166c4f96b6eSkettenis #define RK3399_CRU_CLKGATE_CON(i) (0x0300 + (i) * 4) 16764b62fe2Skettenis #define RK3399_CRU_SOFTRST_CON(i) (0x0400 + (i) * 4) 168d9457073Skettenis #define RK3399_CRU_SDMMC_CON(i) (0x0580 + (i) * 4) 169592afca7Skettenis 170ad8cadefSkettenis #define RK3399_PMUCRU_PPLL_CON(i) (0x0000 + (i) * 4) 171ad8cadefSkettenis #define RK3399_PMUCRU_CLKSEL_CON(i) (0x0080 + (i) * 4) 172ad8cadefSkettenis 17333081393Skettenis /* RK3568 registers */ 17433081393Skettenis #define RK3568_CRU_APLL_CON(i) (0x0000 + (i) * 4) 17533081393Skettenis #define RK3568_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 17633081393Skettenis #define RK3568_CRU_GPLL_CON(i) (0x0040 + (i) * 4) 17733081393Skettenis #define RK3568_CRU_CPLL_CON(i) (0x0060 + (i) * 4) 17833081393Skettenis #define RK3568_CRU_NPLL_CON(i) (0x0080 + (i) * 4) 17933081393Skettenis #define RK3568_CRU_VPLL_CON(i) (0x00a0 + (i) * 4) 18033081393Skettenis #define RK3568_CRU_MODE_CON 0x00c0 18133081393Skettenis #define RK3568_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 18233081393Skettenis #define RK3568_CRU_GATE_CON(i) (0x0300 + (i) * 4) 18333081393Skettenis #define RK3568_CRU_SOFTRST_CON(i) (0x0400 + (i) * 4) 18433081393Skettenis 18533081393Skettenis #define RK3568_PMUCRU_PPLL_CON(i) (0x0000 + (i) * 4) 18633081393Skettenis #define RK3568_PMUCRU_HPLL_CON(i) (0x0040 + (i) * 4) 18733081393Skettenis #define RK3568_PMUCRU_MODE_CON 0x0080 18833081393Skettenis #define RK3568_PMUCRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 189e1414c50Skettenis #define RK3568_PMUCRU_GATE_CON(i) (0x0180 + (i) * 4) 19033081393Skettenis 191e3f8cdb8Skettenis /* RK3588 registers */ 192e3f8cdb8Skettenis #define RK3588_CRU_AUPLL_CON(i) (0x00180 + (i) * 4) 193e3f8cdb8Skettenis #define RK3588_CRU_CPLL_CON(i) (0x001a0 + (i) * 4) 194e3f8cdb8Skettenis #define RK3588_CRU_GPLL_CON(i) (0x001c0 + (i) * 4) 195e3f8cdb8Skettenis #define RK3588_CRU_NPLL_CON(i) (0x001e0 + (i) * 4) 196e3f8cdb8Skettenis #define RK3588_CRU_PLL_M_MASK (0x3ff << 0) 197e3f8cdb8Skettenis #define RK3588_CRU_PLL_M_SHIFT 0 198e3f8cdb8Skettenis #define RK3588_CRU_PLL_RESETB (1 << 13) 199e3f8cdb8Skettenis #define RK3588_CRU_PLL_S_MASK (0x7 << 6) 200e3f8cdb8Skettenis #define RK3588_CRU_PLL_S_SHIFT 6 201e3f8cdb8Skettenis #define RK3588_CRU_PLL_P_MASK (0x3f << 0) 202e3f8cdb8Skettenis #define RK3588_CRU_PLL_P_SHIFT 0 203e3f8cdb8Skettenis #define RK3588_CRU_PLL_K_MASK (0xffff << 0) 204e3f8cdb8Skettenis #define RK3588_CRU_PLL_K_SHIFT 0 205e3f8cdb8Skettenis #define RK3588_CRU_PLL_PLL_LOCK (1 << 15) 206e3f8cdb8Skettenis #define RK3588_CRU_MODE_CON 0x00280 207e3f8cdb8Skettenis #define RK3588_CRU_MODE_MASK 0x3 208e3f8cdb8Skettenis #define RK3588_CRU_MODE_SLOW 0x0 209e3f8cdb8Skettenis #define RK3588_CRU_MODE_NORMAL 0x1 210e3f8cdb8Skettenis 211e3f8cdb8Skettenis #define RK3588_CRU_CLKSEL_CON(i) (0x00300 + (i) * 4) 212e3f8cdb8Skettenis #define RK3588_CRU_GATE_CON(i) (0x00800 + (i) * 4) 21383b03bd4Skettenis #define RK3588_CRU_SOFTRST_CON(i) (0x00a00 + (i) * 4) 214e3f8cdb8Skettenis 215e3f8cdb8Skettenis #define RK3588_PHPTOPCRU_PPLL_CON(i) (0x08200 + (i) * 4) 21683b03bd4Skettenis #define RK3588_PHPTOPCRU_SOFTRST_CON(i) (0x08a00 + (i) * 4) 217e3f8cdb8Skettenis #define RK3588_PMUCRU_CLKSEL_CON(i) (0x30300 + (i) * 4) 218e3f8cdb8Skettenis 219592afca7Skettenis #include "rkclock_clocks.h" 220592afca7Skettenis 221e82d29a5Skettenis struct rkclock { 222e82d29a5Skettenis uint16_t idx; 223e3f8cdb8Skettenis uint32_t reg; 224e82d29a5Skettenis uint16_t sel_mask; 225e82d29a5Skettenis uint16_t div_mask; 2267371cc19Skettenis uint16_t parents[8]; 2273f8209efSkettenis uint32_t flags; 228e82d29a5Skettenis }; 229e82d29a5Skettenis 230e82d29a5Skettenis #define SEL(l, f) (((1 << (l - f + 1)) - 1) << f) 231e82d29a5Skettenis #define DIV(l, f) SEL(l, f) 232e82d29a5Skettenis 2333f8209efSkettenis #define FIXED_PARENT (1 << 0) 2343f8209efSkettenis #define SET_PARENT (1 << 1) 2353f8209efSkettenis 236592afca7Skettenis #define HREAD4(sc, reg) \ 237592afca7Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 238592afca7Skettenis #define HWRITE4(sc, reg, val) \ 239592afca7Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 240592afca7Skettenis #define HSET4(sc, reg, bits) \ 241592afca7Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 242592afca7Skettenis #define HCLR4(sc, reg, bits) \ 243592afca7Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 244592afca7Skettenis 245592afca7Skettenis struct rkclock_softc { 246592afca7Skettenis struct device sc_dev; 247592afca7Skettenis bus_space_tag_t sc_iot; 248592afca7Skettenis bus_space_handle_t sc_ioh; 2492fcaff65Skettenis struct regmap *sc_grf; 250592afca7Skettenis 2519822ab30Skettenis uint32_t sc_phandle; 25237c734d3Snaddy const struct rkclock *sc_clocks; 2539822ab30Skettenis 254592afca7Skettenis struct clock_device sc_cd; 255592afca7Skettenis struct reset_device sc_rd; 256592afca7Skettenis }; 257592afca7Skettenis 258592afca7Skettenis int rkclock_match(struct device *, void *, void *); 259592afca7Skettenis void rkclock_attach(struct device *, struct device *, void *); 260592afca7Skettenis 2619fdf0c62Smpi const struct cfattach rkclock_ca = { 262592afca7Skettenis sizeof (struct rkclock_softc), rkclock_match, rkclock_attach 263592afca7Skettenis }; 264592afca7Skettenis 265592afca7Skettenis struct cfdriver rkclock_cd = { 266592afca7Skettenis NULL, "rkclock", DV_DULL 267592afca7Skettenis }; 268592afca7Skettenis 269bf9e0ff8Skettenis void rk3288_init(struct rkclock_softc *); 270bd903cc4Skettenis uint32_t rk3288_get_frequency(void *, uint32_t *); 271bd903cc4Skettenis int rk3288_set_frequency(void *, uint32_t *, uint32_t); 272bd903cc4Skettenis void rk3288_enable(void *, uint32_t *, int); 273bd903cc4Skettenis void rk3288_reset(void *, uint32_t *, int); 274bd903cc4Skettenis 2751235808cSjmatthew void rk3308_init(struct rkclock_softc *); 2761235808cSjmatthew uint32_t rk3308_get_frequency(void *, uint32_t *); 2771235808cSjmatthew int rk3308_set_frequency(void *, uint32_t *, uint32_t); 2781235808cSjmatthew int rk3308_set_parent(void *, uint32_t *, uint32_t *); 2791235808cSjmatthew void rk3308_enable(void *, uint32_t *, int); 2801235808cSjmatthew void rk3308_reset(void *, uint32_t *, int); 2811235808cSjmatthew 282da841e6eSkettenis void rk3328_init(struct rkclock_softc *); 283da841e6eSkettenis uint32_t rk3328_get_frequency(void *, uint32_t *); 284da841e6eSkettenis int rk3328_set_frequency(void *, uint32_t *, uint32_t); 2859822ab30Skettenis int rk3328_set_parent(void *, uint32_t *, uint32_t *); 286da841e6eSkettenis void rk3328_enable(void *, uint32_t *, int); 287da841e6eSkettenis void rk3328_reset(void *, uint32_t *, int); 288da841e6eSkettenis 28969da300fSkettenis void rk3399_init(struct rkclock_softc *); 290592afca7Skettenis uint32_t rk3399_get_frequency(void *, uint32_t *); 291592afca7Skettenis int rk3399_set_frequency(void *, uint32_t *, uint32_t); 2925486a9fbSpatrick int rk3399_set_parent(void *, uint32_t *, uint32_t *); 293592afca7Skettenis void rk3399_enable(void *, uint32_t *, int); 294592afca7Skettenis void rk3399_reset(void *, uint32_t *, int); 295592afca7Skettenis 296ad8cadefSkettenis void rk3399_pmu_init(struct rkclock_softc *); 297592afca7Skettenis uint32_t rk3399_pmu_get_frequency(void *, uint32_t *); 298592afca7Skettenis int rk3399_pmu_set_frequency(void *, uint32_t *, uint32_t); 299592afca7Skettenis void rk3399_pmu_enable(void *, uint32_t *, int); 300592afca7Skettenis void rk3399_pmu_reset(void *, uint32_t *, int); 301592afca7Skettenis 30233081393Skettenis void rk3568_init(struct rkclock_softc *); 30333081393Skettenis uint32_t rk3568_get_frequency(void *, uint32_t *); 30433081393Skettenis int rk3568_set_frequency(void *, uint32_t *, uint32_t); 305bc4366cbSkettenis int rk3568_set_parent(void *, uint32_t *, uint32_t *); 30633081393Skettenis void rk3568_enable(void *, uint32_t *, int); 30733081393Skettenis void rk3568_reset(void *, uint32_t *, int); 30833081393Skettenis 30933081393Skettenis void rk3568_pmu_init(struct rkclock_softc *); 31033081393Skettenis uint32_t rk3568_pmu_get_frequency(void *, uint32_t *); 31133081393Skettenis int rk3568_pmu_set_frequency(void *, uint32_t *, uint32_t); 31233081393Skettenis void rk3568_pmu_enable(void *, uint32_t *, int); 31333081393Skettenis void rk3568_pmu_reset(void *, uint32_t *, int); 31433081393Skettenis 315e3f8cdb8Skettenis void rk3588_init(struct rkclock_softc *); 316e3f8cdb8Skettenis uint32_t rk3588_get_frequency(void *, uint32_t *); 317e3f8cdb8Skettenis int rk3588_set_frequency(void *, uint32_t *, uint32_t); 318e3f8cdb8Skettenis void rk3588_enable(void *, uint32_t *, int); 319e3f8cdb8Skettenis void rk3588_reset(void *, uint32_t *, int); 320e3f8cdb8Skettenis 321592afca7Skettenis struct rkclock_compat { 322592afca7Skettenis const char *compat; 323d921c7cfSdlg const char *name; 3241af18cc1Skettenis int assign; 32569da300fSkettenis void (*init)(struct rkclock_softc *); 326592afca7Skettenis void (*enable)(void *, uint32_t *, int); 327592afca7Skettenis uint32_t (*get_frequency)(void *, uint32_t *); 328592afca7Skettenis int (*set_frequency)(void *, uint32_t *, uint32_t); 3299822ab30Skettenis int (*set_parent)(void *, uint32_t *, uint32_t *); 330592afca7Skettenis void (*reset)(void *, uint32_t *, int); 331592afca7Skettenis }; 332592afca7Skettenis 33337c734d3Snaddy const struct rkclock_compat rkclock_compat[] = { 334592afca7Skettenis { 335d921c7cfSdlg "rockchip,rk3288-cru", NULL, 0, rk3288_init, 336bd903cc4Skettenis rk3288_enable, rk3288_get_frequency, 3379822ab30Skettenis rk3288_set_frequency, NULL, 3389822ab30Skettenis rk3288_reset 339bd903cc4Skettenis }, 340bd903cc4Skettenis { 341d921c7cfSdlg "rockchip,rk3308-cru", NULL, 1, rk3308_init, 3421235808cSjmatthew rk3308_enable, rk3308_get_frequency, 3431235808cSjmatthew rk3308_set_frequency, rk3308_set_parent, 3441235808cSjmatthew rk3308_reset 3451235808cSjmatthew }, 3461235808cSjmatthew { 347d921c7cfSdlg "rockchip,rk3328-cru", NULL, 1, rk3328_init, 348da841e6eSkettenis rk3328_enable, rk3328_get_frequency, 3499822ab30Skettenis rk3328_set_frequency, rk3328_set_parent, 3509822ab30Skettenis rk3328_reset 351da841e6eSkettenis }, 352da841e6eSkettenis { 353d921c7cfSdlg "rockchip,rk3399-cru", NULL, 1, rk3399_init, 354592afca7Skettenis rk3399_enable, rk3399_get_frequency, 3555486a9fbSpatrick rk3399_set_frequency, rk3399_set_parent, 3569822ab30Skettenis rk3399_reset 357592afca7Skettenis }, 358592afca7Skettenis { 359d921c7cfSdlg "rockchip,rk3399-pmucru", NULL, 1, rk3399_pmu_init, 360592afca7Skettenis rk3399_pmu_enable, rk3399_pmu_get_frequency, 3619822ab30Skettenis rk3399_pmu_set_frequency, NULL, 3629822ab30Skettenis rk3399_pmu_reset 36333081393Skettenis }, 36433081393Skettenis { 365d921c7cfSdlg "rockchip,rk3568-cru", "CRU", 1, rk3568_init, 36633081393Skettenis rk3568_enable, rk3568_get_frequency, 367bc4366cbSkettenis rk3568_set_frequency, rk3568_set_parent, 36833081393Skettenis rk3568_reset 36933081393Skettenis }, 37033081393Skettenis { 371d921c7cfSdlg "rockchip,rk3568-pmucru", "PMUCRU", 1, rk3568_pmu_init, 37233081393Skettenis rk3568_pmu_enable, rk3568_pmu_get_frequency, 37333081393Skettenis rk3568_pmu_set_frequency, NULL, 37433081393Skettenis rk3568_pmu_reset 375e3f8cdb8Skettenis }, 376e3f8cdb8Skettenis { 377d921c7cfSdlg "rockchip,rk3588-cru", NULL, 1, rk3588_init, 378e3f8cdb8Skettenis rk3588_enable, rk3588_get_frequency, 379e3f8cdb8Skettenis rk3588_set_frequency, NULL, 380e3f8cdb8Skettenis rk3588_reset 381e3f8cdb8Skettenis }, 382592afca7Skettenis }; 383592afca7Skettenis 384592afca7Skettenis int 385592afca7Skettenis rkclock_match(struct device *parent, void *match, void *aux) 386592afca7Skettenis { 387592afca7Skettenis struct fdt_attach_args *faa = aux; 388592afca7Skettenis int i; 389592afca7Skettenis 390592afca7Skettenis for (i = 0; i < nitems(rkclock_compat); i++) { 391592afca7Skettenis if (OF_is_compatible(faa->fa_node, rkclock_compat[i].compat)) 392da841e6eSkettenis return 10; 393592afca7Skettenis } 394592afca7Skettenis 395592afca7Skettenis return 0; 396592afca7Skettenis } 397592afca7Skettenis 398592afca7Skettenis void 399592afca7Skettenis rkclock_attach(struct device *parent, struct device *self, void *aux) 400592afca7Skettenis { 401592afca7Skettenis struct rkclock_softc *sc = (struct rkclock_softc *)self; 402592afca7Skettenis struct fdt_attach_args *faa = aux; 4032fcaff65Skettenis uint32_t grf; 404592afca7Skettenis int i; 405592afca7Skettenis 406592afca7Skettenis if (faa->fa_nreg < 1) { 407592afca7Skettenis printf(": no registers\n"); 408592afca7Skettenis return; 409592afca7Skettenis } 410592afca7Skettenis 411592afca7Skettenis sc->sc_iot = faa->fa_iot; 412592afca7Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 413592afca7Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 414592afca7Skettenis printf(": can't map registers\n"); 415592afca7Skettenis return; 416592afca7Skettenis } 417592afca7Skettenis 4182fcaff65Skettenis grf = OF_getpropint(faa->fa_node, "rockchip,grf", 0); 4192fcaff65Skettenis sc->sc_grf = regmap_byphandle(grf); 4202fcaff65Skettenis 4219822ab30Skettenis sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0); 4229822ab30Skettenis 423592afca7Skettenis for (i = 0; i < nitems(rkclock_compat); i++) { 424592afca7Skettenis if (OF_is_compatible(faa->fa_node, rkclock_compat[i].compat)) { 425592afca7Skettenis break; 426592afca7Skettenis } 427592afca7Skettenis } 42869da300fSkettenis KASSERT(i < nitems(rkclock_compat)); 42969da300fSkettenis 430d921c7cfSdlg if (rkclock_compat[i].name != NULL) 431d921c7cfSdlg printf(": %s", rkclock_compat[i].name); 432d921c7cfSdlg 433d921c7cfSdlg printf("\n"); 434d921c7cfSdlg 43569da300fSkettenis if (rkclock_compat[i].init) 43669da300fSkettenis rkclock_compat[i].init(sc); 437592afca7Skettenis 438592afca7Skettenis sc->sc_cd.cd_node = faa->fa_node; 439592afca7Skettenis sc->sc_cd.cd_cookie = sc; 44069da300fSkettenis sc->sc_cd.cd_enable = rkclock_compat[i].enable; 44169da300fSkettenis sc->sc_cd.cd_get_frequency = rkclock_compat[i].get_frequency; 44269da300fSkettenis sc->sc_cd.cd_set_frequency = rkclock_compat[i].set_frequency; 4439822ab30Skettenis sc->sc_cd.cd_set_parent = rkclock_compat[i].set_parent; 444592afca7Skettenis clock_register(&sc->sc_cd); 445592afca7Skettenis 446592afca7Skettenis sc->sc_rd.rd_node = faa->fa_node; 447592afca7Skettenis sc->sc_rd.rd_cookie = sc; 44869da300fSkettenis sc->sc_rd.rd_reset = rkclock_compat[i].reset; 449592afca7Skettenis reset_register(&sc->sc_rd); 4501af18cc1Skettenis 4511af18cc1Skettenis if (rkclock_compat[i].assign) 4521af18cc1Skettenis clock_set_assigned(faa->fa_node); 453592afca7Skettenis } 454592afca7Skettenis 45537c734d3Snaddy const struct rkclock * 456e82d29a5Skettenis rkclock_lookup(struct rkclock_softc *sc, uint32_t idx) 457e82d29a5Skettenis { 45837c734d3Snaddy const struct rkclock *clk; 459e82d29a5Skettenis 460e82d29a5Skettenis for (clk = sc->sc_clocks; clk->idx; clk++) { 461e82d29a5Skettenis if (clk->idx == idx) 462e82d29a5Skettenis return clk; 463e82d29a5Skettenis } 464e82d29a5Skettenis 465e82d29a5Skettenis return NULL; 466e82d29a5Skettenis } 467e82d29a5Skettenis 468e82d29a5Skettenis uint32_t 469c935b871Skettenis rkclock_external_frequency(const char *name) 470c935b871Skettenis { 471c935b871Skettenis char buf[64] = {}; 472c935b871Skettenis int len, node; 473c935b871Skettenis 474c935b871Skettenis /* 475c935b871Skettenis * Hunt through the device tree to find a fixed-rate clock 476c935b871Skettenis * that has the requested clock output signal name. This may 477c935b871Skettenis * be too simple. 478c935b871Skettenis */ 479c935b871Skettenis node = OF_peer(0); 480c935b871Skettenis for (node = OF_child(node); node != 0; node = OF_peer(node)) { 481c935b871Skettenis len = OF_getproplen(node, "clock-output-names"); 482c935b871Skettenis if (len <= 0 || len > sizeof(buf)) 483c935b871Skettenis continue; 484c935b871Skettenis OF_getprop(node, "clock-output-names", buf, sizeof(buf)); 485c935b871Skettenis if (strcmp(buf, name) != 0) 486c935b871Skettenis continue; 487c935b871Skettenis if (OF_is_compatible(node, "fixed-clock")) 488c935b871Skettenis return OF_getpropint(node, "clock-frequency", 0); 489c935b871Skettenis } 490c935b871Skettenis 491c935b871Skettenis return 0; 492c935b871Skettenis } 493c935b871Skettenis 494c935b871Skettenis uint32_t 49537c734d3Snaddy rkclock_div_con(struct rkclock_softc *sc, const struct rkclock *clk, 496f9988e9aSkettenis uint32_t mux, uint32_t freq) 497e82d29a5Skettenis { 498f9988e9aSkettenis uint32_t parent_freq, div, div_con, max_div_con; 499f9988e9aSkettenis uint32_t idx = clk->parents[mux]; 500f9988e9aSkettenis 501f9988e9aSkettenis /* Derive maximum value from mask. */ 502f9988e9aSkettenis max_div_con = clk->div_mask >> (ffs(clk->div_mask) - 1); 503e82d29a5Skettenis 504e82d29a5Skettenis parent_freq = sc->sc_cd.cd_get_frequency(sc, &idx); 505e82d29a5Skettenis div = (parent_freq + freq - 1) / freq; 506f9988e9aSkettenis div_con = (div > 0 ? div - 1 : 0); 507f9988e9aSkettenis return (div_con < max_div_con) ? div_con : max_div_con; 508e82d29a5Skettenis } 509e82d29a5Skettenis 510e82d29a5Skettenis uint32_t 51137c734d3Snaddy rkclock_freq(struct rkclock_softc *sc, const struct rkclock *clk, 5123f8209efSkettenis uint32_t mux, uint32_t freq) 5133f8209efSkettenis { 5143f8209efSkettenis uint32_t parent_freq, div_con; 5153f8209efSkettenis uint32_t idx = clk->parents[mux]; 5163f8209efSkettenis 5173f8209efSkettenis parent_freq = sc->sc_cd.cd_get_frequency(sc, &idx); 5183f8209efSkettenis div_con = rkclock_div_con(sc, clk, mux, freq); 5193f8209efSkettenis return parent_freq / (div_con + 1); 5203f8209efSkettenis } 5213f8209efSkettenis 5223f8209efSkettenis uint32_t 523e82d29a5Skettenis rkclock_get_frequency(struct rkclock_softc *sc, uint32_t idx) 524e82d29a5Skettenis { 52537c734d3Snaddy const struct rkclock *clk; 526e82d29a5Skettenis uint32_t reg, mux, div_con; 527e82d29a5Skettenis int shift; 528e82d29a5Skettenis 529e82d29a5Skettenis clk = rkclock_lookup(sc, idx); 530e82d29a5Skettenis if (clk == NULL) { 531bbd59784Sdlg printf("%s(%s, %u)\n", __func__, sc->sc_dev.dv_xname, idx); 532e82d29a5Skettenis return 0; 533e82d29a5Skettenis } 534e82d29a5Skettenis 535e82d29a5Skettenis reg = HREAD4(sc, clk->reg); 536e82d29a5Skettenis shift = ffs(clk->sel_mask) - 1; 537e82d29a5Skettenis if (shift == -1) 538e82d29a5Skettenis mux = 0; 539e82d29a5Skettenis else 540e82d29a5Skettenis mux = (reg & clk->sel_mask) >> shift; 541e82d29a5Skettenis shift = ffs(clk->div_mask) - 1; 542e82d29a5Skettenis if (shift == -1) 543e82d29a5Skettenis div_con = 0; 544e82d29a5Skettenis else 545e82d29a5Skettenis div_con = (reg & clk->div_mask) >> shift; 546e82d29a5Skettenis 547e82d29a5Skettenis if (clk->parents[mux] == 0) { 548e82d29a5Skettenis printf("%s: parent 0x%08x\n", __func__, idx); 549e82d29a5Skettenis return 0; 550e82d29a5Skettenis } 551e82d29a5Skettenis idx = clk->parents[mux]; 552e82d29a5Skettenis return sc->sc_cd.cd_get_frequency(sc, &idx) / (div_con + 1); 553e82d29a5Skettenis } 554e82d29a5Skettenis 555e82d29a5Skettenis int 556e82d29a5Skettenis rkclock_set_frequency(struct rkclock_softc *sc, uint32_t idx, uint32_t freq) 557e82d29a5Skettenis { 55837c734d3Snaddy const struct rkclock *clk; 559e82d29a5Skettenis uint32_t reg, mux, div_con; 5603f8209efSkettenis uint32_t best_freq, best_mux, f; 56133081393Skettenis uint32_t parent; 5623f8209efSkettenis int sel_shift, div_shift, i; 563e82d29a5Skettenis 564e82d29a5Skettenis clk = rkclock_lookup(sc, idx); 565137e484dSpatrick if (clk == NULL) { 566d921c7cfSdlg printf("%s(%s, %u, %u)\n", __func__, sc->sc_dev.dv_xname, 567d921c7cfSdlg idx, freq); 568e82d29a5Skettenis return -1; 569e82d29a5Skettenis } 570e82d29a5Skettenis 571e82d29a5Skettenis reg = HREAD4(sc, clk->reg); 5723f8209efSkettenis sel_shift = ffs(clk->sel_mask) - 1; 5733f8209efSkettenis if (sel_shift == -1) 5743f8209efSkettenis mux = sel_shift = 0; 575e82d29a5Skettenis else 5763f8209efSkettenis mux = (reg & clk->sel_mask) >> sel_shift; 577e82d29a5Skettenis 578e82d29a5Skettenis if (clk->parents[mux] == 0) { 579d921c7cfSdlg printf("%s(%s, %u, %u) parent\n", __func__, 580d921c7cfSdlg sc->sc_dev.dv_xname, idx, freq); 581e82d29a5Skettenis return 0; 582e82d29a5Skettenis } 583e82d29a5Skettenis 5843f8209efSkettenis if (clk->flags & SET_PARENT) { 58533081393Skettenis parent = clk->parents[mux]; 58633081393Skettenis sc->sc_cd.cd_set_frequency(sc, &parent, freq); 587137e484dSpatrick if (clk->div_mask == 0) 588137e484dSpatrick return 0; 589137e484dSpatrick } 590137e484dSpatrick 59133081393Skettenis /* 592e3f8cdb8Skettenis * If there is no divider, pick the parent with the frequency 593e3f8cdb8Skettenis * closest to the target frequency. 59433081393Skettenis */ 595137e484dSpatrick if (clk->div_mask == 0) { 596e3f8cdb8Skettenis /* 597e3f8cdb8Skettenis * Start out with the current parent. This prevents 598e3f8cdb8Skettenis * unnecessary switching to a different parent. 599e3f8cdb8Skettenis */ 60033081393Skettenis parent = clk->parents[mux]; 601e3f8cdb8Skettenis best_freq = sc->sc_cd.cd_get_frequency(sc, &parent); 602e3f8cdb8Skettenis best_mux = mux; 60333081393Skettenis 60433081393Skettenis for (i = 0; i < nitems(clk->parents); i++) { 60533081393Skettenis if (clk->parents[i] == 0) 60633081393Skettenis continue; 60733081393Skettenis parent = clk->parents[i]; 608e3f8cdb8Skettenis f = sc->sc_cd.cd_get_frequency(sc, &parent); 609e3f8cdb8Skettenis if ((best_freq > freq && f < best_freq) || 610e3f8cdb8Skettenis (f > best_freq && f <= freq)) { 611e3f8cdb8Skettenis best_freq = f; 612e3f8cdb8Skettenis best_mux = i; 61333081393Skettenis } 61433081393Skettenis } 61533081393Skettenis 616e3f8cdb8Skettenis HWRITE4(sc, clk->reg, 617e3f8cdb8Skettenis clk->sel_mask << 16 | best_mux << sel_shift); 618e3f8cdb8Skettenis return 0; 6193f8209efSkettenis } 6203f8209efSkettenis 6213f8209efSkettenis /* 6223f8209efSkettenis * Start out with the current parent. This prevents 6234b1a56afSjsg * unnecessary switching to a different parent. 6243f8209efSkettenis */ 6253f8209efSkettenis best_freq = rkclock_freq(sc, clk, mux, freq); 6263f8209efSkettenis best_mux = mux; 6273f8209efSkettenis 6283f8209efSkettenis /* 6293f8209efSkettenis * Find the parent that allows configuration of a frequency 6303f8209efSkettenis * closest to the target frequency. 6313f8209efSkettenis */ 6323f8209efSkettenis if ((clk->flags & FIXED_PARENT) == 0) { 6333f8209efSkettenis for (i = 0; i < nitems(clk->parents); i++) { 6343f8209efSkettenis if (clk->parents[i] == 0) 6353f8209efSkettenis continue; 6363f8209efSkettenis f = rkclock_freq(sc, clk, i, freq); 637e3f8cdb8Skettenis if ((best_freq > freq && f < best_freq) || 638e3f8cdb8Skettenis (f > best_freq && f <= freq)) { 6393f8209efSkettenis best_freq = f; 6403f8209efSkettenis best_mux = i; 6413f8209efSkettenis } 6423f8209efSkettenis } 6433f8209efSkettenis } 6443f8209efSkettenis 6453f8209efSkettenis div_con = rkclock_div_con(sc, clk, best_mux, freq); 6463f8209efSkettenis div_shift = ffs(clk->div_mask) - 1; 6473f8209efSkettenis HWRITE4(sc, clk->reg, 6483f8209efSkettenis clk->sel_mask << 16 | best_mux << sel_shift | 6493f8209efSkettenis clk->div_mask << 16 | div_con << div_shift); 650e82d29a5Skettenis return 0; 651e82d29a5Skettenis } 652e82d29a5Skettenis 653e82d29a5Skettenis int 654e82d29a5Skettenis rkclock_set_parent(struct rkclock_softc *sc, uint32_t idx, uint32_t parent) 655e82d29a5Skettenis { 65637c734d3Snaddy const struct rkclock *clk; 657e82d29a5Skettenis uint32_t mux; 658e82d29a5Skettenis int shift; 659e82d29a5Skettenis 660e82d29a5Skettenis clk = rkclock_lookup(sc, idx); 661e82d29a5Skettenis if (clk == NULL || clk->sel_mask == 0) { 662e82d29a5Skettenis printf("%s: 0x%08x\n", __func__, idx); 663e82d29a5Skettenis return -1; 664e82d29a5Skettenis } 665e82d29a5Skettenis 666e82d29a5Skettenis for (mux = 0; mux < nitems(clk->parents); mux++) { 667e82d29a5Skettenis if (clk->parents[mux] == parent) 668e82d29a5Skettenis break; 669e82d29a5Skettenis } 670e82d29a5Skettenis if (mux == nitems(clk->parents) || parent == 0) { 671e82d29a5Skettenis printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, parent); 672e82d29a5Skettenis return -1; 673e82d29a5Skettenis } 674e82d29a5Skettenis 675e82d29a5Skettenis shift = ffs(clk->sel_mask) - 1; 676e82d29a5Skettenis HWRITE4(sc, clk->reg, clk->sel_mask << 16 | mux << shift); 677e82d29a5Skettenis return 0; 678e82d29a5Skettenis } 679e82d29a5Skettenis 680592afca7Skettenis /* 681bd903cc4Skettenis * Rockchip RK3288 682bd903cc4Skettenis */ 683bd903cc4Skettenis 68437c734d3Snaddy const struct rkclock rk3288_clocks[] = { 685b1151de3Skettenis { 686b1151de3Skettenis RK3288_CLK_SDMMC, RK3288_CRU_CLKSEL_CON(11), 687b1151de3Skettenis SEL(7, 6), DIV(5, 0), 688b1151de3Skettenis { RK3288_PLL_CPLL, RK3288_PLL_GPLL, RK3288_XIN24M } 689b1151de3Skettenis } 690b1151de3Skettenis }; 691b1151de3Skettenis 692bf9e0ff8Skettenis void 693bf9e0ff8Skettenis rk3288_init(struct rkclock_softc *sc) 694bf9e0ff8Skettenis { 695bf9e0ff8Skettenis int node; 696bf9e0ff8Skettenis 697bf9e0ff8Skettenis /* 698bf9e0ff8Skettenis * Since the hardware comes up with a really conservative CPU 699bf9e0ff8Skettenis * clock frequency, and U-Boot doesn't set it to a more 700bf9e0ff8Skettenis * reasonable default, try to do so here. These defaults were 701bf9e0ff8Skettenis * chosen assuming that the CPU voltage is at least 1.1 V. 702bf9e0ff8Skettenis * Only do this on the Tinker-RK3288 for now where this is 703bf9e0ff8Skettenis * likely to be true given the default voltages for the 704bf9e0ff8Skettenis * regulators on that board. 705bf9e0ff8Skettenis */ 706bf9e0ff8Skettenis node = OF_finddevice("/"); 707bf9e0ff8Skettenis if (OF_is_compatible(node, "rockchip,rk3288-tinker")) { 708bf9e0ff8Skettenis uint32_t idx; 709bf9e0ff8Skettenis 710bf9e0ff8Skettenis /* Run at 1.2 GHz. */ 711bf9e0ff8Skettenis idx = RK3288_ARMCLK; 712bf9e0ff8Skettenis rk3288_set_frequency(sc, &idx, 1200000000); 713bf9e0ff8Skettenis } 714b1151de3Skettenis 715b1151de3Skettenis sc->sc_clocks = rk3288_clocks; 716bf9e0ff8Skettenis } 717bf9e0ff8Skettenis 718bd903cc4Skettenis uint32_t 719bd903cc4Skettenis rk3288_get_pll(struct rkclock_softc *sc, bus_size_t base) 720bd903cc4Skettenis { 721bd903cc4Skettenis uint32_t clkod, clkr, clkf; 722bd903cc4Skettenis uint32_t reg; 723bd903cc4Skettenis 724bd903cc4Skettenis reg = HREAD4(sc, base); 725bf9e0ff8Skettenis clkod = (reg & RK3288_CRU_PLL_CLKOD_MASK) >> 726bf9e0ff8Skettenis RK3288_CRU_PLL_CLKOD_SHIFT; 727bf9e0ff8Skettenis clkr = (reg & RK3288_CRU_PLL_CLKR_MASK) >> 728bf9e0ff8Skettenis RK3288_CRU_PLL_CLKR_SHIFT; 729bd903cc4Skettenis reg = HREAD4(sc, base + 4); 730bf9e0ff8Skettenis clkf = (reg & RK3288_CRU_PLL_CLKF_MASK) >> 731bf9e0ff8Skettenis RK3288_CRU_PLL_CLKF_SHIFT; 732bd903cc4Skettenis return 24000000ULL * (clkf + 1) / (clkr + 1) / (clkod + 1); 733bd903cc4Skettenis } 734bd903cc4Skettenis 735bf9e0ff8Skettenis int 736bf9e0ff8Skettenis rk3288_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 737bf9e0ff8Skettenis { 738bf9e0ff8Skettenis int shift = 4 * (base / RK3288_CRU_CPLL_CON(0)); 739bf9e0ff8Skettenis uint32_t no, nr, nf; 740bf9e0ff8Skettenis 741bf9e0ff8Skettenis /* 742bf9e0ff8Skettenis * It is not clear whether all combinations of the clock 743bf9e0ff8Skettenis * dividers result in a stable clock. Therefore this function 744bf9e0ff8Skettenis * only supports a limited set of PLL clock rates. For now 745bf9e0ff8Skettenis * this set covers all the CPU frequencies supported by the 746bf9e0ff8Skettenis * Linux kernel. 747bf9e0ff8Skettenis */ 748bf9e0ff8Skettenis switch (freq) { 749bf9e0ff8Skettenis case 1800000000: 750bf9e0ff8Skettenis case 1704000000: 751bf9e0ff8Skettenis case 1608000000: 752bf9e0ff8Skettenis case 1512000000: 753bf9e0ff8Skettenis case 1488000000: 754bf9e0ff8Skettenis case 1416000000: 755bf9e0ff8Skettenis case 1200000000: 756bf9e0ff8Skettenis nr = no = 1; 757bf9e0ff8Skettenis break; 758bf9e0ff8Skettenis case 1008000000: 759bf9e0ff8Skettenis case 816000000: 760bf9e0ff8Skettenis case 696000000: 761bf9e0ff8Skettenis case 600000000: 762bf9e0ff8Skettenis nr = 1; no = 2; 763bf9e0ff8Skettenis break; 764bf9e0ff8Skettenis case 408000000: 765bf9e0ff8Skettenis case 312000000: 766bf9e0ff8Skettenis nr = 1; no = 4; 767bf9e0ff8Skettenis break; 768bf9e0ff8Skettenis case 216000000: 769bf9e0ff8Skettenis case 126000000: 770bf9e0ff8Skettenis nr = 1; no = 8; 771bf9e0ff8Skettenis break; 772bf9e0ff8Skettenis default: 7739822ab30Skettenis printf("%s: %u Hz\n", __func__, freq); 774bf9e0ff8Skettenis return -1; 775bf9e0ff8Skettenis } 776bf9e0ff8Skettenis 777bf9e0ff8Skettenis /* Calculate feedback divider. */ 778bf9e0ff8Skettenis nf = freq * nr * no / 24000000; 779bf9e0ff8Skettenis 780bf9e0ff8Skettenis /* 781bf9e0ff8Skettenis * Select slow mode to guarantee a stable clock while we're 782bf9e0ff8Skettenis * adjusting the PLL. 783bf9e0ff8Skettenis */ 784bf9e0ff8Skettenis HWRITE4(sc, RK3288_CRU_MODE_CON, 785bf9e0ff8Skettenis (RK3288_CRU_MODE_PLL_WORK_MODE_MASK << 16 | 786bf9e0ff8Skettenis RK3288_CRU_MODE_PLL_WORK_MODE_SLOW) << shift); 787bf9e0ff8Skettenis 788bf9e0ff8Skettenis /* Assert reset. */ 789bf9e0ff8Skettenis HWRITE4(sc, base + 0x000c, 790bf9e0ff8Skettenis RK3288_CRU_PLL_RESET << 16 | RK3288_CRU_PLL_RESET); 791bf9e0ff8Skettenis 792bf9e0ff8Skettenis /* Set PLL rate. */ 793bf9e0ff8Skettenis HWRITE4(sc, base + 0x0000, 794bf9e0ff8Skettenis RK3288_CRU_PLL_CLKR_MASK << 16 | 795bf9e0ff8Skettenis (nr - 1) << RK3288_CRU_PLL_CLKR_SHIFT | 796bf9e0ff8Skettenis RK3288_CRU_PLL_CLKOD_MASK << 16 | 797bf9e0ff8Skettenis (no - 1) << RK3288_CRU_PLL_CLKOD_SHIFT); 798bf9e0ff8Skettenis HWRITE4(sc, base + 0x0004, 799bf9e0ff8Skettenis RK3288_CRU_PLL_CLKF_MASK << 16 | 800bf9e0ff8Skettenis (nf - 1) << RK3288_CRU_PLL_CLKF_SHIFT); 801bf9e0ff8Skettenis 802bf9e0ff8Skettenis /* Deassert reset and wait. */ 803bf9e0ff8Skettenis HWRITE4(sc, base + 0x000c, 804bf9e0ff8Skettenis RK3288_CRU_PLL_RESET << 16); 805bf9e0ff8Skettenis delay((nr * 500 / 24) + 1); 806bf9e0ff8Skettenis 807bf9e0ff8Skettenis /* Switch back to normal mode. */ 808bf9e0ff8Skettenis HWRITE4(sc, RK3288_CRU_MODE_CON, 809bf9e0ff8Skettenis (RK3288_CRU_MODE_PLL_WORK_MODE_MASK << 16 | 810bf9e0ff8Skettenis RK3288_CRU_MODE_PLL_WORK_MODE_NORMAL) << shift); 811bf9e0ff8Skettenis 812bf9e0ff8Skettenis return 0; 813bf9e0ff8Skettenis } 814bf9e0ff8Skettenis 815bd903cc4Skettenis uint32_t 816bd903cc4Skettenis rk3288_get_frequency(void *cookie, uint32_t *cells) 817bd903cc4Skettenis { 818bd903cc4Skettenis struct rkclock_softc *sc = cookie; 819bd903cc4Skettenis uint32_t idx = cells[0]; 8204764d29aSjsg uint32_t reg, mux, div_con, aclk_div_con; 821bd903cc4Skettenis 822bd903cc4Skettenis switch (idx) { 823227c6ee3Skettenis case RK3288_PLL_APLL: 824227c6ee3Skettenis return rk3288_get_pll(sc, RK3288_CRU_APLL_CON(0)); 825bd903cc4Skettenis case RK3288_PLL_CPLL: 826bd903cc4Skettenis return rk3288_get_pll(sc, RK3288_CRU_CPLL_CON(0)); 827bd903cc4Skettenis case RK3288_PLL_GPLL: 828bd903cc4Skettenis return rk3288_get_pll(sc, RK3288_CRU_GPLL_CON(0)); 82972f108a7Skettenis case RK3288_PLL_NPLL: 83072f108a7Skettenis return rk3288_get_pll(sc, RK3288_CRU_NPLL_CON(0)); 831227c6ee3Skettenis case RK3288_ARMCLK: 832227c6ee3Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(0)); 833227c6ee3Skettenis mux = (reg >> 15) & 0x1; 834227c6ee3Skettenis div_con = (reg >> 8) & 0x1f; 835bf9e0ff8Skettenis idx = (mux == 0) ? RK3288_PLL_APLL : RK3288_PLL_GPLL; 836227c6ee3Skettenis return rk3288_get_frequency(sc, &idx) / (div_con + 1); 837b1151de3Skettenis case RK3288_XIN24M: 838b1151de3Skettenis return 24000000; 839bd903cc4Skettenis case RK3288_CLK_UART0: 840bd903cc4Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(13)); 841bd903cc4Skettenis mux = (reg >> 8) & 0x3; 842bd903cc4Skettenis div_con = reg & 0x7f; 843bd903cc4Skettenis if (mux == 2) 844bd903cc4Skettenis return 24000000 / (div_con + 1); 845bd903cc4Skettenis break; 846bd903cc4Skettenis case RK3288_CLK_UART1: 847bd903cc4Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(14)); 848bd903cc4Skettenis mux = (reg >> 8) & 0x3; 849bd903cc4Skettenis div_con = reg & 0x7f; 850bd903cc4Skettenis if (mux == 2) 851bd903cc4Skettenis return 24000000 / (div_con + 1); 852bd903cc4Skettenis break; 853bd903cc4Skettenis case RK3288_CLK_UART2: 854bd903cc4Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(15)); 855bd903cc4Skettenis mux = (reg >> 8) & 0x3; 856bd903cc4Skettenis div_con = reg & 0x7f; 857bd903cc4Skettenis if (mux == 2) 858bd903cc4Skettenis return 24000000 / (div_con + 1); 859bd903cc4Skettenis break; 860bd903cc4Skettenis case RK3288_CLK_UART3: 861bd903cc4Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(16)); 862bd903cc4Skettenis mux = (reg >> 8) & 0x3; 863bd903cc4Skettenis div_con = reg & 0x7f; 864bd903cc4Skettenis if (mux == 2) 865bd903cc4Skettenis return 24000000 / (div_con + 1); 866bd903cc4Skettenis break; 867bd903cc4Skettenis case RK3288_CLK_UART4: 868bd903cc4Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(3)); 869bd903cc4Skettenis mux = (reg >> 8) & 0x3; 870bd903cc4Skettenis div_con = reg & 0x7f; 871bd903cc4Skettenis if (mux == 2) 872bd903cc4Skettenis return 24000000 / (div_con + 1); 873bd903cc4Skettenis break; 87472f108a7Skettenis case RK3288_CLK_MAC: 87572f108a7Skettenis reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(21)); 87672f108a7Skettenis if (reg & 0x10) 877ab8e3451Sderaadt return 125000000; 87872f108a7Skettenis mux = (reg >> 0) & 0x3; 87972f108a7Skettenis div_con = (reg >> 8) & 0x1f; 88072f108a7Skettenis switch (mux) { 88172f108a7Skettenis case 0: 88272f108a7Skettenis idx = RK3288_PLL_NPLL; 88372f108a7Skettenis break; 88472f108a7Skettenis case 1: 88572f108a7Skettenis idx = RK3288_PLL_CPLL; 88672f108a7Skettenis break; 88772f108a7Skettenis case 2: 88872f108a7Skettenis idx = RK3288_PLL_GPLL; 88972f108a7Skettenis break; 89072f108a7Skettenis default: 89172f108a7Skettenis return 0; 89272f108a7Skettenis } 89372f108a7Skettenis return rk3288_get_frequency(sc, &idx) / (div_con + 1); 8944764d29aSjsg case RK3288_PCLK_I2C0: 8954764d29aSjsg case RK3288_PCLK_I2C2: 8964764d29aSjsg reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(1)); 8974764d29aSjsg mux = (reg >> 15) & 0x1; 8984764d29aSjsg /* pd_bus_pclk_div_con */ 8994764d29aSjsg div_con = (reg >> 12) & 0x7; 9004764d29aSjsg if (mux == 1) 9014764d29aSjsg idx = RK3288_PLL_GPLL; 9024764d29aSjsg else 9034764d29aSjsg idx = RK3288_PLL_CPLL; 9044764d29aSjsg return rk3288_get_frequency(sc, &idx) / (div_con + 1); 9054764d29aSjsg case RK3288_PCLK_I2C1: 9064764d29aSjsg case RK3288_PCLK_I2C3: 9074764d29aSjsg case RK3288_PCLK_I2C4: 9084764d29aSjsg case RK3288_PCLK_I2C5: 9094764d29aSjsg reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(10)); 9104764d29aSjsg mux = (reg >> 15) & 0x1; 9114764d29aSjsg /* peri_pclk_div_con */ 9124764d29aSjsg div_con = (reg >> 12) & 0x3; 9134764d29aSjsg /* peri_aclk_div_con */ 9144764d29aSjsg aclk_div_con = reg & 0xf; 9154764d29aSjsg if (mux == 1) 9164764d29aSjsg idx = RK3288_PLL_GPLL; 9174764d29aSjsg else 9184764d29aSjsg idx = RK3288_PLL_CPLL; 9194764d29aSjsg return (rk3288_get_frequency(sc, &idx) / (aclk_div_con + 1)) >> 9204764d29aSjsg div_con; 921bd903cc4Skettenis default: 922bd903cc4Skettenis break; 923bd903cc4Skettenis } 924bd903cc4Skettenis 925b1151de3Skettenis return rkclock_get_frequency(sc, idx); 926bd903cc4Skettenis } 927bd903cc4Skettenis 928bd903cc4Skettenis int 929bd903cc4Skettenis rk3288_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 930bd903cc4Skettenis { 931bf9e0ff8Skettenis struct rkclock_softc *sc = cookie; 932bd903cc4Skettenis uint32_t idx = cells[0]; 933bf9e0ff8Skettenis int error; 934bf9e0ff8Skettenis 935bf9e0ff8Skettenis switch (idx) { 936bf9e0ff8Skettenis case RK3288_PLL_APLL: 937bf9e0ff8Skettenis return rk3288_set_pll(sc, RK3288_CRU_APLL_CON(0), freq); 938bf9e0ff8Skettenis case RK3288_ARMCLK: 939bf9e0ff8Skettenis idx = RK3288_PLL_APLL; 940bf9e0ff8Skettenis error = rk3288_set_frequency(sc, &idx, freq); 941bf9e0ff8Skettenis if (error == 0) { 942bf9e0ff8Skettenis HWRITE4(sc, RK3288_CRU_CLKSEL_CON(0), 943bf9e0ff8Skettenis ((1 << 15) | (0x1f << 8)) << 16); 944bf9e0ff8Skettenis } 945bf9e0ff8Skettenis return error; 946b1151de3Skettenis default: 947b1151de3Skettenis break; 948bf9e0ff8Skettenis } 949bd903cc4Skettenis 950b1151de3Skettenis return rkclock_set_frequency(sc, idx, freq); 951bd903cc4Skettenis } 952bd903cc4Skettenis 953bd903cc4Skettenis void 954bd903cc4Skettenis rk3288_enable(void *cookie, uint32_t *cells, int on) 955bd903cc4Skettenis { 956bd903cc4Skettenis uint32_t idx = cells[0]; 957bd903cc4Skettenis 958bd903cc4Skettenis switch (idx) { 959bd903cc4Skettenis case RK3288_CLK_SDMMC: 96049b48721Skettenis case RK3288_CLK_TSADC: 961bd903cc4Skettenis case RK3288_CLK_UART0: 962bd903cc4Skettenis case RK3288_CLK_UART1: 963bd903cc4Skettenis case RK3288_CLK_UART2: 964bd903cc4Skettenis case RK3288_CLK_UART3: 965bd903cc4Skettenis case RK3288_CLK_UART4: 966e721b2d9Skettenis case RK3288_CLK_MAC_RX: 967e721b2d9Skettenis case RK3288_CLK_MAC_TX: 968bd903cc4Skettenis case RK3288_CLK_SDMMC_DRV: 969bd903cc4Skettenis case RK3288_CLK_SDMMC_SAMPLE: 970e721b2d9Skettenis case RK3288_CLK_MAC: 971e721b2d9Skettenis case RK3288_ACLK_GMAC: 972e721b2d9Skettenis case RK3288_PCLK_GMAC: 9734764d29aSjsg case RK3288_PCLK_I2C0: 9744764d29aSjsg case RK3288_PCLK_I2C1: 9754764d29aSjsg case RK3288_PCLK_I2C2: 9764764d29aSjsg case RK3288_PCLK_I2C3: 9774764d29aSjsg case RK3288_PCLK_I2C4: 9784764d29aSjsg case RK3288_PCLK_I2C5: 97949b48721Skettenis case RK3288_PCLK_TSADC: 980bd903cc4Skettenis case RK3288_HCLK_HOST0: 981bd903cc4Skettenis case RK3288_HCLK_SDMMC: 982bd903cc4Skettenis /* Enabled by default. */ 983bd903cc4Skettenis break; 984bd903cc4Skettenis default: 985bd903cc4Skettenis printf("%s: 0x%08x\n", __func__, idx); 986bd903cc4Skettenis break; 987bd903cc4Skettenis } 988bd903cc4Skettenis } 989bd903cc4Skettenis 990bd903cc4Skettenis void 991bd903cc4Skettenis rk3288_reset(void *cookie, uint32_t *cells, int on) 992bd903cc4Skettenis { 99349b48721Skettenis struct rkclock_softc *sc = cookie; 994bd903cc4Skettenis uint32_t idx = cells[0]; 99549b48721Skettenis uint32_t mask = (1 << (idx % 16)); 996bd903cc4Skettenis 99749b48721Skettenis HWRITE4(sc, RK3288_CRU_SOFTRST_CON(idx / 16), 99849b48721Skettenis mask << 16 | (on ? mask : 0)); 999bd903cc4Skettenis } 1000bd903cc4Skettenis 1001bd903cc4Skettenis /* 10021235808cSjmatthew * Rockchip RK3308 10031235808cSjmatthew */ 10041235808cSjmatthew 100537c734d3Snaddy const struct rkclock rk3308_clocks[] = { 10061235808cSjmatthew { 10071235808cSjmatthew RK3308_CLK_RTC32K, RK3308_CRU_CLKSEL_CON(2), 10081235808cSjmatthew SEL(10, 9), 0, 10091235808cSjmatthew { RK3308_PLL_VPLL0, RK3308_PLL_VPLL1 } 10101235808cSjmatthew }, 10111235808cSjmatthew { 10121235808cSjmatthew RK3308_CLK_UART0, RK3308_CRU_CLKSEL_CON(10), 10131235808cSjmatthew SEL(15, 13), DIV(4, 0), 10141235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10151235808cSjmatthew RK3308_USB480M, RK3308_XIN24M } 10161235808cSjmatthew }, 10171235808cSjmatthew { 10181235808cSjmatthew RK3308_CLK_UART1, RK3308_CRU_CLKSEL_CON(13), 10191235808cSjmatthew SEL(15, 13), DIV(4, 0), 10201235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10211235808cSjmatthew RK3308_USB480M, RK3308_XIN24M } 10221235808cSjmatthew }, 10231235808cSjmatthew { 10241235808cSjmatthew RK3308_CLK_UART2, RK3308_CRU_CLKSEL_CON(16), 10251235808cSjmatthew SEL(15, 13), DIV(4, 0), 10261235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10271235808cSjmatthew RK3308_USB480M, RK3308_XIN24M } 10281235808cSjmatthew }, 10291235808cSjmatthew { 10301235808cSjmatthew RK3308_CLK_UART3, RK3308_CRU_CLKSEL_CON(19), 10311235808cSjmatthew SEL(15, 13), DIV(4, 0), 10321235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10331235808cSjmatthew RK3308_USB480M, RK3308_XIN24M } 10341235808cSjmatthew }, 10351235808cSjmatthew { 10361235808cSjmatthew RK3308_CLK_UART4, RK3308_CRU_CLKSEL_CON(22), 10371235808cSjmatthew SEL(15, 13), DIV(4, 0), 10381235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10391235808cSjmatthew RK3308_USB480M, RK3308_XIN24M } 10401235808cSjmatthew }, 10411235808cSjmatthew { 10421235808cSjmatthew RK3308_CLK_PWM0, RK3308_CRU_CLKSEL_CON(29), 10431235808cSjmatthew SEL(15, 14), DIV(6, 0), 10441235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_XIN24M } 10451235808cSjmatthew }, 10461235808cSjmatthew { 104717449d5cSkettenis RK3308_CLK_SPI0, RK3308_CRU_CLKSEL_CON(30), 104817449d5cSkettenis SEL(15, 14), DIV(6, 0), 104917449d5cSkettenis { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_XIN24M } 105017449d5cSkettenis }, 105117449d5cSkettenis { 105217449d5cSkettenis RK3308_CLK_SPI1, RK3308_CRU_CLKSEL_CON(31), 105317449d5cSkettenis SEL(15, 14), DIV(6, 0), 105417449d5cSkettenis { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_XIN24M } 105517449d5cSkettenis }, 105617449d5cSkettenis { 105717449d5cSkettenis RK3308_CLK_SPI2, RK3308_CRU_CLKSEL_CON(32), 105817449d5cSkettenis SEL(15, 14), DIV(6, 0), 105917449d5cSkettenis { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_XIN24M } 106017449d5cSkettenis }, 106117449d5cSkettenis { 10621235808cSjmatthew RK3308_CLK_TSADC, RK3308_CRU_CLKSEL_CON(33), 10631235808cSjmatthew 0, DIV(10, 0), 10641235808cSjmatthew { RK3308_XIN24M } 10651235808cSjmatthew }, 10661235808cSjmatthew { 10671235808cSjmatthew RK3308_CLK_SARADC, RK3308_CRU_CLKSEL_CON(34), 10681235808cSjmatthew 0, DIV(10, 0), 10691235808cSjmatthew { RK3308_XIN24M } 10701235808cSjmatthew }, 10711235808cSjmatthew { 10721235808cSjmatthew RK3308_CLK_CRYPTO, RK3308_CRU_CLKSEL_CON(7), 10731235808cSjmatthew SEL(7, 6), DIV(4, 0), 10741235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 0 } 10751235808cSjmatthew }, 10761235808cSjmatthew { 10771235808cSjmatthew RK3308_CLK_CRYPTO_APK, RK3308_CRU_CLKSEL_CON(7), 10781235808cSjmatthew SEL(15, 14), DIV(12, 8), 10791235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 0 } 10801235808cSjmatthew }, 10811235808cSjmatthew { 10821235808cSjmatthew RK3308_CLK_SDMMC, RK3308_CRU_CLKSEL_CON(39), 10831235808cSjmatthew SEL(9, 8), DIV(7, 0), 10841235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10851235808cSjmatthew RK3308_XIN24M } 10861235808cSjmatthew }, 10871235808cSjmatthew { 10881235808cSjmatthew RK3308_CLK_SDIO, RK3308_CRU_CLKSEL_CON(40), 10891235808cSjmatthew SEL(9, 8), DIV(7, 0), 10901235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10911235808cSjmatthew RK3308_XIN24M } 10921235808cSjmatthew }, 10931235808cSjmatthew { 10941235808cSjmatthew RK3308_CLK_EMMC, RK3308_CRU_CLKSEL_CON(41), 10951235808cSjmatthew SEL(9, 8), DIV(7, 0), 10961235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 10971235808cSjmatthew RK3308_XIN24M } 10981235808cSjmatthew }, 10991235808cSjmatthew { 11001235808cSjmatthew RK3308_CLK_MAC_SRC, RK3308_CRU_CLKSEL_CON(43), 11011235808cSjmatthew SEL(7, 6), DIV(4, 0), 11021235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 0 } 11031235808cSjmatthew }, 11041235808cSjmatthew { 11051235808cSjmatthew RK3308_CLK_MAC, RK3308_CRU_CLKSEL_CON(43), 11061235808cSjmatthew SEL(14, 13), 0, 11071235808cSjmatthew { RK3308_CLK_MAC_SRC, 0 }, 11081235808cSjmatthew SET_PARENT 11091235808cSjmatthew }, 11101235808cSjmatthew { 11111235808cSjmatthew RK3308_ACLK_PERI_SRC, RK3308_CRU_CLKSEL_CON(36), 11121235808cSjmatthew SEL(7, 6), 0, 11131235808cSjmatthew { RK3308_PLL_DPLL, RK3308_PLL_VPLL0, RK3308_PLL_VPLL1, 0 } 11141235808cSjmatthew }, 11151235808cSjmatthew { 11161235808cSjmatthew RK3308_PCLK_PERI, RK3308_CRU_CLKSEL_CON(37), 11171235808cSjmatthew 0, DIV(12, 8), 11181235808cSjmatthew { RK3308_ACLK_PERI_SRC } 11191235808cSjmatthew }, 11201235808cSjmatthew { 11211235808cSjmatthew RK3308_PCLK_MAC, 0, 0, 0, 11221235808cSjmatthew { RK3308_PCLK_PERI } 11231235808cSjmatthew }, 11241235808cSjmatthew 11251235808cSjmatthew { 11261235808cSjmatthew /* Sentinel */ 11271235808cSjmatthew } 11281235808cSjmatthew }; 11291235808cSjmatthew 11301235808cSjmatthew void 11311235808cSjmatthew rk3308_init(struct rkclock_softc *sc) 11321235808cSjmatthew { 11331235808cSjmatthew int i; 11341235808cSjmatthew 11351235808cSjmatthew /* The code below assumes all clocks are enabled. Check this!. */ 11361235808cSjmatthew for (i = 0; i <= 14; i++) { 11371235808cSjmatthew if (HREAD4(sc, RK3308_CRU_CLKGATE_CON(i)) != 0x00000000) { 11381235808cSjmatthew printf("CRU_CLKGATE_CON%d: 0x%08x\n", i, 11391235808cSjmatthew HREAD4(sc, RK3308_CRU_CLKGATE_CON(i))); 11401235808cSjmatthew } 11411235808cSjmatthew } 11421235808cSjmatthew sc->sc_clocks = rk3308_clocks; 11431235808cSjmatthew } 11441235808cSjmatthew 11451235808cSjmatthew uint32_t 11461235808cSjmatthew rk3308_armclk_parent(uint32_t mux) 11471235808cSjmatthew { 11481235808cSjmatthew switch (mux) { 11491235808cSjmatthew case 0: 11501235808cSjmatthew return RK3308_PLL_APLL; 11511235808cSjmatthew case 1: 11521235808cSjmatthew return RK3308_PLL_VPLL0; 11531235808cSjmatthew case 2: 11541235808cSjmatthew return RK3308_PLL_VPLL1; 11551235808cSjmatthew } 11561235808cSjmatthew 11571235808cSjmatthew return 0; 11581235808cSjmatthew } 11591235808cSjmatthew 11601235808cSjmatthew uint32_t 11611235808cSjmatthew rk3308_get_armclk(struct rkclock_softc *sc) 11621235808cSjmatthew { 11631235808cSjmatthew uint32_t reg, mux, div_con; 11641235808cSjmatthew uint32_t idx; 11651235808cSjmatthew 11661235808cSjmatthew reg = HREAD4(sc, RK3308_CRU_CLKSEL_CON(0)); 11671235808cSjmatthew mux = (reg & RK3308_CRU_CORE_CLK_PLL_SEL_MASK) >> 11681235808cSjmatthew RK3308_CRU_CORE_CLK_PLL_SEL_SHIFT; 11691235808cSjmatthew div_con = (reg & RK3308_CRU_CLK_CORE_DIV_CON_MASK) >> 11701235808cSjmatthew RK3308_CRU_CLK_CORE_DIV_CON_SHIFT; 11711235808cSjmatthew idx = rk3308_armclk_parent(mux); 11721235808cSjmatthew 11731235808cSjmatthew return rk3308_get_frequency(sc, &idx) / (div_con + 1); 11741235808cSjmatthew } 11751235808cSjmatthew 11761235808cSjmatthew int 11771235808cSjmatthew rk3308_set_armclk(struct rkclock_softc *sc, uint32_t freq) 11781235808cSjmatthew { 11791235808cSjmatthew uint32_t reg, mux; 11801235808cSjmatthew uint32_t old_freq, div; 11811235808cSjmatthew uint32_t idx; 11821235808cSjmatthew 11831235808cSjmatthew old_freq = rk3308_get_armclk(sc); 11841235808cSjmatthew if (freq == old_freq) 11851235808cSjmatthew return 0; 11861235808cSjmatthew 11871235808cSjmatthew reg = HREAD4(sc, RK3308_CRU_CLKSEL_CON(0)); 11881235808cSjmatthew mux = (reg & RK3308_CRU_CORE_CLK_PLL_SEL_MASK) >> 11891235808cSjmatthew RK3308_CRU_CORE_CLK_PLL_SEL_SHIFT; 11901235808cSjmatthew 11911235808cSjmatthew /* Keep the pclk_dbg clock at or below 300 MHz. */ 11921235808cSjmatthew div = 1; 11931235808cSjmatthew while (freq / (div + 1) > 300000000) 11941235808cSjmatthew div++; 11951235808cSjmatthew /* and make sure we use an odd divider. */ 11961235808cSjmatthew if ((div % 2) == 0) 11971235808cSjmatthew div++; 11981235808cSjmatthew 11991235808cSjmatthew /* When ramping up, set clock dividers first. */ 12001235808cSjmatthew if (freq > old_freq) { 12011235808cSjmatthew HWRITE4(sc, RK3308_CRU_CLKSEL_CON(0), 12021235808cSjmatthew RK3308_CRU_CLK_CORE_DIV_CON_MASK << 16 | 12031235808cSjmatthew 0 << RK3308_CRU_CLK_CORE_DIV_CON_SHIFT | 12041235808cSjmatthew RK3308_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 12051235808cSjmatthew 1 << RK3308_CRU_ACLK_CORE_DIV_CON_SHIFT | 12061235808cSjmatthew RK3308_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 12071235808cSjmatthew div << RK3308_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 12081235808cSjmatthew } 12091235808cSjmatthew 12101235808cSjmatthew /* We always use VPLL1 and force the switch below if needed. */ 12111235808cSjmatthew idx = RK3308_PLL_VPLL1; 12121235808cSjmatthew rk3308_set_frequency(sc, &idx, freq); 12131235808cSjmatthew 12141235808cSjmatthew /* When ramping down, set clock dividers last. */ 12151235808cSjmatthew if (freq < old_freq || mux != 2) { 12161235808cSjmatthew HWRITE4(sc, RK3308_CRU_CLKSEL_CON(0), 12171235808cSjmatthew RK3308_CRU_CORE_CLK_PLL_SEL_MASK << 16 | 12181235808cSjmatthew 2 << RK3308_CRU_CORE_CLK_PLL_SEL_SHIFT | 12191235808cSjmatthew RK3308_CRU_CLK_CORE_DIV_CON_MASK << 16 | 12201235808cSjmatthew 0 << RK3308_CRU_CLK_CORE_DIV_CON_SHIFT | 12211235808cSjmatthew RK3308_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 12221235808cSjmatthew 1 << RK3308_CRU_ACLK_CORE_DIV_CON_SHIFT | 12231235808cSjmatthew RK3308_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 12241235808cSjmatthew div << RK3308_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 12251235808cSjmatthew } 12261235808cSjmatthew 12271235808cSjmatthew return 0; 12281235808cSjmatthew } 12291235808cSjmatthew 12301235808cSjmatthew uint32_t 12311235808cSjmatthew rk3308_get_pll(struct rkclock_softc *sc, bus_size_t base) 12321235808cSjmatthew { 12331235808cSjmatthew uint32_t fbdiv, postdiv1, postdiv2, refdiv; 12341235808cSjmatthew uint32_t dsmpd, fracdiv; 12351235808cSjmatthew uint64_t frac = 0; 12361235808cSjmatthew uint32_t reg; 12371235808cSjmatthew 12381235808cSjmatthew reg = HREAD4(sc, base + 0x0000); 12391235808cSjmatthew postdiv1 = (reg & RK3308_CRU_PLL_POSTDIV1_MASK) >> 12401235808cSjmatthew RK3308_CRU_PLL_POSTDIV1_SHIFT; 12411235808cSjmatthew fbdiv = (reg & RK3308_CRU_PLL_FBDIV_MASK) >> 12421235808cSjmatthew RK3308_CRU_PLL_FBDIV_SHIFT; 12431235808cSjmatthew reg = HREAD4(sc, base + 0x0004); 12441235808cSjmatthew dsmpd = (reg & RK3308_CRU_PLL_DSMPD); 12451235808cSjmatthew postdiv2 = (reg & RK3308_CRU_PLL_POSTDIV2_MASK) >> 12461235808cSjmatthew RK3308_CRU_PLL_POSTDIV2_SHIFT; 12471235808cSjmatthew refdiv = (reg & RK3308_CRU_PLL_REFDIV_MASK) >> 12481235808cSjmatthew RK3308_CRU_PLL_REFDIV_SHIFT; 12491235808cSjmatthew reg = HREAD4(sc, base + 0x0008); 12501235808cSjmatthew fracdiv = (reg & RK3308_CRU_PLL_FRACDIV_MASK) >> 12511235808cSjmatthew RK3308_CRU_PLL_FRACDIV_SHIFT; 12521235808cSjmatthew 12531235808cSjmatthew if (dsmpd == 0) 12541235808cSjmatthew frac = (24000000ULL * fracdiv / refdiv) >> 24; 12551235808cSjmatthew return ((24000000ULL * fbdiv / refdiv) + frac) / postdiv1 / postdiv2; 12561235808cSjmatthew } 12571235808cSjmatthew 12581235808cSjmatthew int 12591235808cSjmatthew rk3308_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 12601235808cSjmatthew { 12611235808cSjmatthew uint32_t fbdiv, postdiv1, postdiv2, refdiv; 12621235808cSjmatthew int mode_shift = -1; 12631235808cSjmatthew 12641235808cSjmatthew switch (base) { 12651235808cSjmatthew case RK3308_CRU_APLL_CON(0): 12661235808cSjmatthew mode_shift = 0; 12671235808cSjmatthew break; 12681235808cSjmatthew case RK3308_CRU_DPLL_CON(0): 12691235808cSjmatthew mode_shift = 2; 12701235808cSjmatthew break; 12711235808cSjmatthew case RK3308_CRU_VPLL0_CON(0): 12721235808cSjmatthew mode_shift = 4; 12731235808cSjmatthew break; 12741235808cSjmatthew case RK3308_CRU_VPLL1_CON(0): 12751235808cSjmatthew mode_shift = 6; 12761235808cSjmatthew break; 12771235808cSjmatthew } 12781235808cSjmatthew KASSERT(mode_shift != -1); 12791235808cSjmatthew 12801235808cSjmatthew /* 12811235808cSjmatthew * It is not clear whether all combinations of the clock 12821235808cSjmatthew * dividers result in a stable clock. Therefore this function 12831235808cSjmatthew * only supports a limited set of PLL clock rates. For now 12841235808cSjmatthew * this set covers all the CPU frequencies supported by the 12851235808cSjmatthew * Linux kernel. 12861235808cSjmatthew */ 12871235808cSjmatthew switch (freq) { 12881235808cSjmatthew case 1608000000U: 12891235808cSjmatthew case 1584000000U: 12901235808cSjmatthew case 1560000000U: 12911235808cSjmatthew case 1536000000U: 12921235808cSjmatthew case 1512000000U: 12931235808cSjmatthew case 1488000000U: 12941235808cSjmatthew case 1464000000U: 12951235808cSjmatthew case 1440000000U: 12961235808cSjmatthew case 1416000000U: 12971235808cSjmatthew case 1392000000U: 12981235808cSjmatthew case 1368000000U: 12991235808cSjmatthew case 1344000000U: 13001235808cSjmatthew case 1320000000U: 13011235808cSjmatthew case 1296000000U: 13021235808cSjmatthew case 1272000000U: 13031235808cSjmatthew case 1248000000U: 13041235808cSjmatthew case 1200000000U: 13051235808cSjmatthew case 1104000000U: 13061235808cSjmatthew postdiv1 = postdiv2 = refdiv = 1; 13071235808cSjmatthew break; 13081235808cSjmatthew case 1188000000U: 13091235808cSjmatthew refdiv = 2; postdiv1 = postdiv2 = 1; 13101235808cSjmatthew break; 13111235808cSjmatthew case 1100000000U: 13121235808cSjmatthew refdiv = 12; postdiv1 = postdiv2 = 1; 13131235808cSjmatthew break; 13141235808cSjmatthew case 1000000000U: 13151235808cSjmatthew refdiv = 6; postdiv1 = postdiv2 = 1; 13161235808cSjmatthew break; 13171235808cSjmatthew case 1008000000U: 13181235808cSjmatthew case 984000000U: 13191235808cSjmatthew case 960000000U: 13201235808cSjmatthew case 936000000U: 13211235808cSjmatthew case 912000000U: 13221235808cSjmatthew case 888000000U: 13231235808cSjmatthew case 864000000U: 13241235808cSjmatthew case 840000000U: 13251235808cSjmatthew case 816000000U: 13261235808cSjmatthew case 696000000U: 13271235808cSjmatthew case 624000000U: 13281235808cSjmatthew postdiv1 = 2; postdiv2 = refdiv = 1; 13291235808cSjmatthew break; 13301235808cSjmatthew case 900000000U: 13311235808cSjmatthew refdiv = 4; postdiv1 = 2; postdiv2 = 1; 13321235808cSjmatthew break; 13331235808cSjmatthew case 800000000U: 13341235808cSjmatthew case 700000000U: 13351235808cSjmatthew case 500000000U: 13361235808cSjmatthew refdiv = 6; postdiv1 = 2; postdiv2 = 1; 13371235808cSjmatthew break; 13381235808cSjmatthew case 600000000U: 13391235808cSjmatthew case 504000000U: 13401235808cSjmatthew postdiv1 = 3; postdiv2 = refdiv = 1; 13411235808cSjmatthew break; 13421235808cSjmatthew case 594000000U: 13431235808cSjmatthew refdiv = 2; postdiv1 = 2; postdiv2 = 1; 13441235808cSjmatthew break; 13451235808cSjmatthew case 408000000U: 13461235808cSjmatthew case 312000000U: 13471235808cSjmatthew postdiv1 = postdiv2 = 2; refdiv = 1; 13481235808cSjmatthew break; 13491235808cSjmatthew case 216000000U: 13501235808cSjmatthew postdiv1 = 4; postdiv2 = 2; refdiv = 1; 13511235808cSjmatthew break; 13521235808cSjmatthew case 96000000U: 13531235808cSjmatthew postdiv1 = postdiv2 = 4; refdiv = 1; 13541235808cSjmatthew break; 13551235808cSjmatthew default: 13561235808cSjmatthew printf("%s: %u Hz\n", __func__, freq); 13571235808cSjmatthew return -1; 13581235808cSjmatthew } 13591235808cSjmatthew 13601235808cSjmatthew /* Calculate feedback divider. */ 13611235808cSjmatthew fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 13621235808cSjmatthew 13631235808cSjmatthew /* 13641235808cSjmatthew * Select slow mode to guarantee a stable clock while we're 13651235808cSjmatthew * adjusting the PLL. 13661235808cSjmatthew */ 13671235808cSjmatthew HWRITE4(sc, RK3308_CRU_CRU_MODE, 13681235808cSjmatthew (RK3308_CRU_CRU_MODE_MASK << 16 | 13691235808cSjmatthew RK3308_CRU_CRU_MODE_SLOW) << mode_shift); 13701235808cSjmatthew 13711235808cSjmatthew /* Set PLL rate. */ 13721235808cSjmatthew HWRITE4(sc, base + 0x0000, 13731235808cSjmatthew RK3308_CRU_PLL_POSTDIV1_MASK << 16 | 13741235808cSjmatthew postdiv1 << RK3308_CRU_PLL_POSTDIV1_SHIFT | 13751235808cSjmatthew RK3308_CRU_PLL_FBDIV_MASK << 16 | 13761235808cSjmatthew fbdiv << RK3308_CRU_PLL_FBDIV_SHIFT); 13771235808cSjmatthew HWRITE4(sc, base + 0x0004, 13781235808cSjmatthew RK3308_CRU_PLL_DSMPD << 16 | RK3308_CRU_PLL_DSMPD | 13791235808cSjmatthew RK3308_CRU_PLL_POSTDIV2_MASK << 16 | 13801235808cSjmatthew postdiv2 << RK3308_CRU_PLL_POSTDIV2_SHIFT | 13811235808cSjmatthew RK3308_CRU_PLL_REFDIV_MASK << 16 | 13821235808cSjmatthew refdiv << RK3308_CRU_PLL_REFDIV_SHIFT); 13831235808cSjmatthew 13841235808cSjmatthew /* Wait for PLL to stabilize. */ 13851235808cSjmatthew while ((HREAD4(sc, base + 0x0004) & RK3308_CRU_PLL_PLL_LOCK) == 0) 13861235808cSjmatthew delay(10); 13871235808cSjmatthew 13881235808cSjmatthew /* Switch back to normal mode. */ 13891235808cSjmatthew HWRITE4(sc, RK3308_CRU_CRU_MODE, 13901235808cSjmatthew (RK3308_CRU_CRU_MODE_MASK << 16 | 13911235808cSjmatthew RK3308_CRU_CRU_MODE_NORMAL) << mode_shift); 13921235808cSjmatthew 13931235808cSjmatthew return 0; 13941235808cSjmatthew } 13951235808cSjmatthew 13961235808cSjmatthew uint32_t 13971235808cSjmatthew rk3308_get_rtc32k(struct rkclock_softc *sc) 13981235808cSjmatthew { 13991235808cSjmatthew uint32_t reg, mux, pll, div_con; 14001235808cSjmatthew 14011235808cSjmatthew reg = HREAD4(sc, RK3308_CRU_CLKSEL_CON(2)); 14023f41a742Sjsg mux = (reg & 0x300) >> 8; 14031235808cSjmatthew if (mux != 3) { 14041235808cSjmatthew printf("%s: RTC32K not using clk_32k_div\n", __func__); 14051235808cSjmatthew return 0; 14061235808cSjmatthew } 14071235808cSjmatthew 14081235808cSjmatthew if ((reg >> 10) & 1) 14091235808cSjmatthew pll = RK3308_PLL_VPLL1; 14101235808cSjmatthew else 14111235808cSjmatthew pll = RK3308_PLL_VPLL0; 14121235808cSjmatthew 14131235808cSjmatthew div_con = HREAD4(sc, RK3308_CRU_CLKSEL_CON(4)) & 0xffff; 14141235808cSjmatthew return rk3308_get_frequency(sc, &pll) / (div_con + 1); 14151235808cSjmatthew } 14161235808cSjmatthew 14171235808cSjmatthew int 14181235808cSjmatthew rk3308_set_rtc32k(struct rkclock_softc *sc, uint32_t freq) 14191235808cSjmatthew { 142037c734d3Snaddy const struct rkclock *clk; 14211235808cSjmatthew uint32_t vpll0_freq, vpll1_freq, mux, div_con; 14221235808cSjmatthew 14231235808cSjmatthew clk = rkclock_lookup(sc, RK3308_CLK_RTC32K); 14241235808cSjmatthew vpll0_freq = rkclock_freq(sc, clk, 0, freq); 14251235808cSjmatthew vpll1_freq = rkclock_freq(sc, clk, 1, freq); 14261235808cSjmatthew mux = 0; 14271235808cSjmatthew freq = vpll0_freq; 14281235808cSjmatthew 14291235808cSjmatthew if ((vpll1_freq > vpll0_freq && vpll1_freq <= freq) || 14301235808cSjmatthew (vpll1_freq < vpll0_freq && vpll1_freq >= freq)) { 14311235808cSjmatthew mux = 1; 14321235808cSjmatthew freq = vpll1_freq; 14331235808cSjmatthew } 14341235808cSjmatthew 14351235808cSjmatthew div_con = rkclock_div_con(sc, clk, mux, freq); 14361235808cSjmatthew HWRITE4(sc, RK3308_CRU_CLKSEL_CON(2), 1 << 26 | (mux << 10)); 14371235808cSjmatthew HWRITE4(sc, RK3308_CRU_CLKSEL_CON(4), 0xffff0000 | div_con); 14381235808cSjmatthew return 0; 14391235808cSjmatthew } 14401235808cSjmatthew 14411235808cSjmatthew uint32_t 14421235808cSjmatthew rk3308_get_frequency(void *cookie, uint32_t *cells) 14431235808cSjmatthew { 14441235808cSjmatthew struct rkclock_softc *sc = cookie; 14451235808cSjmatthew uint32_t idx = cells[0]; 14461235808cSjmatthew 14471235808cSjmatthew switch (idx) { 14481235808cSjmatthew case RK3308_PLL_APLL: 14491235808cSjmatthew return rk3308_get_pll(sc, RK3308_CRU_APLL_CON(0)); 14501235808cSjmatthew case RK3308_PLL_DPLL: 14511235808cSjmatthew return rk3308_get_pll(sc, RK3308_CRU_DPLL_CON(0)); 14521235808cSjmatthew case RK3308_PLL_VPLL0: 14531235808cSjmatthew return rk3308_get_pll(sc, RK3308_CRU_VPLL0_CON(0)); 14541235808cSjmatthew case RK3308_PLL_VPLL1: 14551235808cSjmatthew return rk3308_get_pll(sc, RK3308_CRU_VPLL1_CON(0)); 14561235808cSjmatthew case RK3308_ARMCLK: 14571235808cSjmatthew return rk3308_get_armclk(sc); 14581235808cSjmatthew case RK3308_XIN24M: 14591235808cSjmatthew return 24000000; 14601235808cSjmatthew case RK3308_CLK_RTC32K: 14611235808cSjmatthew return rk3308_get_rtc32k(sc); 14621235808cSjmatthew 14631235808cSjmatthew /* 14641235808cSjmatthew * XXX The USB480M clock is external. Returning zero here will cause 14651235808cSjmatthew * it to be ignored for reparenting purposes. 14661235808cSjmatthew */ 14671235808cSjmatthew case RK3308_USB480M: 14681235808cSjmatthew return 0; 14691235808cSjmatthew default: 14701235808cSjmatthew break; 14711235808cSjmatthew } 14721235808cSjmatthew 14731235808cSjmatthew return rkclock_get_frequency(sc, idx); 14741235808cSjmatthew } 14751235808cSjmatthew 14761235808cSjmatthew int 14771235808cSjmatthew rk3308_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 14781235808cSjmatthew { 14791235808cSjmatthew struct rkclock_softc *sc = cookie; 14801235808cSjmatthew uint32_t idx = cells[0]; 14811235808cSjmatthew 14821235808cSjmatthew switch (idx) { 14831235808cSjmatthew case RK3308_PLL_APLL: 14841235808cSjmatthew return rk3308_set_pll(sc, RK3308_CRU_APLL_CON(0), freq); 14851235808cSjmatthew case RK3308_PLL_DPLL: 14861235808cSjmatthew return rk3308_set_pll(sc, RK3308_CRU_DPLL_CON(0), freq); 14871235808cSjmatthew case RK3308_PLL_VPLL0: 14881235808cSjmatthew return rk3308_set_pll(sc, RK3308_CRU_VPLL0_CON(0), freq); 14891235808cSjmatthew case RK3308_PLL_VPLL1: 14901235808cSjmatthew return rk3308_set_pll(sc, RK3308_CRU_VPLL1_CON(0), freq); 14911235808cSjmatthew case RK3308_ARMCLK: 14921235808cSjmatthew return rk3308_set_armclk(sc, freq); 14931235808cSjmatthew case RK3308_CLK_RTC32K: 14941235808cSjmatthew return rk3308_set_rtc32k(sc, freq); 14951235808cSjmatthew default: 14961235808cSjmatthew break; 14971235808cSjmatthew } 14981235808cSjmatthew 14991235808cSjmatthew return rkclock_set_frequency(sc, idx, freq); 15001235808cSjmatthew } 15011235808cSjmatthew 15021235808cSjmatthew 15031235808cSjmatthew int 15041235808cSjmatthew rk3308_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 15051235808cSjmatthew { 15061235808cSjmatthew struct rkclock_softc *sc = cookie; 15071235808cSjmatthew 15081235808cSjmatthew if (pcells[0] != sc->sc_phandle) 15091235808cSjmatthew return -1; 15101235808cSjmatthew 15111235808cSjmatthew return rkclock_set_parent(sc, cells[0], pcells[1]); 15121235808cSjmatthew } 15131235808cSjmatthew 15141235808cSjmatthew void 15151235808cSjmatthew rk3308_enable(void *cookie, uint32_t *cells, int on) 15161235808cSjmatthew { 15171235808cSjmatthew uint32_t idx = cells[0]; 15181235808cSjmatthew 15191235808cSjmatthew /* 15201235808cSjmatthew * All clocks are enabled by default, so there is nothing for 15211235808cSjmatthew * us to do until we start disabling clocks. 15221235808cSjmatthew */ 15231235808cSjmatthew if (!on) 15241235808cSjmatthew printf("%s: 0x%08x\n", __func__, idx); 15251235808cSjmatthew } 15261235808cSjmatthew 15271235808cSjmatthew void 15281235808cSjmatthew rk3308_reset(void *cookie, uint32_t *cells, int on) 15291235808cSjmatthew { 15301235808cSjmatthew struct rkclock_softc *sc = cookie; 15311235808cSjmatthew uint32_t idx = cells[0]; 15321235808cSjmatthew uint32_t mask = (1 << (idx % 16)); 15331235808cSjmatthew 15341235808cSjmatthew HWRITE4(sc, RK3308_CRU_SOFTRST_CON(idx / 16), 15351235808cSjmatthew mask << 16 | (on ? mask : 0)); 15361235808cSjmatthew } 15371235808cSjmatthew 15381235808cSjmatthew 15391235808cSjmatthew /* 1540da841e6eSkettenis * Rockchip RK3328 1541da841e6eSkettenis */ 1542da841e6eSkettenis 154337c734d3Snaddy const struct rkclock rk3328_clocks[] = { 1544e82d29a5Skettenis { 15454cecc5e3Skettenis RK3328_CLK_RTC32K, RK3328_CRU_CLKSEL_CON(38), 15464cecc5e3Skettenis SEL(15, 14), DIV(13, 0), 15477371cc19Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M } 15484cecc5e3Skettenis }, 15494cecc5e3Skettenis { 155017449d5cSkettenis RK3328_CLK_SPI, RK3328_CRU_CLKSEL_CON(24), 155117449d5cSkettenis SEL(7, 7), DIV(6, 0), 155217449d5cSkettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 155317449d5cSkettenis }, 155417449d5cSkettenis { 1555e82d29a5Skettenis RK3328_CLK_SDMMC, RK3328_CRU_CLKSEL_CON(30), 1556e82d29a5Skettenis SEL(9, 8), DIV(7, 0), 15577371cc19Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 1558e82d29a5Skettenis RK3328_USB480M } 1559e82d29a5Skettenis }, 1560e82d29a5Skettenis { 1561e82d29a5Skettenis RK3328_CLK_SDIO, RK3328_CRU_CLKSEL_CON(31), 1562e82d29a5Skettenis SEL(9, 8), DIV(7, 0), 15637371cc19Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 1564e82d29a5Skettenis RK3328_USB480M } 1565e82d29a5Skettenis }, 1566e82d29a5Skettenis { 1567e82d29a5Skettenis RK3328_CLK_EMMC, RK3328_CRU_CLKSEL_CON(32), 1568e82d29a5Skettenis SEL(9, 8), DIV(7, 0), 15697371cc19Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 1570e82d29a5Skettenis RK3328_USB480M } 1571e82d29a5Skettenis }, 1572e82d29a5Skettenis { 1573326e2a79Skettenis RK3328_CLK_TSADC, RK3328_CRU_CLKSEL_CON(22), 1574326e2a79Skettenis 0, DIV(9, 0), 1575326e2a79Skettenis { RK3328_CLK_24M } 1576326e2a79Skettenis }, 1577326e2a79Skettenis { 1578e82d29a5Skettenis RK3328_CLK_UART0, RK3328_CRU_CLKSEL_CON(14), 1579e82d29a5Skettenis SEL(9, 8), 0, 15807371cc19Skettenis { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 1581e82d29a5Skettenis }, 1582e82d29a5Skettenis { 1583e82d29a5Skettenis RK3328_CLK_UART1, RK3328_CRU_CLKSEL_CON(16), 1584e82d29a5Skettenis SEL(9, 8), 0, 15857371cc19Skettenis { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 1586e82d29a5Skettenis }, 1587e82d29a5Skettenis { 1588e82d29a5Skettenis RK3328_CLK_UART2, RK3328_CRU_CLKSEL_CON(18), 1589e82d29a5Skettenis SEL(9, 8), 0, 15907371cc19Skettenis { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 1591e82d29a5Skettenis }, 1592e82d29a5Skettenis { 15934cecc5e3Skettenis RK3328_CLK_WIFI, RK3328_CRU_CLKSEL_CON(52), 15944cecc5e3Skettenis SEL(7, 6), DIV(5, 0), 15954cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_USB480M } 15964cecc5e3Skettenis }, 15974cecc5e3Skettenis { 1598e82d29a5Skettenis RK3328_CLK_I2C0, RK3328_CRU_CLKSEL_CON(34), 1599e82d29a5Skettenis SEL(7, 7), DIV(6, 0), 1600e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 1601e82d29a5Skettenis }, 1602e82d29a5Skettenis { 1603e82d29a5Skettenis RK3328_CLK_I2C1, RK3328_CRU_CLKSEL_CON(34), 1604e82d29a5Skettenis SEL(15, 15), DIV(14, 8), 1605e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 1606e82d29a5Skettenis }, 1607e82d29a5Skettenis { 1608e82d29a5Skettenis RK3328_CLK_I2C2, RK3328_CRU_CLKSEL_CON(35), 1609e82d29a5Skettenis SEL(7, 7), DIV(6, 0), 1610e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 1611e82d29a5Skettenis }, 1612e82d29a5Skettenis { 1613e82d29a5Skettenis RK3328_CLK_I2C3, RK3328_CRU_CLKSEL_CON(35), 1614e82d29a5Skettenis SEL(15, 15), DIV(14, 8), 1615e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 1616e82d29a5Skettenis }, 1617e82d29a5Skettenis { 16184d55a102Skettenis RK3328_CLK_CRYPTO, RK3328_CRU_CLKSEL_CON(20), 16194d55a102Skettenis SEL(7, 7), DIV(4, 0), 16204d55a102Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 16214d55a102Skettenis }, 16224d55a102Skettenis { 1623e82d29a5Skettenis RK3328_CLK_PDM, RK3328_CRU_CLKSEL_CON(20), 1624e82d29a5Skettenis SEL(15, 14), DIV(12, 8), 16253f8209efSkettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_PLL_APLL }, 16263f8209efSkettenis FIXED_PARENT | SET_PARENT 1627e82d29a5Skettenis }, 1628e82d29a5Skettenis { 16294cecc5e3Skettenis RK3328_CLK_VDEC_CABAC, RK3328_CRU_CLKSEL_CON(48), 16304cecc5e3Skettenis SEL(15, 14), DIV(12, 8), 16314cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16324cecc5e3Skettenis RK3328_USB480M } 16334cecc5e3Skettenis }, 16344cecc5e3Skettenis { 16354cecc5e3Skettenis RK3328_CLK_VDEC_CORE, RK3328_CRU_CLKSEL_CON(49), 16364cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 16374cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16384cecc5e3Skettenis RK3328_USB480M } 16394cecc5e3Skettenis }, 16404cecc5e3Skettenis { 16414cecc5e3Skettenis RK3328_CLK_VENC_DSP, RK3328_CRU_CLKSEL_CON(52), 16424cecc5e3Skettenis SEL(15, 14), DIV(12, 8), 16434cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16444cecc5e3Skettenis RK3328_USB480M } 16454cecc5e3Skettenis }, 16464cecc5e3Skettenis { 16474cecc5e3Skettenis RK3328_CLK_VENC_CORE, RK3328_CRU_CLKSEL_CON(51), 16484cecc5e3Skettenis SEL(15, 14), DIV(12, 8), 16494cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16504cecc5e3Skettenis RK3328_USB480M } 16514cecc5e3Skettenis }, 16524cecc5e3Skettenis { 16534cecc5e3Skettenis RK3328_CLK_TSP, RK3328_CRU_CLKSEL_CON(21), 16544cecc5e3Skettenis SEL(15, 15), DIV(12, 8), 16554cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 16564cecc5e3Skettenis }, 16574cecc5e3Skettenis { 16582fcaff65Skettenis RK3328_CLK_MAC2IO_SRC, RK3328_CRU_CLKSEL_CON(27), 16592fcaff65Skettenis SEL(7, 7), DIV(4, 0), 16602fcaff65Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 16612fcaff65Skettenis }, 16622fcaff65Skettenis { 16634cecc5e3Skettenis RK3328_DCLK_LCDC, RK3328_CRU_CLKSEL_CON(40), 16644cecc5e3Skettenis SEL(1, 1), 0, 16654cecc5e3Skettenis { RK3328_HDMIPHY, RK3328_DCLK_LCDC_SRC } 16664cecc5e3Skettenis }, 16674cecc5e3Skettenis { 16684cecc5e3Skettenis RK3328_ACLK_VOP_PRE, RK3328_CRU_CLKSEL_CON(39), 16694cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 16704cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16714cecc5e3Skettenis RK3328_USB480M } 16724cecc5e3Skettenis }, 16734cecc5e3Skettenis { 16744cecc5e3Skettenis RK3328_ACLK_RGA_PRE, RK3328_CRU_CLKSEL_CON(36), 16754cecc5e3Skettenis SEL(15, 14), DIV(12, 8), 16764cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16774cecc5e3Skettenis RK3328_USB480M } 16784cecc5e3Skettenis }, 16794cecc5e3Skettenis { 1680e82d29a5Skettenis RK3328_ACLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(0), 1681e82d29a5Skettenis SEL(14, 13), DIV(12, 8), 1682e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY } 1683e82d29a5Skettenis }, 1684e82d29a5Skettenis { 1685e82d29a5Skettenis RK3328_ACLK_PERI_PRE, RK3328_CRU_CLKSEL_CON(28), 1686e82d29a5Skettenis SEL(7, 6), DIV(4, 0), 1687e82d29a5Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY } 1688e82d29a5Skettenis }, 1689e82d29a5Skettenis { 16904cecc5e3Skettenis RK3328_ACLK_RKVDEC_PRE, RK3328_CRU_CLKSEL_CON(48), 16914cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 16924cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16934cecc5e3Skettenis RK3328_USB480M } 16944cecc5e3Skettenis }, 16954cecc5e3Skettenis { 16964cecc5e3Skettenis RK3328_ACLK_RKVENC, RK3328_CRU_CLKSEL_CON(51), 16974cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 16984cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 16994cecc5e3Skettenis RK3328_USB480M } 17004cecc5e3Skettenis }, 17014cecc5e3Skettenis { 17024cecc5e3Skettenis RK3328_ACLK_VPU_PRE, RK3328_CRU_CLKSEL_CON(50), 17034cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 17044cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 17054cecc5e3Skettenis RK3328_USB480M } 17064cecc5e3Skettenis }, 17074cecc5e3Skettenis { 17084cecc5e3Skettenis RK3328_ACLK_VIO_PRE, RK3328_CRU_CLKSEL_CON(37), 17094cecc5e3Skettenis SEL(7, 6), DIV(4, 0), 17104cecc5e3Skettenis { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 17114cecc5e3Skettenis RK3328_USB480M } 17124cecc5e3Skettenis }, 17134cecc5e3Skettenis { 1714e82d29a5Skettenis RK3328_PCLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(1), 1715e82d29a5Skettenis 0, DIV(14, 12), 1716e82d29a5Skettenis { RK3328_ACLK_BUS_PRE } 1717e82d29a5Skettenis }, 1718e82d29a5Skettenis { 1719e82d29a5Skettenis RK3328_HCLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(1), 1720e82d29a5Skettenis 0, DIV(9, 8), 1721e82d29a5Skettenis { RK3328_ACLK_BUS_PRE } 1722e82d29a5Skettenis }, 1723e82d29a5Skettenis { 1724e82d29a5Skettenis RK3328_PCLK_PERI, RK3328_CRU_CLKSEL_CON(29), 1725e82d29a5Skettenis 0, DIV(6, 4), 1726e82d29a5Skettenis { RK3328_ACLK_PERI_PRE } 1727e82d29a5Skettenis }, 1728e82d29a5Skettenis { 1729e82d29a5Skettenis RK3328_HCLK_PERI, RK3328_CRU_CLKSEL_CON(29), 1730e82d29a5Skettenis 0, DIV(1, 0), 1731e82d29a5Skettenis { RK3328_ACLK_PERI_PRE } 1732e82d29a5Skettenis }, 1733e82d29a5Skettenis { 1734326e2a79Skettenis RK3328_CLK_24M, RK3328_CRU_CLKSEL_CON(2), 1735326e2a79Skettenis 0, DIV(12, 8), 1736326e2a79Skettenis { RK3328_XIN24M } 1737326e2a79Skettenis }, 1738326e2a79Skettenis { 1739e82d29a5Skettenis /* Sentinel */ 1740e82d29a5Skettenis } 1741e82d29a5Skettenis }; 1742e82d29a5Skettenis 1743da841e6eSkettenis void 1744da841e6eSkettenis rk3328_init(struct rkclock_softc *sc) 1745da841e6eSkettenis { 1746da841e6eSkettenis int i; 1747da841e6eSkettenis 1748da841e6eSkettenis /* The code below assumes all clocks are enabled. Check this!. */ 1749da841e6eSkettenis for (i = 0; i <= 28; i++) { 1750da841e6eSkettenis if (HREAD4(sc, RK3328_CRU_CLKGATE_CON(i)) != 0x00000000) { 1751da841e6eSkettenis printf("CRU_CLKGATE_CON%d: 0x%08x\n", i, 1752da841e6eSkettenis HREAD4(sc, RK3328_CRU_CLKGATE_CON(i))); 1753da841e6eSkettenis } 1754da841e6eSkettenis } 1755e82d29a5Skettenis 1756e82d29a5Skettenis sc->sc_clocks = rk3328_clocks; 1757da841e6eSkettenis } 1758da841e6eSkettenis 1759da841e6eSkettenis uint32_t 1760f231fa3aSkettenis rk3328_armclk_parent(uint32_t mux) 1761f231fa3aSkettenis { 1762f231fa3aSkettenis switch (mux) { 1763f231fa3aSkettenis case 0: 1764f231fa3aSkettenis return RK3328_PLL_APLL; 1765f231fa3aSkettenis case 1: 1766f231fa3aSkettenis return RK3328_PLL_GPLL; 1767f231fa3aSkettenis case 2: 1768f231fa3aSkettenis return RK3328_PLL_DPLL; 1769f231fa3aSkettenis case 3: 1770f231fa3aSkettenis return RK3328_PLL_NPLL; 1771f231fa3aSkettenis } 1772f231fa3aSkettenis 1773f231fa3aSkettenis return 0; 1774f231fa3aSkettenis } 1775f231fa3aSkettenis 1776f231fa3aSkettenis uint32_t 1777f231fa3aSkettenis rk3328_get_armclk(struct rkclock_softc *sc) 1778f231fa3aSkettenis { 1779f231fa3aSkettenis uint32_t reg, mux, div_con; 1780f231fa3aSkettenis uint32_t idx; 1781f231fa3aSkettenis 1782f231fa3aSkettenis reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(0)); 1783f231fa3aSkettenis mux = (reg & RK3328_CRU_CORE_CLK_PLL_SEL_MASK) >> 1784f231fa3aSkettenis RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT; 1785f231fa3aSkettenis div_con = (reg & RK3328_CRU_CLK_CORE_DIV_CON_MASK) >> 1786f231fa3aSkettenis RK3328_CRU_CLK_CORE_DIV_CON_SHIFT; 1787f231fa3aSkettenis idx = rk3328_armclk_parent(mux); 1788f231fa3aSkettenis 1789f231fa3aSkettenis return rk3328_get_frequency(sc, &idx) / (div_con + 1); 1790f231fa3aSkettenis } 1791f231fa3aSkettenis 1792f231fa3aSkettenis int 1793f231fa3aSkettenis rk3328_set_armclk(struct rkclock_softc *sc, uint32_t freq) 1794f231fa3aSkettenis { 1795f231fa3aSkettenis uint32_t reg, mux; 1796f231fa3aSkettenis uint32_t old_freq, div; 1797f231fa3aSkettenis uint32_t idx; 1798f231fa3aSkettenis 1799f231fa3aSkettenis old_freq = rk3328_get_armclk(sc); 1800f231fa3aSkettenis if (freq == old_freq) 1801f231fa3aSkettenis return 0; 1802f231fa3aSkettenis 1803f231fa3aSkettenis reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(0)); 1804f231fa3aSkettenis mux = (reg & RK3328_CRU_CORE_CLK_PLL_SEL_MASK) >> 1805f231fa3aSkettenis RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT; 1806f231fa3aSkettenis 1807f231fa3aSkettenis /* Keep the pclk_dbg clock at or below 300 MHz. */ 1808f231fa3aSkettenis div = 1; 1809f231fa3aSkettenis while (freq / (div + 1) > 300000000) 1810f231fa3aSkettenis div++; 1811f231fa3aSkettenis /* and make sure we use an odd divider. */ 1812f231fa3aSkettenis if ((div % 2) == 0) 1813f231fa3aSkettenis div++; 1814f231fa3aSkettenis 1815f231fa3aSkettenis /* When ramping up, set clock dividers first. */ 1816f231fa3aSkettenis if (freq > old_freq) { 1817f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CLKSEL_CON(0), 1818f231fa3aSkettenis RK3328_CRU_CLK_CORE_DIV_CON_MASK << 16 | 1819f231fa3aSkettenis 0 << RK3328_CRU_CLK_CORE_DIV_CON_SHIFT); 1820f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CLKSEL_CON(1), 1821f231fa3aSkettenis RK3328_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 1822f231fa3aSkettenis 1 << RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT | 1823f231fa3aSkettenis RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 1824f231fa3aSkettenis div << RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 1825f231fa3aSkettenis } 1826f231fa3aSkettenis 18274cecc5e3Skettenis /* We always use NPLL and force the switch below if needed. */ 18284cecc5e3Skettenis idx = RK3328_PLL_NPLL; 1829f231fa3aSkettenis rk3328_set_frequency(sc, &idx, freq); 1830f231fa3aSkettenis 18314cecc5e3Skettenis /* When ramping down, set clock dividers last. */ 18324cecc5e3Skettenis if (freq < old_freq || mux != 3) { 1833f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CLKSEL_CON(0), 18344cecc5e3Skettenis RK3328_CRU_CORE_CLK_PLL_SEL_MASK << 16 | 18354cecc5e3Skettenis 3 << RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT | 1836f231fa3aSkettenis RK3328_CRU_CLK_CORE_DIV_CON_MASK << 16 | 1837f231fa3aSkettenis 0 << RK3328_CRU_CLK_CORE_DIV_CON_SHIFT); 1838f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CLKSEL_CON(1), 1839f231fa3aSkettenis RK3328_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 1840f231fa3aSkettenis 1 << RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT | 1841f231fa3aSkettenis RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 1842f231fa3aSkettenis div << RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 1843f231fa3aSkettenis } 1844f231fa3aSkettenis 1845f231fa3aSkettenis return 0; 1846f231fa3aSkettenis } 1847f231fa3aSkettenis 1848f231fa3aSkettenis uint32_t 1849da841e6eSkettenis rk3328_get_pll(struct rkclock_softc *sc, bus_size_t base) 1850da841e6eSkettenis { 1851da841e6eSkettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 18524cecc5e3Skettenis uint32_t dsmpd, fracdiv; 18534cecc5e3Skettenis uint64_t frac = 0; 1854da841e6eSkettenis uint32_t reg; 1855da841e6eSkettenis 1856da841e6eSkettenis reg = HREAD4(sc, base + 0x0000); 1857da841e6eSkettenis postdiv1 = (reg & RK3328_CRU_PLL_POSTDIV1_MASK) >> 1858da841e6eSkettenis RK3328_CRU_PLL_POSTDIV1_SHIFT; 1859da841e6eSkettenis fbdiv = (reg & RK3328_CRU_PLL_FBDIV_MASK) >> 1860da841e6eSkettenis RK3328_CRU_PLL_FBDIV_SHIFT; 1861da841e6eSkettenis reg = HREAD4(sc, base + 0x0004); 18624cecc5e3Skettenis dsmpd = (reg & RK3328_CRU_PLL_DSMPD); 1863da841e6eSkettenis postdiv2 = (reg & RK3328_CRU_PLL_POSTDIV2_MASK) >> 1864da841e6eSkettenis RK3328_CRU_PLL_POSTDIV2_SHIFT; 1865da841e6eSkettenis refdiv = (reg & RK3328_CRU_PLL_REFDIV_MASK) >> 1866f231fa3aSkettenis RK3328_CRU_PLL_REFDIV_SHIFT; 18674cecc5e3Skettenis reg = HREAD4(sc, base + 0x0008); 18684cecc5e3Skettenis fracdiv = (reg & RK3328_CRU_PLL_FRACDIV_MASK) >> 18694cecc5e3Skettenis RK3328_CRU_PLL_FRACDIV_SHIFT; 18704cecc5e3Skettenis 18714cecc5e3Skettenis if (dsmpd == 0) 18724cecc5e3Skettenis frac = (24000000ULL * fracdiv / refdiv) >> 24; 18734cecc5e3Skettenis return ((24000000ULL * fbdiv / refdiv) + frac) / postdiv1 / postdiv2; 1874da841e6eSkettenis } 1875da841e6eSkettenis 1876f231fa3aSkettenis int 1877f231fa3aSkettenis rk3328_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 1878f231fa3aSkettenis { 1879f231fa3aSkettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 1880f231fa3aSkettenis int mode_shift = -1; 1881f231fa3aSkettenis 1882f231fa3aSkettenis switch (base) { 1883f231fa3aSkettenis case RK3328_CRU_APLL_CON(0): 1884f231fa3aSkettenis mode_shift = 0; 1885f231fa3aSkettenis break; 1886f231fa3aSkettenis case RK3328_CRU_DPLL_CON(0): 1887f231fa3aSkettenis mode_shift = 4; 1888f231fa3aSkettenis break; 1889f231fa3aSkettenis case RK3328_CRU_CPLL_CON(0): 1890f231fa3aSkettenis mode_shift = 8; 1891f231fa3aSkettenis break; 1892f231fa3aSkettenis case RK3328_CRU_GPLL_CON(0): 1893f231fa3aSkettenis mode_shift = 12; 1894f231fa3aSkettenis break; 1895f231fa3aSkettenis case RK3328_CRU_NPLL_CON(0): 1896f231fa3aSkettenis mode_shift = 1; 1897f231fa3aSkettenis break; 1898f231fa3aSkettenis } 1899f231fa3aSkettenis KASSERT(mode_shift != -1); 1900f231fa3aSkettenis 1901f231fa3aSkettenis /* 1902f231fa3aSkettenis * It is not clear whether all combinations of the clock 1903f231fa3aSkettenis * dividers result in a stable clock. Therefore this function 1904f231fa3aSkettenis * only supports a limited set of PLL clock rates. For now 1905f231fa3aSkettenis * this set covers all the CPU frequencies supported by the 1906f231fa3aSkettenis * Linux kernel. 1907f231fa3aSkettenis */ 1908f231fa3aSkettenis switch (freq) { 1909f231fa3aSkettenis case 1800000000U: 1910f231fa3aSkettenis case 1704000000U: 1911f231fa3aSkettenis case 1608000000U: 1912f231fa3aSkettenis case 1512000000U: 1913f231fa3aSkettenis case 1488000000U: 1914f231fa3aSkettenis case 1416000000U: 1915f231fa3aSkettenis case 1392000000U: 1916f231fa3aSkettenis case 1296000000U: 1917f231fa3aSkettenis case 1200000000U: 1918f231fa3aSkettenis case 1104000000U: 1919f231fa3aSkettenis postdiv1 = postdiv2 = refdiv = 1; 1920f231fa3aSkettenis break; 1921f231fa3aSkettenis case 1008000000U: 1922f231fa3aSkettenis case 912000000U: 1923f231fa3aSkettenis case 816000000U: 1924f231fa3aSkettenis case 696000000U: 1925f231fa3aSkettenis postdiv1 = 2; postdiv2 = refdiv = 1; 1926f231fa3aSkettenis break; 1927f231fa3aSkettenis case 600000000U: 1928f231fa3aSkettenis postdiv1 = 3; postdiv2 = refdiv = 1; 1929f231fa3aSkettenis break; 1930f231fa3aSkettenis case 408000000U: 1931f231fa3aSkettenis case 312000000U: 1932f231fa3aSkettenis postdiv1 = postdiv2 = 2; refdiv = 1; 1933f231fa3aSkettenis break; 1934f231fa3aSkettenis case 216000000U: 1935f231fa3aSkettenis postdiv1 = 4; postdiv2 = 2; refdiv = 1; 1936f231fa3aSkettenis break; 1937f231fa3aSkettenis case 96000000U: 1938f231fa3aSkettenis postdiv1 = postdiv2 = 4; refdiv = 1; 1939f231fa3aSkettenis break; 1940f231fa3aSkettenis default: 19419822ab30Skettenis printf("%s: %u Hz\n", __func__, freq); 1942f231fa3aSkettenis return -1; 1943f231fa3aSkettenis } 1944f231fa3aSkettenis 1945f231fa3aSkettenis /* Calculate feedback divider. */ 1946f231fa3aSkettenis fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 1947f231fa3aSkettenis 1948f231fa3aSkettenis /* 1949f231fa3aSkettenis * Select slow mode to guarantee a stable clock while we're 1950f231fa3aSkettenis * adjusting the PLL. 1951f231fa3aSkettenis */ 1952f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CRU_MODE, 1953f231fa3aSkettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 1954f231fa3aSkettenis RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 1955f231fa3aSkettenis 1956f231fa3aSkettenis /* Set PLL rate. */ 1957f231fa3aSkettenis HWRITE4(sc, base + 0x0000, 1958f231fa3aSkettenis RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 1959f231fa3aSkettenis postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 1960f231fa3aSkettenis RK3328_CRU_PLL_FBDIV_MASK << 16 | 1961f231fa3aSkettenis fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 1962f231fa3aSkettenis HWRITE4(sc, base + 0x0004, 19634cecc5e3Skettenis RK3328_CRU_PLL_DSMPD << 16 | RK3328_CRU_PLL_DSMPD | 1964f231fa3aSkettenis RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 1965f231fa3aSkettenis postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 1966f231fa3aSkettenis RK3328_CRU_PLL_REFDIV_MASK << 16 | 1967f231fa3aSkettenis refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 1968f231fa3aSkettenis 1969f231fa3aSkettenis /* Wait for PLL to stabilize. */ 1970f231fa3aSkettenis while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 1971f231fa3aSkettenis delay(10); 1972f231fa3aSkettenis 1973f231fa3aSkettenis /* Switch back to normal mode. */ 1974f231fa3aSkettenis HWRITE4(sc, RK3328_CRU_CRU_MODE, 1975f231fa3aSkettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 1976f231fa3aSkettenis RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 1977f231fa3aSkettenis 1978f231fa3aSkettenis return 0; 1979f231fa3aSkettenis } 1980f231fa3aSkettenis 19814cecc5e3Skettenis int 19824cecc5e3Skettenis rk3328_set_frac_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 19834cecc5e3Skettenis { 19844cecc5e3Skettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv, fracdiv; 19854cecc5e3Skettenis int mode_shift = -1; 19864cecc5e3Skettenis uint32_t reg; 19874cecc5e3Skettenis 19884cecc5e3Skettenis switch (base) { 19894cecc5e3Skettenis case RK3328_CRU_APLL_CON(0): 19904cecc5e3Skettenis mode_shift = 0; 19914cecc5e3Skettenis break; 19924cecc5e3Skettenis case RK3328_CRU_DPLL_CON(0): 19934cecc5e3Skettenis mode_shift = 4; 19944cecc5e3Skettenis break; 19954cecc5e3Skettenis case RK3328_CRU_CPLL_CON(0): 19964cecc5e3Skettenis mode_shift = 8; 19974cecc5e3Skettenis break; 19984cecc5e3Skettenis case RK3328_CRU_GPLL_CON(0): 19994cecc5e3Skettenis mode_shift = 12; 20004cecc5e3Skettenis break; 20014cecc5e3Skettenis case RK3328_CRU_NPLL_CON(0): 20024cecc5e3Skettenis mode_shift = 1; 20034cecc5e3Skettenis break; 20044cecc5e3Skettenis } 20054cecc5e3Skettenis KASSERT(mode_shift != -1); 20064cecc5e3Skettenis 20074cecc5e3Skettenis /* 20084cecc5e3Skettenis * It is not clear whether all combinations of the clock 20094cecc5e3Skettenis * dividers result in a stable clock. Therefore this function 20104cecc5e3Skettenis * only supports a limited set of PLL clock rates. This set 20114cecc5e3Skettenis * set covers all the fractional PLL frequencies supported by 20124cecc5e3Skettenis * the Linux kernel. 20134cecc5e3Skettenis */ 20144cecc5e3Skettenis switch (freq) { 20154cecc5e3Skettenis case 1016064000U: 20164cecc5e3Skettenis postdiv1 = postdiv2 = 1; refdiv = 3; fracdiv = 134217; 20174cecc5e3Skettenis break; 20184cecc5e3Skettenis case 983040000U: 20194cecc5e3Skettenis postdiv1 = postdiv2 = 1; refdiv = 24; fracdiv = 671088; 20204cecc5e3Skettenis break; 20214cecc5e3Skettenis case 491520000U: 20224cecc5e3Skettenis postdiv1 = 2; postdiv2 = 1; refdiv = 24; fracdiv = 671088; 20234cecc5e3Skettenis break; 20244cecc5e3Skettenis case 61440000U: 202520464928Skettenis postdiv1 = 7; postdiv2 = 2; refdiv = 6; fracdiv = 671088; 20264cecc5e3Skettenis break; 20274cecc5e3Skettenis case 56448000U: 20284cecc5e3Skettenis postdiv1 = postdiv2 = 4; refdiv = 12; fracdiv = 9797894; 20294cecc5e3Skettenis break; 20304cecc5e3Skettenis case 40960000U: 20314cecc5e3Skettenis postdiv1 = 4; postdiv2 = 5; refdiv = 12; fracdiv = 10066239; 20324cecc5e3Skettenis break; 20334cecc5e3Skettenis default: 20344cecc5e3Skettenis printf("%s: %u Hz\n", __func__, freq); 20354cecc5e3Skettenis return -1; 20364cecc5e3Skettenis } 20374cecc5e3Skettenis 20384cecc5e3Skettenis /* Calculate feedback divider. */ 20394cecc5e3Skettenis fbdiv = (uint64_t)freq * postdiv1 * postdiv2 * refdiv / 24000000; 20404cecc5e3Skettenis 20414cecc5e3Skettenis /* 20424cecc5e3Skettenis * Select slow mode to guarantee a stable clock while we're 20434cecc5e3Skettenis * adjusting the PLL. 20444cecc5e3Skettenis */ 20454cecc5e3Skettenis HWRITE4(sc, RK3328_CRU_CRU_MODE, 20464cecc5e3Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 20474cecc5e3Skettenis RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 20484cecc5e3Skettenis 20494cecc5e3Skettenis /* Set PLL rate. */ 20504cecc5e3Skettenis HWRITE4(sc, base + 0x0000, 20514cecc5e3Skettenis RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 20524cecc5e3Skettenis postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 20534cecc5e3Skettenis RK3328_CRU_PLL_FBDIV_MASK << 16 | 20544cecc5e3Skettenis fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 20554cecc5e3Skettenis HWRITE4(sc, base + 0x0004, 20564cecc5e3Skettenis RK3328_CRU_PLL_DSMPD << 16 | 20574cecc5e3Skettenis RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 20584cecc5e3Skettenis postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 20594cecc5e3Skettenis RK3328_CRU_PLL_REFDIV_MASK << 16 | 20604cecc5e3Skettenis refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 20614cecc5e3Skettenis reg = HREAD4(sc, base + 0x0008); 20624cecc5e3Skettenis reg &= ~RK3328_CRU_PLL_FRACDIV_MASK; 20634cecc5e3Skettenis reg |= fracdiv << RK3328_CRU_PLL_FRACDIV_SHIFT; 20644cecc5e3Skettenis HWRITE4(sc, base + 0x0008, reg); 20654cecc5e3Skettenis 20664cecc5e3Skettenis /* Wait for PLL to stabilize. */ 20674cecc5e3Skettenis while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 20684cecc5e3Skettenis delay(10); 20694cecc5e3Skettenis 20704cecc5e3Skettenis /* Switch back to normal mode. */ 20714cecc5e3Skettenis HWRITE4(sc, RK3328_CRU_CRU_MODE, 20724cecc5e3Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 20734cecc5e3Skettenis RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 20744cecc5e3Skettenis 20754cecc5e3Skettenis return 0; 20764cecc5e3Skettenis } 20774cecc5e3Skettenis 2078da841e6eSkettenis uint32_t 2079da841e6eSkettenis rk3328_get_frequency(void *cookie, uint32_t *cells) 2080da841e6eSkettenis { 2081da841e6eSkettenis struct rkclock_softc *sc = cookie; 2082da841e6eSkettenis uint32_t idx = cells[0]; 20832fcaff65Skettenis uint32_t reg; 2084da841e6eSkettenis 2085da841e6eSkettenis switch (idx) { 2086a2f8fc4bSkettenis case RK3328_PLL_APLL: 2087a2f8fc4bSkettenis return rk3328_get_pll(sc, RK3328_CRU_APLL_CON(0)); 2088a2f8fc4bSkettenis case RK3328_PLL_DPLL: 2089a2f8fc4bSkettenis return rk3328_get_pll(sc, RK3328_CRU_DPLL_CON(0)); 2090da841e6eSkettenis case RK3328_PLL_CPLL: 2091da841e6eSkettenis return rk3328_get_pll(sc, RK3328_CRU_CPLL_CON(0)); 2092da841e6eSkettenis case RK3328_PLL_GPLL: 2093da841e6eSkettenis return rk3328_get_pll(sc, RK3328_CRU_GPLL_CON(0)); 2094a2f8fc4bSkettenis case RK3328_PLL_NPLL: 2095a2f8fc4bSkettenis return rk3328_get_pll(sc, RK3328_CRU_NPLL_CON(0)); 2096a2f8fc4bSkettenis case RK3328_ARMCLK: 2097f231fa3aSkettenis return rk3328_get_armclk(sc); 20987371cc19Skettenis case RK3328_XIN24M: 2099a2f8fc4bSkettenis return 24000000; 21002fcaff65Skettenis case RK3328_GMAC_CLKIN: 21012fcaff65Skettenis return 125000000; 21023f8209efSkettenis /* 21033f8209efSkettenis * XXX The HDMIPHY and USB480M clocks are external. Returning 21043f8209efSkettenis * zero here will cause them to be ignored for reparenting 21053f8209efSkettenis * purposes. 21063f8209efSkettenis */ 21073f8209efSkettenis case RK3328_HDMIPHY: 21083f8209efSkettenis return 0; 21093f8209efSkettenis case RK3328_USB480M: 21103f8209efSkettenis return 0; 21112fcaff65Skettenis case RK3328_CLK_MAC2IO: 21122fcaff65Skettenis reg = regmap_read_4(sc->sc_grf, RK3328_GRF_MAC_CON1); 21132fcaff65Skettenis if (reg & RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL) 21142fcaff65Skettenis idx = RK3328_GMAC_CLKIN; 21152fcaff65Skettenis else 21162fcaff65Skettenis idx = RK3328_CLK_MAC2IO_SRC; 2117015b970dSkettenis return rk3328_get_frequency(sc, &idx); 21187371cc19Skettenis default: 21197371cc19Skettenis break; 2120da841e6eSkettenis } 2121da841e6eSkettenis 2122e82d29a5Skettenis return rkclock_get_frequency(sc, idx); 2123da841e6eSkettenis } 2124da841e6eSkettenis 2125da841e6eSkettenis int 2126da841e6eSkettenis rk3328_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 2127da841e6eSkettenis { 2128f231fa3aSkettenis struct rkclock_softc *sc = cookie; 2129da841e6eSkettenis uint32_t idx = cells[0]; 21304cecc5e3Skettenis uint32_t reg, mux; 2131da841e6eSkettenis 2132f231fa3aSkettenis switch (idx) { 2133f231fa3aSkettenis case RK3328_PLL_APLL: 21344cecc5e3Skettenis return rk3328_set_frac_pll(sc, RK3328_CRU_APLL_CON(0), freq); 2135f231fa3aSkettenis case RK3328_PLL_DPLL: 2136f231fa3aSkettenis return rk3328_set_pll(sc, RK3328_CRU_DPLL_CON(0), freq); 2137f231fa3aSkettenis case RK3328_PLL_CPLL: 2138f231fa3aSkettenis return rk3328_set_pll(sc, RK3328_CRU_CPLL_CON(0), freq); 2139f231fa3aSkettenis case RK3328_PLL_GPLL: 21404cecc5e3Skettenis return rk3328_set_frac_pll(sc, RK3328_CRU_GPLL_CON(0), freq); 2141f231fa3aSkettenis case RK3328_PLL_NPLL: 2142f231fa3aSkettenis return rk3328_set_pll(sc, RK3328_CRU_NPLL_CON(0), freq); 2143f231fa3aSkettenis case RK3328_ARMCLK: 2144f231fa3aSkettenis return rk3328_set_armclk(sc, freq); 21459822ab30Skettenis case RK3328_CLK_UART0: 21469822ab30Skettenis case RK3328_CLK_UART1: 21479822ab30Skettenis case RK3328_CLK_UART2: 21489822ab30Skettenis if (freq == rk3328_get_frequency(sc, &idx)) 21499822ab30Skettenis return 0; 21509822ab30Skettenis break; 21514cecc5e3Skettenis case RK3328_DCLK_LCDC: 21524cecc5e3Skettenis reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(40)); 21534cecc5e3Skettenis mux = (reg & RK3328_CRU_VOP_DCLK_SRC_SEL_MASK) >> 21544cecc5e3Skettenis RK3328_CRU_VOP_DCLK_SRC_SEL_SHIFT; 21554cecc5e3Skettenis idx = (mux == 0) ? RK3328_HDMIPHY : RK3328_DCLK_LCDC_SRC; 21564cecc5e3Skettenis return rk3328_set_frequency(sc, &idx, freq); 21574d55a102Skettenis case RK3328_HCLK_CRYPTO_SLV: 21584d55a102Skettenis idx = RK3328_HCLK_BUS_PRE; 21594d55a102Skettenis return rk3328_set_frequency(sc, &idx, freq); 21607371cc19Skettenis default: 21617371cc19Skettenis break; 2162f231fa3aSkettenis } 2163f231fa3aSkettenis 2164e82d29a5Skettenis return rkclock_set_frequency(sc, idx, freq); 2165da841e6eSkettenis } 2166da841e6eSkettenis 21679822ab30Skettenis int 21689822ab30Skettenis rk3328_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 21699822ab30Skettenis { 21709822ab30Skettenis struct rkclock_softc *sc = cookie; 21719822ab30Skettenis uint32_t idx = cells[0]; 2172e82d29a5Skettenis uint32_t parent; 21739822ab30Skettenis 2174e82d29a5Skettenis if (pcells[0] == sc->sc_phandle) 2175e82d29a5Skettenis parent = pcells[1]; 2176e82d29a5Skettenis else { 2177e82d29a5Skettenis char name[32]; 2178e82d29a5Skettenis int node; 2179e82d29a5Skettenis 2180e82d29a5Skettenis node = OF_getnodebyphandle(pcells[0]); 2181e82d29a5Skettenis if (node == 0) 2182e82d29a5Skettenis return -1; 2183e82d29a5Skettenis name[0] = 0; 2184e82d29a5Skettenis OF_getprop(node, "clock-output-names", name, sizeof(name)); 2185e82d29a5Skettenis name[sizeof(name) - 1] = 0; 21862fcaff65Skettenis if (strcmp(name, "xin24m") == 0) 21877371cc19Skettenis parent = RK3328_XIN24M; 21882fcaff65Skettenis else if (strcmp(name, "gmac_clkin") == 0) 21892fcaff65Skettenis parent = RK3328_GMAC_CLKIN; 21902fcaff65Skettenis else 21912fcaff65Skettenis return -1; 21922fcaff65Skettenis } 21932fcaff65Skettenis 21942fcaff65Skettenis switch (idx) { 21952fcaff65Skettenis case RK3328_CLK_MAC2IO: 21962fcaff65Skettenis if (parent == RK3328_GMAC_CLKIN) { 21972fcaff65Skettenis regmap_write_4(sc->sc_grf, RK3328_GRF_MAC_CON1, 21982fcaff65Skettenis RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL << 16 | 21992fcaff65Skettenis RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL); 22002fcaff65Skettenis } else { 22012fcaff65Skettenis regmap_write_4(sc->sc_grf, RK3328_GRF_MAC_CON1, 22022fcaff65Skettenis RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL << 16); 22032fcaff65Skettenis } 22042fcaff65Skettenis return 0; 2205015b970dSkettenis case RK3328_CLK_MAC2IO_EXT: 2206015b970dSkettenis if (parent == RK3328_GMAC_CLKIN) { 2207015b970dSkettenis regmap_write_4(sc->sc_grf, RK3328_GRF_SOC_CON4, 2208015b970dSkettenis RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN << 16 | 2209015b970dSkettenis RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN); 2210015b970dSkettenis } else { 2211015b970dSkettenis regmap_write_4(sc->sc_grf, RK3328_GRF_SOC_CON4, 2212015b970dSkettenis RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN << 16); 2213015b970dSkettenis } 2214015b970dSkettenis return 0; 22159822ab30Skettenis } 22169822ab30Skettenis 2217e82d29a5Skettenis return rkclock_set_parent(sc, idx, parent); 22189822ab30Skettenis } 22199822ab30Skettenis 2220da841e6eSkettenis void 2221da841e6eSkettenis rk3328_enable(void *cookie, uint32_t *cells, int on) 2222da841e6eSkettenis { 2223da841e6eSkettenis uint32_t idx = cells[0]; 2224da841e6eSkettenis 2225da841e6eSkettenis /* 2226da841e6eSkettenis * All clocks are enabled by default, so there is nothing for 2227da841e6eSkettenis * us to do until we start disabling clocks. 2228da841e6eSkettenis */ 2229da841e6eSkettenis if (!on) 2230da841e6eSkettenis printf("%s: 0x%08x\n", __func__, idx); 2231da841e6eSkettenis } 2232da841e6eSkettenis 2233da841e6eSkettenis void 2234da841e6eSkettenis rk3328_reset(void *cookie, uint32_t *cells, int on) 2235da841e6eSkettenis { 2236da841e6eSkettenis struct rkclock_softc *sc = cookie; 2237da841e6eSkettenis uint32_t idx = cells[0]; 2238da841e6eSkettenis uint32_t mask = (1 << (idx % 16)); 2239da841e6eSkettenis 2240da841e6eSkettenis HWRITE4(sc, RK3328_CRU_SOFTRST_CON(idx / 16), 2241da841e6eSkettenis mask << 16 | (on ? mask : 0)); 2242da841e6eSkettenis } 2243da841e6eSkettenis 2244da841e6eSkettenis /* 2245592afca7Skettenis * Rockchip RK3399 2246592afca7Skettenis */ 2247bd903cc4Skettenis 224837c734d3Snaddy const struct rkclock rk3399_clocks[] = { 22497371cc19Skettenis { 22507371cc19Skettenis RK3399_CLK_I2C1, RK3399_CRU_CLKSEL_CON(61), 22517371cc19Skettenis SEL(7, 7), DIV(6, 0), 22527371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22537371cc19Skettenis }, 22547371cc19Skettenis { 22557371cc19Skettenis RK3399_CLK_I2C2, RK3399_CRU_CLKSEL_CON(62), 22567371cc19Skettenis SEL(7, 7), DIV(6, 0), 22577371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22587371cc19Skettenis }, 22597371cc19Skettenis { 22607371cc19Skettenis RK3399_CLK_I2C3, RK3399_CRU_CLKSEL_CON(63), 22617371cc19Skettenis SEL(7, 7), DIV(6, 0), 22627371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22637371cc19Skettenis }, 22647371cc19Skettenis { 22657371cc19Skettenis RK3399_CLK_I2C5, RK3399_CRU_CLKSEL_CON(61), 22667371cc19Skettenis SEL(15, 15), DIV(14, 8), 22677371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22687371cc19Skettenis }, 22697371cc19Skettenis { 22707371cc19Skettenis RK3399_CLK_I2C6, RK3399_CRU_CLKSEL_CON(62), 22717371cc19Skettenis SEL(15, 15), DIV(14, 8), 22727371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22737371cc19Skettenis }, 22747371cc19Skettenis { 22757371cc19Skettenis RK3399_CLK_I2C7, RK3399_CRU_CLKSEL_CON(63), 22767371cc19Skettenis SEL(15, 15), DIV(14, 8), 22777371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 22787371cc19Skettenis }, 22797371cc19Skettenis { 228017449d5cSkettenis RK3399_CLK_SPI0, RK3399_CRU_CLKSEL_CON(59), 228117449d5cSkettenis SEL(7, 7), DIV(6, 0), 228217449d5cSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 228317449d5cSkettenis }, 228417449d5cSkettenis { 228517449d5cSkettenis RK3399_CLK_SPI1, RK3399_CRU_CLKSEL_CON(59), 228617449d5cSkettenis SEL(15, 15), DIV(14, 8), 228717449d5cSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 228817449d5cSkettenis }, 228917449d5cSkettenis { 229017449d5cSkettenis RK3399_CLK_SPI2, RK3399_CRU_CLKSEL_CON(60), 229117449d5cSkettenis SEL(7, 7), DIV(6, 0), 229217449d5cSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 229317449d5cSkettenis }, 229417449d5cSkettenis { 229517449d5cSkettenis RK3399_CLK_SPI4, RK3399_CRU_CLKSEL_CON(60), 229617449d5cSkettenis SEL(15, 15), DIV(14, 8), 229717449d5cSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 229817449d5cSkettenis }, 229917449d5cSkettenis { 230017449d5cSkettenis RK3399_CLK_SPI5, RK3399_CRU_CLKSEL_CON(58), 230117449d5cSkettenis SEL(15, 15), DIV(14, 8), 230217449d5cSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 230317449d5cSkettenis }, 230417449d5cSkettenis { 23057371cc19Skettenis RK3399_CLK_SDMMC, RK3399_CRU_CLKSEL_CON(16), 23067371cc19Skettenis SEL(10, 8), DIV(6, 0), 23077371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 23087371cc19Skettenis /* RK3399_PLL_PPLL */ 0, /* RK3399_USB_480M */ 0, 23097371cc19Skettenis RK3399_XIN24M } 23107371cc19Skettenis }, 23117371cc19Skettenis { 23127371cc19Skettenis RK3399_CLK_SDIO, RK3399_CRU_CLKSEL_CON(15), 23137371cc19Skettenis SEL(10, 8), DIV(6, 0), 23147371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 23157371cc19Skettenis /* RK3399_PLL_PPLL */ 0, /* RK3399_USB_480M */ 0, 23167371cc19Skettenis RK3399_XIN24M } 23177371cc19Skettenis }, 23187371cc19Skettenis { 2319162ad205Spatrick RK3399_CLK_EMMC, RK3399_CRU_CLKSEL_CON(22), 2320162ad205Spatrick SEL(10, 8), DIV(6, 0), 2321162ad205Spatrick { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 2322162ad205Spatrick /* RK3399_USB_480M */ 0, RK3399_XIN24M } 2323162ad205Spatrick }, 2324162ad205Spatrick { 23252aa5f6a3Skettenis RK3399_CLK_TSADC, RK3399_CRU_CLKSEL_CON(27), 23262aa5f6a3Skettenis SEL(15, 15), DIV(9, 0), 23272aa5f6a3Skettenis { RK3399_XIN24M, RK3399_CLK_32K } 23282aa5f6a3Skettenis }, 23292aa5f6a3Skettenis { 23307371cc19Skettenis RK3399_CLK_UART0, RK3399_CRU_CLKSEL_CON(33), 23317371cc19Skettenis SEL(9, 8), 0, 23327371cc19Skettenis { 0, 0, RK3399_XIN24M } 23337371cc19Skettenis }, 23347371cc19Skettenis { 23357371cc19Skettenis RK3399_CLK_UART1, RK3399_CRU_CLKSEL_CON(34), 23367371cc19Skettenis SEL(9, 8), 0, 23377371cc19Skettenis { 0, 0, RK3399_XIN24M } 23387371cc19Skettenis }, 23397371cc19Skettenis { 23407371cc19Skettenis RK3399_CLK_UART2, RK3399_CRU_CLKSEL_CON(35), 23417371cc19Skettenis SEL(9, 8), 0, 23427371cc19Skettenis { 0, 0, RK3399_XIN24M } 23437371cc19Skettenis }, 23447371cc19Skettenis { 23457371cc19Skettenis RK3399_CLK_UART3, RK3399_CRU_CLKSEL_CON(36), 23467371cc19Skettenis SEL(9, 8), 0, 23477371cc19Skettenis { 0, 0, RK3399_XIN24M } 23487371cc19Skettenis }, 23497371cc19Skettenis { 23507a7bc0a4Spatrick RK3399_CLK_I2S0_8CH, RK3399_CRU_CLKSEL_CON(28), 23517a7bc0a4Spatrick SEL(9, 8), 0, 2352caf123d1Skettenis { RK3399_CLK_I2S0_DIV, RK3399_CLK_I2S0_FRAC, 0, RK3399_XIN12M }, 23537a7bc0a4Spatrick SET_PARENT 23547a7bc0a4Spatrick }, 23557a7bc0a4Spatrick { 23567a7bc0a4Spatrick RK3399_CLK_I2S1_8CH, RK3399_CRU_CLKSEL_CON(29), 23577a7bc0a4Spatrick SEL(9, 8), 0, 2358caf123d1Skettenis { RK3399_CLK_I2S1_DIV, RK3399_CLK_I2S1_FRAC, 0, RK3399_XIN12M }, 23597a7bc0a4Spatrick SET_PARENT 23607a7bc0a4Spatrick }, 23617a7bc0a4Spatrick { 23627a7bc0a4Spatrick RK3399_CLK_I2S2_8CH, RK3399_CRU_CLKSEL_CON(30), 23637a7bc0a4Spatrick SEL(9, 8), 0, 2364caf123d1Skettenis { RK3399_CLK_I2S2_DIV, RK3399_CLK_I2S2_FRAC, 0, RK3399_XIN12M }, 23657a7bc0a4Spatrick SET_PARENT 23667a7bc0a4Spatrick }, 23677a7bc0a4Spatrick { 23687a7bc0a4Spatrick RK3399_CLK_I2S_8CH_OUT, RK3399_CRU_CLKSEL_CON(31), 23697a7bc0a4Spatrick SEL(2, 2), 0, 23707a7bc0a4Spatrick { RK3399_CLK_I2SOUT_SRC, RK3399_XIN12M }, 23717a7bc0a4Spatrick SET_PARENT 23727a7bc0a4Spatrick }, 23737a7bc0a4Spatrick { 2374adb68a6dSkettenis RK3399_CLK_MAC, RK3399_CRU_CLKSEL_CON(20), 2375adb68a6dSkettenis SEL(15, 14), DIV(12, 8), 2376adb68a6dSkettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL } 2377adb68a6dSkettenis }, 2378adb68a6dSkettenis { 2379526b8509Spatrick RK3399_CLK_UPHY0_TCPDCORE, RK3399_CRU_CLKSEL_CON(64), 2380526b8509Spatrick SEL(7, 6), DIV(4, 0), 2381526b8509Spatrick { RK3399_XIN24M, RK3399_CLK_32K, RK3399_PLL_CPLL, 2382526b8509Spatrick RK3399_PLL_GPLL } 2383526b8509Spatrick }, 2384526b8509Spatrick { 2385526b8509Spatrick RK3399_CLK_UPHY1_TCPDCORE, RK3399_CRU_CLKSEL_CON(65), 2386526b8509Spatrick SEL(7, 6), DIV(4, 0), 2387526b8509Spatrick { RK3399_XIN24M, RK3399_CLK_32K, RK3399_PLL_CPLL, 2388526b8509Spatrick RK3399_PLL_GPLL } 2389526b8509Spatrick }, 2390526b8509Spatrick { 23915486a9fbSpatrick RK3399_CLK_PCIEPHY_REF, RK3399_CRU_CLKSEL_CON(18), 23925486a9fbSpatrick SEL(10, 10), 0, 23935486a9fbSpatrick { RK3399_XIN24M, RK3399_CLK_PCIEPHY_REF100M }, 23945486a9fbSpatrick SET_PARENT 23955486a9fbSpatrick }, 23965486a9fbSpatrick { 23975486a9fbSpatrick RK3399_CLK_PCIEPHY_REF100M, RK3399_CRU_CLKSEL_CON(18), 23985486a9fbSpatrick 0, DIV(15, 11), 23995486a9fbSpatrick { RK3399_PLL_NPLL } 24005486a9fbSpatrick }, 24015486a9fbSpatrick { 2402137e484dSpatrick RK3399_DCLK_VOP0, RK3399_CRU_CLKSEL_CON(49), 2403137e484dSpatrick SEL(11, 11), 0, 2404137e484dSpatrick { RK3399_DCLK_VOP0_DIV, RK3399_DCLK_VOP0_FRAC }, 2405137e484dSpatrick SET_PARENT 2406137e484dSpatrick }, 2407137e484dSpatrick { 2408137e484dSpatrick RK3399_DCLK_VOP1, RK3399_CRU_CLKSEL_CON(50), 2409137e484dSpatrick SEL(11, 11), 0, 2410137e484dSpatrick { RK3399_DCLK_VOP1_DIV, RK3399_DCLK_VOP1_FRAC }, 2411137e484dSpatrick SET_PARENT 2412137e484dSpatrick }, 2413137e484dSpatrick { 2414137e484dSpatrick RK3399_DCLK_VOP0_DIV, RK3399_CRU_CLKSEL_CON(49), 2415137e484dSpatrick SEL(9, 8), DIV(7, 0), 2416137e484dSpatrick { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL } 2417137e484dSpatrick }, 2418137e484dSpatrick { 2419137e484dSpatrick RK3399_DCLK_VOP1_DIV, RK3399_CRU_CLKSEL_CON(50), 2420137e484dSpatrick SEL(9, 8), DIV(7, 0), 2421137e484dSpatrick { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL } 2422137e484dSpatrick }, 2423137e484dSpatrick { 24247371cc19Skettenis RK3399_ACLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 24257371cc19Skettenis SEL(7, 7), DIV(4, 0), 24267371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 24277371cc19Skettenis }, 24287371cc19Skettenis { 24297371cc19Skettenis RK3399_ACLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 24307371cc19Skettenis SEL(7, 7), DIV(4, 0), 24317371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 24327371cc19Skettenis }, 24337371cc19Skettenis { 24347371cc19Skettenis RK3399_ACLK_VIO, RK3399_CRU_CLKSEL_CON(42), 24357371cc19Skettenis SEL(7, 6), DIV(4, 0), 24367371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, /* RK3399_PLL_PPLL */ } 24377371cc19Skettenis }, 24387371cc19Skettenis { 24397371cc19Skettenis RK3399_ACLK_CCI, RK3399_CRU_CLKSEL_CON(5), 24407371cc19Skettenis SEL(7, 6), DIV(4, 0), 24417371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 24427371cc19Skettenis RK3399_PLL_VPLL } 24437371cc19Skettenis }, 24447371cc19Skettenis { 2445137e484dSpatrick RK3399_ACLK_VOP0, RK3399_CRU_CLKSEL_CON(47), 2446137e484dSpatrick SEL(7, 6), DIV(4, 0), 2447137e484dSpatrick { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL, 2448137e484dSpatrick RK3399_PLL_NPLL } 2449137e484dSpatrick }, 2450137e484dSpatrick { 2451137e484dSpatrick RK3399_ACLK_VOP1, RK3399_CRU_CLKSEL_CON(48), 2452137e484dSpatrick SEL(7, 6), DIV(4, 0), 2453137e484dSpatrick { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL, 2454137e484dSpatrick RK3399_PLL_NPLL } 2455137e484dSpatrick }, 2456137e484dSpatrick { 2457fdb5bc67Skettenis RK3399_ACLK_HDCP, RK3399_CRU_CLKSEL_CON(42), 2458fdb5bc67Skettenis SEL(15, 14), DIV(12, 8), 2459fdb5bc67Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL, /* RK3399_PLL_PPLL */ } 2460fdb5bc67Skettenis }, 2461fdb5bc67Skettenis { 2462fdb5bc67Skettenis RK3399_ACLK_GIC_PRE, RK3399_CRU_CLKSEL_CON(56), 2463fdb5bc67Skettenis SEL(15, 15), DIV(12, 8), 2464fdb5bc67Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 2465fdb5bc67Skettenis }, 2466fdb5bc67Skettenis { 24677371cc19Skettenis RK3399_PCLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 24687371cc19Skettenis 0, DIV(14, 12), 24697371cc19Skettenis { RK3399_ACLK_PERIPH } 24707371cc19Skettenis }, 24717371cc19Skettenis { 24727371cc19Skettenis RK3399_PCLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 24737371cc19Skettenis 0, DIV(14, 12), 24747371cc19Skettenis { RK3399_ACLK_PERILP0 } 24757371cc19Skettenis }, 24767371cc19Skettenis { 24777371cc19Skettenis RK3399_PCLK_PERILP1, RK3399_CRU_CLKSEL_CON(25), 24787371cc19Skettenis 0, DIV(10, 8), 24797371cc19Skettenis { RK3399_HCLK_PERILP1 } 24807371cc19Skettenis }, 24817371cc19Skettenis { 2482fdb5bc67Skettenis RK3399_PCLK_DDR, RK3399_CRU_CLKSEL_CON(6), 2483fdb5bc67Skettenis SEL(15, 15), DIV(12, 8), 2484fdb5bc67Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 2485fdb5bc67Skettenis }, 2486fdb5bc67Skettenis { 248743d1b45eSchrisz RK3399_PCLK_WDT, RK3399_CRU_CLKSEL_CON(57), 248843d1b45eSchrisz 0, DIV(4, 0), 248943d1b45eSchrisz { RK3399_PLL_GPLL } 249043d1b45eSchrisz }, 249143d1b45eSchrisz { 24927371cc19Skettenis RK3399_HCLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 24937371cc19Skettenis 0, DIV(9, 8), 24947371cc19Skettenis { RK3399_ACLK_PERIPH } 24957371cc19Skettenis }, 24967371cc19Skettenis { 24977371cc19Skettenis RK3399_HCLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 24987371cc19Skettenis 0, DIV(9, 8), 24997371cc19Skettenis { RK3399_ACLK_PERILP0 } 25007371cc19Skettenis }, 25017371cc19Skettenis { 25027371cc19Skettenis RK3399_HCLK_PERILP1, RK3399_CRU_CLKSEL_CON(25), 25037371cc19Skettenis SEL(7, 7), DIV(4, 0), 25047371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 25057371cc19Skettenis }, 25067371cc19Skettenis { 25077371cc19Skettenis RK3399_HCLK_SDMMC, RK3399_CRU_CLKSEL_CON(13), 25087371cc19Skettenis SEL(15, 15), DIV(12, 8), 25097371cc19Skettenis { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 25107371cc19Skettenis }, 25117371cc19Skettenis { 2512137e484dSpatrick RK3399_HCLK_VOP0, RK3399_CRU_CLKSEL_CON(47), 2513137e484dSpatrick 0, DIV(12, 8), 2514137e484dSpatrick { RK3399_ACLK_VOP0 } 2515137e484dSpatrick }, 2516137e484dSpatrick { 2517137e484dSpatrick RK3399_HCLK_VOP1, RK3399_CRU_CLKSEL_CON(48), 2518137e484dSpatrick 0, DIV(12, 8), 2519137e484dSpatrick { RK3399_ACLK_VOP1 } 2520137e484dSpatrick }, 2521137e484dSpatrick { 25227a7bc0a4Spatrick RK3399_CLK_I2S0_DIV, RK3399_CRU_CLKSEL_CON(28), 25237a7bc0a4Spatrick SEL(7, 7), DIV(6, 0), 25247a7bc0a4Spatrick { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 25257a7bc0a4Spatrick }, 25267a7bc0a4Spatrick { 25277a7bc0a4Spatrick RK3399_CLK_I2S1_DIV, RK3399_CRU_CLKSEL_CON(29), 25287a7bc0a4Spatrick SEL(7, 7), DIV(6, 0), 25297a7bc0a4Spatrick { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 25307a7bc0a4Spatrick }, 25317a7bc0a4Spatrick { 25327a7bc0a4Spatrick RK3399_CLK_I2S2_DIV, RK3399_CRU_CLKSEL_CON(30), 25337a7bc0a4Spatrick SEL(7, 7), DIV(6, 0), 25347a7bc0a4Spatrick { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 25357a7bc0a4Spatrick }, 25367a7bc0a4Spatrick { 25377a7bc0a4Spatrick RK3399_CLK_I2SOUT_SRC, RK3399_CRU_CLKSEL_CON(31), 25387a7bc0a4Spatrick SEL(1, 0), 0, 25397a7bc0a4Spatrick { RK3399_CLK_I2S0_8CH, RK3399_CLK_I2S1_8CH, 25407a7bc0a4Spatrick RK3399_CLK_I2S2_8CH }, 25417a7bc0a4Spatrick SET_PARENT 25427a7bc0a4Spatrick }, 25437a7bc0a4Spatrick { 25447371cc19Skettenis /* Sentinel */ 25457371cc19Skettenis } 25467371cc19Skettenis }; 25477371cc19Skettenis 2548ad8cadefSkettenis /* Some of our parent clocks live in the PMUCRU. */ 2549ad8cadefSkettenis struct rkclock_softc *rk3399_pmucru_sc; 2550ad8cadefSkettenis 255169da300fSkettenis void 255269da300fSkettenis rk3399_init(struct rkclock_softc *sc) 255369da300fSkettenis { 255444eccc75Skettenis int i; 2555f8c4fba2Skettenis 2556ad8cadefSkettenis /* PMUCRU instance should attach before us. */ 2557ad8cadefSkettenis KASSERT(rk3399_pmucru_sc != NULL); 2558ad8cadefSkettenis 2559f8c4fba2Skettenis /* 25601af18cc1Skettenis * The U-Boot shipped on the Theobroma Systems RK3399-Q7 25611af18cc1Skettenis * module is buggy and sets the parent of the clock for the 25621af18cc1Skettenis * "big" cluster to LPLL. Undo that mistake here such that 25631af18cc1Skettenis * the clocks of both clusters are independent. 25641af18cc1Skettenis */ 25651af18cc1Skettenis HWRITE4(sc, RK3399_CRU_CLKSEL_CON(2), 25661af18cc1Skettenis RK3399_CRU_CORE_PLL_SEL_MASK << 16 | 25671af18cc1Skettenis RK3399_CRU_CORE_PLL_SEL_BPLL); 25681af18cc1Skettenis 256944eccc75Skettenis /* The code below assumes all clocks are enabled. Check this!. */ 257044eccc75Skettenis for (i = 0; i <= 34; i++) { 257144eccc75Skettenis if (HREAD4(sc, RK3399_CRU_CLKGATE_CON(i)) != 0x00000000) { 257244eccc75Skettenis printf("CRU_CLKGATE_CON%d: 0x%08x\n", i, 257344eccc75Skettenis HREAD4(sc, RK3399_CRU_CLKGATE_CON(i))); 257444eccc75Skettenis } 257544eccc75Skettenis } 25767371cc19Skettenis 25777371cc19Skettenis sc->sc_clocks = rk3399_clocks; 2578f8c4fba2Skettenis } 257969da300fSkettenis 2580d9457073Skettenis uint32_t 2581d9457073Skettenis rk3399_get_pll(struct rkclock_softc *sc, bus_size_t base) 2582d9457073Skettenis { 2583d9457073Skettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 258413d6baf8Skettenis uint32_t pll_work_mode; 2585d9457073Skettenis uint32_t reg; 2586d9457073Skettenis 258713d6baf8Skettenis reg = HREAD4(sc, base + 0x000c); 258869da300fSkettenis pll_work_mode = reg & RK3399_CRU_PLL_PLL_WORK_MODE_MASK; 258969da300fSkettenis if (pll_work_mode == RK3399_CRU_PLL_PLL_WORK_MODE_SLOW) 259013d6baf8Skettenis return 24000000; 259169da300fSkettenis if (pll_work_mode == RK3399_CRU_PLL_PLL_WORK_MODE_DEEP_SLOW) 259213d6baf8Skettenis return 32768; 259313d6baf8Skettenis 259413d6baf8Skettenis reg = HREAD4(sc, base + 0x0000); 2595f8c4fba2Skettenis fbdiv = (reg & RK3399_CRU_PLL_FBDIV_MASK) >> 2596f8c4fba2Skettenis RK3399_CRU_PLL_FBDIV_SHIFT; 259713d6baf8Skettenis reg = HREAD4(sc, base + 0x0004); 2598f8c4fba2Skettenis postdiv2 = (reg & RK3399_CRU_PLL_POSTDIV2_MASK) >> 2599f8c4fba2Skettenis RK3399_CRU_PLL_POSTDIV2_SHIFT; 2600f8c4fba2Skettenis postdiv1 = (reg & RK3399_CRU_PLL_POSTDIV1_MASK) >> 2601f8c4fba2Skettenis RK3399_CRU_PLL_POSTDIV1_SHIFT; 2602f8c4fba2Skettenis refdiv = (reg & RK3399_CRU_PLL_REFDIV_MASK) >> 2603f8c4fba2Skettenis RK3399_CRU_PLL_REFDIV_SHIFT; 2604d9457073Skettenis return 24000000ULL * fbdiv / refdiv / postdiv1 / postdiv2; 2605d9457073Skettenis } 2606592afca7Skettenis 2607f8c4fba2Skettenis int 2608f8c4fba2Skettenis rk3399_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 2609f8c4fba2Skettenis { 2610f8c4fba2Skettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 2611f8c4fba2Skettenis 2612f8c4fba2Skettenis /* 2613f8c4fba2Skettenis * It is not clear whether all combinations of the clock 2614f8c4fba2Skettenis * dividers result in a stable clock. Therefore this function 2615f8c4fba2Skettenis * only supports a limited set of PLL clock rates. For now 2616f8c4fba2Skettenis * this set covers all the CPU frequencies supported by the 2617f8c4fba2Skettenis * Linux kernel. 2618f8c4fba2Skettenis */ 2619f8c4fba2Skettenis switch (freq) { 26207a20c0feSkettenis case 2208000000U: 26217a20c0feSkettenis case 2184000000U: 26227a20c0feSkettenis case 2088000000U: 26237a20c0feSkettenis case 2040000000U: 26247a20c0feSkettenis case 2016000000U: 26257a20c0feSkettenis case 1992000000U: 26267a20c0feSkettenis case 1896000000U: 26277a20c0feSkettenis case 1800000000U: 26287a20c0feSkettenis case 1704000000U: 26297a20c0feSkettenis case 1608000000U: 26307a20c0feSkettenis case 1512000000U: 26317a20c0feSkettenis case 1488000000U: 26327a20c0feSkettenis case 1416000000U: 26337a20c0feSkettenis case 1200000000U: 2634f8c4fba2Skettenis postdiv1 = postdiv2 = refdiv = 1; 2635f8c4fba2Skettenis break; 26367a20c0feSkettenis case 1008000000U: 26377a20c0feSkettenis case 816000000U: 26387a20c0feSkettenis case 696000000U: 2639f8c4fba2Skettenis postdiv1 = 2; postdiv2 = refdiv = 1; 2640f8c4fba2Skettenis break; 264198a76083Skettenis case 676000000U: 264298a76083Skettenis postdiv1 = 2; postdiv2 = 1; refdiv = 3; 264398a76083Skettenis break; 264498a76083Skettenis case 1000000000U: 264598a76083Skettenis case 800000000U: 26467a20c0feSkettenis case 600000000U: 2647f8c4fba2Skettenis postdiv1 = 3; postdiv2 = refdiv = 1; 2648f8c4fba2Skettenis break; 264998a76083Skettenis case 594000000U: 265098a76083Skettenis postdiv1 = 4; postdiv2 = refdiv = 1; 265198a76083Skettenis break; 26527a20c0feSkettenis case 408000000U: 2653f8c4fba2Skettenis postdiv1 = postdiv2 = 2; refdiv = 1; 2654f8c4fba2Skettenis break; 2655549c5039Skettenis case 297000000U: 26567a20c0feSkettenis case 216000000U: 2657f8c4fba2Skettenis postdiv1 = 4; postdiv2 = 2; refdiv = 1; 2658f8c4fba2Skettenis break; 2659549c5039Skettenis case 148500000U: 26607a20c0feSkettenis case 96000000U: 2661f8c4fba2Skettenis postdiv1 = postdiv2 = 4; refdiv = 1; 2662f8c4fba2Skettenis break; 2663549c5039Skettenis case 74250000U: 2664549c5039Skettenis postdiv1 = postdiv2 = 4; refdiv = 2; 2665549c5039Skettenis break; 2666549c5039Skettenis case 65000000U: 2667549c5039Skettenis case 54000000U: 2668549c5039Skettenis case 27000000U: 2669549c5039Skettenis postdiv1 = 6; postdiv2 = 4; refdiv = 1; 2670549c5039Skettenis break; 2671f8c4fba2Skettenis default: 26729822ab30Skettenis printf("%s: %d Hz\n", __func__, freq); 2673f8c4fba2Skettenis return -1; 2674f8c4fba2Skettenis } 2675f8c4fba2Skettenis 2676f8c4fba2Skettenis /* Calculate feedback divider. */ 2677f8c4fba2Skettenis fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 2678f8c4fba2Skettenis 2679f8c4fba2Skettenis /* 2680f8c4fba2Skettenis * Select slow mode to guarantee a stable clock while we're 2681f8c4fba2Skettenis * adjusting the PLL. 2682f8c4fba2Skettenis */ 2683f8c4fba2Skettenis HWRITE4(sc, base + 0x000c, 2684f8c4fba2Skettenis RK3399_CRU_PLL_PLL_WORK_MODE_MASK << 16 | 2685f8c4fba2Skettenis RK3399_CRU_PLL_PLL_WORK_MODE_SLOW); 2686f8c4fba2Skettenis 2687f8c4fba2Skettenis /* Set PLL rate. */ 2688f8c4fba2Skettenis HWRITE4(sc, base + 0x0000, 2689f8c4fba2Skettenis RK3399_CRU_PLL_FBDIV_MASK << 16 | 2690f8c4fba2Skettenis fbdiv << RK3399_CRU_PLL_FBDIV_SHIFT); 2691f8c4fba2Skettenis HWRITE4(sc, base + 0x0004, 2692f8c4fba2Skettenis RK3399_CRU_PLL_POSTDIV2_MASK << 16 | 2693f8c4fba2Skettenis postdiv2 << RK3399_CRU_PLL_POSTDIV2_SHIFT | 2694f8c4fba2Skettenis RK3399_CRU_PLL_POSTDIV1_MASK << 16 | 2695f8c4fba2Skettenis postdiv1 << RK3399_CRU_PLL_POSTDIV1_SHIFT | 2696f8c4fba2Skettenis RK3399_CRU_PLL_REFDIV_MASK << 16 | 2697f8c4fba2Skettenis refdiv << RK3399_CRU_PLL_REFDIV_SHIFT); 2698f8c4fba2Skettenis 2699f8c4fba2Skettenis /* Wait for PLL to stabilize. */ 2700f8c4fba2Skettenis while ((HREAD4(sc, base + 0x0008) & RK3399_CRU_PLL_PLL_LOCK) == 0) 2701f8c4fba2Skettenis delay(10); 2702f8c4fba2Skettenis 2703f8c4fba2Skettenis /* Switch back to normal mode. */ 2704f8c4fba2Skettenis HWRITE4(sc, base + 0x000c, 2705f8c4fba2Skettenis RK3399_CRU_PLL_PLL_WORK_MODE_MASK << 16 | 2706f8c4fba2Skettenis RK3399_CRU_PLL_PLL_WORK_MODE_NORMAL); 2707f8c4fba2Skettenis 2708f8c4fba2Skettenis return 0; 2709f8c4fba2Skettenis } 2710f8c4fba2Skettenis 2711f8c4fba2Skettenis uint32_t 2712f8c4fba2Skettenis rk3399_armclk_parent(uint32_t mux) 2713f8c4fba2Skettenis { 2714f8c4fba2Skettenis switch (mux) { 2715f8c4fba2Skettenis case 0: 2716f8c4fba2Skettenis return RK3399_PLL_ALPLL; 2717f8c4fba2Skettenis case 1: 2718f8c4fba2Skettenis return RK3399_PLL_ABPLL; 2719f8c4fba2Skettenis case 2: 2720f8c4fba2Skettenis return RK3399_PLL_DPLL; 2721f8c4fba2Skettenis case 3: 2722f8c4fba2Skettenis return RK3399_PLL_GPLL; 2723f8c4fba2Skettenis } 2724f8c4fba2Skettenis 2725f8c4fba2Skettenis return 0; 2726f8c4fba2Skettenis } 2727f8c4fba2Skettenis 2728592afca7Skettenis uint32_t 272913d6baf8Skettenis rk3399_get_armclk(struct rkclock_softc *sc, bus_size_t clksel) 273013d6baf8Skettenis { 273113d6baf8Skettenis uint32_t reg, mux, div_con; 273213d6baf8Skettenis uint32_t idx; 273313d6baf8Skettenis 273413d6baf8Skettenis reg = HREAD4(sc, clksel); 2735f8c4fba2Skettenis mux = (reg & RK3399_CRU_CORE_PLL_SEL_MASK) >> 2736f8c4fba2Skettenis RK3399_CRU_CORE_PLL_SEL_SHIFT; 2737f8c4fba2Skettenis div_con = (reg & RK3399_CRU_CLK_CORE_DIV_CON_MASK) >> 2738f8c4fba2Skettenis RK3399_CRU_CLK_CORE_DIV_CON_SHIFT; 2739f8c4fba2Skettenis idx = rk3399_armclk_parent(mux); 274013d6baf8Skettenis 274113d6baf8Skettenis return rk3399_get_frequency(sc, &idx) / (div_con + 1); 274213d6baf8Skettenis } 274313d6baf8Skettenis 2744f8c4fba2Skettenis int 2745f8c4fba2Skettenis rk3399_set_armclk(struct rkclock_softc *sc, bus_size_t clksel, uint32_t freq) 2746f8c4fba2Skettenis { 2747f8c4fba2Skettenis uint32_t reg, mux; 2748f8c4fba2Skettenis uint32_t old_freq, div; 2749f8c4fba2Skettenis uint32_t idx; 2750f8c4fba2Skettenis 2751f8c4fba2Skettenis old_freq = rk3399_get_armclk(sc, clksel); 2752f8c4fba2Skettenis if (freq == old_freq) 2753f8c4fba2Skettenis return 0; 2754f8c4fba2Skettenis 2755f8c4fba2Skettenis reg = HREAD4(sc, clksel); 2756f8c4fba2Skettenis mux = (reg & RK3399_CRU_CORE_PLL_SEL_MASK) >> 2757f8c4fba2Skettenis RK3399_CRU_CORE_PLL_SEL_SHIFT; 2758f8c4fba2Skettenis idx = rk3399_armclk_parent(mux); 2759f8c4fba2Skettenis 2760f8c4fba2Skettenis /* Keep the atclk_core and pclk_dbg clocks at or below 200 MHz. */ 2761f8c4fba2Skettenis div = 1; 2762f8c4fba2Skettenis while (freq / (div + 1) > 200000000) 2763f8c4fba2Skettenis div++; 2764f8c4fba2Skettenis 2765f8c4fba2Skettenis /* When ramping up, set clock dividers first. */ 2766f8c4fba2Skettenis if (freq > old_freq) { 27672cb496bcSkettenis HWRITE4(sc, clksel, 2768f8c4fba2Skettenis RK3399_CRU_CLK_CORE_DIV_CON_MASK << 16 | 2769f8c4fba2Skettenis 0 << RK3399_CRU_CLK_CORE_DIV_CON_SHIFT | 2770f8c4fba2Skettenis RK3399_CRU_ACLKM_CORE_DIV_CON_MASK << 16 | 2771f8c4fba2Skettenis 1 << RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT); 27722cb496bcSkettenis HWRITE4(sc, clksel + 0x0004, 2773f8c4fba2Skettenis RK3399_CRU_PCLK_DBG_DIV_CON_MASK << 16 | 2774f8c4fba2Skettenis div << RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT | 2775f8c4fba2Skettenis RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 | 2776f8c4fba2Skettenis div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT); 2777f8c4fba2Skettenis } 2778f8c4fba2Skettenis 2779f8c4fba2Skettenis rk3399_set_frequency(sc, &idx, freq); 2780f8c4fba2Skettenis 27814cecc5e3Skettenis /* When ramping down, set clock dividers last. */ 2782f8c4fba2Skettenis if (freq < old_freq) { 27832cb496bcSkettenis HWRITE4(sc, clksel, 2784f8c4fba2Skettenis RK3399_CRU_CLK_CORE_DIV_CON_MASK << 16 | 2785f8c4fba2Skettenis 0 << RK3399_CRU_CLK_CORE_DIV_CON_SHIFT | 2786f8c4fba2Skettenis RK3399_CRU_ACLKM_CORE_DIV_CON_MASK << 16 | 2787f8c4fba2Skettenis 1 << RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT); 27882cb496bcSkettenis HWRITE4(sc, clksel + 0x0004, 2789f8c4fba2Skettenis RK3399_CRU_PCLK_DBG_DIV_CON_MASK << 16 | 2790f8c4fba2Skettenis div << RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT | 2791f8c4fba2Skettenis RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 | 2792f8c4fba2Skettenis div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT); 2793f8c4fba2Skettenis } 2794f8c4fba2Skettenis 2795f8c4fba2Skettenis return 0; 2796f8c4fba2Skettenis } 2797f8c4fba2Skettenis 279813d6baf8Skettenis uint32_t 2799a21015c5Skettenis rk3399_get_frac(struct rkclock_softc *sc, uint32_t parent, bus_size_t base) 2800caf123d1Skettenis { 2801a21015c5Skettenis uint32_t parent_freq, frac; 2802caf123d1Skettenis uint16_t n, d; 2803caf123d1Skettenis 2804caf123d1Skettenis frac = HREAD4(sc, base); 2805caf123d1Skettenis n = frac >> 16; 2806caf123d1Skettenis d = frac & 0xffff; 2807a21015c5Skettenis if (n == 0 || d == 0) 2808a21015c5Skettenis n = d = 1; 2809a21015c5Skettenis parent_freq = sc->sc_cd.cd_get_frequency(sc, &parent); 2810a21015c5Skettenis return ((uint64_t)parent_freq * n) / d; 2811caf123d1Skettenis } 2812caf123d1Skettenis 2813caf123d1Skettenis int 2814a21015c5Skettenis rk3399_set_frac(struct rkclock_softc *sc, uint32_t parent, bus_size_t base, 2815caf123d1Skettenis uint32_t freq) 2816caf123d1Skettenis { 2817caf123d1Skettenis uint32_t n, d; 2818caf123d1Skettenis uint32_t p0, p1, p2; 2819caf123d1Skettenis uint32_t q0, q1, q2; 2820caf123d1Skettenis uint32_t a, tmp; 2821caf123d1Skettenis 2822caf123d1Skettenis n = freq; 2823a21015c5Skettenis d = sc->sc_cd.cd_get_frequency(sc, &parent); 2824caf123d1Skettenis 2825caf123d1Skettenis /* 2826caf123d1Skettenis * The denominator needs to be at least 20 times the numerator 2827caf123d1Skettenis * for a stable clock. 2828caf123d1Skettenis */ 2829caf123d1Skettenis if (n == 0 || d == 0 || d < 20 * n) 2830caf123d1Skettenis return -1; 2831caf123d1Skettenis 2832caf123d1Skettenis /* 2833caf123d1Skettenis * This is a simplified implementation of the algorithm to 2834caf123d1Skettenis * calculate the best rational approximation using continued 2835caf123d1Skettenis * fractions. 2836caf123d1Skettenis */ 2837caf123d1Skettenis 2838caf123d1Skettenis p0 = q1 = 0; 2839caf123d1Skettenis p1 = q0 = 1; 2840caf123d1Skettenis 2841caf123d1Skettenis while (d != 0) { 2842caf123d1Skettenis /* 2843caf123d1Skettenis * Calculate next coefficient in the continued 2844caf123d1Skettenis * fraction and keep track of the remainder. 2845caf123d1Skettenis */ 2846caf123d1Skettenis tmp = d; 2847caf123d1Skettenis a = n / d; 2848caf123d1Skettenis d = n % d; 2849caf123d1Skettenis n = tmp; 2850caf123d1Skettenis 2851caf123d1Skettenis /* 2852caf123d1Skettenis * Calculate next approximation in the series based on 2853caf123d1Skettenis * the current coefficient. 2854caf123d1Skettenis */ 2855caf123d1Skettenis p2 = p0 + a * p1; 2856caf123d1Skettenis q2 = q0 + a * q1; 2857caf123d1Skettenis 2858caf123d1Skettenis /* 2859caf123d1Skettenis * Terminate if we reached the maximum allowed 2860caf123d1Skettenis * denominator. 2861caf123d1Skettenis */ 2862caf123d1Skettenis if (q2 > 0xffff) 2863caf123d1Skettenis break; 2864caf123d1Skettenis 2865caf123d1Skettenis p0 = p1; p1 = p2; 2866caf123d1Skettenis q0 = q1; q1 = q2; 2867caf123d1Skettenis } 2868caf123d1Skettenis 2869caf123d1Skettenis HWRITE4(sc, base, p1 << 16 | q1); 2870caf123d1Skettenis return 0; 2871caf123d1Skettenis } 2872caf123d1Skettenis 2873caf123d1Skettenis uint32_t 2874592afca7Skettenis rk3399_get_frequency(void *cookie, uint32_t *cells) 2875592afca7Skettenis { 2876592afca7Skettenis struct rkclock_softc *sc = cookie; 2877592afca7Skettenis uint32_t idx = cells[0]; 2878592afca7Skettenis 2879592afca7Skettenis switch (idx) { 288013d6baf8Skettenis case RK3399_PLL_ALPLL: 288113d6baf8Skettenis return rk3399_get_pll(sc, RK3399_CRU_LPLL_CON(0)); 288213d6baf8Skettenis case RK3399_PLL_ABPLL: 288313d6baf8Skettenis return rk3399_get_pll(sc, RK3399_CRU_BPLL_CON(0)); 288413d6baf8Skettenis case RK3399_PLL_DPLL: 288513d6baf8Skettenis return rk3399_get_pll(sc, RK3399_CRU_DPLL_CON(0)); 2886d9457073Skettenis case RK3399_PLL_CPLL: 2887d9457073Skettenis return rk3399_get_pll(sc, RK3399_CRU_CPLL_CON(0)); 2888d9457073Skettenis case RK3399_PLL_GPLL: 2889d9457073Skettenis return rk3399_get_pll(sc, RK3399_CRU_GPLL_CON(0)); 2890f89cc881Skettenis case RK3399_PLL_NPLL: 2891f89cc881Skettenis return rk3399_get_pll(sc, RK3399_CRU_NPLL_CON(0)); 289298a76083Skettenis case RK3399_PLL_VPLL: 289398a76083Skettenis return rk3399_get_pll(sc, RK3399_CRU_VPLL_CON(0)); 289413d6baf8Skettenis case RK3399_ARMCLKL: 289513d6baf8Skettenis return rk3399_get_armclk(sc, RK3399_CRU_CLKSEL_CON(0)); 289613d6baf8Skettenis case RK3399_ARMCLKB: 289713d6baf8Skettenis return rk3399_get_armclk(sc, RK3399_CRU_CLKSEL_CON(2)); 28987371cc19Skettenis case RK3399_XIN24M: 28997371cc19Skettenis return 24000000; 29002aa5f6a3Skettenis case RK3399_CLK_32K: 29012aa5f6a3Skettenis return 32768; 29027a7bc0a4Spatrick case RK3399_XIN12M: 29037a7bc0a4Spatrick return 12000000; 2904caf123d1Skettenis case RK3399_CLK_I2S0_FRAC: 2905caf123d1Skettenis return rk3399_get_frac(sc, RK3399_CLK_I2S0_DIV, 2906caf123d1Skettenis RK3399_CRU_CLKSEL_CON(96)); 2907caf123d1Skettenis case RK3399_CLK_I2S1_FRAC: 2908caf123d1Skettenis return rk3399_get_frac(sc, RK3399_CLK_I2S1_DIV, 2909caf123d1Skettenis RK3399_CRU_CLKSEL_CON(97)); 2910caf123d1Skettenis case RK3399_CLK_I2S2_FRAC: 2911caf123d1Skettenis return rk3399_get_frac(sc, RK3399_CLK_I2S2_DIV, 2912caf123d1Skettenis RK3399_CRU_CLKSEL_CON(98)); 2913592afca7Skettenis default: 2914592afca7Skettenis break; 2915592afca7Skettenis } 2916592afca7Skettenis 29177371cc19Skettenis return rkclock_get_frequency(sc, idx); 2918592afca7Skettenis } 2919592afca7Skettenis 2920592afca7Skettenis int 2921592afca7Skettenis rk3399_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 2922592afca7Skettenis { 2923f8c4fba2Skettenis struct rkclock_softc *sc = cookie; 2924592afca7Skettenis uint32_t idx = cells[0]; 2925592afca7Skettenis 2926f8c4fba2Skettenis switch (idx) { 2927f8c4fba2Skettenis case RK3399_PLL_ALPLL: 2928f8c4fba2Skettenis return rk3399_set_pll(sc, RK3399_CRU_LPLL_CON(0), freq); 2929f8c4fba2Skettenis case RK3399_PLL_ABPLL: 2930f8c4fba2Skettenis return rk3399_set_pll(sc, RK3399_CRU_BPLL_CON(0), freq); 293198a76083Skettenis case RK3399_PLL_CPLL: 293298a76083Skettenis return rk3399_set_pll(sc, RK3399_CRU_CPLL_CON(0), freq); 293398a76083Skettenis case RK3399_PLL_GPLL: 293498a76083Skettenis return rk3399_set_pll(sc, RK3399_CRU_GPLL_CON(0), freq); 293598a76083Skettenis case RK3399_PLL_NPLL: 293698a76083Skettenis return rk3399_set_pll(sc, RK3399_CRU_NPLL_CON(0), freq); 2937549c5039Skettenis case RK3399_PLL_VPLL: 2938549c5039Skettenis return rk3399_set_pll(sc, RK3399_CRU_VPLL_CON(0), freq); 2939f8c4fba2Skettenis case RK3399_ARMCLKL: 2940f8c4fba2Skettenis return rk3399_set_armclk(sc, RK3399_CRU_CLKSEL_CON(0), freq); 2941f8c4fba2Skettenis case RK3399_ARMCLKB: 2942f8c4fba2Skettenis return rk3399_set_armclk(sc, RK3399_CRU_CLKSEL_CON(2), freq); 2943caf123d1Skettenis case RK3399_CLK_I2S0_8CH: 2944caf123d1Skettenis rkclock_set_parent(sc, idx, RK3399_CLK_I2S0_FRAC); 2945caf123d1Skettenis return rkclock_set_frequency(sc, idx, freq); 2946caf123d1Skettenis case RK3399_CLK_I2S1_8CH: 2947caf123d1Skettenis rkclock_set_parent(sc, idx, RK3399_CLK_I2S1_FRAC); 2948caf123d1Skettenis return rkclock_set_frequency(sc, idx, freq); 2949caf123d1Skettenis case RK3399_CLK_I2S2_8CH: 2950caf123d1Skettenis rkclock_set_parent(sc, idx, RK3399_CLK_I2S2_FRAC); 2951caf123d1Skettenis return rkclock_set_frequency(sc, idx, freq); 29527a7bc0a4Spatrick case RK3399_XIN12M: 29537a7bc0a4Spatrick if (freq / (1000 * 1000) != 12) 29547a7bc0a4Spatrick return -1; 29557a7bc0a4Spatrick return 0; 2956caf123d1Skettenis case RK3399_CLK_I2S0_FRAC: 2957caf123d1Skettenis return rk3399_set_frac(sc, RK3399_CLK_I2S0_DIV, 2958caf123d1Skettenis RK3399_CRU_CLKSEL_CON(96), freq); 2959caf123d1Skettenis case RK3399_CLK_I2S1_FRAC: 2960caf123d1Skettenis return rk3399_set_frac(sc, RK3399_CLK_I2S1_DIV, 2961caf123d1Skettenis RK3399_CRU_CLKSEL_CON(97), freq); 2962caf123d1Skettenis case RK3399_CLK_I2S2_FRAC: 2963caf123d1Skettenis return rk3399_set_frac(sc, RK3399_CLK_I2S2_DIV, 2964caf123d1Skettenis RK3399_CRU_CLKSEL_CON(98), freq); 296598a76083Skettenis default: 296698a76083Skettenis break; 2967f8c4fba2Skettenis } 2968f8c4fba2Skettenis 29697371cc19Skettenis return rkclock_set_frequency(sc, idx, freq); 2970592afca7Skettenis } 2971592afca7Skettenis 29725486a9fbSpatrick 29735486a9fbSpatrick int 29745486a9fbSpatrick rk3399_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 29755486a9fbSpatrick { 29765486a9fbSpatrick struct rkclock_softc *sc = cookie; 29775486a9fbSpatrick 29785486a9fbSpatrick if (pcells[0] != sc->sc_phandle) 29795486a9fbSpatrick return -1; 29805486a9fbSpatrick 29815486a9fbSpatrick return rkclock_set_parent(sc, cells[0], pcells[1]); 29825486a9fbSpatrick } 29835486a9fbSpatrick 2984592afca7Skettenis void 2985592afca7Skettenis rk3399_enable(void *cookie, uint32_t *cells, int on) 2986592afca7Skettenis { 2987875e49c6Spatrick struct rkclock_softc *sc = cookie; 2988592afca7Skettenis uint32_t idx = cells[0]; 2989592afca7Skettenis 299044eccc75Skettenis /* 2991875e49c6Spatrick * All clocks are enabled upon hardware reset, but on some boards the 2992875e49c6Spatrick * firmware will disable some of them. Handle those here. 299344eccc75Skettenis */ 2994875e49c6Spatrick if (!on) { 2995592afca7Skettenis printf("%s: 0x%08x\n", __func__, idx); 2996875e49c6Spatrick return; 2997875e49c6Spatrick } 2998875e49c6Spatrick 2999875e49c6Spatrick switch (idx) { 30002479590bSkettenis case RK3399_CLK_USB2PHY0_REF: 3001*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(6), (1 << 5) << 16); 30022479590bSkettenis break; 30032479590bSkettenis case RK3399_CLK_USB2PHY1_REF: 3004*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(6), (1 << 6) << 16); 30052479590bSkettenis break; 30062479590bSkettenis case RK3399_CLK_UPHY0_TCPDPHY_REF: 3007*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(13), (1 << 4) << 16); 30082479590bSkettenis break; 30092479590bSkettenis case RK3399_CLK_UPHY0_TCPDCORE: 3010*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(13), (1 << 5) << 16); 30112479590bSkettenis break; 30122479590bSkettenis case RK3399_CLK_UPHY1_TCPDPHY_REF: 3013*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(13), (1 << 6) << 16); 30142479590bSkettenis break; 30152479590bSkettenis case RK3399_CLK_UPHY1_TCPDCORE: 3016*41b6ab1fSkettenis HWRITE4(sc, RK3399_CRU_CLKGATE_CON(13), (1 << 7) << 16); 30172479590bSkettenis break; 3018875e49c6Spatrick case RK3399_ACLK_GMAC: 3019875e49c6Spatrick HWRITE4(sc, RK3399_CRU_CLKGATE_CON(32), (1 << 0) << 16); 3020875e49c6Spatrick break; 3021875e49c6Spatrick case RK3399_PCLK_GMAC: 3022875e49c6Spatrick HWRITE4(sc, RK3399_CRU_CLKGATE_CON(32), (1 << 2) << 16); 3023875e49c6Spatrick break; 3024875e49c6Spatrick case RK3399_CLK_MAC: 3025875e49c6Spatrick HWRITE4(sc, RK3399_CRU_CLKGATE_CON(5), (1 << 5) << 16); 3026875e49c6Spatrick break; 3027875e49c6Spatrick case RK3399_CLK_MAC_RX: 3028875e49c6Spatrick HWRITE4(sc, RK3399_CRU_CLKGATE_CON(5), (1 << 8) << 16); 3029875e49c6Spatrick break; 3030875e49c6Spatrick case RK3399_CLK_MAC_TX: 3031875e49c6Spatrick HWRITE4(sc, RK3399_CRU_CLKGATE_CON(5), (1 << 9) << 16); 3032875e49c6Spatrick break; 3033875e49c6Spatrick } 3034592afca7Skettenis } 3035592afca7Skettenis 3036592afca7Skettenis void 3037592afca7Skettenis rk3399_reset(void *cookie, uint32_t *cells, int on) 3038592afca7Skettenis { 303964b62fe2Skettenis struct rkclock_softc *sc = cookie; 3040592afca7Skettenis uint32_t idx = cells[0]; 304164b62fe2Skettenis uint32_t mask = (1 << (idx % 16)); 3042592afca7Skettenis 304364b62fe2Skettenis HWRITE4(sc, RK3399_CRU_SOFTRST_CON(idx / 16), 304464b62fe2Skettenis mask << 16 | (on ? mask : 0)); 3045592afca7Skettenis } 3046592afca7Skettenis 3047f8c4fba2Skettenis /* PMUCRU */ 3048f8c4fba2Skettenis 304937c734d3Snaddy const struct rkclock rk3399_pmu_clocks[] = { 30507371cc19Skettenis { 30517371cc19Skettenis RK3399_CLK_I2C0, RK3399_PMUCRU_CLKSEL_CON(2), 30527371cc19Skettenis 0, DIV(6, 0), 30537371cc19Skettenis { RK3399_PLL_PPLL } 30547371cc19Skettenis }, 30557371cc19Skettenis { 30567371cc19Skettenis RK3399_CLK_I2C4, RK3399_PMUCRU_CLKSEL_CON(3), 30577371cc19Skettenis 0, DIV(6, 0), 30587371cc19Skettenis { RK3399_PLL_PPLL } 30597371cc19Skettenis }, 30607371cc19Skettenis { 30617371cc19Skettenis RK3399_CLK_I2C8, RK3399_PMUCRU_CLKSEL_CON(2), 30627371cc19Skettenis 0, DIV(14, 8), 30637371cc19Skettenis { RK3399_PLL_PPLL } 30647371cc19Skettenis }, 30657371cc19Skettenis { 30668c9e697fSpatrick RK3399_PCLK_RKPWM, RK3399_PMUCRU_CLKSEL_CON(0), 30678c9e697fSpatrick 0, DIV(6, 0), 30688c9e697fSpatrick { RK3399_PLL_PPLL } 30698c9e697fSpatrick }, 30708c9e697fSpatrick { 30717371cc19Skettenis /* Sentinel */ 30727371cc19Skettenis } 30737371cc19Skettenis }; 30747371cc19Skettenis 3075ad8cadefSkettenis void 3076ad8cadefSkettenis rk3399_pmu_init(struct rkclock_softc *sc) 3077ad8cadefSkettenis { 30787371cc19Skettenis sc->sc_clocks = rk3399_pmu_clocks; 3079ad8cadefSkettenis rk3399_pmucru_sc = sc; 3080ad8cadefSkettenis } 3081ad8cadefSkettenis 3082ad8cadefSkettenis uint32_t 3083592afca7Skettenis rk3399_pmu_get_frequency(void *cookie, uint32_t *cells) 3084592afca7Skettenis { 3085ad8cadefSkettenis struct rkclock_softc *sc = cookie; 3086592afca7Skettenis uint32_t idx = cells[0]; 3087592afca7Skettenis 3088ad8cadefSkettenis switch (idx) { 3089ad8cadefSkettenis case RK3399_PLL_PPLL: 3090ad8cadefSkettenis return rk3399_get_pll(sc, RK3399_PMUCRU_PPLL_CON(0)); 3091ad8cadefSkettenis default: 3092ad8cadefSkettenis break; 3093ad8cadefSkettenis } 3094ad8cadefSkettenis 30957371cc19Skettenis return rkclock_get_frequency(sc, idx); 3096592afca7Skettenis } 3097592afca7Skettenis 3098592afca7Skettenis int 3099592afca7Skettenis rk3399_pmu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 3100592afca7Skettenis { 310198a76083Skettenis struct rkclock_softc *sc = cookie; 3102592afca7Skettenis uint32_t idx = cells[0]; 3103592afca7Skettenis 310498a76083Skettenis switch (idx) { 310598a76083Skettenis case RK3399_PLL_PPLL: 310698a76083Skettenis return rk3399_set_pll(sc, RK3399_PMUCRU_PPLL_CON(0), freq); 310798a76083Skettenis default: 310898a76083Skettenis break; 310998a76083Skettenis } 311098a76083Skettenis 31117371cc19Skettenis return rkclock_set_frequency(sc, idx, freq); 3112592afca7Skettenis } 3113592afca7Skettenis 3114592afca7Skettenis void 3115592afca7Skettenis rk3399_pmu_enable(void *cookie, uint32_t *cells, int on) 3116592afca7Skettenis { 3117592afca7Skettenis uint32_t idx = cells[0]; 3118592afca7Skettenis 3119ad8cadefSkettenis switch (idx) { 3120ad8cadefSkettenis case RK3399_CLK_I2C0: 3121ad8cadefSkettenis case RK3399_CLK_I2C4: 3122ad8cadefSkettenis case RK3399_CLK_I2C8: 3123ad8cadefSkettenis case RK3399_PCLK_I2C0: 3124ad8cadefSkettenis case RK3399_PCLK_I2C4: 3125ad8cadefSkettenis case RK3399_PCLK_I2C8: 31268c9e697fSpatrick case RK3399_PCLK_RKPWM: 3127ad8cadefSkettenis /* Enabled by default. */ 3128ad8cadefSkettenis break; 3129ad8cadefSkettenis default: 3130592afca7Skettenis printf("%s: 0x%08x\n", __func__, idx); 3131ad8cadefSkettenis break; 3132ad8cadefSkettenis } 3133592afca7Skettenis } 3134592afca7Skettenis 3135592afca7Skettenis void 3136592afca7Skettenis rk3399_pmu_reset(void *cookie, uint32_t *cells, int on) 3137592afca7Skettenis { 3138592afca7Skettenis uint32_t idx = cells[0]; 3139592afca7Skettenis 3140592afca7Skettenis printf("%s: 0x%08x\n", __func__, idx); 3141592afca7Skettenis } 314233081393Skettenis 314333081393Skettenis /* 314433081393Skettenis * Rockchip RK3568 314533081393Skettenis */ 314633081393Skettenis 314733081393Skettenis const struct rkclock rk3568_clocks[] = { 314833081393Skettenis { 31491f8e42a5Sdlg RK3568_BCLK_EMMC, RK3568_CRU_CLKSEL_CON(28), 31501f8e42a5Sdlg SEL(9, 8), 0, 31511f8e42a5Sdlg { RK3568_GPLL_200M, RK3568_GPLL_150M, RK3568_CPLL_125M } 31521f8e42a5Sdlg }, 31531f8e42a5Sdlg { 31541f8e42a5Sdlg RK3568_CCLK_EMMC, RK3568_CRU_CLKSEL_CON(28), 31551f8e42a5Sdlg SEL(14, 12), 0, 31561f8e42a5Sdlg { RK3568_XIN24M, RK3568_GPLL_200M, RK3568_GPLL_150M, 31571f8e42a5Sdlg RK3568_CPLL_100M, RK3568_CPLL_50M, RK3568_CLK_OSC0_DIV_375K } 31581f8e42a5Sdlg }, 31591f8e42a5Sdlg { 31601f8e42a5Sdlg RK3568_TCLK_EMMC, 0, 0, 0, 31611f8e42a5Sdlg { RK3568_XIN24M } 31621f8e42a5Sdlg }, 31631f8e42a5Sdlg 31641f8e42a5Sdlg { 3165c935b871Skettenis RK3568_ACLK_PHP, RK3568_CRU_CLKSEL_CON(30), 3166c935b871Skettenis SEL(1, 0), 0, 3167c935b871Skettenis { RK3568_GPLL_300M, RK3568_GPLL_200M, 3168c935b871Skettenis RK3568_GPLL_100M, RK3568_XIN24M } 3169c935b871Skettenis }, 3170c935b871Skettenis { 3171c935b871Skettenis RK3568_PCLK_PHP, RK3568_CRU_CLKSEL_CON(30), 3172c935b871Skettenis 0, DIV(7, 4), 3173c935b871Skettenis { RK3568_ACLK_PHP } 3174c935b871Skettenis }, 3175c935b871Skettenis { 317633081393Skettenis RK3568_CLK_SDMMC0, RK3568_CRU_CLKSEL_CON(30), 317733081393Skettenis SEL(10, 8), 0, 317833081393Skettenis { RK3568_XIN24M, RK3568_GPLL_400M, RK3568_GPLL_300M, 317933081393Skettenis RK3568_CPLL_100M, RK3568_CPLL_50M, RK3568_CLK_OSC0_DIV_750K } 318033081393Skettenis }, 318133081393Skettenis { 318233081393Skettenis RK3568_CLK_SDMMC1, RK3568_CRU_CLKSEL_CON(30), 318333081393Skettenis SEL(14, 12), 0, 318433081393Skettenis { RK3568_XIN24M, RK3568_GPLL_400M, RK3568_GPLL_300M, 318533081393Skettenis RK3568_CPLL_100M, RK3568_CPLL_50M, RK3568_CLK_OSC0_DIV_750K } 318633081393Skettenis }, 318733081393Skettenis { 318815d3c08bSkettenis RK3568_CLK_SDMMC2, RK3568_CRU_CLKSEL_CON(32), 318915d3c08bSkettenis SEL(10, 8), 0, 319015d3c08bSkettenis { RK3568_XIN24M, RK3568_GPLL_400M, RK3568_GPLL_300M, 319115d3c08bSkettenis RK3568_CPLL_100M, RK3568_CPLL_50M, RK3568_CLK_OSC0_DIV_750K } 319215d3c08bSkettenis }, 319315d3c08bSkettenis { 3194c935b871Skettenis RK3568_ACLK_GMAC0, 0, 0, 0, 3195c935b871Skettenis { RK3568_ACLK_PHP } 3196c935b871Skettenis }, 3197c935b871Skettenis { 3198c935b871Skettenis RK3568_PCLK_GMAC0, 0, 0, 0, 3199c935b871Skettenis { RK3568_PCLK_PHP } 3200c935b871Skettenis }, 3201c935b871Skettenis { 3202c935b871Skettenis RK3568_CLK_MAC0_2TOP, RK3568_CRU_CLKSEL_CON(31), 3203c935b871Skettenis SEL(9, 8), 0, 3204c935b871Skettenis { RK3568_CPLL_125M, RK3568_CPLL_50M, 3205c935b871Skettenis RK3568_CPLL_25M, RK3568_XIN24M } 3206c935b871Skettenis }, 3207c935b871Skettenis { 3208c935b871Skettenis RK3568_CLK_MAC0_REFOUT, 0, 0, 0, 3209c935b871Skettenis { RK3568_CLK_MAC0_2TOP } 3210c935b871Skettenis }, 3211c935b871Skettenis { 3212c935b871Skettenis RK3568_CLK_GMAC0_PTP_REF, RK3568_CRU_CLKSEL_CON(31), 3213c935b871Skettenis SEL(13, 12), 0, 3214c935b871Skettenis { RK3568_CPLL_62P5M, RK3568_GPLL_100M, 3215c935b871Skettenis RK3568_CPLL_50M, RK3568_XIN24M } 3216c935b871Skettenis }, 3217c935b871Skettenis { 3218c935b871Skettenis RK3568_ACLK_USB, RK3568_CRU_CLKSEL_CON(32), 3219c935b871Skettenis SEL(1, 0), 0, 3220c935b871Skettenis { RK3568_GPLL_300M, RK3568_GPLL_200M, 3221c935b871Skettenis RK3568_GPLL_100M, RK3568_XIN24M } 3222c935b871Skettenis }, 3223c935b871Skettenis { 3224c935b871Skettenis RK3568_PCLK_USB, RK3568_CRU_CLKSEL_CON(32), 3225c935b871Skettenis 0, DIV(7, 4), 3226c935b871Skettenis { RK3568_ACLK_USB } 3227c935b871Skettenis }, 3228c935b871Skettenis { 3229c935b871Skettenis RK3568_ACLK_GMAC1, 0, 0, 0, 3230c935b871Skettenis { RK3568_ACLK_USB } 3231c935b871Skettenis }, 3232c935b871Skettenis { 3233c935b871Skettenis RK3568_PCLK_GMAC1, 0, 0, 0, 3234c935b871Skettenis { RK3568_PCLK_USB } 3235c935b871Skettenis }, 3236c935b871Skettenis { 3237c935b871Skettenis RK3568_CLK_MAC1_2TOP, RK3568_CRU_CLKSEL_CON(33), 3238c935b871Skettenis SEL(9, 8), 0, 3239c935b871Skettenis { RK3568_CPLL_125M, RK3568_CPLL_50M, 3240c935b871Skettenis RK3568_CPLL_25M, RK3568_XIN24M } 3241c935b871Skettenis }, 3242c935b871Skettenis { 3243c935b871Skettenis RK3568_CLK_MAC1_REFOUT, 0, 0, 0, 3244c935b871Skettenis { RK3568_CLK_MAC1_2TOP } 3245c935b871Skettenis }, 3246c935b871Skettenis { 3247c935b871Skettenis RK3568_CLK_GMAC1_PTP_REF, RK3568_CRU_CLKSEL_CON(33), 3248c935b871Skettenis SEL(13, 12), 0, 3249c935b871Skettenis { RK3568_CPLL_62P5M, RK3568_GPLL_100M, 3250c935b871Skettenis RK3568_CPLL_50M, RK3568_XIN24M } 3251c935b871Skettenis }, 3252c935b871Skettenis { 3253422309e7Skettenis RK3568_CLK_TSADC_TSEN, RK3568_CRU_CLKSEL_CON(51), 3254422309e7Skettenis SEL(5, 4), DIV(2, 0), 3255422309e7Skettenis { RK3568_XIN24M, RK3568_GPLL_100M, RK3568_CPLL_100M } 3256422309e7Skettenis }, 3257422309e7Skettenis { 3258422309e7Skettenis RK3568_CLK_TSADC, RK3568_CRU_CLKSEL_CON(51), 3259422309e7Skettenis 0, DIV(14, 8), 3260422309e7Skettenis { RK3568_CLK_TSADC_TSEN } 3261422309e7Skettenis }, 3262422309e7Skettenis { 326333081393Skettenis RK3568_SCLK_UART1, RK3568_CRU_CLKSEL_CON(52), 326433081393Skettenis SEL(13, 12), 0, 326533081393Skettenis { 0, 0, RK3568_XIN24M } 326633081393Skettenis }, 326733081393Skettenis { 326833081393Skettenis RK3568_SCLK_UART2, RK3568_CRU_CLKSEL_CON(54), 326933081393Skettenis SEL(13, 12), 0, 327033081393Skettenis { 0, 0, RK3568_XIN24M } 327133081393Skettenis }, 327233081393Skettenis { 327333081393Skettenis RK3568_SCLK_UART3, RK3568_CRU_CLKSEL_CON(56), 327433081393Skettenis SEL(13, 12), 0, 327533081393Skettenis { 0, 0, RK3568_XIN24M } 327633081393Skettenis }, 327733081393Skettenis { 327833081393Skettenis RK3568_SCLK_UART4, RK3568_CRU_CLKSEL_CON(58), 327933081393Skettenis SEL(13, 12), 0, 328033081393Skettenis { 0, 0, RK3568_XIN24M } 328133081393Skettenis }, 328233081393Skettenis { 328333081393Skettenis RK3568_SCLK_UART5, RK3568_CRU_CLKSEL_CON(60), 328433081393Skettenis SEL(13, 12), 0, 328533081393Skettenis { 0, 0, RK3568_XIN24M } 328633081393Skettenis }, 328733081393Skettenis { 328833081393Skettenis RK3568_SCLK_UART6, RK3568_CRU_CLKSEL_CON(62), 328933081393Skettenis SEL(13, 12), 0, 329033081393Skettenis { 0, 0, RK3568_XIN24M } 329133081393Skettenis }, 329233081393Skettenis { 329333081393Skettenis RK3568_SCLK_UART7, RK3568_CRU_CLKSEL_CON(64), 329433081393Skettenis SEL(13, 12), 0, 329533081393Skettenis { 0, 0, RK3568_XIN24M } 329633081393Skettenis }, 329733081393Skettenis { 329833081393Skettenis RK3568_SCLK_UART8, RK3568_CRU_CLKSEL_CON(66), 329933081393Skettenis SEL(13, 12), 0, 330033081393Skettenis { 0, 0, RK3568_XIN24M } 330133081393Skettenis }, 330233081393Skettenis { 330333081393Skettenis RK3568_SCLK_UART9, RK3568_CRU_CLKSEL_CON(68), 330433081393Skettenis SEL(13, 12), 0, 330533081393Skettenis { 0, 0, RK3568_XIN24M } 330633081393Skettenis }, 330733081393Skettenis { 330833081393Skettenis RK3568_CLK_I2C, RK3568_CRU_CLKSEL_CON(71), 330933081393Skettenis SEL(9, 8), 0, 331033081393Skettenis { 0, 0, RK3568_XIN24M } 331133081393Skettenis }, 331233081393Skettenis { 331333081393Skettenis RK3568_CLK_I2C1, 0, 0, 0, 331433081393Skettenis { RK3568_CLK_I2C } 331533081393Skettenis }, 331633081393Skettenis { 331733081393Skettenis RK3568_CLK_I2C2, 0, 0, 0, 331833081393Skettenis { RK3568_CLK_I2C } 331933081393Skettenis }, 332033081393Skettenis { 332133081393Skettenis RK3568_CLK_I2C3, 0, 0, 0, 332233081393Skettenis { RK3568_CLK_I2C } 332333081393Skettenis }, 332433081393Skettenis { 332533081393Skettenis RK3568_CLK_I2C4, 0, 0, 0, 332633081393Skettenis { RK3568_CLK_I2C } 332733081393Skettenis }, 332833081393Skettenis { 332933081393Skettenis RK3568_CLK_I2C5, 0, 0, 0, 333033081393Skettenis { RK3568_CLK_I2C } 333133081393Skettenis }, 333233081393Skettenis { 333317449d5cSkettenis RK3568_CLK_SPI0, RK3568_CRU_CLKSEL_CON(72), 333417449d5cSkettenis SEL(1, 0), 0, 333517449d5cSkettenis { RK3568_GPLL_200M, RK3568_XIN24M, RK3568_CPLL_100M } 333617449d5cSkettenis }, 333717449d5cSkettenis { 333817449d5cSkettenis RK3568_CLK_SPI1, RK3568_CRU_CLKSEL_CON(72), 333917449d5cSkettenis SEL(3, 2), 0, 334017449d5cSkettenis { RK3568_GPLL_200M, RK3568_XIN24M, RK3568_CPLL_100M } 334117449d5cSkettenis }, 334217449d5cSkettenis { 334317449d5cSkettenis RK3568_CLK_SPI2, RK3568_CRU_CLKSEL_CON(72), 334417449d5cSkettenis SEL(5, 4), 0, 334517449d5cSkettenis { RK3568_GPLL_200M, RK3568_XIN24M, RK3568_CPLL_100M } 334617449d5cSkettenis }, 334717449d5cSkettenis { 334817449d5cSkettenis RK3568_CLK_SPI3, RK3568_CRU_CLKSEL_CON(72), 334917449d5cSkettenis SEL(7, 6), 0, 335017449d5cSkettenis { RK3568_GPLL_200M, RK3568_XIN24M, RK3568_CPLL_100M } 335117449d5cSkettenis }, 335217449d5cSkettenis { 3353c935b871Skettenis RK3568_SCLK_GMAC0, RK3568_CRU_CLKSEL_CON(31), 3354c935b871Skettenis SEL(2, 2), 0, 3355c935b871Skettenis { RK3568_CLK_MAC0_2TOP, RK3568_GMAC0_CLKIN } 3356c935b871Skettenis }, 3357c935b871Skettenis { 3358c935b871Skettenis RK3568_SCLK_GMAC0_RGMII_SPEED, RK3568_CRU_CLKSEL_CON(31), 3359c935b871Skettenis SEL(5, 4), 0, 3360c935b871Skettenis { RK3568_SCLK_GMAC0, RK3568_SCLK_GMAC0, 3361c935b871Skettenis RK3568_SCLK_GMAC0_DIV_50, RK3568_SCLK_GMAC0_DIV_5 } 3362c935b871Skettenis }, 3363c935b871Skettenis { 3364c935b871Skettenis RK3568_SCLK_GMAC0_RMII_SPEED, RK3568_CRU_CLKSEL_CON(31), 3365c935b871Skettenis SEL(3, 3), 0, 3366c935b871Skettenis { RK3568_SCLK_GMAC0_DIV_20, RK3568_SCLK_GMAC0_DIV_2 } 3367c935b871Skettenis }, 3368c935b871Skettenis { 3369c935b871Skettenis RK3568_SCLK_GMAC0_RX_TX, RK3568_CRU_CLKSEL_CON(31), 3370c935b871Skettenis SEL(1, 0), 0, 3371c935b871Skettenis { RK3568_SCLK_GMAC0_RGMII_SPEED, RK3568_SCLK_GMAC0_RMII_SPEED } 3372c935b871Skettenis }, 3373c935b871Skettenis { 3374c935b871Skettenis RK3568_SCLK_GMAC1, RK3568_CRU_CLKSEL_CON(33), 3375c935b871Skettenis SEL(2, 2), 0, 3376c935b871Skettenis { RK3568_CLK_MAC1_2TOP, RK3568_GMAC1_CLKIN } 3377c935b871Skettenis }, 3378c935b871Skettenis { 3379c935b871Skettenis RK3568_SCLK_GMAC1_RGMII_SPEED, RK3568_CRU_CLKSEL_CON(33), 3380c935b871Skettenis SEL(5, 4), 0, 3381c935b871Skettenis { RK3568_SCLK_GMAC1, RK3568_SCLK_GMAC1, 3382c935b871Skettenis RK3568_SCLK_GMAC1_DIV_50, RK3568_SCLK_GMAC1_DIV_5 } 3383c935b871Skettenis }, 3384c935b871Skettenis { 3385c935b871Skettenis RK3568_SCLK_GMAC1_RMII_SPEED, RK3568_CRU_CLKSEL_CON(33), 3386c935b871Skettenis SEL(3, 3), 0, 3387c935b871Skettenis { RK3568_SCLK_GMAC1_DIV_20, RK3568_SCLK_GMAC1_DIV_2 } 3388c935b871Skettenis }, 3389c935b871Skettenis { 3390c935b871Skettenis RK3568_SCLK_GMAC1_RX_TX, RK3568_CRU_CLKSEL_CON(33), 3391c935b871Skettenis SEL(1, 0), 0, 3392c935b871Skettenis { RK3568_SCLK_GMAC1_RGMII_SPEED, RK3568_SCLK_GMAC1_RMII_SPEED } 3393c935b871Skettenis }, 3394c935b871Skettenis { 3395c935b871Skettenis RK3568_CPLL_125M, RK3568_CRU_CLKSEL_CON(80), 3396c935b871Skettenis 0, DIV(4, 0), 3397c935b871Skettenis { RK3568_PLL_CPLL } 3398c935b871Skettenis }, 3399c935b871Skettenis { 3400c935b871Skettenis RK3568_CPLL_62P5M, RK3568_CRU_CLKSEL_CON(80), 3401c935b871Skettenis 0, DIV(12, 8), 3402c935b871Skettenis { RK3568_PLL_CPLL } 3403c935b871Skettenis }, 3404c935b871Skettenis { 340533081393Skettenis RK3568_CPLL_50M, RK3568_CRU_CLKSEL_CON(81), 340633081393Skettenis 0, DIV(4, 0), 340733081393Skettenis { RK3568_PLL_CPLL } 340833081393Skettenis }, 340933081393Skettenis { 3410c935b871Skettenis RK3568_CPLL_25M, RK3568_CRU_CLKSEL_CON(81), 3411c935b871Skettenis 0, DIV(13, 8), 3412c935b871Skettenis { RK3568_PLL_CPLL } 3413c935b871Skettenis }, 3414c935b871Skettenis { 341533081393Skettenis RK3568_CPLL_100M, RK3568_CRU_CLKSEL_CON(82), 341633081393Skettenis 0, DIV(4, 0), 341733081393Skettenis { RK3568_PLL_CPLL } 341833081393Skettenis }, 341933081393Skettenis { 342033081393Skettenis RK3568_GPLL_400M, RK3568_CRU_CLKSEL_CON(75), 342133081393Skettenis 0, DIV(4, 0), 342233081393Skettenis { RK3568_PLL_GPLL } 342333081393Skettenis }, 342433081393Skettenis { 342533081393Skettenis RK3568_GPLL_300M, RK3568_CRU_CLKSEL_CON(75), 342633081393Skettenis 0, DIV(12, 8), 342733081393Skettenis { RK3568_PLL_GPLL } 342833081393Skettenis }, 342933081393Skettenis { 3430c935b871Skettenis RK3568_GPLL_200M, RK3568_CRU_CLKSEL_CON(76), 3431c935b871Skettenis 0, DIV(4, 0), 3432c935b871Skettenis { RK3568_PLL_GPLL } 3433c935b871Skettenis }, 3434c935b871Skettenis { 34351f8e42a5Sdlg RK3568_GPLL_150M, RK3568_CRU_CLKSEL_CON(76), 34361f8e42a5Sdlg 0, DIV(12, 5), 34371f8e42a5Sdlg { RK3568_PLL_GPLL } 34381f8e42a5Sdlg }, 34391f8e42a5Sdlg { 3440422309e7Skettenis RK3568_GPLL_100M, RK3568_CRU_CLKSEL_CON(77), 3441422309e7Skettenis 0, DIV(4, 0), 3442422309e7Skettenis { RK3568_PLL_GPLL } 3443422309e7Skettenis }, 3444422309e7Skettenis { 344533081393Skettenis RK3568_CLK_OSC0_DIV_750K, RK3568_CRU_CLKSEL_CON(82), 344633081393Skettenis 0, DIV(13, 8), 344733081393Skettenis { RK3568_XIN24M } 344833081393Skettenis }, 344933081393Skettenis { 345033081393Skettenis /* Sentinel */ 345133081393Skettenis } 345233081393Skettenis }; 345333081393Skettenis 345433081393Skettenis void 345533081393Skettenis rk3568_init(struct rkclock_softc *sc) 345633081393Skettenis { 345733081393Skettenis int i; 345833081393Skettenis 345933081393Skettenis /* The code below assumes all clocks are enabled. Check this!. */ 346033081393Skettenis for (i = 0; i <= 35; i++) { 346133081393Skettenis if (HREAD4(sc, RK3568_CRU_GATE_CON(i)) != 0x00000000) { 346233081393Skettenis printf("CRU_GATE_CON%d: 0x%08x\n", i, 346333081393Skettenis HREAD4(sc, RK3568_CRU_GATE_CON(i))); 346433081393Skettenis } 346533081393Skettenis } 346633081393Skettenis 346733081393Skettenis sc->sc_clocks = rk3568_clocks; 346833081393Skettenis } 346933081393Skettenis 347033081393Skettenis int 347133081393Skettenis rk3568_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 347233081393Skettenis { 347333081393Skettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 347433081393Skettenis int mode_shift = -1; 347533081393Skettenis 347633081393Skettenis switch (base) { 347733081393Skettenis case RK3568_CRU_APLL_CON(0): 347833081393Skettenis mode_shift = 0; 347933081393Skettenis break; 348033081393Skettenis case RK3568_CRU_DPLL_CON(0): 348133081393Skettenis mode_shift = 2; 348233081393Skettenis break; 348333081393Skettenis case RK3568_CRU_CPLL_CON(0): 348433081393Skettenis mode_shift = 4; 348533081393Skettenis break; 348633081393Skettenis case RK3568_CRU_GPLL_CON(0): 348733081393Skettenis mode_shift = 6; 348833081393Skettenis break; 348933081393Skettenis case RK3568_CRU_NPLL_CON(0): 349033081393Skettenis mode_shift = 10; 349133081393Skettenis break; 349233081393Skettenis case RK3568_CRU_VPLL_CON(0): 349333081393Skettenis mode_shift = 12; 349433081393Skettenis break; 349533081393Skettenis } 349633081393Skettenis KASSERT(mode_shift != -1); 349733081393Skettenis 349833081393Skettenis /* 349933081393Skettenis * It is not clear whether all combinations of the clock 350033081393Skettenis * dividers result in a stable clock. Therefore this function 350133081393Skettenis * only supports a limited set of PLL clock rates. 350233081393Skettenis */ 350333081393Skettenis switch (freq) { 350433081393Skettenis case 1200000000U: 350533081393Skettenis postdiv1 = 2; postdiv2 = refdiv = 1; 350633081393Skettenis break; 350733081393Skettenis default: 350833081393Skettenis printf("%s: %u Hz\n", __func__, freq); 350933081393Skettenis return -1; 351033081393Skettenis } 351133081393Skettenis 351233081393Skettenis /* Calculate feedback divider. */ 351333081393Skettenis fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 351433081393Skettenis 351533081393Skettenis /* 351633081393Skettenis * Select slow mode to guarantee a stable clock while we're 351733081393Skettenis * adjusting the PLL. 351833081393Skettenis */ 351933081393Skettenis HWRITE4(sc, RK3568_CRU_MODE_CON, 352033081393Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 352133081393Skettenis RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 352233081393Skettenis 352333081393Skettenis /* Set PLL rate. */ 352433081393Skettenis HWRITE4(sc, base + 0x0000, 352533081393Skettenis RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 352633081393Skettenis postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 352733081393Skettenis RK3328_CRU_PLL_FBDIV_MASK << 16 | 352833081393Skettenis fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 352933081393Skettenis HWRITE4(sc, base + 0x0004, 353033081393Skettenis RK3328_CRU_PLL_DSMPD << 16 | RK3328_CRU_PLL_DSMPD | 353133081393Skettenis RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 353233081393Skettenis postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 353333081393Skettenis RK3328_CRU_PLL_REFDIV_MASK << 16 | 353433081393Skettenis refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 353533081393Skettenis 353633081393Skettenis /* Wait for PLL to stabilize. */ 353733081393Skettenis while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 353833081393Skettenis delay(10); 353933081393Skettenis 354033081393Skettenis /* Switch back to normal mode. */ 354133081393Skettenis HWRITE4(sc, RK3568_CRU_MODE_CON, 354233081393Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 354333081393Skettenis RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 354433081393Skettenis 354533081393Skettenis return 0; 354633081393Skettenis } 354733081393Skettenis 354833081393Skettenis uint32_t 354933081393Skettenis rk3568_get_frequency(void *cookie, uint32_t *cells) 355033081393Skettenis { 355133081393Skettenis struct rkclock_softc *sc = cookie; 355233081393Skettenis uint32_t idx = cells[0]; 355333081393Skettenis 355433081393Skettenis switch (idx) { 355533081393Skettenis case RK3568_PLL_APLL: 355633081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_APLL_CON(0)); 355733081393Skettenis case RK3568_PLL_DPLL: 355833081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_DPLL_CON(0)); 355933081393Skettenis case RK3568_PLL_CPLL: 356033081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_CPLL_CON(0)); 356133081393Skettenis case RK3568_PLL_GPLL: 356233081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_GPLL_CON(0)); 356333081393Skettenis case RK3568_PLL_NPLL: 356433081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_NPLL_CON(0)); 356533081393Skettenis case RK3568_PLL_VPLL: 356633081393Skettenis return rk3328_get_pll(sc, RK3568_CRU_VPLL_CON(0)); 3567c935b871Skettenis case RK3568_SCLK_GMAC0_DIV_50: 3568c935b871Skettenis idx = RK3568_SCLK_GMAC0; 3569c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 50; 3570c935b871Skettenis case RK3568_SCLK_GMAC0_DIV_5: 3571c935b871Skettenis idx = RK3568_SCLK_GMAC0; 3572c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 5; 3573c935b871Skettenis case RK3568_SCLK_GMAC0_DIV_20: 3574c935b871Skettenis idx = RK3568_SCLK_GMAC0; 3575c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 20; 3576c935b871Skettenis case RK3568_SCLK_GMAC0_DIV_2: 3577c935b871Skettenis idx = RK3568_SCLK_GMAC0; 3578c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 2; 3579c935b871Skettenis case RK3568_SCLK_GMAC1_DIV_50: 3580c935b871Skettenis idx = RK3568_SCLK_GMAC1; 3581c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 50; 3582c935b871Skettenis case RK3568_SCLK_GMAC1_DIV_5: 3583c935b871Skettenis idx = RK3568_SCLK_GMAC1; 3584c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 5; 3585c935b871Skettenis case RK3568_SCLK_GMAC1_DIV_20: 3586c935b871Skettenis idx = RK3568_SCLK_GMAC1; 3587c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 20; 3588c935b871Skettenis case RK3568_SCLK_GMAC1_DIV_2: 3589c935b871Skettenis idx = RK3568_SCLK_GMAC1; 3590c935b871Skettenis return rk3568_get_frequency(sc, &idx) / 2; 35911f8e42a5Sdlg case RK3568_CLK_OSC0_DIV_375K: 35921f8e42a5Sdlg idx = RK3568_CLK_OSC0_DIV_750K; 35931f8e42a5Sdlg return rk3568_get_frequency(sc, &idx) / 2; 3594c935b871Skettenis case RK3568_GMAC0_CLKIN: 3595c935b871Skettenis return rkclock_external_frequency("gmac0_clkin"); 3596c935b871Skettenis case RK3568_GMAC1_CLKIN: 3597c935b871Skettenis return rkclock_external_frequency("gmac1_clkin"); 359833081393Skettenis case RK3568_XIN24M: 359933081393Skettenis return 24000000; 360033081393Skettenis default: 360133081393Skettenis break; 360233081393Skettenis } 360333081393Skettenis 360433081393Skettenis return rkclock_get_frequency(sc, idx); 360533081393Skettenis } 360633081393Skettenis 360733081393Skettenis int 360833081393Skettenis rk3568_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 360933081393Skettenis { 361033081393Skettenis struct rkclock_softc *sc = cookie; 361133081393Skettenis uint32_t idx = cells[0]; 361233081393Skettenis 361333081393Skettenis switch (idx) { 361433081393Skettenis case RK3568_PLL_GPLL: 361533081393Skettenis return rk3568_set_pll(sc, RK3568_CRU_GPLL_CON(0), freq); 361633081393Skettenis default: 361733081393Skettenis break; 361833081393Skettenis } 361933081393Skettenis 362033081393Skettenis return rkclock_set_frequency(sc, idx, freq); 362133081393Skettenis } 362233081393Skettenis 3623bc4366cbSkettenis int 3624bc4366cbSkettenis rk3568_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 3625bc4366cbSkettenis { 3626bc4366cbSkettenis struct rkclock_softc *sc = cookie; 3627bc4366cbSkettenis char buf[64] = {}; 3628bc4366cbSkettenis int len, node; 3629bc4366cbSkettenis 3630bc4366cbSkettenis if (pcells[0] != sc->sc_phandle) { 3631bc4366cbSkettenis node = OF_getnodebyphandle(pcells[0]); 3632bc4366cbSkettenis if (node == 0) 3633bc4366cbSkettenis return -1; 3634bc4366cbSkettenis len = OF_getproplen(node, "clock-output-names"); 3635bc4366cbSkettenis if (len <= 0 || len > sizeof(buf)) 3636bc4366cbSkettenis return -1; 3637bc4366cbSkettenis OF_getprop(node, "clock-output-names", buf, sizeof(buf)); 3638bc4366cbSkettenis 3639bc4366cbSkettenis if (strcmp(buf, "gmac0_clkin") == 0) { 3640bc4366cbSkettenis return rkclock_set_parent(sc, cells[0], 3641bc4366cbSkettenis RK3568_GMAC0_CLKIN); 3642bc4366cbSkettenis } 3643bc4366cbSkettenis if (strcmp(buf, "gmac1_clkin") == 0) { 3644bc4366cbSkettenis return rkclock_set_parent(sc, cells[0], 3645bc4366cbSkettenis RK3568_GMAC1_CLKIN); 3646bc4366cbSkettenis } 3647bc4366cbSkettenis 3648bc4366cbSkettenis printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], pcells[0]); 3649bc4366cbSkettenis return -1; 3650bc4366cbSkettenis } 3651bc4366cbSkettenis 3652bc4366cbSkettenis return rkclock_set_parent(sc, cells[0], pcells[1]); 3653bc4366cbSkettenis } 3654bc4366cbSkettenis 365533081393Skettenis void 365633081393Skettenis rk3568_enable(void *cookie, uint32_t *cells, int on) 365733081393Skettenis { 365833081393Skettenis uint32_t idx = cells[0]; 365933081393Skettenis 366033081393Skettenis /* All clocks are enabled upon hardware reset. */ 366133081393Skettenis if (!on) { 366233081393Skettenis printf("%s: 0x%08x\n", __func__, idx); 366333081393Skettenis return; 366433081393Skettenis } 366533081393Skettenis } 366633081393Skettenis 366733081393Skettenis void 366833081393Skettenis rk3568_reset(void *cookie, uint32_t *cells, int on) 366933081393Skettenis { 367033081393Skettenis struct rkclock_softc *sc = cookie; 367133081393Skettenis uint32_t idx = cells[0]; 367233081393Skettenis uint32_t mask = (1 << (idx % 16)); 367333081393Skettenis 367433081393Skettenis HWRITE4(sc, RK3568_CRU_SOFTRST_CON(idx / 16), 367533081393Skettenis mask << 16 | (on ? mask : 0)); 367633081393Skettenis } 367733081393Skettenis 367833081393Skettenis /* PMUCRU */ 367933081393Skettenis 368033081393Skettenis const struct rkclock rk3568_pmu_clocks[] = { 368133081393Skettenis { 3682a21015c5Skettenis RK3568_CLK_RTC_32K, RK3568_PMUCRU_CLKSEL_CON(0), 3683a21015c5Skettenis SEL(7, 6), 0, 3684a21015c5Skettenis { 0, RK3568_XIN32K, RK3568_CLK_RTC32K_FRAC }, 3685a21015c5Skettenis SET_PARENT 3686a21015c5Skettenis }, 3687a21015c5Skettenis { 368833081393Skettenis RK3568_CLK_I2C0, RK3568_PMUCRU_CLKSEL_CON(3), 368933081393Skettenis 0, DIV(15, 7), 369033081393Skettenis { RK3568_CLK_PDPMU } 369133081393Skettenis }, 369233081393Skettenis { 369333081393Skettenis RK3568_SCLK_UART0, RK3568_PMUCRU_CLKSEL_CON(4), 369433081393Skettenis SEL(11, 10), 0, 369533081393Skettenis { 0, 0, RK3568_XIN24M } 369633081393Skettenis }, 369733081393Skettenis { 3698e1414c50Skettenis RK3568_CLK_PCIEPHY0_OSC0, 0, 0, 0, 3699e1414c50Skettenis { RK3568_XIN24M } 3700e1414c50Skettenis }, 3701e1414c50Skettenis { 3702e1414c50Skettenis RK3568_CLK_PCIEPHY0_DIV, RK3568_PMUCRU_CLKSEL_CON(9), 3703e1414c50Skettenis 0, DIV(2, 0), 3704e1414c50Skettenis { RK3568_PPLL_PH0 } 3705e1414c50Skettenis }, 3706e1414c50Skettenis { 3707e1414c50Skettenis RK3568_CLK_PCIEPHY0_REF, RK3568_PMUCRU_CLKSEL_CON(9), 3708e1414c50Skettenis SEL(3, 3), 0, 3709e1414c50Skettenis { RK3568_CLK_PCIEPHY0_OSC0, RK3568_CLK_PCIEPHY0_DIV }, 3710e1414c50Skettenis SET_PARENT 3711e1414c50Skettenis }, 3712e1414c50Skettenis { 3713e1414c50Skettenis RK3568_CLK_PCIEPHY1_OSC0, 0, 0, 0, 3714e1414c50Skettenis { RK3568_XIN24M } 3715e1414c50Skettenis }, 3716e1414c50Skettenis { 3717e1414c50Skettenis RK3568_CLK_PCIEPHY1_DIV, RK3568_PMUCRU_CLKSEL_CON(9), 3718e1414c50Skettenis 0, DIV(6, 4), 3719e1414c50Skettenis { RK3568_PPLL_PH0 } 3720e1414c50Skettenis }, 3721e1414c50Skettenis { 3722e1414c50Skettenis RK3568_CLK_PCIEPHY1_REF, RK3568_PMUCRU_CLKSEL_CON(9), 3723e1414c50Skettenis SEL(7, 7), 0, 3724e1414c50Skettenis { RK3568_CLK_PCIEPHY1_OSC0, RK3568_CLK_PCIEPHY1_DIV }, 3725e1414c50Skettenis SET_PARENT 3726e1414c50Skettenis }, 3727e1414c50Skettenis { 3728e1414c50Skettenis RK3568_CLK_PCIEPHY2_OSC0, 0, 0, 0, 3729e1414c50Skettenis { RK3568_XIN24M } 3730e1414c50Skettenis }, 3731e1414c50Skettenis { 3732e1414c50Skettenis RK3568_CLK_PCIEPHY2_DIV, RK3568_PMUCRU_CLKSEL_CON(9), 3733e1414c50Skettenis 0, DIV(10, 8), 3734e1414c50Skettenis { RK3568_PPLL_PH0 } 3735e1414c50Skettenis }, 3736e1414c50Skettenis { 3737e1414c50Skettenis RK3568_CLK_PCIEPHY2_REF, RK3568_PMUCRU_CLKSEL_CON(9), 3738e1414c50Skettenis SEL(11, 11), 0, 3739e1414c50Skettenis { RK3568_CLK_PCIEPHY2_OSC0, RK3568_CLK_PCIEPHY2_DIV }, 3740e1414c50Skettenis SET_PARENT 3741e1414c50Skettenis }, 3742e1414c50Skettenis { 374333081393Skettenis RK3568_CLK_PDPMU, RK3568_PMUCRU_CLKSEL_CON(2), 374433081393Skettenis SEL(15, 15), 0, 374533081393Skettenis { RK3568_PLL_PPLL, 0 } 374633081393Skettenis }, 374733081393Skettenis { 374833081393Skettenis /* Sentinel */ 374933081393Skettenis } 375033081393Skettenis }; 375133081393Skettenis 375233081393Skettenis void 375333081393Skettenis rk3568_pmu_init(struct rkclock_softc *sc) 375433081393Skettenis { 3755e1414c50Skettenis int i; 3756e1414c50Skettenis 3757e1414c50Skettenis /* The code below assumes all clocks are enabled. Check this!. */ 3758e1414c50Skettenis for (i = 0; i <= 2; i++) { 3759e1414c50Skettenis if (HREAD4(sc, RK3568_PMUCRU_GATE_CON(i)) != 0x00000000) { 3760e1414c50Skettenis printf("CRU_GATE_CON%d: 0x%08x\n", i, 3761e1414c50Skettenis HREAD4(sc, RK3568_CRU_GATE_CON(i))); 3762e1414c50Skettenis } 3763e1414c50Skettenis } 3764e1414c50Skettenis 376533081393Skettenis sc->sc_clocks = rk3568_pmu_clocks; 376633081393Skettenis } 376733081393Skettenis 376833081393Skettenis int 376933081393Skettenis rk3568_pmu_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 377033081393Skettenis { 377133081393Skettenis uint32_t fbdiv, postdiv1, postdiv2, refdiv; 377233081393Skettenis int mode_shift = -1; 377333081393Skettenis 377433081393Skettenis switch (base) { 377533081393Skettenis case RK3568_PMUCRU_PPLL_CON(0): 377633081393Skettenis mode_shift = 0; 377733081393Skettenis break; 377833081393Skettenis case RK3568_PMUCRU_HPLL_CON(0): 377933081393Skettenis mode_shift = 2; 378033081393Skettenis break; 378133081393Skettenis } 378233081393Skettenis KASSERT(mode_shift != -1); 378333081393Skettenis 378433081393Skettenis /* 378533081393Skettenis * It is not clear whether all combinations of the clock 378633081393Skettenis * dividers result in a stable clock. Therefore this function 378733081393Skettenis * only supports a limited set of PLL clock rates. 378833081393Skettenis */ 378933081393Skettenis switch (freq) { 379033081393Skettenis case 200000000U: 379133081393Skettenis postdiv1 = 3; postdiv2 = 4; refdiv = 1; 379233081393Skettenis break; 379333081393Skettenis default: 379433081393Skettenis printf("%s: %u Hz\n", __func__, freq); 379533081393Skettenis return -1; 379633081393Skettenis } 379733081393Skettenis 379833081393Skettenis /* Calculate feedback divider. */ 379933081393Skettenis fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 380033081393Skettenis 380133081393Skettenis /* 380233081393Skettenis * Select slow mode to guarantee a stable clock while we're 380333081393Skettenis * adjusting the PLL. 380433081393Skettenis */ 380533081393Skettenis HWRITE4(sc, RK3568_PMUCRU_MODE_CON, 380633081393Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 380733081393Skettenis RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 380833081393Skettenis 380933081393Skettenis /* Set PLL rate. */ 381033081393Skettenis HWRITE4(sc, base + 0x0000, 381133081393Skettenis RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 381233081393Skettenis postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 381333081393Skettenis RK3328_CRU_PLL_FBDIV_MASK << 16 | 381433081393Skettenis fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 381533081393Skettenis HWRITE4(sc, base + 0x0004, 381633081393Skettenis RK3328_CRU_PLL_DSMPD << 16 | RK3328_CRU_PLL_DSMPD | 381733081393Skettenis RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 381833081393Skettenis postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 381933081393Skettenis RK3328_CRU_PLL_REFDIV_MASK << 16 | 382033081393Skettenis refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 382133081393Skettenis 382233081393Skettenis /* Wait for PLL to stabilize. */ 382333081393Skettenis while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 382433081393Skettenis delay(10); 382533081393Skettenis 382633081393Skettenis /* Switch back to normal mode. */ 382733081393Skettenis HWRITE4(sc, RK3568_PMUCRU_MODE_CON, 382833081393Skettenis (RK3328_CRU_CRU_MODE_MASK << 16 | 382933081393Skettenis RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 383033081393Skettenis 383133081393Skettenis return 0; 383233081393Skettenis } 383333081393Skettenis 383433081393Skettenis uint32_t 383533081393Skettenis rk3568_pmu_get_frequency(void *cookie, uint32_t *cells) 383633081393Skettenis { 383733081393Skettenis struct rkclock_softc *sc = cookie; 383833081393Skettenis uint32_t idx = cells[0]; 383933081393Skettenis 384033081393Skettenis switch (idx) { 384133081393Skettenis case RK3568_PLL_PPLL: 384233081393Skettenis return rk3328_get_pll(sc, RK3568_PMUCRU_PPLL_CON(0)); 384333081393Skettenis case RK3568_PLL_HPLL: 384433081393Skettenis return rk3328_get_pll(sc, RK3568_PMUCRU_HPLL_CON(0)); 3845a21015c5Skettenis case RK3568_CLK_RTC32K_FRAC: 3846a21015c5Skettenis return rk3399_get_frac(sc, RK3568_XIN24M, 3847a21015c5Skettenis RK3568_PMUCRU_CLKSEL_CON(1)); 3848e1414c50Skettenis case RK3568_PPLL_PH0: 3849e1414c50Skettenis idx = RK3568_PLL_PPLL; 3850e1414c50Skettenis return rk3568_get_frequency(sc, &idx) / 2; 3851a21015c5Skettenis case RK3568_XIN32K: 3852a21015c5Skettenis return 32768; 385333081393Skettenis case RK3568_XIN24M: 385433081393Skettenis return 24000000; 385533081393Skettenis default: 385633081393Skettenis break; 385733081393Skettenis } 385833081393Skettenis 385933081393Skettenis return rkclock_get_frequency(sc, idx); 386033081393Skettenis } 386133081393Skettenis 386233081393Skettenis int 386333081393Skettenis rk3568_pmu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 386433081393Skettenis { 386533081393Skettenis struct rkclock_softc *sc = cookie; 386633081393Skettenis uint32_t idx = cells[0]; 386733081393Skettenis 386833081393Skettenis switch (idx) { 386933081393Skettenis case RK3568_PLL_PPLL: 387033081393Skettenis return rk3568_pmu_set_pll(sc, RK3568_PMUCRU_PPLL_CON(0), freq); 387133081393Skettenis case RK3568_PLL_HPLL: 387233081393Skettenis return rk3568_pmu_set_pll(sc, RK3568_PMUCRU_HPLL_CON(0), freq); 3873a21015c5Skettenis case RK3568_CLK_RTC32K_FRAC: 3874a21015c5Skettenis return rk3399_set_frac(sc, RK3568_XIN24M, 3875a21015c5Skettenis RK3568_PMUCRU_CLKSEL_CON(1), freq); 387633081393Skettenis default: 387733081393Skettenis break; 387833081393Skettenis } 387933081393Skettenis 388033081393Skettenis return rkclock_set_frequency(sc, idx, freq); 388133081393Skettenis } 388233081393Skettenis 388333081393Skettenis void 388433081393Skettenis rk3568_pmu_enable(void *cookie, uint32_t *cells, int on) 388533081393Skettenis { 388633081393Skettenis uint32_t idx = cells[0]; 388733081393Skettenis 388833081393Skettenis switch (idx) { 388954e50d89Skettenis case RK3568_CLK_USBPHY0_REF: 389054e50d89Skettenis case RK3568_CLK_USBPHY1_REF: 3891e1414c50Skettenis case RK3568_CLK_PCIEPHY0_REF: 3892e1414c50Skettenis case RK3568_CLK_PCIEPHY1_REF: 3893e1414c50Skettenis case RK3568_CLK_PCIEPHY2_REF: 389415d3c08bSkettenis case RK3568_CLK_PCIE30PHY_REF_M: 389515d3c08bSkettenis case RK3568_CLK_PCIE30PHY_REF_N: 389633081393Skettenis case RK3568_CLK_I2C0: 389733081393Skettenis case RK3568_SCLK_UART0: 389833081393Skettenis case RK3568_PCLK_I2C0: 389933081393Skettenis /* Enabled by default. */ 390033081393Skettenis break; 390133081393Skettenis default: 390233081393Skettenis printf("%s: 0x%08x\n", __func__, idx); 390333081393Skettenis break; 390433081393Skettenis } 390533081393Skettenis } 390633081393Skettenis 390733081393Skettenis void 390833081393Skettenis rk3568_pmu_reset(void *cookie, uint32_t *cells, int on) 390933081393Skettenis { 391033081393Skettenis uint32_t idx = cells[0]; 391133081393Skettenis 391233081393Skettenis printf("%s: 0x%08x\n", __func__, idx); 391333081393Skettenis } 3914e3f8cdb8Skettenis 3915e3f8cdb8Skettenis /* 3916e3f8cdb8Skettenis * Rockchip RK3588 3917e3f8cdb8Skettenis */ 3918e3f8cdb8Skettenis 3919e3f8cdb8Skettenis const struct rkclock rk3588_clocks[] = { 3920e3f8cdb8Skettenis { 39216555b60dSpatrick RK3588_CLK_PWM1, RK3588_CRU_CLKSEL_CON(59), 39226555b60dSpatrick SEL(13, 12), 0, 39236555b60dSpatrick { RK3588_CLK_100M_SRC, RK3588_CLK_50M_SRC, RK3588_XIN24M }, 39246555b60dSpatrick }, 39256555b60dSpatrick { 39266555b60dSpatrick RK3588_CLK_PWM2, RK3588_CRU_CLKSEL_CON(59), 39276555b60dSpatrick SEL(15, 14), 0, 39286555b60dSpatrick { RK3588_CLK_100M_SRC, RK3588_CLK_50M_SRC, RK3588_XIN24M }, 39296555b60dSpatrick }, 39306555b60dSpatrick { 39316555b60dSpatrick RK3588_CLK_PWM3, RK3588_CRU_CLKSEL_CON(60), 39326555b60dSpatrick SEL(1, 0), 0, 39336555b60dSpatrick { RK3588_CLK_100M_SRC, RK3588_CLK_50M_SRC, RK3588_XIN24M }, 39346555b60dSpatrick }, 39356555b60dSpatrick { 3936e3f8cdb8Skettenis RK3588_ACLK_BUS_ROOT, RK3588_CRU_CLKSEL_CON(38), 3937e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 3938e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 3939e3f8cdb8Skettenis }, 3940e3f8cdb8Skettenis { 3941cec24affSpatrick RK3588_CLK_I2C1, RK3588_CRU_CLKSEL_CON(38), 3942cec24affSpatrick SEL(6, 6), 0, 3943cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3944cec24affSpatrick }, 3945cec24affSpatrick { 3946cec24affSpatrick RK3588_CLK_I2C2, RK3588_CRU_CLKSEL_CON(38), 3947cec24affSpatrick SEL(7, 7), 0, 3948cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3949cec24affSpatrick }, 3950cec24affSpatrick { 3951cec24affSpatrick RK3588_CLK_I2C3, RK3588_CRU_CLKSEL_CON(38), 3952cec24affSpatrick SEL(8, 8), 0, 3953cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3954cec24affSpatrick }, 3955cec24affSpatrick { 3956cec24affSpatrick RK3588_CLK_I2C4, RK3588_CRU_CLKSEL_CON(38), 3957cec24affSpatrick SEL(9, 9), 0, 3958cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3959cec24affSpatrick }, 3960cec24affSpatrick { 3961cec24affSpatrick RK3588_CLK_I2C5, RK3588_CRU_CLKSEL_CON(38), 3962cec24affSpatrick SEL(10, 10), 0, 3963cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3964cec24affSpatrick }, 3965cec24affSpatrick { 3966cec24affSpatrick RK3588_CLK_I2C6, RK3588_CRU_CLKSEL_CON(38), 3967cec24affSpatrick SEL(11, 11), 0, 3968cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3969cec24affSpatrick }, 3970cec24affSpatrick { 3971cec24affSpatrick RK3588_CLK_I2C7, RK3588_CRU_CLKSEL_CON(38), 3972cec24affSpatrick SEL(12, 12), 0, 3973cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3974cec24affSpatrick }, 3975cec24affSpatrick { 3976cec24affSpatrick RK3588_CLK_I2C8, RK3588_CRU_CLKSEL_CON(38), 3977cec24affSpatrick SEL(13, 13), 0, 3978cec24affSpatrick { RK3588_CLK_200M_SRC , RK3588_CLK_100M_SRC }, 3979cec24affSpatrick }, 3980cec24affSpatrick { 39814eda67c7Skettenis RK3588_CLK_SPI0, RK3588_CRU_CLKSEL_CON(59), 39824eda67c7Skettenis SEL(3, 2), 0, 39834eda67c7Skettenis { RK3588_CLK_200M_SRC, RK3588_CLK_150M_SRC, RK3588_XIN24M }, 39844eda67c7Skettenis }, 39854eda67c7Skettenis { 39864eda67c7Skettenis RK3588_CLK_SPI1, RK3588_CRU_CLKSEL_CON(59), 39874eda67c7Skettenis SEL(5, 4), 0, 39884eda67c7Skettenis { RK3588_CLK_200M_SRC, RK3588_CLK_150M_SRC, RK3588_XIN24M }, 39894eda67c7Skettenis }, 39904eda67c7Skettenis { 39914eda67c7Skettenis RK3588_CLK_SPI2, RK3588_CRU_CLKSEL_CON(59), 39924eda67c7Skettenis SEL(7, 6), 0, 39934eda67c7Skettenis { RK3588_CLK_200M_SRC, RK3588_CLK_150M_SRC, RK3588_XIN24M }, 39944eda67c7Skettenis }, 39954eda67c7Skettenis { 39964eda67c7Skettenis RK3588_CLK_SPI3, RK3588_CRU_CLKSEL_CON(59), 39974eda67c7Skettenis SEL(9, 8), 0, 39984eda67c7Skettenis { RK3588_CLK_200M_SRC, RK3588_CLK_150M_SRC, RK3588_XIN24M }, 39994eda67c7Skettenis }, 40004eda67c7Skettenis { 40014eda67c7Skettenis RK3588_CLK_SPI4, RK3588_CRU_CLKSEL_CON(59), 40024eda67c7Skettenis SEL(11, 10), 0, 40034eda67c7Skettenis { RK3588_CLK_200M_SRC, RK3588_CLK_150M_SRC, RK3588_XIN24M }, 40044eda67c7Skettenis }, 40054eda67c7Skettenis { 40069efac0bfSkettenis RK3588_CLK_TSADC, RK3588_CRU_CLKSEL_CON(41), 40079efac0bfSkettenis SEL(8, 8), DIV(7, 0), 40089efac0bfSkettenis { RK3588_PLL_GPLL, RK3588_XIN24M }, 40099efac0bfSkettenis }, 40109efac0bfSkettenis { 4011e3f8cdb8Skettenis RK3588_CLK_UART1_SRC, RK3588_CRU_CLKSEL_CON(41), 4012e3f8cdb8Skettenis SEL(14, 14), DIV(13, 9), 4013e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4014e3f8cdb8Skettenis }, 4015e3f8cdb8Skettenis { 4016e3f8cdb8Skettenis RK3588_CLK_UART1, RK3588_CRU_CLKSEL_CON(43), 4017e3f8cdb8Skettenis SEL(1, 0), 0, 4018e3f8cdb8Skettenis { RK3588_CLK_UART1_SRC, RK3588_CLK_UART1_FRAC, RK3588_XIN24M } 4019e3f8cdb8Skettenis }, 4020e3f8cdb8Skettenis { 4021e3f8cdb8Skettenis RK3588_SCLK_UART1, 0, 0, 0, 4022e3f8cdb8Skettenis { RK3588_CLK_UART1 } 4023e3f8cdb8Skettenis }, 4024e3f8cdb8Skettenis { 4025e3f8cdb8Skettenis RK3588_CLK_UART2_SRC, RK3588_CRU_CLKSEL_CON(43), 4026e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4027e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4028e3f8cdb8Skettenis }, 4029e3f8cdb8Skettenis { 4030e3f8cdb8Skettenis RK3588_CLK_UART2, RK3588_CRU_CLKSEL_CON(45), 4031e3f8cdb8Skettenis SEL(1, 0), 0, 4032e3f8cdb8Skettenis { RK3588_CLK_UART2_SRC, RK3588_CLK_UART2_FRAC, RK3588_XIN24M } 4033e3f8cdb8Skettenis }, 4034e3f8cdb8Skettenis { 4035e3f8cdb8Skettenis RK3588_SCLK_UART2, 0, 0, 0, 4036e3f8cdb8Skettenis { RK3588_CLK_UART2 } 4037e3f8cdb8Skettenis }, 4038e3f8cdb8Skettenis { 4039e3f8cdb8Skettenis RK3588_CLK_UART3_SRC, RK3588_CRU_CLKSEL_CON(45), 4040e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4041e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4042e3f8cdb8Skettenis }, 4043e3f8cdb8Skettenis { 4044e3f8cdb8Skettenis RK3588_CLK_UART3, RK3588_CRU_CLKSEL_CON(47), 4045e3f8cdb8Skettenis SEL(1, 0), 0, 4046e3f8cdb8Skettenis { RK3588_CLK_UART3_SRC, RK3588_CLK_UART3_FRAC, RK3588_XIN24M } 4047e3f8cdb8Skettenis }, 4048e3f8cdb8Skettenis { 4049e3f8cdb8Skettenis RK3588_SCLK_UART3, 0, 0, 0, 4050e3f8cdb8Skettenis { RK3588_CLK_UART3 } 4051e3f8cdb8Skettenis }, 4052e3f8cdb8Skettenis { 4053e3f8cdb8Skettenis RK3588_CLK_UART4_SRC, RK3588_CRU_CLKSEL_CON(47), 4054e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4055e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4056e3f8cdb8Skettenis }, 4057e3f8cdb8Skettenis { 4058e3f8cdb8Skettenis RK3588_CLK_UART4, RK3588_CRU_CLKSEL_CON(49), 4059e3f8cdb8Skettenis SEL(1, 0), 0, 4060e3f8cdb8Skettenis { RK3588_CLK_UART4_SRC, RK3588_CLK_UART4_FRAC, RK3588_XIN24M } 4061e3f8cdb8Skettenis }, 4062e3f8cdb8Skettenis { 4063e3f8cdb8Skettenis RK3588_SCLK_UART4, 0, 0, 0, 4064e3f8cdb8Skettenis { RK3588_CLK_UART4 } 4065e3f8cdb8Skettenis }, 4066e3f8cdb8Skettenis { 4067e3f8cdb8Skettenis RK3588_CLK_UART5_SRC, RK3588_CRU_CLKSEL_CON(49), 4068e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4069e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4070e3f8cdb8Skettenis }, 4071e3f8cdb8Skettenis { 4072e3f8cdb8Skettenis RK3588_CLK_UART5, RK3588_CRU_CLKSEL_CON(51), 4073e3f8cdb8Skettenis SEL(1, 0), 0, 4074e3f8cdb8Skettenis { RK3588_CLK_UART5_SRC, RK3588_CLK_UART5_FRAC, RK3588_XIN24M } 4075e3f8cdb8Skettenis }, 4076e3f8cdb8Skettenis { 4077e3f8cdb8Skettenis RK3588_SCLK_UART5, 0, 0, 0, 4078e3f8cdb8Skettenis { RK3588_CLK_UART5 } 4079e3f8cdb8Skettenis }, 4080e3f8cdb8Skettenis { 4081e3f8cdb8Skettenis RK3588_CLK_UART6_SRC, RK3588_CRU_CLKSEL_CON(51), 4082e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4083e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4084e3f8cdb8Skettenis }, 4085e3f8cdb8Skettenis { 4086e3f8cdb8Skettenis RK3588_CLK_UART6, RK3588_CRU_CLKSEL_CON(53), 4087e3f8cdb8Skettenis SEL(1, 0), 0, 4088e3f8cdb8Skettenis { RK3588_CLK_UART6_SRC, RK3588_CLK_UART6_FRAC, RK3588_XIN24M } 4089e3f8cdb8Skettenis }, 4090e3f8cdb8Skettenis { 4091e3f8cdb8Skettenis RK3588_SCLK_UART6, 0, 0, 0, 4092e3f8cdb8Skettenis { RK3588_CLK_UART6 } 4093e3f8cdb8Skettenis }, 4094e3f8cdb8Skettenis { 4095e3f8cdb8Skettenis RK3588_CLK_UART7_SRC, RK3588_CRU_CLKSEL_CON(53), 4096e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4097e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4098e3f8cdb8Skettenis }, 4099e3f8cdb8Skettenis { 4100e3f8cdb8Skettenis RK3588_CLK_UART7, RK3588_CRU_CLKSEL_CON(55), 4101e3f8cdb8Skettenis SEL(1, 0), 0, 4102e3f8cdb8Skettenis { RK3588_CLK_UART7_SRC, RK3588_CLK_UART7_FRAC, RK3588_XIN24M } 4103e3f8cdb8Skettenis }, 4104e3f8cdb8Skettenis { 4105e3f8cdb8Skettenis RK3588_SCLK_UART7, 0, 0, 0, 4106e3f8cdb8Skettenis { RK3588_CLK_UART7 } 4107e3f8cdb8Skettenis }, 4108e3f8cdb8Skettenis { 4109e3f8cdb8Skettenis RK3588_CLK_UART8_SRC, RK3588_CRU_CLKSEL_CON(55), 4110e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4111e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4112e3f8cdb8Skettenis }, 4113e3f8cdb8Skettenis { 4114e3f8cdb8Skettenis RK3588_CLK_UART8, RK3588_CRU_CLKSEL_CON(57), 4115e3f8cdb8Skettenis SEL(1, 0), 0, 4116e3f8cdb8Skettenis { RK3588_CLK_UART8_SRC, RK3588_CLK_UART8_FRAC, RK3588_XIN24M } 4117e3f8cdb8Skettenis }, 4118e3f8cdb8Skettenis { 4119e3f8cdb8Skettenis RK3588_SCLK_UART8, 0, 0, 0, 4120e3f8cdb8Skettenis { RK3588_CLK_UART8 } 4121e3f8cdb8Skettenis }, 4122e3f8cdb8Skettenis { 4123e3f8cdb8Skettenis RK3588_CLK_UART9_SRC, RK3588_CRU_CLKSEL_CON(57), 4124e3f8cdb8Skettenis SEL(7, 7), DIV(6, 2), 4125e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4126e3f8cdb8Skettenis }, 4127e3f8cdb8Skettenis { 4128e3f8cdb8Skettenis RK3588_CLK_UART9, RK3588_CRU_CLKSEL_CON(59), 4129e3f8cdb8Skettenis SEL(1, 0), 0, 4130e3f8cdb8Skettenis { RK3588_CLK_UART9_SRC, RK3588_CLK_UART9_FRAC, RK3588_XIN24M } 4131e3f8cdb8Skettenis }, 4132e3f8cdb8Skettenis { 4133e3f8cdb8Skettenis RK3588_SCLK_UART9, 0, 0, 0, 4134e3f8cdb8Skettenis { RK3588_CLK_UART9 } 4135e3f8cdb8Skettenis }, 4136e3f8cdb8Skettenis { 4137e3f8cdb8Skettenis RK3588_ACLK_CENTER_ROOT, RK3588_CRU_CLKSEL_CON(165), 4138e3f8cdb8Skettenis SEL(1, 0), 0, 4139e3f8cdb8Skettenis { RK3588_CLK_700M_SRC, RK3588_CLK_400M_SRC, 4140e3f8cdb8Skettenis RK3588_CLK_200M_SRC, RK3588_XIN24M } 4141e3f8cdb8Skettenis }, 4142e3f8cdb8Skettenis { 4143e3f8cdb8Skettenis RK3588_ACLK_CENTER_LOW_ROOT, RK3588_CRU_CLKSEL_CON(165), 4144e3f8cdb8Skettenis SEL(3, 2), 0, 4145e3f8cdb8Skettenis { RK3588_CLK_500M_SRC, RK3588_CLK_250M_SRC, 4146e3f8cdb8Skettenis RK3588_CLK_100M_SRC, RK3588_XIN24M } 4147e3f8cdb8Skettenis }, 4148e3f8cdb8Skettenis { 4149e3f8cdb8Skettenis RK3588_HCLK_CENTER_ROOT, RK3588_CRU_CLKSEL_CON(165), 4150e3f8cdb8Skettenis SEL(5, 4), 0, 4151e3f8cdb8Skettenis { RK3588_CLK_400M_SRC, RK3588_CLK_200M_SRC, 4152e3f8cdb8Skettenis RK3588_CLK_100M_SRC, RK3588_XIN24M } 4153e3f8cdb8Skettenis }, 4154e3f8cdb8Skettenis { 4155e3f8cdb8Skettenis RK3588_CLK_50M_SRC, RK3588_CRU_CLKSEL_CON(0), 4156e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 4157e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4158e3f8cdb8Skettenis }, 4159e3f8cdb8Skettenis { 4160e3f8cdb8Skettenis RK3588_CLK_100M_SRC, RK3588_CRU_CLKSEL_CON(0), 4161e3f8cdb8Skettenis SEL(11, 11), DIV(10, 6), 4162e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4163e3f8cdb8Skettenis }, 4164e3f8cdb8Skettenis { 4165e3f8cdb8Skettenis RK3588_CLK_150M_SRC, RK3588_CRU_CLKSEL_CON(1), 4166e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 4167e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4168e3f8cdb8Skettenis }, 4169e3f8cdb8Skettenis { 4170e3f8cdb8Skettenis RK3588_CLK_200M_SRC, RK3588_CRU_CLKSEL_CON(1), 4171e3f8cdb8Skettenis SEL(11, 11), DIV(10, 6), 4172e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4173e3f8cdb8Skettenis }, 4174e3f8cdb8Skettenis { 4175e3f8cdb8Skettenis RK3588_CLK_250M_SRC, RK3588_CRU_CLKSEL_CON(2), 4176e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 4177e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4178e3f8cdb8Skettenis }, 4179e3f8cdb8Skettenis { 4180e3f8cdb8Skettenis RK3588_CLK_400M_SRC, RK3588_CRU_CLKSEL_CON(3), 4181e3f8cdb8Skettenis SEL(11, 11), DIV(10, 6), 4182e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4183e3f8cdb8Skettenis }, 4184e3f8cdb8Skettenis { 4185e3f8cdb8Skettenis RK3588_CLK_500M_SRC, RK3588_CRU_CLKSEL_CON(4), 4186e3f8cdb8Skettenis SEL(11, 11), DIV(10, 6), 4187e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4188e3f8cdb8Skettenis }, 4189e3f8cdb8Skettenis { 4190e3f8cdb8Skettenis RK3588_CLK_700M_SRC, RK3588_CRU_CLKSEL_CON(6), 4191e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 4192e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_SPLL } 4193e3f8cdb8Skettenis }, 4194e3f8cdb8Skettenis { 4195e3f8cdb8Skettenis RK3588_ACLK_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8), 4196e3f8cdb8Skettenis SEL(6, 5), 0, 4197e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL } 4198e3f8cdb8Skettenis }, 4199e3f8cdb8Skettenis { 4200e3f8cdb8Skettenis RK3588_PCLK_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8), 4201e3f8cdb8Skettenis SEL(8, 7), 0, 4202e3f8cdb8Skettenis { RK3588_CLK_100M_SRC, RK3588_CLK_50M_SRC, RK3588_XIN24M } 4203e3f8cdb8Skettenis }, 4204e3f8cdb8Skettenis { 4205e3f8cdb8Skettenis RK3588_ACLK_LOW_TOP_ROOT, RK3588_CRU_CLKSEL_CON(8), 4206e3f8cdb8Skettenis SEL(14, 14), DIV(13, 9), 4207e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4208e3f8cdb8Skettenis }, 4209e3f8cdb8Skettenis { 4210e3f8cdb8Skettenis RK3588_CLK_GPU_SRC, RK3588_CRU_CLKSEL_CON(158), 4211e3f8cdb8Skettenis SEL(7, 5), DIV(4, 0), 4212e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL, 4213e3f8cdb8Skettenis RK3588_PLL_NPLL, RK3588_PLL_SPLL } 4214e3f8cdb8Skettenis }, 4215e3f8cdb8Skettenis { 4216e3f8cdb8Skettenis RK3588_CLK_GPU, 0, 0, 0, 4217e3f8cdb8Skettenis { RK3588_CLK_GPU_SRC }, 4218e3f8cdb8Skettenis SET_PARENT 4219e3f8cdb8Skettenis }, 4220e3f8cdb8Skettenis { 422113600422Spatrick RK3588_CCLK_EMMC, RK3588_CRU_CLKSEL_CON(77), 422213600422Spatrick SEL(15, 14), DIV(13, 8), 422313600422Spatrick { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_XIN24M } 422413600422Spatrick }, 422513600422Spatrick { 422613600422Spatrick RK3588_BCLK_EMMC, RK3588_CRU_CLKSEL_CON(78), 422713600422Spatrick SEL(5, 5), DIV(4, 0), 422813600422Spatrick { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 422913600422Spatrick }, 423013600422Spatrick { 423113600422Spatrick RK3588_TMCLK_EMMC, 0, 0, 0, 423213600422Spatrick { RK3588_XIN24M } 423313600422Spatrick }, 423413600422Spatrick { 4235761126a9Skettenis RK3588_CLK_GMAC_125M, RK3588_CRU_CLKSEL_CON(83), 4236761126a9Skettenis SEL(15, 15), DIV(14, 8), 4237761126a9Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL } 4238761126a9Skettenis }, 4239761126a9Skettenis { 42400dbfb11eSkettenis RK3588_CCLK_SRC_SDIO, RK3588_CRU_CLKSEL_CON(172), 42410dbfb11eSkettenis SEL(9, 8), DIV(7, 2), 42420dbfb11eSkettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_XIN24M } 42430dbfb11eSkettenis }, 42440dbfb11eSkettenis { 4245e3f8cdb8Skettenis RK3588_ACLK_VOP_ROOT, RK3588_CRU_CLKSEL_CON(110), 4246e3f8cdb8Skettenis SEL(7, 5), DIV(4, 0), 4247e3f8cdb8Skettenis { RK3588_PLL_GPLL, RK3588_PLL_CPLL, RK3588_PLL_AUPLL, 4248e3f8cdb8Skettenis RK3588_PLL_NPLL, RK3588_PLL_SPLL } 4249e3f8cdb8Skettenis }, 4250e3f8cdb8Skettenis { 4251e3f8cdb8Skettenis RK3588_ACLK_VOP, 0, 0, 0, 4252e3f8cdb8Skettenis { RK3588_ACLK_VOP_SUB_SRC }, 4253e3f8cdb8Skettenis SET_PARENT 4254e3f8cdb8Skettenis }, 4255e3f8cdb8Skettenis { 4256e3f8cdb8Skettenis RK3588_ACLK_VOP_SUB_SRC, RK3588_CRU_CLKSEL_CON(115), 4257e3f8cdb8Skettenis SEL(9, 9), 0, 4258e3f8cdb8Skettenis { RK3588_ACLK_VOP_ROOT, 0 /* RK3588_ACLK_VOP_DIV2_SRC */ }, 4259e3f8cdb8Skettenis SET_PARENT 4260e3f8cdb8Skettenis }, 4261e3f8cdb8Skettenis { 4262cec24affSpatrick RK3588_CLK_I2C0, RK3588_CRU_CLKSEL_CON(3), 4263cec24affSpatrick SEL(6, 6), 0, 4264cec24affSpatrick { RK3588_CLK_PMU1_200M_SRC, RK3588_CLK_PMU1_100M_SRC }, 4265cec24affSpatrick }, 4266cec24affSpatrick { 4267e3f8cdb8Skettenis RK3588_CLK_PMU1_50M_SRC, RK3588_PMUCRU_CLKSEL_CON(0), 4268e3f8cdb8Skettenis 0, DIV(3, 0), 4269e3f8cdb8Skettenis { RK3588_CLK_PMU1_400M_SRC } 4270e3f8cdb8Skettenis }, 4271e3f8cdb8Skettenis { 4272e3f8cdb8Skettenis RK3588_CLK_PMU1_100M_SRC, RK3588_PMUCRU_CLKSEL_CON(0), 4273e3f8cdb8Skettenis 0, DIV(6, 4), 4274e3f8cdb8Skettenis { RK3588_CLK_PMU1_400M_SRC } 4275e3f8cdb8Skettenis }, 4276e3f8cdb8Skettenis { 4277e3f8cdb8Skettenis RK3588_CLK_PMU1_200M_SRC, RK3588_PMUCRU_CLKSEL_CON(0), 4278e3f8cdb8Skettenis 0, DIV(9, 7), 4279e3f8cdb8Skettenis { RK3588_CLK_PMU1_400M_SRC } 4280e3f8cdb8Skettenis }, 4281e3f8cdb8Skettenis { 4282e3f8cdb8Skettenis RK3588_CLK_PMU1_400M_SRC, RK3588_PMUCRU_CLKSEL_CON(1), 4283e3f8cdb8Skettenis SEL(5, 5), DIV(4, 0), 4284e3f8cdb8Skettenis { RK3588_CLK_400M_SRC, RK3588_XIN24M } 4285e3f8cdb8Skettenis }, 4286e3f8cdb8Skettenis { 4287e3f8cdb8Skettenis RK3588_PCLK_PMU1_ROOT, RK3588_PMUCRU_CLKSEL_CON(1), 4288e3f8cdb8Skettenis SEL(9, 8), 0, 4289e3f8cdb8Skettenis { RK3588_CLK_PMU1_100M_SRC, RK3588_CLK_PMU1_50M_SRC, 4290e3f8cdb8Skettenis RK3588_XIN24M } 4291e3f8cdb8Skettenis }, 4292e3f8cdb8Skettenis { 4293e3f8cdb8Skettenis RK3588_PCLK_PMU0_ROOT, 0, 0, 0, 4294e3f8cdb8Skettenis { RK3588_PCLK_PMU1_ROOT }, 4295e3f8cdb8Skettenis SET_PARENT 4296e3f8cdb8Skettenis }, 4297e3f8cdb8Skettenis { 4298e3f8cdb8Skettenis RK3588_HCLK_PMU_CM0_ROOT, RK3588_PMUCRU_CLKSEL_CON(1), 4299e3f8cdb8Skettenis SEL(11, 10), 0, 4300e3f8cdb8Skettenis { RK3588_CLK_PMU1_400M_SRC, RK3588_CLK_PMU1_200M_SRC, 4301e3f8cdb8Skettenis RK3588_CLK_PMU1_100M_SRC, RK3588_XIN24M } 4302e3f8cdb8Skettenis }, 4303e3f8cdb8Skettenis { 4304402c60e6Spatrick RK3588_CLK_PMU1PWM, RK3588_PMUCRU_CLKSEL_CON(2), 4305402c60e6Spatrick SEL(10, 9), 0, 4306402c60e6Spatrick { RK3588_CLK_PMU1_100M_SRC, RK3588_CLK_PMU1_50M_SRC, 4307402c60e6Spatrick RK3588_XIN24M } 4308402c60e6Spatrick }, 4309402c60e6Spatrick { 4310e3f8cdb8Skettenis RK3588_CLK_UART0_SRC, RK3588_PMUCRU_CLKSEL_CON(3), 4311e3f8cdb8Skettenis 0, DIV(11, 7), 4312e3f8cdb8Skettenis { RK3588_PLL_CPLL } 4313e3f8cdb8Skettenis }, 4314e3f8cdb8Skettenis { 4315e3f8cdb8Skettenis RK3588_CLK_UART0, RK3588_PMUCRU_CLKSEL_CON(5), 4316e3f8cdb8Skettenis SEL(1, 0), 0, 4317e3f8cdb8Skettenis { RK3588_CLK_UART0_SRC, RK3588_CLK_UART0_FRAC, RK3588_XIN24M } 4318e3f8cdb8Skettenis }, 4319e3f8cdb8Skettenis { 4320e3f8cdb8Skettenis RK3588_SCLK_UART0, 0, 0, 0, 4321e3f8cdb8Skettenis { RK3588_CLK_UART0 } 4322e3f8cdb8Skettenis }, 4323e3f8cdb8Skettenis { 432483b03bd4Skettenis RK3588_CLK_REF_PIPE_PHY0_OSC_SRC, 0, 0, 0, 432583b03bd4Skettenis { RK3588_XIN24M } 432683b03bd4Skettenis }, 432783b03bd4Skettenis { 432820dcd189Spatrick RK3588_CLK_REF_PIPE_PHY1_OSC_SRC, 0, 0, 0, 432920dcd189Spatrick { RK3588_XIN24M } 433020dcd189Spatrick }, 433120dcd189Spatrick { 433220dcd189Spatrick RK3588_CLK_REF_PIPE_PHY2_OSC_SRC, 0, 0, 0, 433320dcd189Spatrick { RK3588_XIN24M } 433420dcd189Spatrick }, 433520dcd189Spatrick { 433683b03bd4Skettenis RK3588_CLK_REF_PIPE_PHY0_PLL_SRC, RK3588_CRU_CLKSEL_CON(176), 433783b03bd4Skettenis 0, DIV(5, 0), 433883b03bd4Skettenis { RK3588_PLL_PPLL } 433983b03bd4Skettenis }, 434083b03bd4Skettenis { 434120dcd189Spatrick RK3588_CLK_REF_PIPE_PHY1_PLL_SRC, RK3588_CRU_CLKSEL_CON(176), 434220dcd189Spatrick 0, DIV(11, 6), 434320dcd189Spatrick { RK3588_PLL_PPLL } 434420dcd189Spatrick }, 434520dcd189Spatrick { 434620dcd189Spatrick RK3588_CLK_REF_PIPE_PHY2_PLL_SRC, RK3588_CRU_CLKSEL_CON(177), 434720dcd189Spatrick 0, DIV(5, 0), 434820dcd189Spatrick { RK3588_PLL_PPLL } 434920dcd189Spatrick }, 435020dcd189Spatrick { 435183b03bd4Skettenis RK3588_CLK_REF_PIPE_PHY0, RK3588_CRU_CLKSEL_CON(177), 435283b03bd4Skettenis SEL(6, 6), 0, 435383b03bd4Skettenis { RK3588_CLK_REF_PIPE_PHY0_OSC_SRC, 435483b03bd4Skettenis RK3588_CLK_REF_PIPE_PHY0_PLL_SRC }, 435583b03bd4Skettenis }, 435683b03bd4Skettenis { 435720dcd189Spatrick RK3588_CLK_REF_PIPE_PHY1, RK3588_CRU_CLKSEL_CON(177), 435820dcd189Spatrick SEL(7, 7), 0, 435920dcd189Spatrick { RK3588_CLK_REF_PIPE_PHY1_OSC_SRC, 436020dcd189Spatrick RK3588_CLK_REF_PIPE_PHY1_PLL_SRC }, 436120dcd189Spatrick }, 436220dcd189Spatrick { 436320dcd189Spatrick RK3588_CLK_REF_PIPE_PHY2, RK3588_CRU_CLKSEL_CON(177), 436420dcd189Spatrick SEL(8, 8), 0, 436520dcd189Spatrick { RK3588_CLK_REF_PIPE_PHY2_OSC_SRC, 436620dcd189Spatrick RK3588_CLK_REF_PIPE_PHY2_PLL_SRC }, 436720dcd189Spatrick }, 436820dcd189Spatrick { 4369e3f8cdb8Skettenis /* Sentinel */ 4370e3f8cdb8Skettenis } 4371e3f8cdb8Skettenis }; 4372e3f8cdb8Skettenis 4373e3f8cdb8Skettenis /* Certain test clocks are disabled. */ 4374e3f8cdb8Skettenis const uint32_t rk3588_gates[78] = { 4375e3f8cdb8Skettenis [2] = 0x00000050, 4376e3f8cdb8Skettenis [22] = 0x00000200, 4377e3f8cdb8Skettenis [25] = 0x00000200, 4378e3f8cdb8Skettenis [29] = 0x00000004, 4379e3f8cdb8Skettenis [66] = 0x00000004, 4380e3f8cdb8Skettenis }; 4381e3f8cdb8Skettenis 4382e3f8cdb8Skettenis void 4383e3f8cdb8Skettenis rk3588_init(struct rkclock_softc *sc) 4384e3f8cdb8Skettenis { 4385e3f8cdb8Skettenis int i; 4386e3f8cdb8Skettenis 4387e3f8cdb8Skettenis /* The code below assumes all clocks are enabled. Check this!. */ 4388e3f8cdb8Skettenis for (i = 0; i < nitems(rk3588_gates); i++) { 4389e3f8cdb8Skettenis if (HREAD4(sc, RK3588_CRU_GATE_CON(i)) != rk3588_gates[i]) { 4390e3f8cdb8Skettenis printf("CRU_GATE_CON%d: 0x%08x\n", i, 4391e3f8cdb8Skettenis HREAD4(sc, RK3588_CRU_GATE_CON(i))); 4392e3f8cdb8Skettenis } 4393e3f8cdb8Skettenis } 4394e3f8cdb8Skettenis 4395e3f8cdb8Skettenis sc->sc_clocks = rk3588_clocks; 4396e3f8cdb8Skettenis } 4397e3f8cdb8Skettenis 4398e3f8cdb8Skettenis int 4399e3f8cdb8Skettenis rk3588_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 4400e3f8cdb8Skettenis { 4401e3f8cdb8Skettenis uint32_t p, m, s, k; 4402e3f8cdb8Skettenis int mode_shift = -1; 4403e3f8cdb8Skettenis 4404e3f8cdb8Skettenis switch (base) { 4405e3f8cdb8Skettenis case RK3588_CRU_AUPLL_CON(0): 4406e3f8cdb8Skettenis mode_shift = 6; 4407e3f8cdb8Skettenis break; 4408e3f8cdb8Skettenis case RK3588_CRU_GPLL_CON(0): 4409e3f8cdb8Skettenis mode_shift = 2; 4410e3f8cdb8Skettenis break; 4411e3f8cdb8Skettenis case RK3588_CRU_NPLL_CON(0): 4412e3f8cdb8Skettenis mode_shift = 0; 4413e3f8cdb8Skettenis break; 4414e3f8cdb8Skettenis case RK3588_PHPTOPCRU_PPLL_CON(0): 4415e3f8cdb8Skettenis mode_shift = 10; 4416e3f8cdb8Skettenis break; 4417e3f8cdb8Skettenis } 4418e3f8cdb8Skettenis KASSERT(mode_shift != -1); 4419e3f8cdb8Skettenis 4420e3f8cdb8Skettenis /* 4421e3f8cdb8Skettenis * It is not clear whether all combinations of the clock 4422e3f8cdb8Skettenis * dividers result in a stable clock. Therefore this function 4423e3f8cdb8Skettenis * only supports a limited set of PLL clock rates. 4424e3f8cdb8Skettenis */ 4425e3f8cdb8Skettenis switch (freq) { 4426e3f8cdb8Skettenis case 1188000000U: 4427e3f8cdb8Skettenis p = 2; m = 198; s = 1; k = 0; 4428e3f8cdb8Skettenis break; 44290dbfb11eSkettenis case 1100000000U: 44300dbfb11eSkettenis p = 3; m = 550; s = 2; k = 0; 44310dbfb11eSkettenis break; 4432e3f8cdb8Skettenis case 850000000U: 4433e3f8cdb8Skettenis p = 3; m = 425; s = 2; k = 0; 4434e3f8cdb8Skettenis break; 4435e3f8cdb8Skettenis case 786432000U: 4436e3f8cdb8Skettenis p = 2; m = 262; s = 2; k = 9437; 4437e3f8cdb8Skettenis break; 4438e3f8cdb8Skettenis case 100000000U: 4439e3f8cdb8Skettenis p = 3; m = 400; s = 5; k = 0; 4440e3f8cdb8Skettenis break; 4441e3f8cdb8Skettenis default: 4442e3f8cdb8Skettenis printf("%s: %u Hz\n", __func__, freq); 4443e3f8cdb8Skettenis return -1; 4444e3f8cdb8Skettenis } 4445e3f8cdb8Skettenis 4446e3f8cdb8Skettenis /* 4447e3f8cdb8Skettenis * Select slow mode to guarantee a stable clock while we're 4448e3f8cdb8Skettenis * adjusting the PLL. 4449e3f8cdb8Skettenis */ 4450e3f8cdb8Skettenis HWRITE4(sc, RK3588_CRU_MODE_CON, 4451e3f8cdb8Skettenis (RK3588_CRU_MODE_MASK << 16 |RK3588_CRU_MODE_SLOW) << mode_shift); 4452e3f8cdb8Skettenis 4453e3f8cdb8Skettenis /* Power down PLL. */ 4454e3f8cdb8Skettenis HWRITE4(sc, base + 0x0004, 4455e3f8cdb8Skettenis RK3588_CRU_PLL_RESETB << 16 | RK3588_CRU_PLL_RESETB); 4456e3f8cdb8Skettenis 4457e3f8cdb8Skettenis /* Set PLL rate. */ 4458e3f8cdb8Skettenis HWRITE4(sc, base + 0x0000, 4459e3f8cdb8Skettenis RK3588_CRU_PLL_M_MASK << 16 | m << RK3588_CRU_PLL_M_SHIFT); 4460e3f8cdb8Skettenis HWRITE4(sc, base + 0x0004, 4461e3f8cdb8Skettenis RK3588_CRU_PLL_S_MASK << 16 | s << RK3588_CRU_PLL_S_SHIFT | 4462e3f8cdb8Skettenis RK3588_CRU_PLL_P_MASK << 16 | p << RK3588_CRU_PLL_P_SHIFT); 4463e3f8cdb8Skettenis HWRITE4(sc, base + 0x0008, 4464e3f8cdb8Skettenis RK3588_CRU_PLL_K_MASK << 16 | k << RK3588_CRU_PLL_K_SHIFT); 4465e3f8cdb8Skettenis 4466e3f8cdb8Skettenis /* Power up PLL. */ 4467e3f8cdb8Skettenis HWRITE4(sc, base + 0x0004, RK3588_CRU_PLL_RESETB << 16); 4468e3f8cdb8Skettenis 4469e3f8cdb8Skettenis /* Wait for PLL to stabilize. */ 4470e3f8cdb8Skettenis while ((HREAD4(sc, base + 0x0018) & RK3588_CRU_PLL_PLL_LOCK) == 0) 4471e3f8cdb8Skettenis delay(10); 4472e3f8cdb8Skettenis 4473e3f8cdb8Skettenis /* Switch back to normal mode. */ 4474e3f8cdb8Skettenis HWRITE4(sc, RK3588_CRU_MODE_CON, 4475e3f8cdb8Skettenis (RK3588_CRU_MODE_MASK << 16 | RK3588_CRU_MODE_NORMAL) << mode_shift); 4476e3f8cdb8Skettenis 4477e3f8cdb8Skettenis return 0; 4478e3f8cdb8Skettenis } 4479e3f8cdb8Skettenis 4480e3f8cdb8Skettenis uint32_t 4481e3f8cdb8Skettenis rk3588_get_pll(struct rkclock_softc *sc, bus_size_t base) 4482e3f8cdb8Skettenis { 4483e3f8cdb8Skettenis uint64_t freq, frac; 4484e3f8cdb8Skettenis uint32_t k, m, p, s; 4485e3f8cdb8Skettenis uint32_t reg; 4486e3f8cdb8Skettenis 4487e3f8cdb8Skettenis reg = HREAD4(sc, base); 4488e3f8cdb8Skettenis m = (reg & RK3588_CRU_PLL_M_MASK) >> RK3588_CRU_PLL_M_SHIFT; 4489e3f8cdb8Skettenis reg = HREAD4(sc, base + 4); 4490e3f8cdb8Skettenis p = (reg & RK3588_CRU_PLL_P_MASK) >> RK3588_CRU_PLL_P_SHIFT; 4491e3f8cdb8Skettenis s = (reg & RK3588_CRU_PLL_S_MASK) >> RK3588_CRU_PLL_S_SHIFT; 4492e3f8cdb8Skettenis reg = HREAD4(sc, base + 8); 4493e3f8cdb8Skettenis k = (reg & RK3588_CRU_PLL_K_MASK) >> RK3588_CRU_PLL_K_SHIFT; 4494e3f8cdb8Skettenis 4495e3f8cdb8Skettenis freq = (24000000ULL * m) / p; 4496e3f8cdb8Skettenis if (k) { 4497e3f8cdb8Skettenis frac = ((24000000ULL * k) / (p * 65535)); 4498e3f8cdb8Skettenis freq += frac; 4499e3f8cdb8Skettenis } 4500e3f8cdb8Skettenis 4501e3f8cdb8Skettenis return freq >> s; 4502e3f8cdb8Skettenis } 4503e3f8cdb8Skettenis 4504e3f8cdb8Skettenis uint32_t 4505e3f8cdb8Skettenis rk3588_get_frequency(void *cookie, uint32_t *cells) 4506e3f8cdb8Skettenis { 4507e3f8cdb8Skettenis struct rkclock_softc *sc = cookie; 4508e3f8cdb8Skettenis uint32_t idx = cells[0]; 4509e3f8cdb8Skettenis uint32_t freq; 4510e3f8cdb8Skettenis 4511e3f8cdb8Skettenis switch (idx) { 4512e3f8cdb8Skettenis case RK3588_PLL_AUPLL: 4513e3f8cdb8Skettenis return rk3588_get_pll(sc, RK3588_CRU_AUPLL_CON(0)); 4514e3f8cdb8Skettenis case RK3588_PLL_CPLL: 4515e3f8cdb8Skettenis return rk3588_get_pll(sc, RK3588_CRU_CPLL_CON(0)); 4516e3f8cdb8Skettenis case RK3588_PLL_GPLL: 4517e3f8cdb8Skettenis return rk3588_get_pll(sc, RK3588_CRU_GPLL_CON(0)); 4518e3f8cdb8Skettenis case RK3588_PLL_NPLL: 4519e3f8cdb8Skettenis return rk3588_get_pll(sc, RK3588_CRU_NPLL_CON(0)); 4520e3f8cdb8Skettenis case RK3588_PLL_PPLL: 4521e3f8cdb8Skettenis return rk3588_get_pll(sc, RK3588_PHPTOPCRU_PPLL_CON(0)); 4522e3f8cdb8Skettenis case RK3588_PLL_SPLL: 4523e3f8cdb8Skettenis return rkclock_external_frequency("spll"); 4524e3f8cdb8Skettenis case RK3588_XIN24M: 4525e3f8cdb8Skettenis return 24000000; 4526e3f8cdb8Skettenis default: 4527e3f8cdb8Skettenis break; 4528e3f8cdb8Skettenis } 4529e3f8cdb8Skettenis 4530e3f8cdb8Skettenis freq = rkclock_get_frequency(sc, idx); 4531e3f8cdb8Skettenis return freq; 4532e3f8cdb8Skettenis } 4533e3f8cdb8Skettenis 4534e3f8cdb8Skettenis int 4535e3f8cdb8Skettenis rk3588_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 4536e3f8cdb8Skettenis { 4537e3f8cdb8Skettenis struct rkclock_softc *sc = cookie; 4538e3f8cdb8Skettenis uint32_t idx = cells[0]; 4539e3f8cdb8Skettenis 4540e3f8cdb8Skettenis switch (idx) { 4541e3f8cdb8Skettenis case RK3588_PLL_AUPLL: 4542e3f8cdb8Skettenis return rk3588_set_pll(sc, RK3588_CRU_AUPLL_CON(0), freq); 4543e3f8cdb8Skettenis case RK3588_PLL_GPLL: 4544e3f8cdb8Skettenis return rk3588_set_pll(sc, RK3588_CRU_GPLL_CON(0), freq); 4545e3f8cdb8Skettenis case RK3588_PLL_NPLL: 4546e3f8cdb8Skettenis return rk3588_set_pll(sc, RK3588_CRU_NPLL_CON(0), freq); 4547e3f8cdb8Skettenis case RK3588_PLL_PPLL: 4548e3f8cdb8Skettenis return rk3588_set_pll(sc, RK3588_PHPTOPCRU_PPLL_CON(0), freq); 4549e3f8cdb8Skettenis default: 4550e3f8cdb8Skettenis break; 4551e3f8cdb8Skettenis } 4552e3f8cdb8Skettenis 4553e3f8cdb8Skettenis return rkclock_set_frequency(sc, idx, freq); 4554e3f8cdb8Skettenis } 4555e3f8cdb8Skettenis 4556e3f8cdb8Skettenis void 4557e3f8cdb8Skettenis rk3588_enable(void *cookie, uint32_t *cells, int on) 4558e3f8cdb8Skettenis { 4559e3f8cdb8Skettenis uint32_t idx = cells[0]; 4560e3f8cdb8Skettenis 4561e3f8cdb8Skettenis /* All clocks are enabled upon hardware reset. */ 4562e3f8cdb8Skettenis if (!on) { 4563e3f8cdb8Skettenis printf("%s: 0x%08x\n", __func__, idx); 4564e3f8cdb8Skettenis return; 4565e3f8cdb8Skettenis } 4566e3f8cdb8Skettenis } 4567e3f8cdb8Skettenis 4568e3f8cdb8Skettenis void 4569e3f8cdb8Skettenis rk3588_reset(void *cookie, uint32_t *cells, int on) 4570e3f8cdb8Skettenis { 457183b03bd4Skettenis struct rkclock_softc *sc = cookie; 4572e3f8cdb8Skettenis uint32_t idx = cells[0]; 457383b03bd4Skettenis uint32_t bit, mask, reg; 4574e3f8cdb8Skettenis 457583b03bd4Skettenis switch (idx) { 45769efac0bfSkettenis case RK3588_SRST_P_TSADC: 45779efac0bfSkettenis reg = RK3588_CRU_SOFTRST_CON(12); 45789efac0bfSkettenis bit = 0; 45799efac0bfSkettenis break; 45809efac0bfSkettenis case RK3588_SRST_TSADC: 45819efac0bfSkettenis reg = RK3588_CRU_SOFTRST_CON(12); 45829efac0bfSkettenis bit = 1; 45839efac0bfSkettenis break; 458413600422Spatrick case RK3588_SRST_H_EMMC: 458513600422Spatrick reg = RK3588_CRU_SOFTRST_CON(31); 458613600422Spatrick bit = 4; 458713600422Spatrick break; 458813600422Spatrick case RK3588_SRST_A_EMMC: 458913600422Spatrick reg = RK3588_CRU_SOFTRST_CON(31); 459013600422Spatrick bit = 5; 459113600422Spatrick break; 459213600422Spatrick case RK3588_SRST_C_EMMC: 459313600422Spatrick reg = RK3588_CRU_SOFTRST_CON(31); 459413600422Spatrick bit = 6; 459513600422Spatrick break; 459613600422Spatrick case RK3588_SRST_B_EMMC: 459713600422Spatrick reg = RK3588_CRU_SOFTRST_CON(31); 459813600422Spatrick bit = 7; 459913600422Spatrick break; 460013600422Spatrick case RK3588_SRST_T_EMMC: 460113600422Spatrick reg = RK3588_CRU_SOFTRST_CON(31); 460213600422Spatrick bit = 8; 460313600422Spatrick break; 4604761126a9Skettenis case RK3588_SRST_A_GMAC0: 4605761126a9Skettenis reg = RK3588_CRU_SOFTRST_CON(32); 4606761126a9Skettenis bit = 10; 4607761126a9Skettenis break; 4608761126a9Skettenis case RK3588_SRST_A_GMAC1: 4609761126a9Skettenis reg = RK3588_CRU_SOFTRST_CON(32); 4610761126a9Skettenis bit = 11; 4611761126a9Skettenis break; 461273d3ec9fSpatrick case RK3588_SRST_PCIE0_POWER_UP: 461373d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(32); 461473d3ec9fSpatrick bit = 13; 461573d3ec9fSpatrick break; 461673d3ec9fSpatrick case RK3588_SRST_PCIE1_POWER_UP: 461773d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(32); 461873d3ec9fSpatrick bit = 14; 461973d3ec9fSpatrick break; 462073d3ec9fSpatrick case RK3588_SRST_PCIE2_POWER_UP: 462173d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(32); 462273d3ec9fSpatrick bit = 15; 462373d3ec9fSpatrick break; 462473d3ec9fSpatrick case RK3588_SRST_PCIE3_POWER_UP: 462573d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(33); 462673d3ec9fSpatrick bit = 0; 462773d3ec9fSpatrick break; 462883b03bd4Skettenis case RK3588_SRST_PCIE4_POWER_UP: 462983b03bd4Skettenis reg = RK3588_CRU_SOFTRST_CON(33); 463083b03bd4Skettenis bit = 1; 463183b03bd4Skettenis break; 463273d3ec9fSpatrick case RK3588_SRST_P_PCIE0: 463373d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(33); 463473d3ec9fSpatrick bit = 12; 463573d3ec9fSpatrick break; 463673d3ec9fSpatrick case RK3588_SRST_P_PCIE1: 463773d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(33); 463873d3ec9fSpatrick bit = 13; 463973d3ec9fSpatrick break; 464073d3ec9fSpatrick case RK3588_SRST_P_PCIE2: 464173d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(33); 464273d3ec9fSpatrick bit = 14; 464373d3ec9fSpatrick break; 464473d3ec9fSpatrick case RK3588_SRST_P_PCIE3: 464573d3ec9fSpatrick reg = RK3588_CRU_SOFTRST_CON(33); 464673d3ec9fSpatrick bit = 15; 464773d3ec9fSpatrick break; 46481897c8c3Skettenis case RK3588_SRST_P_PCIE4: 46491897c8c3Skettenis reg = RK3588_CRU_SOFTRST_CON(34); 46501897c8c3Skettenis bit = 0; 46511897c8c3Skettenis break; 46520dbfb11eSkettenis case RK3588_SRST_A_USB3OTG2: 46530dbfb11eSkettenis reg = RK3588_CRU_SOFTRST_CON(35); 46540dbfb11eSkettenis bit = 7; 46550dbfb11eSkettenis break; 4656e77f74d5Spatrick case RK3588_SRST_A_USB3OTG0: 4657e77f74d5Spatrick reg = RK3588_CRU_SOFTRST_CON(42); 4658e77f74d5Spatrick bit = 4; 4659e77f74d5Spatrick break; 4660e77f74d5Spatrick case RK3588_SRST_A_USB3OTG1: 4661e77f74d5Spatrick reg = RK3588_CRU_SOFTRST_CON(42); 4662e77f74d5Spatrick bit = 7; 4663e77f74d5Spatrick break; 466483b03bd4Skettenis case RK3588_SRST_REF_PIPE_PHY0: 466583b03bd4Skettenis reg = RK3588_CRU_SOFTRST_CON(77); 466683b03bd4Skettenis bit = 6; 466783b03bd4Skettenis break; 466820dcd189Spatrick case RK3588_SRST_REF_PIPE_PHY1: 466920dcd189Spatrick reg = RK3588_CRU_SOFTRST_CON(77); 467020dcd189Spatrick bit = 7; 467120dcd189Spatrick break; 467220dcd189Spatrick case RK3588_SRST_REF_PIPE_PHY2: 467320dcd189Spatrick reg = RK3588_CRU_SOFTRST_CON(77); 467420dcd189Spatrick bit = 8; 467520dcd189Spatrick break; 467683b03bd4Skettenis case RK3588_SRST_P_PCIE2_PHY0: 467783b03bd4Skettenis reg = RK3588_PHPTOPCRU_SOFTRST_CON(0); 467883b03bd4Skettenis bit = 5; 467983b03bd4Skettenis break; 468020dcd189Spatrick case RK3588_SRST_P_PCIE2_PHY1: 468120dcd189Spatrick reg = RK3588_PHPTOPCRU_SOFTRST_CON(0); 468220dcd189Spatrick bit = 6; 468320dcd189Spatrick break; 468420dcd189Spatrick case RK3588_SRST_P_PCIE2_PHY2: 468520dcd189Spatrick reg = RK3588_PHPTOPCRU_SOFTRST_CON(0); 468620dcd189Spatrick bit = 7; 468720dcd189Spatrick break; 468873d3ec9fSpatrick case RK3588_SRST_PCIE30_PHY: 468973d3ec9fSpatrick reg = RK3588_PHPTOPCRU_SOFTRST_CON(0); 469073d3ec9fSpatrick bit = 10; 469173d3ec9fSpatrick break; 469283b03bd4Skettenis default: 4693e3f8cdb8Skettenis printf("%s: 0x%08x\n", __func__, idx); 469483b03bd4Skettenis return; 469583b03bd4Skettenis } 469683b03bd4Skettenis 469783b03bd4Skettenis mask = (1 << bit); 469883b03bd4Skettenis HWRITE4(sc, reg, mask << 16 | (on ? mask : 0)); 4699e3f8cdb8Skettenis } 4700