Skip to content

Commit bbe3b13

Browse files
Qinghao ShiQinghao Shi
authored andcommitted
add lan91c111 drivers for FVP MPS2 platfrom
1 parent 8a2044b commit bbe3b13

File tree

2 files changed

+781
-0
lines changed

2 files changed

+781
-0
lines changed
Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
#include "lan91c111.h"
19+
#include <stddef.h>
20+
21+
static lan91_handle_t *lan91c111_handle;
22+
23+
void LAN91_init(void)
24+
{
25+
26+
uint32_t tcr, stat;
27+
28+
LAN91_ClearInterruptMasks();
29+
LAN91_Reset();
30+
31+
/* Clear control registers. */
32+
LAN91_SelectBank(0);
33+
LREG(uint16_t, B0_RCR) = 0;
34+
LREG(uint16_t, B0_TCR) = 0;
35+
36+
/* Write Configuration Registers */
37+
LAN91_SelectBank(1);
38+
LREG(uint16_t, B1_CR) = CR_EPH_POW_EN | CR_DEFAULT;
39+
40+
/* Reset the PHY*/
41+
write_PHY(0, 0x8000);
42+
43+
/* clear phy 18 status */
44+
read_PHY(18);
45+
46+
/* Use 100MBit link speed by default. */
47+
LAN91_SelectBank(0);
48+
LREG(uint16_t, B0_RPCR) = RPCR_SPEED | LEDA_10M_100M | LEDB_TX_RX;
49+
50+
/* Read Status Register */
51+
stat = read_PHY(18);
52+
53+
/* Set the Control Register */
54+
LAN91_SelectBank(1);
55+
LREG(uint16_t, B1_CTR) = CTR_LE_ENABLE | CTR_CR_ENABLE | CTR_TE_ENABLE | CTR_AUTO_REL | CTR_DEFAULT;
56+
57+
/* Setup Transmit Control Register. */
58+
tcr = TCR_TXENA | TCR_PAD_EN;
59+
if (stat & 0x0040) {
60+
tcr |= TCR_FDUPLX;
61+
}
62+
LREG(uint16_t, B0_TCR) = (uint16_t)tcr;
63+
64+
/* Reset MMU */
65+
LAN91_SelectBank(2);
66+
LREG(uint16_t, B2_MMUCR) = MMU_RESET;
67+
while (LREG(uint16_t, B2_MMUCR) & MMUCR_BUSY);
68+
69+
/* Configure the Interrupts, allow RX_OVRN and RCV intr. */
70+
LAN91_SetInterruptMasks(MSK_RCV);
71+
72+
/* Set all buffers or data in handler for data transmit/receive process. */
73+
LAN91_SetHandler();
74+
}
75+
76+
void read_MACaddr(uint8_t *addr)
77+
{
78+
int i;
79+
80+
LAN91_SelectBank(1);
81+
82+
i = LREG(uint16_t, B1_IAR0);
83+
addr[0] = (uint8_t)i;
84+
addr[1] = (uint8_t)(i >> 8);
85+
86+
i = LREG(uint16_t, B1_IAR2);
87+
addr[2] = (uint8_t)i;
88+
addr[3] = (uint8_t)(i >> 8);
89+
90+
i = LREG(uint16_t, B1_IAR4);
91+
addr[4] = (uint8_t)i;
92+
addr[5] = (uint8_t)(i >> 8);
93+
}
94+
95+
void LAN91_SetCallback(lan91_callback_t callback, void *userData)
96+
{
97+
/* Set callback and userData. */
98+
lan91c111_handle->callback = callback;
99+
lan91c111_handle->userData = userData;
100+
}
101+
102+
103+
bool LAN91_send_frame(uint32_t *buff, uint32_t *size)
104+
{
105+
/* Send frame to Lan91C111 ethernet controller */
106+
uint16_t *dp;
107+
uint8_t packnr;
108+
int i;
109+
110+
LAN91_SelectBank(2);
111+
112+
/* MMU allocate memory for transmitting*/
113+
LREG(uint16_t, B2_MMUCR) = MMU_ALLOC_TX;
114+
115+
/* Check if Interrupt Status Register been set for MMU Allocate Ready */
116+
if (!(LREG(uint16_t, B2_IST) & IST_ALLOC_INT))
117+
{
118+
/* Failed, Reset MMU */
119+
LREG(uint16_t, B2_MMUCR) = MMU_RESET;
120+
while (LREG(uint16_t, B2_MMUCR) & MMUCR_BUSY);
121+
return false;
122+
}
123+
124+
/* set TX package number from allocated package number
125+
and also set pointer register as Auto Increase, write and transmit set */
126+
packnr = LREG(uint8_t, B2_ARR);
127+
LREG(uint8_t, B2_PNR) = packnr;
128+
LREG(uint16_t, B2_PTR) = PTR_AUTO_INCR;
129+
130+
/* Reserve space for Status Word */
131+
LREG(uint16_t, B2_DATA0) = 0x0000;
132+
/* Total = Raw Data Size + STATUS WORD + BYTE COUNT + CONTROL BYTE + LAST BYTE */
133+
LREG(uint16_t, B2_DATA0) = (uint16_t) * size + 6;
134+
135+
/* Copy frame data to Ethernet controller */
136+
dp = (uint16_t *)buff;
137+
for (i = *size; i > 1; i -= 2) {
138+
LREG(uint16_t, B2_DATA0) = *dp++;
139+
}
140+
141+
/* If data is odd , Add a control word and odd byte. */
142+
if (i) {
143+
LREG(uint16_t, B2_DATA0) = (RFC_CRC | RFC_ODD) | (*dp & 0xFF);
144+
} else {
145+
/* Add control word. */
146+
LREG(uint16_t, B2_DATA0) = RFC_CRC;
147+
}
148+
149+
LAN91_SelectBank(0);
150+
/* Enable transmitter. */
151+
LREG(uint16_t, B0_TCR) = TCR_TXENA | TCR_PAD_EN;
152+
153+
/* Enqueue the packet. */
154+
LAN91_SelectBank(2);
155+
LREG(uint16_t, B2_MMUCR) = MMU_ENQ_TX;
156+
157+
return true;
158+
}
159+
160+
161+
162+
bool LAN91_receive_frame(uint32_t *buff, uint32_t *size)
163+
{
164+
uint32_t State, RxLen;
165+
uint32_t val, *dp;
166+
167+
/* No receive packets queued in Rx FIFO queue */
168+
LAN91_SelectBank(2);
169+
State = LREG(uint16_t, B2_FIFO);
170+
if (State & FIFO_REMPTY) {
171+
return false;
172+
}
173+
174+
175+
/* Pointer Register set to RCV + Auto Increase + Read access
176+
So that Data Register is use RX FIFO*/
177+
LREG(uint16_t, B2_PTR) = PTR_RCV | PTR_AUTO_INCR | PTR_READ;
178+
179+
/* Read status word and packet length */
180+
val = LREG(uint32_t, B2_DATA);
181+
State = val & 0xFFFF;
182+
/* Raw Data Size = Total - STATUS WORD - BYTE COUNT - CONTROL BYTE - LAST BYTE */
183+
RxLen = (val >> 16) - 6;
184+
185+
/* Check State word if Odd number of bytes in a frame. */
186+
if (State & RFS_ODDFRM) {
187+
RxLen++;
188+
}
189+
190+
/* Packet too big, ignore it and free MMU and continue */
191+
if (RxLen > LAN91_ETH_MTU_SIZE) {
192+
LREG(uint16_t, B2_MMUCR) = MMU_REMV_REL_RX;
193+
return false;
194+
}
195+
196+
if (buff != NULL) {
197+
/* Make sure that block is dword aligned */
198+
RxLen = (RxLen + 3) >> 2;
199+
*size = RxLen << 2;
200+
dp = buff;
201+
for (; RxLen; RxLen--) {
202+
*dp++ = LREG(uint32_t, B2_DATA);
203+
}
204+
}
205+
206+
/* MMU free packet. Remove and Relase from TOP of RX */
207+
LREG(uint16_t, B2_MMUCR) = MMU_REMV_REL_RX;
208+
209+
return true;
210+
}
211+
212+
213+
214+
void ETHERNET_Handler(void)
215+
{
216+
LAN91_SelectBank(2);
217+
if((LREG(uint8_t, B2_IST) & IST_RCV) !=0)
218+
{
219+
LREG(uint8_t, B2_MSK) = 0;
220+
/* Callback function. */
221+
if (lan91c111_handle->callback) {
222+
lan91c111_handle->callback(LAN91_RxEvent, lan91c111_handle->userData);
223+
}
224+
}
225+
}
226+
227+
228+
lan91_phy_status_t LAN91_GetLinkStatus(void)
229+
{
230+
if (read_PHY(0x2u) & 0x4u)
231+
{
232+
return STATE_LINK_UP;
233+
}
234+
else
235+
{
236+
return STATE_LINK_DOWN;
237+
}
238+
}
239+
240+
static void output_MDO(int bit_value)
241+
{
242+
uint32_t val = MGMT_MDOE;
243+
244+
if (bit_value) {
245+
val |= MGMT_MDO;
246+
}
247+
LREG(uint16_t, B3_MGMT) = (uint16_t)val;
248+
LREG(uint16_t, B3_MGMT) = (uint16_t)(val | MGMT_MCLK);
249+
LREG(uint16_t, B3_MGMT) = (uint16_t)val;
250+
}
251+
252+
253+
254+
static int input_MDI(void)
255+
{
256+
int val = 0;
257+
258+
LREG(uint16_t, B3_MGMT) = 0;
259+
LREG(uint16_t, B3_MGMT) = MGMT_MCLK;
260+
if (LREG(uint16_t, B3_MGMT) & MGMT_MDI) {
261+
val = 1;
262+
}
263+
LREG(uint16_t, B3_MGMT) = 0;
264+
return (val);
265+
}
266+
267+
static void write_PHY(uint32_t PhyReg, int Value)
268+
{
269+
int i;
270+
271+
LAN91_SelectBank(3);
272+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO;
273+
274+
/* 32 consecutive ones on MDO to establish sync */
275+
for (i = 0; i < 32; i++) {
276+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO;
277+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO | MGMT_MCLK;
278+
}
279+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE;
280+
281+
/* start code (01) */
282+
output_MDO(0);
283+
output_MDO(1);
284+
285+
/* write command (01) */
286+
output_MDO(0);
287+
output_MDO(1);
288+
289+
/* write PHY address - which is five 0s for 91C111 */
290+
for (i = 0; i < 5; i++) {
291+
output_MDO(0);
292+
}
293+
294+
/* write the PHY register to write (highest bit first) */
295+
for (i = 0; i < 5; i++) {
296+
output_MDO((PhyReg >> 4) & 0x01);
297+
PhyReg <<= 1;
298+
}
299+
300+
/* turnaround MDO */
301+
output_MDO(1);
302+
output_MDO(0);
303+
304+
/* write the data value (highest bit first) */
305+
for (i = 0; i < 16; i++) {
306+
output_MDO((Value >> 15) & 0x01);
307+
Value <<= 1;
308+
}
309+
310+
/* turnaround MDO is tristated */
311+
LREG(uint16_t, B3_MGMT) = 0;
312+
LREG(uint16_t, B3_MGMT) = MGMT_MCLK;
313+
LREG(uint16_t, B3_MGMT) = 0;
314+
}
315+
316+
317+
static uint16_t read_PHY(uint32_t PhyReg)
318+
{
319+
int i, val;
320+
321+
LAN91_SelectBank(3);
322+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO;
323+
324+
/* 32 consecutive ones on MDO to establish sync */
325+
for (i = 0; i < 32; i++) {
326+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO;
327+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE | MGMT_MDO | MGMT_MCLK;
328+
}
329+
LREG(uint16_t, B3_MGMT) = MGMT_MDOE;
330+
331+
/* start code (01) */
332+
output_MDO(0);
333+
output_MDO(1);
334+
335+
/* read command (10) */
336+
output_MDO(1);
337+
output_MDO(0);
338+
339+
/* write PHY address - which is five 0s for 91C111 */
340+
for (i = 0; i < 5; i++) {
341+
output_MDO(0);
342+
}
343+
344+
/* write the PHY register to read (highest bit first) */
345+
for (i = 0; i < 5; i++) {
346+
output_MDO((PhyReg >> 4) & 0x01);
347+
PhyReg <<= 1;
348+
}
349+
350+
/* turnaround MDO is tristated */
351+
LREG(uint16_t, B3_MGMT) = 0;
352+
LREG(uint16_t, B3_MGMT) = MGMT_MCLK;
353+
LREG(uint16_t, B3_MGMT) = 0;
354+
355+
/* read the data value */
356+
val = 0;
357+
for (i = 0; i < 16; i++) {
358+
val <<= 1;
359+
val |= input_MDI();
360+
}
361+
362+
/* turnaround MDO is tristated */
363+
LREG(uint16_t, B3_MGMT) = 0;
364+
LREG(uint16_t, B3_MGMT) = MGMT_MCLK;
365+
LREG(uint16_t, B3_MGMT) = 0;
366+
367+
return (val);
368+
}

0 commit comments

Comments
 (0)