1 /*
2  * Copyright (c) 2022 ASPEED Technology Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT aspeed_ast10x0_clock
8 #include <errno.h>
9 #include <zephyr/dt-bindings/clock/ast10x0_clock.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/drivers/syscon.h>
12 #include <zephyr/sys/util.h>
13 
14 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(clock_control_ast10x0);
17 
18 #define HPLL_FREQ			MHZ(1000)
19 
20 /*
21  * CLK_STOP_CTRL0/1_SET registers:
22  *   - Each bit in these registers controls a clock gate
23  *   - Write '1' to a bit: turn OFF the corresponding clock
24  *   - Write '0' to a bit: no effect
25  * CLK_STOP_CTRL0/1_CLEAR register:
26  *   - Write '1' to a bit: clear the corresponding bit in CLK_STOP_CTRL0/1.
27  *                         (turn ON the corresponding clock)
28  */
29 #define CLK_STOP_CTRL0_SET		0x80
30 #define CLK_STOP_CTRL0_CLEAR		0x84
31 #define CLK_STOP_CTRL1_SET		0x90
32 #define CLK_STOP_CTRL1_CLEAR		0x94
33 
34 #define CLK_SELECTION_REG4		0x310
35 #define   I3C_CLK_SRC_SEL		BIT(31)
36 #define     I3C_CLK_SRC_HPLL		0
37 #define     I3C_CLK_SRC_480M		1
38 #define   I3C_CLK_DIV_SEL		GENMASK(30, 28)
39 #define     I3C_CLK_DIV_REG_TO_VAL(x)	((x == 0) ? 2 : (x + 1))
40 #define   PCLK_DIV_SEL			GENMASK(11, 8)
41 #define     PCLK_DIV_REG_TO_VAL(x)	((x + 1) << 1)
42 #define CLK_SELECTION_REG5		0x314
43 #define   HCLK_DIV_SEL			GENMASK(30, 28)
44 #define     HCLK_DIV_REG_TO_VAL(x)	((x == 0) ? 2 : x + 1)
45 
46 struct clock_aspeed_config {
47 	const struct device *syscon;
48 };
49 
50 #define DEV_CFG(dev) ((const struct clock_aspeed_config *const)(dev)->config)
51 
aspeed_clock_control_on(const struct device * dev,clock_control_subsys_t sub_system)52 static int aspeed_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system)
53 {
54 	const struct device *syscon = DEV_CFG(dev)->syscon;
55 	uint32_t clk_gate = (uint32_t)sub_system;
56 	uint32_t addr = CLK_STOP_CTRL0_CLEAR;
57 
58 	/* there is no on/off control for group2 clocks */
59 	if (clk_gate >= ASPEED_CLK_GRP_2_OFFSET) {
60 		return 0;
61 	}
62 
63 	if (clk_gate >= ASPEED_CLK_GRP_1_OFFSET) {
64 		clk_gate -= ASPEED_CLK_GRP_1_OFFSET;
65 		addr = CLK_STOP_CTRL1_CLEAR;
66 	}
67 
68 	syscon_write_reg(syscon, addr, BIT(clk_gate));
69 
70 	return 0;
71 }
72 
aspeed_clock_control_off(const struct device * dev,clock_control_subsys_t sub_system)73 static int aspeed_clock_control_off(const struct device *dev, clock_control_subsys_t sub_system)
74 {
75 	const struct device *syscon = DEV_CFG(dev)->syscon;
76 	uint32_t clk_gate = (uint32_t)sub_system;
77 	uint32_t addr = CLK_STOP_CTRL0_SET;
78 
79 	/* there is no on/off control for group2 clocks */
80 	if (clk_gate >= ASPEED_CLK_GRP_2_OFFSET) {
81 		return 0;
82 	}
83 
84 	if (clk_gate >= ASPEED_CLK_GRP_1_OFFSET) {
85 		clk_gate -= ASPEED_CLK_GRP_1_OFFSET;
86 		addr = CLK_STOP_CTRL1_SET;
87 	}
88 
89 	syscon_write_reg(syscon, addr, BIT(clk_gate));
90 
91 	return 0;
92 }
93 
aspeed_clock_control_get_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)94 static int aspeed_clock_control_get_rate(const struct device *dev,
95 					 clock_control_subsys_t sub_system, uint32_t *rate)
96 {
97 	const struct device *syscon = DEV_CFG(dev)->syscon;
98 	uint32_t clk_id = (uint32_t)sub_system;
99 	uint32_t reg, src, clk_div;
100 
101 	switch (clk_id) {
102 	case ASPEED_CLK_I3C0:
103 	case ASPEED_CLK_I3C1:
104 	case ASPEED_CLK_I3C2:
105 	case ASPEED_CLK_I3C3:
106 		syscon_read_reg(syscon, CLK_SELECTION_REG4, &reg);
107 		if (FIELD_GET(I3C_CLK_SRC_SEL, reg) == I3C_CLK_SRC_HPLL) {
108 			src = HPLL_FREQ;
109 		} else {
110 			src = MHZ(480);
111 		}
112 		clk_div = I3C_CLK_DIV_REG_TO_VAL(FIELD_GET(I3C_CLK_DIV_SEL, reg));
113 		*rate = src / clk_div;
114 		break;
115 	case ASPEED_CLK_HCLK:
116 		src = HPLL_FREQ;
117 		syscon_read_reg(syscon, CLK_SELECTION_REG5, &reg);
118 		clk_div = HCLK_DIV_REG_TO_VAL(FIELD_GET(HCLK_DIV_SEL, reg));
119 		*rate = src / clk_div;
120 		break;
121 	case ASPEED_CLK_PCLK:
122 		src = HPLL_FREQ;
123 		syscon_read_reg(syscon, CLK_SELECTION_REG4, &reg);
124 		clk_div = PCLK_DIV_REG_TO_VAL(FIELD_GET(PCLK_DIV_SEL, reg));
125 		*rate = src / clk_div;
126 		break;
127 	case ASPEED_CLK_UART1:
128 	case ASPEED_CLK_UART2:
129 	case ASPEED_CLK_UART3:
130 	case ASPEED_CLK_UART4:
131 	case ASPEED_CLK_UART5:
132 	case ASPEED_CLK_UART6:
133 	case ASPEED_CLK_UART7:
134 	case ASPEED_CLK_UART8:
135 	case ASPEED_CLK_UART9:
136 	case ASPEED_CLK_UART10:
137 	case ASPEED_CLK_UART11:
138 	case ASPEED_CLK_UART12:
139 	case ASPEED_CLK_UART13:
140 		*rate = MHZ(24) / 13;
141 		break;
142 	default:
143 		return -EINVAL;
144 	}
145 
146 	return 0;
147 }
148 
149 static const struct clock_control_driver_api aspeed_clk_api = {
150 	.on = aspeed_clock_control_on,
151 	.off = aspeed_clock_control_off,
152 	.get_rate = aspeed_clock_control_get_rate,
153 };
154 
155 #define ASPEED_CLOCK_INIT(n)                                                                       \
156 	static const struct clock_aspeed_config clock_aspeed_cfg_##n = {                           \
157 		.syscon = DEVICE_DT_GET(DT_NODELABEL(syscon)),                                     \
158 	};                                                                                         \
159 	DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, &clock_aspeed_cfg_##n, PRE_KERNEL_1,            \
160 			      CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &aspeed_clk_api);
161 
162 DT_INST_FOREACH_STATUS_OKAY(ASPEED_CLOCK_INIT)
163