| #include <linux/delay.h> |
| #include <linux/if_ether.h> |
| #include <linux/ioport.h> |
| #include <linux/mv643xx.h> |
| #include <linux/platform_device.h> |
| |
| #include "ocelot_3_fpga.h" |
| |
| #if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) |
| |
| static struct resource mv643xx_eth_shared_resources[] = { |
| [0] = { |
| .name = "ethernet shared base", |
| .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, |
| .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + |
| MV643XX_ETH_SHARED_REGS_SIZE - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| }; |
| |
| static struct platform_device mv643xx_eth_shared_device = { |
| .name = MV643XX_ETH_SHARED_NAME, |
| .id = 0, |
| .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), |
| .resource = mv643xx_eth_shared_resources, |
| }; |
| |
| #define MV_SRAM_BASE 0xfe000000UL |
| #define MV_SRAM_SIZE (256 * 1024) |
| |
| #define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4) |
| #define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4) |
| |
| #define MV_SRAM_BASE_ETH0 MV_SRAM_BASE |
| #define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2)) |
| |
| #define MV64x60_IRQ_ETH_0 48 |
| #define MV64x60_IRQ_ETH_1 49 |
| #define MV64x60_IRQ_ETH_2 50 |
| |
| #ifdef CONFIG_MV643XX_ETH_0 |
| |
| static struct resource mv64x60_eth0_resources[] = { |
| [0] = { |
| .name = "eth0 irq", |
| .start = MV64x60_IRQ_ETH_0, |
| .end = MV64x60_IRQ_ETH_0, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static char eth0_mac_addr[ETH_ALEN]; |
| |
| static struct mv643xx_eth_platform_data eth0_pd = { |
| .mac_addr = eth0_mac_addr, |
| |
| .tx_sram_addr = MV_SRAM_BASE_ETH0, |
| .tx_sram_size = MV_SRAM_TXRING_SIZE, |
| .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, |
| |
| .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE, |
| .rx_sram_size = MV_SRAM_RXRING_SIZE, |
| .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, |
| }; |
| |
| static struct platform_device eth0_device = { |
| .name = MV643XX_ETH_NAME, |
| .id = 0, |
| .num_resources = ARRAY_SIZE(mv64x60_eth0_resources), |
| .resource = mv64x60_eth0_resources, |
| .dev = { |
| .platform_data = ð0_pd, |
| }, |
| }; |
| #endif /* CONFIG_MV643XX_ETH_0 */ |
| |
| #ifdef CONFIG_MV643XX_ETH_1 |
| |
| static struct resource mv64x60_eth1_resources[] = { |
| [0] = { |
| .name = "eth1 irq", |
| .start = MV64x60_IRQ_ETH_1, |
| .end = MV64x60_IRQ_ETH_1, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static char eth1_mac_addr[ETH_ALEN]; |
| |
| static struct mv643xx_eth_platform_data eth1_pd = { |
| .mac_addr = eth1_mac_addr, |
| |
| .tx_sram_addr = MV_SRAM_BASE_ETH1, |
| .tx_sram_size = MV_SRAM_TXRING_SIZE, |
| .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, |
| |
| .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE, |
| .rx_sram_size = MV_SRAM_RXRING_SIZE, |
| .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, |
| }; |
| |
| static struct platform_device eth1_device = { |
| .name = MV643XX_ETH_NAME, |
| .id = 1, |
| .num_resources = ARRAY_SIZE(mv64x60_eth1_resources), |
| .resource = mv64x60_eth1_resources, |
| .dev = { |
| .platform_data = ð1_pd, |
| }, |
| }; |
| #endif /* CONFIG_MV643XX_ETH_1 */ |
| |
| #ifdef CONFIG_MV643XX_ETH_2 |
| |
| static struct resource mv64x60_eth2_resources[] = { |
| [0] = { |
| .name = "eth2 irq", |
| .start = MV64x60_IRQ_ETH_2, |
| .end = MV64x60_IRQ_ETH_2, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static char eth2_mac_addr[ETH_ALEN]; |
| |
| static struct mv643xx_eth_platform_data eth2_pd = { |
| .mac_addr = eth2_mac_addr, |
| }; |
| |
| static struct platform_device eth2_device = { |
| .name = MV643XX_ETH_NAME, |
| .id = 2, |
| .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), |
| .resource = mv64x60_eth2_resources, |
| .dev = { |
| .platform_data = ð2_pd, |
| }, |
| }; |
| #endif /* CONFIG_MV643XX_ETH_2 */ |
| |
| static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { |
| &mv643xx_eth_shared_device, |
| #ifdef CONFIG_MV643XX_ETH_0 |
| ð0_device, |
| #endif |
| #ifdef CONFIG_MV643XX_ETH_1 |
| ð1_device, |
| #endif |
| #ifdef CONFIG_MV643XX_ETH_2 |
| ð2_device, |
| #endif |
| }; |
| |
| static u8 __init exchange_bit(u8 val, u8 cs) |
| { |
| /* place the data */ |
| OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); |
| udelay(1); |
| |
| /* turn the clock on */ |
| OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); |
| udelay(1); |
| |
| /* turn the clock off and read-strobe */ |
| OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); |
| |
| /* return the data */ |
| return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1; |
| } |
| |
| static void __init get_mac(char dest[6]) |
| { |
| u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| int i,j; |
| |
| for (i = 0; i < 12; i++) |
| exchange_bit(read_opcode[i], 1); |
| |
| for (j = 0; j < 6; j++) { |
| dest[j] = 0; |
| for (i = 0; i < 8; i++) { |
| dest[j] <<= 1; |
| dest[j] |= exchange_bit(0, 1); |
| } |
| } |
| |
| /* turn off CS */ |
| exchange_bit(0,0); |
| } |
| |
| /* |
| * Copy and increment ethernet MAC address by a small value. |
| * |
| * This is useful for systems where the only one MAC address is stored in |
| * non-volatile memory for multiple ports. |
| */ |
| static inline void eth_mac_add(unsigned char *dst, unsigned char *src, |
| unsigned int add) |
| { |
| int i; |
| |
| BUG_ON(add >= 256); |
| |
| for (i = ETH_ALEN; i >= 0; i--) { |
| dst[i] = src[i] + add; |
| add = dst[i] < src[i]; /* compute carry */ |
| } |
| |
| WARN_ON(add); |
| } |
| |
| static int __init mv643xx_eth_add_pds(void) |
| { |
| unsigned char mac[ETH_ALEN]; |
| int ret; |
| |
| get_mac(mac); |
| #ifdef CONFIG_MV643XX_ETH_0 |
| eth_mac_add(eth1_mac_addr, mac, 0); |
| #endif |
| #ifdef CONFIG_MV643XX_ETH_1 |
| eth_mac_add(eth1_mac_addr, mac, 1); |
| #endif |
| #ifdef CONFIG_MV643XX_ETH_2 |
| eth_mac_add(eth2_mac_addr, mac, 2); |
| #endif |
| ret = platform_add_devices(mv643xx_eth_pd_devs, |
| ARRAY_SIZE(mv643xx_eth_pd_devs)); |
| |
| return ret; |
| } |
| |
| device_initcall(mv643xx_eth_add_pds); |
| |
| #endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */ |