All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jens Scharsig <js_at_ng@scharsoft.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 8/9 V3] new at91_emac network driver (NET_MULTI api)
Date: Sat, 23 Jan 2010 12:03:45 +0100	[thread overview]
Message-ID: <4B5AD791.2030304@scharsoft.de> (raw)

* add's at91_emac (AT91RM9200) network driver (NET_MULTI api) 
* enable driver with CONFIG_DRIVER_AT91EMAC 
* generic PHY initialization 
* modify AT91RM9200 boards to use NET_MULTI driver 
* the drivers has been tested with LXT971 Phy and DM9161 Phy at 
  MII and RMII interface

Signed-off-by: Jens Scharsig <js_at_ng@scharsoft.de>
---
 README                                  |   10 +
 board/atmel/at91rm9200dk/at91rm9200dk.c |   15 +
 board/atmel/at91rm9200ek/at91rm9200ek.c |   14 +
 board/cmc_pu2/cmc_pu2.c                 |   13 +
 board/csb637/csb637.c                   |   13 +
 board/eukrea/cpuat91/cpuat91.c          |   14 +
 board/kb9202/kb9202.c                   |   13 +
 board/m501sk/m501sk.c                   |   14 +
 board/mp2usb/mp2usb.c                   |   13 +
 cpu/arm920t/at91rm9200/bcm5221.c        |    4 +-
 cpu/arm920t/at91rm9200/dm9161.c         |    3 +-
 drivers/net/Makefile                    |    1 +
 drivers/net/at91_emac.c                 |  498 +++++++++++++++++++++++++++++++
 include/asm-arm/arch-at91/at91_emac.h   |  145 +++++++++
 include/configs/at91rm9200dk.h          |    9 +-
 include/configs/at91rm9200ek.h          |    8 +-
 include/configs/cmc_pu2.h               |    8 +-
 include/configs/cpuat91.h               |    8 +-
 include/configs/csb637.h                |    8 +-
 include/configs/kb9202.h                |    8 +-
 include/configs/m501sk.h                |    9 +-
 include/configs/mp2usb.h                |    8 +-
 include/netdev.h                        |    1 +
 23 files changed, 825 insertions(+), 12 deletions(-)
 create mode 100644 drivers/net/at91_emac.c
 create mode 100644 include/asm-arm/arch-at91/at91_emac.h

diff --git a/README b/README
index 7affe10..3b9eb28 100644
--- a/README
+++ b/README
@@ -822,6 +822,16 @@ The following options need to be configured:
 
 - NETWORK Support (other):
 
+		CONFIG_DRIVER_AT91EMAC
+		Support for AT91RM9200 EMAC.
+
+			CONFIG_RMII
+			Define this to use reduced MII inteface
+
+			CONFIG_DRIVER_AT91EMAC_QUIET
+			If this defined, the driver is quiet.
+			The driver doen't show link status messages.
+
 		CONFIG_DRIVER_LAN91C96
 		Support for SMSC's LAN91C96 chips.
 
diff --git a/board/atmel/at91rm9200dk/at91rm9200dk.c b/board/atmel/at91rm9200dk/at91rm9200dk.c
index c761dd7..49b5fe3 100644
--- a/board/atmel/at91rm9200dk/at91rm9200dk.c
+++ b/board/atmel/at91rm9200dk/at91rm9200dk.c
@@ -23,9 +23,15 @@
  */
 
 #include <common.h>
+#include <exports.h>
+#include <netdev.h>
 #include <asm/arch/AT91RM9200.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <dm9161.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -95,6 +101,15 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 #endif
 #endif	/* CONFIG_DRIVER_ETHER */
 
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
+
 /*
  * Disk On Chip (NAND) Millenium initialization.
  * The NAND lives in the CS2* space
diff --git a/board/atmel/at91rm9200ek/at91rm9200ek.c b/board/atmel/at91rm9200ek/at91rm9200ek.c
index ea684e9..570a09a 100644
--- a/board/atmel/at91rm9200ek/at91rm9200ek.c
+++ b/board/atmel/at91rm9200ek/at91rm9200ek.c
@@ -23,9 +23,14 @@
  */
 
 #include <common.h>
+#include <exports.h>
+#include <netdev.h>
 #include <asm/arch/AT91RM9200.h>
+#include <asm/io.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <dm9161.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -84,3 +89,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 	p_phyops->AutoNegotiate = dm9161_AutoNegotiate;
 }
 #endif
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/board/cmc_pu2/cmc_pu2.c b/board/cmc_pu2/cmc_pu2.c
index 3ad756d..0ac851c 100644
--- a/board/cmc_pu2/cmc_pu2.c
+++ b/board/cmc_pu2/cmc_pu2.c
@@ -30,8 +30,12 @@
 #include <common.h>
 #include <asm/mach-types.h>
 #include <asm/arch/AT91RM9200.h>
