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> 12*96fa1e43SThomas Chou #include <dm.h> 13*96fa1e43SThomas Chou #include <errno.h> 14*96fa1e43SThomas Chou #include <fdt_support.h> 15*96fa1e43SThomas Chou #include <memalign.h> 16*96fa1e43SThomas Chou #include <miiphy.h> 17c960b13eSThomas Chou #include <net.h> 18c960b13eSThomas Chou #include <asm/cache.h> 19c960b13eSThomas Chou #include <asm/dma-mapping.h> 20*96fa1e43SThomas Chou #include <asm/io.h> 21c960b13eSThomas Chou #include "altera_tse.h" 22c960b13eSThomas Chou 23*96fa1e43SThomas Chou DECLARE_GLOBAL_DATA_PTR; 24c960b13eSThomas Chou 25*96fa1e43SThomas Chou static inline void alt_sgdma_construct_descriptor( 26*96fa1e43SThomas Chou struct alt_sgdma_descriptor *desc, 27*96fa1e43SThomas Chou struct alt_sgdma_descriptor *next, 28*96fa1e43SThomas Chou void *read_addr, 29*96fa1e43SThomas Chou void *write_addr, 30c960b13eSThomas Chou unsigned short length_or_eop, 31c960b13eSThomas Chou int generate_eop, 32c960b13eSThomas Chou int read_fixed, 33*96fa1e43SThomas Chou int write_fixed_or_sop) 34c960b13eSThomas Chou { 35*96fa1e43SThomas Chou unsigned char val; 36*96fa1e43SThomas Chou 37c960b13eSThomas Chou /* 38c960b13eSThomas Chou * Mark the "next" descriptor as "not" owned by hardware. This prevents 39*96fa1e43SThomas Chou * The SGDMA controller from continuing to process the chain. 40c960b13eSThomas Chou */ 41*96fa1e43SThomas Chou next->descriptor_control = next->descriptor_control & 42*96fa1e43SThomas Chou ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; 43c960b13eSThomas Chou 44*96fa1e43SThomas Chou memset(desc, 0, sizeof(struct alt_sgdma_descriptor)); 45*96fa1e43SThomas Chou desc->source = virt_to_phys(read_addr); 46*96fa1e43SThomas Chou desc->destination = virt_to_phys(write_addr); 47*96fa1e43SThomas 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 */ 64*96fa1e43SThomas Chou val = ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; 65*96fa1e43SThomas Chou if (generate_eop) 66*96fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK; 67*96fa1e43SThomas Chou if (read_fixed) 68*96fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK; 69*96fa1e43SThomas Chou if (write_fixed_or_sop) 70*96fa1e43SThomas Chou val |= ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK; 71*96fa1e43SThomas Chou desc->descriptor_control = val; 72c960b13eSThomas Chou } 73c960b13eSThomas Chou 74*96fa1e43SThomas Chou static int alt_sgdma_wait_transfer(struct alt_sgdma_registers *regs) 75c960b13eSThomas Chou { 76*96fa1e43SThomas Chou int status; 77*96fa1e43SThomas Chou ulong ctime; 78c960b13eSThomas Chou 79c960b13eSThomas Chou /* Wait for the descriptor (chain) to complete */ 80*96fa1e43SThomas Chou ctime = get_timer(0); 81*96fa1e43SThomas Chou while (1) { 82*96fa1e43SThomas Chou status = readl(®s->status); 83*96fa1e43SThomas Chou if (!(status & ALT_SGDMA_STATUS_BUSY_MSK)) 84*96fa1e43SThomas Chou break; 85*96fa1e43SThomas Chou if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) { 86*96fa1e43SThomas Chou status = -ETIMEDOUT; 87*96fa1e43SThomas Chou debug("sgdma timeout\n"); 88c960b13eSThomas Chou break; 89c960b13eSThomas Chou } 90*96fa1e43SThomas Chou } 91c960b13eSThomas Chou 92*96fa1e43SThomas Chou /* Clear Run */ 93*96fa1e43SThomas Chou writel(0, ®s->control); 94*96fa1e43SThomas Chou /* Clear status */ 95*96fa1e43SThomas Chou writel(0xff, ®s->status); 96c960b13eSThomas Chou 97*96fa1e43SThomas Chou return status; 98*96fa1e43SThomas Chou } 99337aff53SJoachim Foerster 100*96fa1e43SThomas Chou static int alt_sgdma_start_transfer(struct alt_sgdma_registers *regs, 101*96fa1e43SThomas Chou struct alt_sgdma_descriptor *desc) 102*96fa1e43SThomas Chou { 103*96fa1e43SThomas Chou unsigned int val; 104c960b13eSThomas Chou 105c960b13eSThomas Chou /* Point the controller at the descriptor */ 106*96fa1e43SThomas 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 */ 114*96fa1e43SThomas Chou val = ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK; 115*96fa1e43SThomas Chou writel(val, ®s->control); 116c960b13eSThomas Chou 117c960b13eSThomas Chou return 0; 118c960b13eSThomas Chou } 119c960b13eSThomas Chou 120*96fa1e43SThomas Chou static void tse_adjust_link(struct altera_tse_priv *priv, 121*96fa1e43SThomas Chou struct phy_device *phydev) 122c960b13eSThomas Chou { 123*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 124c960b13eSThomas Chou unsigned int refvar; 125c960b13eSThomas Chou 126*96fa1e43SThomas Chou if (!phydev->link) { 127*96fa1e43SThomas Chou debug("%s: No link.\n", phydev->dev->name); 128*96fa1e43SThomas Chou return; 129*96fa1e43SThomas Chou } 130c960b13eSThomas Chou 131*96fa1e43SThomas Chou refvar = readl(&mac_dev->command_config); 132*96fa1e43SThomas Chou 133*96fa1e43SThomas 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 138*96fa1e43SThomas 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 } 152*96fa1e43SThomas Chou writel(refvar, &mac_dev->command_config); 153c960b13eSThomas Chou } 154c960b13eSThomas Chou 155*96fa1e43SThomas Chou static int altera_tse_send(struct udevice *dev, void *packet, int length) 156c960b13eSThomas Chou { 157*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 158*96fa1e43SThomas Chou struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; 159*96fa1e43SThomas Chou unsigned long tx_buf = (unsigned long)packet; 160c960b13eSThomas Chou 161*96fa1e43SThomas Chou flush_dcache_range(tx_buf, tx_buf + length); 162*96fa1e43SThomas Chou alt_sgdma_construct_descriptor( 163*96fa1e43SThomas Chou tx_desc, 164*96fa1e43SThomas Chou tx_desc + 1, 165*96fa1e43SThomas Chou packet, /* read addr */ 166*96fa1e43SThomas Chou NULL, /* write addr */ 167c960b13eSThomas Chou length, /* length or EOP ,will change for each tx */ 168*96fa1e43SThomas Chou 1, /* gen eop */ 169*96fa1e43SThomas Chou 0, /* read fixed */ 170*96fa1e43SThomas Chou 1 /* write fixed or sop */ 171c960b13eSThomas Chou ); 172c960b13eSThomas Chou 173c960b13eSThomas Chou /* send the packet */ 174*96fa1e43SThomas Chou alt_sgdma_start_transfer(priv->sgdma_tx, tx_desc); 175*96fa1e43SThomas Chou alt_sgdma_wait_transfer(priv->sgdma_tx); 176*96fa1e43SThomas Chou debug("sent %d bytes\n", tx_desc->actual_bytes_transferred); 177*96fa1e43SThomas Chou 178*96fa1e43SThomas Chou return tx_desc->actual_bytes_transferred; 179c960b13eSThomas Chou } 180c960b13eSThomas Chou 181*96fa1e43SThomas Chou static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) 182c960b13eSThomas Chou { 183*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 184*96fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 185*96fa1e43SThomas Chou int packet_length; 186c960b13eSThomas Chou 187*96fa1e43SThomas Chou if (rx_desc->descriptor_status & 188c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { 189c960b13eSThomas Chou packet_length = rx_desc->actual_bytes_transferred; 190*96fa1e43SThomas Chou debug("recv %d bytes\n", packet_length); 191*96fa1e43SThomas Chou *packetp = priv->rx_buf; 19270d52f9aSJoachim Foerster 19370d52f9aSJoachim Foerster return packet_length; 194c960b13eSThomas Chou } 195c960b13eSThomas Chou 196*96fa1e43SThomas Chou return -EAGAIN; 197c960b13eSThomas Chou } 198c960b13eSThomas Chou 199*96fa1e43SThomas Chou static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, 200*96fa1e43SThomas Chou int length) 201c960b13eSThomas Chou { 202*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 203*96fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 204*96fa1e43SThomas Chou unsigned long rx_buf = (unsigned long)priv->rx_buf; 205*96fa1e43SThomas Chou 206*96fa1e43SThomas Chou alt_sgdma_wait_transfer(priv->sgdma_rx); 207*96fa1e43SThomas Chou invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); 208*96fa1e43SThomas Chou alt_sgdma_construct_descriptor( 209*96fa1e43SThomas Chou rx_desc, 210*96fa1e43SThomas Chou rx_desc + 1, 211*96fa1e43SThomas Chou NULL, /* read addr */ 212*96fa1e43SThomas Chou priv->rx_buf, /* write addr */ 213*96fa1e43SThomas Chou 0, /* length or EOP */ 214*96fa1e43SThomas Chou 0, /* gen eop */ 215*96fa1e43SThomas Chou 0, /* read fixed */ 216*96fa1e43SThomas Chou 0 /* write fixed or sop */ 217*96fa1e43SThomas Chou ); 218*96fa1e43SThomas Chou 219*96fa1e43SThomas Chou /* setup the sgdma */ 220*96fa1e43SThomas Chou alt_sgdma_start_transfer(priv->sgdma_rx, rx_desc); 221*96fa1e43SThomas Chou debug("recv setup\n"); 222*96fa1e43SThomas Chou 223*96fa1e43SThomas Chou return 0; 224c960b13eSThomas Chou } 225c960b13eSThomas Chou 226*96fa1e43SThomas Chou static void altera_tse_stop(struct udevice *dev) 227c960b13eSThomas Chou { 228*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 229*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 230*96fa1e43SThomas Chou struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; 231*96fa1e43SThomas Chou struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 232*96fa1e43SThomas Chou struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 233*96fa1e43SThomas Chou unsigned int status; 234*96fa1e43SThomas Chou int ret; 235*96fa1e43SThomas Chou ulong ctime; 236c960b13eSThomas Chou 237c960b13eSThomas Chou /* clear rx desc & wait for sgdma to complete */ 238c960b13eSThomas Chou rx_desc->descriptor_control = 0; 239*96fa1e43SThomas Chou writel(0, &rx_sgdma->control); 240*96fa1e43SThomas Chou ret = alt_sgdma_wait_transfer(rx_sgdma); 241*96fa1e43SThomas Chou if (ret == -ETIMEDOUT) 242*96fa1e43SThomas Chou writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, 243*96fa1e43SThomas Chou &rx_sgdma->control); 244c960b13eSThomas Chou 245*96fa1e43SThomas Chou writel(0, &tx_sgdma->control); 246*96fa1e43SThomas Chou ret = alt_sgdma_wait_transfer(tx_sgdma); 247*96fa1e43SThomas Chou if (ret == -ETIMEDOUT) 248*96fa1e43SThomas Chou writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, 249*96fa1e43SThomas Chou &tx_sgdma->control); 250c960b13eSThomas Chou 251c960b13eSThomas Chou /* reset the mac */ 252*96fa1e43SThomas Chou writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config); 253*96fa1e43SThomas Chou ctime = get_timer(0); 254*96fa1e43SThomas Chou while (1) { 255*96fa1e43SThomas Chou status = readl(&mac_dev->command_config); 256*96fa1e43SThomas Chou if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK)) 257*96fa1e43SThomas Chou break; 258*96fa1e43SThomas Chou if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { 259*96fa1e43SThomas Chou debug("Reset mac timeout\n"); 260c960b13eSThomas Chou break; 261c960b13eSThomas Chou } 262*96fa1e43SThomas Chou } 263c960b13eSThomas Chou } 264c960b13eSThomas Chou 265*96fa1e43SThomas Chou static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) 266c960b13eSThomas Chou { 267*96fa1e43SThomas Chou struct altera_tse_priv *priv = bus->priv; 268*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 269*96fa1e43SThomas Chou unsigned int value; 270c960b13eSThomas Chou 271c960b13eSThomas Chou /* set mdio address */ 272*96fa1e43SThomas Chou writel(addr, &mac_dev->mdio_phy1_addr); 273c960b13eSThomas Chou /* get the data */ 274*96fa1e43SThomas Chou value = readl(&mac_dev->mdio_phy1[reg]); 275c960b13eSThomas Chou 276*96fa1e43SThomas Chou return value & 0xffff; 277c960b13eSThomas Chou } 278c960b13eSThomas Chou 279*96fa1e43SThomas Chou static int tse_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, 280*96fa1e43SThomas Chou u16 val) 281c960b13eSThomas Chou { 282*96fa1e43SThomas Chou struct altera_tse_priv *priv = bus->priv; 283*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 284c960b13eSThomas Chou 285c960b13eSThomas Chou /* set mdio address */ 286*96fa1e43SThomas Chou writel(addr, &mac_dev->mdio_phy1_addr); 287*96fa1e43SThomas Chou /* set the data */ 288*96fa1e43SThomas Chou writel(val, &mac_dev->mdio_phy1[reg]); 289c960b13eSThomas Chou 290c960b13eSThomas Chou return 0; 291c960b13eSThomas Chou } 292c960b13eSThomas Chou 293*96fa1e43SThomas Chou static int tse_mdio_init(const char *name, struct altera_tse_priv *priv) 294c960b13eSThomas Chou { 295*96fa1e43SThomas Chou struct mii_dev *bus = mdio_alloc(); 296c960b13eSThomas Chou 297*96fa1e43SThomas Chou if (!bus) { 298*96fa1e43SThomas Chou printf("Failed to allocate MDIO bus\n"); 299*96fa1e43SThomas Chou return -ENOMEM; 300*96fa1e43SThomas Chou } 301*96fa1e43SThomas Chou 302*96fa1e43SThomas Chou bus->read = tse_mdio_read; 303*96fa1e43SThomas Chou bus->write = tse_mdio_write; 304*96fa1e43SThomas Chou snprintf(bus->name, sizeof(bus->name), name); 305*96fa1e43SThomas Chou 306*96fa1e43SThomas Chou bus->priv = (void *)priv; 307*96fa1e43SThomas Chou 308*96fa1e43SThomas Chou return mdio_register(bus); 309*96fa1e43SThomas Chou } 310*96fa1e43SThomas Chou 311*96fa1e43SThomas Chou static int tse_phy_init(struct altera_tse_priv *priv, void *dev) 312*96fa1e43SThomas Chou { 313*96fa1e43SThomas Chou struct phy_device *phydev; 314*96fa1e43SThomas Chou unsigned int mask = 0xffffffff; 315*96fa1e43SThomas Chou 316*96fa1e43SThomas Chou if (priv->phyaddr) 317*96fa1e43SThomas Chou mask = 1 << priv->phyaddr; 318*96fa1e43SThomas Chou 319*96fa1e43SThomas Chou phydev = phy_find_by_mask(priv->bus, mask, priv->interface); 320*96fa1e43SThomas Chou if (!phydev) 321*96fa1e43SThomas Chou return -ENODEV; 322*96fa1e43SThomas Chou 323*96fa1e43SThomas Chou phy_connect_dev(phydev, dev); 324*96fa1e43SThomas Chou 325*96fa1e43SThomas Chou phydev->supported &= PHY_GBIT_FEATURES; 326*96fa1e43SThomas Chou phydev->advertising = phydev->supported; 327*96fa1e43SThomas Chou 328*96fa1e43SThomas Chou priv->phydev = phydev; 329*96fa1e43SThomas Chou phy_config(phydev); 330c960b13eSThomas Chou 331c960b13eSThomas Chou return 0; 332c960b13eSThomas Chou } 333c960b13eSThomas Chou 334*96fa1e43SThomas Chou static int altera_tse_write_hwaddr(struct udevice *dev) 335c960b13eSThomas Chou { 336*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 337*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 338*96fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 339*96fa1e43SThomas Chou u8 *hwaddr = pdata->enetaddr; 340*96fa1e43SThomas Chou unsigned int mac_lo, mac_hi; 341c960b13eSThomas Chou 342*96fa1e43SThomas Chou mac_lo = (hwaddr[3] << 24) | (hwaddr[2] << 16) | 343*96fa1e43SThomas Chou (hwaddr[1] << 8) | hwaddr[0]; 344*96fa1e43SThomas Chou mac_hi = (hwaddr[5] << 8) | hwaddr[4]; 345*96fa1e43SThomas Chou debug("Set MAC address to 0x%04x%08x\n", mac_hi, mac_lo); 346c960b13eSThomas Chou 347*96fa1e43SThomas Chou writel(mac_lo, &mac_dev->mac_addr_0); 348*96fa1e43SThomas Chou writel(mac_hi, &mac_dev->mac_addr_1); 349*96fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_0_0); 350*96fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_0_1); 351*96fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_1_0); 352*96fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_1_1); 353*96fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_2_0); 354*96fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_2_1); 355*96fa1e43SThomas Chou writel(mac_lo, &mac_dev->supp_mac_addr_3_0); 356*96fa1e43SThomas Chou writel(mac_hi, &mac_dev->supp_mac_addr_3_1); 357c960b13eSThomas Chou 358c960b13eSThomas Chou return 0; 359c960b13eSThomas Chou } 360c960b13eSThomas Chou 361*96fa1e43SThomas Chou static int altera_tse_start(struct udevice *dev) 362c960b13eSThomas Chou { 363*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 364*96fa1e43SThomas Chou struct alt_tse_mac *mac_dev = priv->mac_dev; 365*96fa1e43SThomas Chou unsigned int val; 366*96fa1e43SThomas Chou int ret; 367c960b13eSThomas Chou 368c960b13eSThomas Chou /* need to create sgdma */ 369c960b13eSThomas Chou debug("Configuring rx desc\n"); 370*96fa1e43SThomas Chou altera_tse_free_pkt(dev, priv->rx_buf, PKTSIZE_ALIGN); 371c960b13eSThomas Chou /* start TSE */ 372c960b13eSThomas Chou debug("Configuring TSE Mac\n"); 373c960b13eSThomas Chou /* Initialize MAC registers */ 374*96fa1e43SThomas Chou writel(PKTSIZE_ALIGN, &mac_dev->max_frame_length); 375*96fa1e43SThomas Chou writel(priv->rx_fifo_depth - 16, &mac_dev->rx_sel_empty_threshold); 376*96fa1e43SThomas Chou writel(0, &mac_dev->rx_sel_full_threshold); 377*96fa1e43SThomas Chou writel(priv->tx_fifo_depth - 16, &mac_dev->tx_sel_empty_threshold); 378*96fa1e43SThomas Chou writel(0, &mac_dev->tx_sel_full_threshold); 379*96fa1e43SThomas Chou writel(8, &mac_dev->rx_almost_empty_threshold); 380*96fa1e43SThomas Chou writel(8, &mac_dev->rx_almost_full_threshold); 381*96fa1e43SThomas Chou writel(8, &mac_dev->tx_almost_empty_threshold); 382*96fa1e43SThomas Chou writel(3, &mac_dev->tx_almost_full_threshold); 383c960b13eSThomas Chou 384c960b13eSThomas Chou /* NO Shift */ 385*96fa1e43SThomas Chou writel(0, &mac_dev->rx_cmd_stat); 386*96fa1e43SThomas Chou writel(0, &mac_dev->tx_cmd_stat); 387c960b13eSThomas Chou 388c960b13eSThomas Chou /* enable MAC */ 389*96fa1e43SThomas Chou val = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; 390*96fa1e43SThomas Chou writel(val, &mac_dev->command_config); 391c960b13eSThomas Chou 392*96fa1e43SThomas Chou /* Start up the PHY */ 393*96fa1e43SThomas Chou ret = phy_startup(priv->phydev); 394*96fa1e43SThomas Chou if (ret) { 395*96fa1e43SThomas Chou debug("Could not initialize PHY %s\n", 396*96fa1e43SThomas Chou priv->phydev->dev->name); 397*96fa1e43SThomas Chou return ret; 398c960b13eSThomas Chou } 399c960b13eSThomas Chou 400*96fa1e43SThomas Chou tse_adjust_link(priv, priv->phydev); 401*96fa1e43SThomas Chou 402*96fa1e43SThomas Chou if (!priv->phydev->link) 403*96fa1e43SThomas Chou return -EIO; 404*96fa1e43SThomas Chou 405*96fa1e43SThomas Chou return 0; 406c960b13eSThomas Chou } 407c960b13eSThomas Chou 408*96fa1e43SThomas Chou static int altera_tse_probe(struct udevice *dev) 409c960b13eSThomas Chou { 410*96fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 411*96fa1e43SThomas Chou struct altera_tse_priv *priv = dev_get_priv(dev); 412*96fa1e43SThomas Chou const void *blob = gd->fdt_blob; 413*96fa1e43SThomas Chou int node = dev->of_offset; 414*96fa1e43SThomas Chou const char *list, *end; 415*96fa1e43SThomas Chou const fdt32_t *cell; 416*96fa1e43SThomas Chou void *base, *desc_mem = NULL; 417*96fa1e43SThomas Chou unsigned long addr, size; 418*96fa1e43SThomas Chou int len, idx; 419*96fa1e43SThomas Chou int ret; 420c960b13eSThomas Chou 421*96fa1e43SThomas Chou /* 422*96fa1e43SThomas Chou * decode regs, assume address-cells and size-cells are both one. 423*96fa1e43SThomas Chou * there are multiple reg tuples, and they need to match with 424*96fa1e43SThomas Chou * reg-names. 425*96fa1e43SThomas Chou */ 426*96fa1e43SThomas Chou list = fdt_getprop(blob, node, "reg-names", &len); 427*96fa1e43SThomas Chou if (!list) 428*96fa1e43SThomas Chou return -ENOENT; 429*96fa1e43SThomas Chou end = list + len; 430*96fa1e43SThomas Chou cell = fdt_getprop(blob, node, "reg", &len); 431*96fa1e43SThomas Chou if (!cell) 432*96fa1e43SThomas Chou return -ENOENT; 433*96fa1e43SThomas Chou idx = 0; 434*96fa1e43SThomas Chou while (list < end) { 435*96fa1e43SThomas Chou addr = fdt_translate_address((void *)blob, 436*96fa1e43SThomas Chou node, cell + idx); 437*96fa1e43SThomas Chou size = fdt_addr_to_cpu(cell[idx + 1]); 438*96fa1e43SThomas Chou base = ioremap(addr, size); 439*96fa1e43SThomas Chou len = strlen(list); 440*96fa1e43SThomas Chou if (strcmp(list, "control_port") == 0) 441*96fa1e43SThomas Chou priv->mac_dev = base; 442*96fa1e43SThomas Chou else if (strcmp(list, "rx_csr") == 0) 443*96fa1e43SThomas Chou priv->sgdma_rx = base; 444*96fa1e43SThomas Chou else if (strcmp(list, "tx_csr") == 0) 445*96fa1e43SThomas Chou priv->sgdma_tx = base; 446*96fa1e43SThomas Chou else if (strcmp(list, "s1") == 0) 447*96fa1e43SThomas Chou desc_mem = base; 448*96fa1e43SThomas Chou idx += 2; 449*96fa1e43SThomas Chou list += (len + 1); 450*96fa1e43SThomas Chou } 451*96fa1e43SThomas Chou /* decode fifo depth */ 452*96fa1e43SThomas Chou priv->rx_fifo_depth = fdtdec_get_int(blob, node, 453*96fa1e43SThomas Chou "rx-fifo-depth", 0); 454*96fa1e43SThomas Chou priv->tx_fifo_depth = fdtdec_get_int(blob, node, 455*96fa1e43SThomas Chou "tx-fifo-depth", 0); 456*96fa1e43SThomas Chou /* decode phy */ 457*96fa1e43SThomas Chou addr = fdtdec_get_int(blob, node, 458*96fa1e43SThomas Chou "phy-handle", 0); 459*96fa1e43SThomas Chou addr = fdt_node_offset_by_phandle(blob, addr); 460*96fa1e43SThomas Chou priv->phyaddr = fdtdec_get_int(blob, addr, 461*96fa1e43SThomas Chou "reg", 0); 462*96fa1e43SThomas Chou /* init desc */ 463*96fa1e43SThomas Chou len = sizeof(struct alt_sgdma_descriptor) * 4; 464*96fa1e43SThomas Chou if (!desc_mem) { 465*96fa1e43SThomas Chou desc_mem = dma_alloc_coherent(len, &addr); 466*96fa1e43SThomas Chou if (!desc_mem) 467*96fa1e43SThomas Chou return -ENOMEM; 468*96fa1e43SThomas Chou } 469*96fa1e43SThomas Chou memset(desc_mem, 0, len); 470*96fa1e43SThomas Chou priv->tx_desc = desc_mem; 471*96fa1e43SThomas Chou priv->rx_desc = priv->tx_desc + 2; 472*96fa1e43SThomas Chou /* allocate recv packet buffer */ 473*96fa1e43SThomas Chou priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN); 474*96fa1e43SThomas Chou if (!priv->rx_buf) 475*96fa1e43SThomas Chou return -ENOMEM; 476c960b13eSThomas Chou 477*96fa1e43SThomas Chou /* stop controller */ 478*96fa1e43SThomas Chou debug("Reset TSE & SGDMAs\n"); 479*96fa1e43SThomas Chou altera_tse_stop(dev); 480c960b13eSThomas Chou 481*96fa1e43SThomas Chou /* start the phy */ 482*96fa1e43SThomas Chou priv->interface = pdata->phy_interface; 483*96fa1e43SThomas Chou tse_mdio_init(dev->name, priv); 484*96fa1e43SThomas Chou priv->bus = miiphy_get_dev_by_name(dev->name); 485c960b13eSThomas Chou 486*96fa1e43SThomas Chou ret = tse_phy_init(priv, dev); 487c960b13eSThomas Chou 488*96fa1e43SThomas Chou return ret; 489*96fa1e43SThomas Chou } 490*96fa1e43SThomas Chou 491*96fa1e43SThomas Chou static int altera_tse_ofdata_to_platdata(struct udevice *dev) 492*96fa1e43SThomas Chou { 493*96fa1e43SThomas Chou struct eth_pdata *pdata = dev_get_platdata(dev); 494*96fa1e43SThomas Chou const char *phy_mode; 495*96fa1e43SThomas Chou 496*96fa1e43SThomas Chou pdata->phy_interface = -1; 497*96fa1e43SThomas Chou phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); 498*96fa1e43SThomas Chou if (phy_mode) 499*96fa1e43SThomas Chou pdata->phy_interface = phy_get_interface_by_name(phy_mode); 500*96fa1e43SThomas Chou if (pdata->phy_interface == -1) { 501*96fa1e43SThomas Chou debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); 502*96fa1e43SThomas Chou return -EINVAL; 503*96fa1e43SThomas Chou } 504*96fa1e43SThomas Chou 505c960b13eSThomas Chou return 0; 506c960b13eSThomas Chou } 507b962ac79SJoachim Foerster 508*96fa1e43SThomas Chou static const struct eth_ops altera_tse_ops = { 509*96fa1e43SThomas Chou .start = altera_tse_start, 510*96fa1e43SThomas Chou .send = altera_tse_send, 511*96fa1e43SThomas Chou .recv = altera_tse_recv, 512*96fa1e43SThomas Chou .free_pkt = altera_tse_free_pkt, 513*96fa1e43SThomas Chou .stop = altera_tse_stop, 514*96fa1e43SThomas Chou .write_hwaddr = altera_tse_write_hwaddr, 515*96fa1e43SThomas Chou }; 516c960b13eSThomas Chou 517*96fa1e43SThomas Chou static const struct udevice_id altera_tse_ids[] = { 518*96fa1e43SThomas Chou { .compatible = "altr,tse-1.0", }, 519*96fa1e43SThomas Chou { } 520*96fa1e43SThomas Chou }; 521c960b13eSThomas Chou 522*96fa1e43SThomas Chou U_BOOT_DRIVER(altera_tse) = { 523*96fa1e43SThomas Chou .name = "altera_tse", 524*96fa1e43SThomas Chou .id = UCLASS_ETH, 525*96fa1e43SThomas Chou .of_match = altera_tse_ids, 526*96fa1e43SThomas Chou .ops = &altera_tse_ops, 527*96fa1e43SThomas Chou .ofdata_to_platdata = altera_tse_ofdata_to_platdata, 528*96fa1e43SThomas Chou .platdata_auto_alloc_size = sizeof(struct eth_pdata), 529*96fa1e43SThomas Chou .priv_auto_alloc_size = sizeof(struct altera_tse_priv), 530*96fa1e43SThomas Chou .probe = altera_tse_probe, 531*96fa1e43SThomas Chou }; 532