1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-02-16     Tuber             first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14 #include <netif/ethernetif.h>
15 #include "drv_eth.h"
16 
17 #ifdef BSP_USING_ETH
18 
19 static struct eth_device eth_device;
20 
21 //DMA接收内存区,必须4字节对齐
22 __align(4) UINT8 eth_dma_tx_buf[ETH_BUF_SIZE];
23 __align(4) UINT8 eth_dma_rx_buf[ETH_BUF_SIZE];
24 
25 UINT16 eth_rx_len = 0; //接收状态和长度
26 UINT8 eth_rx_buf[ETH_BUF_SIZE]; //中间缓冲区
27 
28 UINT8 eth_mac_addr[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
29 
eth_init(rt_device_t dev)30 static rt_err_t eth_init(rt_device_t dev)
31 {
32     return RT_EOK;
33 }
34 
eth_open(rt_device_t dev,rt_uint16_t oflag)35 static rt_err_t eth_open(rt_device_t dev, rt_uint16_t oflag)
36 {
37     return RT_EOK;
38 }
39 
eth_close(rt_device_t dev)40 static rt_err_t eth_close(rt_device_t dev)
41 {
42     return RT_EOK;
43 }
44 
eth_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)45 static rt_ssize_t eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
46 {
47     rt_set_errno(-RT_ENOSYS);
48     return 0;
49 }
50 
eth_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)51 static rt_ssize_t eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
52 {
53     rt_set_errno(-RT_ENOSYS);
54     return 0;
55 }
56 
eth_control(rt_device_t dev,int cmd,void * args)57 static rt_err_t eth_control(rt_device_t dev, int cmd, void *args)
58 {
59     switch (cmd)
60     {
61     case NIOCTL_GADDR:
62         /* get mac address */
63         if (args) rt_memcpy(args, eth_mac_addr, 6);
64         else return -RT_ERROR;
65         break;
66     default :
67         break;
68     }
69 
70     return RT_EOK;
71 }
72 
eth_tx(rt_device_t dev,struct pbuf * p)73 rt_err_t eth_tx(rt_device_t dev, struct pbuf *p)
74 {
75     //判断eth是否处于发送状态
76     if ((R8_ETH_ECON1 & RB_ETH_ECON1_TXRTS) != 0x00)
77     {
78         return ERR_INPROGRESS;
79     }
80 
81     //确定缓冲区是否足够
82     if (p->tot_len > sizeof(eth_dma_tx_buf))
83     {
84         return ERR_MEM;
85     }
86 
87     //拷贝数据到dma缓冲区
88     rt_memcpy(eth_dma_tx_buf, p->payload, p->tot_len);
89 
90     //设置数据长度
91     R16_ETH_ETXLN = p->tot_len;
92 
93     //开始发送
94     R8_ETH_ECON1 |= RB_ETH_ECON1_TXRTS;
95 
96     return ERR_OK;
97 }
98 
eth_rx(rt_device_t dev)99 struct pbuf *eth_rx(rt_device_t dev)
100 {
101     struct pbuf *p = NULL;
102 
103     //检查是否有数据
104     if (eth_rx_len == 0)
105     {
106         return NULL;
107     }
108 
109     p = pbuf_alloc(PBUF_RAW, eth_rx_len, PBUF_POOL);
110     if (p == NULL)
111     {
112         rt_kprintf("eth_rx: pbuf_alloc failed\n");
113         eth_rx_len = 0;
114         return NULL;
115     }
116 
117     //拷贝数据到pbuf
118     rt_memcpy((uint8_t *)((uint8_t *)p->payload), (uint8_t *)((uint8_t *)eth_rx_buf), eth_rx_len);
119     //恢复状态
120     eth_rx_len = 0;
121 
122     return p;
123 }
124 
read_eth_link_status()125 int read_eth_link_status()
126 {
127     R8_ETH_MIREGADR = 0x01;//状态寄存器
128     R8_ETH_MISTAT |= 0x00; //读MII寄存器
129 
130     //获取link状态
131     if ((R16_ETH_MIRD & 0x04) != 0)
132     {
133         return 1; //已插入
134     }
135 
136     return 0;
137 }
138 
ETH_IRQHandler(void)139 void ETH_IRQHandler(void) /* 以太网中断 */
140 {
141     rt_interrupt_enter();
142 
143     //接收到数据包
144     if ((R8_ETH_EIR & RB_ETH_EIR_RXIF) != 0)
145     {
146         //判断缓存区是否有数据
147         if (eth_rx_len == 0)
148         {
149             rt_memcpy(eth_rx_buf, eth_dma_rx_buf, R16_ETH_ERXLN);
150             eth_rx_len = R16_ETH_ERXLN;
151             //通知拿数据
152             eth_device_ready(&eth_device);
153         }
154 
155         R8_ETH_EIR |= RB_ETH_EIR_RXIF; //清除中断
156     }
157 
158     //接收错误
159     if ((R8_ETH_EIR & RB_ETH_EIE_RXERIE) != 0)
160     {
161         R8_ETH_EIR |= RB_ETH_EIE_RXERIE; //清除中断
162     }
163 
164     //发送完成
165     if ((R8_ETH_EIR & RB_ETH_EIR_TXIF) != 0)
166     {
167         R8_ETH_EIR |= RB_ETH_EIR_TXIF; //清除中断
168     }
169 
170     //发送错误
171     if ((R8_ETH_EIR & RB_ETH_EIE_TXERIE) != 0)
172     {
173         R8_ETH_EIR |= RB_ETH_EIE_TXERIE; //清除中断
174     }
175 
176     //Link 变化标志
177     if ((R8_ETH_EIR & RB_ETH_EIR_LINKIF) != 0)
178     {
179         //获取连接状态
180         if (read_eth_link_status())
181         {
182             eth_device_linkchange(&eth_device, RT_TRUE);
183             rt_kprintf("eth1: link is up\n");
184         }
185         else
186         {
187             eth_device_linkchange(&eth_device, RT_FALSE);
188             rt_kprintf("eth1: link is down\n");
189         }
190 
191         R8_ETH_EIR |= RB_ETH_EIR_LINKIF; //清除中断
192     }
193 
194     rt_interrupt_leave();
195 }
196 
rt_hw_eth_init(void)197 int rt_hw_eth_init(void)
198 {
199     //使能ETH引脚
200     R16_PIN_ANALOG_IE |= RB_PIN_ETH_IE;
201 
202     //进入安全访问模式
203     R8_SAFE_ACCESS_SIG = 0x57;
204     R8_SAFE_ACCESS_SIG = 0xA8;
205     //打开以太网时钟
206     R8_SLP_CLK_OFF1 &= (~RB_SLP_CLK_ETH);
207     //打开以太网电源
208     R8_SLP_POWER_CTRL &= (~RB_SLP_ETH_PWR_DN);
209     //退出安全访问模式
210     R8_SAFE_ACCESS_SIG = 0x00;
211 
212     //开启以太网中断
213     R8_ETH_EIE |= RB_ETH_EIE_INTIE;
214     //启用以太网接收中断
215     R8_ETH_EIE |= RB_ETH_EIE_RXIE;
216     //R8_ETH_EIE |= RB_ETH_EIE_RXERIE;
217     //启用以太网发送中断
218     R8_ETH_EIE |= RB_ETH_EIR_TXIF;
219     R8_ETH_EIE |= RB_ETH_EIR_TXERIF;
220     //启用Link变化中断
221     R8_ETH_EIE |= RB_ETH_EIE_LINKIE;
222     //启用内置的50欧姆阻抗匹配电阻
223     R8_ETH_EIE |= RB_ETH_EIE_R_EN50;
224 
225     //配置接收过滤模式
226     R8_ETH_ERXFCON = RB_ETH_ERXFCON_ANDOR | RB_ETH_ERXFCON_CRCEN;
227 
228     //设置发送dma
229     R16_ETH_ETXST = (uint32_t)eth_dma_tx_buf;
230     //设置接收dma
231     R16_ETH_ERXST = (uint32_t)eth_dma_rx_buf;
232     //设置最大接收长度
233     R16_ETH_MAMXFL = sizeof(eth_dma_rx_buf);
234 
235     //使能MAC层接收
236     R8_ETH_MACON1 |= RB_ETH_MACON1_MARXEN;
237     //开启硬件CRC
238     R8_ETH_MACON2 |= RB_ETH_MACON2_TXCRCEN;
239     //所有短包填充0至60字节,再4字节 CRC
240     R8_ETH_MACON2 |= 0x20;
241     //使能接收
242     R8_ETH_ECON1 |= RB_ETH_ECON1_RXEN;
243 
244     //开启中断
245     NVIC_EnableIRQ(ETH_IRQn);
246 
247     //设置回调函数
248     eth_device.parent.init       = eth_init;
249     eth_device.parent.open       = eth_open;
250     eth_device.parent.close      = eth_close;
251     eth_device.parent.read       = eth_read;
252     eth_device.parent.write      = eth_write;
253     eth_device.parent.control    = eth_control;
254     eth_device.parent.user_data  = RT_NULL;
255     eth_device.eth_rx            = eth_rx;
256     eth_device.eth_tx            = eth_tx;
257 
258     return eth_device_init(&(eth_device), "e0");
259 }
260 INIT_DEVICE_EXPORT(rt_hw_eth_init);
261 #endif /* BSP_USING_ETH */
262