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 <linux/export.h> 13 #include <bcm63xx_dev_enet.h> 14 #include <bcm63xx_io.h> 15 #include <bcm63xx_regs.h> 16 17 static const unsigned long bcm6348_regs_enetdmac[] = { 18 [ENETDMAC_CHANCFG] = ENETDMAC_CHANCFG_REG, 19 [ENETDMAC_IR] = ENETDMAC_IR_REG, 20 [ENETDMAC_IRMASK] = ENETDMAC_IRMASK_REG, 21 [ENETDMAC_MAXBURST] = ENETDMAC_MAXBURST_REG, 22 }; 23 24 static const unsigned long bcm6345_regs_enetdmac[] = { 25 [ENETDMAC_CHANCFG] = ENETDMA_6345_CHANCFG_REG, 26 [ENETDMAC_IR] = ENETDMA_6345_IR_REG, 27 [ENETDMAC_IRMASK] = ENETDMA_6345_IRMASK_REG, 28 [ENETDMAC_MAXBURST] = ENETDMA_6345_MAXBURST_REG, 29 [ENETDMAC_BUFALLOC] = ENETDMA_6345_BUFALLOC_REG, 30 [ENETDMAC_RSTART] = ENETDMA_6345_RSTART_REG, 31 [ENETDMAC_FC] = ENETDMA_6345_FC_REG, 32 [ENETDMAC_LEN] = ENETDMA_6345_LEN_REG, 33 }; 34 35 const unsigned long *bcm63xx_regs_enetdmac; 36 EXPORT_SYMBOL(bcm63xx_regs_enetdmac); 37 38 static __init void bcm63xx_enetdmac_regs_init(void) 39 { 40 if (BCMCPU_IS_6345()) 41 bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac; 42 else 43 bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac; 44 } 45 46 static struct resource shared_res[] = { 47 { 48 .start = -1, /* filled at runtime */ 49 .end = -1, /* filled at runtime */ 50 .flags = IORESOURCE_MEM, 51 }, 52 { 53 .start = -1, /* filled at runtime */ 54 .end = -1, /* filled at runtime */ 55 .flags = IORESOURCE_MEM, 56 }, 57 { 58 .start = -1, /* filled at runtime */ 59 .end = -1, /* filled at runtime */ 60 .flags = IORESOURCE_MEM, 61 }, 62 }; 63 64 static struct platform_device bcm63xx_enet_shared_device = { 65 .name = "bcm63xx_enet_shared", 66 .id = 0, 67 .num_resources = ARRAY_SIZE(shared_res), 68 .resource = shared_res, 69 }; 70 71 static int shared_device_registered; 72 73 static u64 enet_dmamask = DMA_BIT_MASK(32); 74 75 static struct resource enet0_res[] = { 76 { 77 .start = -1, /* filled at runtime */ 78 .end = -1, /* filled at runtime */ 79 .flags = IORESOURCE_MEM, 80 }, 81 { 82 .start = -1, /* filled at runtime */ 83 .flags = IORESOURCE_IRQ, 84 }, 85 { 86 .start = -1, /* filled at runtime */ 87 .flags = IORESOURCE_IRQ, 88 }, 89 { 90 .start = -1, /* filled at runtime */ 91 .flags = IORESOURCE_IRQ, 92 }, 93 }; 94 95 static struct bcm63xx_enet_platform_data enet0_pd; 96 97 static struct platform_device bcm63xx_enet0_device = { 98 .name = "bcm63xx_enet", 99 .id = 0, 100 .num_resources = ARRAY_SIZE(enet0_res), 101 .resource = enet0_res, 102 .dev = { 103 .platform_data = &enet0_pd, 104 .dma_mask = &enet_dmamask, 105 .coherent_dma_mask = DMA_BIT_MASK(32), 106 }, 107 }; 108 109 static struct resource enet1_res[] = { 110 { 111 .start = -1, /* filled at runtime */ 112 .end = -1, /* filled at runtime */ 113 .flags = IORESOURCE_MEM, 114 }, 115 { 116 .start = -1, /* filled at runtime */ 117 .flags = IORESOURCE_IRQ, 118 }, 119 { 120 .start = -1, /* filled at runtime */ 121 .flags = IORESOURCE_IRQ, 122 }, 123 { 124 .start = -1, /* filled at runtime */ 125 .flags = IORESOURCE_IRQ, 126 }, 127 }; 128 129 static struct bcm63xx_enet_platform_data enet1_pd; 130 131 static struct platform_device bcm63xx_enet1_device = { 132 .name = "bcm63xx_enet", 133 .id = 1, 134 .num_resources = ARRAY_SIZE(enet1_res), 135 .resource = enet1_res, 136 .dev = { 137 .platform_data = &enet1_pd, 138 .dma_mask = &enet_dmamask, 139 .coherent_dma_mask = DMA_BIT_MASK(32), 140 }, 141 }; 142 143 static struct resource enetsw_res[] = { 144 { 145 /* start & end filled at runtime */ 146 .flags = IORESOURCE_MEM, 147 }, 148 { 149 /* start filled at runtime */ 150 .flags = IORESOURCE_IRQ, 151 }, 152 { 153 /* start filled at runtime */ 154 .flags = IORESOURCE_IRQ, 155 }, 156 }; 157 158 static struct bcm63xx_enetsw_platform_data enetsw_pd; 159 160 static struct platform_device bcm63xx_enetsw_device = { 161 .name = "bcm63xx_enetsw", 162 .num_resources = ARRAY_SIZE(enetsw_res), 163 .resource = enetsw_res, 164 .dev = { 165 .platform_data = &enetsw_pd, 166 .dma_mask = &enet_dmamask, 167 .coherent_dma_mask = DMA_BIT_MASK(32), 168 }, 169 }; 170 171 static int __init register_shared(void) 172 { 173 int ret, chan_count; 174 175 if (shared_device_registered) 176 return 0; 177 178 bcm63xx_enetdmac_regs_init(); 179 180 shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); 181 shared_res[0].end = shared_res[0].start; 182 if (BCMCPU_IS_6345()) 183 shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1; 184 else 185 shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; 186 187 if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) 188 chan_count = 32; 189 else if (BCMCPU_IS_6345()) 190 chan_count = 8; 191 else 192 chan_count = 16; 193 194 shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); 195 shared_res[1].end = shared_res[1].start; 196 shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1; 197 198 shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); 199 shared_res[2].end = shared_res[2].start; 200 shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1; 201 202 ret = platform_device_register(&bcm63xx_enet_shared_device); 203 if (ret) 204 return ret; 205 shared_device_registered = 1; 206 207 return 0; 208 } 209 210 int __init bcm63xx_enet_register(int unit, 211 const struct bcm63xx_enet_platform_data *pd) 212 { 213 struct platform_device *pdev; 214 struct bcm63xx_enet_platform_data *dpd; 215 int ret; 216 217 if (unit > 1) 218 return -ENODEV; 219 220 if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345())) 221 return -ENODEV; 222 223 ret = register_shared(); 224 if (ret) 225 return ret; 226 227 if (unit == 0) { 228 enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); 229 enet0_res[0].end = enet0_res[0].start; 230 enet0_res[0].end += RSET_ENET_SIZE - 1; 231 enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0); 232 enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA); 233 enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA); 234 pdev = &bcm63xx_enet0_device; 235 } else { 236 enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1); 237 enet1_res[0].end = enet1_res[0].start; 238 enet1_res[0].end += RSET_ENET_SIZE - 1; 239 enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1); 240 enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA); 241 enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA); 242 pdev = &bcm63xx_enet1_device; 243 } 244 245 /* copy given platform data */ 246 dpd = pdev->dev.platform_data; 247 memcpy(dpd, pd, sizeof(*pd)); 248 249 /* adjust them in case internal phy is used */ 250 if (dpd->use_internal_phy) { 251 252 /* internal phy only exists for enet0 */ 253 if (unit == 1) 254 return -ENODEV; 255 256 dpd->phy_id = 1; 257 dpd->has_phy_interrupt = 1; 258 dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY); 259 } 260 261 dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; 262 dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; 263 if (BCMCPU_IS_6345()) { 264 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK; 265 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK; 266 dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK; 267 dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK; 268 dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK; 269 dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH; 270 dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT; 271 } else { 272 dpd->dma_has_sram = true; 273 dpd->dma_chan_width = ENETDMA_CHAN_WIDTH; 274 } 275 276 if (unit == 0) { 277 dpd->rx_chan = 0; 278 dpd->tx_chan = 1; 279 } else { 280 dpd->rx_chan = 2; 281 dpd->tx_chan = 3; 282 } 283 284 ret = platform_device_register(pdev); 285 if (ret) 286 return ret; 287 return 0; 288 } 289 290 int __init 291 bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd) 292 { 293 int ret; 294 295 if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368()) 296 return -ENODEV; 297 298 ret = register_shared(); 299 if (ret) 300 return ret; 301 302 enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW); 303 enetsw_res[0].end = enetsw_res[0].start; 304 enetsw_res[0].end += RSET_ENETSW_SIZE - 1; 305 enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0); 306 enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0); 307 if (!enetsw_res[2].start) 308 enetsw_res[2].start = -1; 309 310 memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd)); 311 312 if (BCMCPU_IS_6328()) 313 enetsw_pd.num_ports = ENETSW_PORTS_6328; 314 else if (BCMCPU_IS_6362() || BCMCPU_IS_6368()) 315 enetsw_pd.num_ports = ENETSW_PORTS_6368; 316 317 enetsw_pd.dma_has_sram = true; 318 enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH; 319 enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; 320 enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; 321 322 ret = platform_device_register(&bcm63xx_enetsw_device); 323 if (ret) 324 return ret; 325 326 return 0; 327 } 328
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.