1#include <linux/delay.h> 2#include <linux/if_ether.h> 3#include <linux/ioport.h> 4#include <linux/mv643xx.h> 5#include <linux/platform_device.h> 6 7#include "ocelot_c_fpga.h" 8 9#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) 10 11static struct resource mv643xx_eth_shared_resources[] = { 12 [0] = { 13 .name = "ethernet shared base", 14 .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, 15 .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + 16 MV643XX_ETH_SHARED_REGS_SIZE - 1, 17 .flags = IORESOURCE_MEM, 18 }, 19}; 20 21static struct platform_device mv643xx_eth_shared_device = { 22 .name = MV643XX_ETH_SHARED_NAME, 23 .id = 0, 24 .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), 25 .resource = mv643xx_eth_shared_resources, 26}; 27 28#define MV_SRAM_BASE 0xfe000000UL 29#define MV_SRAM_SIZE (256 * 1024) 30 31#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4) 32#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4) 33 34#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE 35#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2)) 36 37#define MV64x60_IRQ_ETH_0 48 38#define MV64x60_IRQ_ETH_1 49 39 40static struct resource mv64x60_eth0_resources[] = { 41 [0] = { 42 .name = "eth0 irq", 43 .start = MV64x60_IRQ_ETH_0, 44 .end = MV64x60_IRQ_ETH_0, 45 .flags = IORESOURCE_IRQ, 46 }, 47}; 48 49static struct mv643xx_eth_platform_data eth0_pd = { 50 .port_number = 0, 51 52 .tx_sram_addr = MV_SRAM_BASE_ETH0, 53 .tx_sram_size = MV_SRAM_TXRING_SIZE, 54 .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, 55 56 .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE, 57 .rx_sram_size = MV_SRAM_RXRING_SIZE, 58 .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, 59}; 60 61static struct platform_device eth0_device = { 62 .name = MV643XX_ETH_NAME, 63 .id = 0, 64 .num_resources = ARRAY_SIZE(mv64x60_eth0_resources), 65 .resource = mv64x60_eth0_resources, 66 .dev = { 67 .platform_data = ð0_pd, 68 }, 69}; 70 71static struct resource mv64x60_eth1_resources[] = { 72 [0] = { 73 .name = "eth1 irq", 74 .start = MV64x60_IRQ_ETH_1, 75 .end = MV64x60_IRQ_ETH_1, 76 .flags = IORESOURCE_IRQ, 77 }, 78}; 79 80static struct mv643xx_eth_platform_data eth1_pd = { 81 .port_number = 1, 82 83 .tx_sram_addr = MV_SRAM_BASE_ETH1, 84 .tx_sram_size = MV_SRAM_TXRING_SIZE, 85 .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, 86 87 .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE, 88 .rx_sram_size = MV_SRAM_RXRING_SIZE, 89 .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, 90}; 91 92static struct platform_device eth1_device = { 93 .name = MV643XX_ETH_NAME, 94 .id = 1, 95 .num_resources = ARRAY_SIZE(mv64x60_eth1_resources), 96 .resource = mv64x60_eth1_resources, 97 .dev = { 98 .platform_data = ð1_pd, 99 }, 100}; 101 102static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { 103 &mv643xx_eth_shared_device, 104 ð0_device, 105 ð1_device, 106 /* The third port is not wired up on the Ocelot C */ 107}; 108 109static u8 __init exchange_bit(u8 val, u8 cs) 110{ 111 /* place the data */ 112 OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); 113 udelay(1); 114 115 /* turn the clock on */ 116 OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); 117 udelay(1); 118 119 /* turn the clock off and read-strobe */ 120 OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); 121 122 /* return the data */ 123 return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1; 124} 125 126static void __init get_mac(char dest[6]) 127{ 128 u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 129 int i,j; 130 131 for (i = 0; i < 12; i++) 132 exchange_bit(read_opcode[i], 1); 133 134 for (j = 0; j < 6; j++) { 135 dest[j] = 0; 136 for (i = 0; i < 8; i++) { 137 dest[j] <<= 1; 138 dest[j] |= exchange_bit(0, 1); 139 } 140 } 141 142 /* turn off CS */ 143 exchange_bit(0,0); 144} 145 146/* 147 * Copy and increment ethernet MAC address by a small value. 148 * 149 * This is useful for systems where the only one MAC address is stored in 150 * non-volatile memory for multiple ports. 151 */ 152static inline void eth_mac_add(unsigned char *dst, unsigned char *src, 153 unsigned int add) 154{ 155 int i; 156 157 BUG_ON(add >= 256); 158 159 for (i = ETH_ALEN; i >= 0; i--) { 160 dst[i] = src[i] + add; 161 add = dst[i] < src[i]; /* compute carry */ 162 } 163 164 WARN_ON(add); 165} 166 167static int __init mv643xx_eth_add_pds(void) 168{ 169 unsigned char mac[ETH_ALEN]; 170 int ret; 171 172 get_mac(mac); 173 eth_mac_add(eth0_pd.mac_addr, mac, 0); 174 eth_mac_add(eth1_pd.mac_addr, mac, 1); 175 ret = platform_add_devices(mv643xx_eth_pd_devs, 176 ARRAY_SIZE(mv643xx_eth_pd_devs)); 177 178 return ret; 179} 180 181device_initcall(mv643xx_eth_add_pds); 182 183#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */ 184