1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Description: Hieth system operation
18 */
19
20
21 #include <config.h>
22 #include "hieth.h"
23 #include "sys.h"
24
25 #if defined(CONFIG_GODBOX) || defined(CONFIG_GODBOX_V1)
26 #define HIETH_CRG_REG (REG_BASE_CRG + REG_PERI_CRG26)
27 #else
28 #define HIETH_CRG_REG (CRG_REG_BASE + REG_ETH_CRG)
29 #endif
30
31 #define ETH_SOFT_RESET bit(0)
32 #if defined(CONFIG_GODBOX) || defined(CONFIG_GODBOX_V1)
33 #define ETH_CLK_ENABLE bit(8)
34 #elif defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
35 #define ETH_CLK_ENABLE bit(4)
36 #else
37 #define ETH_CLK_ENABLE bit(1)
38 #endif
39
40 #if defined(HISFV_RESET_PHY_BY_CRG)
41 #if defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
42 #define ETH_EXTERNAL_PHY_RESET bit(0)
43 #else
44 #define ETH_EXTERNAL_PHY_RESET bit(3)
45 #endif
46 #endif
47
48 #if defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
49 #define ETH_CORE_CLK_SELECT_54M bit(12)
50 #else
51 #define ETH_CORE_CLK_SELECT_54M bit(7)
52 #endif
53
54 #if defined(CONFIG_HI3520D)
55 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + PERIPHCTRL24)
56 #define ETH_INTERNAL_PHY_RESET bit(2)
57 #define HIETH_EFUSE_REG (CRG_REG_BASE + EFUSE_CTRL_CRG)
58 #define HIETH_EFUSE_DATA_REG (EFUSE_REG_BASE + EFUSE_DATA_SEL)
59 #elif defined(CONFIG_HI3536DV100)
60 #define HIETH_SYSCTL_REG (MISC_REG_BASE + REG_FEPHY_CTRL1)
61 #define BIT_FEPHY_SEL bit(5)
62 #define BIT_PHY_RMII_MODE bit(8)
63 #define ETH_INTERNAL_PHY_RESET bit(9)
64 #define ETH_INTERNAL_PHY_CLK_EN bit(10)
65 #endif
66
67 #if defined(CONFIG_TARGET_HI3516EV200)
68 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
69 #define ETH_INTERNAL_PHY_RESET bit(3)
70 #define ETH_INTERNAL_PHY_CLK_EN bit(2)
71 #endif
72
73 #if defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
74 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + REG_FEPHY_CTRL0)
75 #define ETH_INTERNAL_PHY_RESET bit(0)
76 #define ETH_INTERNAL_PHY_CLK_EN bit(4)
77 #endif
78
79 #if defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
80 #define HIETH_CRG_INPHY_CLK_REG (CRG_REG_BASE + REG_INFEPHY_CLK_RST)
81 #define HIETH_CRG_EXTPHY_CLK_REG (CRG_REG_BASE + REG_EXTFEPHY_CLK_RST)
82 #else
83 #define HIETH_CRG_INPHY_CLK_REG HIETH_CRG_REG
84 #define HIETH_CRG_EXTPHY_CLK_REG HIETH_CRG_REG
85 #endif
86
87 #if defined(CONFIG_TARGET_HI3516EV300)
88 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
89 #define ETH_INTERNAL_PHY_RESET bit(3)
90 #define ETH_INTERNAL_PHY_CLK_EN bit(2)
91 #endif
92
93 #if defined(CONFIG_TARGET_HI3518EV300)
94 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
95 #define ETH_INTERNAL_PHY_RESET bit(3)
96 #define ETH_INTERNAL_PHY_CLK_EN bit(2)
97 #endif
98
99 #if defined(CONFIG_TARGET_HI3516DV200)
100 #define HIETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
101 #define ETH_INTERNAL_PHY_RESET bit(3)
102 #define ETH_INTERNAL_PHY_CLK_EN bit(2)
103 #endif
104
105 #if defined(CONFIG_HI3536DV100)
hieth_use_fephy(void)106 static unsigned char hieth_use_fephy(void)
107 {
108 return !(readl(HIETH_SYSCTL_REG) & BIT_FEPHY_SEL);
109 }
110 #endif
111
112 #if defined(INNER_PHY) && defined(CONFIG_HI3520D)
set_efuse_unread(void)113 void set_efuse_unread(void)
114 {
115 u32 reg_value;
116
117 reg_value = readl(HIETH_EFUSE_REG);
118 reg_value |= 0x1;
119 writel(reg_value, HIETH_EFUSE_REG);
120
121 reg_value = readl(HIETH_EFUSE_DATA_REG);
122 reg_value |= 0x1;
123 writel(reg_value, HIETH_EFUSE_DATA_REG);
124
125 mdelay(300); /* delay 300ms */
126
127 reg_value = readl(HIETH_EFUSE_REG);
128 reg_value &= ~0x1;
129 writel(reg_value, HIETH_EFUSE_REG);
130 }
131 #else
set_efuse_unread(void)132 void set_efuse_unread(void)
133 {
134 }
135 #endif
136
137 #ifdef INNER_PHY
set_inner_phy_addr(u32 phy_addr)138 void set_inner_phy_addr(u32 phy_addr)
139 {
140 u32 reg_value;
141
142 #if defined(CONFIG_HI3536DV100)
143 if (!hieth_use_fephy())
144 phy_addr += 1;
145 #endif
146 reg_value = readl(HIETH_SYSCTL_REG);
147 reg_value &= ~0x1f;
148 phy_addr &= 0x1f;
149 reg_value |= phy_addr;
150 writel(reg_value, HIETH_SYSCTL_REG);
151 }
152 #else
set_inner_phy_addr(u32 phyaddr)153 void set_inner_phy_addr(u32 phyaddr)
154 {
155 }
156 #endif
157
158 #if defined(INNER_PHY) && defined(CONFIG_HI3520D)
revise_led_shine(void)159 void revise_led_shine(void)
160 {
161 #define MDIO_RWCTRL 0x1100
162 #define tmp_mdio_ready() \
163 (readl(REG_BASE_SF + MDIO_RWCTRL) & bit(15))
164
165 unsigned int reg_value;
166 /* select page 7 */
167 do {
168 reg_value = 0x0007235f;
169 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
170 udelay(10); /* delay 10us */
171 } while (!tmp_mdio_ready());
172
173 /* enable LED modify function */
174 do {
175 reg_value = 0xc03c2353;
176 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
177 udelay(10); /* delay 10us */
178 } while (!tmp_mdio_ready());
179
180 /* set green LED shine all the while when link up,
181 * yellow LED blink when data coming
182 */
183 do {
184 reg_value = 0x00382351;
185 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
186 udelay(10); /* delay 10us */
187 } while (!tmp_mdio_ready());
188
189 return;
190 }
191 #else
revise_led_shine(void)192 void revise_led_shine(void)
193 {
194 }
195 #endif
196
197 #if defined(INNER_PHY) && defined(CONFIG_HI3520D)
set_phy_valtage(void)198 void set_phy_valtage(void)
199 {
200 #define MDIO_RWCTRL 0x1100
201 #define tmp_mdio_ready() \
202 (readl(REG_BASE_SF + MDIO_RWCTRL) & bit(15))
203
204 unsigned int reg_value;
205 /* select page 1 */
206 do {
207 reg_value = 0x0001235f;
208 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
209 udelay(10); /* delay 10us */
210 } while (!tmp_mdio_ready());
211
212 /* set fe-phy in lower valtage */
213 do {
214 reg_value = 0x94482352;
215 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
216 udelay(10); /* delay 10us */
217 } while (!tmp_mdio_ready());
218
219 /* select page 0 */
220 do {
221 reg_value = 0x0000235f;
222 writel(reg_value, REG_BASE_SF + MDIO_RWCTRL);
223 udelay(10); /* delay 10us */
224 } while (!tmp_mdio_ready());
225 }
226 #else
set_phy_valtage(void)227 void set_phy_valtage(void)
228 {
229 }
230 #endif
231
hieth_reset(int rst)232 static void hieth_reset(int rst)
233 {
234 u32 val;
235
236 val = _readl(HIETH_CRG_REG);
237 if (rst) {
238 val |= ETH_SOFT_RESET;
239 } else {
240 val &= ~ETH_SOFT_RESET;
241 }
242 _writel(val, HIETH_CRG_REG);
243
244 udelay(100); /* delay 100us */
245 }
246
hieth_clk_ena(void)247 static inline void hieth_clk_ena(void)
248 {
249 u32 val = _readl(HIETH_CRG_REG);
250 val |= (ETH_CORE_CLK_SELECT_54M | ETH_CLK_ENABLE);
251 _writel(val, HIETH_CRG_REG);
252 }
253
hieth_clk_dis(void)254 static inline void hieth_clk_dis(void)
255 {
256 u32 val = _readl(HIETH_CRG_REG);
257 val &= ~ETH_CLK_ENABLE;
258 _writel(val, HIETH_CRG_REG);
259 }
260
261 #if defined(CONFIG_HI3536DV100) || defined(INNER_PHY)
hieth_fephy_trim(void)262 static void hieth_fephy_trim(void)
263 {
264 /* To simplify internal FEPHY trim process,
265 * we just delay 300ms to wait FEPHY auto-trim completed.
266 * Not read trim data from EFUSE register.
267 */
268 mdelay(350); /* delay 350ms */
269 }
270 #endif
271
272 #if defined(CONFIG_HI3536DV100)
hieth_set_crg_phy_mode(unsigned char is_rmii_mode)273 void hieth_set_crg_phy_mode(unsigned char is_rmii_mode)
274 {
275 u32 val;
276
277 val = readl(HIETH_CRG_REG);
278 if (is_rmii_mode) {
279 val |= BIT_PHY_RMII_MODE;
280 } else {
281 val &= ~BIT_PHY_RMII_MODE;
282 }
283 writel(val, HIETH_CRG_REG);
284 }
285 #endif
286
hieth_reset_internal_phy(void)287 static void hieth_reset_internal_phy(void)
288 {
289 #ifdef INNER_PHY
290 u32 rst;
291
292 #if defined(CONFIG_HI3536DV100)
293 if (!hieth_use_fephy()) {
294 return;
295 }
296 #endif
297 /* disable MDCK clock to make sure FEPHY reset success */
298 hieth_clk_dis();
299
300 rst = readl(HIETH_CRG_INPHY_CLK_REG);
301 rst |= ETH_INTERNAL_PHY_CLK_EN;
302 /* internal FEPHY only support MII mode */
303 #if defined(CONFIG_HI3536DV100)
304 rst &= ~BIT_PHY_RMII_MODE;
305 #endif
306 writel(rst, HIETH_CRG_INPHY_CLK_REG);
307 udelay(10); /* delay 10us */
308
309 rst = _readl(HIETH_CRG_INPHY_CLK_REG);
310 rst |= ETH_INTERNAL_PHY_RESET;
311 _writel(rst, HIETH_CRG_INPHY_CLK_REG);
312 /* delay at least 10ms */
313 mdelay(15); /* delay 15ms */
314
315 rst = _readl(HIETH_CRG_INPHY_CLK_REG);
316 rst &= ~ETH_INTERNAL_PHY_RESET;
317 _writel(rst, HIETH_CRG_INPHY_CLK_REG);
318 /* delay at least 15ms for MDIO operation */
319 mdelay(20); /* delay 20ms */
320
321 hieth_clk_ena();
322 /* delay 5ms after enable MDCK to make sure FEPHY trim safe */
323 mdelay(5); /* delay 5ms */
324 hieth_fephy_trim();
325 #endif
326 }
327
hieth_reset_external_phy_by_crg(void)328 static void hieth_reset_external_phy_by_crg(void)
329 {
330 #if defined(HISFV_RESET_PHY_BY_CRG)
331 u32 v;
332
333 /************************************************/
334 /* reset external phy with default reset pin */
335 v = readl(HIETH_CRG_EXTPHY_CLK_REG);
336 v |= ETH_EXTERNAL_PHY_RESET;
337 writel(v, HIETH_CRG_EXTPHY_CLK_REG);
338
339 mdelay(50); /* delay 50ms */
340
341 /* then, cancel reset, and should delay some time */
342 v = readl(HIETH_CRG_EXTPHY_CLK_REG);
343 v &= ~ETH_EXTERNAL_PHY_RESET;
344 writel(v, HIETH_CRG_EXTPHY_CLK_REG);
345
346 mdelay(50); /* delay 50ms */
347 #endif
348 }
349
hieth_reset_external_phy_by_gpio(void)350 static void hieth_reset_external_phy_by_gpio(void)
351 {
352 #ifdef HISFV_RESET_GPIO_EN
353 unsigned int val;
354 /* gpiox[x] set to reset, then delay 200ms */
355 val = __raw_readw(HISFV_RESET_GPIO_BASE + HISFV_RESET_GPIO_DIR);
356 val |= (HISFV_RESET_GPIO_DIR_OUT << HISFV_RESET_GPIO_BIT);
357 __raw_writew(val, HISFV_RESET_GPIO_BASE + HISFV_RESET_GPIO_DIR);
358 __raw_writew(HISFV_RESET_GPIO_DATA,
359 HISFV_RESET_GPIO_BASE +
360 (4 << HISFV_RESET_GPIO_BIT)); /* offset addr 4 */
361
362 mdelay(200); /* delay 200ms */
363
364 /* then,cancel reset,and should delay 200ms */
365 val = __raw_readw(HISFV_RESET_GPIO_BASE + HISFV_RESET_GPIO_DIR);
366 val |= (HISFV_RESET_GPIO_DIR_OUT << HISFV_RESET_GPIO_BIT);
367 __raw_writew(val, HISFV_RESET_GPIO_BASE + HISFV_RESET_GPIO_DIR);
368 __raw_writew(((!HISFV_RESET_GPIO_DATA) << HISFV_RESET_GPIO_BIT),
369 HISFV_RESET_GPIO_BASE +
370 (4 << HISFV_RESET_GPIO_BIT)); /* offset addr 4 */
371
372 mdelay(20); /* delay 20ms */
373 #endif
374 }
375
hieth_phy_reset(void)376 static void hieth_phy_reset(void)
377 {
378 hieth_reset_internal_phy();
379 hieth_reset_external_phy_by_crg();
380 hieth_reset_external_phy_by_gpio();
381 }
382
hieth_funsel_config(void)383 static void hieth_funsel_config(void)
384 {
385 }
386
hieth_funsel_restore(void)387 static void hieth_funsel_restore(void)
388 {
389 }
390
391 /**************************************************/
hieth_sys_startup(void)392 void hieth_sys_startup(void)
393 {
394 hieth_clk_ena();
395 /* undo reset */
396 hieth_reset(0);
397 }
398
hieth_sys_allstop(void)399 void hieth_sys_allstop(void)
400 {
401 }
402
hieth_sys_init(void)403 void hieth_sys_init(void)
404 {
405 hieth_funsel_config();
406 hieth_sys_allstop();
407 hieth_clk_ena();
408 hieth_reset(1);
409 hieth_reset(0);
410 hieth_phy_reset();
411 revise_led_shine();
412 }
413
hieth_sys_exit(void)414 void hieth_sys_exit(void)
415 {
416 hieth_funsel_restore();
417 hieth_sys_allstop();
418 }
419