~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to drivers/net/cs8900.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cirrus Logic CS8900A Ethernet
 
3
 *
 
4
 * (C) 2009 Ben Warren , biggerbadderben@gmail.com
 
5
 *     Converted to use CONFIG_NET_MULTI API
 
6
 *
 
7
 * (C) 2003 Wolfgang Denk, wd@denx.de
 
8
 *     Extension to synchronize ethaddr environment variable
 
9
 *     against value in EEPROM
 
10
 *
 
11
 * (C) Copyright 2002
 
12
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 
13
 * Marius Groeger <mgroeger@sysgo.de>
 
14
 *
 
15
 * Copyright (C) 1999 Ben Williamson <benw@pobox.com>
 
16
 *
 
17
 * See file CREDITS for list of people who contributed to this
 
18
 * project.
 
19
 *
 
20
 * This program is loaded into SRAM in bootstrap mode, where it waits
 
21
 * for commands on UART1 to read and write memory, jump to code etc.
 
22
 * A design goal for this program is to be entirely independent of the
 
23
 * target board.  Anything with a CL-PS7111 or EP7211 should be able to run
 
24
 * this code in bootstrap mode.  All the board specifics can be handled on
 
25
 * the host.
 
26
 *
 
27
 * This program is free software; you can redistribute it and/or modify
 
28
 * it under the terms of the GNU General Public License as published by
 
29
 * the Free Software Foundation; either version 2 of the License, or
 
30
 * (at your option) any later version.
 
31
 *
 
32
 * This program is distributed in the hope that it will be useful,
 
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
35
 * GNU General Public License for more details.
 
36
 *
 
37
 * You should have received a copy of the GNU General Public License
 
38
 * along with this program; if not, write to the Free Software
 
39
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
40
 */
 
41
 
 
42
#include <common.h>
 
43
#include <command.h>
 
44
#include <asm/io.h>
 
45
#include <net.h>
 
46
#include <malloc.h>
 
47
#include "cs8900.h"
 
48
 
 
49
#undef DEBUG
 
50
 
 
51
/* packet page register access functions */
 
52
 
 
53
#ifdef CONFIG_CS8900_BUS32
 
54
 
 
55
#define REG_WRITE(v, a) writel((v),(a))
 
56
#define REG_READ(a) readl((a))
 
57
 
 
58
/* we don't need 16 bit initialisation on 32 bit bus */
 
59
#define get_reg_init_bus(r,d) get_reg((r),(d))
 
60
 
 
61
#else
 
62
 
 
63
#define REG_WRITE(v, a) writew((v),(a))
 
64
#define REG_READ(a) readw((a))
 
65
 
 
66
static u16 get_reg_init_bus(struct eth_device *dev, int regno)
 
67
{
 
68
        /* force 16 bit busmode */
 
69
        volatile u8 c;
 
70
        struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
 
71
        uint8_t volatile * const iob = (uint8_t volatile * const)dev->iobase;
 
72
 
 
73
        c = readb(iob);
 
74
        c = readb(iob + 1);
 
75
        c = readb(iob);
 
76
        c = readb(iob + 1);
 
77
        c = readb(iob);
 
78
 
 
79
        REG_WRITE(regno, &priv->regs->pptr);
 
80
        return REG_READ(&priv->regs->pdata);
 
81
}
 
82
#endif
 
83
 
 
84
static u16 get_reg(struct eth_device *dev, int regno)
 
85
{
 
86
        struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
 
87
        REG_WRITE(regno, &priv->regs->pptr);
 
88
        return REG_READ(&priv->regs->pdata);
 
89
}
 
90
 
 
91
 
 
92
static void put_reg(struct eth_device *dev, int regno, u16 val)
 
93
{
 
94
        struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
 
95
        REG_WRITE(regno, &priv->regs->pptr);
 
96
        REG_WRITE(val, &priv->regs->pdata);
 
97
}
 
98
 
 
99
static void cs8900_reset(struct eth_device *dev)
 
100
{
 
101
        int tmo;
 
102
        u16 us;
 
103
 
 
104
        /* reset NIC */
 
105
        put_reg(dev, PP_SelfCTL, get_reg(dev, PP_SelfCTL) | PP_SelfCTL_Reset);
 
106
 
 
107
        /* wait for 200ms */
 
108
        udelay(200000);
 
109
        /* Wait until the chip is reset */
 
110
 
 
111
        tmo = get_timer(0) + 1 * CONFIG_SYS_HZ;
 
112
        while ((((us = get_reg_init_bus(dev, PP_SelfSTAT)) &
 
113
                PP_SelfSTAT_InitD) == 0) && tmo < get_timer(0))
 
114
                /*NOP*/;
 
115
}
 
