blob: d042ef631dc515745d27ad9dae6cdb1035403cd3 [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <kernel/thread.h>
24#include <kernel/mutex.h>
25#include <platform/at91sam7.h>
26#include <platform/debug.h>
27
28#include <dev/ethernet.h>
29
30#include <malloc.h>
31#include <string.h>
32
33#include <hw/mii.h>
34
35void emac_init_send(void);
36
37#define PHYA 31
38
39static unsigned mi_rd(AT91EMAC *emac, unsigned addr)
40{
41 addr &= 0x1f;
42
43 thread_sleep(20);
44
45 emac->MAN =
46 (1 << 30) | /* sof: 01 */
47 (2 << 28) | /* rw: 10 = read */
48 (PHYA << 23) | /* phya: PHYA */
49 (addr << 18) | /* rega: addr */
50 (2 << 16); /* code: 10 */
51
52 while(!(emac->NSR & NSR_IDLE)) ;
53
54 thread_sleep(20);
55 return emac->MAN & 0xffff;
56}
57
58static void mi_wr(AT91EMAC *emac, unsigned addr, unsigned val)
59{
60 addr &= 0x1f;
61 val &= 0xffff;
62
63 emac->MAN =
64 (1 << 30) | /* sof: 01 */
65 (1 << 28) | /* rw: 01 = read */
66 (PHYA << 23) | /* phya: PHYA */
67 (addr << 18) | /* rega: addr */
68 (2 << 16) | /* code: 10 */
69 val; /* data: val */
70
71 while(!(emac->NSR & NSR_IDLE)) ;
72}
73
74#define PIN_EMAC_ALL 0x3ffff
75#define PIN_PHY_PD (1 << 18)
76#define PIN_PHY_IRQ (1 << 26)
77
78#define PIN_PHYAD0 (1 << 26)
79#define PIN_PHYAD1 (1 << 14)
80#define PIN_PHYAD2 (1 << 13)
81#define PIN_PHYAD3 (1 << 6)
82#define PIN_PHYAD4 (1 << 5)
83#define PIN_LPBK (1 << 15)
84#define PIN_ISOLATE (1 << 7)
85#define PIN_RMII_MODE (1 << 16)
86#define PIN_RMII_BTB (1 << 4)
87
88/* select RMII w/ BTB, 100mbps duplex autonegotiate
89** disable ISOLATE and LPBK
90** phya=00001b
91*/
92#define PIN_RESET_LOW (PIN_LPBK)
93
94int emac_init(void)
95{
96 AT91EMAC *emac = AT91EMAC_ADDR;
97 AT91PIO *piob = AT91PIOB_ADDR;
98 AT91PMC *pmc = AT91PMC_ADDR;
99 AT91RSTC *rstc = AT91RSTC_ADDR;
100
101 dprintf("emac_init()\n");
102
103 /* enable clock to EMAC */
104 pmc->PCER = (1 << PID_EMAC);
105
106 thread_sleep(10);
107
108 /* for reset, all lines are gpio inputs and pullups are
109 enabled or disabled per strapping mode defined above */
110 piob->pio_enable = PIN_EMAC_ALL | PIN_PHY_PD | PIN_PHY_IRQ;
111 piob->select_a = PIN_EMAC_ALL;
112 piob->pullup_enable = PIN_EMAC_ALL | PIN_PHY_IRQ;
113 piob->pullup_disable = PIN_LPBK | PIN_ISOLATE | PIN_RMII_MODE;
114 piob->output_disable = PIN_EMAC_ALL;
115
116 /* PHY PD becomes output and high (no powerdown mode */
117 piob->data_set = PIN_PHY_PD;
118 piob->output_enable = PIN_PHY_PD;
119
120 thread_sleep(30);
121
122 dprintf("emac_init() - reset phy\n");
123
124 /* assert the RST line and wait until the it deasserts */
125 rstc->CR = RSTC_KEY | RSTC_EXTRST;
126 while(rstc->SR & RSTC_NRSTL) ;
127
128 thread_sleep(30);
129
130 /* after reset all the gpios are assigned to the EMAC,
131 except for PHY_PD (which remains output and high) */
132 piob->pio_disable = PIN_EMAC_ALL;
133
134 emac->USRIO = USRIO_CLKEN;
135
136 thread_sleep(1000);
137
138 dprintf("emac_init() - read state\n");
139
140 emac->NCR = NCR_MPE;
141 emac->NCFG = NCFG_CLK_d64;
142
143 dprintf("bcr = %x\n", mi_rd(emac, MII_REG_BCR));
144 dprintf("id1 = %x\n", mi_rd(emac, MII_REG_PHY_ID1));
145 dprintf("id2 = %x\n", mi_rd(emac, MII_REG_PHY_ID2));
146
147#if 0
148 unsigned state, last;
149 last = 0xff;
150
151 for(;;) {
152 state = mi_rd(emac, MII_REG_100TX_PHY) & MII_100TX_MODE_MASK;
153 if(last != state) {
154 last = state;
155 char *name;
156 switch(state) {
157 case MII_100TX_MODE_AUTO:
158 name = "auto negotiate";
159 break;
160 case MII_100TX_MODE_10T_H:
161 name = "10-T half duplex";
162 break;
163 case MII_100TX_MODE_10T_F:
164 name = "10-T full duplex";
165 break;
166 case MII_100TX_MODE_100TX_H:
167 name = "100-TX half duplex";
168 break;
169 case MII_100TX_MODE_100TX_F:
170 name = "100-TX full duplex";
171 break;
172 case MII_100TX_MODE_ISOLATE:
173 name = "isolate";
174 break;
175 default:
176 name = "unknown";
177 }
178 dprintf("link state: %s\n", name);
179 }
180 thread_sleep(100);
181 }
182#endif
183
184 emac_init_send();
185
186 return 0;
187}
188
189#define XMIT_ENTRY_COUNT 32
190static emac_xmit_entry xmit_list[XMIT_ENTRY_COUNT];
191static unsigned xmit_next = 0;
192static mutex_t xmit_lock;
193
194void emac_init_send(void)
195{
196 AT91EMAC *emac = AT91EMAC_ADDR;
197 int i;
198
199 for(i = 0; i < XMIT_ENTRY_COUNT; i++) {
200 xmit_list[i].info = XMIT_USED;
201 xmit_list[i].addr = 0;
202 }
203 xmit_list[i-1].info |= XMIT_LAST;
204
205 emac->NCFG = NCFG_CLK_d64 | NCFG_SPD | NCFG_FD;
206 emac->NCR = NCR_TE | NCR_MPE;
207 emac->TBQP = (unsigned) xmit_list;
208
209 mutex_init(&xmit_lock);
210}
211
212int ethernet_send(void *data, unsigned len)
213{
214 AT91EMAC *emac = AT91EMAC_ADDR;
215
216 emac_xmit_entry *xe;
217 int waited = 0;
218
219 mutex_acquire(&xmit_lock);
220
221 xe = xmit_list + xmit_next;
222
223 while(!(xe->info & XMIT_USED)) {
224 thread_yield();
225 waited++;
226 }
227
228 if(waited) dprintf("W%d\n",waited);
229
230 if(xe->addr != 0) {
231 free((void*) xe->addr);
232 }
233
234 xe->addr = (unsigned) data;
235 if(xmit_next == (XMIT_ENTRY_COUNT - 1)) {
236 xe->info = XMIT_LENGTH(len) | XMIT_LAST | XMIT_WRAP;
237 xmit_next = 0;
238 } else {
239 xe->info = XMIT_LENGTH(len) | XMIT_LAST;
240 xmit_next++;
241 }
242
243 emac->NCR |= NCR_TSTART;
244
245 mutex_release(&xmit_lock);
246
247 return 0;
248}
249