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 /* 202*337aff53SJoachim Foerster * Clear the RUN bit in the control register. This is needed 203*337aff53SJoachim Foerster * to restart the SGDMA engine later on. 204*337aff53SJoachim Foerster */ 205*337aff53SJoachim Foerster dev->control = 0; 206*337aff53SJoachim Foerster 207*337aff53SJoachim Foerster /* 208c960b13eSThomas Chou * Clear any (previous) status register information 209c960b13eSThomas Chou * that might occlude our error checking later. 210c960b13eSThomas Chou */ 211c960b13eSThomas Chou dev->status = 0xFF; 212c960b13eSThomas Chou 213c960b13eSThomas Chou /* Point the controller at the descriptor */ 214c960b13eSThomas Chou dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF; 215c960b13eSThomas Chou 216c960b13eSThomas Chou /* 217c960b13eSThomas Chou * Set up SGDMA controller to: 218c960b13eSThomas Chou * - Disable interrupt generation 219c960b13eSThomas Chou * - Run once a valid descriptor is written to controller 220c960b13eSThomas Chou * - Stop on an error with any particular descriptor 221c960b13eSThomas Chou */ 222c960b13eSThomas Chou dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | 223c960b13eSThomas Chou ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); 224c960b13eSThomas Chou 225c960b13eSThomas Chou /* we really should check if the transfer completes properly */ 226c960b13eSThomas Chou return 0; 227c960b13eSThomas Chou } 228c960b13eSThomas Chou 229c960b13eSThomas Chou /* u-boot interface */ 230c960b13eSThomas Chou static int tse_adjust_link(struct altera_tse_priv *priv) 231c960b13eSThomas Chou { 232c960b13eSThomas Chou unsigned int refvar; 233c960b13eSThomas Chou 234c960b13eSThomas Chou refvar = priv->mac_dev->command_config.image; 235c960b13eSThomas Chou 236c960b13eSThomas Chou if (!(priv->duplexity)) 237c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; 238c960b13eSThomas Chou else 239c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK; 240c960b13eSThomas Chou 241c960b13eSThomas Chou switch (priv->speed) { 242c960b13eSThomas Chou case 1000: 243c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; 244c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 245c960b13eSThomas Chou break; 246c960b13eSThomas Chou case 100: 247c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 248c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; 249c960b13eSThomas Chou break; 250c960b13eSThomas Chou case 10: 251c960b13eSThomas Chou refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; 252c960b13eSThomas Chou refvar |= ALTERA_TSE_CMD_ENA_10_MSK; 253c960b13eSThomas Chou break; 254c960b13eSThomas Chou } 255c960b13eSThomas Chou priv->mac_dev->command_config.image = refvar; 256c960b13eSThomas Chou 257c960b13eSThomas Chou return 0; 258c960b13eSThomas Chou } 259c960b13eSThomas Chou 260c960b13eSThomas Chou static int tse_eth_send(struct eth_device *dev, 261c960b13eSThomas Chou volatile void *packet, int length) 262c960b13eSThomas Chou { 263c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 264c960b13eSThomas Chou volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 265c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc = 266c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)priv->tx_desc; 267c960b13eSThomas Chou 268c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc_cur = 269c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0]; 270c960b13eSThomas Chou 271c960b13eSThomas Chou flush_dcache((unsigned long)packet, length); 272c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 273c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0], 274c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[1], 275c960b13eSThomas Chou (unsigned int *)packet, /* read addr */ 276c960b13eSThomas Chou (unsigned int *)0, 277c960b13eSThomas Chou length, /* length or EOP ,will change for each tx */ 278c960b13eSThomas Chou 0x1, /* gen eop */ 279c960b13eSThomas Chou 0x0, /* read fixed */ 280c960b13eSThomas Chou 0x1, /* write fixed or sop */ 281c960b13eSThomas Chou 0x0, /* read burst */ 282c960b13eSThomas Chou 0x0, /* write burst */ 283c960b13eSThomas Chou 0x0 /* channel */ 284c960b13eSThomas Chou ); 285c960b13eSThomas Chou debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length); 286c960b13eSThomas Chou 287c960b13eSThomas Chou /* send the packet */ 288c960b13eSThomas Chou debug("sending packet\n"); 289c960b13eSThomas Chou alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur); 290c960b13eSThomas Chou debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred); 291c960b13eSThomas Chou return tx_desc_cur->actual_bytes_transferred; 292c960b13eSThomas Chou } 293c960b13eSThomas Chou 294c960b13eSThomas Chou static int tse_eth_rx(struct eth_device *dev) 295c960b13eSThomas Chou { 296c960b13eSThomas Chou int packet_length = 0; 297c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 298c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = 299c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)priv->rx_desc; 300c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0]; 301c960b13eSThomas Chou 302c960b13eSThomas Chou if (rx_desc_cur->descriptor_status & 303c960b13eSThomas Chou ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { 304c960b13eSThomas Chou debug("got packet\n"); 305c960b13eSThomas Chou packet_length = rx_desc->actual_bytes_transferred; 306c960b13eSThomas Chou NetReceive(NetRxPackets[0], packet_length); 307c960b13eSThomas Chou 308c960b13eSThomas Chou /* start descriptor again */ 309c960b13eSThomas Chou flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); 310c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 311c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0], 312c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[1], 313c960b13eSThomas Chou (unsigned int)0x0, /* read addr */ 314c960b13eSThomas Chou (unsigned int *)NetRxPackets[0], 315c960b13eSThomas Chou 0x0, /* length or EOP */ 316c960b13eSThomas Chou 0x0, /* gen eop */ 317c960b13eSThomas Chou 0x0, /* read fixed */ 318c960b13eSThomas Chou 0x0, /* write fixed or sop */ 319c960b13eSThomas Chou 0x0, /* read burst */ 320c960b13eSThomas Chou 0x0, /* write burst */ 321c960b13eSThomas Chou 0x0 /* channel */ 322c960b13eSThomas Chou ); 323c960b13eSThomas Chou 324c960b13eSThomas Chou /* setup the sgdma */ 325c960b13eSThomas Chou alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]); 326c960b13eSThomas Chou } 327c960b13eSThomas Chou 328c960b13eSThomas Chou return -1; 329c960b13eSThomas Chou } 330c960b13eSThomas Chou 331c960b13eSThomas Chou static void tse_eth_halt(struct eth_device *dev) 332c960b13eSThomas Chou { 333c960b13eSThomas Chou /* don't do anything! */ 334c960b13eSThomas Chou /* this gets called after each uboot */ 335c960b13eSThomas Chou /* network command. don't need to reset the thing all of the time */ 336c960b13eSThomas Chou } 337c960b13eSThomas Chou 338c960b13eSThomas Chou static void tse_eth_reset(struct eth_device *dev) 339c960b13eSThomas Chou { 340c960b13eSThomas Chou /* stop sgdmas, disable tse receive */ 341c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 342c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 343c960b13eSThomas Chou volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; 344c960b13eSThomas Chou volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 345c960b13eSThomas Chou int counter; 346c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = 347c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0]; 348c960b13eSThomas Chou 349c960b13eSThomas Chou /* clear rx desc & wait for sgdma to complete */ 350c960b13eSThomas Chou rx_desc->descriptor_control = 0; 351c960b13eSThomas Chou rx_sgdma->control = 0; 352c960b13eSThomas Chou counter = 0; 353c960b13eSThomas Chou while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 354c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 355c960b13eSThomas Chou break; 356c960b13eSThomas Chou } 357c960b13eSThomas Chou 358c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 359c960b13eSThomas Chou debug("Timeout waiting for rx sgdma!\n"); 360c960b13eSThomas Chou rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 361c960b13eSThomas Chou rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 362c960b13eSThomas Chou } 363c960b13eSThomas Chou 364c960b13eSThomas Chou counter = 0; 365c960b13eSThomas Chou tx_sgdma->control = 0; 366c960b13eSThomas Chou while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 367c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 368c960b13eSThomas Chou break; 369c960b13eSThomas Chou } 370c960b13eSThomas Chou 371c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 372c960b13eSThomas Chou debug("Timeout waiting for tx sgdma!\n"); 373c960b13eSThomas Chou tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 374c960b13eSThomas Chou tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 375c960b13eSThomas Chou } 376c960b13eSThomas Chou /* reset the mac */ 377c960b13eSThomas Chou mac_dev->command_config.bits.transmit_enable = 1; 378c960b13eSThomas Chou mac_dev->command_config.bits.receive_enable = 1; 379c960b13eSThomas Chou mac_dev->command_config.bits.software_reset = 1; 380c960b13eSThomas Chou 381c960b13eSThomas Chou counter = 0; 382c960b13eSThomas Chou while (mac_dev->command_config.bits.software_reset) { 383c960b13eSThomas Chou if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR) 384c960b13eSThomas Chou break; 385c960b13eSThomas Chou } 386c960b13eSThomas Chou 387c960b13eSThomas Chou if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR) 388c960b13eSThomas Chou debug("TSEMAC SW reset bit never cleared!\n"); 389c960b13eSThomas Chou } 390c960b13eSThomas Chou 391c960b13eSThomas Chou static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) 392c960b13eSThomas Chou { 393c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 394c960b13eSThomas Chou unsigned int *mdio_regs; 395c960b13eSThomas Chou unsigned int data; 396c960b13eSThomas Chou u16 value; 397c960b13eSThomas Chou 398c960b13eSThomas Chou mac_dev = priv->mac_dev; 399c960b13eSThomas Chou 400c960b13eSThomas Chou /* set mdio address */ 401c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 402c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 403c960b13eSThomas Chou 404c960b13eSThomas Chou /* get the data */ 405c960b13eSThomas Chou data = mdio_regs[regnum]; 406c960b13eSThomas Chou 407c960b13eSThomas Chou value = data & 0xffff; 408c960b13eSThomas Chou 409c960b13eSThomas Chou return value; 410c960b13eSThomas Chou } 411c960b13eSThomas Chou 412c960b13eSThomas Chou static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, 413c960b13eSThomas Chou unsigned int value) 414c960b13eSThomas Chou { 415c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 416c960b13eSThomas Chou unsigned int *mdio_regs; 417c960b13eSThomas Chou unsigned int data; 418c960b13eSThomas Chou 419c960b13eSThomas Chou mac_dev = priv->mac_dev; 420c960b13eSThomas Chou 421c960b13eSThomas Chou /* set mdio address */ 422c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 423c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 424c960b13eSThomas Chou 425c960b13eSThomas Chou /* get the data */ 426c960b13eSThomas Chou data = (unsigned int)value; 427c960b13eSThomas Chou 428c960b13eSThomas Chou mdio_regs[regnum] = data; 429c960b13eSThomas Chou 430c960b13eSThomas Chou return 0; 431c960b13eSThomas Chou } 432c960b13eSThomas Chou 433c960b13eSThomas Chou /* MDIO access to phy */ 434c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 4355700bb63SMike Frysinger static int altera_tse_miiphy_write(const char *devname, unsigned char addr, 436c960b13eSThomas Chou unsigned char reg, unsigned short value) 437c960b13eSThomas Chou { 438c960b13eSThomas Chou struct eth_device *dev; 439c960b13eSThomas Chou struct altera_tse_priv *priv; 440c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 441c960b13eSThomas Chou priv = dev->priv; 442c960b13eSThomas Chou 443c960b13eSThomas Chou tse_mdio_write(priv, (uint) reg, (uint) value); 444c960b13eSThomas Chou 445c960b13eSThomas Chou return 0; 446c960b13eSThomas Chou } 447c960b13eSThomas Chou 4485700bb63SMike Frysinger static int altera_tse_miiphy_read(const char *devname, unsigned char addr, 449c960b13eSThomas Chou unsigned char reg, unsigned short *value) 450c960b13eSThomas Chou { 451c960b13eSThomas Chou struct eth_device *dev; 452c960b13eSThomas Chou struct altera_tse_priv *priv; 453c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 454c960b13eSThomas Chou unsigned int *mdio_regs; 455c960b13eSThomas Chou 456c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 457c960b13eSThomas Chou priv = dev->priv; 458c960b13eSThomas Chou 459c960b13eSThomas Chou mac_dev = priv->mac_dev; 460c960b13eSThomas Chou mac_dev->mdio_phy1_addr = (int)addr; 461c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 462c960b13eSThomas Chou 463c960b13eSThomas Chou *value = 0xffff & mdio_regs[reg]; 464c960b13eSThomas Chou 465c960b13eSThomas Chou return 0; 466c960b13eSThomas Chou 467c960b13eSThomas Chou } 468c960b13eSThomas Chou #endif 469c960b13eSThomas Chou 470c960b13eSThomas Chou /* 471c960b13eSThomas Chou * Also copied from tsec.c 472c960b13eSThomas Chou */ 473c960b13eSThomas Chou /* Parse the status register for link, and then do 474c960b13eSThomas Chou * auto-negotiation 475c960b13eSThomas Chou */ 476c960b13eSThomas Chou static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv) 477c960b13eSThomas Chou { 478c960b13eSThomas Chou /* 479c960b13eSThomas Chou * Wait if the link is up, and autonegotiation is in progress 480c960b13eSThomas Chou * (ie - we're capable and it's not done) 481c960b13eSThomas Chou */ 482c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 483c960b13eSThomas Chou 4848ef583a0SMike Frysinger if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & BMSR_ANEGCAPABLE) 4858ef583a0SMike Frysinger && !(mii_reg & BMSR_ANEGCOMPLETE)) { 486c960b13eSThomas Chou int i = 0; 487c960b13eSThomas Chou 488c960b13eSThomas Chou puts("Waiting for PHY auto negotiation to complete"); 4898ef583a0SMike Frysinger while (!(mii_reg & BMSR_ANEGCOMPLETE)) { 490c960b13eSThomas Chou /* 491c960b13eSThomas Chou * Timeout reached ? 492c960b13eSThomas Chou */ 493c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 494c960b13eSThomas Chou puts(" TIMEOUT !\n"); 495c960b13eSThomas Chou priv->link = 0; 496c960b13eSThomas Chou return 0; 497c960b13eSThomas Chou } 498c960b13eSThomas Chou 499c960b13eSThomas Chou if ((i++ % 1000) == 0) 500c960b13eSThomas Chou putc('.'); 501c960b13eSThomas Chou udelay(1000); /* 1 ms */ 502c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 503c960b13eSThomas Chou } 504c960b13eSThomas Chou puts(" done\n"); 505c960b13eSThomas Chou priv->link = 1; 506c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 507c960b13eSThomas Chou } else { 508c960b13eSThomas Chou if (mii_reg & MIIM_STATUS_LINK) { 509c960b13eSThomas Chou debug("Link is up\n"); 510c960b13eSThomas Chou priv->link = 1; 511c960b13eSThomas Chou } else { 512c960b13eSThomas Chou debug("Link is down\n"); 513c960b13eSThomas Chou priv->link = 0; 514c960b13eSThomas Chou } 515c960b13eSThomas Chou } 516c960b13eSThomas Chou 517c960b13eSThomas Chou return 0; 518c960b13eSThomas Chou } 519c960b13eSThomas Chou 520c960b13eSThomas Chou /* Parse the 88E1011's status register for speed and duplex 521c960b13eSThomas Chou * information 522c960b13eSThomas Chou */ 523c960b13eSThomas Chou static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv) 524c960b13eSThomas Chou { 525c960b13eSThomas Chou uint speed; 526c960b13eSThomas Chou 527c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 528c960b13eSThomas Chou 529c960b13eSThomas Chou if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && 530c960b13eSThomas Chou !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 531c960b13eSThomas Chou int i = 0; 532c960b13eSThomas Chou 533c960b13eSThomas Chou puts("Waiting for PHY realtime link"); 534c960b13eSThomas Chou while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 535c960b13eSThomas Chou /* Timeout reached ? */ 536c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 537c960b13eSThomas Chou puts(" TIMEOUT !\n"); 538c960b13eSThomas Chou priv->link = 0; 539c960b13eSThomas Chou break; 540c960b13eSThomas Chou } 541c960b13eSThomas Chou 542c960b13eSThomas Chou if ((i++ == 1000) == 0) { 543c960b13eSThomas Chou i = 0; 544c960b13eSThomas Chou puts("."); 545c960b13eSThomas Chou } 546c960b13eSThomas Chou udelay(1000); /* 1 ms */ 547c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 548c960b13eSThomas Chou } 549c960b13eSThomas Chou puts(" done\n"); 550c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 551c960b13eSThomas Chou } else { 552c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) 553c960b13eSThomas Chou priv->link = 1; 554c960b13eSThomas Chou else 555c960b13eSThomas Chou priv->link = 0; 556c960b13eSThomas Chou } 557c960b13eSThomas Chou 558c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) 559c960b13eSThomas Chou priv->duplexity = 1; 560c960b13eSThomas Chou else 561c960b13eSThomas Chou priv->duplexity = 0; 562c960b13eSThomas Chou 563c960b13eSThomas Chou speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); 564c960b13eSThomas Chou 565c960b13eSThomas Chou switch (speed) { 566c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_GBIT: 567c960b13eSThomas Chou priv->speed = 1000; 568c960b13eSThomas Chou debug("PHY Speed is 1000Mbit\n"); 569c960b13eSThomas Chou break; 570c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_100: 571c960b13eSThomas Chou debug("PHY Speed is 100Mbit\n"); 572c960b13eSThomas Chou priv->speed = 100; 573c960b13eSThomas Chou break; 574c960b13eSThomas Chou default: 575c960b13eSThomas Chou debug("PHY Speed is 10Mbit\n"); 576c960b13eSThomas Chou priv->speed = 10; 577c960b13eSThomas Chou } 578c960b13eSThomas Chou 579c960b13eSThomas Chou return 0; 580c960b13eSThomas Chou } 581c960b13eSThomas Chou 582c960b13eSThomas Chou static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv) 583c960b13eSThomas Chou { 584c960b13eSThomas Chou uint mii_data = tse_mdio_read(priv, mii_reg); 585c960b13eSThomas Chou mii_data &= 0xfff0; 586c960b13eSThomas Chou mii_data |= 0xb; 587c960b13eSThomas Chou return mii_data; 588c960b13eSThomas Chou } 589c960b13eSThomas Chou 590c960b13eSThomas Chou static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv) 591c960b13eSThomas Chou { 592c960b13eSThomas Chou uint mii_data = tse_mdio_read(priv, mii_reg); 593c960b13eSThomas Chou mii_data &= ~0x82; 594c960b13eSThomas Chou mii_data |= 0x82; 595c960b13eSThomas Chou return mii_data; 596c960b13eSThomas Chou } 597c960b13eSThomas Chou 598c960b13eSThomas Chou /* 599c960b13eSThomas Chou * Returns which value to write to the control register. 600c960b13eSThomas Chou * For 10/100, the value is slightly different 601c960b13eSThomas Chou */ 602c960b13eSThomas Chou static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv) 603c960b13eSThomas Chou { 604c960b13eSThomas Chou return MIIM_CONTROL_INIT; 605c960b13eSThomas Chou } 606c960b13eSThomas Chou 607c960b13eSThomas Chou /* 608c960b13eSThomas Chou * PHY & MDIO code 609c960b13eSThomas Chou * Need to add SGMII stuff 610c960b13eSThomas Chou * 611c960b13eSThomas Chou */ 612c960b13eSThomas Chou 613c960b13eSThomas Chou static struct phy_info phy_info_M88E1111S = { 614c960b13eSThomas Chou 0x01410cc, 615c960b13eSThomas Chou "Marvell 88E1111S", 616c960b13eSThomas Chou 4, 617c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 618c960b13eSThomas Chou /* Reset and configure the PHY */ 619c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 620c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_SR, 0x848f, 621c960b13eSThomas Chou &mii_m88e1111s_setmode_sr}, 622c960b13eSThomas Chou /* Delay RGMII TX and RX */ 623c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_CR, 0x0cd2, 624c960b13eSThomas Chou &mii_m88e1111s_setmode_cr}, 625c960b13eSThomas Chou {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, 626c960b13eSThomas Chou {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, 627c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 628c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, 629c960b13eSThomas Chou {miim_end,} 630c960b13eSThomas Chou }, 631c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 632c960b13eSThomas Chou /* Status is read once to clear old link state */ 633c960b13eSThomas Chou {MIIM_STATUS, miim_read, NULL}, 634c960b13eSThomas Chou /* Auto-negotiate */ 635c960b13eSThomas Chou {MIIM_STATUS, miim_read, &mii_parse_sr}, 636c960b13eSThomas Chou /* Read the status */ 637c960b13eSThomas Chou {MIIM_88E1011_PHY_STATUS, miim_read, 638c960b13eSThomas Chou &mii_parse_88E1011_psr}, 639c960b13eSThomas Chou {miim_end,} 640c960b13eSThomas Chou }, 641c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 642c960b13eSThomas Chou {miim_end,} 643c960b13eSThomas Chou }, 644c960b13eSThomas Chou }; 645c960b13eSThomas Chou 646c960b13eSThomas Chou /* a generic flavor. */ 647c960b13eSThomas Chou static struct phy_info phy_info_generic = { 648c960b13eSThomas Chou 0, 649c960b13eSThomas Chou "Unknown/Generic PHY", 650c960b13eSThomas Chou 32, 651c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 6528ef583a0SMike Frysinger {MII_BMCR, BMCR_RESET, NULL}, 6538ef583a0SMike Frysinger {MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART, NULL}, 654c960b13eSThomas Chou {miim_end,} 655c960b13eSThomas Chou }, 656c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 6578ef583a0SMike Frysinger {MII_BMSR, miim_read, NULL}, 6588ef583a0SMike Frysinger {MII_BMSR, miim_read, &mii_parse_sr}, 659c960b13eSThomas Chou {miim_end,} 660c960b13eSThomas Chou }, 661c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 662c960b13eSThomas Chou {miim_end,} 663c960b13eSThomas Chou } 664c960b13eSThomas Chou }; 665c960b13eSThomas Chou 666c960b13eSThomas Chou static struct phy_info *phy_info[] = { 667c960b13eSThomas Chou &phy_info_M88E1111S, 668c960b13eSThomas Chou NULL 669c960b13eSThomas Chou }; 670c960b13eSThomas Chou 671c960b13eSThomas Chou /* Grab the identifier of the device's PHY, and search through 672c960b13eSThomas Chou * all of the known PHYs to see if one matches. If so, return 673c960b13eSThomas Chou * it, if not, return NULL 674c960b13eSThomas Chou */ 675c960b13eSThomas Chou static struct phy_info *get_phy_info(struct eth_device *dev) 676c960b13eSThomas Chou { 677c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 678c960b13eSThomas Chou uint phy_reg, phy_ID; 679c960b13eSThomas Chou int i; 680c960b13eSThomas Chou struct phy_info *theInfo = NULL; 681c960b13eSThomas Chou 682c960b13eSThomas Chou /* Grab the bits from PHYIR1, and put them in the upper half */ 683c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR1); 684c960b13eSThomas Chou phy_ID = (phy_reg & 0xffff) << 16; 685c960b13eSThomas Chou 686c960b13eSThomas Chou /* Grab the bits from PHYIR2, and put them in the lower half */ 687c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR2); 688c960b13eSThomas Chou phy_ID |= (phy_reg & 0xffff); 689c960b13eSThomas Chou 690c960b13eSThomas Chou /* loop through all the known PHY types, and find one that */ 691c960b13eSThomas Chou /* matches the ID we read from the PHY. */ 692c960b13eSThomas Chou for (i = 0; phy_info[i]; i++) { 693c960b13eSThomas Chou if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { 694c960b13eSThomas Chou theInfo = phy_info[i]; 695c960b13eSThomas Chou break; 696c960b13eSThomas Chou } 697c960b13eSThomas Chou } 698c960b13eSThomas Chou 699c960b13eSThomas Chou if (theInfo == NULL) { 700c960b13eSThomas Chou theInfo = &phy_info_generic; 701c960b13eSThomas Chou debug("%s: No support for PHY id %x; assuming generic\n", 702c960b13eSThomas Chou dev->name, phy_ID); 703c960b13eSThomas Chou } else 704c960b13eSThomas Chou debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); 705c960b13eSThomas Chou 706c960b13eSThomas Chou return theInfo; 707c960b13eSThomas Chou } 708c960b13eSThomas Chou 709c960b13eSThomas Chou /* Execute the given series of commands on the given device's 710c960b13eSThomas Chou * PHY, running functions as necessary 711c960b13eSThomas Chou */ 712c960b13eSThomas Chou static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd) 713c960b13eSThomas Chou { 714c960b13eSThomas Chou int i; 715c960b13eSThomas Chou uint result; 716c960b13eSThomas Chou 717c960b13eSThomas Chou for (i = 0; cmd->mii_reg != miim_end; i++) { 718c960b13eSThomas Chou if (cmd->mii_data == miim_read) { 719c960b13eSThomas Chou result = tse_mdio_read(priv, cmd->mii_reg); 720c960b13eSThomas Chou 721c960b13eSThomas Chou if (cmd->funct != NULL) 722c960b13eSThomas Chou (*(cmd->funct)) (result, priv); 723c960b13eSThomas Chou 724c960b13eSThomas Chou } else { 725c960b13eSThomas Chou if (cmd->funct != NULL) 726c960b13eSThomas Chou result = (*(cmd->funct)) (cmd->mii_reg, priv); 727c960b13eSThomas Chou else 728c960b13eSThomas Chou result = cmd->mii_data; 729c960b13eSThomas Chou 730c960b13eSThomas Chou tse_mdio_write(priv, cmd->mii_reg, result); 731c960b13eSThomas Chou 732c960b13eSThomas Chou } 733c960b13eSThomas Chou cmd++; 734c960b13eSThomas Chou } 735c960b13eSThomas Chou } 736c960b13eSThomas Chou 737c960b13eSThomas Chou /* Phy init code */ 738c960b13eSThomas Chou static int init_phy(struct eth_device *dev) 739c960b13eSThomas Chou { 740c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 741c960b13eSThomas Chou struct phy_info *curphy; 742c960b13eSThomas Chou 743c960b13eSThomas Chou /* Get the cmd structure corresponding to the attached 744c960b13eSThomas Chou * PHY */ 745c960b13eSThomas Chou curphy = get_phy_info(dev); 746c960b13eSThomas Chou 747c960b13eSThomas Chou if (curphy == NULL) { 748c960b13eSThomas Chou priv->phyinfo = NULL; 749c960b13eSThomas Chou debug("%s: No PHY found\n", dev->name); 750c960b13eSThomas Chou 751c960b13eSThomas Chou return 0; 752c960b13eSThomas Chou } else 753c960b13eSThomas Chou debug("%s found\n", curphy->name); 754c960b13eSThomas Chou priv->phyinfo = curphy; 755c960b13eSThomas Chou 756c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->config); 757c960b13eSThomas Chou 758c960b13eSThomas Chou return 1; 759c960b13eSThomas Chou } 760c960b13eSThomas Chou 7616c7c4447SThomas Chou static int tse_set_mac_address(struct eth_device *dev) 7626c7c4447SThomas Chou { 7636c7c4447SThomas Chou struct altera_tse_priv *priv = dev->priv; 7646c7c4447SThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 7656c7c4447SThomas Chou 7666c7c4447SThomas Chou debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\n", 7676c7c4447SThomas Chou dev->enetaddr[5], dev->enetaddr[4], 7686c7c4447SThomas Chou dev->enetaddr[3], dev->enetaddr[2], 7696c7c4447SThomas Chou dev->enetaddr[1], dev->enetaddr[0]); 7706c7c4447SThomas Chou mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 | 7716c7c4447SThomas Chou (dev->enetaddr[2]) << 16 | 7726c7c4447SThomas Chou (dev->enetaddr[1]) << 8 | (dev->enetaddr[0])); 7736c7c4447SThomas Chou 7746c7c4447SThomas Chou mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 | 7756c7c4447SThomas Chou (dev->enetaddr[4])) & 0xFFFF); 7766c7c4447SThomas Chou 7776c7c4447SThomas Chou /* Set the MAC address */ 7786c7c4447SThomas Chou mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0; 7796c7c4447SThomas Chou mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1; 7806c7c4447SThomas Chou 7816c7c4447SThomas Chou /* Set the MAC address */ 7826c7c4447SThomas Chou mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0; 7836c7c4447SThomas Chou mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1; 7846c7c4447SThomas Chou 7856c7c4447SThomas Chou /* Set the MAC address */ 7866c7c4447SThomas Chou mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0; 7876c7c4447SThomas Chou mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1; 7886c7c4447SThomas Chou 7896c7c4447SThomas Chou /* Set the MAC address */ 7906c7c4447SThomas Chou mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0; 7916c7c4447SThomas Chou mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1; 7926c7c4447SThomas Chou return 0; 7936c7c4447SThomas Chou } 7946c7c4447SThomas Chou 795c960b13eSThomas Chou static int tse_eth_init(struct eth_device *dev, bd_t * bd) 796c960b13eSThomas Chou { 797c960b13eSThomas Chou int dat; 798c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 799c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 800c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; 801c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 802c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc_cur = 803c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0]; 804c960b13eSThomas Chou 805c960b13eSThomas Chou /* stop controller */ 806c960b13eSThomas Chou debug("Reseting TSE & SGDMAs\n"); 807c960b13eSThomas Chou tse_eth_reset(dev); 808c960b13eSThomas Chou 809c960b13eSThomas Chou /* start the phy */ 810c960b13eSThomas Chou debug("Configuring PHY\n"); 811c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->startup); 812c960b13eSThomas Chou 813c960b13eSThomas Chou /* need to create sgdma */ 814c960b13eSThomas Chou debug("Configuring tx desc\n"); 815c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 816c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0], 817c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[1], 818c960b13eSThomas Chou (unsigned int *)NULL, /* read addr */ 819c960b13eSThomas Chou (unsigned int *)0, 820c960b13eSThomas Chou 0, /* length or EOP ,will change for each tx */ 821c960b13eSThomas Chou 0x1, /* gen eop */ 822c960b13eSThomas Chou 0x0, /* read fixed */ 823c960b13eSThomas Chou 0x1, /* write fixed or sop */ 824c960b13eSThomas Chou 0x0, /* read burst */ 825c960b13eSThomas Chou 0x0, /* write burst */ 826c960b13eSThomas Chou 0x0 /* channel */ 827c960b13eSThomas Chou ); 828c960b13eSThomas Chou debug("Configuring rx desc\n"); 829c960b13eSThomas Chou flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); 830c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 831c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0], 832c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[1], 833c960b13eSThomas Chou (unsigned int)0x0, /* read addr */ 834c960b13eSThomas Chou (unsigned int *)NetRxPackets[0], 835c960b13eSThomas Chou 0x0, /* length or EOP */ 836c960b13eSThomas Chou 0x0, /* gen eop */ 837c960b13eSThomas Chou 0x0, /* read fixed */ 838c960b13eSThomas Chou 0x0, /* write fixed or sop */ 839c960b13eSThomas Chou 0x0, /* read burst */ 840c960b13eSThomas Chou 0x0, /* write burst */ 841c960b13eSThomas Chou 0x0 /* channel */ 842c960b13eSThomas Chou ); 843c960b13eSThomas Chou /* start rx async transfer */ 844c960b13eSThomas Chou debug("Starting rx sgdma\n"); 845c960b13eSThomas Chou alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur); 846c960b13eSThomas Chou 847c960b13eSThomas Chou /* start TSE */ 848c960b13eSThomas Chou debug("Configuring TSE Mac\n"); 849c960b13eSThomas Chou /* Initialize MAC registers */ 850c960b13eSThomas Chou mac_dev->max_frame_length = PKTSIZE_ALIGN; 851c960b13eSThomas Chou mac_dev->rx_almost_empty_threshold = 8; 852c960b13eSThomas Chou mac_dev->rx_almost_full_threshold = 8; 853c960b13eSThomas Chou mac_dev->tx_almost_empty_threshold = 8; 854c960b13eSThomas Chou mac_dev->tx_almost_full_threshold = 3; 855c960b13eSThomas Chou mac_dev->tx_sel_empty_threshold = 856c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 857c960b13eSThomas Chou mac_dev->tx_sel_full_threshold = 0; 858c960b13eSThomas Chou mac_dev->rx_sel_empty_threshold = 859c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 860c960b13eSThomas Chou mac_dev->rx_sel_full_threshold = 0; 861c960b13eSThomas Chou 862c960b13eSThomas Chou /* NO Shift */ 863c960b13eSThomas Chou mac_dev->rx_cmd_stat.bits.rx_shift16 = 0; 864c960b13eSThomas Chou mac_dev->tx_cmd_stat.bits.tx_shift16 = 0; 865c960b13eSThomas Chou 866c960b13eSThomas Chou /* enable MAC */ 867c960b13eSThomas Chou dat = 0; 868c960b13eSThomas Chou dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; 869c960b13eSThomas Chou 870c960b13eSThomas Chou mac_dev->command_config.image = dat; 871c960b13eSThomas Chou 872c960b13eSThomas Chou /* configure the TSE core */ 873c960b13eSThomas Chou /* -- output clocks, */ 874c960b13eSThomas Chou /* -- and later config stuff for SGMII */ 875c960b13eSThomas Chou if (priv->link) { 876c960b13eSThomas Chou debug("Adjusting TSE to link speed\n"); 877c960b13eSThomas Chou tse_adjust_link(priv); 878c960b13eSThomas Chou } 879c960b13eSThomas Chou 880c960b13eSThomas Chou return priv->link ? 0 : -1; 881c960b13eSThomas Chou } 882c960b13eSThomas Chou 883c960b13eSThomas Chou /* TSE init code */ 884c960b13eSThomas Chou int altera_tse_initialize(u8 dev_num, int mac_base, 885c960b13eSThomas Chou int sgdma_rx_base, int sgdma_tx_base) 886c960b13eSThomas Chou { 887c960b13eSThomas Chou struct altera_tse_priv *priv; 888c960b13eSThomas Chou struct eth_device *dev; 889c960b13eSThomas Chou struct alt_sgdma_descriptor *rx_desc; 890c960b13eSThomas Chou struct alt_sgdma_descriptor *tx_desc; 891c960b13eSThomas Chou unsigned long dma_handle; 892c960b13eSThomas Chou 893c960b13eSThomas Chou dev = (struct eth_device *)malloc(sizeof *dev); 894c960b13eSThomas Chou 895c960b13eSThomas Chou if (NULL == dev) 896c960b13eSThomas Chou return 0; 897c960b13eSThomas Chou 898c960b13eSThomas Chou memset(dev, 0, sizeof *dev); 899c960b13eSThomas Chou 900c960b13eSThomas Chou priv = malloc(sizeof(*priv)); 901c960b13eSThomas Chou 902c960b13eSThomas Chou if (!priv) { 903c960b13eSThomas Chou free(dev); 904c960b13eSThomas Chou return 0; 905c960b13eSThomas Chou } 906c960b13eSThomas Chou tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), 907c960b13eSThomas Chou &dma_handle); 908c960b13eSThomas Chou rx_desc = tx_desc + 2; 909c960b13eSThomas Chou debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc); 910c960b13eSThomas Chou debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc); 911c960b13eSThomas Chou 912c960b13eSThomas Chou if (!tx_desc) { 913c960b13eSThomas Chou free(priv); 914c960b13eSThomas Chou free(dev); 915c960b13eSThomas Chou return 0; 916c960b13eSThomas Chou } 917c960b13eSThomas Chou memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1)); 918c960b13eSThomas Chou memset(tx_desc, 0, (sizeof *tx_desc) * 2); 919c960b13eSThomas Chou 920c960b13eSThomas Chou /* initialize tse priv */ 921c960b13eSThomas Chou priv->mac_dev = (volatile struct alt_tse_mac *)mac_base; 922c960b13eSThomas Chou priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base; 923c960b13eSThomas Chou priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base; 924c960b13eSThomas Chou priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR; 925c960b13eSThomas Chou priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS; 926c960b13eSThomas Chou priv->rx_desc = rx_desc; 927c960b13eSThomas Chou priv->tx_desc = tx_desc; 928c960b13eSThomas Chou 929c960b13eSThomas Chou /* init eth structure */ 930c960b13eSThomas Chou dev->priv = priv; 931c960b13eSThomas Chou dev->init = tse_eth_init; 932c960b13eSThomas Chou dev->halt = tse_eth_halt; 933c960b13eSThomas Chou dev->send = tse_eth_send; 934c960b13eSThomas Chou dev->recv = tse_eth_rx; 9356c7c4447SThomas Chou dev->write_hwaddr = tse_set_mac_address; 936c960b13eSThomas Chou sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num); 937c960b13eSThomas Chou 938c960b13eSThomas Chou eth_register(dev); 939c960b13eSThomas Chou 940c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 941c960b13eSThomas Chou miiphy_register(dev->name, altera_tse_miiphy_read, 942c960b13eSThomas Chou altera_tse_miiphy_write); 943c960b13eSThomas Chou #endif 944c960b13eSThomas Chou 945c960b13eSThomas Chou init_phy(dev); 946c960b13eSThomas Chou 947c960b13eSThomas Chou return 1; 948c960b13eSThomas Chou } 949