Add support for I2S clocks.diff -r1.12 -r1.13 src/sys/arch/arm/rockchip/rk3399_cru.c
(jmcneill)
--- src/sys/arch/arm/rockchip/rk3399_cru.c 2019/11/10 11:43:04 1.12
+++ src/sys/arch/arm/rockchip/rk3399_cru.c 2019/11/16 13:23:13 1.13
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: rk3399_cru.c,v 1.12 2019/11/10 11:43:04 jmcneill Exp $ */ | 1 | /* $NetBSD: rk3399_cru.c,v 1.13 2019/11/16 13:23:13 jmcneill Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -18,27 +18,27 @@ | @@ -18,27 +18,27 @@ | |||
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | 30 | |||
31 | __KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.12 2019/11/10 11:43:04 jmcneill Exp $"); | 31 | __KERNEL_RCSID(1, "$NetBSD: rk3399_cru.c,v 1.13 2019/11/16 13:23:13 jmcneill Exp $"); | |
32 | 32 | |||
33 | #include <sys/param.h> | 33 | #include <sys/param.h> | |
34 | #include <sys/bus.h> | 34 | #include <sys/bus.h> | |
35 | #include <sys/device.h> | 35 | #include <sys/device.h> | |
36 | #include <sys/systm.h> | 36 | #include <sys/systm.h> | |
37 | 37 | |||
38 | #include <dev/fdt/fdtvar.h> | 38 | #include <dev/fdt/fdtvar.h> | |
39 | 39 | |||
40 | #include <arm/rockchip/rk_cru.h> | 40 | #include <arm/rockchip/rk_cru.h> | |
41 | #include <arm/rockchip/rk3399_cru.h> | 41 | #include <arm/rockchip/rk3399_cru.h> | |
42 | 42 | |||
43 | #define PLL_CON(n) (0x0000 + (n) * 4) | 43 | #define PLL_CON(n) (0x0000 + (n) * 4) | |
44 | #define CLKSEL_CON(n) (0x0100 + (n) * 4) | 44 | #define CLKSEL_CON(n) (0x0100 + (n) * 4) | |
@@ -351,26 +351,31 @@ static const char * mux_pll_src_cpll_gpl | @@ -351,26 +351,31 @@ static const char * mux_pll_src_cpll_gpl | |||
351 | static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" }; | 351 | static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" }; | |
352 | static const char * mux_pll_src_cpll_gpll_ppll_parents[] = { "cpll", "gpll", "npll" }; | 352 | static const char * mux_pll_src_cpll_gpll_ppll_parents[] = { "cpll", "gpll", "npll" }; | |
353 | static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" }; | 353 | static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" }; | |
354 | static const char * mux_pll_src_cpll_gpll_npll_24m_parents[] = { "cpll", "gpll", "npll", "xin24m" }; | 354 | static const char * mux_pll_src_cpll_gpll_npll_24m_parents[] = { "cpll", "gpll", "npll", "xin24m" }; | |
355 | static const char * mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents[] = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" }; | 355 | static const char * mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents[] = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" }; | |
356 | static const char * mux_pll_src_vpll_cpll_gpll_parents[] = { "vpll", "cpll", "gpll" }; | 356 | static const char * mux_pll_src_vpll_cpll_gpll_parents[] = { "vpll", "cpll", "gpll" }; | |
357 | static const char * mux_pll_src_vpll_cpll_gpll_npll_parents[] = { "vpll", "cpll", "gpll", "npll" }; | 357 | static const char * mux_pll_src_vpll_cpll_gpll_npll_parents[] = { "vpll", "cpll", "gpll", "npll" }; | |
358 | static const char * mux_aclk_perilp0_parents[] = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" }; | 358 | static const char * mux_aclk_perilp0_parents[] = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" }; | |
359 | static const char * mux_hclk_perilp1_parents[] = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" }; | 359 | static const char * mux_hclk_perilp1_parents[] = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" }; | |
360 | static const char * mux_aclk_perihp_parents[] = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" }; | 360 | static const char * mux_aclk_perihp_parents[] = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" }; | |
361 | static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" }; | 361 | static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" }; | |
362 | static const char * mux_dclk_vop0_parents[] = { "dclk_vop0_div", "dclk_vop0_frac" }; | 362 | static const char * mux_dclk_vop0_parents[] = { "dclk_vop0_div", "dclk_vop0_frac" }; | |
363 | static const char * mux_dclk_vop1_parents[] = { "dclk_vop1_div", "dclk_vop1_frac" }; | 363 | static const char * mux_dclk_vop1_parents[] = { "dclk_vop1_div", "dclk_vop1_frac" }; | |
364 | static const char * mux_i2s0_parents[] = { "clk_i2s0_div", "clk_i2s0_frac", "clkin_i2s", "xin12m" }; | |||
365 | static const char * mux_i2s1_parents[] = { "clk_i2s1_div", "clk_i2s1_frac", "clkin_i2s", "xin12m" }; | |||
366 | static const char * mux_i2s2_parents[] = { "clk_i2s2_div", "clk_i2s2_frac", "clkin_i2s", "xin12m" }; | |||
367 | static const char * mux_i2sch_parents[] = { "clk_i2s0", "clk_i2s1", "clk_i2s2" }; | |||
368 | static const char * mux_i2sout_parents[] = { "clk_i2sout_src", "xin12m" }; | |||
364 | static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; | 369 | static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; | |
365 | static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; | 370 | static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; | |
366 | static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; | 371 | static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; | |
367 | static const char * mux_uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; | 372 | static const char * mux_uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; | |
368 | static const char * mux_rmii_parents[] = { "clk_gmac", "clkin_gmac" }; | 373 | static const char * mux_rmii_parents[] = { "clk_gmac", "clkin_gmac" }; | |
369 | static const char * mux_aclk_gmac_parents[] = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" }; | 374 | static const char * mux_aclk_gmac_parents[] = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" }; | |
370 | static const char * mux_aclk_emmc_parents[] = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" }; | 375 | static const char * mux_aclk_emmc_parents[] = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" }; | |
371 | static const char * mux_pll_src_24m_pciephy_parents[] = { "xin24m", "clk_pciephy_ref100m" }; | 376 | static const char * mux_pll_src_24m_pciephy_parents[] = { "xin24m", "clk_pciephy_ref100m" }; | |
372 | static const char * mux_pciecore_cru_phy_parents[] = { "clk_pcie_core_cru", "clk_pcie_core_phy" }; | 377 | static const char * mux_pciecore_cru_phy_parents[] = { "clk_pcie_core_cru", "clk_pcie_core_phy" }; | |
373 | 378 | |||
374 | static struct rk_cru_clk rk3399_cru_clks[] = { | 379 | static struct rk_cru_clk rk3399_cru_clks[] = { | |
375 | RK3399_PLL(RK3399_PLL_APLLL, "lpll", pll_parents, | 380 | RK3399_PLL(RK3399_PLL_APLLL, "lpll", pll_parents, | |
376 | PLL_CON(0), /* con_base */ | 381 | PLL_CON(0), /* con_base */ | |
@@ -929,47 +934,126 @@ static struct rk_cru_clk rk3399_cru_clks | @@ -929,47 +934,126 @@ static struct rk_cru_clk rk3399_cru_clks | |||
929 | __BITS(14,10), /* div_mask */ | 934 | __BITS(14,10), /* div_mask */ | |
930 | CLKGATE_CON(11), /* gate_reg */ | 935 | CLKGATE_CON(11), /* gate_reg */ | |
931 | __BIT(10), /* gate_mask */ | 936 | __BIT(10), /* gate_mask */ | |
932 | 0), | 937 | 0), | |
933 | RK_COMPOSITE(RK3399_SCLK_HDMI_CEC, "clk_hdmi_cec", pll_parents, | 938 | RK_COMPOSITE(RK3399_SCLK_HDMI_CEC, "clk_hdmi_cec", pll_parents, | |
934 | CLKSEL_CON(45), /* muxdiv_reg */ | 939 | CLKSEL_CON(45), /* muxdiv_reg */ | |
935 | __BIT(15), /* mux_mask */ | 940 | __BIT(15), /* mux_mask */ | |
936 | __BITS(9,0), /* div_mask */ | 941 | __BITS(9,0), /* div_mask */ | |
937 | CLKGATE_CON(11), /* gate_reg */ | 942 | CLKGATE_CON(11), /* gate_reg */ | |
938 | __BIT(7), /* gate_mask */ | 943 | __BIT(7), /* gate_mask */ | |
939 | 0), | 944 | 0), | |
940 | RK_GATE(RK3399_PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", CLKGATE_CON(29), 6), | 945 | RK_GATE(RK3399_PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", CLKGATE_CON(29), 6), | |
941 | RK_GATE(RK3399_SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", CLKGATE_CON(11), 6), | 946 | RK_GATE(RK3399_SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", CLKGATE_CON(11), 6), | |
947 | ||||
948 | /* I2S2 */ | |||
949 | RK_COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_parents, | |||
950 | CLKSEL_CON(28), /* muxdiv_reg */ | |||
951 | __BIT(7), /* mux_mask */ | |||
952 | __BITS(6,0), /* div_mask */ | |||
953 | CLKGATE_CON(8), /* gate_reg */ | |||
954 | __BIT(3), /* gate_mask */ | |||
955 | 0), | |||
956 | RK_COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_parents, | |||
957 | CLKSEL_CON(29), /* muxdiv_reg */ | |||
958 | __BIT(7), /* mux_mask */ | |||
959 | __BITS(6,0), /* div_mask */ | |||
960 | CLKGATE_CON(8), /* gate_reg */ | |||
961 | __BIT(6), /* gate_mask */ | |||
962 | 0), | |||
963 | RK_COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_parents, | |||
964 | CLKSEL_CON(30), /* muxdiv_reg */ | |||
965 | __BIT(7), /* mux_mask */ | |||
966 | __BITS(6,0), /* div_mask */ | |||
967 | CLKGATE_CON(8), /* gate_reg */ | |||
968 | __BIT(9), /* gate_mask */ | |||
969 | 0), | |||
970 | RK_COMPOSITE_FRAC(0, "clk_i2s0_frac", "clk_i2s0_div", | |||
971 | CLKSEL_CON(96), /* frac_reg */ | |||
972 | 0), | |||
973 | RK_COMPOSITE_FRAC(0, "clk_i2s1_frac", "clk_i2s1_div", | |||
974 | CLKSEL_CON(97), /* frac_reg */ | |||
975 | 0), | |||
976 | RK_COMPOSITE_FRAC(0, "clk_i2s2_frac", "clk_i2s2_div", | |||
977 | CLKSEL_CON(98), /* frac_reg */ | |||
978 | 0), | |||
979 | RK_MUX(0, "clk_i2s0_mux", mux_i2s0_parents, CLKSEL_CON(28), __BITS(9,8)), | |||
980 | RK_MUX(0, "clk_i2s1_mux", mux_i2s1_parents, CLKSEL_CON(29), __BITS(9,8)), | |||
981 | RK_MUX(0, "clk_i2s2_mux", mux_i2s2_parents, CLKSEL_CON(30), __BITS(9,8)), | |||
982 | RK_GATE(RK3399_SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLKGATE_CON(8), 5), | |||
983 | RK_GATE(RK3399_SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLKGATE_CON(8), 8), | |||
984 | RK_GATE(RK3399_SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLKGATE_CON(8), 11), | |||
985 | RK_GATE(RK3399_HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", CLKGATE_CON(34), 0), | |||
986 | RK_GATE(RK3399_HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", CLKGATE_CON(34), 1), | |||
987 | RK_GATE(RK3399_HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", CLKGATE_CON(34), 2), | |||
988 | RK_MUX(0, "clk_i2sout_src", mux_i2sch_parents, CLKSEL_CON(31), __BITS(1,0)), | |||
989 | RK_COMPOSITE(RK3399_SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_parents, | |||
990 | CLKSEL_CON(31), /* muxdiv_reg */ | |||
991 | __BIT(2), /* mux_mask */ | |||
992 | 0, /* div_mask */ | |||
993 | CLKGATE_CON(8), /* gate_reg */ | |||
994 | __BIT(12), /* gate_mask */ | |||
995 | RK_COMPOSITE_SET_RATE_PARENT), | |||
996 | }; | |||
997 | ||||
998 | static const struct rk3399_init_param { | |||
999 | const char *clk; | |||
1000 | const char *parent; | |||
1001 | } rk3399_init_params[] = { | |||
1002 | { .clk = "clk_i2s0_mux", .parent = "clk_i2s0_frac" }, | |||
1003 | { .clk = "clk_i2s1_mux", .parent = "clk_i2s1_frac" }, | |||
1004 | { .clk = "clk_i2s2_mux", .parent = "clk_i2s2_frac" }, | |||
942 | }; | 1005 | }; | |
943 | 1006 | |||
944 | static void | 1007 | static void | |
945 | rk3399_cru_init(struct rk_cru_softc *sc) | 1008 | rk3399_cru_init(struct rk_cru_softc *sc) | |
946 | { | 1009 | { | |
947 | struct rk_cru_clk *clk; | 1010 | struct rk_cru_clk *clk, *pclk; | |
948 | uint32_t write_mask, write_val; | 1011 | uint32_t write_mask, write_val; | |
1012 | int error; | |||
1013 | u_int n; | |||
949 | 1014 | |||
950 | /* | 1015 | /* | |
951 | * Force an update of BPLL to bring it out of slow mode. | 1016 | * Force an update of BPLL to bring it out of slow mode. | |
952 | */ | 1017 | */ | |
953 | clk = rk_cru_clock_find(sc, "armclkb"); | 1018 | clk = rk_cru_clock_find(sc, "armclkb"); | |
954 | clk_set_rate(&clk->base, clk_get_rate(&clk->base)); | 1019 | clk_set_rate(&clk->base, clk_get_rate(&clk->base)); | |
955 | 1020 | |||
956 | /* | 1021 | /* | |
957 | * Set DCLK_VOP0 and DCLK_VOP1 dividers to 1. | 1022 | * Set DCLK_VOP0 and DCLK_VOP1 dividers to 1. | |
958 | */ | 1023 | */ | |
959 | write_mask = __BITS(7,0) << 16; | 1024 | write_mask = __BITS(7,0) << 16; | |
960 | write_val = 0; | 1025 | write_val = 0; | |
961 | CRU_WRITE(sc, CLKSEL_CON(49), write_mask | write_val); | 1026 | CRU_WRITE(sc, CLKSEL_CON(49), write_mask | write_val); | |
962 | CRU_WRITE(sc, CLKSEL_CON(50), write_mask | write_val); | 1027 | CRU_WRITE(sc, CLKSEL_CON(50), write_mask | write_val); | |
1028 | ||||
1029 | /* | |||
1030 | * Set defaults | |||
1031 | */ | |||
1032 | for (n = 0; n < __arraycount(rk3399_init_params); n++) { | |||
1033 | const struct rk3399_init_param *param = &rk3399_init_params[n]; | |||
1034 | clk = rk_cru_clock_find(sc, param->clk); | |||
1035 | KASSERTMSG(clk != NULL, "couldn't find clock %s", param->clk); | |||
1036 | if (param->parent != NULL) { | |||
1037 | pclk = rk_cru_clock_find(sc, param->parent); | |||
1038 | KASSERTMSG(pclk != NULL, "couldn't find clock %s", param->parent); | |||
1039 | error = clk_set_parent(&clk->base, &pclk->base); | |||
1040 | if (error != 0) { | |||
1041 | aprint_error_dev(sc->sc_dev, "couldn't set %s parent to %s: %d\n", | |||
1042 | param->clk, param->parent, error); | |||
1043 | continue; | |||
1044 | } | |||
1045 | } | |||
1046 | } | |||
963 | } | 1047 | } | |
964 | 1048 | |||
965 | static int | 1049 | static int | |
966 | rk3399_cru_match(device_t parent, cfdata_t cf, void *aux) | 1050 | rk3399_cru_match(device_t parent, cfdata_t cf, void *aux) | |
967 | { | 1051 | { | |
968 | struct fdt_attach_args * const faa = aux; | 1052 | struct fdt_attach_args * const faa = aux; | |
969 | 1053 | |||
970 | return of_match_compatible(faa->faa_phandle, compatible); | 1054 | return of_match_compatible(faa->faa_phandle, compatible); | |
971 | } | 1055 | } | |
972 | 1056 | |||
973 | static void | 1057 | static void | |
974 | rk3399_cru_attach(device_t parent, device_t self, void *aux) | 1058 | rk3399_cru_attach(device_t parent, device_t self, void *aux) | |
975 | { | 1059 | { |
--- src/sys/arch/arm/rockchip/rk_cru.h 2019/11/10 11:43:04 1.6
+++ src/sys/arch/arm/rockchip/rk_cru.h 2019/11/16 13:23:13 1.7
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: rk_cru.h,v 1.6 2019/11/10 11:43:04 jmcneill Exp $ */ | 1 | /* $NetBSD: rk_cru.h,v 1.7 2019/11/16 13:23:13 jmcneill Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -190,68 +190,77 @@ int rk_cru_arm_set_parent(struct rk_cru_ | @@ -190,68 +190,77 @@ int rk_cru_arm_set_parent(struct rk_cru_ | |||
190 | .set_rate = rk_cru_arm_set_rate, \ | 190 | .set_rate = rk_cru_arm_set_rate, \ | |
191 | .get_parent = rk_cru_arm_get_parent, \ | 191 | .get_parent = rk_cru_arm_get_parent, \ | |
192 | .set_parent = rk_cru_arm_set_parent, \ | 192 | .set_parent = rk_cru_arm_set_parent, \ | |
193 | } | 193 | } | |
194 | 194 | |||
195 | /* Composite clocks */ | 195 | /* Composite clocks */ | |
196 | 196 | |||
197 | struct rk_cru_composite { | 197 | struct rk_cru_composite { | |
198 | bus_size_t muxdiv_reg; | 198 | bus_size_t muxdiv_reg; | |
199 | uint32_t mux_mask; | 199 | uint32_t mux_mask; | |
200 | uint32_t div_mask; | 200 | uint32_t div_mask; | |
201 | bus_size_t gate_reg; | 201 | bus_size_t gate_reg; | |
202 | uint32_t gate_mask; | 202 | uint32_t gate_mask; | |
203 | bus_size_t frac_reg; | |||
203 | const char **parents; | 204 | const char **parents; | |
204 | u_int nparents; | 205 | u_int nparents; | |
205 | u_int flags; | 206 | u_int flags; | |
206 | #define RK_COMPOSITE_ROUND_DOWN 0x01 | 207 | #define RK_COMPOSITE_ROUND_DOWN 0x01 | |
207 | #define RK_COMPOSITE_SET_RATE_PARENT 0x02 | 208 | #define RK_COMPOSITE_SET_RATE_PARENT 0x02 | |
209 | #define RK_COMPOSITE_FRACDIV 0x04 | |||
208 | }; | 210 | }; | |
209 | 211 | |||
210 | int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int); | 212 | int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int); | |
211 | u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); | 213 | u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); | |
212 | int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); | 214 | int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); | |
213 | const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); | 215 | const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); | |
214 | int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); | 216 | int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); | |
215 | 217 | |||
216 | #define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \ | 218 | #define _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _frac_reg, _flags) \ | |
217 | { \ | 219 | { \ | |
218 | .id = (_id), \ | 220 | .id = (_id), \ | |
219 | .type = RK_CRU_COMPOSITE, \ | 221 | .type = RK_CRU_COMPOSITE, \ | |
220 | .base.name = (_name), \ | 222 | .base.name = (_name), \ | |
221 | .base.flags = 0, \ | 223 | .base.flags = 0, \ | |
222 | .u.composite.parents = (_parents), \ | 224 | .u.composite.parents = (_parents), \ | |
223 | .u.composite.nparents = __arraycount(_parents), \ | 225 | .u.composite.nparents = __arraycount(_parents), \ | |
224 | .u.composite.muxdiv_reg = (_muxdiv_reg), \ | 226 | .u.composite.muxdiv_reg = (_muxdiv_reg), \ | |
225 | .u.composite.mux_mask = (_mux_mask), \ | 227 | .u.composite.mux_mask = (_mux_mask), \ | |
226 | .u.composite.div_mask = (_div_mask), \ | 228 | .u.composite.div_mask = (_div_mask), \ | |
227 | .u.composite.gate_reg = (_gate_reg), \ | 229 | .u.composite.gate_reg = (_gate_reg), \ | |
228 | .u.composite.gate_mask = (_gate_mask), \ | 230 | .u.composite.gate_mask = (_gate_mask), \ | |
231 | .u.composite.frac_reg = (_frac_reg), \ | |||
229 | .u.composite.flags = (_flags), \ | 232 | .u.composite.flags = (_flags), \ | |
230 | .enable = rk_cru_composite_enable, \ | 233 | .enable = rk_cru_composite_enable, \ | |
231 | .get_rate = rk_cru_composite_get_rate, \ | 234 | .get_rate = rk_cru_composite_get_rate, \ | |
232 | .set_rate = rk_cru_composite_set_rate, \ | 235 | .set_rate = rk_cru_composite_set_rate, \ | |
233 | .get_parent = rk_cru_composite_get_parent, \ | 236 | .get_parent = rk_cru_composite_get_parent, \ | |
234 | .set_parent = rk_cru_composite_set_parent, \ | 237 | .set_parent = rk_cru_composite_set_parent, \ | |
235 | } | 238 | } | |
236 | 239 | |||
240 | #define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \ | |||
241 | _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, 0, _flags) | |||
242 | ||||
237 | #define RK_COMPOSITE_NOMUX(_id, _name, _parent, _div_reg, _div_mask, _gate_reg, _gate_mask, _flags) \ | 243 | #define RK_COMPOSITE_NOMUX(_id, _name, _parent, _div_reg, _div_mask, _gate_reg, _gate_mask, _flags) \ | |
238 | RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, _gate_reg, _gate_mask, _flags) | 244 | _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, _gate_reg, _gate_mask, 0, _flags) | |
239 | 245 | |||
240 | #define RK_COMPOSITE_NOGATE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _flags) \ | 246 | #define RK_COMPOSITE_NOGATE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _flags) \ | |
241 | RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, 0, 0, _flags) | 247 | _RK_COMPOSITE_INIT(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, 0, 0, 0, _flags) | |
248 | ||||
249 | #define RK_COMPOSITE_FRAC(_id, _name, _parent, _frac_reg, _flags) \ | |||
250 | _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, 0, 0, 0, 0, 0, _frac_reg, (_flags) | RK_COMPOSITE_FRACDIV) | |||
242 | 251 | |||
243 | #define RK_DIV(_id, _name, _parent, _div_reg, _div_mask, _flags) \ | 252 | #define RK_DIV(_id, _name, _parent, _div_reg, _div_mask, _flags) \ | |
244 | RK_COMPOSITE(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, 0, 0, _flags) | 253 | _RK_COMPOSITE_INIT(_id, _name, (const char *[]){ _parent }, _div_reg, 0, _div_mask, 0, 0, 0, _flags) | |
245 | 254 | |||
246 | /* Gate clocks */ | 255 | /* Gate clocks */ | |
247 | 256 | |||
248 | struct rk_cru_gate { | 257 | struct rk_cru_gate { | |
249 | bus_size_t reg; | 258 | bus_size_t reg; | |
250 | uint32_t mask; | 259 | uint32_t mask; | |
251 | const char *parent; | 260 | const char *parent; | |
252 | }; | 261 | }; | |
253 | 262 | |||
254 | int rk_cru_gate_enable(struct rk_cru_softc *, | 263 | int rk_cru_gate_enable(struct rk_cru_softc *, | |
255 | struct rk_cru_clk *, int); | 264 | struct rk_cru_clk *, int); | |
256 | const char *rk_cru_gate_get_parent(struct rk_cru_softc *, | 265 | const char *rk_cru_gate_get_parent(struct rk_cru_softc *, | |
257 | struct rk_cru_clk *); | 266 | struct rk_cru_clk *); |
--- src/sys/arch/arm/rockchip/rk_cru_composite.c 2019/11/10 11:43:04 1.4
+++ src/sys/arch/arm/rockchip/rk_cru_composite.c 2019/11/16 13:23:13 1.5
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: rk_cru_composite.c,v 1.4 2019/11/10 11:43:04 jmcneill Exp $ */ | 1 | /* $NetBSD: rk_cru_composite.c,v 1.5 2019/11/16 13:23:13 jmcneill Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -17,27 +17,27 @@ | @@ -17,27 +17,27 @@ | |||
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | __KERNEL_RCSID(0, "$NetBSD: rk_cru_composite.c,v 1.4 2019/11/10 11:43:04 jmcneill Exp $"); | 30 | __KERNEL_RCSID(0, "$NetBSD: rk_cru_composite.c,v 1.5 2019/11/16 13:23:13 jmcneill Exp $"); | |
31 | 31 | |||
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | #include <sys/bus.h> | 33 | #include <sys/bus.h> | |
34 | 34 | |||
35 | #include <dev/clk/clk_backend.h> | 35 | #include <dev/clk/clk_backend.h> | |
36 | 36 | |||
37 | #include <arm/rockchip/rk_cru.h> | 37 | #include <arm/rockchip/rk_cru.h> | |
38 | 38 | |||
39 | #include <dev/fdt/fdtvar.h> | 39 | #include <dev/fdt/fdtvar.h> | |
40 | 40 | |||
41 | int | 41 | int | |
42 | rk_cru_composite_enable(struct rk_cru_softc *sc, struct rk_cru_clk *clk, | 42 | rk_cru_composite_enable(struct rk_cru_softc *sc, struct rk_cru_clk *clk, | |
43 | int enable) | 43 | int enable) | |
@@ -65,50 +65,99 @@ rk_cru_composite_get_rate(struct rk_cru_ | @@ -65,50 +65,99 @@ rk_cru_composite_get_rate(struct rk_cru_ | |||
65 | struct clk *clkp, *clkp_parent; | 65 | struct clk *clkp, *clkp_parent; | |
66 | 66 | |||
67 | KASSERT(clk->type == RK_CRU_COMPOSITE); | 67 | KASSERT(clk->type == RK_CRU_COMPOSITE); | |
68 | 68 | |||
69 | clkp = &clk->base; | 69 | clkp = &clk->base; | |
70 | clkp_parent = clk_get_parent(clkp); | 70 | clkp_parent = clk_get_parent(clkp); | |
71 | if (clkp_parent == NULL) | 71 | if (clkp_parent == NULL) | |
72 | return 0; | 72 | return 0; | |
73 | 73 | |||
74 | const u_int prate = clk_get_rate(clkp_parent); | 74 | const u_int prate = clk_get_rate(clkp_parent); | |
75 | if (prate == 0) | 75 | if (prate == 0) | |
76 | return 0; | 76 | return 0; | |
77 | 77 | |||
78 | const uint32_t val = CRU_READ(sc, composite->muxdiv_reg); | 78 | if (composite->flags & RK_COMPOSITE_FRACDIV) { | |
79 | const u_int div = __SHIFTOUT(val, composite->div_mask) + 1; | 79 | const uint32_t val = CRU_READ(sc, composite->frac_reg); | |
80 | const u_int num = (val >> 16) & 0xffff; | |||
81 | const u_int den = val & 0xffff; | |||
80 | 82 | |||
81 | return prate / div; | 83 | return (u_int)((uint64_t)prate * num / den); | |
84 | } else { | |||
85 | const uint32_t val = CRU_READ(sc, composite->muxdiv_reg); | |||
86 | const u_int div = __SHIFTOUT(val, composite->div_mask) + 1; | |||
87 | ||||
88 | return prate / div; | |||
89 | } | |||
90 | } | |||
91 | ||||
92 | static u_int | |||
93 | rk_cru_composite_get_frac_div(u_int n, u_int d) | |||
94 | { | |||
95 | u_int tmp; | |||
96 | ||||
97 | while (d > 0) { | |||
98 | tmp = d; | |||
99 | d = n % d; | |||
100 | n = tmp; | |||
101 | } | |||
102 | ||||
103 | return n; | |||
104 | } | |||
105 | ||||
106 | static int | |||
107 | rk_cru_composite_set_rate_frac(struct rk_cru_softc *sc, | |||
108 | struct rk_cru_clk *clk, u_int rate) | |||
109 | { | |||
110 | struct rk_cru_composite *composite = &clk->u.composite; | |||
111 | struct clk *clk_parent; | |||
112 | ||||
113 | clk_parent = clk_get_parent(&clk->base); | |||
114 | if (clk_parent == NULL) | |||
115 | return ENXIO; | |||
116 | ||||
117 | const u_int prate = clk_get_rate(clk_parent); | |||
118 | const u_int v = rk_cru_composite_get_frac_div(prate, rate); | |||
119 | const u_int num = (prate / v) & 0xffff; | |||
120 | const u_int den = (rate / v) & 0xffff; | |||
121 | if (prate / num * den != rate) | |||
122 | return EINVAL; | |||
123 | ||||
124 | CRU_WRITE(sc, composite->frac_reg, (den << 16) | num); | |||
125 | ||||
126 | return 0; | |||
82 | } | 127 | } | |
83 | 128 | |||
84 | int | 129 | int | |
85 | rk_cru_composite_set_rate(struct rk_cru_softc *sc, | 130 | rk_cru_composite_set_rate(struct rk_cru_softc *sc, | |
86 | struct rk_cru_clk *clk, u_int rate) | 131 | struct rk_cru_clk *clk, u_int rate) | |
87 | { | 132 | { | |
88 | struct rk_cru_composite *composite = &clk->u.composite; | 133 | struct rk_cru_composite *composite = &clk->u.composite; | |
89 | u_int best_div, best_mux, best_diff; | 134 | u_int best_div, best_mux, best_diff; | |
90 | struct rk_cru_clk *rclk_parent; | 135 | struct rk_cru_clk *rclk_parent; | |
91 | struct clk *clk_parent; | 136 | struct clk *clk_parent; | |
92 | 137 | |||
93 | KASSERT(clk->type == RK_CRU_COMPOSITE); | 138 | KASSERT(clk->type == RK_CRU_COMPOSITE); | |
94 | 139 | |||
95 | if (composite->flags & RK_COMPOSITE_SET_RATE_PARENT) { | 140 | if (composite->flags & RK_COMPOSITE_SET_RATE_PARENT) { | |
96 | clk_parent = clk_get_parent(&clk->base); | 141 | clk_parent = clk_get_parent(&clk->base); | |
97 | if (clk_parent == NULL) | 142 | if (clk_parent == NULL) | |
98 | return ENXIO; | 143 | return ENXIO; | |
99 | return clk_set_rate(clk_parent, rate); | 144 | return clk_set_rate(clk_parent, rate); | |
100 | } | 145 | } | |
101 | 146 | |||
147 | if (composite->flags & RK_COMPOSITE_FRACDIV) { | |||
148 | return rk_cru_composite_set_rate_frac(sc, clk, rate); | |||
149 | } | |||
150 | ||||
102 | best_div = 0; | 151 | best_div = 0; | |
103 | best_mux = 0; | 152 | best_mux = 0; | |
104 | best_diff = INT_MAX; | 153 | best_diff = INT_MAX; | |
105 | for (u_int mux = 0; mux < composite->nparents; mux++) { | 154 | for (u_int mux = 0; mux < composite->nparents; mux++) { | |
106 | rclk_parent = rk_cru_clock_find(sc, composite->parents[mux]); | 155 | rclk_parent = rk_cru_clock_find(sc, composite->parents[mux]); | |
107 | if (rclk_parent != NULL) | 156 | if (rclk_parent != NULL) | |
108 | clk_parent = &rclk_parent->base; | 157 | clk_parent = &rclk_parent->base; | |
109 | else | 158 | else | |
110 | clk_parent = fdtbus_clock_byname(composite->parents[mux]); | 159 | clk_parent = fdtbus_clock_byname(composite->parents[mux]); | |
111 | if (clk_parent == NULL) | 160 | if (clk_parent == NULL) | |
112 | continue; | 161 | continue; | |
113 | 162 | |||
114 | const u_int prate = clk_get_rate(clk_parent); | 163 | const u_int prate = clk_get_rate(clk_parent); |