1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 */ 8 9 #include <linux/init.h> 10 #include <linux/kernel.h> 11 #include <linux/platform_device.h> 12 #include <bcm63xx_dev_enet.h> 13 #include <bcm63xx_io.h> 14 #include <bcm63xx_regs.h> 15 16 static struct resource shared_res[] = { 17 { 18 .start = -1, /* filled at runtime */ 19 .end = -1, /* filled at runtime */ 20 .flags = IORESOURCE_MEM, 21 }, 22 }; 23 24 static struct platform_device bcm63xx_enet_shared_device = { 25 .name = "bcm63xx_enet_shared", 26 .id = 0, 27 .num_resources = ARRAY_SIZE(shared_res), 28 .resource = shared_res, 29 }; 30 31 static int shared_device_registered; 32 33 static struct resource enet0_res[] = { 34 { 35 .start = -1, /* filled at runtime */ 36 .end = -1, /* filled at runtime */ 37 .flags = IORESOURCE_MEM, 38 }, 39 { 40 .start = -1, /* filled at runtime */ 41 .flags = IORESOURCE_IRQ, 42 }, 43 { 44 .start = -1, /* filled at runtime */ 45 .flags = IORESOURCE_IRQ, 46 }, 47 { 48 .start = -1, /* filled at runtime */ 49 .flags = IORESOURCE_IRQ, 50 }, 51 }; 52 53 static struct bcm63xx_enet_platform_data enet0_pd; 54 55 static struct platform_device bcm63xx_enet0_device = { 56 .name = "bcm63xx_enet", 57 .id = 0, 58 .num_resources = ARRAY_SIZE(enet0_res), 59 .resource = enet0_res, 60 .dev = { 61 .platform_data = &enet0_pd, 62 }, 63 }; 64 65 static struct resource enet1_res[] = { 66 { 67 .start = -1, /* filled at runtime */ 68 .end = -1, /* filled at runtime */ 69 .flags = IORESOURCE_MEM, 70 }, 71 { 72 .start = -1, /* filled at runtime */ 73 .flags = IORESOURCE_IRQ, 74 }, 75 { 76 .start = -1, /* filled at runtime */ 77 .flags = IORESOURCE_IRQ, 78 }, 79 { 80 .start = -1, /* filled at runtime */ 81 .flags = IORESOURCE_IRQ, 82 }, 83 }; 84 85 static struct bcm63xx_enet_platform_data enet1_pd; 86 87 static struct platform_device bcm63xx_enet1_device = { 88 .name = "bcm63xx_enet", 89 .id = 1, 90 .num_resources = ARRAY_SIZE(enet1_res), 91 .resource = enet1_res, 92 .dev = { 93 .platform_data = &enet1_pd, 94 }, 95 }; 96 97 int __init bcm63xx_enet_register(int unit, 98 const struct bcm63xx_enet_platform_data *pd) 99 { 100 struct platform_device *pdev; 101 struct bcm63xx_enet_platform_data *dpd; 102 int ret; 103 104 if (unit > 1) 105 return -ENODEV; 106 107 if (!shared_device_registered) { 108 shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); 109 shared_res[0].end = shared_res[0].start; 110 if (BCMCPU_IS_6338()) 111 shared_res[0].end += (RSET_ENETDMA_SIZE / 2) - 1; 112 else 113 shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; 114 115 ret = platform_device_register(&bcm63xx_enet_shared_device); 116 if (ret) 117 return ret; 118 shared_device_registered = 1; 119 } 120 121 if (unit == 0) { 122 enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); 123 enet0_res[0].end = enet0_res[0].start; 124 enet0_res[0].end += RSET_ENET_SIZE - 1; 125 enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0); 126 enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA); 127 enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA); 128 pdev = &bcm63xx_enet0_device; 129 } else { 130 enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1); 131 enet1_res[0].end = enet1_res[0].start; 132 enet1_res[0].end += RSET_ENET_SIZE - 1; 133 enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1); 134 enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA); 135 enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA); 136 pdev = &bcm63xx_enet1_device; 137 } 138 139 /* copy given platform data */ 140 dpd = pdev->dev.platform_data; 141 memcpy(dpd, pd, sizeof(*pd)); 142 143 /* adjust them in case internal phy is used */ 144 if (dpd->use_internal_phy) { 145 146 /* internal phy only exists for enet0 */ 147 if (unit == 1) 148 return -ENODEV; 149 150 dpd->phy_id = 1; 151 dpd->has_phy_interrupt = 1; 152 dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY); 153 } 154 155 ret = platform_device_register(pdev); 156 if (ret) 157 return ret; 158 return 0; 159 } 160