Commit 45a1693a312453dcb5d26cd03c57569c50872cc6

Authored by Roberto Cerati
Committed by Joe Hershberger
1 parent 6027384a69

net: ks8851_mll: add ethernet support

The device interface is 16 bits wide.
All the available packets are read from the incoming fifo.

Signed-off-by: Roberto Cerati <roberto.cerati@bticino.it>
Signed-off-by: Raffaele Recalcati <raffaele.recalcati@bticino.it>
[voice.shen@atmel.com: address comments from review results]
[voice.shen@atmel.com: clean up for submit]
Signed-off-by: Bo Shen <voice.shen@atmel.com>
Tested-by: Raffaele Recalcati <raffaele.recalcati@bticino.it>

Showing 4 changed files with 1004 additions and 0 deletions Side-by-side Diff

drivers/net/Makefile
... ... @@ -50,6 +50,7 @@
50 50 COBJS-$(CONFIG_GRETH) += greth.o
51 51 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
52 52 COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
  53 +COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
53 54 COBJS-$(CONFIG_LAN91C96) += lan91c96.o
54 55 COBJS-$(CONFIG_MACB) += macb.o
55 56 COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
drivers/net/ks8851_mll.c
  1 +/*
  2 + * Micrel KS8851_MLL 16bit Network driver
  3 + * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it>
  4 + *
  5 + * This program is free software; you can redistribute it and/or modify
  6 + * it under the terms of the GNU General Public License as published by
  7 + * the Free Software Foundation; either version 2 of the License, or
  8 + * (at your option) any later version.
  9 + *
  10 + * This program is distributed in the hope that it will be useful,
  11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 + * GNU General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License
  16 + * along with this program; if not, write to the Free Software
  17 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 + */
  19 +
  20 +#include <asm/io.h>
  21 +#include <common.h>
  22 +#include <command.h>
  23 +#include <malloc.h>
  24 +#include <net.h>
  25 +#include <miiphy.h>
  26 +
  27 +#include "ks8851_mll.h"
  28 +
  29 +#define DRIVERNAME "ks8851_mll"
  30 +
  31 +#define MAX_RECV_FRAMES 32
  32 +#define MAX_BUF_SIZE 2048
  33 +#define TX_BUF_SIZE 2000
  34 +#define RX_BUF_SIZE 2000
  35 +
  36 +static const struct chip_id chip_ids[] = {
  37 + {CIDER_ID, "KSZ8851"},
  38 + {0, NULL},
  39 +};
  40 +
  41 +/*
  42 + * union ks_tx_hdr - tx header data
  43 + * @txb: The header as bytes
  44 + * @txw: The header as 16bit, little-endian words
  45 + *
  46 + * A dual representation of the tx header data to allow
  47 + * access to individual bytes, and to allow 16bit accesses
  48 + * with 16bit alignment.
  49 + */
  50 +union ks_tx_hdr {
  51 + u8 txb[4];
  52 + __le16 txw[2];
  53 +};
  54 +
  55 +/*
  56 + * struct ks_net - KS8851 driver private data
  57 + * @net_device : The network device we're bound to
  58 + * @txh : temporaly buffer to save status/length.
  59 + * @frame_head_info : frame header information for multi-pkt rx.
  60 + * @statelock : Lock on this structure for tx list.
  61 + * @msg_enable : The message flags controlling driver output (see ethtool).
  62 + * @frame_cnt : number of frames received.
  63 + * @bus_width : i/o bus width.
  64 + * @irq : irq number assigned to this device.
  65 + * @rc_rxqcr : Cached copy of KS_RXQCR.
  66 + * @rc_txcr : Cached copy of KS_TXCR.
  67 + * @rc_ier : Cached copy of KS_IER.
  68 + * @sharedbus : Multipex(addr and data bus) mode indicator.
  69 + * @cmd_reg_cache : command register cached.
  70 + * @cmd_reg_cache_int : command register cached. Used in the irq handler.
  71 + * @promiscuous : promiscuous mode indicator.
  72 + * @all_mcast : mutlicast indicator.
  73 + * @mcast_lst_size : size of multicast list.
  74 + * @mcast_lst : multicast list.
  75 + * @mcast_bits : multicast enabed.
  76 + * @mac_addr : MAC address assigned to this device.
  77 + * @fid : frame id.
  78 + * @extra_byte : number of extra byte prepended rx pkt.
  79 + * @enabled : indicator this device works.
  80 + */
  81 +
  82 +/* Receive multiplex framer header info */
  83 +struct type_frame_head {
  84 + u16 sts; /* Frame status */
  85 + u16 len; /* Byte count */
  86 +} fr_h_i[MAX_RECV_FRAMES];
  87 +
  88 +struct ks_net {
  89 + struct net_device *netdev;
  90 + union ks_tx_hdr txh;
  91 + struct type_frame_head *frame_head_info;
  92 + u32 msg_enable;
  93 + u32 frame_cnt;
  94 + int bus_width;
  95 + int irq;
  96 + u16 rc_rxqcr;
  97 + u16 rc_txcr;
  98 + u16 rc_ier;
  99 + u16 sharedbus;
  100 + u16 cmd_reg_cache;
  101 + u16 cmd_reg_cache_int;
  102 + u16 promiscuous;
  103 + u16 all_mcast;
  104 + u16 mcast_lst_size;
  105 + u8 mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN];
  106 + u8 mcast_bits[HW_MCAST_SIZE];
  107 + u8 mac_addr[6];
  108 + u8 fid;
  109 + u8 extra_byte;
  110 + u8 enabled;
  111 +} ks_str, *ks;
  112 +
  113 +#define BE3 0x8000 /* Byte Enable 3 */
  114 +#define BE2 0x4000 /* Byte Enable 2 */
  115 +#define BE1 0x2000 /* Byte Enable 1 */
  116 +#define BE0 0x1000 /* Byte Enable 0 */
  117 +
  118 +static u8 ks_rdreg8(struct eth_device *dev, u16 offset)
  119 +{
  120 + u8 shift_bit = offset & 0x03;
  121 + u8 shift_data = (offset & 1) << 3;
  122 +
  123 + writew(offset | (BE0 << shift_bit), dev->iobase + 2);
  124 +
  125 + return (u8)(readw(dev->iobase) >> shift_data);
  126 +}
  127 +
  128 +static u16 ks_rdreg16(struct eth_device *dev, u16 offset)
  129 +{
  130 + writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
  131 +
  132 + return readw(dev->iobase);
  133 +}
  134 +
  135 +static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val)
  136 +{
  137 + u8 shift_bit = (offset & 0x03);
  138 + u16 value_write = (u16)(val << ((offset & 1) << 3));
  139 +
  140 + writew(offset | (BE0 << shift_bit), dev->iobase + 2);
  141 + writew(value_write, dev->iobase);
  142 +}
  143 +
  144 +static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val)
  145 +{
  146 + writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
  147 + writew(val, dev->iobase);
  148 +}
  149 +
  150 +/*
  151 + * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode
  152 + * enabled.
  153 + * @ks: The chip state
  154 + * @wptr: buffer address to save data
  155 + * @len: length in byte to read
  156 + */
  157 +static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len)
  158 +{
  159 + len >>= 1;
  160 +
  161 + while (len--)
  162 + *wptr++ = readw(dev->iobase);
  163 +}
  164 +
  165 +/*
  166 + * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled.
  167 + * @ks: The chip information
  168 + * @wptr: buffer address
  169 + * @len: length in byte to write
  170 + */
  171 +static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len)
  172 +{
  173 + len >>= 1;
  174 +
  175 + while (len--)
  176 + writew(*wptr++, dev->iobase);
  177 +}
  178 +
  179 +static void ks_enable_int(struct eth_device *dev)
  180 +{
  181 + ks_wrreg16(dev, KS_IER, ks->rc_ier);
  182 +}
  183 +
  184 +static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode)
  185 +{
  186 + unsigned pmecr;
  187 +
  188 + ks_rdreg16(dev, KS_GRR);
  189 + pmecr = ks_rdreg16(dev, KS_PMECR);
  190 + pmecr &= ~PMECR_PM_MASK;
  191 + pmecr |= pwrmode;
  192 +
  193 + ks_wrreg16(dev, KS_PMECR, pmecr);
  194 +}
  195 +
  196 +/*
  197 + * ks_read_config - read chip configuration of bus width.
  198 + * @ks: The chip information
  199 + */
  200 +static void ks_read_config(struct eth_device *dev)
  201 +{
  202 + u16 reg_data = 0;
  203 +
  204 + /* Regardless of bus width, 8 bit read should always work. */
  205 + reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF;
  206 + reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8;
  207 +
  208 + /* addr/data bus are multiplexed */
  209 + ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
  210 +
  211 + /*
  212 + * There are garbage data when reading data from QMU,
  213 + * depending on bus-width.
  214 + */
  215 + if (reg_data & CCR_8BIT) {
  216 + ks->bus_width = ENUM_BUS_8BIT;
  217 + ks->extra_byte = 1;
  218 + } else if (reg_data & CCR_16BIT) {
  219 + ks->bus_width = ENUM_BUS_16BIT;
  220 + ks->extra_byte = 2;
  221 + } else {
  222 + ks->bus_width = ENUM_BUS_32BIT;
  223 + ks->extra_byte = 4;
  224 + }
  225 +}
  226 +
  227 +/*
  228 + * ks_soft_reset - issue one of the soft reset to the device
  229 + * @ks: The device state.
  230 + * @op: The bit(s) to set in the GRR
  231 + *
  232 + * Issue the relevant soft-reset command to the device's GRR register
  233 + * specified by @op.
  234 + *
  235 + * Note, the delays are in there as a caution to ensure that the reset
  236 + * has time to take effect and then complete. Since the datasheet does
  237 + * not currently specify the exact sequence, we have chosen something
  238 + * that seems to work with our device.
  239 + */
  240 +static void ks_soft_reset(struct eth_device *dev, unsigned op)
  241 +{
  242 + /* Disable interrupt first */
  243 + ks_wrreg16(dev, KS_IER, 0x0000);
  244 + ks_wrreg16(dev, KS_GRR, op);
  245 + mdelay(10); /* wait a short time to effect reset */
  246 + ks_wrreg16(dev, KS_GRR, 0);
  247 + mdelay(1); /* wait for condition to clear */
  248 +}
  249 +
  250 +void ks_enable_qmu(struct eth_device *dev)
  251 +{
  252 + u16 w;
  253 +
  254 + w = ks_rdreg16(dev, KS_TXCR);
  255 +
  256 + /* Enables QMU Transmit (TXCR). */
  257 + ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE);
  258 +
  259 + /* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */
  260 + w = ks_rdreg16(dev, KS_RXQCR);
  261 + ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE);
  262 +
  263 + /* Enables QMU Receive (RXCR1). */
  264 + w = ks_rdreg16(dev, KS_RXCR1);
  265 + ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE);
  266 +}
  267 +
  268 +static void ks_disable_qmu(struct eth_device *dev)
  269 +{
  270 + u16 w;
  271 +
  272 + w = ks_rdreg16(dev, KS_TXCR);
  273 +
  274 + /* Disables QMU Transmit (TXCR). */
  275 + w &= ~TXCR_TXE;
  276 + ks_wrreg16(dev, KS_TXCR, w);
  277 +
  278 + /* Disables QMU Receive (RXCR1). */
  279 + w = ks_rdreg16(dev, KS_RXCR1);
  280 + w &= ~RXCR1_RXE;
  281 + ks_wrreg16(dev, KS_RXCR1, w);
  282 +}
  283 +
  284 +static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len)
  285 +{
  286 + u32 r = ks->extra_byte & 0x1;
  287 + u32 w = ks->extra_byte - r;
  288 +
  289 + /* 1. set sudo DMA mode */
  290 + ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
  291 + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
  292 +
  293 + /*
  294 + * 2. read prepend data
  295 + *
  296 + * read 4 + extra bytes and discard them.
  297 + * extra bytes for dummy, 2 for status, 2 for len
  298 + */
  299 +
  300 + if (r)
  301 + ks_rdreg8(dev, 0);
  302 +
  303 + ks_inblk(dev, buf, w + 2 + 2);
  304 +
  305 + /* 3. read pkt data */
  306 + ks_inblk(dev, buf, ALIGN(len, 4));
  307 +
  308 + /* 4. reset sudo DMA Mode */
  309 + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
  310 +}
  311 +
  312 +static void ks_rcv(struct eth_device *dev, uchar **pv_data)
  313 +{
  314 + struct type_frame_head *frame_hdr = ks->frame_head_info;
  315 + int i;
  316 +
  317 + ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8;
  318 +
  319 + /* read all header information */
  320 + for (i = 0; i < ks->frame_cnt; i++) {
  321 + /* Checking Received packet status */
  322 + frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR);
  323 + /* Get packet len from hardware */
  324 + frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR);
  325 + frame_hdr++;
  326 + }
  327 +
  328 + frame_hdr = ks->frame_head_info;
  329 + while (ks->frame_cnt--) {
  330 + if ((frame_hdr->sts & RXFSHR_RXFV) &&
  331 + (frame_hdr->len < RX_BUF_SIZE) &&
  332 + frame_hdr->len) {
  333 + /* read data block including CRC 4 bytes */
  334 + ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len);
  335 +
  336 + /* NetRxPackets buffer size is ok (*pv_data pointer) */
  337 + NetReceive(*pv_data, frame_hdr->len);
  338 + pv_data++;
  339 + } else {
  340 + ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
  341 + printf(DRIVERNAME ": bad packet\n");
  342 + }
  343 + frame_hdr++;
  344 + }
  345 +}
  346 +
  347 +/*
  348 + * ks_read_selftest - read the selftest memory info.
  349 + * @ks: The device state
  350 + *
  351 + * Read and check the TX/RX memory selftest information.
  352 + */
  353 +static int ks_read_selftest(struct eth_device *dev)
  354 +{
  355 + u16 both_done = MBIR_TXMBF | MBIR_RXMBF;
  356 + u16 mbir;
  357 + int ret = 0;
  358 +
  359 + mbir = ks_rdreg16(dev, KS_MBIR);
  360 +
  361 + if ((mbir & both_done) != both_done) {
  362 + printf(DRIVERNAME ": Memory selftest not finished\n");
  363 + return 0;
  364 + }
  365 +
  366 + if (mbir & MBIR_TXMBFA) {
  367 + printf(DRIVERNAME ": TX memory selftest fails\n");
  368 + ret |= 1;
  369 + }
  370 +
  371 + if (mbir & MBIR_RXMBFA) {
  372 + printf(DRIVERNAME ": RX memory selftest fails\n");
  373 + ret |= 2;
  374 + }
  375 +
  376 + debug(DRIVERNAME ": the selftest passes\n");
  377 +
  378 + return ret;
  379 +}
  380 +
  381 +static void ks_setup(struct eth_device *dev)
  382 +{
  383 + u16 w;
  384 +
  385 + /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */
  386 + ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
  387 +
  388 + /* Setup Receive Frame Data Pointer Auto-Increment */
  389 + ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
  390 +
  391 + /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */
  392 + ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK);
  393 +
  394 + /* Setup RxQ Command Control (RXQCR) */
  395 + ks->rc_rxqcr = RXQCR_CMD_CNTL;
  396 + ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr);
  397 +
  398 + /*
  399 + * set the force mode to half duplex, default is full duplex
  400 + * because if the auto-negotiation fails, most switch uses
  401 + * half-duplex.
  402 + */
  403 + w = ks_rdreg16(dev, KS_P1MBCR);
  404 + w &= ~P1MBCR_FORCE_FDX;
  405 + ks_wrreg16(dev, KS_P1MBCR, w);
  406 +
  407 + w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP;
  408 + ks_wrreg16(dev, KS_TXCR, w);
  409 +
  410 + w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC;
  411 +
  412 + /* Normal mode */
  413 + w |= RXCR1_RXPAFMA;
  414 +
  415 + ks_wrreg16(dev, KS_RXCR1, w);
  416 +}
  417 +
  418 +static void ks_setup_int(struct eth_device *dev)
  419 +{
  420 + ks->rc_ier = 0x00;
  421 +
  422 + /* Clear the interrupts status of the hardware. */
  423 + ks_wrreg16(dev, KS_ISR, 0xffff);
  424 +
  425 + /* Enables the interrupts of the hardware. */
  426 + ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI);
  427 +}
  428 +
  429 +static int ks8851_mll_detect_chip(struct eth_device *dev)
  430 +{
  431 + unsigned short val, i;
  432 +
  433 + ks_read_config(dev);
  434 +
  435 + val = ks_rdreg16(dev, KS_CIDER);
  436 +
  437 + if (val == 0xffff) {
  438 + /* Special case -- no chip present */
  439 + printf(DRIVERNAME ": is chip mounted ?\n");
  440 + return -1;
  441 + } else if ((val & 0xfff0) != CIDER_ID) {
  442 + printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val);
  443 + return -1;
  444 + }
  445 +
  446 + debug("Read back KS8851 id 0x%x\n", val);
  447 +
  448 + /* only one entry in the table */
  449 + val &= 0xfff0;
  450 + for (i = 0; chip_ids[i].id != 0; i++) {
  451 + if (chip_ids[i].id == val)
  452 + break;
  453 + }
  454 + if (!chip_ids[i].id) {
  455 + printf(DRIVERNAME ": Unknown chip ID %04x\n", val);
  456 + return -1;
  457 + }
  458 +
  459 + dev->priv = (void *)&chip_ids[i];
  460 +
  461 + return 0;
  462 +}
  463 +
  464 +static void ks8851_mll_reset(struct eth_device *dev)
  465 +{
  466 + /* wake up powermode to normal mode */
  467 + ks_set_powermode(dev, PMECR_PM_NORMAL);
  468 + mdelay(1); /* wait for normal mode to take effect */
  469 +
  470 + /* Disable interrupt and reset */
  471 + ks_soft_reset(dev, GRR_GSR);
  472 +
  473 + /* turn off the IRQs and ack any outstanding */
  474 + ks_wrreg16(dev, KS_IER, 0x0000);
  475 + ks_wrreg16(dev, KS_ISR, 0xffff);
  476 +
  477 + /* shutdown RX/TX QMU */
  478 + ks_disable_qmu(dev);
  479 +}
  480 +
  481 +static void ks8851_mll_phy_configure(struct eth_device *dev)
  482 +{
  483 + u16 data;
  484 +
  485 + ks_setup(dev);
  486 + ks_setup_int(dev);
  487 +
  488 + /* Probing the phy */
  489 + data = ks_rdreg16(dev, KS_OBCR);
  490 + ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA);
  491 +
  492 + debug(DRIVERNAME ": phy initialized\n");
  493 +}
  494 +
  495 +static void ks8851_mll_enable(struct eth_device *dev)
  496 +{
  497 + ks_wrreg16(dev, KS_ISR, 0xffff);
  498 + ks_enable_int(dev);
  499 + ks_enable_qmu(dev);
  500 +}
  501 +
  502 +static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
  503 +{
  504 + struct chip_id *id = dev->priv;
  505 +
  506 + debug(DRIVERNAME ": detected %s controller\n", id->name);
  507 +
  508 + if (ks_read_selftest(dev)) {
  509 + printf(DRIVERNAME ": Selftest failed\n");
  510 + return -1;
  511 + }
  512 +
  513 + ks8851_mll_reset(dev);
  514 +
  515 + /* Configure the PHY, initialize the link state */
  516 + ks8851_mll_phy_configure(dev);
  517 +
  518 + /* static allocation of private informations */
  519 + ks->frame_head_info = fr_h_i;
  520 +
  521 + /* Turn on Tx + Rx */
  522 + ks8851_mll_enable(dev);
  523 +
  524 + return 0;
  525 +}
  526 +
  527 +static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len)
  528 +{
  529 + /* start header at txb[0] to align txw entries */
  530 + ks->txh.txw[0] = 0;
  531 + ks->txh.txw[1] = cpu_to_le16(len);
  532 +
  533 + /* 1. set sudo-DMA mode */
  534 + ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
  535 + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
  536 + /* 2. write status/lenth info */
  537 + ks_outblk(dev, ks->txh.txw, 4);
  538 + /* 3. write pkt data */
  539 + ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4));
  540 + /* 4. reset sudo-DMA mode */
  541 + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
  542 + /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */
  543 + ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE);
  544 + /* 6. wait until TXQCR_METFE is auto-cleared */
  545 + do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE);
  546 +}
  547 +
  548 +static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
  549 +{
  550 + u8 *data = (u8 *)packet;
  551 + u16 tmplen = (u16)length;
  552 + u16 retv;
  553 +
  554 + /*
  555 + * Extra space are required:
  556 + * 4 byte for alignment, 4 for status/length, 4 for CRC
  557 + */
  558 + retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff;
  559 + if (retv >= tmplen + 12) {
  560 + ks_write_qmu(dev, data, tmplen);
  561 + return 0;
  562 + } else {
  563 + printf(DRIVERNAME ": failed to send packet: No buffer\n");
  564 + return -1;
  565 + }
  566 +}
  567 +
  568 +static void ks8851_mll_halt(struct eth_device *dev)
  569 +{
  570 + ks8851_mll_reset(dev);
  571 +}
  572 +
  573 +/*
  574 + * Maximum receive ring size; that is, the number of packets
  575 + * we can buffer before overflow happens. Basically, this just
  576 + * needs to be enough to prevent a packet being discarded while
  577 + * we are processing the previous one.
  578 + */
  579 +static int ks8851_mll_recv(struct eth_device *dev)
  580 +{
  581 + u16 status;
  582 +
  583 + status = ks_rdreg16(dev, KS_ISR);
  584 +
  585 + ks_wrreg16(dev, KS_ISR, status);
  586 +
  587 + if ((status & IRQ_RXI))
  588 + ks_rcv(dev, (uchar **)NetRxPackets);
  589 +
  590 + if ((status & IRQ_LDI)) {
  591 + u16 pmecr = ks_rdreg16(dev, KS_PMECR);
  592 + pmecr &= ~PMECR_WKEVT_MASK;
  593 + ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
  594 + }
  595 +
  596 + return 0;
  597 +}
  598 +
  599 +static int ks8851_mll_write_hwaddr(struct eth_device *dev)
  600 +{
  601 + u16 addrl, addrm, addrh;
  602 +
  603 + addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1];
  604 + addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3];
  605 + addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5];
  606 +
  607 + ks_wrreg16(dev, KS_MARH, addrh);
  608 + ks_wrreg16(dev, KS_MARM, addrm);
  609 + ks_wrreg16(dev, KS_MARL, addrl);
  610 +
  611 + return 0;
  612 +}
  613 +
  614 +int ks8851_mll_initialize(u8 dev_num, int base_addr)
  615 +{
  616 + struct eth_device *dev;
  617 +
  618 + dev = malloc(sizeof(*dev));
  619 + if (!dev) {
  620 + printf("Error: Failed to allocate memory\n");
  621 + return -1;
  622 + }
  623 + memset(dev, 0, sizeof(*dev));
  624 +
  625 + dev->iobase = base_addr;
  626 +
  627 + ks = &ks_str;
  628 +
  629 + /* Try to detect chip. Will fail if not present. */
  630 + if (ks8851_mll_detect_chip(dev)) {
  631 + free(dev);
  632 + return -1;
  633 + }
  634 +
  635 + dev->init = ks8851_mll_init;
  636 + dev->halt = ks8851_mll_halt;
  637 + dev->send = ks8851_mll_send;
  638 + dev->recv = ks8851_mll_recv;
  639 + dev->write_hwaddr = ks8851_mll_write_hwaddr;
  640 + sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
  641 +
  642 + eth_register(dev);
  643 +
  644 + return 0;
  645 +}