+#include <asm/io.h>
+#include <netdev.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <dm9161.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -177,3 +181,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 
 #endif
 #endif	/* CONFIG_DRIVER_ETHER */
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/board/csb637/csb637.c b/board/csb637/csb637.c
index fbc3c87..d7fdcc4 100644
--- a/board/csb637/csb637.c
+++ b/board/csb637/csb637.c
@@ -23,8 +23,12 @@
 
 #include <common.h>
 #include <asm/arch/AT91RM9200.h>
+#include <netdev.h>
+#include <asm/io.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <bcm5221.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -79,3 +83,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 
 #endif
 #endif	/* CONFIG_DRIVER_ETHER */
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/board/eukrea/cpuat91/cpuat91.c b/board/eukrea/cpuat91/cpuat91.c
index 1a700b6..0017962 100644
--- a/board/eukrea/cpuat91/cpuat91.c
+++ b/board/eukrea/cpuat91/cpuat91.c
@@ -26,9 +26,14 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <asm/arch/AT91RM9200.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <ks8721.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -79,3 +84,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 
 #endif	/* CONFIG_CMD_NET */
 #endif	/* CONFIG_DRIVER_ETHER */
+#ifdef CONFIG_DRIVER_AT91EMAC
+
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/board/kb9202/kb9202.c b/board/kb9202/kb9202.c
index 59ed8ff..3164cc5 100644
--- a/board/kb9202/kb9202.c
+++ b/board/kb9202/kb9202.c
@@ -28,8 +28,12 @@
 
 #include <common.h>
 #include <asm/arch/AT91RM9200.h>
+#include <asm/io.h>
+#include <netdev.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <lxt971a.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -92,3 +96,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 
 #endif
 #endif	/* CONFIG_DRIVER_ETHER */
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/board/m501sk/m501sk.c b/board/m501sk/m501sk.c
index 1e6a605..c995768 100644
--- a/board/m501sk/m501sk.c
+++ b/board/m501sk/m501sk.c
@@ -24,8 +24,13 @@
  */
 
 #include <common.h>
+#include <asm/io.h>
+#include <netdev.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <dm9161.h>
+#endif
+
 #include "m501sk.h"
 #include "net.h"
 
@@ -186,4 +191,13 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 }
 #endif /* CONFIG_CMD_NET */
 #endif /* CONFIG_DRIVER_ETHER */
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
 #endif /* CONFIG_M501SK */
diff --git a/board/mp2usb/mp2usb.c b/board/mp2usb/mp2usb.c
index dcda699..e5eba6b 100644
--- a/board/mp2usb/mp2usb.c
+++ b/board/mp2usb/mp2usb.c
@@ -27,8 +27,12 @@
 
 #include <common.h>
 #include <asm/arch/AT91RM9200.h>
+#include <netdev.h>
+#include <asm/io.h>
+#if defined(CONFIG_DRIVER_ETHER)
 #include <at91rm9200_net.h>
 #include <dm9161.h>
+#endif
 #include <asm/mach-types.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -83,3 +87,12 @@ void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
 
 #endif
 #endif	/* CONFIG_DRIVER_ETHER */
+
+#ifdef CONFIG_DRIVER_AT91EMAC
+int board_eth_init(bd_t *bis)
+{
+	int rc = 0;
+	rc = at91emac_register(bis, 0);
+	return rc;
+}
+#endif
diff --git a/cpu/arm920t/at91rm9200/bcm5221.c b/cpu/arm920t/at91rm9200/bcm5221.c
index b52c615..8de3cba 100644
--- a/cpu/arm920t/at91rm9200/bcm5221.c
+++ b/cpu/arm920t/at91rm9200/bcm5221.c
@@ -28,10 +28,10 @@
 
 #include <at91rm9200_net.h>
 #include <net.h>
-#include <bcm5221.h>
-
 #ifdef CONFIG_DRIVER_ETHER
 
