2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
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>
56 #define PCLK_GPIO0 200
57 #define PCLK_GPIO1 201
58 #define PCLK_GPIO2 202
59 #define PCLK_GPIO3 203
64 #define PCLK_TSADC 213
65 #define HCLK_SDMMC 317
68 #define HCLK_SDMMC_EXT 320
70 static struct rk_cru_gate rk3328_gates[] = {
71 /* CRU_CLKGATE_CON0 */
72 CRU_GATE(0, "apll_core", "apll", 0x200, 0)
73 CRU_GATE(0, "dpll_core", "dpll", 0x200, 1)
74 CRU_GATE(0, "gpll_core", "gpll", 0x200, 2)
75 CRU_GATE(0, "npll_core", "npll", 0x200, 12)
77 /* CRU_CLKGATE_CON4 */
78 CRU_GATE(0, "gpll_peri", "gpll", 0x210, 0)
79 CRU_GATE(0, "cpll_peri", "cpll", 0x210, 1)
81 /* CRU_CLKGATE_CON8 */
82 CRU_GATE(0, "pclk_bus", "pclk_bus_pre", 0x220, 3)
83 CRU_GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0x220, 4)
85 /* CRU_CLKGATE_CON10 */
86 CRU_GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0x228, 0)
88 /* CRU_CLKGATE_CON15*/
89 CRU_GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0x23C, 10)
91 /* CRU_CLKGATE_CON16 */
92 CRU_GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0x23C, 0)
93 CRU_GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0x23C, 1)
94 CRU_GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0x23C, 2)
95 CRU_GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0x23C, 14)
97 CRU_GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0x240, 7)
98 CRU_GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0x240, 8)
99 CRU_GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0x240, 9)
100 CRU_GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0x240, 10)
102 /* CRU_CLKGATE_CON19 */
103 CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0x24C, 0)
104 CRU_GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0x24C, 1)
105 CRU_GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0x24C, 2)
106 CRU_GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0x24C, 15)
119 static struct rk_clk_pll_rate rk3328_pll_rates[] = {
459 static struct rk_clk_pll_rate rk3328_pll_frac_rates[] = {
517 static const char *pll_parents[] = {"xin24m"};
518 static struct rk_clk_pll_def apll = {
522 .parent_names = pll_parents,
523 .parent_cnt = nitems(pll_parents),
526 .gate_offset = 0x200,
530 .flags = RK_CLK_PLL_HAVE_GATE,
531 .frac_rates = rk3328_pll_frac_rates,
534 static struct rk_clk_pll_def dpll = {
538 .parent_names = pll_parents,
539 .parent_cnt = nitems(pll_parents),
542 .gate_offset = 0x200,
546 .flags = RK_CLK_PLL_HAVE_GATE,
549 static struct rk_clk_pll_def cpll = {
553 .parent_names = pll_parents,
554 .parent_cnt = nitems(pll_parents),
559 .rates = rk3328_pll_rates,
562 static struct rk_clk_pll_def gpll = {
566 .parent_names = pll_parents,
567 .parent_cnt = nitems(pll_parents),
570 .gate_offset = 0x200,
574 .flags = RK_CLK_PLL_HAVE_GATE,
575 .frac_rates = rk3328_pll_frac_rates,
578 static struct rk_clk_pll_def npll = {
582 .parent_names = pll_parents,
583 .parent_cnt = nitems(pll_parents),
586 .gate_offset = 0x200,
590 .flags = RK_CLK_PLL_HAVE_GATE,
591 .rates = rk3328_pll_rates,
594 /* CRU_CLKSEL_CON0 */
595 #define ACLK_BUS_PRE 136
597 /* Needs hdmiphy as parent too*/
598 static const char *aclk_bus_pre_parents[] = {"cpll", "gpll"};
599 static struct rk_clk_composite_def aclk_bus_pre = {
602 .name = "aclk_bus_pre",
603 .parent_names = aclk_bus_pre_parents,
604 .parent_cnt = nitems(aclk_bus_pre_parents),
606 .muxdiv_offset = 0x100,
613 .gate_offset = 0x220,
616 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
619 static struct rk_clk_armclk_rates rk3328_armclk_rates[] = {
671 static const char *armclk_parents[] = {"apll", "gpll", "dpll", "npll" };
672 static struct rk_clk_armclk_def armclk = {
676 .parent_names = armclk_parents,
677 .parent_cnt = nitems(armclk_parents),
679 .muxdiv_offset = 0x100,
686 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
687 .main_parent = 3, /* npll */
688 .alt_parent = 0, /* apll */
690 .rates = rk3328_armclk_rates,
691 .nrates = nitems(rk3328_armclk_rates),
694 /* CRU_CLKSEL_CON1 */
696 #define PCLK_BUS_PRE 216
697 #define HCLK_BUS_PRE 328
699 static const char *hclk_bus_pre_parents[] = {"aclk_bus_pre"};
700 static struct rk_clk_composite_def hclk_bus_pre = {
703 .name = "hclk_bus_pre",
704 .parent_names = hclk_bus_pre_parents,
705 .parent_cnt = nitems(hclk_bus_pre_parents),
707 .muxdiv_offset = 0x104,
712 .gate_offset = 0x220,
715 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
718 static const char *pclk_bus_pre_parents[] = {"aclk_bus_pre"};
719 static struct rk_clk_composite_def pclk_bus_pre = {
722 .name = "pclk_bus_pre",
723 .parent_names = pclk_bus_pre_parents,
724 .parent_cnt = nitems(pclk_bus_pre_parents),
726 .muxdiv_offset = 0x104,
731 .gate_offset = 0x220,
734 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
737 /* CRU_CLKSEL_CON22 */
739 #define SCLK_TSADC 36
741 static const char *clk_tsadc_parents[] = {"xin24m"};
742 static struct rk_clk_composite_def clk_tsadc = {
746 .parent_names = clk_tsadc_parents,
747 .parent_cnt = nitems(clk_tsadc_parents),
753 /* CRU_CLKSEL_CON28 */
755 #define ACLK_PERI_PRE 137
757 static const char *aclk_peri_pre_parents[] = {"cpll", "gpll"/* , "hdmiphy" */};
758 static struct rk_clk_composite_def aclk_peri_pre = {
761 .name = "aclk_peri_pre",
762 .parent_names = aclk_peri_pre_parents,
763 .parent_cnt = nitems(aclk_peri_pre_parents),
765 .muxdiv_offset = 0x170,
773 .flags = RK_CLK_COMPOSITE_HAVE_MUX,
776 /* CRU_CLKSEL_CON29 */
778 #define PCLK_PERI 230
779 #define HCLK_PERI 308
781 static const char *phclk_peri_parents[] = {"aclk_peri_pre"};
782 static struct rk_clk_composite_def pclk_peri = {
786 .parent_names = phclk_peri_parents,
787 .parent_cnt = nitems(phclk_peri_parents),
793 /* CRU_CLKGATE_CON10 */
794 .gate_offset = 0x228,
797 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
800 static struct rk_clk_composite_def hclk_peri = {
804 .parent_names = phclk_peri_parents,
805 .parent_cnt = nitems(phclk_peri_parents),
811 /* CRU_CLKGATE_CON10 */
812 .gate_offset = 0x228,
815 .flags = RK_CLK_COMPOSITE_HAVE_GATE,
818 /* CRU_CLKSEL_CON30 */
820 #define SCLK_SDMMC 33
822 static const char *mmc_parents[] = {"cpll", "gpll", "xin24m"/* , "usb480m" */};
823 static struct rk_clk_composite_def sdmmc = {
827 .parent_names = mmc_parents,
828 .parent_cnt = nitems(mmc_parents),
830 .muxdiv_offset = 0x178,
838 /* CRU_CLKGATE_CON4 */
839 .gate_offset = 0x210,
842 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
845 /* CRU_CLKSEL_CON31 */
848 static struct rk_clk_composite_def sdio = {
852 .parent_names = mmc_parents,
853 .parent_cnt = nitems(mmc_parents),
855 .muxdiv_offset = 0x17C,
863 /* CRU_CLKGATE_CON4 */
864 .gate_offset = 0x210,
867 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
870 /* CRU_CLKSEL_CON32 */
873 static struct rk_clk_composite_def emmc = {
877 .parent_names = mmc_parents,
878 .parent_cnt = nitems(mmc_parents),
880 .muxdiv_offset = 0x180,
888 /* CRU_CLKGATE_CON4 */
889 .gate_offset = 0x210,
892 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
895 /* CRU_CLKSEL_CON34 */
899 static const char *i2c_parents[] = {"cpll", "gpll"};
901 static struct rk_clk_composite_def i2c0 = {
905 .parent_names = i2c_parents,
906 .parent_cnt = nitems(i2c_parents),
908 .muxdiv_offset = 0x188,
916 /* CRU_CLKGATE_CON2 */
917 .gate_offset = 0x208,
920 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
923 static struct rk_clk_composite_def i2c1 = {
927 .parent_names = i2c_parents,
928 .parent_cnt = nitems(i2c_parents),
930 .muxdiv_offset = 0x188,
938 /* CRU_CLKGATE_CON2 */
939 .gate_offset = 0x208,
942 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
945 /* CRU_CLKSEL_CON35 */
949 static struct rk_clk_composite_def i2c2 = {
953 .parent_names = i2c_parents,
954 .parent_cnt = nitems(i2c_parents),
956 .muxdiv_offset = 0x18C,
964 /* CRU_CLKGATE_CON2 */
965 .gate_offset = 0x208,
968 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
971 static struct rk_clk_composite_def i2c3 = {
975 .parent_names = i2c_parents,
976 .parent_cnt = nitems(i2c_parents),
978 .muxdiv_offset = 0x18C,
986 /* CRU_CLKGATE_CON2 */
987 .gate_offset = 0x208,
990 .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
993 static struct rk_clk rk3328_clks[] = {
995 .type = RK3328_CLK_PLL,
999 .type = RK3328_CLK_PLL,
1003 .type = RK3328_CLK_PLL,
1007 .type = RK3328_CLK_PLL,
1011 .type = RK3328_CLK_PLL,
1016 .type = RK_CLK_COMPOSITE,
1017 .clk.composite = &aclk_bus_pre
1020 .type = RK_CLK_COMPOSITE,
1021 .clk.composite = &hclk_bus_pre
1024 .type = RK_CLK_COMPOSITE,
1025 .clk.composite = &pclk_bus_pre
1029 .type = RK_CLK_ARMCLK,
1030 .clk.armclk = &armclk,
1034 .type = RK_CLK_COMPOSITE,
1035 .clk.composite = &clk_tsadc,
1038 .type = RK_CLK_COMPOSITE,
1039 .clk.composite = &aclk_peri_pre,
1042 .type = RK_CLK_COMPOSITE,
1043 .clk.composite = &pclk_peri,
1046 .type = RK_CLK_COMPOSITE,
1047 .clk.composite = &hclk_peri,
1050 .type = RK_CLK_COMPOSITE,
1051 .clk.composite = &sdmmc
1054 .type = RK_CLK_COMPOSITE,
1055 .clk.composite = &sdio
1058 .type = RK_CLK_COMPOSITE,
1059 .clk.composite = &emmc
1063 .type = RK_CLK_COMPOSITE,
1064 .clk.composite = &i2c0
1067 .type = RK_CLK_COMPOSITE,
1068 .clk.composite = &i2c1
1071 .type = RK_CLK_COMPOSITE,
1072 .clk.composite = &i2c2
1075 .type = RK_CLK_COMPOSITE,
1076 .clk.composite = &i2c3
1081 rk3328_cru_probe(device_t dev)
1084 if (!ofw_bus_status_okay(dev))
1087 if (ofw_bus_is_compatible(dev, "rockchip,rk3328-cru")) {
1088 device_set_desc(dev, "Rockchip RK3328 Clock and Reset Unit");
1089 return (BUS_PROBE_DEFAULT);
1096 rk3328_cru_attach(device_t dev)
1098 struct rk_cru_softc *sc;
1100 sc = device_get_softc(dev);
1103 sc->gates = rk3328_gates;
1104 sc->ngates = nitems(rk3328_gates);
1106 sc->clks = rk3328_clks;
1107 sc->nclks = nitems(rk3328_clks);
1109 sc->reset_offset = 0x300;
1110 sc->reset_num = 184;
1112 return (rk_cru_attach(dev));
1115 static device_method_t rk3328_cru_methods[] = {
1116 /* Device interface */
1117 DEVMETHOD(device_probe, rk3328_cru_probe),
1118 DEVMETHOD(device_attach, rk3328_cru_attach),
1123 static devclass_t rk3328_cru_devclass;
1125 DEFINE_CLASS_1(rk3328_cru, rk3328_cru_driver, rk3328_cru_methods,
1126 sizeof(struct rk_cru_softc), rk_cru_driver);
1128 EARLY_DRIVER_MODULE(rk3328_cru, simplebus, rk3328_cru_driver,
1129 rk3328_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);