drivers/net/ks8851_mll.h
  1 +/*
  2 + * drivers/net/ks8851_mll.c
  3 + *
  4 + * Supports:
  5 + * KS8851 16bit MLL chip from Micrel Inc.
  6 + *
  7 + * Copyright (c) 2009 Micrel Inc.
  8 + *
  9 + * modified by
  10 + * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it>
  11 + *
  12 + * This program is free software; you can redistribute it and/or modify
  13 + * it under the terms of the GNU General Public License version 2 as
  14 + * published by the Free Software Foundation.
  15 + *
  16 + * This program is distributed in the hope that it will be useful,
  17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19 + * GNU General Public License for more details.
  20 + *
  21 + * You should have received a copy of the GNU General Public License
  22 + * along with this program; if not, write to the Free Software
  23 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 + */
  25 +#ifndef _KS8851_MLL_H_
  26 +#define _KS8851_MLL_H_
  27 +
  28 +#include <linux/types.h>
  29 +
  30 +#define KS_CCR 0x08
  31 +#define CCR_EEPROM (1 << 9)
  32 +#define CCR_SPI (1 << 8)
  33 +#define CCR_8BIT (1 << 7)
  34 +#define CCR_16BIT (1 << 6)
  35 +#define CCR_32BIT (1 << 5)
  36 +#define CCR_SHARED (1 << 4)
  37 +#define CCR_32PIN (1 << 0)
  38 +
  39 +/* MAC address registers */
  40 +#define KS_MARL 0x10
  41 +#define KS_MARM 0x12
  42 +#define KS_MARH 0x14
  43 +
  44 +#define KS_OBCR 0x20
  45 +#define OBCR_ODS_16MA (1 << 6)
  46 +
  47 +#define KS_EEPCR 0x22
  48 +#define EEPCR_EESA (1 << 4)
  49 +#define EEPCR_EESB (1 << 3)
  50 +#define EEPCR_EEDO (1 << 2)
  51 +#define EEPCR_EESCK (1 << 1)
  52 +#define EEPCR_EECS (1 << 0)
  53 +
  54 +#define KS_MBIR 0x24
  55 +#define MBIR_TXMBF (1 << 12)
  56 +#define MBIR_TXMBFA (1 << 11)
  57 +#define MBIR_RXMBF (1 << 4)
  58 +#define MBIR_RXMBFA (1 << 3)
  59 +
  60 +#define KS_GRR 0x26
  61 +#define GRR_QMU (1 << 1)
  62 +#define GRR_GSR (1 << 0)
  63 +
  64 +#define KS_WFCR 0x2A
  65 +#define WFCR_MPRXE (1 << 7)
  66 +#define WFCR_WF3E (1 << 3)
  67 +#define WFCR_WF2E (1 << 2)
  68 +#define WFCR_WF1E (1 << 1)
  69 +#define WFCR_WF0E (1 << 0)
  70 +
  71 +#define KS_WF0CRC0 0x30
  72 +#define KS_WF0CRC1 0x32
  73 +#define KS_WF0BM0 0x34
  74 +#define KS_WF0BM1 0x36
  75 +#define KS_WF0BM2 0x38
  76 +#define KS_WF0BM3 0x3A
  77 +
  78 +#define KS_WF1CRC0 0x40
  79 +#define KS_WF1CRC1 0x42
  80 +#define KS_WF1BM0 0x44
  81 +#define KS_WF1BM1 0x46
  82 +#define KS_WF1BM2 0x48
  83 +#define KS_WF1BM3 0x4A
  84 +
  85 +#define KS_WF2CRC0 0x50
  86 +#define KS_WF2CRC1 0x52
  87 +#define KS_WF2BM0 0x54
  88 +#define KS_WF2BM1 0x56
  89 +#define KS_WF2BM2 0x58
  90 +#define KS_WF2BM3 0x5A
  91 +
  92 +#define KS_WF3CRC0 0x60
  93 +#define KS_WF3CRC1 0x62
  94 +#define KS_WF3BM0 0x64
  95 +#define KS_WF3BM1 0x66
  96 +#define KS_WF3BM2 0x68
  97 +#define KS_WF3BM3 0x6A
  98 +
  99 +#define KS_TXCR 0x70
  100 +#define TXCR_TCGICMP (1 << 8)
  101 +#define TXCR_TCGUDP (1 << 7)
  102 +#define TXCR_TCGTCP (1 << 6)
  103 +#define TXCR_TCGIP (1 << 5)
  104 +#define TXCR_FTXQ (1 << 4)
  105 +#define TXCR_TXFCE (1 << 3)
  106 +#define TXCR_TXPE (1 << 2)
  107 +#define TXCR_TXCRC (1 << 1)
  108 +#define TXCR_TXE (1 << 0)
  109 +
  110 +#define KS_TXSR 0x72
  111 +#define TXSR_TXLC (1 << 13)
  112 +#define TXSR_TXMC (1 << 12)
  113 +#define TXSR_TXFID_MASK (0x3f << 0)
  114 +#define TXSR_TXFID_SHIFT (0)
  115 +#define TXSR_TXFID_GET(_v) (((_v) >> 0) & 0x3f)
  116 +
  117 +
  118 +#define KS_RXCR1 0x74
  119 +#define RXCR1_FRXQ (1 << 15)
  120 +#define RXCR1_RXUDPFCC (1 << 14)
  121 +#define RXCR1_RXTCPFCC (1 << 13)
  122 +#define RXCR1_RXIPFCC (1 << 12)
  123 +#define RXCR1_RXPAFMA (1 << 11)
  124 +#define RXCR1_RXFCE (1 << 10)
  125 +#define RXCR1_RXEFE (1 << 9)
  126 +#define RXCR1_RXMAFMA (1 << 8)
  127 +#define RXCR1_RXBE (1 << 7)
  128 +#define RXCR1_RXME (1 << 6)
  129 +#define RXCR1_RXUE (1 << 5)
  130 +#define RXCR1_RXAE (1 << 4)
  131 +#define RXCR1_RXINVF (1 << 1)
  132 +#define RXCR1_RXE (1 << 0)
  133 +#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \
  134 + RXCR1_RXMAFMA | RXCR1_RXPAFMA)
  135 +
  136 +#define KS_RXCR2 0x76
  137 +#define RXCR2_SRDBL_MASK (0x7 << 5)
  138 +#define RXCR2_SRDBL_SHIFT (5)
  139 +#define RXCR2_SRDBL_4B (0x0 << 5)
  140 +#define RXCR2_SRDBL_8B (0x1 << 5)
  141 +#define RXCR2_SRDBL_16B (0x2 << 5)
  142 +#define RXCR2_SRDBL_32B (0x3 << 5)
  143 +/* #define RXCR2_SRDBL_FRAME (0x4 << 5) */
  144 +#define RXCR2_IUFFP (1 << 4)
  145 +#define RXCR2_RXIUFCEZ (1 << 3)
  146 +#define RXCR2_UDPLFE (1 << 2)
  147 +#define RXCR2_RXICMPFCC (1 << 1)
  148 +#define RXCR2_RXSAF (1 << 0)
  149 +
  150 +#define KS_TXMIR 0x78
  151 +
  152 +#define KS_RXFHSR 0x7C
  153 +#define RXFSHR_RXFV (1 << 15)
  154 +#define RXFSHR_RXICMPFCS (1 << 13)
  155 +#define RXFSHR_RXIPFCS (1 << 12)
  156 +#define RXFSHR_RXTCPFCS (1 << 11)
  157 +#define RXFSHR_RXUDPFCS (1 << 10)
  158 +#define RXFSHR_RXBF (1 << 7)
  159 +#define RXFSHR_RXMF (1 << 6)
  160 +#define RXFSHR_RXUF (1 << 5)
  161 +#define RXFSHR_RXMR (1 << 4)
  162 +#define RXFSHR_RXFT (1 << 3)
  163 +#define RXFSHR_RXFTL (1 << 2)
  164 +#define RXFSHR_RXRF (1 << 1)
  165 +#define RXFSHR_RXCE (1 << 0)
  166 +#define RXFSHR_ERR (RXFSHR_RXCE | RXFSHR_RXRF |\
  167 + RXFSHR_RXFTL | RXFSHR_RXMR |\
  168 + RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\
  169 + RXFSHR_RXTCPFCS)
  170 +#define KS_RXFHBCR 0x7E
  171 +#define RXFHBCR_CNT_MASK 0x0FFF
  172 +
  173 +#define KS_TXQCR 0x80
  174 +#define TXQCR_AETFE (1 << 2)
  175 +#define TXQCR_TXQMAM (1 << 1)
  176 +#define TXQCR_METFE (1 << 0)
  177 +
  178 +#define KS_RXQCR 0x82
  179 +#define RXQCR_RXDTTS (1 << 12)
  180 +#define RXQCR_RXDBCTS (1 << 11)
  181 +#define RXQCR_RXFCTS (1 << 10)
  182 +#define RXQCR_RXIPHTOE (1 << 9)
  183 +#define RXQCR_RXDTTE (1 << 7)
  184 +#define RXQCR_RXDBCTE (1 << 6)
  185 +#define RXQCR_RXFCTE (1 << 5)
  186 +#define RXQCR_ADRFE (1 << 4)
  187 +#define RXQCR_SDA (1 << 3)
  188 +#define RXQCR_RRXEF (1 << 0)
  189 +#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE)
  190 +
  191 +#define KS_TXFDPR 0x84
  192 +#define TXFDPR_TXFPAI (1 << 14)
  193 +#define TXFDPR_TXFP_MASK (0x7ff << 0)
  194 +#define TXFDPR_TXFP_SHIFT (0)
  195 +
  196 +#define KS_RXFDPR 0x86
  197 +#define RXFDPR_RXFPAI (1 << 14)
  198 +
  199 +#define KS_RXDTTR 0x8C
  200 +#define KS_RXDBCTR 0x8E
  201 +
  202 +#define KS_IER 0x90
  203 +#define KS_ISR 0x92
  204 +#define IRQ_LCI (1 << 15)
  205 +#define IRQ_TXI (1 << 14)
  206 +#define IRQ_RXI (1 << 13)
  207 +#define IRQ_RXOI (1 << 11)
  208 +#define IRQ_TXPSI (1 << 9)
  209 +#define IRQ_RXPSI (1 << 8)
  210 +#define IRQ_TXSAI (1 << 6)
  211 +#define IRQ_RXWFDI (1 << 5)
  212 +#define IRQ_RXMPDI (1 << 4)
  213 +#define IRQ_LDI (1 << 3)
  214 +#define IRQ_EDI (1 << 2)
  215 +#define IRQ_SPIBEI (1 << 1)
  216 +#define IRQ_DEDI (1 << 0)
  217 +
  218 +#define KS_RXFCTR 0x9C
  219 +#define RXFCTR_THRESHOLD_MASK 0x00FF
  220 +
  221 +#define KS_RXFC 0x9D
  222 +#define RXFCTR_RXFC_MASK (0xff << 8)
  223 +#define RXFCTR_RXFC_SHIFT (8)
  224 +#define RXFCTR_RXFC_GET(_v) (((_v) >> 8) & 0xff)
  225 +#define RXFCTR_RXFCT_MASK (0xff << 0)
  226 +#define RXFCTR_RXFCT_SHIFT (0)
  227 +
  228 +#define KS_TXNTFSR 0x9E
  229 +
  230 +#define KS_MAHTR0 0xA0
  231 +#define KS_MAHTR1 0xA2
  232 +#define KS_MAHTR2 0xA4
  233 +#define KS_MAHTR3 0xA6
  234 +
  235 +#define KS_FCLWR 0xB0
  236 +#define KS_FCHWR 0xB2
  237 +#define KS_FCOWR 0xB4
  238 +
  239 +#define KS_CIDER 0xC0
  240 +#define CIDER_ID 0x8870
  241 +#define CIDER_REV_MASK (0x7 << 1)
  242 +#define CIDER_REV_SHIFT (1)
  243 +#define CIDER_REV_GET(_v) (((_v) >> 1) & 0x7)
  244 +
  245 +#define KS_CGCR 0xC6
  246 +#define KS_IACR 0xC8
  247 +#define IACR_RDEN (1 << 12)
  248 +#define IACR_TSEL_MASK (0x3 << 10)
  249 +#define IACR_TSEL_SHIFT (10)
  250 +#define IACR_TSEL_MIB (0x3 << 10)
  251 +#define IACR_ADDR_MASK (0x1f << 0)
  252 +#define IACR_ADDR_SHIFT (0)
  253 +
  254 +#define KS_IADLR 0xD0
  255 +#define KS_IAHDR 0xD2
  256 +
  257 +#define KS_PMECR 0xD4
  258 +#define PMECR_PME_DELAY (1 << 14)
  259 +#define PMECR_PME_POL (1 << 12)
  260 +#define PMECR_WOL_WAKEUP (1 << 11)
  261 +#define PMECR_WOL_MAGICPKT (1 << 10)
  262 +#define PMECR_WOL_LINKUP (1 << 9)
  263 +#define PMECR_WOL_ENERGY (1 << 8)
  264 +#define PMECR_AUTO_WAKE_EN (1 << 7)
  265 +#define PMECR_WAKEUP_NORMAL (1 << 6)
  266 +#define PMECR_WKEVT_MASK (0xf << 2)
  267 +#define PMECR_WKEVT_SHIFT (2)
  268 +#define PMECR_WKEVT_GET(_v) (((_v) >> 2) & 0xf)
  269 +#define PMECR_WKEVT_ENERGY (0x1 << 2)
  270 +#define PMECR_WKEVT_LINK (0x2 << 2)
  271 +#define PMECR_WKEVT_MAGICPKT (0x4 << 2)
  272 +#define PMECR_WKEVT_FRAME (0x8 << 2)
  273 +#define PMECR_PM_MASK (0x3 << 0)
  274 +#define PMECR_PM_SHIFT (0)
  275 +#define PMECR_PM_NORMAL (0x0 << 0)
  276 +#define PMECR_PM_ENERGY (0x1 << 0)
  277 +#define PMECR_PM_SOFTDOWN (0x2 << 0)
  278 +#define PMECR_PM_POWERSAVE (0x3 << 0)
  279 +
  280 +/* Standard MII PHY data */
  281 +#define KS_P1MBCR 0xE4
  282 +#define P1MBCR_FORCE_FDX (1 << 8)
  283 +
  284 +#define KS_P1MBSR 0xE6
  285 +#define P1MBSR_AN_COMPLETE (1 << 5)
  286 +#define P1MBSR_AN_CAPABLE (1 << 3)
  287 +#define P1MBSR_LINK_UP (1 << 2)
  288 +
  289 +#define KS_PHY1ILR 0xE8
  290 +#define KS_PHY1IHR 0xEA
  291 +#define KS_P1ANAR 0xEC
  292 +#define KS_P1ANLPR 0xEE
  293 +
  294 +#define KS_P1SCLMD 0xF4
  295 +#define P1SCLMD_LEDOFF (1 << 15)
  296 +#define P1SCLMD_TXIDS (1 << 14)
  297 +#define P1SCLMD_RESTARTAN (1 << 13)
  298 +#define P1SCLMD_DISAUTOMDIX (1 << 10)
  299 +#define P1SCLMD_FORCEMDIX (1 << 9)
  300 +#define P1SCLMD_AUTONEGEN (1 << 7)
  301 +#define P1SCLMD_FORCE100 (1 << 6)
  302 +#define P1SCLMD_FORCEFDX (1 << 5)
  303 +#define P1SCLMD_ADV_FLOW (1 << 4)
  304 +#define P1SCLMD_ADV_100BT_FDX (1 << 3)
  305 +#define P1SCLMD_ADV_100BT_HDX (1 << 2)
  306 +#define P1SCLMD_ADV_10BT_FDX (1 << 1)
  307 +#define P1SCLMD_ADV_10BT_HDX (1 << 0)
  308 +
  309 +#define KS_P1CR 0xF6
  310 +#define P1CR_HP_MDIX (1 << 15)
  311 +#define P1CR_REV_POL (1 << 13)
  312 +#define P1CR_OP_100M (1 << 10)
  313 +#define P1CR_OP_FDX (1 << 9)
  314 +#define P1CR_OP_MDI (1 << 7)
  315 +#define P1CR_AN_DONE (1 << 6)
  316 +#define P1CR_LINK_GOOD (1 << 5)
  317 +#define P1CR_PNTR_FLOW (1 << 4)
  318 +#define P1CR_PNTR_100BT_FDX (1 << 3)
  319 +#define P1CR_PNTR_100BT_HDX (1 << 2)
  320 +#define P1CR_PNTR_10BT_FDX (1 << 1)
  321 +#define P1CR_PNTR_10BT_HDX (1 << 0)
  322 +
  323 +/* TX Frame control */
  324 +#define TXFR_TXIC (1 << 15)
  325 +#define TXFR_TXFID_MASK (0x3f << 0)
  326 +#define TXFR_TXFID_SHIFT (0)
  327 +
  328 +#define KS_P1SR 0xF8
  329 +#define P1SR_HP_MDIX (1 << 15)
  330 +#define P1SR_REV_POL (1 << 13)
  331 +#define P1SR_OP_100M (1 << 10)
  332 +#define P1SR_OP_FDX (1 << 9)
  333 +#define P1SR_OP_MDI (1 << 7)
  334 +#define P1SR_AN_DONE (1 << 6)
  335 +#define P1SR_LINK_GOOD (1 << 5)
  336 +#define P1SR_PNTR_FLOW (1 << 4)
  337 +#define P1SR_PNTR_100BT_FDX (1 << 3)
  338 +#define P1SR_PNTR_100BT_HDX (1 << 2)
  339 +#define P1SR_PNTR_10BT_FDX (1 << 1)
  340 +#define P1SR_PNTR_10BT_HDX (1 << 0)
  341 +
  342 +#define ENUM_BUS_NONE 0
  343 +#define ENUM_BUS_8BIT 1
  344 +#define ENUM_BUS_16BIT 2
  345 +#define ENUM_BUS_32BIT 3
  346 +
  347 +#define MAX_MCAST_LST 32
  348 +#define HW_MCAST_SIZE 8
  349 +#define MAC_ADDR_LEN 6
  350 +
  351 +/* Chip ID values */
  352 +struct chip_id {
  353 + u16 id;
  354 + char *name;
  355 +};
  356 +
  357 +#endif
... ... @@ -71,6 +71,7 @@
71 71 void gt6426x_eth_initialize(bd_t *bis);
72 72 int inca_switch_initialize(bd_t *bis);
73 73 int ks8695_eth_initialize(void);
  74 +int ks8851_mll_initialize(u8 dev_num, int base_addr);
74 75 int lan91c96_initialize(u8 dev_num, int base_addr);
75 76 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
76 77 int mcdmafec_initialize(bd_t *bis);