2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
5 * Copyright (c) 2018 Greg V <greg@unrelenting.technology>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <machine/bus.h>
42 #include <dev/fdt/simplebus.h>
44 #include <dev/ofw/ofw_bus.h>
45 #include <dev/ofw/ofw_bus_subr.h>
47 #include <dev/extres/clk/clk_div.h>
48 #include <dev/extres/clk/clk_fixed.h>
49 #include <dev/extres/clk/clk_mux.h>
51 #include <arm64/rockchip/clk/rk_cru.h>
55 #define ACLK_EMMC_CORE 241
56 #define ACLK_EMMC_NOC 242
57 #define ACLK_EMMC_GRF 243
58 #define PCLK_GPIO2 336
59 #define PCLK_GPIO3 337
60 #define PCLK_GPIO4 338
67 #define HCLK_SDMMC 462
69 static struct rk_cru_gate rk3399_gates[] = {
70 /* CRU_CLKGATE_CON0 */
71 CRU_GATE(0, "clk_core_l_lpll_src", "lpll", 0x300, 0)
72 CRU_GATE(0, "clk_core_l_bpll_src", "bpll", 0x300, 1)
73 CRU_GATE(0, "clk_core_l_dpll_src", "dpll", 0x300, 2)
74 CRU_GATE(0, "clk_core_l_gpll_src", "gpll", 0x300, 3)
76 /* CRU_CLKGATE_CON1 */
77 CRU_GATE(0, "clk_core_b_lpll_src", "lpll", 0x304, 0)
78 CRU_GATE(0, "clk_core_b_bpll_src", "bpll", 0x304, 1)
79 CRU_GATE(0, "clk_core_b_dpll_src", "dpll", 0x304, 2)
80 CRU_GATE(0, "clk_core_b_gpll_src", "gpll", 0x304, 3)
82 /* CRU_CLKGATE_CON5 */
83 CRU_GATE(0, "cpll_aclk_perihp_src", "cpll", 0x314, 0)
84 CRU_GATE(0, "gpll_aclk_perihp_src", "gpll", 0x314, 1)
86 /* CRU_CLKGATE_CON6 */
87 CRU_GATE(0, "gpll_aclk_emmc_src", "gpll", 0x318, 12)
88 CRU_GATE(0, "cpll_aclk_emmc_src", "cpll", 0x318, 13)
90 /* CRU_CLKGATE_CON7 */
91 CRU_GATE(0, "gpll_aclk_perilp0_src", "gpll", 0x31C, 0)
92 CRU_GATE(0, "cpll_aclk_perilp0_src", "cpll", 0x31C, 1)
94 /* CRU_CLKGATE_CON8 */
95 CRU_GATE(0, "hclk_perilp1_cpll_src", "cpll", 0x320, 1)
96 CRU_GATE(0, "hclk_perilp1_gpll_src", "gpll", 0x320, 0)
98 /* CRU_CLKGATE_CON22 */
99 CRU_GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0x358, 5)
100 CRU_GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0x358, 6)
101 CRU_GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0x358, 7)
102 CRU_GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0x358, 8)
103 CRU_GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0x358, 9)
104 CRU_GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0x358, 10)
106 /* CRU_CLKGATE_CON31 */
107 CRU_GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0x37c, 3)
108 CRU_GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0x37c, 4)
109 CRU_GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0x37c, 5)
111 /* CRU_CLKGATE_CON32 */
112 CRU_GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", 0x380, 8)
113 CRU_GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", 0x380, 9)
114 CRU_GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", 0x380, 10)
116 /* CRU_CLKGATE_CON33 */
117 CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0x384, 8)
133 static struct rk_clk_pll_rate rk3399_pll_rates[] = {
753 static const char *pll_parents[] = {"xin24m"};
755 static struct rk_clk_pll_def lpll = {
759 .parent_names = pll_parents,
760 .parent_cnt = nitems(pll_parents),
763 .gate_offset = 0x300,
765 .flags = RK_CLK_PLL_HAVE_GATE,
766 .rates = rk3399_pll_rates,
770 static struct rk_clk_pll_def bpll = {
774 .parent_names = pll_parents,
775 .parent_cnt = nitems(pll_parents),
778 .gate_offset = 0x300,
780 .flags = RK_CLK_PLL_HAVE_GATE,
781 .rates = rk3399_pll_rates,
785 static struct rk_clk_pll_def dpll = {
789 .parent_names = pll_parents,
790 .parent_cnt = nitems(pll_parents),
793 .gate_offset = 0x300,
795 .flags = RK_CLK_PLL_HAVE_GATE,
796 .rates = rk3399_pll_rates,
800 static struct rk_clk_pll_def cpll = {
804 .parent_names = pll_parents,
805 .parent_cnt = nitems(pll_parents),
808 .rates = rk3399_pll_rates,
811 static struct rk_clk_pll_def gpll = {
815 .parent_names = pll_parents,
816 .parent_cnt = nitems(pll_parents),
819 .gate_offset = 0x300,
821 .flags = RK_CLK_PLL_HAVE_GATE,
822 .rates = rk3399_pll_rates,
825 static struct rk_clk_pll_def npll = {
829 .parent_names = pll_parents,
830 .parent_cnt = nitems(pll_parents),
833 .rates = rk3399_pll_rates,
836 static struct rk_clk_pll_def vpll = {
840 .parent_names = pll_parents,
841 .parent_cnt = nitems(pll_parents),
844 .rates = rk3399_pll_rates,
847 #define ACLK_PERIHP 192
848 #define HCLK_PERIHP 448
849 #define PCLK_PERIHP 320
851 static const char *aclk_perihp_parents[] = {"cpll_aclk_perihp_src", "gpll_aclk_perihp_src"};
853 static struct rk_clk_composite_def aclk_perihp = {
856 .name = "aclk_perihp",
857 .parent_names = aclk_perihp_parents,
858 .parent_cnt = nitems(aclk_perihp_parents),
860 /* CRU_CLKSEL_CON14 */
861 .muxdiv_offset = 0x138,
869 /* CRU_CLKGATE_CON5 */
870 .gate_offset = 0x314,
873 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
876 static const char *hclk_pclk_perihp_parents[] = {"aclk_perihp"};
878 static struct rk_clk_composite_def hclk_perihp = {
881 .name = "hclk_perihp",
882 .parent_names = hclk_pclk_perihp_parents,
883 .parent_cnt = nitems(hclk_pclk_perihp_parents),
885 /* CRU_CLKSEL_CON14 */
886 .muxdiv_offset = 0x138,
891 /* CRU_CLKGATE_CON5 */
892 .gate_offset = 0x314,
895 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
898 static struct rk_clk_composite_def pclk_perihp = {
901 .name = "pclk_perihp",
902 .parent_names = hclk_pclk_perihp_parents,
903 .parent_cnt = nitems(hclk_pclk_perihp_parents),
905 /* CRU_CLKSEL_CON14 */
906 .muxdiv_offset = 0x138,
911 /* CRU_CLKGATE_CON5 */
912 .gate_offset = 0x314,
915 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
918 #define ACLK_PERILP0 194
919 #define HCLK_PERILP0 449
920 #define PCLK_PERILP0 322
922 static const char *aclk_perilp0_parents[] = {"cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src"};
924 static struct rk_clk_composite_def aclk_perilp0 = {
927 .name = "aclk_perilp0",
928 .parent_names = aclk_perilp0_parents,
929 .parent_cnt = nitems(aclk_perilp0_parents),
931 /* CRU_CLKSEL_CON14 */
932 .muxdiv_offset = 0x15C,
940 /* CRU_CLKGATE_CON7 */
941 .gate_offset = 0x31C,
944 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
947 static const char *hclk_pclk_perilp0_parents[] = {"aclk_perilp0"};
949 static struct rk_clk_composite_def hclk_perilp0 = {
952 .name = "hclk_perilp0",
953 .parent_names = hclk_pclk_perilp0_parents,
954 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
956 /* CRU_CLKSEL_CON23 */
957 .muxdiv_offset = 0x15C,
962 /* CRU_CLKGATE_CON7 */
963 .gate_offset = 0x31C,
966 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
969 static struct rk_clk_composite_def pclk_perilp0 = {
972 .name = "pclk_perilp0",
973 .parent_names = hclk_pclk_perilp0_parents,
974 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
976 /* CRU_CLKSEL_CON23 */
977 .muxdiv_offset = 0x15C,
982 /* CRU_CLKGATE_CON7 */
983 .gate_offset = 0x31C,
986 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
992 #define PCLK_ALIVE 390
994 static const char *alive_parents[] = {"gpll"};
996 static struct rk_clk_composite_def pclk_alive = {
999 .name = "pclk_alive",
1000 .parent_names = alive_parents,
1001 .parent_cnt = nitems(alive_parents),
1003 /* CRU_CLKSEL_CON57 */
1004 .muxdiv_offset = 0x01e4,
1010 #define HCLK_PERILP1 450
1011 #define PCLK_PERILP1 323
1013 static const char *hclk_perilp1_parents[] = {"cpll", "gpll"};
1015 static struct rk_clk_composite_def hclk_perilp1 = {
1018 .name = "hclk_perilp1",
1019 .parent_names = hclk_perilp1_parents,
1020 .parent_cnt = nitems(hclk_perilp1_parents),
1022 /* CRU_CLKSEL_CON25 */
1023 .muxdiv_offset = 0x164,
1030 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1033 static const char *pclk_perilp1_parents[] = {"hclk_perilp1"};
1035 static struct rk_clk_composite_def pclk_perilp1 = {
1038 .name = "pclk_perilp1",
1039 .parent_names = pclk_perilp1_parents,
1040 .parent_cnt = nitems(pclk_perilp1_parents),
1042 /* CRU_CLKSEL_CON25 */
1043 .muxdiv_offset = 0x164,
1048 /* CRU_CLKGATE_CON8 */
1049 .gate_offset = 0x320,
1052 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
1058 static const char *i2c_parents[] = {"cpll", "gpll"};
1060 #define SCLK_I2C1 65
1061 #define SCLK_I2C2 66
1062 #define SCLK_I2C3 67
1063 #define SCLK_I2C5 68
1064 #define SCLK_I2C6 69
1065 #define SCLK_I2C7 70
1067 static struct rk_clk_composite_def i2c1 = {
1071 .parent_names = i2c_parents,
1072 .parent_cnt = nitems(i2c_parents),
1074 /* CRU_CLKSEL_CON61 */
1075 .muxdiv_offset = 0x01f4,
1082 /* CRU_CLKGATE_CON10 */
1083 .gate_offset = 0x0328,
1086 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1089 static struct rk_clk_composite_def i2c2 = {
1093 .parent_names = i2c_parents,
1094 .parent_cnt = nitems(i2c_parents),
1096 /* CRU_CLKSEL_CON62 */
1097 .muxdiv_offset = 0x01f8,
1104 /* CRU_CLKGATE_CON10 */
1105 .gate_offset = 0x0328,
1108 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1111 static struct rk_clk_composite_def i2c3 = {
1115 .parent_names = i2c_parents,
1116 .parent_cnt = nitems(i2c_parents),
1118 /* CRU_CLKSEL_CON63 */
1119 .muxdiv_offset = 0x01fc,
1126 /* CRU_CLKGATE_CON10 */
1127 .gate_offset = 0x0328,
1130 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1133 static struct rk_clk_composite_def i2c5 = {
1137 .parent_names = i2c_parents,
1138 .parent_cnt = nitems(i2c_parents),
1140 /* CRU_CLKSEL_CON61 */
1141 .muxdiv_offset = 0x01f4,
1148 /* CRU_CLKGATE_CON10 */
1149 .gate_offset = 0x0328,
1152 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1155 static struct rk_clk_composite_def i2c6 = {
1159 .parent_names = i2c_parents,
1160 .parent_cnt = nitems(i2c_parents),
1162 /* CRU_CLKSEL_CON62 */
1163 .muxdiv_offset = 0x01f8,
1170 /* CRU_CLKGATE_CON10 */
1171 .gate_offset = 0x0328,
1174 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1177 static struct rk_clk_composite_def i2c7 = {
1181 .parent_names = i2c_parents,
1182 .parent_cnt = nitems(i2c_parents),
1184 /* CRU_CLKSEL_CON63 */
1185 .muxdiv_offset = 0x01fc,
1192 /* CRU_CLKGATE_CON10 */
1193 .gate_offset = 0x0328,
1196 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1200 * ARM CPU clocks (LITTLE and big)
1205 static const char *armclk_parents[] = {"lpll", "bpll", "dpll", "gpll"};
1207 static struct rk_clk_armclk_rates rk3399_armclkl_rates[] = {
1270 static struct rk_clk_armclk_def armclk_l = {
1274 .parent_names = armclk_parents,
1275 .parent_cnt = nitems(armclk_parents),
1277 /* CRU_CLKSEL_CON0 */
1278 .muxdiv_offset = 0x100,
1285 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1289 .rates = rk3399_armclkl_rates,
1290 .nrates = nitems(rk3399_armclkl_rates),
1293 static struct rk_clk_armclk_rates rk3399_armclkb_rates[] = {
1384 static struct rk_clk_armclk_def armclk_b = {
1388 .parent_names = armclk_parents,
1389 .parent_cnt = nitems(armclk_parents),
1391 .muxdiv_offset = 0x108,
1398 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1402 .rates = rk3399_armclkb_rates,
1403 .nrates = nitems(rk3399_armclkb_rates),
1412 static const char *hclk_sd_parents[] = {"cpll", "gpll"};
1414 static struct rk_clk_composite_def hclk_sd = {
1418 .parent_names = hclk_sd_parents,
1419 .parent_cnt = nitems(hclk_sd_parents),
1422 .muxdiv_offset = 0x134,
1429 .gate_offset = 0x330,
1432 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1435 #define SCLK_SDMMC 76
1437 static const char *sclk_sdmmc_parents[] = {"cpll", "gpll", "npll", "ppll"};
1439 static struct rk_clk_composite_def sclk_sdmmc = {
1442 .name = "sclk_sdmmc",
1443 .parent_names = sclk_sdmmc_parents,
1444 .parent_cnt = nitems(sclk_sdmmc_parents),
1447 .muxdiv_offset = 0x140,
1454 .gate_offset = 0x318,
1457 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1464 #define SCLK_EMMC 78
1466 static const char *sclk_emmc_parents[] = {"cpll", "gpll", "npll"};
1468 static struct rk_clk_composite_def sclk_emmc = {
1471 .name = "sclk_emmc",
1472 .parent_names = sclk_emmc_parents,
1473 .parent_cnt = nitems(sclk_emmc_parents),
1476 .muxdiv_offset = 0x158,
1483 .gate_offset = 0x318,
1486 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1489 #define ACLK_EMMC 240
1491 static const char *aclk_emmc_parents[] = {
1492 "cpll_aclk_emmc_src",
1493 "gpll_aclk_emmc_src"
1496 static struct rk_clk_composite_def aclk_emmc = {
1499 .name = "aclk_emmc",
1500 .parent_names = aclk_emmc_parents,
1501 .parent_cnt = nitems(aclk_emmc_parents),
1504 .muxdiv_offset = 0x154,
1511 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1514 static struct rk_clk rk3399_clks[] = {
1516 .type = RK3399_CLK_PLL,
1520 .type = RK3399_CLK_PLL,
1524 .type = RK3399_CLK_PLL,
1528 .type = RK3399_CLK_PLL,
1532 .type = RK3399_CLK_PLL,
1536 .type = RK3399_CLK_PLL,
1540 .type = RK3399_CLK_PLL,
1545 .type = RK_CLK_COMPOSITE,
1546 .clk.composite = &aclk_perihp,
1549 .type = RK_CLK_COMPOSITE,
1550 .clk.composite = &hclk_perihp,
1553 .type = RK_CLK_COMPOSITE,
1554 .clk.composite = &pclk_perihp,
1557 .type = RK_CLK_COMPOSITE,
1558 .clk.composite = &aclk_perilp0,
1561 .type = RK_CLK_COMPOSITE,
1562 .clk.composite = &hclk_perilp0,
1565 .type = RK_CLK_COMPOSITE,
1566 .clk.composite = &pclk_perilp0,
1569 .type = RK_CLK_COMPOSITE,
1570 .clk.composite = &pclk_alive,
1573 .type = RK_CLK_COMPOSITE,
1574 .clk.composite = &hclk_perilp1,
1577 .type = RK_CLK_COMPOSITE,
1578 .clk.composite = &pclk_perilp1,
1581 .type = RK_CLK_COMPOSITE,
1582 .clk.composite = &i2c1,
1585 .type = RK_CLK_COMPOSITE,
1586 .clk.composite = &i2c2,
1589 .type = RK_CLK_COMPOSITE,
1590 .clk.composite = &i2c3,
1593 .type = RK_CLK_COMPOSITE,
1594 .clk.composite = &i2c5,
1597 .type = RK_CLK_COMPOSITE,
1598 .clk.composite = &i2c6,
1601 .type = RK_CLK_COMPOSITE,
1602 .clk.composite = &i2c7,
1606 .type = RK_CLK_ARMCLK,
1607 .clk.armclk = &armclk_l,
1610 .type = RK_CLK_ARMCLK,
1611 .clk.armclk = &armclk_b,
1615 .type = RK_CLK_COMPOSITE,
1616 .clk.composite = &hclk_sd,
1619 .type = RK_CLK_COMPOSITE,
1620 .clk.composite = &sclk_sdmmc,
1624 .type = RK_CLK_COMPOSITE,
1625 .clk.composite = &sclk_emmc,
1628 .type = RK_CLK_COMPOSITE,
1629 .clk.composite = &aclk_emmc,
1634 rk3399_cru_probe(device_t dev)
1637 if (!ofw_bus_status_okay(dev))
1640 if (ofw_bus_is_compatible(dev, "rockchip,rk3399-cru")) {
1641 device_set_desc(dev, "Rockchip RK3399 Clock and Reset Unit");
1642 return (BUS_PROBE_DEFAULT);
1649 rk3399_cru_attach(device_t dev)
1651 struct rk_cru_softc *sc;
1653 sc = device_get_softc(dev);
1656 sc->gates = rk3399_gates;
1657 sc->ngates = nitems(rk3399_gates);
1659 sc->clks = rk3399_clks;
1660 sc->nclks = nitems(rk3399_clks);
1662 return (rk_cru_attach(dev));
1665 static device_method_t rk3399_cru_methods[] = {
1666 /* Device interface */
1667 DEVMETHOD(device_probe, rk3399_cru_probe),
1668 DEVMETHOD(device_attach, rk3399_cru_attach),
1673 static devclass_t rk3399_cru_devclass;
1675 DEFINE_CLASS_1(rk3399_cru, rk3399_cru_driver, rk3399_cru_methods,
1676 sizeof(struct rk_cru_softc), rk_cru_driver);
1678 EARLY_DRIVER_MODULE(rk3399_cru, simplebus, rk3399_cru_driver,
1679 rk3399_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);