xref: /freebsd/sys/dev/clk/spacemit/k1_apmu.c (revision dcb10e3add17259715352885dfc55ca92061d2ed)
1 /*
2  * Copyright (c) 2026 Bojan Novković <bnovkov@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 /*
8  * Driver for the SpacemiT K1 SoC APMU clock control unit.
9  *
10  * Written using SpacemiT's K1 Chip Product Documentation,
11  * Section 9., "Top System (1/2)" and the accompanying clock
12  * tree schematic, available at https://www.spacemit.com/community/document/
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/bus.h>
18 #include <sys/kernel.h>
19 #include <sys/module.h>
20 #include <sys/mutex.h>
21 #include <sys/resource.h>
22 #include <sys/rman.h>
23 
24 #include <machine/bus.h>
25 
26 #include <dev/fdt/simplebus.h>
27 #include <dev/ofw/ofw_bus.h>
28 #include <dev/ofw/ofw_bus_subr.h>
29 
30 #include <dev/clk/clk.h>
31 #include <dev/hwreset/hwreset.h>
32 
33 #include <dt-bindings/clock/spacemit,k1-syscon.h>
34 
35 #include "k1_clk.h"
36 
37 #define K1_SDH0_CLK_RES_CTRL 0x54
38 #define K1_SDH1_CLK_RES_CTRL 0x58
39 #define K1_SDH2_CLK_RES_CTRL 0xE0
40 #define K1_PMUA_ACLK_CTRL    0x388
41 
42 static const struct k1_clk_def apmu_clks[] = {
43 K1_CLK_DIV_MUX(pmua_aclk, CLK_PMUA_ACLK, K1_PMUA_ACLK_CTRL,
44 	1, 0, 2, 1, 4,
45 	"pll1_d10_aud", "pll1_d8"),
46 
47 K1_CLK_GATE(sdh_axi_aclk, CLK_SDH_AXI, K1_SDH0_CLK_RES_CTRL, 4,
48 	"pmua_aclk"),
49 
50 K1_CLK_DIV_MUX_GATE(sdh0_clk, CLK_SDH0, K1_SDH0_CLK_RES_CTRL,
51 	3, 8, 3, 5, 4, 11,
52 	"pll1_d6", "pll1_d4", "pll2_d8", "pll2_d5",
53 	"pll1_d11", "pll1_d11" , "pll1_d13", "pll1_d23"),
54 
55 K1_CLK_DIV_MUX_GATE(sdh1_clk, CLK_SDH1, K1_SDH1_CLK_RES_CTRL,
56 	3, 8, 3, 5, 4, 11,
57 	"pll1_d6", "pll1_d4", "pll2_d8", "pll2_d5",
58 	"pll1_d11", "pll1_d11" , "pll1_d13", "pll1_d23"),
59 
60 K1_CLK_DIV_MUX_GATE(sdh2_clk, CLK_SDH2, K1_SDH2_CLK_RES_CTRL,
61 	3, 8, 3, 5, 4, 11,
62 	"pll1_d6", "pll1_d4", "pll2_d8", "pll1_d3",
63 	"pll1_d11", "pll1_d11" , "pll1_d13", "pll1_d23")
64 };
65 
66 static const struct k1_reset_def apmu_resets[] = {
67 K1_RESET(RESET_SDH_AXI, K1_SDH0_CLK_RES_CTRL, 0, 3),
68 K1_RESET(RESET_SDH0, K1_SDH0_CLK_RES_CTRL, 0, 1),
69 K1_RESET(RESET_SDH1, K1_SDH1_CLK_RES_CTRL, 0, 1),
70 K1_RESET(RESET_SDH2, K1_SDH2_CLK_RES_CTRL, 0, 1),
71 };
72 
73 #define K1_APMU_NRESETS (RESET_SDH2 + 1);
74 
75 static int
k1_apmu_probe(device_t dev)76 k1_apmu_probe(device_t dev)
77 {
78 
79 	if (!ofw_bus_status_okay(dev))
80 		return (ENXIO);
81 	if (!ofw_bus_is_compatible(dev, "spacemit,k1-syscon-apmu"))
82 		return (ENXIO);
83 	device_set_desc(dev, "SpacemitT K1 APMU Clock Controller");
84 
85 	return (BUS_PROBE_DEFAULT);
86 }
87 
88 static int
k1_apmu_attach(device_t dev)89 k1_apmu_attach(device_t dev)
90 {
91 	struct k1_clkdev_softc *sc;
92 
93 	sc = device_get_softc(dev);
94 	sc->clks = apmu_clks;
95 	sc->nclks = nitems(apmu_clks);
96 
97 	sc->resets = apmu_resets;
98 	sc->nresets = K1_APMU_NRESETS;
99 
100 	return (k1_clk_attach(dev));
101 }
102 
103 static device_method_t k1_apmu_clkdev_methods[] = {
104 	/* device_if */
105 	DEVMETHOD(device_probe, 	k1_apmu_probe),
106 	DEVMETHOD(device_attach, 	k1_apmu_attach),
107 
108 	DEVMETHOD_END
109 };
110 
111 DEFINE_CLASS_1(k1_apmu, k1_apmu_driver, k1_apmu_clkdev_methods,
112     sizeof(struct k1_clkdev_softc), k1_clkdev_driver);
113 EARLY_DRIVER_MODULE(k1_apmu, simplebus, k1_apmu_driver, 0, 0,
114     BUS_PASS_BUS + BUS_PASS_ORDER_LAST);
115