All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
@ 2010-08-25 12:47 Reinhard Meyer
  2010-08-26  3:55 ` Mike Frysinger
  0 siblings, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-08-25 12:47 UTC (permalink / raw)
  To: u-boot

From: Reinhard Meyer <info@emk-elektronik.de>

Signed-off-by: Reinhard Meyer <u-boot@emk-elektronik.de>
---
 drivers/net/Makefile   |    1 +
 drivers/net/enc28j60.c |  650 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/enc28j60.h |  217 ++++++++++++++++
 include/netdev.h       |    1 +
 4 files changed, 869 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/enc28j60.c
 create mode 100644 drivers/net/enc28j60.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 479954d..79eb66b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -39,6 +39,7 @@ COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o
 COBJS-$(CONFIG_DNET) += dnet.o
 COBJS-$(CONFIG_E1000) += e1000.o
 COBJS-$(CONFIG_EEPRO100) += eepro100.o
+COBJS-$(CONFIG_ENC28J60) += enc28j60.o
 COBJS-$(CONFIG_ENC28J60_LPC2292) += enc28j60_lpc2292.o
 COBJS-$(CONFIG_EP93XX) += ep93xx_eth.o
 COBJS-$(CONFIG_ETHOC) += ethoc.o
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
new file mode 100644
index 0000000..dec5d78
--- /dev/null
+++ b/drivers/net/enc28j60.c
@@ -0,0 +1,650 @@
+/*
+ * (X) reworked enc28j60.c
+ * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <spi.h>
+#include <malloc.h>
+#include <asm/arch/hardware.h>
+#include "enc28j60.h"
+
+#define ENC28J60_DRIVERNAME "enc"
+
+#define FAILSAFE_VALUE 5000
+
+/*
+ * Controller memory layout:
+ *
+ * 0x0000 - 0x17ff  6k bytes receive buffer
+ * 0x1800 - 0x1fff  2k bytes transmit buffer
+ *
+ * Use the lower memory for receiver buffer. See errata pt. 5
+ */
+#define ENC_RX_BUF_START	0x0000
+#define ENC_TX_BUF_START	0x1800
+#define ENC_RX_BUF_END		0x17ff
+#define ENC_TX_BUF_END		0x1fff
+#define ENC_MAX_FRM_LEN		1518
+
+/*
+ * NEW feature:
+ * we encode a register's bank in the upper byte,
+ * use a cached value to keep track of the current bank
+ * and add automatic bank switching to register accesses
+ *
+ * registers available in all banks have bank number 0
+ */
+static u8 enc_r8 (u16 regNo);
+static u16 enc_r16 (u16 regNo);
+static void enc_w8 (u16 regNo, u8 data);
+static void enc_w16 (u16 regNo, u16 data);
+static void enc_w8Retry (u16 regNo, u8 data, int c);
+static void enc_w16Retry (u16 regNo, u16 data, int c);
+static void enc_rbuf (u16 length, u8 *pBuff);
+static void enc_wbuf (u16 length, u8 *pBuff);
+/* regNo is char here to detect someone trying to use a non common register */
+static void enc_bset (u8 regNo, u8 data);
+static void enc_bclr (u8 regNo, u8 data);
+static void enc_reset (void);
+static void enc_init (u8 *pEthAddr);
+static u16 phy_read (u8 addr);
+static void phy_write(u8, u16);
+static void enc_poll (void);
+static void enc_receive (void);
+
+static u8 bank = 0;	/* current bank in enc28j60 */
+static u16 next_pointer;
+/* NetReceive() requires the packet to be word aligned! */
+static u8 packet[ENC_MAX_FRM_LEN] __attribute__ ((aligned(4)));
+static int rx_reset_counter = 0;
+static struct spi_slave *slave;
+
+#define RX_RESET_COUNTER 1000;
+
+/*
+ * high byte of the register contains bank number:
+ * 0: no bank switch necessary
+ * 1: switch to bank 0
+ * 2: switch to bank 1
+ * 3: switch to bank 2
+ * 4: switch to bank 3
+ */
+static void encSetBank (const u16 regNo)
+{
+	u8 newbank = regNo >> 8;
+
+	if (newbank == 0 || newbank == bank)
+		return;
+	switch (newbank) {
+	case 1:
+		enc_bclr(CTL_REG_ECON1, ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
+		break;
+	case 2:
+		enc_bset(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+		enc_bclr(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+		break;
+	case 3:
+		enc_bclr(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+		enc_bset(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+		break;
+	case 4:
+		enc_bset(CTL_REG_ECON1, ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
+		break;
+	}
+	bank = newbank;
+}
+
+int enc28j60_init (struct eth_device *dev, bd_t * bis)
+{
+	u8 estatVal;
+	u8 enetaddr[6];
+
+	slave = spi_setup_slave(ENC_SPI_BUS, ENC_CS_NUM, ENC_SPI_CLOCK, SPI_MODE_0);
+	spi_claim_bus (slave);
+	/*
+	 * Wait for CLKRDY to become set (i.e., check that we can communicate with
+	 * the ENC)
+	 * TODO: a timeout might be wise here...
+	 */
+	do
+	{
+		estatVal = enc_r8(CTL_REG_ESTAT);
+	} while ((estatVal & 0x08) || (~estatVal & ENC_ESTAT_CLKRDY));
+
+	/* initialize controller */
+	enc_reset ();
+#ifdef CONFIG_NET_MULTI
+	memcpy(enetaddr, eth_get_dev()->enetaddr, 6);
+#else
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+#endif
+	enc_init(enetaddr);
+	enc_bset(CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+	return 0;
+}
+
+int enc28j60_send (struct eth_device *dev, volatile void *packet, int length)
+{
+	/* check frame length, etc. */
+
+	/* set EWRPT */
+	enc_w16(CTL_REG_EWRPTL, ENC_TX_BUF_START);
+	/* set ETXND */
+	enc_w16(CTL_REG_ETXNDL, length + ENC_TX_BUF_START);
+	/* set ETXST */
+	enc_w16(CTL_REG_ETXSTL, ENC_TX_BUF_START);
+	/* write packet */
+	enc_wbuf(length, (u8 *) packet);
+	/*
+	 * Verify that the internal transmit logic has not been altered by excessive
+	 *  collisions.  See Errata B4 12 and 14.
+	 */
+	if (enc_r8(CTL_REG_EIR) & ENC_EIR_TXERIF) {
+		enc_bset(CTL_REG_ECON1, ENC_ECON1_TXRST);
+		enc_bclr(CTL_REG_ECON1, ENC_ECON1_TXRST);
+	}
+	enc_bclr(CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
+	/* set ECON1.TXRTS */
+	enc_bset(CTL_REG_ECON1, ENC_ECON1_TXRTS);
+	return 0;
+}
+
+/*
+ * This function resets the receiver only. This function may be called from
+ * interrupt-context.
+ */
+static void encReceiverReset (void)
+{
+	u8 econ1;
+
+	econ1 = enc_r8(CTL_REG_ECON1);
+	if ((econ1 & ENC_ECON1_RXRST) == 0) {
+		enc_bset(CTL_REG_ECON1, ENC_ECON1_RXRST);
+		rx_reset_counter = RX_RESET_COUNTER;
+	}
+}
+
+/*
+ * receiver reset timer
+ */
+static void encReceiverResetCallback (void)
+{
+	enc_bclr(CTL_REG_ECON1, ENC_ECON1_RXRST);
+	enc_bset(CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+}
+
+/*
+ * Check for received packets. Call NetReceive for each packet. The return
+ * value is ignored by the caller.
+ */
+int enc28j60_recv (struct eth_device *dev)
+{
+	if (rx_reset_counter > 0 && --rx_reset_counter == 0) {
+		encReceiverResetCallback();
+	}
+	enc_poll();
+	return 0;
+}
+
+void enc28j60_halt (struct eth_device *dev)
+{
+	enc_bclr(CTL_REG_ECON1, ENC_ECON1_RXEN);	/* disable receive */
+}
+
+static void enc_poll (void)
+{
+	u8 eir_reg;
+	volatile u8 estat_reg;
+	u8 pkt_cnt;
+
+#ifdef CONFIG_USE_IRQ
+	/* clear global interrupt enable bit in enc28j60 */
+	enc_bclr(CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+	estat_reg = enc_r8(CTL_REG_ESTAT);
+	eir_reg = enc_r8(CTL_REG_EIR);
+	if (eir_reg & ENC_EIR_TXIF) {
+		/* clear TXIF bit in EIR */
+		enc_bclr(CTL_REG_EIR, ENC_EIR_TXIF);
+	}
+	/* We have to use pktcnt and not pktif bit, see errata pt. 6 */
+	/* read pktcnt */
+	pkt_cnt = enc_r8(CTL_REG_EPKTCNT);
+	if (pkt_cnt > 0) {
+		if ((eir_reg & ENC_EIR_PKTIF) == 0) {
+			debug("enc_poll: pkt cnt > 0, but pktif not set\n");
+		}
+		enc_receive();
+		/*
+		 * clear PKTIF bit in EIR, this should not need to be done but it
+		 *  seems like we get problems if we do not
+		 */
+		enc_bclr(CTL_REG_EIR, ENC_EIR_PKTIF);
+	}
+	if (eir_reg & ENC_EIR_RXERIF) {
+		printf("enc_poll: rx error\n");
+		enc_bclr(CTL_REG_EIR, ENC_EIR_RXERIF);
+	}
+	if (eir_reg & ENC_EIR_TXERIF) {
+		printf("enc_poll: tx error\n");
+		enc_bclr(CTL_REG_EIR, ENC_EIR_TXERIF);
+	}
+#ifdef CONFIG_USE_IRQ
+	/* set global interrupt enable bit in enc28j60 */
+	enc_bset(CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+static void enc_receive (void)
+{
+	u16 pkt_len;
+	u16 copy_len;
+	u16 status;
+	u8 eir_reg;
+	u8 pkt_cnt = 0;
+	u16 rxbuf_rdpt;
+	u8 hbuf[6];
+
+	enc_w16(CTL_REG_ERDPTL, next_pointer);
+	do {
+		enc_rbuf(6, hbuf);
+		next_pointer = hbuf[0] | (hbuf[1] << 8);
+		pkt_len = hbuf[2] | (hbuf[3] << 8);
+		status = hbuf[4] | (hbuf[5] << 8);
+#ifdef DEBUG
+		printf("next_pointer=$%04x pkt_len=%u status=$%04x\n",
+			next_pointer, pkt_len, status);
+#endif
+		if (pkt_len <= ENC_MAX_FRM_LEN)
+			copy_len = pkt_len;
+		else
+			copy_len = 0;
+		if ((status & (1L << 7)) == 0) /* check Received Ok bit */
+			copy_len = 0;
+		/* check if next pointer is resonable */
+		if (next_pointer >= ENC_TX_BUF_START)
+			copy_len = 0;
+		if (copy_len > 0) {
+			enc_rbuf(copy_len, packet);
+		}
+		/* advance read pointer to next pointer */
+		enc_w16(CTL_REG_ERDPTL, next_pointer);
+		/* decrease packet counter */
+		enc_bset(CTL_REG_ECON2, ENC_ECON2_PKTDEC);
+		/*
+		 * Only odd values should be written to ERXRDPTL,
+		 * see errata B4 pt.13
+		 */
+		rxbuf_rdpt = next_pointer - 1;
+		if ((rxbuf_rdpt < enc_r16(CTL_REG_ERXSTL)) ||
+			(rxbuf_rdpt > enc_r16(CTL_REG_ERXNDL))) {
+			enc_w16(CTL_REG_ERXRDPTL, enc_r16(CTL_REG_ERXNDL));
+		} else {
+			enc_w16(CTL_REG_ERXRDPTL, rxbuf_rdpt);
+		}
+		/* read pktcnt */
+		pkt_cnt = enc_r8(CTL_REG_EPKTCNT);
+		if (copy_len == 0) {
+			eir_reg = enc_r8(CTL_REG_EIR);
+			encReceiverReset();
+			printf("eth_rx: copy_len=0\n");
+			continue;
+		}
+		NetReceive(packet, pkt_len);
+		eir_reg = enc_r8(CTL_REG_EIR);
+	} while (pkt_cnt);	/* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
+}
+
+static void enc_w8 (u16 regNo, u8 data)
+{
+	u8 dout[2];
+
+	encSetBank(regNo);
+	dout[0] = (0x40 | regNo); /* write in regNo */
+	dout[1] = data;
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+static void enc_w16 (u16 regNo, u16 data)
+{
+	u8 dout[2];
+
+	encSetBank(regNo);
+	dout[0] = (0x40 | regNo); /* write in regNo */
+	dout[1] = data;
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+	dout[0]++; /* write in regNo+1 */
+	dout[1] = data >> 8;
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+static void enc_w8Retry (u16 regNo, u8 data, int c)
+{
+	u8 dout[2];
+	u8 readback;
+	int i;
+
+	encSetBank(regNo);
+	for (i = 0; i < c; i++) {
+		dout[0] = (0x40 | regNo); /* write in regNo */
+		dout[1] = data;
+		spi_xfer(slave, 2 * 8, dout, NULL,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		readback = enc_r8(regNo);
+		if (readback == data)
+			break;
+	}
+	if (i == c) {
+		printf("enc28j60: write reg %d failed\n", regNo);
+	}
+}
+
+static void enc_w16Retry (u16 regNo, u16 data, int c)
+{
+	enc_w8Retry(regNo, data, c);
+	enc_w8Retry(regNo+1, data>>8, c);
+}
+
+static u8 enc_r8 (u16 regNo)
+{
+	u8 dout[3];
+	u8 din[3];
+
+	encSetBank(regNo);
+	dout[0] = regNo;	/* read in regNo */
+	/* check if MAC or MII register */
+	if (((bank == 3) && (dout[0] <= 0x1a)) ||
+	    ((bank == 4) && (dout[0] <= 0x05 || dout[0] == 0x0a))) {
+		/* read three bytes */
+		spi_xfer(slave, 3 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		return din[2];
+	} else {
+		spi_xfer(slave, 2 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		return din[1];
+	}
+}
+
+static u16 enc_r16 (u16 regNo)
+{
+	u8 dout[3];
+	u8 din[3];
+	u16 rxByte;
+
+	encSetBank(regNo);
+	dout[0] = regNo;	/* read in regNo */
+	/* check if MAC or MII register */
+	if (((bank == 3) && (dout[0] <= 0x1a)) ||
+	    ((bank == 4) && (dout[0] <= 0x05 || dout[0] == 0x0a))) {
+		/* read three bytes (twice) */
+		spi_xfer(slave, 3 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		rxByte = din[2];
+		dout[0]++;
+		spi_xfer(slave, 3 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		rxByte |= din[2] << 8;
+	} else {
+		spi_xfer(slave, 2 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		rxByte = din[1];
+		dout[0]++;
+		spi_xfer(slave, 2 * 8, dout, din,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+		rxByte |= din[1] << 8;
+	}
+	return rxByte;
+}
+
+static void enc_rbuf (u16 length, u8 *pBuff)
+{
+	u8 dout[1];
+
+	dout[0] = (0x20 | 0x1a);
+	spi_xfer(slave, 8, dout, NULL, SPI_XFER_BEGIN);
+	spi_xfer(slave, length * 8, NULL, pBuff, SPI_XFER_END);
+	debug("Rx:\n");
+#ifdef DEBUG
+	print_buffer(0, pBuff, 1, length, 0);
+#endif
+}
+
+static void enc_wbuf (u16 length, u8 *pBuff)
+{
+	u8 dout[2];
+	dout[0] = (0x60 | 0x1a);
+	dout[1] = (0x00);
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN);
+	spi_xfer(slave, length * 8, pBuff, NULL, SPI_XFER_END);
+	debug("Tx:\n");
+#ifdef DEBUG
+	print_buffer(0, pBuff, 1, length, 0);
+#endif
+}
+
+static void enc_bset (u8 regNo, u8 data)
+{
+	u8 dout[2];
+
+	dout[0] = (0x80 | regNo);
+	dout[1] = data;
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+static void enc_bclr (u8 regNo, u8 data)
+{
+	u8 dout[2];
+
+	dout[0] = (0xA0 | regNo);
+	dout[1] = data;
+	spi_xfer(slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+static void enc_reset (void)
+{
+	u8 dout[1];
+
+	dout[0] = 0xff;
+	spi_xfer(slave, 8, dout, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+	/* sleep 1 ms. See errata pt. 2 */
+	udelay(1000);
+}
+
+static void enc_init (u8 *pEthAddr)
+{
+	u16 phid1 = 0;
+	u16 phid2 = 0;
+
+	/*
+	 * Setup the buffer space. The reset values are valid for the
+	 * other pointers.
+	 *
+	 * We shall not write to ERXST, see errata pt. 5. Instead we
+	 * have to make sure that ENC_RX_BUS_START is 0.
+	 */
+	enc_w16Retry(CTL_REG_ERXSTL, ENC_RX_BUF_START, 1);
+	enc_w16Retry(CTL_REG_ERXNDL, ENC_RX_BUF_END, 1);
+	enc_w16Retry(CTL_REG_ERDPTL, ENC_RX_BUF_START, 1);
+	next_pointer = ENC_RX_BUF_START;
+	/* verify identification */
+	phid1 = phy_read(PHY_REG_PHID1);
+	phid2 = phy_read(PHY_REG_PHID2);
+	if (phid1 != ENC_PHID1_VALUE
+	    || (phid2 & ENC_PHID2_MASK) != ENC_PHID2_VALUE) {
+		printf("ERROR: failed to identify controller\n");
+		printf("phid1 = %x, phid2 = %x\n",
+			phid1, (phid2 & ENC_PHID2_MASK));
+		printf("should be phid1 = %x, phid2 = %x\n",
+			ENC_PHID1_VALUE, ENC_PHID2_VALUE);
+	}
+#ifdef ENC_BROADCAST_RCV
+	/* set the filter to receive only good-CRC unicast and broadcast frames */
+	enc_w8Retry(CTL_REG_ERXFCON,
+		ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN, 10);
+#else
+	/* set the filter to receive only good-CRC unicast frames */
+	enc_w8Retry(CTL_REG_ERXFCON,
+		ENC_RFR_UCEN | ENC_RFR_CRCEN, 10);
+#endif
+	/* Pull MAC out of Reset */
+	/* enable MAC to receive frames */
+	enc_w8Retry(CTL_REG_MACON1,
+		(ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS), 10);
+	/* configure pad, tx-crc and duplex */
+	enc_w8Retry(CTL_REG_MACON3,
+		(ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN | ENC_MACON3_FRMLNEN), 10);
+	/* Allow infinite deferals if the medium is continously busy */
+	enc_w8Retry(CTL_REG_MACON4, (1<<6) /*ENC_MACON4_DEFER*/, 10);
+	/* Late collisions occur beyond 63 bytes */
+	enc_w8Retry(CTL_REG_MACLCON2, 63, 10);
+	/* Set (low byte) Non-Back-to_Back Inter-Packet Gap. Recommended 0x12 */
+	enc_w8Retry(CTL_REG_MAIPGL, 0x12, 10);
+	/*
+	* Set (high byte) Non-Back-to_Back Inter-Packet Gap. Recommended
+	* 0x0c for half-duplex. Nothing for full-duplex
+	*/
+	enc_w8Retry(CTL_REG_MAIPGH, 0x0C, 10);
+	/* set maximum frame length */
+	enc_w16Retry(CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN, 10);
+	/*
+	 * Set MAC back-to-back inter-packet gap. Recommended 0x12 for half duplex
+	 * and 0x15 for full duplex.
+	 */
+	enc_w8Retry(CTL_REG_MABBIPG, 0x12, 10);
+	/* set MAC address */
+	enc_w8Retry(CTL_REG_MAADR0, pEthAddr[5], 1);
+	enc_w8Retry(CTL_REG_MAADR1, pEthAddr[4], 1);
+	enc_w8Retry(CTL_REG_MAADR2, pEthAddr[3], 1);
+	enc_w8Retry(CTL_REG_MAADR3, pEthAddr[2], 1);
+	enc_w8Retry(CTL_REG_MAADR4, pEthAddr[1], 1);
+	enc_w8Retry(CTL_REG_MAADR5, pEthAddr[0], 1);
+	/*
+	 * Prevent automatic loopback of data beeing transmitted by setting
+	 * ENC_PHCON2_HDLDIS
+	 */
+	phy_write(PHY_REG_PHCON2, (1<<8));
+	/*
+	 * LEDs configuration
+	 * LEDA: LACFG = 0100 -> display link status
+	 * LEDB: LBCFG = 0111 -> display TX & RX activity
+	 * STRCH = 1 -> LED pulses
+	 */
+	phy_write(PHY_REG_PHLCON, 0x0472);
+	/* Reset PDPXMD-bit => half duplex */
+	phy_write(PHY_REG_PHCON1, 0);
+	/*
+	 * Receive settings
+	 */
+#ifdef CONFIG_USE_IRQ
+	/* enable interrupts */
+	enc_bset(CTL_REG_EIE, ENC_EIE_PKTIE);
+	enc_bset(CTL_REG_EIE, ENC_EIE_TXIE);
+	enc_bset(CTL_REG_EIE, ENC_EIE_RXERIE);
+	enc_bset(CTL_REG_EIE, ENC_EIE_TXERIE);
+	enc_bset(CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+/*
+ *
+ * Description:
+ *    Read PHY registers.
+ *
+ *    NOTE! This function will change to Bank 2.
+ *
+ * Params:
+ *    [in] addr address of the register to read
+ *
+ * Returns:
+ *    The value in the register
+ */
+static u16 phy_read (u8 addr)
+{
+	int cnt;
+
+	/* write address to MIREGADR */
+	enc_w8(CTL_REG_MIREGADR, addr);
+	/* set MICMD.MIIRD */
+	enc_w8(CTL_REG_MICMD, ENC_MICMD_MIIRD);
+	/* poll MISTAT.BUSY bit until operation is complete */
+	cnt = 0;
+	while ((enc_r8(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		if (cnt++ >= 1000) {
+			/* GJ - this seems extremely dangerous! */
+			printf("#1");
+			return 0;
+		}
+	}
+	/* clear MICMD.MIIRD */
+	enc_w8(CTL_REG_MICMD, 0);
+	return enc_r16(CTL_REG_MIRDL);
+}
+
+/*
+ *
+ * Taken from the Linux driver.
+ * Description:
+ * Write PHY registers.
+ *
+ * NOTE! This function will change to Bank 3.
+ *
+ * Params:
+ * [in] addr address of the register to write to
+ * [in] data to be written
+ *
+ * Returns:
+ *    None
+ */
+static void phy_write(u8 addr, u16 data)
+{
+	int cnt;
+	/* write address to MIREGADR */
+	enc_w8(CTL_REG_MIREGADR, addr);
+	enc_w16(CTL_REG_MIWRL, data);
+	/* poll MISTAT.BUSY bit until operation is complete */
+	cnt = 0;
+	while((enc_r8(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		if (cnt++ >= 1000) {
+			/* GJ - this seems extremely dangerous! */
+			printf("#2");
+			return;
+		}
+	}
+}
+
+int enc28j60_initialize(u8 dev_num)
+{
+	struct eth_device *dev;
+
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		return 0;
+	}
+	memset(dev, 0, sizeof(*dev));
+	dev->init = enc28j60_init;
+	dev->halt = enc28j60_halt;
+	dev->send = enc28j60_send;
+	dev->recv = enc28j60_recv;
+	sprintf(dev->name, "%s%hu", ENC28J60_DRIVERNAME, dev_num);
+	eth_register(dev);
+	return 0;
+}
diff --git a/drivers/net/enc28j60.h b/drivers/net/enc28j60.h
new file mode 100644
index 0000000..8bbee68
--- /dev/null
+++ b/drivers/net/enc28j60.h
@@ -0,0 +1,217 @@
+/*
+ * (X) extracted from enc28j60.c
+ * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* NEW: encode (bank number+1) in upper byte */
+
+/* these are common in all banks */
+#define CTL_REG_EIE		0x01B
+#define CTL_REG_EIR		0x01C
+#define CTL_REG_ESTAT		0x01D
+#define CTL_REG_ECON2		0x01E
+#define CTL_REG_ECON1		0x01F
+
+/* Control Registers in Bank 0 */
+#define CTL_REG_ERDPTL		0x100
+#define CTL_REG_ERDPTH		0x101
+#define CTL_REG_EWRPTL		0x102
+#define CTL_REG_EWRPTH		0x103
+#define CTL_REG_ETXSTL		0x104
+#define CTL_REG_ETXSTH		0x105
+#define CTL_REG_ETXNDL		0x106
+#define CTL_REG_ETXNDH		0x107
+#define CTL_REG_ERXSTL		0x108
+#define CTL_REG_ERXSTH		0x109
+#define CTL_REG_ERXNDL		0x10A
+#define CTL_REG_ERXNDH		0x10B
+#define CTL_REG_ERXRDPTL	0x10C
+#define CTL_REG_ERXRDPTH	0x10D
+#define CTL_REG_ERXWRPTL	0x10E
+#define CTL_REG_ERXWRPTH	0x10F
+#define CTL_REG_EDMASTL		0x110
+#define CTL_REG_EDMASTH		0x111
+#define CTL_REG_EDMANDL		0x112
+#define CTL_REG_EDMANDH		0x113
+#define CTL_REG_EDMADSTL	0x114
+#define CTL_REG_EDMADSTH	0x115
+#define CTL_REG_EDMACSL		0x116
+#define CTL_REG_EDMACSH		0x117
+
+/* Control Registers in Bank 1 */
+#define CTL_REG_EHT0		0x200
+#define CTL_REG_EHT1		0x201
+#define CTL_REG_EHT2		0x202
+#define CTL_REG_EHT3		0x203
+#define CTL_REG_EHT4		0x204
+#define CTL_REG_EHT5		0x205
+#define CTL_REG_EHT6		0x206
+#define CTL_REG_EHT7		0x207
+#define CTL_REG_EPMM0		0x208
+#define CTL_REG_EPMM1		0x209
+#define CTL_REG_EPMM2		0x20A
+#define CTL_REG_EPMM3		0x20B
+#define CTL_REG_EPMM4		0x20C
+#define CTL_REG_EPMM5		0x20D
+#define CTL_REG_EPMM6		0x20E
+#define CTL_REG_EPMM7		0x20F
+#define CTL_REG_EPMCSL		0x210
+#define CTL_REG_EPMCSH		0x211
+#define CTL_REG_EPMOL		0x214
+#define CTL_REG_EPMOH		0x215
+#define CTL_REG_EWOLIE		0x216
+#define CTL_REG_EWOLIR		0x217
+#define CTL_REG_ERXFCON		0x218
+#define CTL_REG_EPKTCNT		0x219
+
+/* Control Registers in Bank 2 */
+#define CTL_REG_MACON1		0x300
+#define CTL_REG_MACON2		0x301
+#define CTL_REG_MACON3		0x302
+#define CTL_REG_MACON4		0x303
+#define CTL_REG_MABBIPG		0x304
+#define CTL_REG_MAIPGL		0x306
+#define CTL_REG_MAIPGH		0x307
+#define CTL_REG_MACLCON1	0x308
+#define CTL_REG_MACLCON2	0x309
+#define CTL_REG_MAMXFLL		0x30A
+#define CTL_REG_MAMXFLH		0x30B
+#define CTL_REG_MAPHSUP		0x30D
+#define CTL_REG_MICON		0x311
+#define CTL_REG_MICMD		0x312
+#define CTL_REG_MIREGADR	0x314
+#define CTL_REG_MIWRL		0x316
+#define CTL_REG_MIWRH		0x317
+#define CTL_REG_MIRDL		0x318
+#define CTL_REG_MIRDH		0x319
+
+/* Control Registers in Bank 3 */
+#define CTL_REG_MAADR1		0x400
+#define CTL_REG_MAADR0		0x401
+#define CTL_REG_MAADR3		0x402
+#define CTL_REG_MAADR2		0x403
+#define CTL_REG_MAADR5		0x404
+#define CTL_REG_MAADR4		0x405
+#define CTL_REG_EBSTSD		0x406
+#define CTL_REG_EBSTCON		0x407
+#define CTL_REG_EBSTCSL		0x408
+#define CTL_REG_EBSTCSH		0x409
+#define CTL_REG_MISTAT		0x40A
+#define CTL_REG_EREVID		0x412
+#define CTL_REG_ECOCON		0x415
+#define CTL_REG_EFLOCON		0x417
+#define CTL_REG_EPAUSL		0x418
+#define CTL_REG_EPAUSH		0x419
+
+/* PHY Register */
+#define PHY_REG_PHID1		0x02
+#define PHY_REG_PHID2		0x03
+#define PHY_REG_PHCON1		0x00
+#define PHY_REG_PHCON2		0x10
+#define PHY_REG_PHLCON		0x14
+
+/* Receive Filter Register (ERXFCON) bits */
+#define ENC_RFR_UCEN		0x80
+#define ENC_RFR_ANDOR		0x40
+#define ENC_RFR_CRCEN		0x20
+#define ENC_RFR_PMEN		0x10
+#define ENC_RFR_MPEN		0x08
+#define ENC_RFR_HTEN		0x04
+#define ENC_RFR_MCEN		0x02
+#define ENC_RFR_BCEN		0x01
+
+/* ECON1 Register Bits */
+#define ENC_ECON1_TXRST		0x80
+#define ENC_ECON1_RXRST		0x40
+#define ENC_ECON1_DMAST		0x20
+#define ENC_ECON1_CSUMEN	0x10
+#define ENC_ECON1_TXRTS		0x08
+#define ENC_ECON1_RXEN		0x04
+#define ENC_ECON1_BSEL1		0x02
+#define ENC_ECON1_BSEL0		0x01
+
+/* ECON2 Register Bits */
+#define ENC_ECON2_AUTOINC	0x80
+#define ENC_ECON2_PKTDEC	0x40
+#define ENC_ECON2_PWRSV		0x20
+#define ENC_ECON2_VRPS		0x08
+
+/* EIR Register Bits */
+#define ENC_EIR_PKTIF		0x40
+#define ENC_EIR_DMAIF		0x20
+#define ENC_EIR_LINKIF		0x10
+#define ENC_EIR_TXIF		0x08
+#define ENC_EIR_WOLIF		0x04
+#define ENC_EIR_TXERIF		0x02
+#define ENC_EIR_RXERIF		0x01
+
+/* ESTAT Register Bits */
+#define ENC_ESTAT_INT		0x80
+#define ENC_ESTAT_LATECOL	0x10
+#define ENC_ESTAT_RXBUSY	0x04
+#define ENC_ESTAT_TXABRT	0x02
+#define ENC_ESTAT_CLKRDY	0x01
+
+/* EIE Register Bits */
+#define ENC_EIE_INTIE		0x80
+#define ENC_EIE_PKTIE		0x40
+#define ENC_EIE_DMAIE		0x20
+#define ENC_EIE_LINKIE		0x10
+#define ENC_EIE_TXIE		0x08
+#define ENC_EIE_WOLIE		0x04
+#define ENC_EIE_TXERIE		0x02
+#define ENC_EIE_RXERIE		0x01
+
+/* MACON1 Register Bits */
+#define ENC_MACON1_LOOPBK	0x10
+#define ENC_MACON1_TXPAUS	0x08
+#define ENC_MACON1_RXPAUS	0x04
+#define ENC_MACON1_PASSALL	0x02
+#define ENC_MACON1_MARXEN	0x01
+
+/* MACON2 Register Bits */
+#define ENC_MACON2_MARST	0x80
+#define ENC_MACON2_RNDRST	0x40
+#define ENC_MACON2_MARXRST	0x08
+#define ENC_MACON2_RFUNRST	0x04
+#define ENC_MACON2_MATXRST	0x02
+#define ENC_MACON2_TFUNRST	0x01
+
+/* MACON3 Register Bits */
+#define ENC_MACON3_PADCFG2	0x80
+#define ENC_MACON3_PADCFG1	0x40
+#define ENC_MACON3_PADCFG0	0x20
+#define ENC_MACON3_TXCRCEN	0x10
+#define ENC_MACON3_PHDRLEN	0x08
+#define ENC_MACON3_HFRMEN	0x04
+#define ENC_MACON3_FRMLNEN	0x02
+#define ENC_MACON3_FULDPX	0x01
+
+/* MICMD Register Bits */
+#define ENC_MICMD_MIISCAN	0x02
+#define ENC_MICMD_MIIRD		0x01
+
+/* MISTAT Register Bits */
+#define ENC_MISTAT_NVALID	0x04
+#define ENC_MISTAT_SCAN		0x02
+#define ENC_MISTAT_BUSY		0x01
+
+/* PHID1 and PHID2 values */
+#define ENC_PHID1_VALUE		0x0083
+#define ENC_PHID2_VALUE		0x1400
+#define ENC_PHID2_MASK		0xFC00
diff --git a/include/netdev.h b/include/netdev.h
index 94eedfe..4210e69 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -54,6 +54,7 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr);
 int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
+int enc28j60_initialize(int id);
 int ep93xx_eth_initialize(u8 dev_num, int base_addr);
 int ethoc_initialize(u8 dev_num, int base_addr);
 int eth_3com_initialize (bd_t * bis);
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-25 12:47 [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework Reinhard Meyer
@ 2010-08-26  3:55 ` Mike Frysinger
  2010-08-26  6:19   ` Reinhard Meyer
  2010-09-03 17:50   ` Reinhard Meyer
  0 siblings, 2 replies; 13+ messages in thread
