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 PCLK_GPIO2 336
56 #define PCLK_GPIO3 337
57 #define PCLK_GPIO4 338
64 #define HCLK_SDMMC 462
66 static struct rk_cru_gate rk3399_gates[] = {
67 /* CRU_CLKGATE_CON0 */
68 CRU_GATE(0, "clk_core_l_lpll_src", "lpll", 0x300, 0)
69 CRU_GATE(0, "clk_core_l_bpll_src", "bpll", 0x300, 1)
70 CRU_GATE(0, "clk_core_l_dpll_src", "dpll", 0x300, 2)
71 CRU_GATE(0, "clk_core_l_gpll_src", "gpll", 0x300, 3)
73 /* CRU_CLKGATE_CON1 */
74 CRU_GATE(0, "clk_core_b_lpll_src", "lpll", 0x304, 0)
75 CRU_GATE(0, "clk_core_b_bpll_src", "bpll", 0x304, 1)
76 CRU_GATE(0, "clk_core_b_dpll_src", "dpll", 0x304, 2)
77 CRU_GATE(0, "clk_core_b_gpll_src", "gpll", 0x304, 3)
79 /* CRU_CLKGATE_CON5 */
80 CRU_GATE(0, "cpll_aclk_perihp_src", "cpll", 0x314, 0)
81 CRU_GATE(0, "gpll_aclk_perihp_src", "gpll", 0x314, 1)
83 /* CRU_CLKGATE_CON7 */
84 CRU_GATE(0, "gpll_aclk_perilp0_src", "gpll", 0x31C, 0)
85 CRU_GATE(0, "cpll_aclk_perilp0_src", "cpll", 0x31C, 1)
87 /* CRU_CLKGATE_CON8 */
88 CRU_GATE(0, "hclk_perilp1_cpll_src", "cpll", 0x320, 1)
89 CRU_GATE(0, "hclk_perilp1_gpll_src", "gpll", 0x320, 0)
91 /* CRU_CLKGATE_CON22 */
92 CRU_GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0x358, 5)
93 CRU_GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0x358, 6)
94 CRU_GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0x358, 7)
95 CRU_GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0x358, 8)
96 CRU_GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0x358, 9)
97 CRU_GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0x358, 10)
99 /* CRU_CLKGATE_CON31 */
100 CRU_GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0x37c, 3)
101 CRU_GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0x37c, 4)
102 CRU_GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0x37c, 5)
104 /* CRU_CLKGATE_CON33 */
105 CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0x384, 8)
121 static struct rk_clk_pll_rate rk3399_pll_rates[] = {
741 static const char *pll_parents[] = {"xin24m"};
743 static struct rk_clk_pll_def lpll = {
747 .parent_names = pll_parents,
748 .parent_cnt = nitems(pll_parents),
751 .gate_offset = 0x300,
753 .flags = RK_CLK_PLL_HAVE_GATE,
754 .rates = rk3399_pll_rates,
757 static struct rk_clk_pll_def bpll = {
761 .parent_names = pll_parents,
762 .parent_cnt = nitems(pll_parents),
765 .gate_offset = 0x300,
767 .flags = RK_CLK_PLL_HAVE_GATE,
768 .rates = rk3399_pll_rates,
771 static struct rk_clk_pll_def dpll = {
775 .parent_names = pll_parents,
776 .parent_cnt = nitems(pll_parents),
779 .gate_offset = 0x300,
781 .flags = RK_CLK_PLL_HAVE_GATE,
782 .rates = rk3399_pll_rates,
786 static struct rk_clk_pll_def cpll = {
790 .parent_names = pll_parents,
791 .parent_cnt = nitems(pll_parents),
794 .rates = rk3399_pll_rates,
797 static struct rk_clk_pll_def gpll = {
801 .parent_names = pll_parents,
802 .parent_cnt = nitems(pll_parents),
805 .gate_offset = 0x300,
807 .flags = RK_CLK_PLL_HAVE_GATE,
808 .rates = rk3399_pll_rates,
811 static struct rk_clk_pll_def npll = {
815 .parent_names = pll_parents,
816 .parent_cnt = nitems(pll_parents),
819 .rates = rk3399_pll_rates,
822 static struct rk_clk_pll_def vpll = {
826 .parent_names = pll_parents,
827 .parent_cnt = nitems(pll_parents),
830 .rates = rk3399_pll_rates,
833 #define ACLK_PERIHP 192
834 #define HCLK_PERIHP 448
835 #define PCLK_PERIHP 320
837 static const char *aclk_perihp_parents[] = {"cpll_aclk_perihp_src", "gpll_aclk_perihp_src"};
839 static struct rk_clk_composite_def aclk_perihp = {
842 .name = "aclk_perihp",
843 .parent_names = aclk_perihp_parents,
844 .parent_cnt = nitems(aclk_perihp_parents),
846 /* CRU_CLKSEL_CON14 */
847 .muxdiv_offset = 0x138,
855 /* CRU_CLKGATE_CON5 */
856 .gate_offset = 0x314,
859 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
862 static const char *hclk_pclk_perihp_parents[] = {"aclk_perihp"};
864 static struct rk_clk_composite_def hclk_perihp = {
867 .name = "hclk_perihp",
868 .parent_names = hclk_pclk_perihp_parents,
869 .parent_cnt = nitems(hclk_pclk_perihp_parents),
871 /* CRU_CLKSEL_CON14 */
872 .muxdiv_offset = 0x138,
877 /* CRU_CLKGATE_CON5 */
878 .gate_offset = 0x314,
881 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
884 static struct rk_clk_composite_def pclk_perihp = {
887 .name = "pclk_perihp",
888 .parent_names = hclk_pclk_perihp_parents,
889 .parent_cnt = nitems(hclk_pclk_perihp_parents),
891 /* CRU_CLKSEL_CON14 */
892 .muxdiv_offset = 0x138,
897 /* CRU_CLKGATE_CON5 */
898 .gate_offset = 0x314,
901 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
904 #define ACLK_PERILP0 194
905 #define HCLK_PERILP0 449
906 #define PCLK_PERILP0 322
908 static const char *aclk_perilp0_parents[] = {"cpll_aclk_perilp0_src", "gpll_aclk_perilp0_src"};
910 static struct rk_clk_composite_def aclk_perilp0 = {
913 .name = "aclk_perilp0",
914 .parent_names = aclk_perilp0_parents,
915 .parent_cnt = nitems(aclk_perilp0_parents),
917 /* CRU_CLKSEL_CON14 */
918 .muxdiv_offset = 0x15C,
926 /* CRU_CLKGATE_CON7 */
927 .gate_offset = 0x31C,
930 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
933 static const char *hclk_pclk_perilp0_parents[] = {"aclk_perilp0"};
935 static struct rk_clk_composite_def hclk_perilp0 = {
938 .name = "hclk_perilp0",
939 .parent_names = hclk_pclk_perilp0_parents,
940 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
942 /* CRU_CLKSEL_CON23 */
943 .muxdiv_offset = 0x15C,
948 /* CRU_CLKGATE_CON7 */
949 .gate_offset = 0x31C,
952 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
955 static struct rk_clk_composite_def pclk_perilp0 = {
958 .name = "pclk_perilp0",
959 .parent_names = hclk_pclk_perilp0_parents,
960 .parent_cnt = nitems(hclk_pclk_perilp0_parents),
962 /* CRU_CLKSEL_CON23 */
963 .muxdiv_offset = 0x15C,
968 /* CRU_CLKGATE_CON7 */
969 .gate_offset = 0x31C,
972 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
978 #define PCLK_ALIVE 390
980 static const char *alive_parents[] = {"gpll"};
982 static struct rk_clk_composite_def pclk_alive = {
985 .name = "pclk_alive",
986 .parent_names = alive_parents,
987 .parent_cnt = nitems(alive_parents),
989 /* CRU_CLKSEL_CON57 */
990 .muxdiv_offset = 0x01e4,
996 #define HCLK_PERILP1 450
997 #define PCLK_PERILP1 323
999 static const char *hclk_perilp1_parents[] = {"cpll", "gpll"};
1001 static struct rk_clk_composite_def hclk_perilp1 = {
1004 .name = "hclk_perilp1",
1005 .parent_names = hclk_perilp1_parents,
1006 .parent_cnt = nitems(hclk_perilp1_parents),
1008 /* CRU_CLKSEL_CON25 */
1009 .muxdiv_offset = 0x164,
1016 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1019 static const char *pclk_perilp1_parents[] = {"hclk_perilp1"};
1021 static struct rk_clk_composite_def pclk_perilp1 = {
1024 .name = "pclk_perilp1",
1025 .parent_names = pclk_perilp1_parents,
1026 .parent_cnt = nitems(pclk_perilp1_parents),
1028 /* CRU_CLKSEL_CON25 */
1029 .muxdiv_offset = 0x164,
1034 /* CRU_CLKGATE_CON8 */
1035 .gate_offset = 0x320,
1038 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
1044 static const char *i2c_parents[] = {"cpll", "gpll"};
1046 #define SCLK_I2C1 65
1047 #define SCLK_I2C2 66
1048 #define SCLK_I2C3 67
1049 #define SCLK_I2C5 68
1050 #define SCLK_I2C6 69
1051 #define SCLK_I2C7 70
1053 static struct rk_clk_composite_def i2c1 = {
1057 .parent_names = i2c_parents,
1058 .parent_cnt = nitems(i2c_parents),
1060 /* CRU_CLKSEL_CON61 */
1061 .muxdiv_offset = 0x01f4,
1068 /* CRU_CLKGATE_CON10 */
1069 .gate_offset = 0x0328,
1072 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1075 static struct rk_clk_composite_def i2c2 = {
1079 .parent_names = i2c_parents,
1080 .parent_cnt = nitems(i2c_parents),
1082 /* CRU_CLKSEL_CON62 */
1083 .muxdiv_offset = 0x01f8,
1090 /* CRU_CLKGATE_CON10 */
1091 .gate_offset = 0x0328,
1094 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1097 static struct rk_clk_composite_def i2c3 = {
1101 .parent_names = i2c_parents,
1102 .parent_cnt = nitems(i2c_parents),
1104 /* CRU_CLKSEL_CON63 */
1105 .muxdiv_offset = 0x01fc,
1112 /* CRU_CLKGATE_CON10 */
1113 .gate_offset = 0x0328,
1116 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1119 static struct rk_clk_composite_def i2c5 = {
1123 .parent_names = i2c_parents,
1124 .parent_cnt = nitems(i2c_parents),
1126 /* CRU_CLKSEL_CON61 */
1127 .muxdiv_offset = 0x01f4,
1134 /* CRU_CLKGATE_CON10 */
1135 .gate_offset = 0x0328,
1138 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1141 static struct rk_clk_composite_def i2c6 = {
1145 .parent_names = i2c_parents,
1146 .parent_cnt = nitems(i2c_parents),
1148 /* CRU_CLKSEL_CON62 */
1149 .muxdiv_offset = 0x01f8,
1156 /* CRU_CLKGATE_CON10 */
1157 .gate_offset = 0x0328,
1160 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1163 static struct rk_clk_composite_def i2c7 = {
1167 .parent_names = i2c_parents,
1168 .parent_cnt = nitems(i2c_parents),
1170 /* CRU_CLKSEL_CON63 */
1171 .muxdiv_offset = 0x01fc,
1178 /* CRU_CLKGATE_CON10 */
1179 .gate_offset = 0x0328,
1182 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1186 * ARM CPU clocks (LITTLE and big)
1191 static const char *armclk_parents[] = {"lpll", "bpll", "dpll", "gpll"};
1193 static struct rk_clk_armclk_rates rk3399_armclkl_rates[] = {
1256 static struct rk_clk_armclk_def armclk_l = {
1260 .parent_names = armclk_parents,
1261 .parent_cnt = nitems(armclk_parents),
1263 /* CRU_CLKSEL_CON0 */
1264 .muxdiv_offset = 0x100,
1271 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1275 .rates = rk3399_armclkl_rates,
1276 .nrates = nitems(rk3399_armclkl_rates),
1279 static struct rk_clk_armclk_rates rk3399_armclkb_rates[] = {
1370 static struct rk_clk_armclk_def armclk_b = {
1374 .parent_names = armclk_parents,
1375 .parent_cnt = nitems(armclk_parents),
1377 .muxdiv_offset = 0x108,
1384 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
1388 .rates = rk3399_armclkb_rates,
1389 .nrates = nitems(rk3399_armclkb_rates),
1398 static const char *hclk_sd_parents[] = {"cpll", "gpll"};
1400 static struct rk_clk_composite_def hclk_sd = {
1404 .parent_names = hclk_sd_parents,
1405 .parent_cnt = nitems(hclk_sd_parents),
1408 .muxdiv_offset = 0x134,
1415 .gate_offset = 0x330,
1418 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1421 #define SCLK_SDMMC 76
1423 static const char *sclk_sdmmc_parents[] = {"cpll", "gpll", "npll", "ppll"};
1425 static struct rk_clk_composite_def sclk_sdmmc = {
1428 .name = "sclk_sdmmc",
1429 .parent_names = sclk_sdmmc_parents,
1430 .parent_cnt = nitems(sclk_sdmmc_parents),
1433 .muxdiv_offset = 0x140,
1440 .gate_offset = 0x318,
1443 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
1446 static struct rk_clk rk3399_clks[] = {
1448 .type = RK3399_CLK_PLL,
1452 .type = RK3399_CLK_PLL,
1456 .type = RK3399_CLK_PLL,
1460 .type = RK3399_CLK_PLL,
1464 .type = RK3399_CLK_PLL,
1468 .type = RK3399_CLK_PLL,
1472 .type = RK3399_CLK_PLL,
1477 .type = RK_CLK_COMPOSITE,
1478 .clk.composite = &aclk_perihp,
1481 .type = RK_CLK_COMPOSITE,
1482 .clk.composite = &hclk_perihp,
1485 .type = RK_CLK_COMPOSITE,
1486 .clk.composite = &pclk_perihp,
1489 .type = RK_CLK_COMPOSITE,
1490 .clk.composite = &aclk_perilp0,
1493 .type = RK_CLK_COMPOSITE,
1494 .clk.composite = &hclk_perilp0,
1497 .type = RK_CLK_COMPOSITE,
1498 .clk.composite = &pclk_perilp0,
1501 .type = RK_CLK_COMPOSITE,
1502 .clk.composite = &pclk_alive,
1505 .type = RK_CLK_COMPOSITE,
1506 .clk.composite = &hclk_perilp1,
1509 .type = RK_CLK_COMPOSITE,
1510 .clk.composite = &pclk_perilp1,
1513 .type = RK_CLK_COMPOSITE,
1514 .clk.composite = &i2c1,
1517 .type = RK_CLK_COMPOSITE,
1518 .clk.composite = &i2c2,
1521 .type = RK_CLK_COMPOSITE,
1522 .clk.composite = &i2c3,
1525 .type = RK_CLK_COMPOSITE,
1526 .clk.composite = &i2c5,
1529 .type = RK_CLK_COMPOSITE,
1530 .clk.composite = &i2c6,
1533 .type = RK_CLK_COMPOSITE,
1534 .clk.composite = &i2c7,
1538 .type = RK_CLK_ARMCLK,
1539 .clk.armclk = &armclk_l,
1542 .type = RK_CLK_ARMCLK,
1543 .clk.armclk = &armclk_b,
1547 .type = RK_CLK_COMPOSITE,
1548 .clk.composite = &hclk_sd,
1551 .type = RK_CLK_COMPOSITE,
1552 .clk.composite = &sclk_sdmmc,
1557 rk3399_cru_probe(device_t dev)
1560 if (!ofw_bus_status_okay(dev))
1563 if (ofw_bus_is_compatible(dev, "rockchip,rk3399-cru")) {
1564 device_set_desc(dev, "Rockchip RK3399 Clock and Reset Unit");
1565 return (BUS_PROBE_DEFAULT);
1572 rk3399_cru_attach(device_t dev)
1574 struct rk_cru_softc *sc;
1576 sc = device_get_softc(dev);
1579 sc->gates = rk3399_gates;
1580 sc->ngates = nitems(rk3399_gates);
1582 sc->clks = rk3399_clks;
1583 sc->nclks = nitems(rk3399_clks);
1585 return (rk_cru_attach(dev));
1588 static device_method_t rk3399_cru_methods[] = {
1589 /* Device interface */
1590 DEVMETHOD(device_probe, rk3399_cru_probe),
1591 DEVMETHOD(device_attach, rk3399_cru_attach),
1596 static devclass_t rk3399_cru_devclass;
1598 DEFINE_CLASS_1(rk3399_cru, rk3399_cru_driver, rk3399_cru_methods,
1599 sizeof(struct rk_cru_softc), rk_cru_driver);
1601 EARLY_DRIVER_MODULE(rk3399_cru, simplebus, rk3399_cru_driver,
1602 rk3399_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);