1c960b13eSThomas Chou /* 2c960b13eSThomas Chou * Altera 10/100/1000 triple speed ethernet mac driver 3c960b13eSThomas Chou * 4c960b13eSThomas Chou * Copyright (C) 2008 Altera Corporation. 5c960b13eSThomas Chou * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> 6c960b13eSThomas Chou * 7c960b13eSThomas Chou * This program is free software; you can redistribute it and/or modify 8c960b13eSThomas Chou * it under the terms of the GNU General Public License version 2 as 9c960b13eSThomas Chou * published by the Free Software Foundation. 10c960b13eSThomas Chou */ 11c960b13eSThomas Chou #include <common.h> 1296fa1e43SThomas Chou #include <dm.h> 1396fa1e43SThomas Chou #include <errno.h> 1496fa1e43SThomas Chou #include <fdt_support.h> 1596fa1e43SThomas Chou #include <memalign.h> 1696fa1e43SThomas Chou #include <miiphy.h> 17c960b13eSThomas Chou #include <net.h> 18c960b13eSThomas Chou #include <asm/cache.h> 19c960b13eSThomas Chou #include <asm/dma-mapping.h> 2096fa1e43SThomas Chou #include <asm/io.h> 21c960b13eSThomas Chou #include "altera_tse.h" 22c960b13eSThomas Chou 2396fa1e43SThomas Chou DECLARE_GLOBAL_DATA_PTR; 24c960b13eSThomas Chou 2596fa1e43SThomas Chou static inline void alt_sgdma_construct_descriptor( 2696fa1e43SThomas Chou struct alt_sgdma_descriptor *desc, 2796fa1e43SThomas Chou struct alt_sgdma_descriptor *next, 2896fa1e43SThomas Chou void *read_addr, 2996fa1e43SThomas Chou void *write_addr, 302cd0a52eSThomas Chou u16 length_or_eop, 31c960b13eSThomas Chou int generate_eop, 32c960b13eSThomas Chou int read_fixed, 3396fa1e43SThomas Chou int write_fixed_or_sop) 34c960b13eSThomas Chou { 352cd0a52eSThomas Chou u8 val; 3696fa1e43SThomas Chou 37c960b13eSThomas Chou /* 38c960b13eSThomas Chou * Mark the "next" descriptor as "not" owned by hardware. This prevents 3996fa1e43SThomas Chou * The SGDMA controller from continuing to process the chain. 40c960b13eSThomas Chou */ 4196fa1e43SThomas Chou next->descriptor_control = next->descriptor_control & 4296fa1e43SThomas Chou ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; 43c960b13eSThomas Chou 4496fa1e43SThomas Chou memset(desc, 0, sizeof(struct alt_sgdma_descriptor)); 4596fa1e43SThomas Chou desc->source = virt_to_phys(read_addr); 4696fa1e43SThomas Chou desc->destination = virt_to_phys(write_addr); 4796fa1e43SThomas Chou desc->next = virt_to_phys(next); 48c960b13eSThomas Chou desc->bytes_to_transfer = length_or_eop; 49c960b13eSThomas Chou 50c960b13eSThomas Chou /* 51c960b13eSThomas Chou * Set the descriptor control block as follows: 52c960b13eSThomas Chou * - Set "owned by hardware" bit 53c960b13eSThomas Chou * - Optionally set "generate EOP" bit 54c960b13eSThomas Chou * - Optionally set the "read from fixed address" bit 55c960b13eSThomas Chou * - Optionally set the "write to fixed address bit (which serves 56c960b13eSThomas Chou * serves as a "generate SOP" control bit in memory-to-stream mode). 57c960b13eSThomas Chou * - Set the 4-bit atlantic channel, if specified 58c960b13eSThomas Chou * 59c960b13eSThomas Chou * Note this step is performed after all other descriptor information 60c960b13eSThomas Chou * has been filled out so that, if the controller already happens to be 61c960b13eSThomas Chou * pointing at this descriptor, it will not run (via the "owned by 62c960b13eSThomas Chou * hardware" bit) until all other descriptor has been set up. 63c960b13eSThomas Chou */ 6496fa1e43SThomas Chou val = ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; 6596fa1e43SThomas Chou if (generate_eop) 6696fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK; 6796fa1e43SThomas Chou if (read_fixed) 6896fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK; 6996fa1e43SThomas Chou if (write_fixed_or_sop) 7096fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK; 7196fa1e43SThomas Chou desc->descriptor_control = val; 72c960b13eSThomas Chou } 73c960b13eSThomas Chou 7496fa1e43SThomas Chou static int alt_sgdma_wait_transfer(struct alt_sgdma_registers *regs) 75c960b13eSThomas Chou { 7696fa1e43SThomas Chou int status; 7796fa1e43SThomas Chou ulong ctime; 78c960b13eSThomas Chou 79c960b13eSThomas Chou /* Wait for the descriptor (chain) to complete */ 8096fa1e43SThomas Chou ctime = get_timer(0); 8196fa1e43SThomas Chou while (1) { 8296fa1e43SThomas Chou status = readl(®s->status); 8396fa1e43SThomas Chou if (!(status & ALT_SGDMA_STATUS_BUSY_MSK)) 8496fa1e43SThomas Chou break; 8596fa1e43SThomas Chou if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) { 8696fa1e43SThomas Chou status = -ETIMEDOUT; 8796fa1e43SThomas Chou debug("sgdma timeout\n"); 88c960b13eSThomas Chou break; 89c960b13eSThomas Chou } 9096fa1e43SThomas Chou } 91c960b13eSThomas Chou 9296fa1e43SThomas Chou /* Clear Run */ 9396fa1e43SThomas Chou writel(0, ®s->control); 9496fa1e43SThomas Chou /* Clear status */ 9596fa1e43SThomas Chou writel(0xff, ®s->status); 96c960b13eSThomas Chou 9796fa1e43SThomas Chou return status; 9896fa1e43SThomas Chou } 99337aff53SJoachim Foerster 10096fa1e43SThomas Chou static int alt_sgdma_start_transfer(struct alt_sgdma_registers *regs, 10196fa1e43SThomas Chou struct alt_sgdma_descriptor *desc) 10296fa1e43SThomas Chou { 1032cd0a52eSThomas Chou u32 val; 104c960b13eSThomas Chou 105c960b13eSThomas Chou /* Point the controller at the descriptor */ 10696fa1e43SThomas Chou writel(virt_to_phys(desc), ®s->next_descriptor_pointer); 107c960b13eSThomas Chou 108c960b13eSThomas Chou /* 109c960b13eSThomas Chou * Set up SGDMA controller to: 110c960b13eSThomas Chou * - Disable interrupt generation 111c960b13eSThomas Chou * - Run once a valid descriptor is written to controller 112c960b13eSThomas Chou * - Stop on an error with any particular descriptor 113c960b13eSThomas Chou */ 11496fa1e43SThomas Chou val = ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK; 11596fa1e43SThomas Chou writel(val, ®s->control); 116c960b13eSThomas Chou 117c960b13eSThomas Chou return 0; 118c960b13eSThomas Chou } 119c960b13eSThomas Chou 12096fa1e43SThomas Chou static void tse_adjust_link(struct altera_tse_priv *priv, 12196fa1e43SThomas Chou struct phy_device *phydev) 122c960b13eSThomas Chou { 12396fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 1242cd0a52eSThomas Chou u32 refvar; 125c960b13eSThomas Chou 12696fa1e43SThomas Chou if (!phydev->link) { 12796fa1e43SThomas Chou debug("%s: No link.\n", phydev->dev->name); 12896fa1e43SThomas Chou return; 12996fa1e43SThomas Chou } 130c960b13eSThomas Chou 13196fa1e43SThomas Chou refvar = readl(&mac_dev->command_config); 13296fa1e43SThomas Chou 13396fa1e43SThomas Chou if (phydev->duplex) 134c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; 135c960b13eSThomas Chou else 136c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK; 137c960b13eSThomas Chou 13896fa1e43SThomas Chou switch (phydev->speed) { 139c960b13eSThomas Chou case 1000: 140c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; 141c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 142c960b13eSThomas Chou break; 143c960b13eSThomas Chou case 100: 144c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 145c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 146c960b13eSThomas Chou break; 147c960b13eSThomas Chou case 10: 148c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 149c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ENA_10_MSK; 150c960b13eSThomas Chou break; 151c960b13eSThomas Chou } 15296fa1e43SThomas Chou writel(refvar, &mac_dev->command_config); 153c960b13eSThomas Chou } 154c960b13eSThomas Chou 155*38fa4acaSThomas Chou static int altera_tse_send_sgdma(struct udevice *dev, void *packet, int length) 156c960b13eSThomas Chou { 15796fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 15896fa1e43SThomas Chou struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; 159c960b13eSThomas Chou 16096fa1e43SThomas Chou alt_sgdma_construct_descriptor( 16196fa1e43SThomas Chou tx_desc, 16296fa1e43SThomas Chou tx_desc + 1, 16396fa1e43SThomas Chou packet, /* read addr */ 16496fa1e43SThomas Chou NULL, /* write addr */ 165c960b13eSThomas Chou length, /* length or EOP ,will change for each tx */ 16696fa1e43SThomas Chou 1, /* gen eop */ 16796fa1e43SThomas Chou 0, /* read fixed */ 16896fa1e43SThomas Chou 1 /* write fixed or sop */ 169c960b13eSThomas Chou ); 170c960b13eSThomas Chou 171c960b13eSThomas Chou /* send the packet */ 17296fa1e43SThomas Chou alt_sgdma_start_transfer(priv->sgdma_tx, tx_desc); 17396fa1e43SThomas Chou alt_sgdma_wait_transfer(priv->sgdma_tx); 17496fa1e43SThomas Chou debug("sent %d bytes\n", tx_desc->actual_bytes_transferred); 17596fa1e43SThomas Chou 17696fa1e43SThomas Chou return tx_desc->actual_bytes_transferred; 177c960b13eSThomas Chou } 178c960b13eSThomas Chou 179*38fa4acaSThomas Chou static int altera_tse_recv_sgdma(struct udevice *dev, int flags, 180*38fa4acaSThomas Chou uchar **packetp) 181c960b13eSThomas Chou { 18296fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 18396fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 18496fa1e43SThomas Chou int packet_length; 185c960b13eSThomas Chou 18696fa1e43SThomas Chou if (rx_desc->descriptor_status & 187c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { 188577662f0SThomas Chou alt_sgdma_wait_transfer(priv->sgdma_rx); 189c960b13eSThomas Chou packet_length = rx_desc->actual_bytes_transferred; 19096fa1e43SThomas Chou debug("recv %d bytes\n", packet_length); 19196fa1e43SThomas Chou *packetp = priv->rx_buf; 19270d52f9aSJoachim Foerster 19370d52f9aSJoachim Foerster return packet_length; 194c960b13eSThomas Chou } 195c960b13eSThomas Chou 19696fa1e43SThomas Chou return -EAGAIN; 197c960b13eSThomas Chou } 198c960b13eSThomas Chou 199*38fa4acaSThomas Chou static int altera_tse_free_pkt_sgdma(struct udevice *dev, uchar *packet, 20096fa1e43SThomas Chou int length) 201c960b13eSThomas Chou { 20296fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 20396fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 20496fa1e43SThomas Chou 20596fa1e43SThomas Chou alt_sgdma_construct_descriptor( 20696fa1e43SThomas Chou rx_desc, 20796fa1e43SThomas Chou rx_desc + 1, 20896fa1e43SThomas Chou NULL, /* read addr */ 20996fa1e43SThomas Chou priv->rx_buf, /* write addr */ 21096fa1e43SThomas Chou 0, /* length or EOP */ 21196fa1e43SThomas Chou 0, /* gen eop */ 21296fa1e43SThomas Chou 0, /* read fixed */ 21396fa1e43SThomas Chou 0 /* write fixed or sop */ 21496fa1e43SThomas Chou ); 21596fa1e43SThomas Chou 21696fa1e43SThomas Chou /* setup the sgdma */ 21796fa1e43SThomas Chou alt_sgdma_start_transfer(priv->sgdma_rx, rx_desc); 21896fa1e43SThomas Chou debug("recv setup\n"); 21996fa1e43SThomas Chou 22096fa1e43SThomas Chou return 0; 221c960b13eSThomas Chou } 222c960b13eSThomas Chou 223acd71c32SThomas Chou static void altera_tse_stop_mac(struct altera_tse_priv *priv) 224acd71c32SThomas Chou { 225acd71c32SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 226acd71c32SThomas Chou u32 status; 227acd71c32SThomas Chou ulong ctime; 228acd71c32SThomas Chou 229acd71c32SThomas Chou /* reset the mac */ 230acd71c32SThomas Chou writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config); 231acd71c32SThomas Chou ctime = get_timer(0); 232acd71c32SThomas Chou while (1) { 233acd71c32SThomas Chou status = readl(&mac_dev->command_config); 234acd71c32SThomas Chou if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK)) 235acd71c32SThomas Chou break; 236acd71c32SThomas Chou if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { 237acd71c32SThomas Chou debug("Reset mac timeout\n"); 238acd71c32SThomas Chou break; 239acd71c32SThomas Chou } 240acd71c32SThomas Chou } 241acd71c32SThomas Chou } 242acd71c32SThomas Chou 243*38fa4acaSThomas Chou static void altera_tse_stop_sgdma(struct udevice *dev) 244c960b13eSThomas Chou { 24596fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 24696fa1e43SThomas Chou struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; 24796fa1e43SThomas Chou struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 24896fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 24996fa1e43SThomas Chou int ret; 250c960b13eSThomas Chou 251c960b13eSThomas Chou /* clear rx desc & wait for sgdma to complete */ 252c960b13eSThomas Chou rx_desc->descriptor_control = 0; 25396fa1e43SThomas Chou writel(0, &rx_sgdma->control); 25496fa1e43SThomas Chou ret = alt_sgdma_wait_transfer(rx_sgdma); 25596fa1e43SThomas Chou if (ret == -ETIMEDOUT) 25696fa1e43SThomas Chou writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, 25796fa1e43SThomas Chou &rx_sgdma->control); 258c960b13eSThomas Chou 25996fa1e43SThomas Chou writel(0, &tx_sgdma->control); 26096fa1e43SThomas Chou ret = alt_sgdma_wait_transfer(tx_sgdma); 26196fa1e43SThomas Chou if (ret == -ETIMEDOUT) 26296fa1e43SThomas Chou writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, 26396fa1e43SThomas Chou &tx_sgdma->control); 264c960b13eSThomas Chou } 265c960b13eSThomas Chou 26696fa1e43SThomas Chou static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) 267c960b13eSThomas Chou { 26896fa1e43SThomas Chou struct altera_tse_priv *priv = bus->priv; 26996fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 2702cd0a52eSThomas Chou u32 value; 271c960b13eSThomas Chou 272c960b13eSThomas Chou /* set mdio address */ 27396fa1e43SThomas Chou writel(addr, &mac_dev->mdio_phy1_addr); 274c960b13eSThomas Chou /* get the data */ 27596fa1e43SThomas Chou value = readl(&mac_dev->mdio_phy1[reg]); 276c960b13eSThomas Chou 27796fa1e43SThomas Chou return value & 0xffff; 278c960b13eSThomas Chou } 279c960b13eSThomas Chou 28096fa1e43SThomas Chou static int tse_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, 28196fa1e43SThomas Chou u16 val) 282c960b13eSThomas Chou { 28396fa1e43SThomas Chou struct altera_tse_priv *priv = bus->priv; 28496fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 285c960b13eSThomas Chou 286c960b13eSThomas Chou /* set mdio address */ 28796fa1e43SThomas Chou writel(addr, &mac_dev->mdio_phy1_addr); 28896fa1e43SThomas Chou /* set the data */ 28996fa1e43SThomas Chou writel(val, &mac_dev->mdio_phy1[reg]); 290c960b13eSThomas Chou 291c960b13eSThomas Chou return 0; 292c960b13eSThomas Chou } 293c960b13eSThomas Chou 29496fa1e43SThomas Chou static int tse_mdio_init(const char *name, struct altera_tse_priv *priv) 295c960b13eSThomas Chou { 29696fa1e43SThomas Chou struct mii_dev *bus = mdio_alloc(); 297c960b13eSThomas Chou 29896fa1e43SThomas Chou if (!bus) { 29996fa1e43SThomas Chou printf("Failed to allocate MDIO bus\n"); 30096fa1e43SThomas Chou return -ENOMEM; 30196fa1e43SThomas Chou } 30296fa1e43SThomas Chou 30396fa1e43SThomas Chou bus->read = tse_mdio_read; 30496fa1e43SThomas Chou bus->write = tse_mdio_write; 30596fa1e43SThomas Chou snprintf(bus->name, sizeof(bus->name), name); 30696fa1e43SThomas Chou 30796fa1e43SThomas Chou bus->priv = (void *)priv; 30896fa1e43SThomas Chou 30996fa1e43SThomas Chou return mdio_register(bus); 31096fa1e43SThomas Chou } 31196fa1e43SThomas Chou 31296fa1e43SThomas Chou static int tse_phy_init(struct altera_tse_priv *priv, void *dev) 31396fa1e43SThomas Chou { 31496fa1e43SThomas Chou struct phy_device *phydev; 31596fa1e43SThomas Chou unsigned int mask = 0xffffffff; 31696fa1e43SThomas Chou 31796fa1e43SThomas Chou if (priv->phyaddr) 31896fa1e43SThomas Chou mask = 1 << priv->phyaddr; 31996fa1e43SThomas Chou 32096fa1e43SThomas Chou phydev = phy_find_by_mask(priv->bus, mask, priv->interface); 32196fa1e43SThomas Chou if (!phydev) 32296fa1e43SThomas Chou return -ENODEV; 32396fa1e43SThomas Chou 32496fa1e43SThomas Chou phy_connect_dev(phydev, dev); 32596fa1e43SThomas Chou 32696fa1e43SThomas Chou phydev->supported &= PHY_GBIT_FEATURES; 32796fa1e43SThomas Chou phydev->advertising = phydev->supported; 32896fa1e43SThomas Chou 32996fa1e43SThomas Chou priv->phydev = phydev; 33096fa1e43SThomas Chou phy_config(phydev); 331c960b13eSThomas Chou 332c960b13eSThomas Chou return 0; 333c960b13eSThomas Chou } 334c960b13eSThomas Chou 33596fa1e43SThomas Chou static int altera_tse_write_hwaddr(struct udevice *dev) 336c960b13eSThomas Chou { 33796fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 33896fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 33996fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 34096fa1e43SThomas Chou u8 *hwaddr = pdata->enetaddr; 3412cd0a52eSThomas Chou u32 mac_lo, mac_hi; 342c960b13eSThomas Chou 34396fa1e43SThomas Chou mac_lo = (hwaddr[3] << 24) | (hwaddr[2] << 16) | 34496fa1e43SThomas Chou (hwaddr[1] << 8) | hwaddr[0]; 34596fa1e43SThomas Chou mac_hi = (hwaddr[5] << 8) | hwaddr[4]; 34696fa1e43SThomas Chou debug("Set MAC address to 0x%04x%08x\n", mac_hi, mac_lo); 347c960b13eSThomas Chou 34896fa1e43SThomas Chou writel(mac_lo, &mac_dev->mac_addr_0); 34996fa1e43SThomas Chou writel(mac_hi, &mac_dev->mac_addr_1); 35096fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_0_0); 35196fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_0_1); 35296fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_1_0); 35396fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_1_1); 35496fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_2_0); 35596fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_2_1); 35696fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_3_0); 35796fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_3_1); 358c960b13eSThomas Chou 359c960b13eSThomas Chou return 0; 360c960b13eSThomas Chou } 361c960b13eSThomas Chou 362*38fa4acaSThomas Chou static int altera_tse_send(struct udevice *dev, void *packet, int length) 363*38fa4acaSThomas Chou { 364*38fa4acaSThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 365*38fa4acaSThomas Chou unsigned long tx_buf = (unsigned long)packet; 366*38fa4acaSThomas Chou 367*38fa4acaSThomas Chou flush_dcache_range(tx_buf, tx_buf + length); 368*38fa4acaSThomas Chou 369*38fa4acaSThomas Chou return priv->ops->send(dev, packet, length); 370*38fa4acaSThomas Chou } 371*38fa4acaSThomas Chou 372*38fa4acaSThomas Chou static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) 373*38fa4acaSThomas Chou { 374*38fa4acaSThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 375*38fa4acaSThomas Chou 376*38fa4acaSThomas Chou return priv->ops->recv(dev, flags, packetp); 377*38fa4acaSThomas Chou } 378*38fa4acaSThomas Chou 379*38fa4acaSThomas Chou static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, 380*38fa4acaSThomas Chou int length) 381*38fa4acaSThomas Chou { 382*38fa4acaSThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 383*38fa4acaSThomas Chou unsigned long rx_buf = (unsigned long)priv->rx_buf; 384*38fa4acaSThomas Chou 385*38fa4acaSThomas Chou invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); 386*38fa4acaSThomas Chou 387*38fa4acaSThomas Chou return priv->ops->free_pkt(dev, packet, length); 388*38fa4acaSThomas Chou } 389*38fa4acaSThomas Chou 390*38fa4acaSThomas Chou static void altera_tse_stop(struct udevice *dev) 391*38fa4acaSThomas Chou { 392*38fa4acaSThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 393*38fa4acaSThomas Chou 394*38fa4acaSThomas Chou priv->ops->stop(dev); 395*38fa4acaSThomas Chou altera_tse_stop_mac(priv); 396*38fa4acaSThomas Chou } 397*38fa4acaSThomas Chou 39896fa1e43SThomas Chou static int altera_tse_start(struct udevice *dev) 399c960b13eSThomas Chou { 40096fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 40196fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 4022cd0a52eSThomas Chou u32 val; 40396fa1e43SThomas Chou int ret; 404c960b13eSThomas Chou 405c960b13eSThomas Chou /* need to create sgdma */ 406c960b13eSThomas Chou debug("Configuring rx desc\n"); 40796fa1e43SThomas Chou altera_tse_free_pkt(dev, priv->rx_buf, PKTSIZE_ALIGN); 408c960b13eSThomas Chou /* start TSE */ 409c960b13eSThomas Chou debug("Configuring TSE Mac\n"); 410c960b13eSThomas Chou /* Initialize MAC registers */ 41196fa1e43SThomas Chou writel(PKTSIZE_ALIGN, &mac_dev->max_frame_length); 41296fa1e43SThomas Chou writel(priv->rx_fifo_depth - 16, &mac_dev->rx_sel_empty_threshold); 41396fa1e43SThomas Chou writel(0, &mac_dev->rx_sel_full_threshold); 41496fa1e43SThomas Chou writel(priv->tx_fifo_depth - 16, &mac_dev->tx_sel_empty_threshold); 41596fa1e43SThomas Chou writel(0, &mac_dev->tx_sel_full_threshold); 41696fa1e43SThomas Chou writel(8, &mac_dev->rx_almost_empty_threshold); 41796fa1e43SThomas Chou writel(8, &mac_dev->rx_almost_full_threshold); 41896fa1e43SThomas Chou writel(8, &mac_dev->tx_almost_empty_threshold); 41996fa1e43SThomas Chou writel(3, &mac_dev->tx_almost_full_threshold); 420c960b13eSThomas Chou 421c960b13eSThomas Chou /* NO Shift */ 42296fa1e43SThomas Chou writel(0, &mac_dev->rx_cmd_stat); 42396fa1e43SThomas Chou writel(0, &mac_dev->tx_cmd_stat); 424c960b13eSThomas Chou 425c960b13eSThomas Chou /* enable MAC */ 42696fa1e43SThomas Chou val = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; 42796fa1e43SThomas Chou writel(val, &mac_dev->command_config); 428c960b13eSThomas Chou 42996fa1e43SThomas Chou /* Start up the PHY */ 43096fa1e43SThomas Chou ret = phy_startup(priv->phydev); 43196fa1e43SThomas Chou if (ret) { 43296fa1e43SThomas Chou debug("Could not initialize PHY %s\n", 43396fa1e43SThomas Chou priv->phydev->dev->name); 43496fa1e43SThomas Chou return ret; 435c960b13eSThomas Chou } 436c960b13eSThomas Chou 43796fa1e43SThomas Chou tse_adjust_link(priv, priv->phydev); 43896fa1e43SThomas Chou 43996fa1e43SThomas Chou if (!priv->phydev->link) 44096fa1e43SThomas Chou return -EIO; 44196fa1e43SThomas Chou 44296fa1e43SThomas Chou return 0; 443c960b13eSThomas Chou } 444c960b13eSThomas Chou 445*38fa4acaSThomas Chou static const struct tse_ops tse_sgdma_ops = { 446*38fa4acaSThomas Chou .send = altera_tse_send_sgdma, 447*38fa4acaSThomas Chou .recv = altera_tse_recv_sgdma, 448*38fa4acaSThomas Chou .free_pkt = altera_tse_free_pkt_sgdma, 449*38fa4acaSThomas Chou .stop = altera_tse_stop_sgdma, 450*38fa4acaSThomas Chou }; 451*38fa4acaSThomas Chou 45296fa1e43SThomas Chou static int altera_tse_probe(struct udevice *dev) 453c960b13eSThomas Chou { 45496fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 45596fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 45675199d6fSThomas Chou void *blob = (void *)gd->fdt_blob; 45796fa1e43SThomas Chou int node = dev->of_offset; 45896fa1e43SThomas Chou const char *list, *end; 45996fa1e43SThomas Chou const fdt32_t *cell; 46096fa1e43SThomas Chou void *base, *desc_mem = NULL; 46196fa1e43SThomas Chou unsigned long addr, size; 46275199d6fSThomas Chou int parent, addrc, sizec; 46396fa1e43SThomas Chou int len, idx; 46496fa1e43SThomas Chou int ret; 465c960b13eSThomas Chou 466*38fa4acaSThomas Chou priv->dma_type = dev_get_driver_data(dev); 467*38fa4acaSThomas Chou if (priv->dma_type == ALT_SGDMA) 468*38fa4acaSThomas Chou priv->ops = &tse_sgdma_ops; 46996fa1e43SThomas Chou /* 47075199d6fSThomas Chou * decode regs. there are multiple reg tuples, and they need to 47175199d6fSThomas Chou * match with reg-names. 47296fa1e43SThomas Chou */ 47375199d6fSThomas Chou parent = fdt_parent_offset(blob, node); 47475199d6fSThomas Chou of_bus_default_count_cells(blob, parent, &addrc, &sizec); 47596fa1e43SThomas Chou list = fdt_getprop(blob, node, "reg-names", &len); 47696fa1e43SThomas Chou if (!list) 47796fa1e43SThomas Chou return -ENOENT; 47896fa1e43SThomas Chou end = list + len; 47996fa1e43SThomas Chou cell = fdt_getprop(blob, node, "reg", &len); 48096fa1e43SThomas Chou if (!cell) 48196fa1e43SThomas Chou return -ENOENT; 48296fa1e43SThomas Chou idx = 0; 48396fa1e43SThomas Chou while (list < end) { 48496fa1e43SThomas Chou addr = fdt_translate_address((void *)blob, 48596fa1e43SThomas Chou node, cell + idx); 48675199d6fSThomas Chou size = fdt_addr_to_cpu(cell[idx + addrc]); 48796fa1e43SThomas Chou base = ioremap(addr, size); 48896fa1e43SThomas Chou len = strlen(list); 48996fa1e43SThomas Chou if (strcmp(list, "control_port") == 0) 49096fa1e43SThomas Chou priv->mac_dev = base; 49196fa1e43SThomas Chou else if (strcmp(list, "rx_csr") == 0) 49296fa1e43SThomas Chou priv->sgdma_rx = base; 49396fa1e43SThomas Chou else if (strcmp(list, "tx_csr") == 0) 49496fa1e43SThomas Chou priv->sgdma_tx = base; 49596fa1e43SThomas Chou else if (strcmp(list, "s1") == 0) 49696fa1e43SThomas Chou desc_mem = base; 49775199d6fSThomas Chou idx += addrc + sizec; 49896fa1e43SThomas Chou list += (len + 1); 49996fa1e43SThomas Chou } 50096fa1e43SThomas Chou /* decode fifo depth */ 50196fa1e43SThomas Chou priv->rx_fifo_depth = fdtdec_get_int(blob, node, 50296fa1e43SThomas Chou "rx-fifo-depth", 0); 50396fa1e43SThomas Chou priv->tx_fifo_depth = fdtdec_get_int(blob, node, 50496fa1e43SThomas Chou "tx-fifo-depth", 0); 50596fa1e43SThomas Chou /* decode phy */ 50696fa1e43SThomas Chou addr = fdtdec_get_int(blob, node, 50796fa1e43SThomas Chou "phy-handle", 0); 50896fa1e43SThomas Chou addr = fdt_node_offset_by_phandle(blob, addr); 50996fa1e43SThomas Chou priv->phyaddr = fdtdec_get_int(blob, addr, 51096fa1e43SThomas Chou "reg", 0); 51196fa1e43SThomas Chou /* init desc */ 512*38fa4acaSThomas Chou if (priv->dma_type == ALT_SGDMA) { 51396fa1e43SThomas Chou len = sizeof(struct alt_sgdma_descriptor) * 4; 51496fa1e43SThomas Chou if (!desc_mem) { 51596fa1e43SThomas Chou desc_mem = dma_alloc_coherent(len, &addr); 51696fa1e43SThomas Chou if (!desc_mem) 51796fa1e43SThomas Chou return -ENOMEM; 51896fa1e43SThomas Chou } 51996fa1e43SThomas Chou memset(desc_mem, 0, len); 52096fa1e43SThomas Chou priv->tx_desc = desc_mem; 521*38fa4acaSThomas Chou priv->rx_desc = priv->tx_desc + 522*38fa4acaSThomas Chou 2 * sizeof(struct alt_sgdma_descriptor); 523*38fa4acaSThomas Chou } 52496fa1e43SThomas Chou /* allocate recv packet buffer */ 52596fa1e43SThomas Chou priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN); 52696fa1e43SThomas Chou if (!priv->rx_buf) 52796fa1e43SThomas Chou return -ENOMEM; 528c960b13eSThomas Chou 52996fa1e43SThomas Chou /* stop controller */ 53096fa1e43SThomas Chou debug("Reset TSE & SGDMAs\n"); 53196fa1e43SThomas Chou altera_tse_stop(dev); 532c960b13eSThomas Chou 53396fa1e43SThomas Chou /* start the phy */ 53496fa1e43SThomas Chou priv->interface = pdata->phy_interface; 53596fa1e43SThomas Chou tse_mdio_init(dev->name, priv); 53696fa1e43SThomas Chou priv->bus = miiphy_get_dev_by_name(dev->name); 537c960b13eSThomas Chou 53896fa1e43SThomas Chou ret = tse_phy_init(priv, dev); 539c960b13eSThomas Chou 54096fa1e43SThomas Chou return ret; 54196fa1e43SThomas Chou } 54296fa1e43SThomas Chou 54396fa1e43SThomas Chou static int altera_tse_ofdata_to_platdata(struct udevice *dev) 54496fa1e43SThomas Chou { 54596fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 54696fa1e43SThomas Chou const char *phy_mode; 54796fa1e43SThomas Chou 54896fa1e43SThomas Chou pdata->phy_interface = -1; 54996fa1e43SThomas Chou phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); 55096fa1e43SThomas Chou if (phy_mode) 55196fa1e43SThomas Chou pdata->phy_interface = phy_get_interface_by_name(phy_mode); 55296fa1e43SThomas Chou if (pdata->phy_interface == -1) { 55396fa1e43SThomas Chou debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); 55496fa1e43SThomas Chou return -EINVAL; 55596fa1e43SThomas Chou } 55696fa1e43SThomas Chou 557c960b13eSThomas Chou return 0; 558c960b13eSThomas Chou } 559b962ac79SJoachim Foerster 56096fa1e43SThomas Chou static const struct eth_ops altera_tse_ops = { 56196fa1e43SThomas Chou .start = altera_tse_start, 56296fa1e43SThomas Chou .send = altera_tse_send, 56396fa1e43SThomas Chou .recv = altera_tse_recv, 56496fa1e43SThomas Chou .free_pkt = altera_tse_free_pkt, 56596fa1e43SThomas Chou .stop = altera_tse_stop, 56696fa1e43SThomas Chou .write_hwaddr = altera_tse_write_hwaddr, 56796fa1e43SThomas Chou }; 568c960b13eSThomas Chou 56996fa1e43SThomas Chou static const struct udevice_id altera_tse_ids[] = { 570*38fa4acaSThomas Chou { .compatible = "altr,tse-1.0", .data = ALT_SGDMA }, 57196fa1e43SThomas Chou {} 57296fa1e43SThomas Chou }; 573c960b13eSThomas Chou 57496fa1e43SThomas Chou U_BOOT_DRIVER(altera_tse) = { 57596fa1e43SThomas Chou .name = "altera_tse", 57696fa1e43SThomas Chou .id = UCLASS_ETH, 57796fa1e43SThomas Chou .of_match = altera_tse_ids, 57896fa1e43SThomas Chou .ops = &altera_tse_ops, 57996fa1e43SThomas Chou .ofdata_to_platdata = altera_tse_ofdata_to_platdata, 58096fa1e43SThomas Chou .platdata_auto_alloc_size = sizeof(struct eth_pdata), 58196fa1e43SThomas Chou .priv_auto_alloc_size = sizeof(struct altera_tse_priv), 58296fa1e43SThomas Chou .probe = altera_tse_probe, 58396fa1e43SThomas Chou }; 584