From: Mike Frysinger @ 2010-08-26  3:55 UTC (permalink / raw)
  To: u-boot

On Wednesday, August 25, 2010 08:47:39 Reinhard Meyer wrote:
> From: Reinhard Meyer <info@emk-elektronik.de>
> 
> Signed-off-by: Reinhard Meyer <u-boot@emk-elektronik.de>

these two fields should match (e-mail)

also, this patch seems to depend on some other change not in mainline or Ben's 
net tree ...

> +#include <config.h>
> +#include <common.h>

the common.h header takes care of config.h already

> +#include <asm/arch/hardware.h>

err, what ?

> +#define ENC28J60_DRIVERNAME "enc"

this is used in only one place, so no point in a define

> +#define FAILSAFE_VALUE 5000

this isnt used anywhere

> +static u8 enc_r8 (u16 regNo);
> +static void enc_rbuf (u16 length, u8 *pBuff);

this whole file needs to be checked for function style.  no space after the 
function name.

also, drop the camel case and hungarian notation.  use "reg" and "buff".

> +/* NetReceive() requires the packet to be word aligned! */
> +static u8 packet[ENC_MAX_FRM_LEN] __attribute__ ((aligned(4)));

why do you need to declare your own buffer ?  the common code already sets up 
one for you and it uses the standard 1518 size (PKTSIZE).

