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