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_3_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#define MV64x60_IRQ_ETH_2 50 40 41static struct resource mv64x60_eth0_resources[] = { 42 [0] = { 43 .name = "eth0 irq", 44 .start = MV64x60_IRQ_ETH_0, 45 .end = MV64x60_IRQ_ETH_0, 46 .flags = IORESOURCE_IRQ, 47 }, 48}; 49 50static struct mv643xx_eth_platform_data eth0_pd = { 51 .port_number = 0, 52 53 .tx_sram_addr = MV_SRAM_BASE_ETH0, 54 .tx_sram_size = MV_SRAM_TXRING_SIZE, 55 .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, 56 57 .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE, 58 .rx_sram_size = MV_SRAM_RXRING_SIZE, 59 .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, 60}; 61 62static struct platform_device eth0_device = { 63 .name = MV643XX_ETH_NAME, 64 .id = 0, 65 .num_resources = ARRAY_SIZE(mv64x60_eth0_resources), 66 .resource = mv64x60_eth0_resources, 67 .dev = { 68 .platform_data = ð0_pd, 69 }, 70}; 71 72static struct resource mv64x60_eth1_resources[] = { 73 [0] = { 74 .name = "eth1 irq", 75 .start = MV64x60_IRQ_ETH_1, 76 .end = MV64x60_IRQ_ETH_1, 77 .flags = IORESOURCE_IRQ, 78 }, 79}; 80 81static struct mv643xx_eth_platform_data eth1_pd = { 82 .port_number = 1, 83 84 .tx_sram_addr = MV_SRAM_BASE_ETH1, 85 .tx_sram_size = MV_SRAM_TXRING_SIZE, 86 .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, 87 88 .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE, 89 .rx_sram_size = MV_SRAM_RXRING_SIZE, 90 .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, 91}; 92 93static struct platform_device eth1_device = { 94 .name = MV643XX_ETH_NAME, 95 .id = 1, 96 .num_resources = ARRAY_SIZE(mv64x60_eth1_resources), 97 .resource = mv64x60_eth1_resources, 98 .dev = { 99 .platform_data = ð1_pd, 100 }, 101}; 102 103static struct resource mv64x60_eth2_resources[] = { 104 [0] = { 105 .name = "eth2 irq", 106 .start = MV64x60_IRQ_ETH_2, 107 .end = MV64x60_IRQ_ETH_2, 108 .flags = IORESOURCE_IRQ, 109 }, 110}; 111 112static struct mv643xx_eth_platform_data eth2_pd = { 113 .port_number = 2, 114}; 115 116static struct platform_device eth2_device = { 117 .name = MV643XX_ETH_NAME, 118 .id = 2, 119 .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), 120 .resource = mv64x60_eth2_resources, 121 .dev = { 122 .platform_data = ð2_pd, 123 }, 124}; 125 126static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { 127 &mv643xx_eth_shared_device, 128 ð0_device, 129 ð1_device, 130 ð2_device, 131}; 132 133static u8 __init exchange_bit(u8 val, u8 cs) 134{ 135 /* place the data */ 136 OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); 137 udelay(1); 138 139 /* turn the clock on */ 140 OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); 141 udelay(1); 142 143 /* turn the clock off and read-strobe */ 144 OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); 145 146 /* return the data */ 147 return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1; 148} 149 150static void __init get_mac(char dest[6]) 151{ 152 u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 153 int i,j; 154 155 for (i = 0; i < 12; i++) 156 exchange_bit(read_opcode[i], 1); 157 158 for (j = 0; j < 6; j++) { 159 dest[j] = 0; 160 for (i = 0; i < 8; i++) { 161 dest[j] <<= 1; 162 dest[j] |= exchange_bit(0, 1); 163 } 164 } 165 166 /* turn off CS */ 167 exchange_bit(0,0); 168} 169 170/* 171 * Copy and increment ethernet MAC address by a small value. 172 * 173 * This is useful for systems where the only one MAC address is stored in 174 * non-volatile memory for multiple ports. 175 */ 176static inline void eth_mac_add(unsigned char *dst, unsigned char *src, 177 unsigned int add) 178{ 179 int i; 180 181 BUG_ON(add >= 256); 182 183 for (i = ETH_ALEN; i >= 0; i--) { 184 dst[i] = src[i] + add; 185 add = dst[i] < src[i]; /* compute carry */ 186 } 187 188 WARN_ON(add); 189} 190 191static int __init mv643xx_eth_add_pds(void) 192{ 193 unsigned char mac[ETH_ALEN]; 194 int ret; 195 196 get_mac(mac); 197 eth_mac_add(eth0_pd.mac_addr, mac, 0); 198 eth_mac_add(eth1_pd.mac_addr, mac, 1); 199 eth_mac_add(eth2_pd.mac_addr, mac, 2); 200 ret = platform_add_devices(mv643xx_eth_pd_devs, 201 ARRAY_SIZE(mv643xx_eth_pd_devs)); 202 203 return ret; 204} 205 206device_initcall(mv643xx_eth_add_pds); 207 208#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */ 209