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,
769 static struct rk_clk_pll_def bpll = {
773 .parent_names = pll_parents,
774 .parent_cnt = nitems(pll_parents),
777 .gate_offset = 0x300,
779 .flags = RK_CLK_PLL_HAVE_GATE,
780 .rates = rk3399_pll_rates,
783 static struct rk_clk_pll_def dpll = {
787 .parent_names = pll_parents,
788 .parent_cnt = nitems(pll_parents),
791 .gate_offset = 0x300,
793 .flags = RK_CLK_PLL_HAVE_GATE,
794 .rates = rk3399_pll_rates,
798 static struct rk_clk_pll_def cpll = {
802 .parent_names = pll_parents,
803 .parent_cnt = nitems(pll_parents),
806 .rates = rk3399_pll_rates,
809 static struct rk_clk_pll_def gpll = {
813 .parent_names = pll_parents,
814 .parent_cnt = nitems(pll_parents),
817 .gate_offset = 0x300,
819 .flags = RK_CLK_PLL_HAVE_GATE,
820 .rates = rk3399_pll_rates,
823 static struct rk_clk_pll_def npll = {
827 .parent_names = pll_parents,
828 .parent_cnt = nitems(pll_parents),
831 .rates = rk3399_pll_rates,
834 static struct rk_clk_pll_def vpll = {
838 .parent_names = pll_parents,
839 .parent_cnt = nitems(pll_parents),
842 .rates = rk3399_pll_rates,
845 #define ACLK_PERIHP 192
846 #define HCLK_PERIHP 448
847 #define PCLK_PERIHP 320
849 static const char *aclk_perihp_parents[] = {"cpll_aclk_perihp_src", "gpll_aclk_perihp_src"};
851 static struct rk_clk_composite_def aclk_perihp = {
854 .name = "aclk_perihp",
855 .parent_names = aclk_perihp_parents,
856 .parent_cnt = nitems(aclk_perihp_parents),
858 /* CRU_CLKSEL_CON14 */
859 .muxdiv_offset = 0x138,
867 /* CRU_CLKGATE_CON5 */
868 .gate_offset = 0x314,
871 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
874 static const char *hclk_pclk_perihp_parents[] = {"aclk_perihp"};
876 static struct rk_clk_composite_def hclk_perihp = {
879 .name = "hclk_perihp",
880 .parent_names = hclk_pclk_perihp_parents,
881 .parent_cnt = nitems(hclk_pclk_perihp_parents),
883 /* CRU_CLKSEL_CON14 */
884 .muxdiv_offset = 0x138,
889 /* CRU_CLKGATE_CON5 */
890 .gate_offset = 0x314,
893 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
896 static struct rk_clk_composite_def pclk_perihp = {
899 .name = "pclk_perihp",
900 .parent_names = hclk_pclk_perihp_parents,
901 .parent_cnt = nitems(hclk_pclk_perihp_parents),
903 /* CRU_CLKSEL_CON14 */
904 .muxdiv_offset = 0x138,
909 /* CRU_CLKGATE_CON5 */
910 .gate_offset = 0x314,
913 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
916 #define ACLK_PERILP0 194
917 #define HCLK_PERILP0 449
918 #define PCLK_PERILP0 322
920 static const char *aclk_perilp0_parents[] = {"cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src"};
922 static struct rk_clk_composite_def aclk_perilp0 = {
925 .name = "aclk_perilp0",
926 .parent_names = aclk_perilp0_parents,
927 .parent_cnt = nitems(aclk_perilp0_parents),
929 /* CRU_CLKSEL_CON14 */
930 .muxdiv_offset = 0x15C,
938 /* CRU_CLKGATE_CON7 */
939 .gate_offset = 0x31C,
942 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
945 static const char *hclk_pclk_perilp0_parents[] = {"aclk_perilp0"};
947 static struct rk_clk_composite_def hclk_perilp0 = {
950 .name = "hclk_perilp0",
951 .parent_names = hclk_pclk_perilp0_parents,
952 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
954 /* CRU_CLKSEL_CON23 */
955 .muxdiv_offset = 0x15C,
960 /* CRU_CLKGATE_CON7 */
961 .gate_offset = 0x31C,
964 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
967 static struct rk_clk_composite_def pclk_perilp0 = {
970 .name = "pclk_perilp0",
971 .parent_names = hclk_pclk_perilp0_parents,
972 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
974 /* CRU_CLKSEL_CON23 */
975 .muxdiv_offset = 0x15C,
980 /* CRU_CLKGATE_CON7 */
981 .gate_offset = 0x31C,
984 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
990 #define PCLK_ALIVE 390
992 static const char *alive_parents[] = {"gpll"};
994 static struct rk_clk_composite_def pclk_alive = {
997 .name = "pclk_alive",
998 .parent_names = alive_parents,
999 .parent_cnt = nitems(alive_parents),
1001 /* CRU_CLKSEL_CON57 */
1002 .muxdiv_offset = 0x01e4,
1008 #define HCLK_PERILP1 450
1009 #define PCLK_PERILP1 323
1011 static const char *hclk_perilp1_parents[] = {"cpll", "gpll"};
1013 static struct rk_clk_composite_def hclk_perilp1 = {
1016 .name = "hclk_perilp1",
1017 .parent_names = hclk_perilp1_parents,
1018 .parent_cnt = nitems(hclk_perilp1_parents),
1020 /* CRU_CLKSEL_CON25 */
1021 .muxdiv_offset = 0x164,
1028 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1031 static const char *pclk_perilp1_parents[] = {"hclk_perilp1"};
1033 static struct rk_clk_composite_def pclk_perilp1 = {
1036 .name = "pclk_perilp1",
1037 .parent_names = pclk_perilp1_parents,
1038 .parent_cnt = nitems(pclk_perilp1_parents),
1040 /* CRU_CLKSEL_CON25 */
1041 .muxdiv_offset = 0x164,
1046 /* CRU_CLKGATE_CON8 */
1047 .gate_offset = 0x320,
1050 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
1056 static const char *i2c_parents[] = {"cpll", "gpll"};
1058 #define SCLK_I2C1 65
1059 #define SCLK_I2C2 66
1060 #define SCLK_I2C3 67
1061 #define SCLK_I2C5 68
1062 #define SCLK_I2C6 69
1063 #define SCLK_I2C7 70
1065 static struct rk_clk_composite_def i2c1 = {
1069 .parent_names = i2c_parents,
1070 .parent_cnt = nitems(i2c_parents),
1072 /* CRU_CLKSEL_CON61 */
1073 .muxdiv_offset = 0x01f4,
1080 /* CRU_CLKGATE_CON10 */
1081 .gate_offset = 0x0328,
1084 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1087 static struct rk_clk_composite_def i2c2 = {
1091 .parent_names = i2c_parents,
1092 .parent_cnt = nitems(i2c_parents),
1094 /* CRU_CLKSEL_CON62 */
1095 .muxdiv_offset = 0x01f8,
1102 /* CRU_CLKGATE_CON10 */
1103 .gate_offset = 0x0328,
1106 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1109 static struct rk_clk_composite_def i2c3 = {
1113 .parent_names = i2c_parents,
1114 .parent_cnt = nitems(i2c_parents),
1116 /* CRU_CLKSEL_CON63 */
1117 .muxdiv_offset = 0x01fc,
1124 /* CRU_CLKGATE_CON10 */
1125 .gate_offset = 0x0328,
1128 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1131 static struct rk_clk_composite_def i2c5 = {
1135 .parent_names = i2c_parents,
1136 .parent_cnt = nitems(i2c_parents),
1138 /* CRU_CLKSEL_CON61 */
1139 .muxdiv_offset = 0x01f4,
1146 /* CRU_CLKGATE_CON10 */
1147 .gate_offset = 0x0328,
1150 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1153 static struct rk_clk_composite_def i2c6 = {
1157 .parent_names = i2c_parents,
1158 .parent_cnt = nitems(i2c_parents),
1160 /* CRU_CLKSEL_CON62 */
1161 .muxdiv_offset = 0x01f8,
1168 /* CRU_CLKGATE_CON10 */
1169 .gate_offset = 0x0328,
1172 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1175 static struct rk_clk_composite_def i2c7 = {
1179 .parent_names = i2c_parents,
1180 .parent_cnt = nitems(i2c_parents),
1182 /* CRU_CLKSEL_CON63 */
1183 .muxdiv_offset = 0x01fc,
1190 /* CRU_CLKGATE_CON10 */
1191 .gate_offset = 0x0328,
1194 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1198 * ARM CPU clocks (LITTLE and big)
1203 static const char *armclk_parents[] = {"lpll", "bpll", "dpll", "gpll"};
1205 static struct rk_clk_armclk_rates rk3399_armclkl_rates[] = {
1268 static struct rk_clk_armclk_def armclk_l = {
1272 .parent_names = armclk_parents,
1273 .parent_cnt = nitems(armclk_parents),
1275 /* CRU_CLKSEL_CON0 */
1276 .muxdiv_offset = 0x100,
1283 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1287 .rates = rk3399_armclkl_rates,
1288 .nrates = nitems(rk3399_armclkl_rates),
1291 static struct rk_clk_armclk_rates rk3399_armclkb_rates[] = {
1382 static struct rk_clk_armclk_def armclk_b = {
1386 .parent_names = armclk_parents,
1387 .parent_cnt = nitems(armclk_parents),
1389 .muxdiv_offset = 0x108,
1396 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1400 .rates = rk3399_armclkb_rates,
1401 .nrates = nitems(rk3399_armclkb_rates),
1410 static const char *hclk_sd_parents[] = {"cpll", "gpll"};
1412 static struct rk_clk_composite_def hclk_sd = {
1416 .parent_names = hclk_sd_parents,
1417 .parent_cnt = nitems(hclk_sd_parents),
1420 .muxdiv_offset = 0x134,
1427 .gate_offset = 0x330,
1430 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1433 #define SCLK_SDMMC 76
1435 static const char *sclk_sdmmc_parents[] = {"cpll", "gpll", "npll", "ppll"};
1437 static struct rk_clk_composite_def sclk_sdmmc = {
1440 .name = "sclk_sdmmc",
1441 .parent_names = sclk_sdmmc_parents,
1442 .parent_cnt = nitems(sclk_sdmmc_parents),
1445 .muxdiv_offset = 0x140,
1452 .gate_offset = 0x318,
1455 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1462 #define SCLK_EMMC 78
1464 static const char *sclk_emmc_parents[] = {"cpll", "gpll", "npll"};
1466 static struct rk_clk_composite_def sclk_emmc = {
1469 .name = "sclk_emmc",
1470 .parent_names = sclk_emmc_parents,
1471 .parent_cnt = nitems(sclk_emmc_parents),
1474 .muxdiv_offset = 0x158,
1481 .gate_offset = 0x318,
1484 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1487 #define ACLK_EMMC 240
1489 static const char *aclk_emmc_parents[] = {
1490 "cpll_aclk_emmc_src",
1491 "gpll_aclk_emmc_src"
1494 static struct rk_clk_composite_def aclk_emmc = {
1497 .name = "aclk_emmc",
1498 .parent_names = aclk_emmc_parents,
1499 .parent_cnt = nitems(aclk_emmc_parents),
1502 .muxdiv_offset = 0x154,
1509 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1512 static struct rk_clk rk3399_clks[] = {
1514 .type = RK3399_CLK_PLL,
1518 .type = RK3399_CLK_PLL,
1522 .type = RK3399_CLK_PLL,
1526 .type = RK3399_CLK_PLL,
1530 .type = RK3399_CLK_PLL,
1534 .type = RK3399_CLK_PLL,
1538 .type = RK3399_CLK_PLL,
1543 .type = RK_CLK_COMPOSITE,
1544 .clk.composite = &aclk_perihp,
1547 .type = RK_CLK_COMPOSITE,
1548 .clk.composite = &hclk_perihp,
1551 .type = RK_CLK_COMPOSITE,
1552 .clk.composite = &pclk_perihp,
1555 .type = RK_CLK_COMPOSITE,
1556 .clk.composite = &aclk_perilp0,
1559 .type = RK_CLK_COMPOSITE,
1560 .clk.composite = &hclk_perilp0,
1563 .type = RK_CLK_COMPOSITE,
1564 .clk.composite = &pclk_perilp0,
1567 .type = RK_CLK_COMPOSITE,
1568 .clk.composite = &pclk_alive,
1571 .type = RK_CLK_COMPOSITE,
1572 .clk.composite = &hclk_perilp1,
1575 .type = RK_CLK_COMPOSITE,
1576 .clk.composite = &pclk_perilp1,
1579 .type = RK_CLK_COMPOSITE,
1580 .clk.composite = &i2c1,
1583 .type = RK_CLK_COMPOSITE,
1584 .clk.composite = &i2c2,
1587 .type = RK_CLK_COMPOSITE,
1588 .clk.composite = &i2c3,
1591 .type = RK_CLK_COMPOSITE,
1592 .clk.composite = &i2c5,
1595 .type = RK_CLK_COMPOSITE,
1596 .clk.composite = &i2c6,
1599 .type = RK_CLK_COMPOSITE,
1600 .clk.composite = &i2c7,
1604 .type = RK_CLK_ARMCLK,
1605 .clk.armclk = &armclk_l,
1608 .type = RK_CLK_ARMCLK,
1609 .clk.armclk = &armclk_b,
1613 .type = RK_CLK_COMPOSITE,
1614 .clk.composite = &hclk_sd,
1617 .type = RK_CLK_COMPOSITE,
1618 .clk.composite = &sclk_sdmmc,
1622 .type = RK_CLK_COMPOSITE,
1623 .clk.composite = &sclk_emmc,
1626 .type = RK_CLK_COMPOSITE,
1627 .clk.composite = &aclk_emmc,
1632 rk3399_cru_probe(device_t dev)
1635 if (!ofw_bus_status_okay(dev))
1638 if (ofw_bus_is_compatible(dev, "rockchip,rk3399-cru")) {
1639 device_set_desc(dev, "Rockchip RK3399 Clock and Reset Unit");
1640 return (BUS_PROBE_DEFAULT);
1647 rk3399_cru_attach(device_t dev)
1649 struct rk_cru_softc *sc;
1651 sc = device_get_softc(dev);
1654 sc->gates = rk3399_gates;
1655 sc->ngates = nitems(rk3399_gates);
1657 sc->clks = rk3399_clks;
1658 sc->nclks = nitems(rk3399_clks);
1660 return (rk_cru_attach(dev));
1663 static device_method_t rk3399_cru_methods[] = {
1664 /* Device interface */
1665 DEVMETHOD(device_probe, rk3399_cru_probe),
1666 DEVMETHOD(device_attach, rk3399_cru_attach),
1671 static devclass_t rk3399_cru_devclass;
1673 DEFINE_CLASS_1(rk3399_cru, rk3399_cru_driver, rk3399_cru_methods,
1674 sizeof(struct rk_cru_softc), rk_cru_driver);
1676 EARLY_DRIVER_MODULE(rk3399_cru, simplebus, rk3399_cru_driver,
1677 rk3399_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);