1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the People's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sunxi_hal_geth.h>
34
random_ether_addr(uint8_t * addr)35 void random_ether_addr(uint8_t *addr)
36 {
37 uint32_t sid3;
38
39 /*
40 * F133 chipid the start address is located at 0x03006200.
41 * SID total of 128bits,the offset 0x0c is variable.
42 */
43 sid3 = hal_readl(0x03006200 + 0xc);
44
45 /*
46 * DC-44-6D from ieee official licensed to Allwinner.
47 * on here, for testing purposes only.
48 */
49 addr[0] = 0xDC;
50 addr[1] = 0x44;
51 addr[2] = 0x6D;
52 addr[3] = sid3 & 0xFFu;
53 addr[4] = (sid3 >> 8) & 0xFFu;
54 addr[5] = (sid3 >> 16) & 0xFFu;
55 }
56
geth_set_link_mode(unsigned long iobase,int duplex,int speed)57 void geth_set_link_mode(unsigned long iobase, int duplex, int speed)
58 {
59 uint32_t value;
60
61 value = hal_readl(iobase + GETH_BASIC_CTL0);
62 if (!duplex)
63 value &= ~CTL0_DM;
64 else
65 value |= CTL0_DM;
66
67 switch (speed) {
68 case 1000:
69 value &= ~0x0C;
70 break;
71 case 100:
72 case 10:
73 default:
74 value |= 0x08;
75 if (speed == 100)
76 value |= 0x04;
77 else
78 value &= ~0x04;
79 break;
80 }
81
82 hal_writel(value, iobase + GETH_BASIC_CTL0);
83 }
84
geth_mac_loopback(unsigned long iobase,int enable)85 void geth_mac_loopback(unsigned long iobase, int enable)
86 {
87 uint32_t value;
88
89 value = hal_readl(iobase + GETH_BASIC_CTL0);
90 if (enable)
91 value |= 0x02;
92 else
93 value &= ~0x02;
94
95 hal_writel(value, iobase + GETH_BASIC_CTL0);
96 }
97
geth_start_tx(unsigned long iobase)98 void geth_start_tx(unsigned long iobase)
99 {
100 uint32_t value;
101
102 value = hal_readl(iobase + GETH_TX_CTL1);
103 value |= (1 << 30);
104 hal_writel(value, iobase + GETH_TX_CTL1);
105 }
106
geth_stop_tx(unsigned long iobase)107 void geth_stop_tx(unsigned long iobase)
108 {
109 uint32_t value;
110
111 value = hal_readl(iobase + GETH_TX_CTL1);
112 value &= ~(1 << 30);
113 hal_writel(value, iobase + GETH_TX_CTL1);
114 }
115
geth_start_rx(unsigned long iobase)116 void geth_start_rx(unsigned long iobase)
117 {
118 uint32_t value;
119
120 value = hal_readl(iobase + GETH_RX_CTL1);
121 value |= (1 << 30);
122 hal_writel(value, iobase + GETH_RX_CTL1);
123 }
124
geth_stop_rx(unsigned long iobase)125 void geth_stop_rx(unsigned long iobase)
126 {
127 uint32_t value;
128
129 value = hal_readl(iobase + GETH_RX_CTL1);
130 value &= ~(1 << 30);
131 hal_writel(value, iobase + GETH_RX_CTL1);
132 }
133
geth_loopback_enable(unsigned long iobase)134 void geth_loopback_enable(unsigned long iobase)
135 {
136 uint32_t value;
137
138 value = hal_readl(iobase + GETH_BASIC_CTL0);
139 value |= (1 << 0);
140 hal_writel(value, iobase + GETH_BASIC_CTL0);
141 }
142
geth_loopback_disable(unsigned long iobase)143 void geth_loopback_disable(unsigned long iobase)
144 {
145 uint32_t value;
146
147 value = hal_readl(iobase + GETH_BASIC_CTL0);
148 value &= ~(1 << 0);
149 hal_writel(value, iobase + GETH_BASIC_CTL0);
150 }
151
geth_mac_reset(unsigned long iobase)152 uint32_t geth_mac_reset(unsigned long iobase)
153 {
154 uint32_t value;
155
156 /* Soft reset all registers and logic */
157 value = hal_readl(iobase + GETH_BASIC_CTL1);
158 value |= SOFT_RST;
159 hal_writel(value, iobase + GETH_BASIC_CTL1);
160
161 while(value)
162 {
163 rt_thread_delay(10);
164 value = (hal_readl(iobase + GETH_BASIC_CTL1) & SOFT_RST);
165 }
166 return !!value;
167 }
168
geth_mac_init(unsigned long iobase)169 void geth_mac_init(unsigned long iobase)
170 {
171 uint32_t value;
172
173 value = hal_readl(iobase + GETH_TX_CTL1);
174 /* Transmit COE type 2 cannot be done in cut-through mode. */
175 value |= TX_MD;
176 hal_writel(value, iobase + GETH_TX_CTL1);
177
178 value = hal_readl(iobase + GETH_RX_CTL0);
179 hal_writel((0x3 << 20), iobase + GETH_MDIO_ADDR); /* MDC_DIV_RATIO */
180
181 value = hal_readl(iobase + GETH_RX_CTL1);
182 value |= RX_MD;
183 /* Forward frames with error and undersized good frame. */
184 value |= (RX_ERR_FRM | RX_RUNT_FRM );
185 hal_writel(value, iobase + GETH_RX_CTL1);
186 }
187
geth_set_filter(unsigned long iobase)188 void geth_set_filter(unsigned long iobase)
189 {
190 uint32_t value;
191
192 value = hal_readl(iobase + GETH_RX_FRM_FLT);
193 value |= 0x1;
194 hal_writel(value, iobase + GETH_RX_FRM_FLT);
195 }
196
geth_set_mac_addr(unsigned long iobase,unsigned char * addr,int index)197 void geth_set_mac_addr(unsigned long iobase, unsigned char *addr, int index)
198 {
199 uint32_t value;
200
201 value = (addr[5] << 8) | addr[4];
202 hal_writel(value, iobase + GETH_ADDR_HI(index));
203
204 value = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
205 hal_writel(value, iobase + GETH_ADDR_LO(index));
206 }
207
geth_mac_enable(unsigned long iobase)208 void geth_mac_enable(unsigned long iobase)
209 {
210 uint32_t value;
211
212 value = hal_readl(iobase + GETH_TX_CTL0);
213 value |= (1 << 31);
214 hal_writel(value, iobase + GETH_TX_CTL0);
215
216 value = hal_readl(iobase + GETH_RX_CTL0);
217 value |= (1 << 31);
218 hal_writel(value, iobase + GETH_RX_CTL0);
219 }
220
geth_mac_disable(unsigned long iobase)221 void geth_mac_disable(unsigned long iobase)
222 {
223 uint32_t value;
224
225 value = hal_readl(iobase + GETH_TX_CTL0);
226 value &= ~(1 << 31);
227 hal_writel(value, iobase + GETH_TX_CTL0);
228
229 value = hal_readl(iobase + GETH_RX_CTL0);
230 value &= ~(1 << 31);
231 hal_writel(value, iobase + GETH_RX_CTL0);
232 }
233
geth_tx_poll(unsigned long iobase)234 void geth_tx_poll(unsigned long iobase)
235 {
236 uint32_t value;
237
238 value = hal_readl(iobase + GETH_TX_CTL1);
239 value |= (1 << 31);
240 hal_writel(value, iobase + GETH_TX_CTL1);
241 }
242
geth_rx_poll(unsigned long iobase)243 void geth_rx_poll(unsigned long iobase)
244 {
245 uint32_t value;
246
247 value = hal_readl(iobase + GETH_RX_CTL1);
248 value |= (1 << 31);
249 hal_writel(value, iobase + GETH_RX_CTL1);
250 }
251
geth_flush_tx(unsigned long iobase)252 void geth_flush_tx(unsigned long iobase)
253 {
254 uint32_t value;
255
256 value = hal_readl(iobase + GETH_TX_CTL1);
257 value |= 0x1;
258 hal_writel(value, iobase + GETH_TX_CTL1);
259 }
260
261
geth_rx_int_enable(unsigned long iobase)262 void geth_rx_int_enable(unsigned long iobase)
263 {
264 uint32_t value = 0;
265 value |= RX_INT;
266 hal_writel(value , iobase + GETH_INT_EN);
267 }
268
geth_tx_int_enable(unsigned long iobase)269 void geth_tx_int_enable(unsigned long iobase)
270 {
271 uint32_t value = 0;
272 value |= (TX_INT | TX_STOP_INT | TX_UA_INT | TX_TOUT_INT | TX_UNF_INT);
273 hal_writel(value, iobase + GETH_INT_EN);
274 }
275
geth_rx_int_disable(unsigned long iobase)276 void geth_rx_int_disable(unsigned long iobase)
277 {
278 uint32_t value = 0;
279 value = hal_readl(iobase + GETH_INT_EN);
280 value &= ~RX_INT;
281 hal_writel(value , iobase + GETH_INT_EN);}
282
geth_tx_int_disable(unsigned long iobase)283 void geth_tx_int_disable(unsigned long iobase)
284 {
285 uint32_t value = 0;
286 value = hal_readl(iobase + GETH_INT_EN);
287 value &= ~TX_INT;
288 hal_writel(value, iobase + GETH_INT_EN);
289 }
290
geth_all_int_disable(unsigned long iobase)291 void geth_all_int_disable(unsigned long iobase)
292 {
293 hal_writel(0, iobase + GETH_INT_EN);
294 }
295
geth_clk_enable(uint32_t used_type,uint32_t phy_interface,uint32_t tx_delay,uint32_t rx_delay)296 void geth_clk_enable(uint32_t used_type,uint32_t phy_interface,uint32_t tx_delay,uint32_t rx_delay)
297 {
298 uint32_t value;
299 uint32_t reg_val;
300
301 /* Enalbe clk for gmac */
302 value = hal_readl(CCMU_BASE + CCMU_GETH_CLK_REG);
303 value |= (1 << CCMU_GETH_RST_BIT);
304 value |= (1 << CCMU_GETH_GATING_BIT);
305 hal_writel(value, CCMU_BASE + CCMU_GETH_CLK_REG);
306
307 /* Enable clk for ephy */
308 #ifdef USE_EPHY25M
309 value = hal_readl(CCMU_BASE + CCMU_EPHY_CLK_REG);
310 value |= (1 << CCMU_EPHY_PLL_PERI0_GATING_BIT);
311 value |= (1 << CCMU_EPHY_SCLK_GATING_BIT);
312 hal_writel(value, CCMU_BASE + CCMU_EPHY_CLK_REG);
313 #endif
314
315 /* Set phy clock */
316 value = hal_readl(PHY_CLK_REG);
317
318 if (used_type == INT_PHY){
319 reg_val = hal_readl(CCMU_BASE + 0x0070);
320 reg_val |= (1 << 0);
321 hal_writel(reg_val, CCMU_BASE + 0x0070);
322
323 reg_val = hal_readl(CCMU_BASE + 0x02c8);
324 reg_val |= (1 << 2);
325 hal_writel(reg_val, CCMU_BASE + 0x02c8);
326
327 value |= (1 << 15);
328 value &= ~(1 << 16);
329 value |= (3 << 17);
330 } else {
331 value &= ~(1 << 15);
332 value |= (1 << 16);
333 }
334
335 if (phy_interface == PHY_INTERFACE_MODE_RGMII) {
336 value |= 0x00000004;
337 } else {
338 value &= ~0x00000004;
339 }
340
341 value &= ~0x00002003;
342 if (phy_interface == PHY_INTERFACE_MODE_RGMII
343 || phy_interface == PHY_INTERFACE_MODE_GMII) {
344 value |= 0x00000002;
345 } else if (phy_interface == PHY_INTERFACE_MODE_RMII) {
346 value |= 0x00002001;
347 }
348 /* Adjust Tx/Rx clock delay */
349 value &= ~(0x07 << 10);
350 value |= ((tx_delay & 0x07) << 10);
351 value &= ~(0x1f << 5);
352 value |= ((rx_delay & 0x1f) << 5);
353
354 hal_writel(value, PHY_CLK_REG);
355
356 }
357
geth_clk_disable(void)358 void geth_clk_disable(void)
359 {
360 uint32_t value;
361
362 /* Disalbe clk for gmac */
363 value = hal_readl(CCMU_BASE + CCMU_GETH_CLK_REG);
364 value &= ~(1 << CCMU_GETH_RST_BIT);
365 value &= ~(1 << CCMU_GETH_GATING_BIT);
366 hal_writel(value, CCMU_BASE + CCMU_GETH_CLK_REG);
367
368 /* Disable clk for ephy */
369 #ifdef USE_EPHY25M
370 value = hal_readl(CCMU_BASE + CCMU_EPHY_CLK_REG);
371 value &= ~(1 << CCMU_EPHY_PLL_PERI0_GATING_BIT);
372 value &= ~(1 << CCMU_EPHY_SCLK_GATING_BIT);
373 hal_writel(value, CCMU_BASE + CCMU_EPHY_CLK_REG);
374 #endif
375 }
376
geth_mdio_read(unsigned long iobase,int phy_addr,u8 reg)377 uint32_t geth_mdio_read(unsigned long iobase, int phy_addr, u8 reg)
378 {
379 uint32_t value = 0;
380
381 value |= (0x06 << 20);
382 value |= (((phy_addr << 12) & (0x0001F000)) |
383 ((reg << 4) & (0x000007F0)) |
384 MII_BUSY);
385
386 hal_writel(value, iobase + GETH_MDIO_ADDR);
387 while (hal_readl(iobase + GETH_MDIO_ADDR) & MII_BUSY)
388 ;
389
390 return (uint32_t)hal_readl(iobase + GETH_MDIO_DATA);
391 }
392
geth_mdio_write(unsigned long iobase,int phy_addr,u8 reg,u16 data)393 uint32_t geth_mdio_write(unsigned long iobase, int phy_addr, u8 reg, u16 data)
394 {
395 uint32_t value = 0;
396
397 value |= (0x06 << 20);
398 value |= (((phy_addr << 12) & (0x0001F000)) |
399 ((reg << 4) & (0x000007F0)) |
400 MII_WRITE | MII_BUSY);
401
402 /* Set the MII address register to write */
403 hal_writel(data, iobase + GETH_MDIO_DATA);
404 hal_writel(value, iobase + GETH_MDIO_ADDR);
405
406 /* Wait until any existing MII operation is complete */
407 while (hal_readl(iobase + GETH_MDIO_ADDR) & MII_BUSY)
408 ;
409
410 return 0;
411 }
412