116
 
 
117
static void cs8900_reginit(struct eth_device *dev)
 
118
{
 
119
        /* receive only error free packets addressed to this card */
 
120
        put_reg(dev, PP_RxCTL,
 
121
                PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK);
 
122
        /* do not generate any interrupts on receive operations */
 
123
        put_reg(dev, PP_RxCFG, 0);
 
124
        /* do not generate any interrupts on transmit operations */
 
125
        put_reg(dev, PP_TxCFG, 0);
 
126
        /* do not generate any interrupts on buffer operations */
 
127
        put_reg(dev, PP_BufCFG, 0);
 
128
        /* enable transmitter/receiver mode */
 
129
        put_reg(dev, PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
 
130
}
 
131
 
 
132
void cs8900_get_enetaddr(struct eth_device *dev)
 
133
{
 
134
        int i;
 
135
 
 
136
        /* verify chip id */
 
137
        if (get_reg_init_bus(dev, PP_ChipID) != 0x630e)
 
138
                return;
 
139
        cs8900_reset(dev);
 
140
        if ((get_reg(dev, PP_SelfSTAT) &
 
141
                (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) ==
 
142
                (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) {
 
143
 
 
144
                /* Load the MAC from EEPROM */
 
145
                for (i = 0; i < 3; i++) {
 
146
                        u32 Addr;
 
147
 
 
148
                        Addr = get_reg(dev, PP_IA + i * 2);
 
149
                        dev->enetaddr[i * 2] = Addr & 0xFF;
 
150
                        dev->enetaddr[i * 2 + 1] = Addr >> 8;
 
151
                }
 
152
        }
 
153
}
 
154
 
 
155
void cs8900_halt(struct eth_device *dev)
 
156
{
 
157
        /* disable transmitter/receiver mode */
 
158
        put_reg(dev, PP_LineCTL, 0);
 
159
 
 
160
        /* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */
 
161
        get_reg_init_bus(dev, PP_ChipID);
 
162
}
 
163
 
 
164
static int cs8900_init(struct eth_device *dev, bd_t * bd)
 
165
{
 
166
        uchar *enetaddr = dev->enetaddr;
 
167
        u16 id;
 
168
 
 
169
        /* verify chip id */
 
170
        id = get_reg_init_bus(dev, PP_ChipID);
 
171
        if (id != 0x630e) {
 
172
                printf ("CS8900 Ethernet chip not found: "
 
173
                        "ID=0x%04x instead 0x%04x\n", id, 0x630e);
 
174
                return 1;
 
175
        }
 
176
 
 
177
        cs8900_reset (dev);
 
178
        /* set the ethernet address */
 
179
        put_reg(dev, PP_IA + 0, enetaddr[0] | (enetaddr[1] << 8));
 
180
        put_reg(dev, PP_IA + 2, enetaddr[2] | (enetaddr[3] << 8));
 
181
        put_reg(dev, PP_IA + 4, enetaddr[4] | (enetaddr[5] << 8));
 
182
 
 
183
        cs8900_reginit(dev);
 
184
        return 0;
 
185
}
 
186
 
 
187
/* Get a data block via Ethernet */
 
188
static int cs8900_recv(struct eth_device *dev)
 
189
{
 
190
        int i;
 
191
        u16 rxlen;
 
192
        u16 *addr;
 
193
        u16 status;
 
194
 
 
195
        struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
 
196
 
 
197
        status = get_reg(dev, PP_RER);
 
198
 
 
199
        if ((status & PP_RER_RxOK) == 0)
 
200
                return 0;
 
201
 
 
202
        status = REG_READ(&priv->regs->rtdata);
 
203
        rxlen = REG_READ(&priv->regs->rtdata);
 
204
 
 
205
        if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
 
206
                debug("packet too big!\n");
 
207
        for (addr = (u16 *) NetRxPackets[0], i = rxlen >> 1; i > 0;
 
208
                 i--)
 
209
                *addr++ = REG_READ(&priv->regs->rtdata);
 
210
        if (rxlen & 1)
 
211
                *addr++ = REG_READ(&priv->regs->rtdata);
 
212
 
 
213
        /* Pass the packet up to the protocol layers. */
 
214
        NetReceive (NetRxPackets[0], rxlen);
 
215
        return rxlen;
 
216
}
 
217
 
 
218
/* Send a data block via Ethernet. */
 
219
static int cs8900_send(struct eth_device *dev,
 
220
                        volatile void *packet, int length)
 
221
{
 
222
        volatile u16 *addr;
 
223
        int tmo;
 
224
        u16 s;
 
225
        struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
 
226
 
 
227
retry:
 
228
        /* initiate a transmit sequence */
 
229
        REG_WRITE(PP_TxCmd_TxStart_Full, &priv->regs->txcmd);
 
230
        REG_WRITE(length, &priv->regs->txlen);
 
231
 
 
232
        /* Test to see if the chip has allocated memory for the packet */
 
233
        if ((get_reg(dev, PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) {
 
234
                /* Oops... this should not happen! */
 
235
                debug("cs: unable to send packet; retrying...\n");
 
236
                for (tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
 
237
                        get_timer(0) < tmo;)
 
238
                        /*NOP*/;
 
239
                cs8900_reset(dev);
 
240
                cs8900_reginit(dev);
 
241
                goto retry;
 
242
        }
 
243
 
 
244
        /* Write the contents of the packet */
 
245
        /* assume even number of bytes */
 
246
        for (addr = packet; length > 0; length -= 2)
 
247
                REG_WRITE(*addr++, &priv->regs->rtdata);
 
248
 
 
249
        /* wait for transfer to succeed */
 
250
        tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
 
251
        while ((s = get_reg(dev, PP_TER) & ~0x1F) == 0) {
 
252
                if (get_timer(0) >= tmo)
 
253
                        break;
 
254
        }
 
255
 
 
256
        /* nothing */ ;
 
257
        if((s & (PP_TER_CRS | PP_TER_TxOK)) != PP_TER_TxOK) {
 
258
                debug("\ntransmission error %#x\n", s);
 
259
        }
 
260
 
 
261
        return 0;
 
262
}
 
263
 
 
264
static void cs8900_e2prom_ready(struct eth_device *dev)
 
265
{
 
266
        while (get_reg(dev, PP_SelfSTAT) & SI_BUSY)
 
267
                ;
 
268
}
 
269
 
 
270
/***********************************************************/
 
271
/* read a 16-bit word out of the EEPROM                    */
 
272
/***********************************************************/
 
273
 
 
274
int cs8900_e2prom_read(struct eth_device *dev,
 
275
                        u8 addr, u16 *value)
 
276
{
 
277
        cs8900_e2prom_ready(dev);
 
278
        put_reg(dev, PP_EECMD, EEPROM_READ_CMD | addr);
 
279
        cs8900_e2prom_ready(dev);
 
280
        *value = get_reg(dev, PP_EEData);
 
281
 
 
282
        return 0;
 
283
}
 
284
 
 
285
 
 
286
/***********************************************************/
 
287
/* write a 16-bit word into the EEPROM                     */
 
288
/***********************************************************/
 
289
 
 
290
int cs8900_e2prom_write(struct eth_device *dev, u8 addr, u16 value)
 
291
{
 
292
        cs8900_e2prom_ready(dev);
 
293
        put_reg(dev, PP_EECMD, EEPROM_WRITE_EN);
 
294
        cs8900_e2prom_ready(dev);
 
295
        put_reg(dev, PP_EEData, value);
 
296
        put_reg(dev, PP_EECMD, EEPROM_WRITE_CMD | addr);
 
297
        cs8900_e2prom_ready(dev);
 
298
        put_reg(dev, PP_EECMD, EEPROM_WRITE_DIS);
 
299
        cs8900_e2prom_ready(dev);
 
300
 
 
301
        return 0;
 
302
}
 
303
 
 
304
int cs8900_initialize(u8 dev_num, int base_addr)
 
305
{
 
306
        struct eth_device *dev;
 
307
        struct cs8900_priv *priv;
 
308
 
 
309
        dev = malloc(sizeof(*dev));
 
310
        if (!dev) {
 
311
                return 0;
 
312
        }
 
313
        memset(dev, 0, sizeof(*dev));
 
314
 
 
315
        priv = malloc(sizeof(*priv));
 
316
        if (!priv) {
 
317
                free(dev);
 
318
                return 0;
 
319
        }
 
320
        memset(priv, 0, sizeof(*priv));
 
321
        priv->regs = (struct cs8900_regs *)base_addr;
 
322
 
 
323
        dev->iobase = base_addr;
 
324
        dev->priv = priv;
 
325
        dev->init = cs8900_init;
 
326
        dev->halt = cs8900_halt;
 
327
        dev->send = cs8900_send;
 
328
        dev->recv = cs8900_recv;
 
329
 
 
330
        /* Load MAC address from EEPROM */
 
331
        cs8900_get_enetaddr(dev);
 
332
 
 
333
        sprintf(dev->name, "%s-%hu", CS8900_DRIVERNAME, dev_num);
 
334
 
 
335
        eth_register(dev);
 
336
        return 0;
 
337
}