+#include <bcm5221.h>
+
 #if defined(CONFIG_CMD_NET)
 
 /*
diff --git a/cpu/arm920t/at91rm9200/dm9161.c b/cpu/arm920t/at91rm9200/dm9161.c
index 1beb6e8..6d4384f 100644
--- a/cpu/arm920t/at91rm9200/dm9161.c
+++ b/cpu/arm920t/at91rm9200/dm9161.c
@@ -23,9 +23,8 @@
 
 #include <at91rm9200_net.h>
 #include <net.h>
-#include <dm9161.h>
-
 #ifdef CONFIG_DRIVER_ETHER
+#include <dm9161.h>
 
 #if defined(CONFIG_CMD_NET)
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 904727e..b6de1e3 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -27,6 +27,7 @@ LIB	:= $(obj)libnet.a
 
 COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o
 COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
+COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
 COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o
 COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o
diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c
new file mode 100644
index 0000000..2399569
--- /dev/null
+++ b/drivers/net/at91_emac.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2009 BuS Elektronik GmbH & Co. KG
+ * Jens Scharsig (esw at bus-elektronik.de)
+ *
+ * (C) Copyright 2003
+ * Author : Hamid Ikdoumi (Atmel)
+
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <asm/io.h>
+#ifndef CONFIG_AT91_LEGACY
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_emac.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_pio.h>
+#else
+/* remove next 5 lines, if all RM9200 boards convert to at91 arch */
+#include <asm/arch-at91/at91rm9200.h>
+#include <asm/arch-at91/hardware.h>
+#include <asm/arch-at91/at91_emac.h>
+#include <asm/arch-at91/at91_pmc.h>
+#include <asm/arch-at91/at91_pio.h>
+#endif
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <linux/mii.h>
+
+#undef MII_DEBUG
+#undef ET_DEBUG
+
+#if (CONFIG_SYS_RX_ETH_BUFFER > 1024)
+#error AT91 EMAC supports max 1024 RX buffers. \
+	Please decrease the CONFIG_SYS_RX_ETH_BUFFER value
+#endif
+
+/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */
+#if (AT91C_MASTER_CLOCK > 80000000)
+	#define HCLK_DIV	AT91_EMAC_CFG_MCLK_64
+#elif (AT91C_MASTER_CLOCK > 40000000)
+	#define HCLK_DIV	AT91_EMAC_CFG_MCLK_32
+#elif (AT91C_MASTER_CLOCK > 20000000)
+	#define HCLK_DIV	AT91_EMAC_CFG_MCLK_16
+#else
+	#define HCLK_DIV	AT91_EMAC_CFG_MCLK_8
+#endif
+
+#ifdef ET_DEBUG
+#define DEBUG_AT91EMAC(...)	printf(__VA_ARGS__);
+#else
+#define DEBUG_AT91EMAC(...)
+#endif
+
+#ifdef MII_DEBUG
+#define DEBUG_AT91PHY(...)	printf(__VA_ARGS__);
+#else
+#define DEBUG_AT91PHY(...)
+#endif
+
+#ifndef CONFIG_DRIVER_AT91EMAC_QUIET
+#define VERBOSEP(...)	printf(__VA_ARGS__);
+#else
+#define VERBOSEP(...)
+#endif
+
+#define RBF_ADDR      0xfffffffc
+#define RBF_OWNER     (1<<0)
+#define RBF_WRAP      (1<<1)
+#define RBF_BROADCAST (1<<31)
+#define RBF_MULTICAST (1<<30)
+#define RBF_UNICAST   (1<<29)
+#define RBF_EXTERNAL  (1<<28)
+#define RBF_UNKOWN    (1<<27)
+#define RBF_SIZE      0x07ff
+#define RBF_LOCAL4    (1<<26)
+#define RBF_LOCAL3    (1<<25)
+#define RBF_LOCAL2    (1<<24)
+#define RBF_LOCAL1    (1<<23)
+
+#define RBF_FRAMEMAX CONFIG_SYS_RX_ETH_BUFFER
+#define RBF_FRAMELEN 0x600
+
+typedef struct {
+	unsigned long addr, size;
+} rbf_t;
+
+typedef struct {
+	rbf_t 		rbfdt[RBF_FRAMEMAX];
+	unsigned long	rbindex;
+} emac_device;
+
+void at91emac_EnableMDIO(at91_emac_t *at91mac)
+{
+	/* Mac CTRL reg set for MDIO enable */
+	writel(readl(&at91mac->ctl) | AT91_EMAC_CTL_MPE, &at91mac->ctl);
+}
+
+void at91emac_DisableMDIO(at91_emac_t *at91mac)
+{
+	/* Mac CTRL reg set for MDIO disable */
+	writel(readl(&at91mac->ctl) & ~AT91_EMAC_CTL_MPE, &at91mac->ctl);
+}
+
+int  at91emac_read(at91_emac_t *at91mac, unsigned char addr,
+		unsigned char reg, unsigned short *value)
+{
+	at91emac_EnableMDIO(at91mac);
+
+	writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_R |
+		AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
+		AT91_EMAC_MAN_PHYA(addr),
+		&at91mac->man);
+	udelay(10000);
+	*value = readl(&at91mac->man) & AT91_EMAC_MAN_DATA_MASK;
+
+	at91emac_DisableMDIO(at91mac);
+
+	DEBUG_AT91PHY("AT91PHY read %x REG(%d)=%x\n", at91mac, reg, *value)
+
+	return 0;
+}
+
+int  at91emac_write(at91_emac_t *at91mac, unsigned char addr,
+		unsigned char reg, unsigned short value)
+{
+	DEBUG_AT91PHY("AT91PHY write %x REG(%d)=%x\n", at91mac, reg, &value)
+
+	at91emac_EnableMDIO(at91mac);
+
+	writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_W |
+		AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
+		AT91_EMAC_MAN_PHYA(addr) | (value & AT91_EMAC_MAN_DATA_MASK),
+		&at91mac->man);
+	udelay(10000);
+
+	at91emac_DisableMDIO(at91mac);
+	return 0;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+at91_emac_t *get_emacbase_by_name(char *devname)
+{
+	struct eth_device *netdev;
+
+	netdev = eth_get_dev_by_name(devname);
+	return (at91_emac_t *) netdev->iobase;
+}
+
+int  at91emac_mii_read(char *devname, unsigned char addr,
+		unsigned char reg, unsigned short *value)
+{
+	at91_emac_t *emac;
+
+	emac = get_emacbase_by_name(devname);
+	at91emac_read(emac , addr, reg, value);
+	return 0;
+}
+
+
+int  at91emac_mii_write(char *devname, unsigned char addr,
+		unsigned char reg, unsigned short value)
+{
+	at91_emac_t *emac;
+
+	emac = get_emacbase_by_name(devname);
+	at91emac_write(emac, addr, reg, value);
+	return 0;
+}
+
+#endif
+
+static int at91emac_phy_reset(struct eth_device *netdev)
+{
+	int i;
+	u16 status, adv;
+	at91_emac_t *emac;
+
+	emac = (at91_emac_t *) netdev->iobase;
+
+	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+	at91emac_write(emac, 0, MII_ADVERTISE, adv);
+	VERBOSEP("%s: Starting autonegotiation...\n", netdev->name);
+	at91emac_write(emac, 0, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
+
+	for (i = 0; i < 100000 / 100; i++) {
+		at91emac_read(emac, 0, MII_BMSR, &status);
+		if (status & BMSR_ANEGCOMPLETE)
+			break;
+		udelay(100);
+	}
+
+	if (status & BMSR_ANEGCOMPLETE) {
+		VERBOSEP("%s: Autonegotiation complete\n", netdev->name);
+	} else {
+		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+		       netdev->name, status);
+		return 1;
+	}
+	return 0;
+}
+
+static int at91emac_phy_init(struct eth_device *netdev)
+{
+	u16 phy_id, status, adv, lpa;
+	int media, speed, duplex;
+	int i;
+	at91_emac_t *emac;
+
+	emac = (at91_emac_t *) netdev->iobase;
+
+	/* Check if the PHY is up to snuff... */
+	at91emac_read(emac, 0, MII_PHYSID1, &phy_id);
+	if (phy_id == 0xffff) {
+		printf("%s: No PHY present\n", netdev->name);
+		return 1;
+	}
+
+	at91emac_read(emac, 0, MII_BMSR, &status);
+
+	if (!(status & BMSR_LSTATUS)) {
+		/* Try to re-negotiate if we don't have link already. */
+		if (at91emac_phy_reset(netdev))
+			return 2;
+
+		for (i = 0; i < 100000 / 100; i++) {
+			at91emac_read(emac, 0, MII_BMSR, &status);
+			if (status & BMSR_LSTATUS)
+				break;
+			udelay(100);
+		}
+	}
+	if (!(status & BMSR_LSTATUS)) {
+		VERBOSEP("%s: link down\n", netdev->name);
+		return 3;
+	} else {
+		at91emac_read(emac, 0, MII_ADVERTISE, &adv);
+		at91emac_read(emac, 0, MII_LPA, &lpa);
+		media = mii_nway_result(lpa & adv);
+		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+			 ? 1 : 0);
+		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+		VERBOSEP("%s: link up, %sMbps %s-duplex\n",
+		       netdev->name,
+		       speed ? "100" : "10",
+		       duplex ? "full" : "half");
+	}
+	return 0;
+}
+
+int at91emac_UpdateLinkSpeed(at91_emac_t *emac)
+{
+	unsigned short stat1;
+
+	at91emac_read(emac, 0, MII_BMSR, &stat1);
+
+	if (!(stat1 & BMSR_LSTATUS))	/* link status up? */
+		return 1;
+
+	if (stat1 & BMSR_100FULL) {
+		/*set Emac for 100BaseTX and Full Duplex  */
+		writel(readl(&emac->cfg) |
+			AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD,
+			&emac->cfg);
+		return 0;
+	}
+
+	if (stat1 & BMSR_10FULL) {
+		/*set MII for 10BaseT and Full Duplex  */
+		writel((readl(&emac->cfg) &
+			~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
+			) | AT91_EMAC_CFG_FD,
+			&emac->cfg);
+		return 0;
+	}
+
+	if (stat1 & BMSR_100HALF) {
+		/*set MII for 100BaseTX and Half Duplex  */
+		writel((readl(&emac->cfg) &
+			~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
+			) | AT91_EMAC_CFG_SPD,
+			&emac->cfg);
+		return 0;
+	}
+
+	if (stat1 & BMSR_10HALF) {
+		/*set MII for 10BaseT and Half Duplex  */
+		writel((readl(&emac->cfg) &
+			~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)),
+			&emac->cfg);
+		return 0;
+	}
+	return 1;
+}
+
+static int at91emac_init(struct eth_device *netdev, bd_t *bd)
+{
+	int i;
+	u32 value;
+	emac_device *dev;
+	at91_emac_t *emac;
+	at91_pio_t *pio = (at91_pio_t *) AT91_PIO_BASE;
+	at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE;
+
+	emac = (at91_emac_t *) netdev->iobase;
+	dev = (emac_device *) netdev->priv;
+
+	/* PIO Disable Register */
+	value =	AT91_PMX_AA_EMDIO |	AT91_PMX_AA_EMDC |
+		AT91_PMX_AA_ERXER |	AT91_PMX_AA_ERX1 |
+		AT91_PMX_AA_ERX0 |	AT91_PMX_AA_ECRS |
+		AT91_PMX_AA_ETX1 |	AT91_PMX_AA_ETX0 |
+		AT91_PMX_AA_ETXEN |	AT91_PMX_AA_EREFCK;
+
+	writel(value, &pio->pioa.pdr);
+	writel(value, &pio->pioa.asr);
+
+#ifdef CONFIG_RMII
+	value = AT91_PMX_BA_ERXCK;
+#else
+	value = AT91_PMX_BA_ERXCK |	AT91_PMX_BA_ECOL |
+		AT91_PMX_BA_ERXDV |	AT91_PMX_BA_ERX3 |
+		AT91_PMX_BA_ERX2 |	AT91_PMX_BA_ETXER |
+		AT91_PMX_BA_ETX3 |	AT91_PMX_BA_ETX2;
+#endif
+	writel(value, &pio->piob.pdr);
+	writel(value, &pio->piob.bsr);
+
+	writel(1 << AT91_ID_EMAC, &pmc->pcer);
+	writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl);
+
+	DEBUG_AT91EMAC("init MAC-ADDR %x%x \n",
+		cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))),
+		cpu_to_le32(*((u32 *)netdev->enetaddr)));
+	writel(cpu_to_le32(*((u32 *)netdev->enetaddr)), &emac->sa2l);
+	writel(cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))), &emac->sa2h);
+	DEBUG_AT91EMAC("init MAC-ADDR %x%x \n",
+		readl(&emac->sa2h), readl(&emac->sa2l));
+
+	/* Init Ethernet buffers */
+	for (i = 0; i < RBF_FRAMEMAX; i++) {
+		dev->rbfdt[i].addr = (unsigned long) NetRxPackets[i];
+		dev->rbfdt[i].size = 0;
+	}
+	dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
+	dev->rbindex = 0;
+	writel((u32) &(dev->rbfdt[0]), &emac->rbqp);
+
+	writel(readl(&emac->rsr) &
+		~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA),
+		&emac->rsr);
+
+	value = AT91_EMAC_CFG_CAF |	AT91_EMAC_CFG_NBC |
+		HCLK_DIV;
+#ifdef CONFIG_RMII
+	value |= AT91C_EMAC_RMII;
+#endif
+	writel(value, &emac->cfg);
+
+	writel(readl(&emac->ctl) | AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE,
+		&emac->ctl);
+
+	if (!at91emac_phy_init(netdev)) {
+		at91emac_UpdateLinkSpeed(emac);
+		return 0;
+	}
+	return 1;
+}
+
+static void at91emac_halt(struct eth_device *netdev)
+{
+	at91_emac_t *emac;
+
+	emac = (at91_emac_t *) netdev->iobase;
+	writel(readl(&emac->ctl) & ~(AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE),
+		&emac->ctl);
+	DEBUG_AT91EMAC("halt MAC\n");
+}
+
+static int at91emac_send(struct eth_device *netdev, volatile void *packet,
+		     int length)
+{
+	at91_emac_t *emac;
+
+	emac = (at91_emac_t *) netdev->iobase;
+
+	while (!(readl(&emac->tsr) & AT91_EMAC_TSR_BNQ))
+		;
+	writel((u32) packet, &emac->tar);
+	writel(AT91_EMAC_TCR_LEN(length), &emac->tcr);
+	while (AT91_EMAC_TCR_LEN(readl(&emac->tcr)))
+		;
+	DEBUG_AT91EMAC("Send %d \n", length);
+	writel(readl(&emac->tsr) | AT91_EMAC_TSR_COMP, &emac->tsr);
+	return 0;
+}
+
+static int at91emac_recv(struct eth_device *netdev)
+{
+	emac_device *dev;
+	at91_emac_t *emac;
+	rbf_t *rbfp;
+	int size;
+
+	emac = (at91_emac_t *) netdev->iobase;
+	dev = (emac_device *) netdev->priv;
+
+	rbfp = &dev->rbfdt[dev->rbindex];
+	while (rbfp->addr & RBF_OWNER)	{
+		size = rbfp->size & RBF_SIZE;
+		NetReceive(NetRxPackets[dev->rbindex], size);
+
+		DEBUG_AT91EMAC("Recv[%d]: %d bytes @ %x \n",
+			dev->rbindex, size, rbfp->addr);
+
+		rbfp->addr &= ~RBF_OWNER;
+		rbfp->size = 0;
+		if (dev->rbindex < (RBF_FRAMEMAX-1))
+			dev->rbindex++;
+		else
+			dev->rbindex = 0;
+
+		rbfp = &(dev->rbfdt[dev->rbindex]);
+		if (!(rbfp->addr & RBF_OWNER))
+			writel(readl(&emac->rsr) | AT91_EMAC_RSR_REC,
+				&emac->rsr);
+	}
+
+	if (readl(&emac->isr) & AT91_EMAC_IxR_RBNA) {
+		/* EMAC silicon bug 41.3.1 workaround 1 */
+		writel(readl(&emac->ctl) & ~AT91_EMAC_CTL_RE, &emac->ctl);
+		writel(readl(&emac->ctl) | AT91_EMAC_CTL_RE, &emac->ctl);
+		dev->rbindex = 0;
+		printf("%s: reset receiver (EMAC dead lock bug)\n",
+			netdev->name);
+	}
+	return 0;
+}
+
+int at91emac_register(bd_t *bis, unsigned long iobase)
+{
+	emac_device *emac;
+	emac_device *emacfix;
+	struct eth_device *dev;
+
+	if (iobase == 0)
+		iobase = AT91_EMAC_BASE;
+	emac = malloc(sizeof(*emac)+512);
+	if (emac == NULL)
+		return 1;
+	dev = malloc(sizeof(*dev));
+	if (dev == NULL) {
+		free(emac);
+		return 1;
+	}
+	/* alignment as per Errata (64 bytes) is insufficient! */
+	emacfix = (emac_device *) (((unsigned long) emac + 0x1ff) & 0xFFFFFE00);
+	memset(emacfix, 0, sizeof(emac_device));
+
+	memset(dev, 0, sizeof(*dev));
+#ifndef CONFIG_RMII
+	sprintf(dev->name, "AT91 EMAC");
+#else
+	sprintf(dev->name, "AT91 EMAC RMII");
+#endif
+	dev->iobase = iobase;
+	dev->priv = emacfix;
+	dev->init = at91emac_init;
+	dev->halt = at91emac_halt;
+	dev->send = at91emac_send;
+	dev->recv = at91emac_recv;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, at91emac_mii_read, at91emac_mii_write);
+#endif
+	return 1;
+}
diff --git a/include/asm-arm/arch-at91/at91_emac.h b/include/asm-arm/arch-at91/at91_emac.h
new file mode 100644
index 0000000..4b96f04
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91_emac.h
@@ -0,0 +1,145 @@
+/*
+ * Memory Setup stuff - taken from blob memsetup.S
+ *
+ * Copyright (C) 2009 Jens Scharsig (js_at_ng at scharsoft.de)
+ *
+ * based on AT91RM9200 datasheet revision I (36. Ethernet MAC (EMAC))
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#ifndef AT91_H
+#define AT91_H
+
+typedef struct at91_emac {
+	u32	 ctl;
+	u32	 cfg;
+	u32	 sr;
+	u32	 tar;
+	u32	 tcr;
+	u32	 tsr;
+	u32	 rbqp;
+	u32	 reserved0;
+	u32	 rsr;
+	u32	 isr;
+	u32	 ier;
+	u32	 idr;
+	u32	 imr;
+	u32	 man;
+	u32	 reserved1[2];
+	u32	 fra;
+	u32	 scol;
+	u32	 mocl;
+	u32	 ok;
+	u32	 seqe;
+	u32	 ale;
+	u32	 dte;
+	u32	 lcol;
+	u32	 ecol;
+	u32	 cse;
+	u32	 tue;
+	u32	 cde;
+	u32	 elr;
+	u32	 rjb;
+	u32	 usf;
+	u32	 sqee;
+	u32	 drfc;
+	u32	 reserved2[3];
+	u32	 hsh;
+	u32	 hsl;
+	u32	 sh1l;
+	u32	 sa1h;
+	u32	 sa2l;
+	u32	 sa2h;
+	u32	 sa3l;
+	u32	 sa3h;
+	u32	 sa4l;
+	u32	 sa4h;
+} at91_emac_t;
+
+#define AT91_EMAC_CTL_LB	0x0001
+#define AT91_EMAC_CTL_LBL	0x0002
+#define AT91_EMAC_CTL_RE	0x0004
+#define AT91_EMAC_CTL_TE	0x0008
+#define AT91_EMAC_CTL_MPE	0x0010
+#define AT91_EMAC_CTL_CSR	0x0020
+#define AT91_EMAC_CTL_ISR	0x0040
+#define AT91_EMAC_CTL_WES	0x0080
+#define AT91_EMAC_CTL_BP	0x1000
+
+#define AT91_EMAC_CFG_SPD	0x0001
+#define AT91_EMAC_CFG_FD	0x0002
+#define AT91_EMAC_CFG_BR	0x0004
+#define AT91_EMAC_CFG_CAF	0x0010
+#define AT91_EMAC_CFG_NBC	0x0020
+#define AT91_EMAC_CFG_MTI	0x0040
+#define AT91_EMAC_CFG_UNI	0x0080
+#define AT91_EMAC_CFG_BIG	0x0100
+#define AT91_EMAC_CFG_EAE	0x0200
+#define AT91_EMAC_CFG_CLK_MASK	0xFFFFF3FF
+#define AT91_EMAC_CFG_MCLK_8	0x0000
+#define AT91_EMAC_CFG_MCLK_16	0x0400
+#define AT91_EMAC_CFG_MCLK_32	0x0800
+#define AT91_EMAC_CFG_MCLK_64	0x0C00
+#define AT91_EMAC_CFG_RTY	0x1000
+#define AT91_EMAC_CFG_RMII	0x2000
+
+#define AT91_EMAC_SR_LINK	0x0001
+#define AT91_EMAC_SR_MDIO	0x0002
+#define AT91_EMAC_SR_IDLE	0x0004
+
+#define AT91_EMAC_TCR_LEN(x)	(x & 0x7FF)
+#define AT91_EMAC_TCR_NCRC	0x8000
+
+#define AT91_EMAC_TSR_OVR	0x0001
+#define AT91_EMAC_TSR_COL	0x0002
+#define AT91_EMAC_TSR_RLE	0x0004
+#define AT91_EMAC_TSR_TXIDLE	0x0008
+#define AT91_EMAC_TSR_BNQ	0x0010
+#define AT91_EMAC_TSR_COMP	0x0020
+#define AT91_EMAC_TSR_UND	0x0040
+
+#define AT91_EMAC_RSR_BNA	0x0001
+#define AT91_EMAC_RSR_REC	0x0002
+#define AT91_EMAC_RSR_OVR	0x0004
+
+/*  ISR, IER, IDR, IMR use the same bits */
+#define AT91_EMAC_IxR_DONE	0x0001
+#define AT91_EMAC_IxR_RCOM	0x0002
+#define AT91_EMAC_IxR_RBNA	0x0004
+#define AT91_EMAC_IxR_TOVR	0x0008
+#define AT91_EMAC_IxR_TUND	0x0010
+#define AT91_EMAC_IxR_RTRY	0x0020
+#define AT91_EMAC_IxR_TBRE	0x0040
+#define AT91_EMAC_IxR_TCOM	0x0080
+#define AT91_EMAC_IxR_TIDLE	0x0100
+#define AT91_EMAC_IxR_LINK	0x0200
+#define AT91_EMAC_IxR_ROVR	0x0400
+#define AT91_EMAC_IxR_HRESP	0x0800
+
+#define AT91_EMAC_MAN_DATA_MASK		0xFFFF
+#define AT91_EMAC_MAN_CODE_802_3	0x00020000
+#define AT91_EMAC_MAN_REGA(reg)		((reg & 0x1F) << 18)
+#define AT91_EMAC_MAN_PHYA(phy)		((phy & 0x1F) << 23)
+#define AT91_EMAC_MAN_RW_R		0x20000000
+#define AT91_EMAC_MAN_RW_W		0x10000000
+#define AT91_EMAC_MAN_HIGH		0x40000000
+#define AT91_EMAC_MAN_LOW		0x80000000
+
+#endif
diff --git a/include/configs/at91rm9200dk.h b/include/configs/at91rm9200dk.h
index bc61677..d39e8f2 100644
--- a/include/configs/at91rm9200dk.h
+++ b/include/configs/at91rm9200dk.h
@@ -124,7 +124,14 @@
 #define CONFIG_SYS_MEMTEST_START		PHYS_SDRAM
 #define CONFIG_SYS_MEMTEST_END			CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