> +int enc28j60_init (struct eth_device *dev, bd_t * bis)

all of the enc28j60 funcs that go into eth_device dont need to be public.  so 
add static to the init/halt/recv/send funcs.

also, it's "bd_t *bis"

> +	slave = spi_setup_slave(ENC_SPI_BUS, ENC_CS_NUM, ENC_SPI_CLOCK,
> SPI_MODE_0);

pass the bus/cs/speed/mode in to the initialize function and store it in the 
per-device state.  then you can work fine with multiple enc28j60 devices in 
one board.

along those lines, all of the local enc funcs should be changed to take the 
private state and operate off that instead of random global variables.

> +	spi_claim_bus (slave);

missing check on the return value

> +	do
> +	{
> +		estatVal = enc_r8(CTL_REG_ESTAT);
> +	} while ((estatVal & 0x08) || (~estatVal & ENC_ESTAT_CLKRDY));

the bit inverting ("~") should be on the mask so it's done at compile time 
instead of forcing the board to do it at runtime

> +#ifdef CONFIG_NET_MULTI
> +	memcpy(enetaddr, eth_get_dev()->enetaddr, 6);
> +#else
> +	eth_getenv_enetaddr("ethaddr", enetaddr);
> +#endif
> +	enc_init(enetaddr);

this should be one line:
	enc_init(dev->enetaddr);

