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 <config.h> 12c960b13eSThomas Chou #include <common.h> 13c960b13eSThomas Chou #include <malloc.h> 14c960b13eSThomas Chou #include <net.h> 15c960b13eSThomas Chou #include <command.h> 16c960b13eSThomas Chou #include <asm/cache.h> 17c960b13eSThomas Chou #include <asm/dma-mapping.h> 18c960b13eSThomas Chou #include <miiphy.h> 19c960b13eSThomas Chou #include "altera_tse.h" 20c960b13eSThomas Chou 21c960b13eSThomas Chou /* sgdma debug - print descriptor */ 22c960b13eSThomas Chou static void alt_sgdma_print_desc(volatile struct alt_sgdma_descriptor *desc) 23c960b13eSThomas Chou { 24c960b13eSThomas Chou debug("SGDMA DEBUG :\n"); 25c960b13eSThomas Chou debug("desc->source : 0x%x \n", (unsigned int)desc->source); 26c960b13eSThomas Chou debug("desc->destination : 0x%x \n", (unsigned int)desc->destination); 27c960b13eSThomas Chou debug("desc->next : 0x%x \n", (unsigned int)desc->next); 28c960b13eSThomas Chou debug("desc->source_pad : 0x%x \n", (unsigned int)desc->source_pad); 29c960b13eSThomas Chou debug("desc->destination_pad : 0x%x \n", 30c960b13eSThomas Chou (unsigned int)desc->destination_pad); 31c960b13eSThomas Chou debug("desc->next_pad : 0x%x \n", (unsigned int)desc->next_pad); 32c960b13eSThomas Chou debug("desc->bytes_to_transfer : 0x%x \n", 33c960b13eSThomas Chou (unsigned int)desc->bytes_to_transfer); 34c960b13eSThomas Chou debug("desc->actual_bytes_transferred : 0x%x \n", 35c960b13eSThomas Chou (unsigned int)desc->actual_bytes_transferred); 36c960b13eSThomas Chou debug("desc->descriptor_status : 0x%x \n", 37c960b13eSThomas Chou (unsigned int)desc->descriptor_status); 38c960b13eSThomas Chou debug("desc->descriptor_control : 0x%x \n", 39c960b13eSThomas Chou (unsigned int)desc->descriptor_control); 40c960b13eSThomas Chou } 41c960b13eSThomas Chou 42c960b13eSThomas Chou /* This is a generic routine that the SGDMA mode-specific routines 43c960b13eSThomas Chou * call to populate a descriptor. 44c960b13eSThomas Chou * arg1 :pointer to first SGDMA descriptor. 45c960b13eSThomas Chou * arg2 :pointer to next SGDMA descriptor. 46c960b13eSThomas Chou * arg3 :Address to where data to be written. 47c960b13eSThomas Chou * arg4 :Address from where data to be read. 48c960b13eSThomas Chou * arg5 :no of byte to transaction. 49c960b13eSThomas Chou * arg6 :variable indicating to generate start of packet or not 50c960b13eSThomas Chou * arg7 :read fixed 51c960b13eSThomas Chou * arg8 :write fixed 52c960b13eSThomas Chou * arg9 :read burst 53c960b13eSThomas Chou * arg10 :write burst 54c960b13eSThomas Chou * arg11 :atlantic_channel number 55c960b13eSThomas Chou */ 56c960b13eSThomas Chou static void alt_sgdma_construct_descriptor_burst( 57c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *desc, 58c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *next, 59c960b13eSThomas Chou unsigned int *read_addr, 60c960b13eSThomas Chou unsigned int *write_addr, 61c960b13eSThomas Chou unsigned short length_or_eop, 62c960b13eSThomas Chou int generate_eop, 63c960b13eSThomas Chou int read_fixed, 64c960b13eSThomas Chou int write_fixed_or_sop, 65c960b13eSThomas Chou int read_burst, 66c960b13eSThomas Chou int write_burst, 67c960b13eSThomas Chou unsigned char atlantic_channel) 68c960b13eSThomas Chou { 69c960b13eSThomas Chou /* 70c960b13eSThomas Chou * Mark the "next" descriptor as "not" owned by hardware. This prevents 71c960b13eSThomas Chou * The SGDMA controller from continuing to process the chain. This is 72c960b13eSThomas Chou * done as a single IO write to bypass cache, without flushing 73c960b13eSThomas Chou * the entire descriptor, since only the 8-bit descriptor status must 74c960b13eSThomas Chou * be flushed. 75c960b13eSThomas Chou */ 76c960b13eSThomas Chou if (!next) 77c960b13eSThomas Chou debug("Next descriptor not defined!!\n"); 78c960b13eSThomas Chou 79c960b13eSThomas Chou next->descriptor_control = (next->descriptor_control & 80c960b13eSThomas Chou ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK); 81c960b13eSThomas Chou 82c960b13eSThomas Chou desc->source = (unsigned int *)((unsigned int)read_addr & 0x1FFFFFFF); 83c960b13eSThomas Chou desc->destination = 84c960b13eSThomas Chou (unsigned int *)((unsigned int)write_addr & 0x1FFFFFFF); 85c960b13eSThomas Chou desc->next = (unsigned int *)((unsigned int)next & 0x1FFFFFFF); 86c960b13eSThomas Chou desc->source_pad = 0x0; 87c960b13eSThomas Chou desc->destination_pad = 0x0; 88c960b13eSThomas Chou desc->next_pad = 0x0; 89c960b13eSThomas Chou desc->bytes_to_transfer = length_or_eop; 90c960b13eSThomas Chou desc->actual_bytes_transferred = 0; 91c960b13eSThomas Chou desc->descriptor_status = 0x0; 92c960b13eSThomas Chou 93c960b13eSThomas Chou /* SGDMA burst not currently supported */ 94c960b13eSThomas Chou desc->read_burst = 0; 95c960b13eSThomas Chou desc->write_burst = 0; 96c960b13eSThomas Chou 97c960b13eSThomas Chou /* 98c960b13eSThomas Chou * Set the descriptor control block as follows: 99c960b13eSThomas Chou * - Set "owned by hardware" bit 100c960b13eSThomas Chou * - Optionally set "generate EOP" bit 101c960b13eSThomas Chou * - Optionally set the "read from fixed address" bit 102c960b13eSThomas Chou * - Optionally set the "write to fixed address bit (which serves 103c960b13eSThomas Chou * serves as a "generate SOP" control bit in memory-to-stream mode). 104c960b13eSThomas Chou * - Set the 4-bit atlantic channel, if specified 105c960b13eSThomas Chou * 106c960b13eSThomas Chou * Note this step is performed after all other descriptor information 107c960b13eSThomas Chou * has been filled out so that, if the controller already happens to be 108c960b13eSThomas Chou * pointing at this descriptor, it will not run (via the "owned by 109c960b13eSThomas Chou * hardware" bit) until all other descriptor has been set up. 110c960b13eSThomas Chou */ 111c960b13eSThomas Chou 112c960b13eSThomas Chou desc->descriptor_control = 113c960b13eSThomas Chou ((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) | 114c960b13eSThomas Chou (generate_eop ? 115c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) | 116c960b13eSThomas Chou (read_fixed ? 117c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) | 118c960b13eSThomas Chou (write_fixed_or_sop ? 119c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) | 120c960b13eSThomas Chou (atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0) 121c960b13eSThomas Chou ); 122c960b13eSThomas Chou } 123c960b13eSThomas Chou 124c960b13eSThomas Chou static int alt_sgdma_do_sync_transfer(volatile struct alt_sgdma_registers *dev, 125c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *desc) 126c960b13eSThomas Chou { 127c960b13eSThomas Chou unsigned int status; 128c960b13eSThomas Chou int counter = 0; 129c960b13eSThomas Chou 130c960b13eSThomas Chou /* Wait for any pending transfers to complete */ 131c960b13eSThomas Chou alt_sgdma_print_desc(desc); 132c960b13eSThomas Chou status = dev->status; 133c960b13eSThomas Chou 134c960b13eSThomas Chou counter = 0; 135c960b13eSThomas Chou while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) { 136c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 137c960b13eSThomas Chou break; 138c960b13eSThomas Chou } 139c960b13eSThomas Chou 140c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 141c960b13eSThomas Chou debug("Timeout waiting sgdma in do sync!\n"); 142c960b13eSThomas Chou 143c960b13eSThomas Chou /* 144c960b13eSThomas Chou * Clear any (previous) status register information 145c960b13eSThomas Chou * that might occlude our error checking later. 146c960b13eSThomas Chou */ 147c960b13eSThomas Chou dev->status = 0xFF; 148c960b13eSThomas Chou 149c960b13eSThomas Chou /* Point the controller at the descriptor */ 150c960b13eSThomas Chou dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF; 151c960b13eSThomas Chou debug("next desc in sgdma 0x%x\n", 152c960b13eSThomas Chou (unsigned int)dev->next_descriptor_pointer); 153c960b13eSThomas Chou 154c960b13eSThomas Chou /* 155c960b13eSThomas Chou * Set up SGDMA controller to: 156c960b13eSThomas Chou * - Disable interrupt generation 157c960b13eSThomas Chou * - Run once a valid descriptor is written to controller 158c960b13eSThomas Chou * - Stop on an error with any particular descriptor 159c960b13eSThomas Chou */ 160c960b13eSThomas Chou dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | 161c960b13eSThomas Chou ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); 162c960b13eSThomas Chou 163c960b13eSThomas Chou /* Wait for the descriptor (chain) to complete */ 164c960b13eSThomas Chou status = dev->status; 165c960b13eSThomas Chou debug("wait for sgdma...."); 166c960b13eSThomas Chou while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) 167c960b13eSThomas Chou ; 168c960b13eSThomas Chou debug("done\n"); 169c960b13eSThomas Chou 170c960b13eSThomas Chou /* Clear Run */ 171c960b13eSThomas Chou dev->control = (dev->control & (~ALT_SGDMA_CONTROL_RUN_MSK)); 172c960b13eSThomas Chou 173c960b13eSThomas Chou /* Get & clear status register contents */ 174c960b13eSThomas Chou status = dev->status; 175c960b13eSThomas Chou dev->status = 0xFF; 176c960b13eSThomas Chou 177c960b13eSThomas Chou /* we really should check if the transfer completes properly */ 178c960b13eSThomas Chou debug("tx sgdma status = 0x%x", status); 179c960b13eSThomas Chou return 0; 180c960b13eSThomas Chou } 181c960b13eSThomas Chou 182c960b13eSThomas Chou static int alt_sgdma_do_async_transfer(volatile struct alt_sgdma_registers *dev, 183c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *desc) 184c960b13eSThomas Chou { 185c960b13eSThomas Chou unsigned int status; 186c960b13eSThomas Chou int counter = 0; 187c960b13eSThomas Chou 188c960b13eSThomas Chou /* Wait for any pending transfers to complete */ 189c960b13eSThomas Chou alt_sgdma_print_desc(desc); 190c960b13eSThomas Chou status = dev->status; 191c960b13eSThomas Chou 192c960b13eSThomas Chou counter = 0; 193c960b13eSThomas Chou while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) { 194c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 195c960b13eSThomas Chou break; 196c960b13eSThomas Chou } 197c960b13eSThomas Chou 198c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 199c960b13eSThomas Chou debug("Timeout waiting sgdma in do async!\n"); 200c960b13eSThomas Chou 201c960b13eSThomas Chou /* 202c960b13eSThomas Chou * Clear any (previous) status register information 203c960b13eSThomas Chou * that might occlude our error checking later. 204c960b13eSThomas Chou */ 205c960b13eSThomas Chou dev->status = 0xFF; 206c960b13eSThomas Chou 207c960b13eSThomas Chou /* Point the controller at the descriptor */ 208c960b13eSThomas Chou dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF; 209c960b13eSThomas Chou 210c960b13eSThomas Chou /* 211c960b13eSThomas Chou * Set up SGDMA controller to: 212c960b13eSThomas Chou * - Disable interrupt generation 213c960b13eSThomas Chou * - Run once a valid descriptor is written to controller 214c960b13eSThomas Chou * - Stop on an error with any particular descriptor 215c960b13eSThomas Chou */ 216c960b13eSThomas Chou dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | 217c960b13eSThomas Chou ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); 218c960b13eSThomas Chou 219c960b13eSThomas Chou /* we really should check if the transfer completes properly */ 220c960b13eSThomas Chou return 0; 221c960b13eSThomas Chou } 222c960b13eSThomas Chou 223c960b13eSThomas Chou /* u-boot interface */ 224c960b13eSThomas Chou static int tse_adjust_link(struct altera_tse_priv *priv) 225c960b13eSThomas Chou { 226c960b13eSThomas Chou unsigned int refvar; 227c960b13eSThomas Chou 228c960b13eSThomas Chou refvar = priv->mac_dev->command_config.image; 229c960b13eSThomas Chou 230c960b13eSThomas Chou if (!(priv->duplexity)) 231c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; 232c960b13eSThomas Chou else 233c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK; 234c960b13eSThomas Chou 235c960b13eSThomas Chou switch (priv->speed) { 236c960b13eSThomas Chou case 1000: 237c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; 238c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 239c960b13eSThomas Chou break; 240c960b13eSThomas Chou case 100: 241c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 242c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 243c960b13eSThomas Chou break; 244c960b13eSThomas Chou case 10: 245c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 246c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ENA_10_MSK; 247c960b13eSThomas Chou break; 248c960b13eSThomas Chou } 249c960b13eSThomas Chou priv->mac_dev->command_config.image = refvar; 250c960b13eSThomas Chou 251c960b13eSThomas Chou return 0; 252c960b13eSThomas Chou } 253c960b13eSThomas Chou 254c960b13eSThomas Chou static int tse_eth_send(struct eth_device *dev, 255c960b13eSThomas Chou volatile void *packet, int length) 256c960b13eSThomas Chou { 257c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 258c960b13eSThomas Chou volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 259c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc = 260c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)priv->tx_desc; 261c960b13eSThomas Chou 262c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc_cur = 263c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0]; 264c960b13eSThomas Chou 265c960b13eSThomas Chou flush_dcache((unsigned long)packet, length); 266c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 267c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0], 268c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[1], 269c960b13eSThomas Chou (unsigned int *)packet, /* read addr */ 270c960b13eSThomas Chou (unsigned int *)0, 271c960b13eSThomas Chou length, /* length or EOP ,will change for each tx */ 272c960b13eSThomas Chou 0x1, /* gen eop */ 273c960b13eSThomas Chou 0x0, /* read fixed */ 274c960b13eSThomas Chou 0x1, /* write fixed or sop */ 275c960b13eSThomas Chou 0x0, /* read burst */ 276c960b13eSThomas Chou 0x0, /* write burst */ 277c960b13eSThomas Chou 0x0 /* channel */ 278c960b13eSThomas Chou ); 279c960b13eSThomas Chou debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length); 280c960b13eSThomas Chou 281c960b13eSThomas Chou /* send the packet */ 282c960b13eSThomas Chou debug("sending packet\n"); 283c960b13eSThomas Chou alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur); 284c960b13eSThomas Chou debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred); 285c960b13eSThomas Chou return tx_desc_cur->actual_bytes_transferred; 286c960b13eSThomas Chou } 287c960b13eSThomas Chou 288c960b13eSThomas Chou static int tse_eth_rx(struct eth_device *dev) 289c960b13eSThomas Chou { 290c960b13eSThomas Chou int packet_length = 0; 291c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 292c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = 293c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)priv->rx_desc; 294c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0]; 295c960b13eSThomas Chou 296c960b13eSThomas Chou if (rx_desc_cur->descriptor_status & 297c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { 298c960b13eSThomas Chou debug("got packet\n"); 299c960b13eSThomas Chou packet_length = rx_desc->actual_bytes_transferred; 300c960b13eSThomas Chou NetReceive(NetRxPackets[0], packet_length); 301c960b13eSThomas Chou 302c960b13eSThomas Chou /* start descriptor again */ 303c960b13eSThomas Chou flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); 304c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 305c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0], 306c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[1], 307c960b13eSThomas Chou (unsigned int)0x0, /* read addr */ 308c960b13eSThomas Chou (unsigned int *)NetRxPackets[0], 309c960b13eSThomas Chou 0x0, /* length or EOP */ 310c960b13eSThomas Chou 0x0, /* gen eop */ 311c960b13eSThomas Chou 0x0, /* read fixed */ 312c960b13eSThomas Chou 0x0, /* write fixed or sop */ 313c960b13eSThomas Chou 0x0, /* read burst */ 314c960b13eSThomas Chou 0x0, /* write burst */ 315c960b13eSThomas Chou 0x0 /* channel */ 316c960b13eSThomas Chou ); 317c960b13eSThomas Chou 318c960b13eSThomas Chou /* setup the sgdma */ 319c960b13eSThomas Chou alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]); 320c960b13eSThomas Chou } 321c960b13eSThomas Chou 322c960b13eSThomas Chou return -1; 323c960b13eSThomas Chou } 324c960b13eSThomas Chou 325c960b13eSThomas Chou static void tse_eth_halt(struct eth_device *dev) 326c960b13eSThomas Chou { 327c960b13eSThomas Chou /* don't do anything! */ 328c960b13eSThomas Chou /* this gets called after each uboot */ 329c960b13eSThomas Chou /* network command. don't need to reset the thing all of the time */ 330c960b13eSThomas Chou } 331c960b13eSThomas Chou 332c960b13eSThomas Chou static void tse_eth_reset(struct eth_device *dev) 333c960b13eSThomas Chou { 334c960b13eSThomas Chou /* stop sgdmas, disable tse receive */ 335c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 336c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 337c960b13eSThomas Chou volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; 338c960b13eSThomas Chou volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 339c960b13eSThomas Chou int counter; 340c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = 341c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0]; 342c960b13eSThomas Chou 343c960b13eSThomas Chou /* clear rx desc & wait for sgdma to complete */ 344c960b13eSThomas Chou rx_desc->descriptor_control = 0; 345c960b13eSThomas Chou rx_sgdma->control = 0; 346c960b13eSThomas Chou counter = 0; 347c960b13eSThomas Chou while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 348c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 349c960b13eSThomas Chou break; 350c960b13eSThomas Chou } 351c960b13eSThomas Chou 352c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 353c960b13eSThomas Chou debug("Timeout waiting for rx sgdma!\n"); 354c960b13eSThomas Chou rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 355c960b13eSThomas Chou rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 356c960b13eSThomas Chou } 357c960b13eSThomas Chou 358c960b13eSThomas Chou counter = 0; 359c960b13eSThomas Chou tx_sgdma->control = 0; 360c960b13eSThomas Chou while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 361c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 362c960b13eSThomas Chou break; 363c960b13eSThomas Chou } 364c960b13eSThomas Chou 365c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 366c960b13eSThomas Chou debug("Timeout waiting for tx sgdma!\n"); 367c960b13eSThomas Chou tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 368c960b13eSThomas Chou tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 369c960b13eSThomas Chou } 370c960b13eSThomas Chou /* reset the mac */ 371c960b13eSThomas Chou mac_dev->command_config.bits.transmit_enable = 1; 372c960b13eSThomas Chou mac_dev->command_config.bits.receive_enable = 1; 373c960b13eSThomas Chou mac_dev->command_config.bits.software_reset = 1; 374c960b13eSThomas Chou 375c960b13eSThomas Chou counter = 0; 376c960b13eSThomas Chou while (mac_dev->command_config.bits.software_reset) { 377c960b13eSThomas Chou if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR) 378c960b13eSThomas Chou break; 379c960b13eSThomas Chou } 380c960b13eSThomas Chou 381c960b13eSThomas Chou if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR) 382c960b13eSThomas Chou debug("TSEMAC SW reset bit never cleared!\n"); 383c960b13eSThomas Chou } 384c960b13eSThomas Chou 385c960b13eSThomas Chou static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) 386c960b13eSThomas Chou { 387c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 388c960b13eSThomas Chou unsigned int *mdio_regs; 389c960b13eSThomas Chou unsigned int data; 390c960b13eSThomas Chou u16 value; 391c960b13eSThomas Chou 392c960b13eSThomas Chou mac_dev = priv->mac_dev; 393c960b13eSThomas Chou 394c960b13eSThomas Chou /* set mdio address */ 395c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 396c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 397c960b13eSThomas Chou 398c960b13eSThomas Chou /* get the data */ 399c960b13eSThomas Chou data = mdio_regs[regnum]; 400c960b13eSThomas Chou 401c960b13eSThomas Chou value = data & 0xffff; 402c960b13eSThomas Chou 403c960b13eSThomas Chou return value; 404c960b13eSThomas Chou } 405c960b13eSThomas Chou 406c960b13eSThomas Chou static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, 407c960b13eSThomas Chou unsigned int value) 408c960b13eSThomas Chou { 409c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 410c960b13eSThomas Chou unsigned int *mdio_regs; 411c960b13eSThomas Chou unsigned int data; 412c960b13eSThomas Chou 413c960b13eSThomas Chou mac_dev = priv->mac_dev; 414c960b13eSThomas Chou 415c960b13eSThomas Chou /* set mdio address */ 416c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 417c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 418c960b13eSThomas Chou 419c960b13eSThomas Chou /* get the data */ 420c960b13eSThomas Chou data = (unsigned int)value; 421c960b13eSThomas Chou 422c960b13eSThomas Chou mdio_regs[regnum] = data; 423c960b13eSThomas Chou 424c960b13eSThomas Chou return 0; 425c960b13eSThomas Chou } 426c960b13eSThomas Chou 427c960b13eSThomas Chou /* MDIO access to phy */ 428c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 429*5700bb63SMike Frysinger static int altera_tse_miiphy_write(const char *devname, unsigned char addr, 430c960b13eSThomas Chou unsigned char reg, unsigned short value) 431c960b13eSThomas Chou { 432c960b13eSThomas Chou struct eth_device *dev; 433c960b13eSThomas Chou struct altera_tse_priv *priv; 434c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 435c960b13eSThomas Chou priv = dev->priv; 436c960b13eSThomas Chou 437c960b13eSThomas Chou tse_mdio_write(priv, (uint) reg, (uint) value); 438c960b13eSThomas Chou 439c960b13eSThomas Chou return 0; 440c960b13eSThomas Chou } 441c960b13eSThomas Chou 442*5700bb63SMike Frysinger static int altera_tse_miiphy_read(const char *devname, unsigned char addr, 443c960b13eSThomas Chou unsigned char reg, unsigned short *value) 444c960b13eSThomas Chou { 445c960b13eSThomas Chou struct eth_device *dev; 446c960b13eSThomas Chou struct altera_tse_priv *priv; 447c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 448c960b13eSThomas Chou unsigned int *mdio_regs; 449c960b13eSThomas Chou 450c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 451c960b13eSThomas Chou priv = dev->priv; 452c960b13eSThomas Chou 453c960b13eSThomas Chou mac_dev = priv->mac_dev; 454c960b13eSThomas Chou mac_dev->mdio_phy1_addr = (int)addr; 455c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 456c960b13eSThomas Chou 457c960b13eSThomas Chou *value = 0xffff & mdio_regs[reg]; 458c960b13eSThomas Chou 459c960b13eSThomas Chou return 0; 460c960b13eSThomas Chou 461c960b13eSThomas Chou } 462c960b13eSThomas Chou #endif 463c960b13eSThomas Chou 464c960b13eSThomas Chou /* 465c960b13eSThomas Chou * Also copied from tsec.c 466c960b13eSThomas Chou */ 467c960b13eSThomas Chou /* Parse the status register for link, and then do 468c960b13eSThomas Chou * auto-negotiation 469c960b13eSThomas Chou */ 470c960b13eSThomas Chou static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv) 471c960b13eSThomas Chou { 472c960b13eSThomas Chou /* 473c960b13eSThomas Chou * Wait if the link is up, and autonegotiation is in progress 474c960b13eSThomas Chou * (ie - we're capable and it's not done) 475c960b13eSThomas Chou */ 476c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 477c960b13eSThomas Chou 478c960b13eSThomas Chou if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & PHY_BMSR_AUTN_ABLE) 479c960b13eSThomas Chou && !(mii_reg & PHY_BMSR_AUTN_COMP)) { 480c960b13eSThomas Chou int i = 0; 481c960b13eSThomas Chou 482c960b13eSThomas Chou puts("Waiting for PHY auto negotiation to complete"); 483c960b13eSThomas Chou while (!(mii_reg & PHY_BMSR_AUTN_COMP)) { 484c960b13eSThomas Chou /* 485c960b13eSThomas Chou * Timeout reached ? 486c960b13eSThomas Chou */ 487c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 488c960b13eSThomas Chou puts(" TIMEOUT !\n"); 489c960b13eSThomas Chou priv->link = 0; 490c960b13eSThomas Chou return 0; 491c960b13eSThomas Chou } 492c960b13eSThomas Chou 493c960b13eSThomas Chou if ((i++ % 1000) == 0) 494c960b13eSThomas Chou putc('.'); 495c960b13eSThomas Chou udelay(1000); /* 1 ms */ 496c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 497c960b13eSThomas Chou } 498c960b13eSThomas Chou puts(" done\n"); 499c960b13eSThomas Chou priv->link = 1; 500c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 501c960b13eSThomas Chou } else { 502c960b13eSThomas Chou if (mii_reg & MIIM_STATUS_LINK) { 503c960b13eSThomas Chou debug("Link is up\n"); 504c960b13eSThomas Chou priv->link = 1; 505c960b13eSThomas Chou } else { 506c960b13eSThomas Chou debug("Link is down\n"); 507c960b13eSThomas Chou priv->link = 0; 508c960b13eSThomas Chou } 509c960b13eSThomas Chou } 510c960b13eSThomas Chou 511c960b13eSThomas Chou return 0; 512c960b13eSThomas Chou } 513c960b13eSThomas Chou 514c960b13eSThomas Chou /* Parse the 88E1011's status register for speed and duplex 515c960b13eSThomas Chou * information 516c960b13eSThomas Chou */ 517c960b13eSThomas Chou static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv) 518c960b13eSThomas Chou { 519c960b13eSThomas Chou uint speed; 520c960b13eSThomas Chou 521c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 522c960b13eSThomas Chou 523c960b13eSThomas Chou if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && 524c960b13eSThomas Chou !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 525c960b13eSThomas Chou int i = 0; 526c960b13eSThomas Chou 527c960b13eSThomas Chou puts("Waiting for PHY realtime link"); 528c960b13eSThomas Chou while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 529c960b13eSThomas Chou /* Timeout reached ? */ 530c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 531c960b13eSThomas Chou puts(" TIMEOUT !\n"); 532c960b13eSThomas Chou priv->link = 0; 533c960b13eSThomas Chou break; 534c960b13eSThomas Chou } 535c960b13eSThomas Chou 536c960b13eSThomas Chou if ((i++ == 1000) == 0) { 537c960b13eSThomas Chou i = 0; 538c960b13eSThomas Chou puts("."); 539c960b13eSThomas Chou } 540c960b13eSThomas Chou udelay(1000); /* 1 ms */ 541c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 542c960b13eSThomas Chou } 543c960b13eSThomas Chou puts(" done\n"); 544c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 545c960b13eSThomas Chou } else { 546c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) 547c960b13eSThomas Chou priv->link = 1; 548c960b13eSThomas Chou else 549c960b13eSThomas Chou priv->link = 0; 550c960b13eSThomas Chou } 551c960b13eSThomas Chou 552c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) 553c960b13eSThomas Chou priv->duplexity = 1; 554c960b13eSThomas Chou else 555c960b13eSThomas Chou priv->duplexity = 0; 556c960b13eSThomas Chou 557c960b13eSThomas Chou speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); 558c960b13eSThomas Chou 559c960b13eSThomas Chou switch (speed) { 560c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_GBIT: 561c960b13eSThomas Chou priv->speed = 1000; 562c960b13eSThomas Chou debug("PHY Speed is 1000Mbit\n"); 563c960b13eSThomas Chou break; 564c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_100: 565c960b13eSThomas Chou debug("PHY Speed is 100Mbit\n"); 566c960b13eSThomas Chou priv->speed = 100; 567c960b13eSThomas Chou break; 568c960b13eSThomas Chou default: 569c960b13eSThomas Chou debug("PHY Speed is 10Mbit\n"); 570c960b13eSThomas Chou priv->speed = 10; 571c960b13eSThomas Chou } 572c960b13eSThomas Chou 573c960b13eSThomas Chou return 0; 574c960b13eSThomas Chou } 575c960b13eSThomas Chou 576c960b13eSThomas Chou static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv) 577c960b13eSThomas Chou { 578c960b13eSThomas Chou uint mii_data = tse_mdio_read(priv, mii_reg); 579c960b13eSThomas Chou mii_data &= 0xfff0; 580c960b13eSThomas Chou mii_data |= 0xb; 581c960b13eSThomas Chou return mii_data; 582c960b13eSThomas Chou } 583c960b13eSThomas Chou 584c960b13eSThomas Chou static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv) 585c960b13eSThomas Chou { 586c960b13eSThomas Chou uint mii_data = tse_mdio_read(priv, mii_reg); 587c960b13eSThomas Chou mii_data &= ~0x82; 588c960b13eSThomas Chou mii_data |= 0x82; 589c960b13eSThomas Chou return mii_data; 590c960b13eSThomas Chou } 591c960b13eSThomas Chou 592c960b13eSThomas Chou /* 593c960b13eSThomas Chou * Returns which value to write to the control register. 594c960b13eSThomas Chou * For 10/100, the value is slightly different 595c960b13eSThomas Chou */ 596c960b13eSThomas Chou static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv) 597c960b13eSThomas Chou { 598c960b13eSThomas Chou return MIIM_CONTROL_INIT; 599c960b13eSThomas Chou } 600c960b13eSThomas Chou 601c960b13eSThomas Chou /* 602c960b13eSThomas Chou * PHY & MDIO code 603c960b13eSThomas Chou * Need to add SGMII stuff 604c960b13eSThomas Chou * 605c960b13eSThomas Chou */ 606c960b13eSThomas Chou 607c960b13eSThomas Chou static struct phy_info phy_info_M88E1111S = { 608c960b13eSThomas Chou 0x01410cc, 609c960b13eSThomas Chou "Marvell 88E1111S", 610c960b13eSThomas Chou 4, 611c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 612c960b13eSThomas Chou /* Reset and configure the PHY */ 613c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 614c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_SR, 0x848f, 615c960b13eSThomas Chou &mii_m88e1111s_setmode_sr}, 616c960b13eSThomas Chou /* Delay RGMII TX and RX */ 617c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_CR, 0x0cd2, 618c960b13eSThomas Chou &mii_m88e1111s_setmode_cr}, 619c960b13eSThomas Chou {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, 620c960b13eSThomas Chou {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, 621c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 622c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, 623c960b13eSThomas Chou {miim_end,} 624c960b13eSThomas Chou }, 625c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 626c960b13eSThomas Chou /* Status is read once to clear old link state */ 627c960b13eSThomas Chou {MIIM_STATUS, miim_read, NULL}, 628c960b13eSThomas Chou /* Auto-negotiate */ 629c960b13eSThomas Chou {MIIM_STATUS, miim_read, &mii_parse_sr}, 630c960b13eSThomas Chou /* Read the status */ 631c960b13eSThomas Chou {MIIM_88E1011_PHY_STATUS, miim_read, 632c960b13eSThomas Chou &mii_parse_88E1011_psr}, 633c960b13eSThomas Chou {miim_end,} 634c960b13eSThomas Chou }, 635c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 636c960b13eSThomas Chou {miim_end,} 637c960b13eSThomas Chou }, 638c960b13eSThomas Chou }; 639c960b13eSThomas Chou 640c960b13eSThomas Chou /* a generic flavor. */ 641c960b13eSThomas Chou static struct phy_info phy_info_generic = { 642c960b13eSThomas Chou 0, 643c960b13eSThomas Chou "Unknown/Generic PHY", 644c960b13eSThomas Chou 32, 645c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 646c960b13eSThomas Chou {PHY_BMCR, PHY_BMCR_RESET, NULL}, 647c960b13eSThomas Chou {PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG, NULL}, 648c960b13eSThomas Chou {miim_end,} 649c960b13eSThomas Chou }, 650c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 651c960b13eSThomas Chou {PHY_BMSR, miim_read, NULL}, 652c960b13eSThomas Chou {PHY_BMSR, miim_read, &mii_parse_sr}, 653c960b13eSThomas Chou {miim_end,} 654c960b13eSThomas Chou }, 655c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 656c960b13eSThomas Chou {miim_end,} 657c960b13eSThomas Chou } 658c960b13eSThomas Chou }; 659c960b13eSThomas Chou 660c960b13eSThomas Chou static struct phy_info *phy_info[] = { 661c960b13eSThomas Chou &phy_info_M88E1111S, 662c960b13eSThomas Chou NULL 663c960b13eSThomas Chou }; 664c960b13eSThomas Chou 665c960b13eSThomas Chou /* Grab the identifier of the device's PHY, and search through 666c960b13eSThomas Chou * all of the known PHYs to see if one matches. If so, return 667c960b13eSThomas Chou * it, if not, return NULL 668c960b13eSThomas Chou */ 669c960b13eSThomas Chou static struct phy_info *get_phy_info(struct eth_device *dev) 670c960b13eSThomas Chou { 671c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 672c960b13eSThomas Chou uint phy_reg, phy_ID; 673c960b13eSThomas Chou int i; 674c960b13eSThomas Chou struct phy_info *theInfo = NULL; 675c960b13eSThomas Chou 676c960b13eSThomas Chou /* Grab the bits from PHYIR1, and put them in the upper half */ 677c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR1); 678c960b13eSThomas Chou phy_ID = (phy_reg & 0xffff) << 16; 679c960b13eSThomas Chou 680c960b13eSThomas Chou /* Grab the bits from PHYIR2, and put them in the lower half */ 681c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR2); 682c960b13eSThomas Chou phy_ID |= (phy_reg & 0xffff); 683c960b13eSThomas Chou 684c960b13eSThomas Chou /* loop through all the known PHY types, and find one that */ 685c960b13eSThomas Chou /* matches the ID we read from the PHY. */ 686c960b13eSThomas Chou for (i = 0; phy_info[i]; i++) { 687c960b13eSThomas Chou if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { 688c960b13eSThomas Chou theInfo = phy_info[i]; 689c960b13eSThomas Chou break; 690c960b13eSThomas Chou } 691c960b13eSThomas Chou } 692c960b13eSThomas Chou 693c960b13eSThomas Chou if (theInfo == NULL) { 694c960b13eSThomas Chou theInfo = &phy_info_generic; 695c960b13eSThomas Chou debug("%s: No support for PHY id %x; assuming generic\n", 696c960b13eSThomas Chou dev->name, phy_ID); 697c960b13eSThomas Chou } else 698c960b13eSThomas Chou debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); 699c960b13eSThomas Chou 700c960b13eSThomas Chou return theInfo; 701c960b13eSThomas Chou } 702c960b13eSThomas Chou 703c960b13eSThomas Chou /* Execute the given series of commands on the given device's 704c960b13eSThomas Chou * PHY, running functions as necessary 705c960b13eSThomas Chou */ 706c960b13eSThomas Chou static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd) 707c960b13eSThomas Chou { 708c960b13eSThomas Chou int i; 709c960b13eSThomas Chou uint result; 710c960b13eSThomas Chou 711c960b13eSThomas Chou for (i = 0; cmd->mii_reg != miim_end; i++) { 712c960b13eSThomas Chou if (cmd->mii_data == miim_read) { 713c960b13eSThomas Chou result = tse_mdio_read(priv, cmd->mii_reg); 714c960b13eSThomas Chou 715c960b13eSThomas Chou if (cmd->funct != NULL) 716c960b13eSThomas Chou (*(cmd->funct)) (result, priv); 717c960b13eSThomas Chou 718c960b13eSThomas Chou } else { 719c960b13eSThomas Chou if (cmd->funct != NULL) 720c960b13eSThomas Chou result = (*(cmd->funct)) (cmd->mii_reg, priv); 721c960b13eSThomas Chou else 722c960b13eSThomas Chou result = cmd->mii_data; 723c960b13eSThomas Chou 724c960b13eSThomas Chou tse_mdio_write(priv, cmd->mii_reg, result); 725c960b13eSThomas Chou 726c960b13eSThomas Chou } 727c960b13eSThomas Chou cmd++; 728c960b13eSThomas Chou } 729c960b13eSThomas Chou } 730c960b13eSThomas Chou 731c960b13eSThomas Chou /* Phy init code */ 732c960b13eSThomas Chou static int init_phy(struct eth_device *dev) 733c960b13eSThomas Chou { 734c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 735c960b13eSThomas Chou struct phy_info *curphy; 736c960b13eSThomas Chou 737c960b13eSThomas Chou /* Get the cmd structure corresponding to the attached 738c960b13eSThomas Chou * PHY */ 739c960b13eSThomas Chou curphy = get_phy_info(dev); 740c960b13eSThomas Chou 741c960b13eSThomas Chou if (curphy == NULL) { 742c960b13eSThomas Chou priv->phyinfo = NULL; 743c960b13eSThomas Chou debug("%s: No PHY found\n", dev->name); 744c960b13eSThomas Chou 745c960b13eSThomas Chou return 0; 746c960b13eSThomas Chou } else 747c960b13eSThomas Chou debug("%s found\n", curphy->name); 748c960b13eSThomas Chou priv->phyinfo = curphy; 749c960b13eSThomas Chou 750c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->config); 751c960b13eSThomas Chou 752c960b13eSThomas Chou return 1; 753c960b13eSThomas Chou } 754c960b13eSThomas Chou 7556c7c4447SThomas Chou static int tse_set_mac_address(struct eth_device *dev) 7566c7c4447SThomas Chou { 7576c7c4447SThomas Chou struct altera_tse_priv *priv = dev->priv; 7586c7c4447SThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 7596c7c4447SThomas Chou 7606c7c4447SThomas Chou debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\n", 7616c7c4447SThomas Chou dev->enetaddr[5], dev->enetaddr[4], 7626c7c4447SThomas Chou dev->enetaddr[3], dev->enetaddr[2], 7636c7c4447SThomas Chou dev->enetaddr[1], dev->enetaddr[0]); 7646c7c4447SThomas Chou mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 | 7656c7c4447SThomas Chou (dev->enetaddr[2]) << 16 | 7666c7c4447SThomas Chou (dev->enetaddr[1]) << 8 | (dev->enetaddr[0])); 7676c7c4447SThomas Chou 7686c7c4447SThomas Chou mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 | 7696c7c4447SThomas Chou (dev->enetaddr[4])) & 0xFFFF); 7706c7c4447SThomas Chou 7716c7c4447SThomas Chou /* Set the MAC address */ 7726c7c4447SThomas Chou mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0; 7736c7c4447SThomas Chou mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1; 7746c7c4447SThomas Chou 7756c7c4447SThomas Chou /* Set the MAC address */ 7766c7c4447SThomas Chou mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0; 7776c7c4447SThomas Chou mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1; 7786c7c4447SThomas Chou 7796c7c4447SThomas Chou /* Set the MAC address */ 7806c7c4447SThomas Chou mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0; 7816c7c4447SThomas Chou mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1; 7826c7c4447SThomas Chou 7836c7c4447SThomas Chou /* Set the MAC address */ 7846c7c4447SThomas Chou mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0; 7856c7c4447SThomas Chou mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1; 7866c7c4447SThomas Chou return 0; 7876c7c4447SThomas Chou } 7886c7c4447SThomas Chou 789c960b13eSThomas Chou static int tse_eth_init(struct eth_device *dev, bd_t * bd) 790c960b13eSThomas Chou { 791c960b13eSThomas Chou int dat; 792c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 793c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 794c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; 795c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 796c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc_cur = 797c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0]; 798c960b13eSThomas Chou 799c960b13eSThomas Chou /* stop controller */ 800c960b13eSThomas Chou debug("Reseting TSE & SGDMAs\n"); 801c960b13eSThomas Chou tse_eth_reset(dev); 802c960b13eSThomas Chou 803c960b13eSThomas Chou /* start the phy */ 804c960b13eSThomas Chou debug("Configuring PHY\n"); 805c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->startup); 806c960b13eSThomas Chou 807c960b13eSThomas Chou /* need to create sgdma */ 808c960b13eSThomas Chou debug("Configuring tx desc\n"); 809c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 810c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0], 811c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[1], 812c960b13eSThomas Chou (unsigned int *)NULL, /* read addr */ 813c960b13eSThomas Chou (unsigned int *)0, 814c960b13eSThomas Chou 0, /* length or EOP ,will change for each tx */ 815c960b13eSThomas Chou 0x1, /* gen eop */ 816c960b13eSThomas Chou 0x0, /* read fixed */ 817c960b13eSThomas Chou 0x1, /* write fixed or sop */ 818c960b13eSThomas Chou 0x0, /* read burst */ 819c960b13eSThomas Chou 0x0, /* write burst */ 820c960b13eSThomas Chou 0x0 /* channel */ 821c960b13eSThomas Chou ); 822c960b13eSThomas Chou debug("Configuring rx desc\n"); 823c960b13eSThomas Chou flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); 824c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 825c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0], 826c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[1], 827c960b13eSThomas Chou (unsigned int)0x0, /* read addr */ 828c960b13eSThomas Chou (unsigned int *)NetRxPackets[0], 829c960b13eSThomas Chou 0x0, /* length or EOP */ 830c960b13eSThomas Chou 0x0, /* gen eop */ 831c960b13eSThomas Chou 0x0, /* read fixed */ 832c960b13eSThomas Chou 0x0, /* write fixed or sop */ 833c960b13eSThomas Chou 0x0, /* read burst */ 834c960b13eSThomas Chou 0x0, /* write burst */ 835c960b13eSThomas Chou 0x0 /* channel */ 836c960b13eSThomas Chou ); 837c960b13eSThomas Chou /* start rx async transfer */ 838c960b13eSThomas Chou debug("Starting rx sgdma\n"); 839c960b13eSThomas Chou alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur); 840c960b13eSThomas Chou 841c960b13eSThomas Chou /* start TSE */ 842c960b13eSThomas Chou debug("Configuring TSE Mac\n"); 843c960b13eSThomas Chou /* Initialize MAC registers */ 844c960b13eSThomas Chou mac_dev->max_frame_length = PKTSIZE_ALIGN; 845c960b13eSThomas Chou mac_dev->rx_almost_empty_threshold = 8; 846c960b13eSThomas Chou mac_dev->rx_almost_full_threshold = 8; 847c960b13eSThomas Chou mac_dev->tx_almost_empty_threshold = 8; 848c960b13eSThomas Chou mac_dev->tx_almost_full_threshold = 3; 849c960b13eSThomas Chou mac_dev->tx_sel_empty_threshold = 850c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 851c960b13eSThomas Chou mac_dev->tx_sel_full_threshold = 0; 852c960b13eSThomas Chou mac_dev->rx_sel_empty_threshold = 853c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 854c960b13eSThomas Chou mac_dev->rx_sel_full_threshold = 0; 855c960b13eSThomas Chou 856c960b13eSThomas Chou /* NO Shift */ 857c960b13eSThomas Chou mac_dev->rx_cmd_stat.bits.rx_shift16 = 0; 858c960b13eSThomas Chou mac_dev->tx_cmd_stat.bits.tx_shift16 = 0; 859c960b13eSThomas Chou 860c960b13eSThomas Chou /* enable MAC */ 861c960b13eSThomas Chou dat = 0; 862c960b13eSThomas Chou dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; 863c960b13eSThomas Chou 864c960b13eSThomas Chou mac_dev->command_config.image = dat; 865c960b13eSThomas Chou 866c960b13eSThomas Chou /* configure the TSE core */ 867c960b13eSThomas Chou /* -- output clocks, */ 868c960b13eSThomas Chou /* -- and later config stuff for SGMII */ 869c960b13eSThomas Chou if (priv->link) { 870c960b13eSThomas Chou debug("Adjusting TSE to link speed\n"); 871c960b13eSThomas Chou tse_adjust_link(priv); 872c960b13eSThomas Chou } 873c960b13eSThomas Chou 874c960b13eSThomas Chou return priv->link ? 0 : -1; 875c960b13eSThomas Chou } 876c960b13eSThomas Chou 877c960b13eSThomas Chou /* TSE init code */ 878c960b13eSThomas Chou int altera_tse_initialize(u8 dev_num, int mac_base, 879c960b13eSThomas Chou int sgdma_rx_base, int sgdma_tx_base) 880c960b13eSThomas Chou { 881c960b13eSThomas Chou struct altera_tse_priv *priv; 882c960b13eSThomas Chou struct eth_device *dev; 883c960b13eSThomas Chou struct alt_sgdma_descriptor *rx_desc; 884c960b13eSThomas Chou struct alt_sgdma_descriptor *tx_desc; 885c960b13eSThomas Chou unsigned long dma_handle; 886c960b13eSThomas Chou 887c960b13eSThomas Chou dev = (struct eth_device *)malloc(sizeof *dev); 888c960b13eSThomas Chou 889c960b13eSThomas Chou if (NULL == dev) 890c960b13eSThomas Chou return 0; 891c960b13eSThomas Chou 892c960b13eSThomas Chou memset(dev, 0, sizeof *dev); 893c960b13eSThomas Chou 894c960b13eSThomas Chou priv = malloc(sizeof(*priv)); 895c960b13eSThomas Chou 896c960b13eSThomas Chou if (!priv) { 897c960b13eSThomas Chou free(dev); 898c960b13eSThomas Chou return 0; 899c960b13eSThomas Chou } 900c960b13eSThomas Chou tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), 901c960b13eSThomas Chou &dma_handle); 902c960b13eSThomas Chou rx_desc = tx_desc + 2; 903c960b13eSThomas Chou debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc); 904c960b13eSThomas Chou debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc); 905c960b13eSThomas Chou 906c960b13eSThomas Chou if (!tx_desc) { 907c960b13eSThomas Chou free(priv); 908c960b13eSThomas Chou free(dev); 909c960b13eSThomas Chou return 0; 910c960b13eSThomas Chou } 911c960b13eSThomas Chou memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1)); 912c960b13eSThomas Chou memset(tx_desc, 0, (sizeof *tx_desc) * 2); 913c960b13eSThomas Chou 914c960b13eSThomas Chou /* initialize tse priv */ 915c960b13eSThomas Chou priv->mac_dev = (volatile struct alt_tse_mac *)mac_base; 916c960b13eSThomas Chou priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base; 917c960b13eSThomas Chou priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base; 918c960b13eSThomas Chou priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR; 919c960b13eSThomas Chou priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS; 920c960b13eSThomas Chou priv->rx_desc = rx_desc; 921c960b13eSThomas Chou priv->tx_desc = tx_desc; 922c960b13eSThomas Chou 923c960b13eSThomas Chou /* init eth structure */ 924c960b13eSThomas Chou dev->priv = priv; 925c960b13eSThomas Chou dev->init = tse_eth_init; 926c960b13eSThomas Chou dev->halt = tse_eth_halt; 927c960b13eSThomas Chou dev->send = tse_eth_send; 928c960b13eSThomas Chou dev->recv = tse_eth_rx; 9296c7c4447SThomas Chou dev->write_hwaddr = tse_set_mac_address; 930c960b13eSThomas Chou sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num); 931c960b13eSThomas Chou 932c960b13eSThomas Chou eth_register(dev); 933c960b13eSThomas Chou 934c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 935c960b13eSThomas Chou miiphy_register(dev->name, altera_tse_miiphy_read, 936c960b13eSThomas Chou altera_tse_miiphy_write); 937c960b13eSThomas Chou #endif 938c960b13eSThomas Chou 939c960b13eSThomas Chou init_phy(dev); 940c960b13eSThomas Chou 941c960b13eSThomas Chou return 1; 942c960b13eSThomas Chou } 943