+
 #define CONFIG_NET_RETRY_COUNT		20
 #define CONFIG_AT91C_USE_RMII
 
diff --git a/include/configs/at91rm9200ek.h b/include/configs/at91rm9200ek.h
index f5206b1..145c3c3 100644
--- a/include/configs/at91rm9200ek.h
+++ b/include/configs/at91rm9200ek.h
@@ -147,7 +147,13 @@
 /*
  * Network Driver Setting
  */
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT		20
 #define CONFIG_AT91C_USE_RMII
 
diff --git a/include/configs/cmc_pu2.h b/include/configs/cmc_pu2.h
index 16ae03e..ffe83f0 100644
--- a/include/configs/cmc_pu2.h
+++ b/include/configs/cmc_pu2.h
@@ -154,7 +154,13 @@
 #define CONFIG_SYS_MEMTEST_START	PHYS_SDRAM
 #define CONFIG_SYS_MEMTEST_END		CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT		20
 #define CONFIG_AT91C_USE_RMII
 
diff --git a/include/configs/cpuat91.h b/include/configs/cpuat91.h
index 9f0ac03..b4fda76 100644
--- a/include/configs/cpuat91.h
+++ b/include/configs/cpuat91.h
@@ -130,7 +130,13 @@
 #define CONFIG_SYS_MEMTEST_END			\
 	(CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 512 * 1024)
 