also, nowhere in this init func can i see error checking that the enc28j60 
device is actually out there.  the enc_init() should return an error if the 
expected phy's/etc... dont match, and this init func should key off that.

> +static void enc_init (u8 *pEthAddr)
> +{
> +	u16 phid1 = 0;
> +	u16 phid2 = 0;

these are always set up below, so no point in setting them to 0

> +static void phy_write(u8 addr, u16 data)
>
> +	while((enc_r8(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {

missing a space after that "while"

> +	sprintf(dev->name, "%s%hu", ENC28J60_DRIVERNAME, dev_num);

once this func is fixed to take the spi bus/cs, the name can be based on that 
instead of an arbitrary integer.
	"enc%i.%i", bus, cs

> --- /dev/null
> +++ b/drivers/net/enc28j60.h

this header is missing ifdef protection against multiple inclusion

> --- a/include/netdev.h
> +++ b/include/netdev.h
>
> +int enc28j60_initialize(int id);

this doesnt match the prototype in the source.  you should have the .c file 
include netdev.h so that desyncs are caught & prevented in the future.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100825/87dd332f/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-26  3:55 ` Mike Frysinger
@ 2010-08-26  6:19   ` Reinhard Meyer
  2010-08-26  6:32     ` Mike Frysinger
  2010-09-03 17:50   ` Reinhard Meyer
  1 sibling, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-08-26  6:19 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,
>> From: Reinhard Meyer<info@emk-elektronik.de>

Give me a tip how I can change that info. The first patch to this was
committed while I used <info>. Squashing other patches into it does not
change that. rebase -i, edit, --amend does not present that line for
edit. The only idea I have now is making an empty commit and squashing
that before the original patch...

> also, this patch seems to depend on some other change not in mainline or Ben's
> net tree ...

Should have mentioned that the "move enc28j60 to sidetrack" patch is to be
applied first.

>> +static u8 enc_r8 (u16 regNo);
>> +static void enc_rbuf (u16 length, u8 *pBuff);
>
> this whole file needs to be checked for function style.  no space after the
> function name.

That's what happens if one reworks an existing driver. I'll recheck all this.

> why do you need to declare your own buffer ?  the common code already sets up
> one for you and it uses the standard 1518 size (PKTSIZE).

Ok, better. Just hint me on its name, browsing the common code none did catch
my eye:)

> pass the bus/cs/speed/mode in to the initialize function and store it in the
> per-device state.  then you can work fine with multiple enc28j60 devices in
> one board.

<joke>
Ok, I was already planning to build a 16 port hub using 16 such devices ;)
</joke>
But generalization is good. I might end up using two, actually.

> also, nowhere in this init func can i see error checking that the enc28j60
> device is actually out there.  the enc_init() should return an error if the
> expected phy's/etc... dont match, and this init func should key off that.

I'd like to even have the phy start auto-negotiation at that moment, I'm
just not sure that's ok. I won't wait for it to complete, of course, just
trigger it.

> once this func is fixed to take the spi bus/cs, the name can be based on that
> instead of an arbitrary integer.
> 	"enc%i.%i", bus, cs

setenv ethact enc1.13 - one can get used to that ;)

Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-26  6:19   ` Reinhard Meyer
@ 2010-08-26  6:32     ` Mike Frysinger
  2010-08-26  6:41       ` Reinhard Meyer
  0 siblings, 1 reply; 13+ messages in thread
From: Mike Frysinger @ 2010-08-26  6:32 UTC (permalink / raw)
  To: u-boot

On Thursday, August 26, 2010 02:19:07 Reinhard Meyer wrote:
> >> From: Reinhard Meyer<info@emk-elektronik.de>
> 
> Give me a tip how I can change that info. The first patch to this was
> committed while I used <info>. Squashing other patches into it does not
> change that. rebase -i, edit, --amend does not present that line for
> edit. The only idea I have now is making an empty commit and squashing
> that before the original patch...

use the --author option to the commit sub command

> > why do you need to declare your own buffer ?  the common code already
> > sets up one for you and it uses the standard 1518 size (PKTSIZE).
> 
> Ok, better. Just hint me on its name, browsing the common code none did
> catch my eye:)

NetRxPackets and friends
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100826/933d07b3/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-26  6:32     ` Mike Frysinger
@ 2010-08-26  6:41       ` Reinhard Meyer
  2010-08-26  7:11         ` Mike Frysinger
  0 siblings, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-08-26  6:41 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,
>>>> From: Reinhard Meyer<info@emk-elektronik.de>
>>
>> Give me a tip how I can change that info. The first patch to this was
>> committed while I used<info>. Squashing other patches into it does not
>> change that. rebase -i, edit, --amend does not present that line for
>> edit. The only idea I have now is making an empty commit and squashing
>> that before the original patch...
>
> use the --author option to the commit sub command

Hmm, as I said above, the first commit was made while I had the <info>
address in use. All new commits use the <u-boot> address anyway.
But when I squash new commits onto the first one, the old address
prevails...

I'll try "rebase -i", "edit", reset HEAD^, and a new commit then.
That might work.

Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-26  6:41       ` Reinhard Meyer
@ 2010-08-26  7:11         ` Mike Frysinger
  0 siblings, 0 replies; 13+ messages in thread
From: Mike Frysinger @ 2010-08-26  7:11 UTC (permalink / raw)
  To: u-boot

On Thursday, August 26, 2010 02:41:56 Reinhard Meyer wrote:
> >>>> From: Reinhard Meyer<info@emk-elektronik.de>
> >> 
> >> Give me a tip how I can change that info. The first patch to this was
> >> committed while I used<info>. Squashing other patches into it does not
> >> change that. rebase -i, edit, --amend does not present that line for
> >> edit. The only idea I have now is making an empty commit and squashing
> >> that before the original patch...
> > 
> > use the --author option to the commit sub command
> 
> Hmm, as I said above, the first commit was made while I had the <info>
> address in use. All new commits use the <u-boot> address anyway.
> But when I squash new commits onto the first one, the old address
> prevails...

there is no "field" to edit in the commit message.  the "From:" is generated 
by the author information in the commit.  the only way to change it is to 
amend the commit in question with --author.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100826/172ca580/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-08-26  3:55 ` Mike Frysinger
  2010-08-26  6:19   ` Reinhard Meyer
@ 2010-09-03 17:50   ` Reinhard Meyer
  2010-09-03 19:51     ` Mike Frysinger
  1 sibling, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-09-03 17:50 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

> pass the bus/cs/speed/mode in to the initialize function and store it in the
> per-device state.  then you can work fine with multiple enc28j60 devices in
> one board.
>
> along those lines, all of the local enc funcs should be changed to take the
> private state and operate off that instead of random global variables.

Something like this?

typedef struct enc_device {
	struct eth_device	netdev;
	struct spi_slave	*slave;
	u16			next_pointer;
	int			rx_reset_counter;
	u8			bank;	/* current bank in enc28j60 */
} enc_dev_t;
#define to_enc(_nd) container_of(_nd, struct enc_device, netdev)

...

static u8 enc_r8(enc_dev_t *, u16 reg);
static u16 enc_r16(enc_dev_t *, u16 reg);
static void enc_w8(enc_dev_t *, u16 reg, u8 data);
static void enc_w16(enc_dev_t *, u16 reg, u16 data);
static void enc_w8_retry(enc_dev_t *, u16 reg, u8 data, int c);

I agree that's more perfect but kind of overkill, too;
assuming that only one enc can be active at any given time;)

Best Regards,
Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 17:50   ` Reinhard Meyer
@ 2010-09-03 19:51     ` Mike Frysinger
  2010-09-03 20:31       ` Reinhard Meyer
  0 siblings, 1 reply; 13+ messages in thread
From: Mike Frysinger @ 2010-09-03 19:51 UTC (permalink / raw)
  To: u-boot

On Friday, September 03, 2010 13:50:28 Reinhard Meyer wrote:
> Something like this?

yes

> I agree that's more perfect but kind of overkill, too;
> assuming that only one enc can be active at any given time;)

yes and no.  the spi bus/cs/mode/speed is established at initialize() time, 
not init(), so you'd need to store that per-instance information somewhere.  
and how the discussion about netconsole handling falls out (not calling 
init/halt after every transaction), this base assumption may not be valid.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100903/3300012f/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 19:51     ` Mike Frysinger
@ 2010-09-03 20:31       ` Reinhard Meyer
  2010-09-03 21:03         ` Mike Frysinger
  0 siblings, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-09-03 20:31 UTC (permalink / raw)
  To: u-boot

On 03.09.2010 21:51, Mike Frysinger wrote:
> yes and no.  the spi bus/cs/mode/speed is established at initialize() time,
> not init(), so you'd need to store that per-instance information somewhere.
> and how the discussion about netconsole handling falls out (not calling
> init/halt after every transaction), this base assumption may not be valid.
> -mike

/*
  * This is the only exported function.
  *
  * It may be called several times with different bus:cs combinations.
  */
int enc_initialize(int bus, int cs, int speed)
{
	enc_dev_t *enc;

	enc = malloc(sizeof(*enc));
	if (!enc) {
		return -1;
	}
	memset(enc, 0, sizeof(*enc));
	enc->slave = spi_setup_slave(bus, cs, speed, SPI_MODE_0);
	if (!enc->slave) {
		free(enc);
		return -1;
	}
	enc->netdev.init = enc_init;
	enc->netdev.halt = enc_halt;
	enc->netdev.send = enc_send;
	enc->netdev.recv = enc_recv;
	sprintf(enc->netdev.name, "enc%i.%i", bus, cs);
	eth_register(&(enc->netdev));
	return 0;
}
(not compiled yet)
not sure, however, if calling spi_setup_slave() is ok at this point.

Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 20:31       ` Reinhard Meyer
@ 2010-09-03 21:03         ` Mike Frysinger
  2010-09-03 21:23           ` Reinhard Meyer
  0 siblings, 1 reply; 13+ messages in thread
From: Mike Frysinger @ 2010-09-03 21:03 UTC (permalink / raw)
  To: u-boot

On Friday, September 03, 2010 16:31:47 Reinhard Meyer wrote:
> int enc_initialize(int bus, int cs, int speed)

should take the same parameters (including type) as spi_setup_slave

> 	eth_register(&(enc->netdev));

no need for the () before the &

> not sure, however, if calling spi_setup_slave() is ok at this point.

i believe the func should only doing validation on the arguments.  it shouldnt 
need to talk to any actual hardware.  maybe this needs codifying in the API 
documentation.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100903/3bb55261/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 21:03         ` Mike Frysinger
@ 2010-09-03 21:23           ` Reinhard Meyer
  2010-09-03 22:14             ` Mike Frysinger
  0 siblings, 1 reply; 13+ messages in thread
From: Reinhard Meyer @ 2010-09-03 21:23 UTC (permalink / raw)
  To: u-boot

On 03.09.2010 23:03, Mike Frysinger wrote:
>> not sure, however, if calling spi_setup_slave() is ok at this point.
>
> i believe the func should only doing validation on the arguments.  it shouldnt
> need to talk to any actual hardware.  maybe this needs codifying in the API
> documentation.
In atmel_spi.c it sets up the csr[indexed by cs=0..3] register with clock,
phase and polarity.
That's harmless, but might need some rethinking there.

Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 21:23           ` Reinhard Meyer
@ 2010-09-03 22:14             ` Mike Frysinger
  2010-09-04  3:25               ` Reinhard Meyer
  0 siblings, 1 reply; 13+ messages in thread
From: Mike Frysinger @ 2010-09-03 22:14 UTC (permalink / raw)
  To: u-boot

On Friday, September 03, 2010 17:23:43 Reinhard Meyer wrote:
> On 03.09.2010 23:03, Mike Frysinger wrote:
> >> not sure, however, if calling spi_setup_slave() is ok at this point.
> > 
> > i believe the func should only doing validation on the arguments.  it
> > shouldnt need to talk to any actual hardware.  maybe this needs
> > codifying in the API documentation.
> 
> In atmel_spi.c it sets up the csr[indexed by cs=0..3] register with clock,
> phase and polarity.
> That's harmless, but might need some rethinking there.

i'm not familiar with the Atmel SPI controller, but my gut reaction is that 
register values should be calculated in spi_setup_slave(), stored in the 
internal xxx_spi_slave struct, and then written at spi_claim_bus() time.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100903/dd926dab/attachment.pgp 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework
  2010-09-03 22:14             ` Mike Frysinger
@ 2010-09-04  3:25               ` Reinhard Meyer
  0 siblings, 0 replies; 13+ messages in thread
From: Reinhard Meyer @ 2010-09-04  3:25 UTC (permalink / raw)
  To: u-boot

On 04.09.2010 00:14, Mike Frysinger wrote:
> On Friday, September 03, 2010 17:23:43 Reinhard Meyer wrote:
>> On 03.09.2010 23:03, Mike Frysinger wrote:
>>>> not sure, however, if calling spi_setup_slave() is ok at this point.
>>>
>>> i believe the func should only doing validation on the arguments.  it
>>> shouldnt need to talk to any actual hardware.  maybe this needs
>>> codifying in the API documentation.
>>
>> In atmel_spi.c it sets up the csr[indexed by cs=0..3] register with clock,
>> phase and polarity.
>> That's harmless, but might need some rethinking there.
>
> i'm not familiar with the Atmel SPI controller, but my gut reaction is that
> register values should be calculated in spi_setup_slave(), stored in the
> internal xxx_spi_slave struct, and then written at spi_claim_bus() time.
> -mike
Well, the SPI hardware can store the settings for 4 chip selects, and quite
automagically switch between them, including programmable switch times. When
using DMA it would be possible to setup transfers to/from different chip
selects without software doing the switches, ex:
15 words of 13 bits using 199kHz and mode 3 via CS2,
2 words of 8 bits using 10MHz and mode 0 via CS3, etc...
All this, of course, is not needed in u-boot and currently only half used
anyway. Therefore I tend to rework the atmel_spi.c not to make use of that
feature at all.

For codig the ENC driver I will just postulate its save to setup the slave
at initialize time.

Reinhard

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-09-04  3:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-25 12:47 [U-Boot] [PATCH] NET: add ENC28J60 driver using SPI framework Reinhard Meyer
2010-08-26  3:55 ` Mike Frysinger
2010-08-26  6:19   ` Reinhard Meyer
2010-08-26  6:32     ` Mike Frysinger
2010-08-26  6:41       ` Reinhard Meyer
2010-08-26  7:11         ` Mike Frysinger
2010-09-03 17:50   ` Reinhard Meyer
2010-09-03 19:51     ` Mike Frysinger
2010-09-03 20:31       ` Reinhard Meyer
2010-09-03 21:03         ` Mike Frysinger
2010-09-03 21:23           ` Reinhard Meyer
2010-09-03 22:14             ` Mike Frysinger
2010-09-04  3:25               ` Reinhard Meyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.