1 /*
2  * Copyright (c) 2018 Synopsys, Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/devicetree.h>
8 #include "sysconf.h"
9 
10 /* default system clock */
11 #define SYSCLK_DEFAULT_IOSC_HZ			MHZ(16)
12 
13 #define PLL_CLK_IN	(SYSCLK_DEFAULT_IOSC_HZ / 1000000)  /* PLL clock in */
14 
15 
16 #define sysconf_reg_ptr ((sysconf_reg_t *)(DT_REG_ADDR(DT_NODELABEL(sysconf))))
17 
18 
19 typedef struct pll_conf {
20 	uint32_t fout;
21 	uint32_t pll;
22 } pll_conf_t;
23 
24 #define PLL_CONF_VAL(n, m, od) \
25 	(((n) << PLLCON_BIT_OFFSET_N) | \
26 	((m) << (PLLCON_BIT_OFFSET_M)) | \
27 	((od) << PLLCON_BIT_OFFSET_OD))
28 
29 
30 /* the following configuration is based on Fin = 16 Mhz */
31 static const pll_conf_t pll_configuration[] = {
32 	{100, PLL_CONF_VAL(1, 25, 2)},  /* 100 Mhz */
33 	{50,  PLL_CONF_VAL(1, 25, 3)},  /* 50 Mhz */
34 	{150, PLL_CONF_VAL(4, 75, 1)},  /* 150 Mhz */
35 	{75,  PLL_CONF_VAL(4, 75, 2)},  /* 75 Mhz */
36 	{25,  PLL_CONF_VAL(2, 25, 3)},  /* 25 Mhz */
37 	{72,  PLL_CONF_VAL(8, 144, 2)}, /* 72 Mhz */
38 	{144, PLL_CONF_VAL(8, 144, 1)}, /* 144 Mhz */
39 };
40 
41 
42 /**
43  * PLL Fout = Fin * M/ (N *n NO)
44  *
45  * Fref = Fin / N; Fvco = Fref * M Fout = Fvco / NO
46  *
47  *  N = input divider value (1, 2, 3 … 15)
48  *  M = feedback divider value (4, 5, 6 … 16383)
49  *  NO = output divider value (1, 2, 4, or 8)
50  *
51  *  1 Mhz <= Fref <= 50 Mhz
52  *  200 Mhz <= Fvco <= 400 Mhz
53  *
54  */
arc_iot_pll_conf_reg(uint32_t val)55 void arc_iot_pll_conf_reg(uint32_t val)
56 {
57 
58 	sysconf_reg_ptr->CLKSEL = CLKSEL_EXT_16M;
59 	/* 0x52000000 is not described in spec. */
60 	sysconf_reg_ptr->PLLCON = val | (0x52000000);
61 
62 	sysconf_reg_ptr->PLLCON = val | (1 << PLLCON_BIT_OFFSET_PLLRST);
63 	sysconf_reg_ptr->PLLCON = val & (~(1 << PLLCON_BIT_OFFSET_PLLRST));
64 
65 	while (!(sysconf_reg_ptr->PLLSTAT & (1 << PLLSTAT_BIT_OFFSET_PLLSTB))) {
66 		;
67 	}
68 
69 	sysconf_reg_ptr->CLKSEL = CLKSEL_PLL;
70 	/* from AHB_CLK_DIVIDER, not from DVFSS&PMC */
71 	sysconf_reg_ptr->AHBCLKDIV_SEL |= 1;
72 	/* AHB clk divisor = 1 */
73 	sysconf_reg_ptr->AHBCLKDIV = 0x1;
74 }
75 
arc_iot_pll_fout_config(uint32_t freq)76 int32_t arc_iot_pll_fout_config(uint32_t freq)
77 {
78 	uint32_t i;
79 
80 	if (freq == PLL_CLK_IN) {
81 		sysconf_reg_ptr->CLKSEL = CLKSEL_EXT_16M;
82 	}
83 
84 	for (i = 0U; i < ARRAY_SIZE(pll_configuration); i++) {
85 		if (pll_configuration[i].fout == freq) {
86 			break;
87 		}
88 	}
89 
90 	if (i >= ARRAY_SIZE(pll_configuration)) {
91 		return -1;
92 	}
93 
94 	/* config eflash clk, must be < 100 Mhz */
95 	if (freq > 100) {
96 		arc_iot_eflash_clk_div(2);
97 	} else {
98 		arc_iot_eflash_clk_div(1);
99 	}
100 
101 	arc_iot_pll_conf_reg(pll_configuration[i].pll);
102 
103 	return 0;
104 }
105 
arc_iot_ahb_clk_divisor(uint8_t div)106 void arc_iot_ahb_clk_divisor(uint8_t div)
107 {
108 	sysconf_reg_ptr->AHBCLKDIV = div;
109 }
110 
arc_iot_ahb_clk_enable(uint8_t dev)111 void arc_iot_ahb_clk_enable(uint8_t dev)
112 {
113 	if (dev > AHBCLKEN_BIT_SDIO) {
114 		return;
115 	}
116 
117 	sysconf_reg_ptr->AHBCLKEN |= (1 << dev);
118 }
119 
arc_iot_ahb_clk_disable(uint8_t dev)120 void arc_iot_ahb_clk_disable(uint8_t dev)
121 {
122 	if (dev > AHBCLKEN_BIT_SDIO) {
123 		return;
124 	}
125 
126 	sysconf_reg_ptr->AHBCLKEN &= (~(1 << dev));
127 }
128 
arc_iot_apb_clk_divisor(uint8_t div)129 void arc_iot_apb_clk_divisor(uint8_t div)
130 {
131 	sysconf_reg_ptr->APBCLKDIV = div;
132 }
133 
arc_iot_apb_clk_enable(uint8_t dev)134 void arc_iot_apb_clk_enable(uint8_t dev)
135 {
136 	if (dev > APBCLKEN_BIT_I3C) {
137 		return;
138 	}
139 
140 	sysconf_reg_ptr->APBCLKEN |= (1 << dev);
141 }
142 
arc_iot_apb_clk_disable(uint8_t dev)143 void arc_iot_apb_clk_disable(uint8_t dev)
144 {
145 	if (dev > APBCLKEN_BIT_I3C) {
146 		return;
147 	}
148 
149 	sysconf_reg_ptr->APBCLKEN &= (~(1 << dev));
150 }
151 
arc_iot_dio_clk_divisor(uint8_t div)152 void arc_iot_dio_clk_divisor(uint8_t div)
153 {
154 	sysconf_reg_ptr->SDIO_REFCLK_DIV;
155 }
156 
arc_iot_spi_master_clk_divisor(uint8_t id,uint8_t div)157 void arc_iot_spi_master_clk_divisor(uint8_t id, uint8_t div)
158 {
159 	if (id == SPI_MASTER_0) {
160 		sysconf_reg_ptr->SPI_MST_CLKDIV =
161 		    (sysconf_reg_ptr->SPI_MST_CLKDIV & 0xffffff00) | div;
162 	} else if (id == SPI_MASTER_1) {
163 		sysconf_reg_ptr->SPI_MST_CLKDIV =
164 		    (sysconf_reg_ptr->SPI_MST_CLKDIV & 0xffff00ff) | (div << 8);
165 	} else if (id == SPI_MASTER_2) {
166 		sysconf_reg_ptr->SPI_MST_CLKDIV =
167 		    (sysconf_reg_ptr->SPI_MST_CLKDIV & 0xff00ffff) | (div << 16);
168 	}
169 }
170 
arc_iot_gpio8b_dbclk_div(uint8_t bank,uint8_t div)171 void arc_iot_gpio8b_dbclk_div(uint8_t bank, uint8_t div)
172 {
173 	if (bank == GPIO8B_BANK0) {
174 		sysconf_reg_ptr->GPIO8B_DBCLK_DIV =
175 		    (sysconf_reg_ptr->GPIO8B_DBCLK_DIV & 0xffffff00) | div;
176 	} else if (bank == GPIO8B_BANK1) {
177 		sysconf_reg_ptr->GPIO8B_DBCLK_DIV =
178 		    (sysconf_reg_ptr->GPIO8B_DBCLK_DIV & 0xffff00ff) | (div << 8);
179 	} else if (bank == GPIO8B_BANK2) {
180 		sysconf_reg_ptr->GPIO8B_DBCLK_DIV =
181 		    (sysconf_reg_ptr->GPIO8B_DBCLK_DIV & 0xff00ffff) | (div << 16);
182 	} else if (bank == GPIO8B_BANK3) {
183 		sysconf_reg_ptr->GPIO8B_DBCLK_DIV =
184 		    (sysconf_reg_ptr->GPIO8B_DBCLK_DIV & 0x00ffffff) | (div << 24);
185 	}
186 }
187 
arc_iot_gpio4b_dbclk_div(uint8_t bank,uint8_t div)188 void arc_iot_gpio4b_dbclk_div(uint8_t bank, uint8_t div)
189 {
190 	if (bank == GPIO4B_BANK0) {
191 		sysconf_reg_ptr->GPIO4B_DBCLK_DIV =
192 		    (sysconf_reg_ptr->GPIO4B_DBCLK_DIV & 0xffffff00) | div;
193 	} else if (bank == GPIO4B_BANK1) {
194 		sysconf_reg_ptr->GPIO4B_DBCLK_DIV =
195 		    (sysconf_reg_ptr->GPIO4B_DBCLK_DIV & 0xffff00ff) | (div << 8);
196 	} else if (bank == GPIO4B_BANK2) {
197 		sysconf_reg_ptr->GPIO4B_DBCLK_DIV =
198 		    (sysconf_reg_ptr->GPIO4B_DBCLK_DIV & 0xff00ffff) | (div << 16);
199 	}
200 }
201 
arc_iot_i2s_tx_clk_div(uint8_t div)202 void arc_iot_i2s_tx_clk_div(uint8_t div)
203 {
204 	sysconf_reg_ptr->I2S_TX_SCLKDIV = div;
205 }
206 
arc_iot_i2s_rx_clk_div(uint8_t div)207 void arc_iot_i2s_rx_clk_div(uint8_t div)
208 {
209 	sysconf_reg_ptr->I2S_RX_SCLKDIV = div;
210 }
211 
arc_iot_i2s_rx_clk_sel(uint8_t sel)212 void arc_iot_i2s_rx_clk_sel(uint8_t sel)
213 {
214 	sysconf_reg_ptr->I2S_RX_SCLKSEL = sel;
215 }
216 
arc_iot_syscon_reset(void)217 void arc_iot_syscon_reset(void)
218 {
219 	sysconf_reg_ptr->RSTCON = 0x55AA6699;
220 }
221 
arc_iot_is_poweron_rst(void)222 uint32_t arc_iot_is_poweron_rst(void)
223 {
224 	if (sysconf_reg_ptr->RSTSTAT & SYS_RST_SOFTWARE_ON) {
225 		return 0;
226 	} else {
227 		return 1;
228 	}
229 }
230 
arc_iot_dvfs_clk_divisor(uint8_t level,uint8_t div)231 void arc_iot_dvfs_clk_divisor(uint8_t level, uint8_t div)
232 {
233 	if (level == DVFS_PERF_LEVEL0) {
234 		sysconf_reg_ptr->DVFS_CLKDIV =
235 		    (sysconf_reg_ptr->DVFS_CLKDIV & 0xffffff00) | div;
236 	} else if (level == DVFS_PERF_LEVEL1) {
237 		sysconf_reg_ptr->DVFS_CLKDIV =
238 		    (sysconf_reg_ptr->DVFS_CLKDIV & 0xffff00ff) | (div << 8);
239 	} else if (level == DVFS_PERF_LEVEL2) {
240 		sysconf_reg_ptr->DVFS_CLKDIV =
241 		    (sysconf_reg_ptr->DVFS_CLKDIV & 0xff00ffff) | (div << 16);
242 	} else if (level == DVFS_PERF_LEVEL3) {
243 		sysconf_reg_ptr->DVFS_CLKDIV =
244 		    (sysconf_reg_ptr->DVFS_CLKDIV & 0x00ffffff) | (div << 24);
245 	}
246 }
247 
arc_iot_dvfs_vdd_config(uint8_t level,uint8_t val)248 void arc_iot_dvfs_vdd_config(uint8_t level, uint8_t val)
249 {
250 	val &= 0xf;
251 
252 	if (level == DVFS_PERF_LEVEL0) {
253 		sysconf_reg_ptr->DVFS_VDDSET =
254 		    (sysconf_reg_ptr->DVFS_VDDSET & 0xfffffff0) | val;
255 	} else if (level == DVFS_PERF_LEVEL1) {
256 		sysconf_reg_ptr->DVFS_VDDSET =
257 		    (sysconf_reg_ptr->DVFS_VDDSET & 0xffffff0f) | (val << 4);
258 	} else if (level == DVFS_PERF_LEVEL2) {
259 		sysconf_reg_ptr->DVFS_VDDSET =
260 		    (sysconf_reg_ptr->DVFS_VDDSET & 0xfffff0ff) | (val << 8);
261 	} else if (level == DVFS_PERF_LEVEL3) {
262 		sysconf_reg_ptr->DVFS_CLKDIV =
263 		    (sysconf_reg_ptr->DVFS_CLKDIV & 0xffff0fff) | (val << 12);
264 	}
265 }
266 
arc_iot_dvfs_vwtime_config(uint8_t time)267 void arc_iot_dvfs_vwtime_config(uint8_t time)
268 {
269 	sysconf_reg_ptr->DVFS_VWTIME = time;
270 }
271 
arc_iot_pmc_pwwtime_config(uint8_t time)272 void arc_iot_pmc_pwwtime_config(uint8_t time)
273 {
274 	sysconf_reg_ptr->PMC_PUWTIME = time;
275 }
276 
arc_iot_uart3_clk_divisor(uint8_t div)277 void arc_iot_uart3_clk_divisor(uint8_t div)
278 {
279 	sysconf_reg_ptr->UART3SCLK_DIV = div;
280 }
281 
arc_iot_reset_powerdown_vector(uint32_t addr)282 void arc_iot_reset_powerdown_vector(uint32_t addr)
283 {
284 	sysconf_reg_ptr->RESET_PD_VECTOR = addr;
285 }
286 
arc_iot_pwm_timer_pause(uint32_t id,uint32_t pause)287 void arc_iot_pwm_timer_pause(uint32_t id, uint32_t pause)
288 {
289 	uint32_t val = sysconf_reg_ptr->TIMER_PAUSE;
290 
291 	if (id > PWM_TIMER5) {
292 		return;
293 	}
294 
295 	if (pause) {
296 		val |= (1 << id);
297 	} else {
298 		val &= (~(1 << id));
299 	}
300 
301 	sysconf_reg_ptr->TIMER_PAUSE = val;
302 }
303 
arc_iot_eflash_clk_div(uint8_t div)304 void arc_iot_eflash_clk_div(uint8_t div)
305 {
306 	sysconf_reg_ptr->AHBCLKDIV |= (div << 8);
307 }
308