-#define CONFIG_DRIVER_ETHER			1
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT			20
 #define CONFIG_AT91C_USE_RMII			1
 #define CONFIG_PHY_ADDRESS			(1 << 5)
diff --git a/include/configs/csb637.h b/include/configs/csb637.h
index 90269a7..efa2780 100644
--- a/include/configs/csb637.h
+++ b/include/configs/csb637.h
@@ -128,7 +128,13 @@
 #define CONFIG_SYS_ALT_MEMTEST			1
 #define CONFIG_SYS_MEMTEST_SCRATCH		CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 4
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT		20
 #undef CONFIG_AT91C_USE_RMII
 
diff --git a/include/configs/kb9202.h b/include/configs/kb9202.h
index 24fd1ef..41ec1d5 100644
--- a/include/configs/kb9202.h
+++ b/include/configs/kb9202.h
@@ -117,7 +117,13 @@
 #define CONFIG_SYS_MEMTEST_START		PHYS_SDRAM
 #define CONFIG_SYS_MEMTEST_END			CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - (512*1024)
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT		20
 
 #define CONFIG_SYS_FLASH_BASE			0x10000000
diff --git a/include/configs/m501sk.h b/include/configs/m501sk.h
index 17469e5..26c2bcb 100644
--- a/include/configs/m501sk.h
+++ b/include/configs/m501sk.h
@@ -36,6 +36,7 @@
 #define AT91C_MASTER_CLOCK	59904000
 #define AT91_SLOW_CLOCK	32768 /* slow clock */
 
