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 /* 202337aff53SJoachim Foerster * Clear the RUN bit in the control register. This is needed 203337aff53SJoachim Foerster * to restart the SGDMA engine later on. 204337aff53SJoachim Foerster */ 205337aff53SJoachim Foerster dev->control = 0; 206337aff53SJoachim Foerster 207337aff53SJoachim 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]); 326*70d52f9aSJoachim Foerster 327*70d52f9aSJoachim Foerster return packet_length; 328c960b13eSThomas Chou } 329c960b13eSThomas Chou 330c960b13eSThomas Chou return -1; 331c960b13eSThomas Chou } 332c960b13eSThomas Chou 333c960b13eSThomas Chou static void tse_eth_halt(struct eth_device *dev) 334c960b13eSThomas Chou { 335c960b13eSThomas Chou /* don't do anything! */ 336c960b13eSThomas Chou /* this gets called after each uboot */ 337c960b13eSThomas Chou /* network command. don't need to reset the thing all of the time */ 338c960b13eSThomas Chou } 339c960b13eSThomas Chou 340c960b13eSThomas Chou static void tse_eth_reset(struct eth_device *dev) 341c960b13eSThomas Chou { 342c960b13eSThomas Chou /* stop sgdmas, disable tse receive */ 343c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 344c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 345c960b13eSThomas Chou volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; 346c960b13eSThomas Chou volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; 347c960b13eSThomas Chou int counter; 348c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = 349c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0]; 350c960b13eSThomas Chou 351c960b13eSThomas Chou /* clear rx desc & wait for sgdma to complete */ 352c960b13eSThomas Chou rx_desc->descriptor_control = 0; 353c960b13eSThomas Chou rx_sgdma->control = 0; 354c960b13eSThomas Chou counter = 0; 355c960b13eSThomas Chou while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 356c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 357c960b13eSThomas Chou break; 358c960b13eSThomas Chou } 359c960b13eSThomas Chou 360c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 361c960b13eSThomas Chou debug("Timeout waiting for rx sgdma!\n"); 36229095f1aSJoachim Foerster rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 36329095f1aSJoachim Foerster rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 364c960b13eSThomas Chou } 365c960b13eSThomas Chou 366c960b13eSThomas Chou counter = 0; 367c960b13eSThomas Chou tx_sgdma->control = 0; 368c960b13eSThomas Chou while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { 369c960b13eSThomas Chou if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) 370c960b13eSThomas Chou break; 371c960b13eSThomas Chou } 372c960b13eSThomas Chou 373c960b13eSThomas Chou if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { 374c960b13eSThomas Chou debug("Timeout waiting for tx sgdma!\n"); 37529095f1aSJoachim Foerster tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 37629095f1aSJoachim Foerster tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; 377c960b13eSThomas Chou } 378c960b13eSThomas Chou /* reset the mac */ 379c960b13eSThomas Chou mac_dev->command_config.bits.transmit_enable = 1; 380c960b13eSThomas Chou mac_dev->command_config.bits.receive_enable = 1; 381c960b13eSThomas Chou mac_dev->command_config.bits.software_reset = 1; 382c960b13eSThomas Chou 383c960b13eSThomas Chou counter = 0; 384c960b13eSThomas Chou while (mac_dev->command_config.bits.software_reset) { 385c960b13eSThomas Chou if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR) 386c960b13eSThomas Chou break; 387c960b13eSThomas Chou } 388c960b13eSThomas Chou 389c960b13eSThomas Chou if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR) 390c960b13eSThomas Chou debug("TSEMAC SW reset bit never cleared!\n"); 391c960b13eSThomas Chou } 392c960b13eSThomas Chou 393c960b13eSThomas Chou static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) 394c960b13eSThomas Chou { 395c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 396c960b13eSThomas Chou unsigned int *mdio_regs; 397c960b13eSThomas Chou unsigned int data; 398c960b13eSThomas Chou u16 value; 399c960b13eSThomas Chou 400c960b13eSThomas Chou mac_dev = priv->mac_dev; 401c960b13eSThomas Chou 402c960b13eSThomas Chou /* set mdio address */ 403c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 404c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 405c960b13eSThomas Chou 406c960b13eSThomas Chou /* get the data */ 407c960b13eSThomas Chou data = mdio_regs[regnum]; 408c960b13eSThomas Chou 409c960b13eSThomas Chou value = data & 0xffff; 410c960b13eSThomas Chou 411c960b13eSThomas Chou return value; 412c960b13eSThomas Chou } 413c960b13eSThomas Chou 414c960b13eSThomas Chou static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, 415c960b13eSThomas Chou unsigned int value) 416c960b13eSThomas Chou { 417c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 418c960b13eSThomas Chou unsigned int *mdio_regs; 419c960b13eSThomas Chou unsigned int data; 420c960b13eSThomas Chou 421c960b13eSThomas Chou mac_dev = priv->mac_dev; 422c960b13eSThomas Chou 423c960b13eSThomas Chou /* set mdio address */ 424c960b13eSThomas Chou mac_dev->mdio_phy1_addr = priv->phyaddr; 425c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 426c960b13eSThomas Chou 427c960b13eSThomas Chou /* get the data */ 428c960b13eSThomas Chou data = (unsigned int)value; 429c960b13eSThomas Chou 430c960b13eSThomas Chou mdio_regs[regnum] = data; 431c960b13eSThomas Chou 432c960b13eSThomas Chou return 0; 433c960b13eSThomas Chou } 434c960b13eSThomas Chou 435c960b13eSThomas Chou /* MDIO access to phy */ 436c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 4375700bb63SMike Frysinger static int altera_tse_miiphy_write(const char *devname, unsigned char addr, 438c960b13eSThomas Chou unsigned char reg, unsigned short value) 439c960b13eSThomas Chou { 440c960b13eSThomas Chou struct eth_device *dev; 441c960b13eSThomas Chou struct altera_tse_priv *priv; 442c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 443c960b13eSThomas Chou priv = dev->priv; 444c960b13eSThomas Chou 445c960b13eSThomas Chou tse_mdio_write(priv, (uint) reg, (uint) value); 446c960b13eSThomas Chou 447c960b13eSThomas Chou return 0; 448c960b13eSThomas Chou } 449c960b13eSThomas Chou 4505700bb63SMike Frysinger static int altera_tse_miiphy_read(const char *devname, unsigned char addr, 451c960b13eSThomas Chou unsigned char reg, unsigned short *value) 452c960b13eSThomas Chou { 453c960b13eSThomas Chou struct eth_device *dev; 454c960b13eSThomas Chou struct altera_tse_priv *priv; 455c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev; 456c960b13eSThomas Chou unsigned int *mdio_regs; 457c960b13eSThomas Chou 458c960b13eSThomas Chou dev = eth_get_dev_by_name(devname); 459c960b13eSThomas Chou priv = dev->priv; 460c960b13eSThomas Chou 461c960b13eSThomas Chou mac_dev = priv->mac_dev; 462c960b13eSThomas Chou mac_dev->mdio_phy1_addr = (int)addr; 463c960b13eSThomas Chou mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; 464c960b13eSThomas Chou 465c960b13eSThomas Chou *value = 0xffff & mdio_regs[reg]; 466c960b13eSThomas Chou 467c960b13eSThomas Chou return 0; 468c960b13eSThomas Chou 469c960b13eSThomas Chou } 470c960b13eSThomas Chou #endif 471c960b13eSThomas Chou 472c960b13eSThomas Chou /* 473c960b13eSThomas Chou * Also copied from tsec.c 474c960b13eSThomas Chou */ 475c960b13eSThomas Chou /* Parse the status register for link, and then do 476c960b13eSThomas Chou * auto-negotiation 477c960b13eSThomas Chou */ 478c960b13eSThomas Chou static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv) 479c960b13eSThomas Chou { 480c960b13eSThomas Chou /* 481c960b13eSThomas Chou * Wait if the link is up, and autonegotiation is in progress 482c960b13eSThomas Chou * (ie - we're capable and it's not done) 483c960b13eSThomas Chou */ 484c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 485c960b13eSThomas Chou 4868ef583a0SMike Frysinger if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & BMSR_ANEGCAPABLE) 4878ef583a0SMike Frysinger && !(mii_reg & BMSR_ANEGCOMPLETE)) { 488c960b13eSThomas Chou int i = 0; 489c960b13eSThomas Chou 490c960b13eSThomas Chou puts("Waiting for PHY auto negotiation to complete"); 4918ef583a0SMike Frysinger while (!(mii_reg & BMSR_ANEGCOMPLETE)) { 492c960b13eSThomas Chou /* 493c960b13eSThomas Chou * Timeout reached ? 494c960b13eSThomas Chou */ 495c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 496c960b13eSThomas Chou puts(" TIMEOUT !\n"); 497c960b13eSThomas Chou priv->link = 0; 498c960b13eSThomas Chou return 0; 499c960b13eSThomas Chou } 500c960b13eSThomas Chou 501c960b13eSThomas Chou if ((i++ % 1000) == 0) 502c960b13eSThomas Chou putc('.'); 503c960b13eSThomas Chou udelay(1000); /* 1 ms */ 504c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_STATUS); 505c960b13eSThomas Chou } 506c960b13eSThomas Chou puts(" done\n"); 507c960b13eSThomas Chou priv->link = 1; 508c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 509c960b13eSThomas Chou } else { 510c960b13eSThomas Chou if (mii_reg & MIIM_STATUS_LINK) { 511c960b13eSThomas Chou debug("Link is up\n"); 512c960b13eSThomas Chou priv->link = 1; 513c960b13eSThomas Chou } else { 514c960b13eSThomas Chou debug("Link is down\n"); 515c960b13eSThomas Chou priv->link = 0; 516c960b13eSThomas Chou } 517c960b13eSThomas Chou } 518c960b13eSThomas Chou 519c960b13eSThomas Chou return 0; 520c960b13eSThomas Chou } 521c960b13eSThomas Chou 522c960b13eSThomas Chou /* Parse the 88E1011's status register for speed and duplex 523c960b13eSThomas Chou * information 524c960b13eSThomas Chou */ 525c960b13eSThomas Chou static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv) 526c960b13eSThomas Chou { 527c960b13eSThomas Chou uint speed; 528c960b13eSThomas Chou 529c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 530c960b13eSThomas Chou 531c960b13eSThomas Chou if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && 532c960b13eSThomas Chou !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 533c960b13eSThomas Chou int i = 0; 534c960b13eSThomas Chou 535c960b13eSThomas Chou puts("Waiting for PHY realtime link"); 536c960b13eSThomas Chou while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { 537c960b13eSThomas Chou /* Timeout reached ? */ 538c960b13eSThomas Chou if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 539c960b13eSThomas Chou puts(" TIMEOUT !\n"); 540c960b13eSThomas Chou priv->link = 0; 541c960b13eSThomas Chou break; 542c960b13eSThomas Chou } 543c960b13eSThomas Chou 544c960b13eSThomas Chou if ((i++ == 1000) == 0) { 545c960b13eSThomas Chou i = 0; 546c960b13eSThomas Chou puts("."); 547c960b13eSThomas Chou } 548c960b13eSThomas Chou udelay(1000); /* 1 ms */ 549c960b13eSThomas Chou mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); 550c960b13eSThomas Chou } 551c960b13eSThomas Chou puts(" done\n"); 552c960b13eSThomas Chou udelay(500000); /* another 500 ms (results in faster booting) */ 553c960b13eSThomas Chou } else { 554c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) 555c960b13eSThomas Chou priv->link = 1; 556c960b13eSThomas Chou else 557c960b13eSThomas Chou priv->link = 0; 558c960b13eSThomas Chou } 559c960b13eSThomas Chou 560c960b13eSThomas Chou if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) 561c960b13eSThomas Chou priv->duplexity = 1; 562c960b13eSThomas Chou else 563c960b13eSThomas Chou priv->duplexity = 0; 564c960b13eSThomas Chou 565c960b13eSThomas Chou speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); 566c960b13eSThomas Chou 567c960b13eSThomas Chou switch (speed) { 568c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_GBIT: 569c960b13eSThomas Chou priv->speed = 1000; 570c960b13eSThomas Chou debug("PHY Speed is 1000Mbit\n"); 571c960b13eSThomas Chou break; 572c960b13eSThomas Chou case MIIM_88E1011_PHYSTAT_100: 573c960b13eSThomas Chou debug("PHY Speed is 100Mbit\n"); 574c960b13eSThomas Chou priv->speed = 100; 575c960b13eSThomas Chou break; 576c960b13eSThomas Chou default: 577c960b13eSThomas Chou debug("PHY Speed is 10Mbit\n"); 578c960b13eSThomas Chou priv->speed = 10; 579c960b13eSThomas Chou } 580c960b13eSThomas Chou 581c960b13eSThomas Chou return 0; 582c960b13eSThomas Chou } 583c960b13eSThomas Chou 584c960b13eSThomas Chou static uint mii_m88e1111s_setmode_sr(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 &= 0xfff0; 58815eb1069SJoachim Foerster if ((priv->flags >= 1) && (priv->flags <= 4)) 589c960b13eSThomas Chou mii_data |= 0xb; 59015eb1069SJoachim Foerster else if (priv->flags == 5) 59115eb1069SJoachim Foerster mii_data |= 0x4; 59215eb1069SJoachim Foerster 593c960b13eSThomas Chou return mii_data; 594c960b13eSThomas Chou } 595c960b13eSThomas Chou 596c960b13eSThomas Chou static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv) 597c960b13eSThomas Chou { 598c960b13eSThomas Chou uint mii_data = tse_mdio_read(priv, mii_reg); 599c960b13eSThomas Chou mii_data &= ~0x82; 60015eb1069SJoachim Foerster if ((priv->flags >= 1) && (priv->flags <= 4)) 601c960b13eSThomas Chou mii_data |= 0x82; 60215eb1069SJoachim Foerster 603c960b13eSThomas Chou return mii_data; 604c960b13eSThomas Chou } 605c960b13eSThomas Chou 606c960b13eSThomas Chou /* 607c960b13eSThomas Chou * Returns which value to write to the control register. 608c960b13eSThomas Chou * For 10/100, the value is slightly different 609c960b13eSThomas Chou */ 610c960b13eSThomas Chou static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv) 611c960b13eSThomas Chou { 612c960b13eSThomas Chou return MIIM_CONTROL_INIT; 613c960b13eSThomas Chou } 614c960b13eSThomas Chou 615c960b13eSThomas Chou /* 616c960b13eSThomas Chou * PHY & MDIO code 617c960b13eSThomas Chou * Need to add SGMII stuff 618c960b13eSThomas Chou * 619c960b13eSThomas Chou */ 620c960b13eSThomas Chou 621c960b13eSThomas Chou static struct phy_info phy_info_M88E1111S = { 622c960b13eSThomas Chou 0x01410cc, 623c960b13eSThomas Chou "Marvell 88E1111S", 624c960b13eSThomas Chou 4, 625c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 626c960b13eSThomas Chou /* Reset and configure the PHY */ 627c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 628c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_SR, 0x848f, 629c960b13eSThomas Chou &mii_m88e1111s_setmode_sr}, 630c960b13eSThomas Chou /* Delay RGMII TX and RX */ 631c960b13eSThomas Chou {MIIM_88E1111_PHY_EXT_CR, 0x0cd2, 632c960b13eSThomas Chou &mii_m88e1111s_setmode_cr}, 633c960b13eSThomas Chou {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, 634c960b13eSThomas Chou {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, 635c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, 636c960b13eSThomas Chou {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, 637c960b13eSThomas Chou {miim_end,} 638c960b13eSThomas Chou }, 639c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 640c960b13eSThomas Chou /* Status is read once to clear old link state */ 641c960b13eSThomas Chou {MIIM_STATUS, miim_read, NULL}, 642c960b13eSThomas Chou /* Auto-negotiate */ 643c960b13eSThomas Chou {MIIM_STATUS, miim_read, &mii_parse_sr}, 644c960b13eSThomas Chou /* Read the status */ 645c960b13eSThomas Chou {MIIM_88E1011_PHY_STATUS, miim_read, 646c960b13eSThomas Chou &mii_parse_88E1011_psr}, 647c960b13eSThomas Chou {miim_end,} 648c960b13eSThomas Chou }, 649c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 650c960b13eSThomas Chou {miim_end,} 651c960b13eSThomas Chou }, 652c960b13eSThomas Chou }; 653c960b13eSThomas Chou 654c960b13eSThomas Chou /* a generic flavor. */ 655c960b13eSThomas Chou static struct phy_info phy_info_generic = { 656c960b13eSThomas Chou 0, 657c960b13eSThomas Chou "Unknown/Generic PHY", 658c960b13eSThomas Chou 32, 659c960b13eSThomas Chou (struct phy_cmd[]){ /* config */ 6608ef583a0SMike Frysinger {MII_BMCR, BMCR_RESET, NULL}, 6618ef583a0SMike Frysinger {MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART, NULL}, 662c960b13eSThomas Chou {miim_end,} 663c960b13eSThomas Chou }, 664c960b13eSThomas Chou (struct phy_cmd[]){ /* startup */ 6658ef583a0SMike Frysinger {MII_BMSR, miim_read, NULL}, 6668ef583a0SMike Frysinger {MII_BMSR, miim_read, &mii_parse_sr}, 667c960b13eSThomas Chou {miim_end,} 668c960b13eSThomas Chou }, 669c960b13eSThomas Chou (struct phy_cmd[]){ /* shutdown */ 670c960b13eSThomas Chou {miim_end,} 671c960b13eSThomas Chou } 672c960b13eSThomas Chou }; 673c960b13eSThomas Chou 674c960b13eSThomas Chou static struct phy_info *phy_info[] = { 675c960b13eSThomas Chou &phy_info_M88E1111S, 676c960b13eSThomas Chou NULL 677c960b13eSThomas Chou }; 678c960b13eSThomas Chou 679c960b13eSThomas Chou /* Grab the identifier of the device's PHY, and search through 680c960b13eSThomas Chou * all of the known PHYs to see if one matches. If so, return 681c960b13eSThomas Chou * it, if not, return NULL 682c960b13eSThomas Chou */ 683c960b13eSThomas Chou static struct phy_info *get_phy_info(struct eth_device *dev) 684c960b13eSThomas Chou { 685c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 686c960b13eSThomas Chou uint phy_reg, phy_ID; 687c960b13eSThomas Chou int i; 688c960b13eSThomas Chou struct phy_info *theInfo = NULL; 689c960b13eSThomas Chou 690c960b13eSThomas Chou /* Grab the bits from PHYIR1, and put them in the upper half */ 691c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR1); 692c960b13eSThomas Chou phy_ID = (phy_reg & 0xffff) << 16; 693c960b13eSThomas Chou 694c960b13eSThomas Chou /* Grab the bits from PHYIR2, and put them in the lower half */ 695c960b13eSThomas Chou phy_reg = tse_mdio_read(priv, MIIM_PHYIR2); 696c960b13eSThomas Chou phy_ID |= (phy_reg & 0xffff); 697c960b13eSThomas Chou 698c960b13eSThomas Chou /* loop through all the known PHY types, and find one that */ 699c960b13eSThomas Chou /* matches the ID we read from the PHY. */ 700c960b13eSThomas Chou for (i = 0; phy_info[i]; i++) { 701c960b13eSThomas Chou if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { 702c960b13eSThomas Chou theInfo = phy_info[i]; 703c960b13eSThomas Chou break; 704c960b13eSThomas Chou } 705c960b13eSThomas Chou } 706c960b13eSThomas Chou 707c960b13eSThomas Chou if (theInfo == NULL) { 708c960b13eSThomas Chou theInfo = &phy_info_generic; 709c960b13eSThomas Chou debug("%s: No support for PHY id %x; assuming generic\n", 710c960b13eSThomas Chou dev->name, phy_ID); 711c960b13eSThomas Chou } else 712c960b13eSThomas Chou debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); 713c960b13eSThomas Chou 714c960b13eSThomas Chou return theInfo; 715c960b13eSThomas Chou } 716c960b13eSThomas Chou 717c960b13eSThomas Chou /* Execute the given series of commands on the given device's 718c960b13eSThomas Chou * PHY, running functions as necessary 719c960b13eSThomas Chou */ 720c960b13eSThomas Chou static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd) 721c960b13eSThomas Chou { 722c960b13eSThomas Chou int i; 723c960b13eSThomas Chou uint result; 724c960b13eSThomas Chou 725c960b13eSThomas Chou for (i = 0; cmd->mii_reg != miim_end; i++) { 726c960b13eSThomas Chou if (cmd->mii_data == miim_read) { 727c960b13eSThomas Chou result = tse_mdio_read(priv, cmd->mii_reg); 728c960b13eSThomas Chou 729c960b13eSThomas Chou if (cmd->funct != NULL) 730c960b13eSThomas Chou (*(cmd->funct)) (result, priv); 731c960b13eSThomas Chou 732c960b13eSThomas Chou } else { 733c960b13eSThomas Chou if (cmd->funct != NULL) 734c960b13eSThomas Chou result = (*(cmd->funct)) (cmd->mii_reg, priv); 735c960b13eSThomas Chou else 736c960b13eSThomas Chou result = cmd->mii_data; 737c960b13eSThomas Chou 738c960b13eSThomas Chou tse_mdio_write(priv, cmd->mii_reg, result); 739c960b13eSThomas Chou 740c960b13eSThomas Chou } 741c960b13eSThomas Chou cmd++; 742c960b13eSThomas Chou } 743c960b13eSThomas Chou } 744c960b13eSThomas Chou 745c960b13eSThomas Chou /* Phy init code */ 746c960b13eSThomas Chou static int init_phy(struct eth_device *dev) 747c960b13eSThomas Chou { 748c960b13eSThomas Chou struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; 749c960b13eSThomas Chou struct phy_info *curphy; 750c960b13eSThomas Chou 751c960b13eSThomas Chou /* Get the cmd structure corresponding to the attached 752c960b13eSThomas Chou * PHY */ 753c960b13eSThomas Chou curphy = get_phy_info(dev); 754c960b13eSThomas Chou 755c960b13eSThomas Chou if (curphy == NULL) { 756c960b13eSThomas Chou priv->phyinfo = NULL; 757c960b13eSThomas Chou debug("%s: No PHY found\n", dev->name); 758c960b13eSThomas Chou 759c960b13eSThomas Chou return 0; 760c960b13eSThomas Chou } else 761c960b13eSThomas Chou debug("%s found\n", curphy->name); 762c960b13eSThomas Chou priv->phyinfo = curphy; 763c960b13eSThomas Chou 764c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->config); 765c960b13eSThomas Chou 766c960b13eSThomas Chou return 1; 767c960b13eSThomas Chou } 768c960b13eSThomas Chou 7696c7c4447SThomas Chou static int tse_set_mac_address(struct eth_device *dev) 7706c7c4447SThomas Chou { 7716c7c4447SThomas Chou struct altera_tse_priv *priv = dev->priv; 7726c7c4447SThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 7736c7c4447SThomas Chou 7746c7c4447SThomas Chou debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\n", 7756c7c4447SThomas Chou dev->enetaddr[5], dev->enetaddr[4], 7766c7c4447SThomas Chou dev->enetaddr[3], dev->enetaddr[2], 7776c7c4447SThomas Chou dev->enetaddr[1], dev->enetaddr[0]); 7786c7c4447SThomas Chou mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 | 7796c7c4447SThomas Chou (dev->enetaddr[2]) << 16 | 7806c7c4447SThomas Chou (dev->enetaddr[1]) << 8 | (dev->enetaddr[0])); 7816c7c4447SThomas Chou 7826c7c4447SThomas Chou mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 | 7836c7c4447SThomas Chou (dev->enetaddr[4])) & 0xFFFF); 7846c7c4447SThomas Chou 7856c7c4447SThomas Chou /* Set the MAC address */ 7866c7c4447SThomas Chou mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0; 7876c7c4447SThomas Chou mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1; 7886c7c4447SThomas Chou 7896c7c4447SThomas Chou /* Set the MAC address */ 7906c7c4447SThomas Chou mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0; 7916c7c4447SThomas Chou mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1; 7926c7c4447SThomas Chou 7936c7c4447SThomas Chou /* Set the MAC address */ 7946c7c4447SThomas Chou mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0; 7956c7c4447SThomas Chou mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1; 7966c7c4447SThomas Chou 7976c7c4447SThomas Chou /* Set the MAC address */ 7986c7c4447SThomas Chou mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0; 7996c7c4447SThomas Chou mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1; 8006c7c4447SThomas Chou return 0; 8016c7c4447SThomas Chou } 8026c7c4447SThomas Chou 803c960b13eSThomas Chou static int tse_eth_init(struct eth_device *dev, bd_t * bd) 804c960b13eSThomas Chou { 805c960b13eSThomas Chou int dat; 806c960b13eSThomas Chou struct altera_tse_priv *priv = dev->priv; 807c960b13eSThomas Chou volatile struct alt_tse_mac *mac_dev = priv->mac_dev; 808c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; 809c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; 810c960b13eSThomas Chou volatile struct alt_sgdma_descriptor *rx_desc_cur = 811c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0]; 812c960b13eSThomas Chou 813c960b13eSThomas Chou /* stop controller */ 814c960b13eSThomas Chou debug("Reseting TSE & SGDMAs\n"); 815c960b13eSThomas Chou tse_eth_reset(dev); 816c960b13eSThomas Chou 817c960b13eSThomas Chou /* start the phy */ 818c960b13eSThomas Chou debug("Configuring PHY\n"); 819c960b13eSThomas Chou phy_run_commands(priv, priv->phyinfo->startup); 820c960b13eSThomas Chou 821c960b13eSThomas Chou /* need to create sgdma */ 822c960b13eSThomas Chou debug("Configuring tx desc\n"); 823c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 824c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[0], 825c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&tx_desc[1], 826c960b13eSThomas Chou (unsigned int *)NULL, /* read addr */ 827c960b13eSThomas Chou (unsigned int *)0, 828c960b13eSThomas Chou 0, /* length or EOP ,will change for each tx */ 829c960b13eSThomas Chou 0x1, /* gen eop */ 830c960b13eSThomas Chou 0x0, /* read fixed */ 831c960b13eSThomas Chou 0x1, /* write fixed or sop */ 832c960b13eSThomas Chou 0x0, /* read burst */ 833c960b13eSThomas Chou 0x0, /* write burst */ 834c960b13eSThomas Chou 0x0 /* channel */ 835c960b13eSThomas Chou ); 836c960b13eSThomas Chou debug("Configuring rx desc\n"); 837c960b13eSThomas Chou flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); 838c960b13eSThomas Chou alt_sgdma_construct_descriptor_burst( 839c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[0], 840c960b13eSThomas Chou (volatile struct alt_sgdma_descriptor *)&rx_desc[1], 841c960b13eSThomas Chou (unsigned int)0x0, /* read addr */ 842c960b13eSThomas Chou (unsigned int *)NetRxPackets[0], 843c960b13eSThomas Chou 0x0, /* length or EOP */ 844c960b13eSThomas Chou 0x0, /* gen eop */ 845c960b13eSThomas Chou 0x0, /* read fixed */ 846c960b13eSThomas Chou 0x0, /* write fixed or sop */ 847c960b13eSThomas Chou 0x0, /* read burst */ 848c960b13eSThomas Chou 0x0, /* write burst */ 849c960b13eSThomas Chou 0x0 /* channel */ 850c960b13eSThomas Chou ); 851c960b13eSThomas Chou /* start rx async transfer */ 852c960b13eSThomas Chou debug("Starting rx sgdma\n"); 853c960b13eSThomas Chou alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur); 854c960b13eSThomas Chou 855c960b13eSThomas Chou /* start TSE */ 856c960b13eSThomas Chou debug("Configuring TSE Mac\n"); 857c960b13eSThomas Chou /* Initialize MAC registers */ 858c960b13eSThomas Chou mac_dev->max_frame_length = PKTSIZE_ALIGN; 859c960b13eSThomas Chou mac_dev->rx_almost_empty_threshold = 8; 860c960b13eSThomas Chou mac_dev->rx_almost_full_threshold = 8; 861c960b13eSThomas Chou mac_dev->tx_almost_empty_threshold = 8; 862c960b13eSThomas Chou mac_dev->tx_almost_full_threshold = 3; 863c960b13eSThomas Chou mac_dev->tx_sel_empty_threshold = 864c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 865c960b13eSThomas Chou mac_dev->tx_sel_full_threshold = 0; 866c960b13eSThomas Chou mac_dev->rx_sel_empty_threshold = 867c960b13eSThomas Chou CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; 868c960b13eSThomas Chou mac_dev->rx_sel_full_threshold = 0; 869c960b13eSThomas Chou 870c960b13eSThomas Chou /* NO Shift */ 871c960b13eSThomas Chou mac_dev->rx_cmd_stat.bits.rx_shift16 = 0; 872c960b13eSThomas Chou mac_dev->tx_cmd_stat.bits.tx_shift16 = 0; 873c960b13eSThomas Chou 874c960b13eSThomas Chou /* enable MAC */ 875c960b13eSThomas Chou dat = 0; 876c960b13eSThomas Chou dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; 877c960b13eSThomas Chou 878c960b13eSThomas Chou mac_dev->command_config.image = dat; 879c960b13eSThomas Chou 880c960b13eSThomas Chou /* configure the TSE core */ 881c960b13eSThomas Chou /* -- output clocks, */ 882c960b13eSThomas Chou /* -- and later config stuff for SGMII */ 883c960b13eSThomas Chou if (priv->link) { 884c960b13eSThomas Chou debug("Adjusting TSE to link speed\n"); 885c960b13eSThomas Chou tse_adjust_link(priv); 886c960b13eSThomas Chou } 887c960b13eSThomas Chou 888c960b13eSThomas Chou return priv->link ? 0 : -1; 889c960b13eSThomas Chou } 890c960b13eSThomas Chou 891c960b13eSThomas Chou /* TSE init code */ 892c960b13eSThomas Chou int altera_tse_initialize(u8 dev_num, int mac_base, 893b962ac79SJoachim Foerster int sgdma_rx_base, int sgdma_tx_base, 894b962ac79SJoachim Foerster u32 sgdma_desc_base, u32 sgdma_desc_size) 895c960b13eSThomas Chou { 896c960b13eSThomas Chou struct altera_tse_priv *priv; 897c960b13eSThomas Chou struct eth_device *dev; 898c960b13eSThomas Chou struct alt_sgdma_descriptor *rx_desc; 899c960b13eSThomas Chou struct alt_sgdma_descriptor *tx_desc; 900c960b13eSThomas Chou unsigned long dma_handle; 901c960b13eSThomas Chou 902c960b13eSThomas Chou dev = (struct eth_device *)malloc(sizeof *dev); 903c960b13eSThomas Chou 904c960b13eSThomas Chou if (NULL == dev) 905c960b13eSThomas Chou return 0; 906c960b13eSThomas Chou 907c960b13eSThomas Chou memset(dev, 0, sizeof *dev); 908c960b13eSThomas Chou 909c960b13eSThomas Chou priv = malloc(sizeof(*priv)); 910c960b13eSThomas Chou 911c960b13eSThomas Chou if (!priv) { 912c960b13eSThomas Chou free(dev); 913c960b13eSThomas Chou return 0; 914c960b13eSThomas Chou } 915b962ac79SJoachim Foerster if (sgdma_desc_size) { 916b962ac79SJoachim Foerster if (sgdma_desc_size < (sizeof(*tx_desc) * (3 + PKTBUFSRX))) { 917b962ac79SJoachim Foerster printf("ALTERA_TSE-%hu: " 918b962ac79SJoachim Foerster "descriptor memory is too small\n", dev_num); 919b962ac79SJoachim Foerster free(priv); 920b962ac79SJoachim Foerster free(dev); 921b962ac79SJoachim Foerster return 0; 922b962ac79SJoachim Foerster } 923b962ac79SJoachim Foerster tx_desc = (struct alt_sgdma_descriptor *)sgdma_desc_base; 924b962ac79SJoachim Foerster } else { 925c960b13eSThomas Chou tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), 926c960b13eSThomas Chou &dma_handle); 927b962ac79SJoachim Foerster } 928b962ac79SJoachim Foerster 929c960b13eSThomas Chou rx_desc = tx_desc + 2; 930c960b13eSThomas Chou debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc); 931c960b13eSThomas Chou debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc); 932c960b13eSThomas Chou 933c960b13eSThomas Chou if (!tx_desc) { 934c960b13eSThomas Chou free(priv); 935c960b13eSThomas Chou free(dev); 936c960b13eSThomas Chou return 0; 937c960b13eSThomas Chou } 938c960b13eSThomas Chou memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1)); 939c960b13eSThomas Chou memset(tx_desc, 0, (sizeof *tx_desc) * 2); 940c960b13eSThomas Chou 941c960b13eSThomas Chou /* initialize tse priv */ 942c960b13eSThomas Chou priv->mac_dev = (volatile struct alt_tse_mac *)mac_base; 943c960b13eSThomas Chou priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base; 944c960b13eSThomas Chou priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base; 945c960b13eSThomas Chou priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR; 946c960b13eSThomas Chou priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS; 947c960b13eSThomas Chou priv->rx_desc = rx_desc; 948c960b13eSThomas Chou priv->tx_desc = tx_desc; 949c960b13eSThomas Chou 950c960b13eSThomas Chou /* init eth structure */ 951c960b13eSThomas Chou dev->priv = priv; 952c960b13eSThomas Chou dev->init = tse_eth_init; 953c960b13eSThomas Chou dev->halt = tse_eth_halt; 954c960b13eSThomas Chou dev->send = tse_eth_send; 955c960b13eSThomas Chou dev->recv = tse_eth_rx; 9566c7c4447SThomas Chou dev->write_hwaddr = tse_set_mac_address; 957c960b13eSThomas Chou sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num); 958c960b13eSThomas Chou 959c960b13eSThomas Chou eth_register(dev); 960c960b13eSThomas Chou 961c960b13eSThomas Chou #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) 962c960b13eSThomas Chou miiphy_register(dev->name, altera_tse_miiphy_read, 963c960b13eSThomas Chou altera_tse_miiphy_write); 964c960b13eSThomas Chou #endif 965c960b13eSThomas Chou 966c960b13eSThomas Chou init_phy(dev); 967c960b13eSThomas Chou 968c960b13eSThomas Chou return 1; 969c960b13eSThomas Chou } 970