<br><br><div class="gmail_quote">2011/4/11 <span dir="ltr"><<a href="mailto:franck.jullien@gmail.com">franck.jullien@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
From: Franck JULLIEN <<a href="mailto:franck.jullien@gmail.com">franck.jullien@gmail.com</a>><br>
<br>
Add Altera Triple Speed Ethernet driver<br>
<br>
Signed-off-by: Franck JULLIEN <<a href="mailto:franck.jullien@gmail.com">franck.jullien@gmail.com</a>><br>
---<br>
drivers/net/Kconfig | 16 ++<br>
drivers/net/Makefile | 1 +<br>
drivers/net/altera_tse.c | 579 ++++++++++++++++++++++++++++++++++++++++++++++<br>
drivers/net/altera_tse.h | 303 ++++++++++++++++++++++++<br>
4 files changed, 899 insertions(+), 0 deletions(-)<br>
create mode 100644 drivers/net/altera_tse.c<br>
create mode 100644 drivers/net/altera_tse.h<br>
<br>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig<br>
index 6479417..19e35db 100644<br>
--- a/drivers/net/Kconfig<br>
+++ b/drivers/net/Kconfig<br>
@@ -84,6 +84,22 @@ config DRIVER_NET_TAP<br>
bool "tap Ethernet driver"<br>
depends on LINUX<br>
<br>
+config DRIVER_NET_TSE<br>
+ depends on NIOS2<br>
+ bool "Altera TSE ethernet driver"<br>
+ select MIIDEV<br>
+ help<br>
+ This option enables support for the Altera TSE MAC.<br>
+<br>
+config TSE_USE_DEDICATED_DESC_MEM<br>
+ depends on DRIVER_NET_TSE<br>
+ bool "Altera TSE uses dedicated descriptor memory"<br>
+ help<br>
+ This option tells the TSE driver to use an onchip memory<br>
+ to store SGDMA descriptors. Descriptor memory is not<br>
+ reserved with a malloc but directly mapped to the memory<br>
+ address (defined in config.h)<br>
+<br>
source "drivers/net/usb/Kconfig"<br>
<br>
endmenu<br>
diff --git a/drivers/net/Makefile b/drivers/net/Makefile<br>
index ab23d22..f02618b 100644<br>
--- a/drivers/net/Makefile<br>
+++ b/drivers/net/Makefile<br>
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRIVER_NET_MACB) += macb.o<br>
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o<br>
obj-$(CONFIG_MIIDEV) += miidev.o<br>
obj-$(CONFIG_NET_USB) += usb/<br>
+obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o<br>
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c<br>
new file mode 100644<br>
index 0000000..d922a9a<br>
--- /dev/null<br>
+++ b/drivers/net/altera_tse.c<br>
@@ -0,0 +1,579 @@<br>
+/*<br>
+ * Altera TSE Network driver<br>
+ *<br>
+ * Copyright (C) 2008 Altera Corporation.<br>
+ * Copyright (C) 2010 Thomas Chou <<a href="mailto:thomas@wytron.com.tw">thomas@wytron.com.tw</a>><br>
+ * Copyright (C) 2011 Franck JULLIEN, <<a href="mailto:elec4fun@gmail.com">elec4fun@gmail.com</a>><br>
+ *<br>
+ * See file CREDITS for list of people who contributed to this<br>
+ * project.<br>
+ *<br>
+ * This program is free software; you can redistribute it and/or<br>
+ * modify it under the terms of the GNU General Public License as<br>
+ * published by the Free Software Foundation; either version 2 of<br>
+ * the License, or (at your option) any later version.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License<br>
+ * along with this program; if not, write to the Free Software<br>
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,<br>
+ * MA 02111-1307 USA<br>
+ */<br>
+<br>
+#include <common.h><br>
+#include <net.h><br>
+#include <miidev.h><br>
+#include <init.h><br>
+#include <clock.h><br>
+#include <linux/mii.h><br>
+<br>
+#include <asm/io.h><br>
+#include <asm/dma-mapping.h><br>
+<br>
+#include "altera_tse.h"<br>
+<br>
+/* This is a generic routine that the SGDMA mode-specific routines<br>
+ * call to populate a descriptor.<br>
+ * arg1 :pointer to first SGDMA descriptor.<br>
+ * arg2 :pointer to next SGDMA descriptor.<br>
+ * arg3 :Address to where data to be written.<br>
+ * arg4 :Address from where data to be read.<br>
+ * arg5 :no of byte to transaction.<br>
+ * arg6 :variable indicating to generate start of packet or not<br>
+ * arg7 :read fixed<br>
+ * arg8 :write fixed<br>
+ * arg9 :read burst<br>
+ * arg10 :write burst<br>
+ * arg11 :atlantic_channel number<br>
+ */<br>
+static void alt_sgdma_construct_descriptor_burst(<br>
+ struct alt_sgdma_descriptor *desc,<br>
+ struct alt_sgdma_descriptor *next,<br>
+ uint32_t *read_addr,<br>
+ uint32_t *write_addr,<br>
+ uint16_t length_or_eop,<br>
+ uint8_t generate_eop,<br>
+ uint8_t read_fixed,<br>
+ uint8_t write_fixed_or_sop,<br>
+ uint8_t read_burst,<br>
+ uint8_t write_burst,<br>
+ uint8_t atlantic_channel)<br>
+{<br>
+ uint32_t temp;<br>
+<br>
+ /*<br>
+ * Mark the "next" descriptor as "not" owned by hardware. This prevents<br>
+ * The SGDMA controller from continuing to process the chain. This is<br>
+ * done as a single IO write to bypass cache, without flushing<br>
+ * the entire descriptor, since only the 8-bit descriptor status must<br>
+ * be flushed.<br>
+ */<br>
+ if (!next)<br>
+ printf("Next descriptor not defined!!\n");<br>
+<br>
+ temp = readb(&next->descriptor_control);<br>
+ writeb(temp & ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK,<br>
+ &next->descriptor_control);<br>
+<br>
+ writel((uint32_t)read_addr, &desc->source);<br>
+ writel((uint32_t)write_addr, &desc->destination);<br>
+ writel((uint32_t)next, &desc->next);<br>
+<br>
+ writel(0, &desc->source_pad);<br>
+ writel(0, &desc->destination_pad);<br>
+ writel(0, &desc->next_pad);<br>
+ writew(length_or_eop, &desc->bytes_to_transfer);<br>
+ writew(0, &desc->actual_bytes_transferred);<br>
+ writeb(0, &desc->descriptor_status);<br>
+<br>
+ /* SGDMA burst not currently supported */<br>
+ writeb(0, &desc->read_burst);<br>
+ writeb(0, &desc->write_burst);<br>
+<br>
+ /*<br>
+ * Set the descriptor control block as follows:<br>
+ * - Set "owned by hardware" bit<br>
+ * - Optionally set "generate EOP" bit<br>
+ * - Optionally set the "read from fixed address" bit<br>
+ * - Optionally set the "write to fixed address bit (which serves<br>
+ * serves as a "generate SOP" control bit in memory-to-stream mode).<br>
+ * - Set the 4-bit atlantic channel, if specified<br>
+ *<br>
+ * Note this step is performed after all other descriptor information<br>
+ * has been filled out so that, if the controller already happens to be<br>
+ * pointing at this descriptor, it will not run (via the "owned by<br>
+ * hardware" bit) until all other descriptor has been set up.<br>
+ */<br>
+<br>
+ writeb((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) |<br>
+ (generate_eop ? ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0) |<br>
+ (read_fixed ? ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0) |<br>
+ (write_fixed_or_sop ? ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0) |<br>
+ (atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0),<br>
+ &desc->descriptor_control);<br>
+}<br>
+<br>
+static int alt_sgdma_do_sync_transfer(struct alt_sgdma_registers *dev,<br>
+ struct alt_sgdma_descriptor *desc)<br>
+{<br>
+ uint32_t temp;<br>
+ uint64_t start;<br>
+ uint64_t tout;<br>
+<br>
+ /* Wait for any pending transfers to complete */<br>
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;<br>
+<br>
+ start = get_time_ns();<br>
+<br>
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ debug("Timeout waiting sgdma in do sync!\n");<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ /*<br>
+ * Clear any (previous) status register information<br>
+ * that might occlude our error checking later.<br>
+ */<br>
+ writel(0xFF, &dev->status);<br>
+<br>
+ /* Point the controller at the descriptor */<br>
+ writel((uint32_t)desc, &dev->next_descriptor_pointer);<br>
+ debug("next desc in sgdma 0x%x\n", (uint32_t)dev->next_descriptor_pointer);<br>
+<br>
+ /*<br>
+ * Set up SGDMA controller to:<br>
+ * - Disable interrupt generation<br>
+ * - Run once a valid descriptor is written to controller<br>
+ * - Stop on an error with any particular descriptor<br>
+ */<br>
+ writel(ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK,<br>
+ &dev->control);<br>
+<br>
+ /* Wait for the descriptor (chain) to complete */<br>
+ debug("wait for sgdma....");<br>
+ start = get_time_ns();<br>
+<br>
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ debug("Timeout waiting sgdma in do sync!\n");<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ debug("done\n");<br>
+<br>
+ /* Clear Run */<br>
+ temp = readl(&dev->control);<br>
+ writel(temp & ~ALT_SGDMA_CONTROL_RUN_MSK, &dev->control);<br>
+<br>
+ /* Get & clear status register contents */<br>
+ debug("tx sgdma status = 0x%x", readl(&dev->status));<br>
+ writel(0xFF, &dev->status);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int alt_sgdma_do_async_transfer(struct alt_sgdma_registers *dev,<br>
+ struct alt_sgdma_descriptor *desc)<br>
+{<br>
+ uint64_t start;<br>
+ uint64_t tout;<br>
+<br>
+ /* Wait for any pending transfers to complete */<br>
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;<br>
+<br>
+ start = get_time_ns();<br>
+<br>
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ debug("Timeout waiting sgdma in do async!\n");<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ /*<br>
+ * Clear any (previous) status register information<br>
+ * that might occlude our error checking later.<br>
+ */<br>
+ writel(0xFF, &dev->status);<br>
+<br>
+ /* Point the controller at the descriptor */<br>
+ writel((uint32_t)desc, &dev->next_descriptor_pointer);<br>
+<br>
+ /*<br>
+ * Set up SGDMA controller to:<br>
+ * - Disable interrupt generation<br>
+ * - Run once a valid descriptor is written to controller<br>
+ * - Stop on an error with any particular descriptor<br>
+ */<br>
+ writel(ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK,<br>
+ &dev->control);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_get_ethaddr(struct eth_device *edev, unsigned char *m)<br>
+{<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_tse_mac *mac_dev = priv->mac_dev;<br>
+<br>
+ m[5] = (readl(&mac_dev->mac_addr_1) >> 8) && 0xFF;<br>
+ m[4] = (readl(&mac_dev->mac_addr_1)) && 0xFF;<br>
+ m[3] = (readl(&mac_dev->mac_addr_0) >> 24) && 0xFF;<br>
+ m[2] = (readl(&mac_dev->mac_addr_0) >> 16) && 0xFF;<br>
+ m[1] = (readl(&mac_dev->mac_addr_0) >> 8) && 0xFF;<br>
+ m[0] = (readl(&mac_dev->mac_addr_0)) && 0xFF;<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_set_ethaddr(struct eth_device *edev, unsigned char *m)<br>
+{<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_tse_mac *mac_dev = priv->mac_dev;<br>
+<br>
+ debug("Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",<br>
+ m[0], m[1], m[2], m[3], m[4], m[5]);<br>
+<br>
+ writel(m[3] << 24 | m[2] << 16 | m[1] << 8 | m[0], &mac_dev->mac_addr_0);<br>
+ writel((m[5] << 8 | m[4]) & 0xFFFF, &mac_dev->mac_addr_1);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)<br>
+{<br>
+ struct eth_device *edev = mdev->edev;<br>
+ struct alt_tse_mac *mac_dev;<br>
+ uint32_t *mdio_regs;<br>
+<br>
+ mac_dev = (struct alt_tse_mac *)edev->iobase;<br>
+ writel(phy_addr, &mac_dev->mdio_phy1_addr);<br>
+<br>
+ mdio_regs = (uint32_t *)&mac_dev->mdio_phy1;<br>
+<br>
+ return readl(&mdio_regs[reg]) & 0xFFFF;<br>
+}<br>
+<br>
+static int tse_phy_write(struct mii_device *mdev, int phy_addr, int reg, int val)<br>
+{<br>
+ struct eth_device *edev = mdev->edev;<br>
+ struct alt_tse_mac *mac_dev;<br>
+ uint32_t *mdio_regs;<br>
+<br>
+ mac_dev = (struct alt_tse_mac *)edev->iobase;<br>
+ writel(phy_addr, &mac_dev->mdio_phy1_addr);<br>
+<br>
+ mdio_regs = (uint32_t *)&mac_dev->mdio_phy1;<br>
+<br>
+ writel((uint32_t)val, &mdio_regs[reg]);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static void tse_reset(struct eth_device *edev)<br>
+{<br>
+ /* stop sgdmas, disable tse receive */<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_tse_mac *mac_dev = priv->mac_dev;<br>
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;<br>
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;<br>
+ struct alt_sgdma_descriptor *rx_desc = (struct alt_sgdma_descriptor *)&priv->rx_desc[0];<br>
+ struct alt_sgdma_descriptor *tx_desc = (struct alt_sgdma_descriptor *)&priv->tx_desc[0];<br>
+ uint64_t start;<br>
+ uint64_t tout;<br>
+<br>
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;<br>
+<br>
+ /* clear rx desc & wait for sgdma to complete */<br>
+ writeb(0, &rx_desc->descriptor_control);<br>
+ writel(0, &rx_sgdma->control);<br>
+<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);<br>
+ mdelay(100);<br>
+<br>
+ start = get_time_ns();<br>
+<br>
+ while (readl(&rx_sgdma->status) & ALT_SGDMA_STATUS_BUSY_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ printf("Timeout waiting for rx sgdma!\n");<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ /* clear tx desc & wait for sgdma to complete */<br>
+ writeb(0, &tx_desc->descriptor_control);<br>
+ writel(0, &tx_sgdma->control);<br>
+<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);<br>
+ mdelay(100);<br>
+<br>
+ start = get_time_ns();<br>
+<br>
+ while (readl(&tx_sgdma->status) & ALT_SGDMA_STATUS_BUSY_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ printf("Timeout waiting for tx sgdma!\n");<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);<br>
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ /* reset the mac */<br>
+ writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK |<br>
+ ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config);<br>
+<br>
+ start = get_time_ns();<br>
+ tout = ALT_TSE_SW_RESET_WATCHDOG_TOUT * MSECOND;<br>
+<br>
+ while (readl(&mac_dev->command_config) & ALTERA_TSE_CMD_SW_RESET_MSK) {<br>
+ if (is_timeout(start, tout)) {<br>
+ printf("TSEMAC SW reset bit never cleared!\n");<br>
+ break;<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+static int tse_eth_open(struct eth_device *edev)<br>
+{<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+<br>
+ miidev_wait_aneg(priv->miidev);<br>
+ miidev_print_status(priv->miidev);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_eth_send(struct eth_device *edev, void *packet, int length)<br>
+{<br>
+<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;<br>
+ struct alt_sgdma_descriptor *tx_desc = (struct alt_sgdma_descriptor *)priv->tx_desc;<br>
+<br>
+ struct alt_sgdma_descriptor *tx_desc_cur = (struct alt_sgdma_descriptor *)&tx_desc[0];<br>
+<br>
+ flush_dcache_range((uint32_t)packet, (uint32_t)packet + length);<br>
+ alt_sgdma_construct_descriptor_burst(<br>
+ (struct alt_sgdma_descriptor *)&tx_desc[0],<br>
+ (struct alt_sgdma_descriptor *)&tx_desc[1],<br>
+ (uint32_t *)packet, /* read addr */<br>
+ (uint32_t *)0, /* */<br>
+ length, /* length or EOP ,will change for each tx */<br>
+ 0x1, /* gen eop */<br>
+ 0x0, /* read fixed */<br>
+ 0x1, /* write fixed or sop */<br>
+ 0x0, /* read burst */<br>
+ 0x0, /* write burst */<br>
+ 0x0 /* channel */<br>
+ );<br>
+<br>
+ alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur);<br>
+<br>
+ return 0;;<br>
+}<br>
+<br>
+static void tse_eth_halt(struct eth_device *edev)<br>
+{<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;<br>
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;<br>
+<br>
+ writel(0, &rx_sgdma->control); /* Stop the controller and reset settings */<br>
+ writel(0, &tx_sgdma->control); /* Stop the controller and reset settings */<br>
+}<br>
+<br>
+static int tse_eth_rx(struct eth_device *edev)<br>
+{<br>
+ uint16_t packet_length = 0;<br>
+<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_sgdma_descriptor *rx_desc = (struct alt_sgdma_descriptor *)priv->rx_desc;<br>
+ struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0];<br>
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;<br>
+<br>
+ if (rx_desc_cur->descriptor_status &<br>
+ ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {<br>
+<br>
+ packet_length = rx_desc->actual_bytes_transferred;<br>
+ net_receive(NetRxPackets[0], packet_length);<br>
+<br>
+ /* Clear Run */<br>
+ rx_sgdma->control = (rx_sgdma->control & (~ALT_SGDMA_CONTROL_RUN_MSK));<br>
+<br>
+ /* start descriptor again */<br>
+ flush_dcache_range((uint32_t)(NetRxPackets[0]), (uint32_t)(NetRxPackets[0]) + PKTSIZE);<br>
+ alt_sgdma_construct_descriptor_burst(<br>
+ (struct alt_sgdma_descriptor *)&rx_desc[0],<br>
+ (struct alt_sgdma_descriptor *)&rx_desc[1],<br>
+ (uint32_t)0x0, /* read addr */<br>
+ (uint32_t *)NetRxPackets[0], /* */<br>
+ 0x0, /* length or EOP */<br>
+ 0x0, /* gen eop */<br>
+ 0x0, /* read fixed */<br>
+ 0x0, /* write fixed or sop */<br>
+ 0x0, /* read burst */<br>
+ 0x0, /* write burst */<br>
+ 0x0 /* channel */<br>
+ );<br>
+<br>
+ /* setup the sgdma */<br>
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]);<br>
+ }<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_init_dev(struct eth_device *edev)<br>
+{<br>
+ struct altera_tse_priv *priv = edev->priv;<br>
+ struct alt_tse_mac *mac_dev = priv->mac_dev;<br>
+ struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;<br>
+ struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;<br>
+ struct alt_sgdma_descriptor *rx_desc_cur;<br>
+<br>
+ rx_desc_cur = (struct alt_sgdma_descriptor *)&rx_desc[0];<br>
+<br>
+ tse_reset(edev);<br>
+<br>
+ /* need to create sgdma */<br>
+ alt_sgdma_construct_descriptor_burst(<br>
+ (struct alt_sgdma_descriptor *)&tx_desc[0],<br>
+ (struct alt_sgdma_descriptor *)&tx_desc[1],<br>
+ (uint32_t *)NULL, /* read addr */<br>
+ (uint32_t *)0, /* */<br>
+ 0, /* length or EOP ,will change for each tx */<br>
+ 0x1, /* gen eop */<br>
+ 0x0, /* read fixed */<br>
+ 0x1, /* write fixed or sop */<br>
+ 0x0, /* read burst */<br>
+ 0x0, /* write burst */<br>
+ 0x0 /* channel */<br>
+ );<br>
+<br>
+ flush_dcache_range((uint32_t)(NetRxPackets[0]), (uint32_t)(NetRxPackets[0]) + PKTSIZE);<br>
+ alt_sgdma_construct_descriptor_burst(<br>
+ (struct alt_sgdma_descriptor *)&rx_desc[0],<br>
+ (struct alt_sgdma_descriptor *)&rx_desc[1],<br>
+ (uint32_t)0x0, /* read addr */<br>
+ (uint32_t *)NetRxPackets[0], /* */<br>
+ 0x0, /* length or EOP */<br>
+ 0x0, /* gen eop */<br>
+ 0x0, /* read fixed */<br>
+ 0x0, /* write fixed or sop */<br>
+ 0x0, /* read burst */<br>
+ 0x0, /* write burst */<br>
+ 0x0 /* channel */<br>
+ );<br>
+<br>
+ /* start rx async transfer */<br>
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur);<br>
+<br>
+ /* Initialize MAC registers */<br>
+ writel(PKTSIZE, &mac_dev->max_frame_length);<br>
+<br>
+ /* NO Shift */<br>
+ writel(0, &mac_dev->rx_cmd_stat);<br>
+ writel(0, &mac_dev->tx_cmd_stat);<br>
+<br>
+ /* enable MAC */<br>
+ writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK, &mac_dev->command_config);<br>
+<br>
+ miidev_restart_aneg(priv->miidev);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int tse_probe(struct device_d *dev)<br>
+{<br>
+ struct altera_tse_priv *priv;<br>
+ struct mii_device *miidev;<br>
+ struct eth_device *edev;<br>
+ struct alt_sgdma_descriptor *rx_desc;<br>
+ struct alt_sgdma_descriptor *tx_desc;<br>
+#ifndef CONFIG_TSE_USE_DEDICATED_DESC_MEM<br>
+ uint32_t dma_handle;<br>
+#endif<br>
+ edev = xzalloc(sizeof(struct eth_device) + sizeof(struct altera_tse_priv));<br>
+ miidev = xzalloc(sizeof(struct mii_device));<br>
+<br>
+ dev->type_data = edev;<br>
+ edev->priv = (struct altera_tse_priv *)(edev + 1);<br>
+<br>
+ edev->iobase = dev->map_base;<br>
+<br>
+ priv = edev->priv;<br>
+<br>
+ edev->init = tse_init_dev;<br>
+ edev->open = tse_eth_open;<br>
+ edev->send = tse_eth_send;<br>
+ edev->recv = tse_eth_rx;<br>
+ edev->halt = tse_eth_halt;<br>
+ edev->get_ethaddr = tse_get_ethaddr;<br>
+ edev->set_ethaddr = tse_set_ethaddr;<br>
+<br>
+#ifdef CONFIG_TSE_USE_DEDICATED_DESC_MEM<br>
+ tx_desc = (struct alt_sgdma_descriptor *)NIOS_SOPC_TSE_DESC_MEM_BASE;<br>
+ rx_desc = tx_desc + 2;<br>
+#else<br>
+ tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), &dma_handle);<br>
+ rx_desc = tx_desc + 2;<br>
+<br>
+ if (!tx_desc) {<br>
+ free(edev);<br>
+ free(miidev);<br>
+ return 0;<br>
+ }<br>
+#endif<br>
+<br>
+ memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1));<br>
+ memset(tx_desc, 0, (sizeof *tx_desc) * 2);<br>
+<br>
+ priv->mac_dev = (struct alt_tse_mac *)dev->map_base;<br>
+ priv->sgdma_rx = (struct alt_sgdma_registers *)NIOS_SOPC_SGDMA_RX_BASE;<br>
+ priv->sgdma_tx = (struct alt_sgdma_registers *)NIOS_SOPC_SGDMA_TX_BASE;<br>
+ priv->rx_desc = rx_desc;<br>
+ priv->tx_desc = tx_desc;<br>
+<br>
+ priv->miidev = miidev;<br>
+<br>
+ miidev->read = tse_phy_read;<br>
+ miidev->write = tse_phy_write;<br>
+ miidev->flags = 0;<br>
+ miidev->edev = edev;<br>
+<br>
+ if (dev->platform_data != NULL)<br>
+ miidev->address = *((int8_t *)(dev->platform_data));<br>
+ else {<br>
+ printf("No PHY address specified.\n");<br>
+ return -ENODEV;<br>
+ }<br>
+<br>
+ mii_register(miidev);<br>
+<br>
+ return eth_register(edev);<br>
+}<br>
+<br>
+static struct driver_d altera_tse_driver = {<br>
+ .name = "altera_tse",<br>
+ .probe = tse_probe,<br>
+};<br>
+<br>
+static int tse_init(void)<br>
+{<br>
+ register_driver(&altera_tse_driver);<br>
+ return 0;<br>
+}<br>
+<br>
+device_initcall(tse_init);<br>
+<br>
diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h<br>
new file mode 100644<br>
index 0000000..c907c74<br>
--- /dev/null<br>
+++ b/drivers/net/altera_tse.h<br>
@@ -0,0 +1,303 @@<br>
+/*<br>
+ * Altera 10/100/1000 triple speed ethernet mac<br>
+ *<br>
+ * Copyright (C) 2008 Altera Corporation.<br>
+ * Copyright (C) 2010 Thomas Chou <<a href="mailto:thomas@wytron.com.tw">thomas@wytron.com.tw</a>><br>
+ * Copyright (C) 2011 Franck JULLIEN <<a href="mailto:elec4fun@gmail.com">elec4fun@gmail.com</a>><br>
+ *<br>
+ * This program is free software; you can redistribute it and/or modify<br>
+ * it under the terms of the GNU General Public License version 2 as<br>
+ * published by the Free Software Foundation.<br>
+ */<br>
+#ifndef _ALTERA_TSE_H_<br>
+#define _ALTERA_TSE_H_<br>
+<br>
+/* SGDMA Stuff */<br>
+#define ALT_SGDMA_STATUS_ERROR_MSK (0x00000001)<br>
+#define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK (0x00000002)<br>
+#define ALT_SGDMA_STATUS_DESC_COMPLETED_MSK (0x00000004)<br>
+#define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK (0x00000008)<br>
+#define ALT_SGDMA_STATUS_BUSY_MSK (0x00000010)<br>
+<br>
+#define ALT_SGDMA_CONTROL_IE_ERROR_MSK (0x00000001)<br>
+#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK (0x00000002)<br>
+#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK (0x00000004)<br>
+#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK (0x00000008)<br>
+#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK (0x00000010)<br>
+#define ALT_SGDMA_CONTROL_RUN_MSK (0x00000020)<br>
+#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK (0x00000040)<br>
+#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK (0x00000080)<br>
+#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK (0x0000FF00)<br>
+#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK (0x00010000)<br>
+#define ALT_SGDMA_CONTROL_PARK_MSK (0x00020000)<br>
+#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK (0x80000000)<br>
+<br>
+#define ALTERA_TSE_SGDMA_INTR_MASK (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \<br>
+ | ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \<br>
+ | ALT_SGDMA_CONTROL_IE_GLOBAL_MSK)<br>
+<br>
+/*<br>
+ * Descriptor control bit masks & offsets<br>
+ *<br>
+ * Note: The control byte physically occupies bits [31:24] in memory.<br>
+ * The following bit-offsets are expressed relative to the LSB of<br>
+ * the control register bitfield.<br>
+ */<br>
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK (0x00000001)<br>
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK (0x00000002)<br>
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK (0x00000004)<br>
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_ATLANTIC_CHANNEL_MSK (0x00000008)<br>
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK (0x00000080)<br>
+<br>
+/*<br>
+ * Descriptor status bit masks & offsets<br>
+ *<br>
+ * Note: The status byte physically occupies bits [23:16] in memory.<br>
+ * The following bit-offsets are expressed relative to the LSB of<br>
+ * the status register bitfield.<br>
+ */<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK (0x00000001)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK (0x00000002)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK (0x00000004)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK (0x00000008)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK (0x00000010)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK (0x00000020)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK (0x00000040)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK (0x00000080)<br>
+#define ALT_SGDMA_DESCRIPTOR_STATUS_ERROR_MSK (0x0000007F)<br>
+<br>
+/*<br>
+ * The SGDMA controller buffer descriptor allocates<br>
+ * 64 bits for each address. To support ANSI C, the<br>
+ * struct implementing a descriptor places 32-bits<br>
+ * of padding directly above each address; each pad must<br>
+ * be cleared when initializing a descriptor.<br>
+ */<br>
+<br>
+/*<br>
+ * Buffer Descriptor data structure<br>
+ *<br>
+ */<br>
+struct alt_sgdma_descriptor {<br>
+ unsigned int *source; /* the address of data to be read. */<br>
+ unsigned int source_pad;<br>
+<br>
+ unsigned int *destination; /* the address to write data */<br>
+ unsigned int destination_pad;<br>
+<br>
+ unsigned int *next; /* the next descriptor in the list. */<br>
+ unsigned int next_pad;<br>
+<br>
+ unsigned short bytes_to_transfer; /* the number of bytes to transfer */<br>
+ unsigned char read_burst;<br>
+ unsigned char write_burst;<br>
+<br>
+ unsigned short actual_bytes_transferred;/* bytes transferred by DMA */<br>
+ unsigned char descriptor_status;<br>
+ unsigned char descriptor_control;<br>
+<br>
+} __attribute__ ((packed, aligned(1)));<br>
+<br>
+/* SG-DMA Control/Status Slave registers map */<br>
+<br>
+struct alt_sgdma_registers {<br>
+ unsigned int status;<br>
+ unsigned int status_pad[3];<br>
+ unsigned int control;<br>
+ unsigned int control_pad[3];<br>
+ unsigned int next_descriptor_pointer;<br>
+ unsigned int descriptor_pad[3];<br>
+};<br>
+<br>
+/* TSE Stuff */<br>
+#define ALTERA_TSE_CMD_TX_ENA_MSK (0x00000001)<br>
+#define ALTERA_TSE_CMD_RX_ENA_MSK (0x00000002)<br>
+#define ALTERA_TSE_CMD_XON_GEN_MSK (0x00000004)<br>
+#define ALTERA_TSE_CMD_ETH_SPEED_MSK (0x00000008)<br>
+#define ALTERA_TSE_CMD_PROMIS_EN_MSK (0x00000010)<br>
+#define ALTERA_TSE_CMD_PAD_EN_MSK (0x00000020)<br>
+#define ALTERA_TSE_CMD_CRC_FWD_MSK (0x00000040)<br>
+#define ALTERA_TSE_CMD_PAUSE_FWD_MSK (0x00000080)<br>
+#define ALTERA_TSE_CMD_PAUSE_IGNORE_MSK (0x00000100)<br>
+#define ALTERA_TSE_CMD_TX_ADDR_INS_MSK (0x00000200)<br>
+#define ALTERA_TSE_CMD_HD_ENA_MSK (0x00000400)<br>
+#define ALTERA_TSE_CMD_EXCESS_COL_MSK (0x00000800)<br>
+#define ALTERA_TSE_CMD_LATE_COL_MSK (0x00001000)<br>
+#define ALTERA_TSE_CMD_SW_RESET_MSK (0x00002000)<br>
+#define ALTERA_TSE_CMD_MHASH_SEL_MSK (0x00004000)<br>
+#define ALTERA_TSE_CMD_LOOPBACK_MSK (0x00008000)<br>
+/* Bits (18:16) = address select */<br>
+#define ALTERA_TSE_CMD_TX_ADDR_SEL_MSK (0x00070000)<br>
+#define ALTERA_TSE_CMD_MAGIC_ENA_MSK (0x00080000)<br>
+#define ALTERA_TSE_CMD_SLEEP_MSK (0x00100000)<br>
+#define ALTERA_TSE_CMD_WAKEUP_MSK (0x00200000)<br>
+#define ALTERA_TSE_CMD_XOFF_GEN_MSK (0x00400000)<br>
+#define ALTERA_TSE_CMD_CNTL_FRM_ENA_MSK (0x00800000)<br>
+#define ALTERA_TSE_CMD_NO_LENGTH_CHECK_MSK (0x01000000)<br>
+#define ALTERA_TSE_CMD_ENA_10_MSK (0x02000000)<br>
+#define ALTERA_TSE_CMD_RX_ERR_DISC_MSK (0x04000000)<br>
+/* Bits (30..27) reserved */<br>
+#define ALTERA_TSE_CMD_CNT_RESET_MSK (0x80000000)<br>
+<br>
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 (0x00040000)<br>
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC (0x00020000)<br>
+<br>
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 (0x02000000)<br>
+<br>
+#define ALT_TSE_SW_RESET_WATCHDOG_CNTR 10000<br>
+#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR 90000000<br>
+<br>
+#define ALT_TSE_SW_RESET_WATCHDOG_TOUT 1 /* ms */<br>
+#define ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT 5 /* ms */<br>
+<br>
+struct alt_tse_mdio {<br>
+ unsigned int control; /*PHY device operation control register */<br>
+ unsigned int status; /*PHY device operation status register */<br>
+ unsigned int phy_id1; /*Bits 31:16 of PHY identifier. */<br>
+ unsigned int phy_id2; /*Bits 15:0 of PHY identifier. */<br>
+ unsigned int auto_negotiation_advertisement;<br>
+ unsigned int remote_partner_base_page_ability;<br>
+<br>
+ unsigned int reg6;<br>
+ unsigned int reg7;<br>
+ unsigned int reg8;<br>
+ unsigned int reg9;<br>
+ unsigned int rega;<br>
+ unsigned int regb;<br>
+ unsigned int regc;<br>
+ unsigned int regd;<br>
+ unsigned int rege;<br>
+ unsigned int regf;<br>
+ unsigned int reg10;<br>
+ unsigned int reg11;<br>
+ unsigned int reg12;<br>
+ unsigned int reg13;<br>
+ unsigned int reg14;<br>
+ unsigned int reg15;<br>
+ unsigned int reg16;<br>
+ unsigned int reg17;<br>
+ unsigned int reg18;<br>
+ unsigned int reg19;<br>
+ unsigned int reg1a;<br>
+ unsigned int reg1b;<br>
+ unsigned int reg1c;<br>
+ unsigned int reg1d;<br>
+ unsigned int reg1e;<br>
+ unsigned int reg1f;<br>
+};<br>
+<br>
+/* MAC register Space */<br>
+<br>
+struct alt_tse_mac {<br>
+ unsigned int megacore_revision;<br>
+ unsigned int scratch_pad;<br>
+ unsigned int command_config;<br>
+ unsigned int mac_addr_0;<br>
+ unsigned int mac_addr_1;<br>
+ unsigned int max_frame_length;<br>
+ unsigned int pause_quanta;<br>
+ unsigned int rx_sel_empty_threshold;<br>
+ unsigned int rx_sel_full_threshold;<br>
+ unsigned int tx_sel_empty_threshold;<br>
+ unsigned int tx_sel_full_threshold;<br>
+ unsigned int rx_almost_empty_threshold;<br>
+ unsigned int rx_almost_full_threshold;<br>
+ unsigned int tx_almost_empty_threshold;<br>
+ unsigned int tx_almost_full_threshold;<br>
+ unsigned int mdio_phy0_addr;<br>
+ unsigned int mdio_phy1_addr;<br>
+<br>
+ /* only if 100/1000 BaseX PCS, reserved otherwise */<br>
+ unsigned int reservedx44[5];<br>
+<br>
+ unsigned int reg_read_access_status;<br>
+ unsigned int min_tx_ipg_length;<br>
+<br>
+ /* IEEE 802.3 oEntity Managed Object Support */<br>
+ unsigned int aMACID_1; /*The MAC addresses */<br>
+ unsigned int aMACID_2;<br>
+ unsigned int aFramesTransmittedOK;<br>
+ unsigned int aFramesReceivedOK;<br>
+ unsigned int aFramesCheckSequenceErrors;<br>
+ unsigned int aAlignmentErrors;<br>
+ unsigned int aOctetsTransmittedOK;<br>
+ unsigned int aOctetsReceivedOK;<br>
+<br>
+ /* IEEE 802.3 oPausedEntity Managed Object Support */<br>
+ unsigned int aTxPAUSEMACCtrlFrames;<br>
+ unsigned int aRxPAUSEMACCtrlFrames;<br>
+<br>
+ /* IETF MIB (MIB-II) Object Support */<br>
+ unsigned int ifInErrors;<br>
+ unsigned int ifOutErrors;<br>
+ unsigned int ifInUcastPkts;<br>
+ unsigned int ifInMulticastPkts;<br>
+ unsigned int ifInBroadcastPkts;<br>
+ unsigned int ifOutDiscards;<br>
+ unsigned int ifOutUcastPkts;<br>
+ unsigned int ifOutMulticastPkts;<br>
+ unsigned int ifOutBroadcastPkts;<br>
+<br>
+ /* IETF RMON MIB Object Support */<br>
+ unsigned int etherStatsDropEvent;<br>
+ unsigned int etherStatsOctets;<br>
+ unsigned int etherStatsPkts;<br>
+ unsigned int etherStatsUndersizePkts;<br>
+ unsigned int etherStatsOversizePkts;<br>
+ unsigned int etherStatsPkts64Octets;<br>
+ unsigned int etherStatsPkts65to127Octets;<br>
+ unsigned int etherStatsPkts128to255Octets;<br>
+ unsigned int etherStatsPkts256to511Octets;<br>
+ unsigned int etherStatsPkts512to1023Octets;<br>
+ unsigned int etherStatsPkts1024to1518Octets;<br>
+<br>
+ unsigned int etherStatsPkts1519toXOctets;<br>
+ unsigned int etherStatsJabbers;<br>
+ unsigned int etherStatsFragments;<br>
+<br>
+ unsigned int reservedxE4;<br>
+<br>
+ /*FIFO control register. */<br>
+ unsigned int tx_cmd_stat;<br>
+ unsigned int rx_cmd_stat;<br>
+<br>
+ unsigned int ipaccTxConf;<br>
+ unsigned int ipaccRxConf;<br>
+ unsigned int ipaccRxStat;<br>
+ unsigned int ipaccRxStatSum;<br>
+<br>
+ /*Multicast address resolution table */<br>
+ unsigned int hash_table[64];<br>
+<br>
+ /*Registers 0 to 31 within PHY device 0/1 */<br>
+ struct alt_tse_mdio mdio_phy0;<br>
+ struct alt_tse_mdio mdio_phy1;<br>
+<br>
+ /*4 Supplemental MAC Addresses */<br>
+ unsigned int supp_mac_addr_0_0;<br>
+ unsigned int supp_mac_addr_0_1;<br>
+ unsigned int supp_mac_addr_1_0;<br>
+ unsigned int supp_mac_addr_1_1;<br>
+ unsigned int supp_mac_addr_2_0;<br>
+ unsigned int supp_mac_addr_2_1;<br>
+ unsigned int supp_mac_addr_3_0;<br>
+ unsigned int supp_mac_addr_3_1;<br>
+<br>
+ unsigned int reservedx320[56];<br>
+};<br>
+<br>
+struct altera_tse_priv {<br>
+ struct alt_tse_mac *mac_dev;<br>
+ struct alt_sgdma_registers *sgdma_rx;<br>
+ struct alt_sgdma_registers *sgdma_tx;<br>
+ unsigned int rx_sgdma_irq;<br>
+ unsigned int tx_sgdma_irq;<br>
+ unsigned int has_descriptor_mem;<br>
+ unsigned int descriptor_mem_base;<br>
+ unsigned int descriptor_mem_size;<br>
+ struct alt_sgdma_descriptor *rx_desc;<br>
+ struct alt_sgdma_descriptor *tx_desc;<br>
+ struct mii_device *miidev;<br>
+};<br>
+<br>
+#endif /* _ALTERA_TSE_H_ */<br>
<font color="#888888">--<br>
1.7.0.4<br>
<br>
</font></blockquote></div><br><div>Hello,</div><div><br></div><div>Did you have time to check this one ? Should I review it ?</div><div><br></div><div>Thanks,</div><div>Franck.</div>