Sat Nov 16 13:23:13 2019 UTC ()
Add support for I2S clocks.


(jmcneill)
diff -r1.12 -r1.13 src/sys/arch/arm/rockchip/rk3399_cru.c
diff -r1.6 -r1.7 src/sys/arch/arm/rockchip/rk_cru.h
diff -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_cru_composite.c

cvs diff -r1.12 -r1.13 src/sys/arch/arm/rockchip/rk3399_cru.c (expand / switch to unified diff)

--- 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
351static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" }; 351static const char * mux_pll_src_cpll_gpll_npll_parents[] = { "cpll", "gpll", "npll" };
352static const char * mux_pll_src_cpll_gpll_ppll_parents[] = { "cpll", "gpll", "npll" }; 352static const char * mux_pll_src_cpll_gpll_ppll_parents[] = { "cpll", "gpll", "npll" };
353static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" }; 353static const char * mux_pll_src_cpll_gpll_upll_parents[] = { "cpll", "gpll", "upll" };
354static const char * mux_pll_src_cpll_gpll_npll_24m_parents[] = { "cpll", "gpll", "npll", "xin24m" }; 354static const char * mux_pll_src_cpll_gpll_npll_24m_parents[] = { "cpll", "gpll", "npll", "xin24m" };
355static const char * mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents[] = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" }; 355static const char * mux_pll_src_cpll_gpll_npll_ppll_upll_24m_parents[] = { "cpll", "gpll", "npll", "ppll", "upll", "xin24m" };
356static const char * mux_pll_src_vpll_cpll_gpll_parents[] = { "vpll", "cpll", "gpll" }; 356static const char * mux_pll_src_vpll_cpll_gpll_parents[] = { "vpll", "cpll", "gpll" };
357static const char * mux_pll_src_vpll_cpll_gpll_npll_parents[] = { "vpll", "cpll", "gpll", "npll" }; 357static const char * mux_pll_src_vpll_cpll_gpll_npll_parents[] = { "vpll", "cpll", "gpll", "npll" };
358static const char * mux_aclk_perilp0_parents[] = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" }; 358static const char * mux_aclk_perilp0_parents[] = { "cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src" };
359static const char * mux_hclk_perilp1_parents[] = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" }; 359static const char * mux_hclk_perilp1_parents[] = { "cpll_hclk_perilp1_src", "gpll_hclk_perilp1_src" };
360static const char * mux_aclk_perihp_parents[] = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" }; 360static const char * mux_aclk_perihp_parents[] = { "cpll_aclk_perihp_src", "gpll_aclk_perihp_src" };
361static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" }; 361static const char * mux_aclk_cci_parents[] = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", "vpll_aclk_cci_src" };
362static const char * mux_dclk_vop0_parents[] = { "dclk_vop0_div", "dclk_vop0_frac" }; 362static const char * mux_dclk_vop0_parents[] = { "dclk_vop0_div", "dclk_vop0_frac" };
363static const char * mux_dclk_vop1_parents[] = { "dclk_vop1_div", "dclk_vop1_frac" }; 363static const char * mux_dclk_vop1_parents[] = { "dclk_vop1_div", "dclk_vop1_frac" };
 364static const char * mux_i2s0_parents[] = { "clk_i2s0_div", "clk_i2s0_frac", "clkin_i2s", "xin12m" };
 365static const char * mux_i2s1_parents[] = { "clk_i2s1_div", "clk_i2s1_frac", "clkin_i2s", "xin12m" };
 366static const char * mux_i2s2_parents[] = { "clk_i2s2_div", "clk_i2s2_frac", "clkin_i2s", "xin12m" };
 367static const char * mux_i2sch_parents[] = { "clk_i2s0", "clk_i2s1", "clk_i2s2" };
 368static const char * mux_i2sout_parents[] = { "clk_i2sout_src", "xin12m" };
364static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; 369static const char * mux_uart0_parents[] = { "clk_uart0_div", "clk_uart0_frac", "xin24m" };
365static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; 370static const char * mux_uart1_parents[] = { "clk_uart1_div", "clk_uart1_frac", "xin24m" };
366static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; 371static const char * mux_uart2_parents[] = { "clk_uart2_div", "clk_uart2_frac", "xin24m" };
367static const char * mux_uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; 372static const char * mux_uart3_parents[] = { "clk_uart3_div", "clk_uart3_frac", "xin24m" };
368static const char * mux_rmii_parents[] = { "clk_gmac", "clkin_gmac" }; 373static const char * mux_rmii_parents[] = { "clk_gmac", "clkin_gmac" };
369static const char * mux_aclk_gmac_parents[] = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" }; 374static const char * mux_aclk_gmac_parents[] = { "cpll_aclk_gmac_src", "gpll_aclk_gmac_src" };
370static const char * mux_aclk_emmc_parents[] = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" }; 375static const char * mux_aclk_emmc_parents[] = { "cpll_aclk_emmc_src", "gpll_aclk_emmc_src" };
371static const char * mux_pll_src_24m_pciephy_parents[] = { "xin24m", "clk_pciephy_ref100m" }; 376static const char * mux_pll_src_24m_pciephy_parents[] = { "xin24m", "clk_pciephy_ref100m" };
372static const char * mux_pciecore_cru_phy_parents[] = { "clk_pcie_core_cru", "clk_pcie_core_phy" }; 377static const char * mux_pciecore_cru_phy_parents[] = { "clk_pcie_core_cru", "clk_pcie_core_phy" };
373 378
374static struct rk_cru_clk rk3399_cru_clks[] = { 379static 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
 998static 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
944static void 1007static void
945rk3399_cru_init(struct rk_cru_softc *sc) 1008rk3399_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
965static int 1049static int
966rk3399_cru_match(device_t parent, cfdata_t cf, void *aux) 1050rk3399_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
973static void 1057static void
974rk3399_cru_attach(device_t parent, device_t self, void *aux) 1058rk3399_cru_attach(device_t parent, device_t self, void *aux)
975{ 1059{

cvs diff -r1.6 -r1.7 src/sys/arch/arm/rockchip/rk_cru.h (expand / switch to unified diff)

--- 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
197struct rk_cru_composite { 197struct 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
210int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int); 212int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int);
211u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); 213u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *);
212int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); 214int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int);
213const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); 215const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *);
214int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); 216int 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
248struct rk_cru_gate { 257struct 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
254int rk_cru_gate_enable(struct rk_cru_softc *, 263int rk_cru_gate_enable(struct rk_cru_softc *,
255 struct rk_cru_clk *, int); 264 struct rk_cru_clk *, int);
256const char *rk_cru_gate_get_parent(struct rk_cru_softc *, 265const char *rk_cru_gate_get_parent(struct rk_cru_softc *,
257 struct rk_cru_clk *); 266 struct rk_cru_clk *);

cvs diff -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_cru_composite.c (expand / switch to unified diff)

--- 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
41int 41int
42rk_cru_composite_enable(struct rk_cru_softc *sc, struct rk_cru_clk *clk, 42rk_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
 92static u_int
 93rk_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
 106static int
 107rk_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
84int 129int
85rk_cru_composite_set_rate(struct rk_cru_softc *sc, 130rk_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);