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