+#define CONFIG_AT91RM9200	1	/* It's an Atmel AT91RM9200 SoC	*/
 #define CONFIG_AT91RM9200DK	1 /* on an AT91RM9200DK Board    */
 #undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
 #define CONFIG_CMDLINE_TAG	1 /* enable passing of ATAGs    */
@@ -168,7 +169,13 @@
 /* CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 */
 #define CONFIG_SYS_MEMTEST_END	0x00100000
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT	20
 #define CONFIG_AT91C_USE_RMII
 
diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h
index c66f8ea..3138b49 100644
--- a/include/configs/mp2usb.h
+++ b/include/configs/mp2usb.h
@@ -183,7 +183,13 @@
 #define CONFIG_SYS_MEMTEST_START	PHYS_SDRAM
 #define CONFIG_SYS_MEMTEST_END		CONFIG_SYS_MEMTEST_START + PHYS_SDRAM_SIZE - 262144
 
-#define CONFIG_DRIVER_ETHER
+#define CONFIG_NET_MULTI		1
+#ifdef CONFIG_NET_MULTI
+#define CONFIG_DRIVER_AT91EMAC		1
+#define CONFIG_SYS_RX_ETH_BUFFER	8
+#else
+#define CONFIG_DRIVER_ETHER		1
+#endif
 #define CONFIG_NET_RETRY_COUNT		20
 #undef CONFIG_AT91C_USE_RMII
 
diff --git a/include/netdev.h b/include/netdev.h
index a9d5ec9..078bba7 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -42,6 +42,7 @@ int cpu_eth_init(bd_t *bis);
 
 /* Driver initialization prototypes */
 int au1x00_enet_initialize(bd_t*);
+int at91emac_register(bd_t *bis, unsigned long iobase);
 int bfin_EMAC_initialize(bd_t *bis);
 int cs8900_initialize(u8 dev_num, int base_addr);
 int dc21x4x_initialize(bd_t *bis);

             reply	other threads:[~2010-01-23 11:03 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-23 11:03 Jens Scharsig [this message]
2010-01-31  1:39 ` [U-Boot] [PATCH 8/9 V3] new at91_emac network driver (NET_MULTI api) Tom
2010-02-01  6:02 ` Ben Warren
2010-02-03 21:47 ` [U-Boot] [PATCH 8/9 V4] " Jens Scharsig

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B5AD791.2030304@scharsoft.de \
    --to=js_at_ng@scharsoft.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.