linux/arch/mips/bcm63xx/dev-enet.c
<<
>>
Prefs
   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
  17static 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
  24static 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
  35const unsigned long *bcm63xx_regs_enetdmac;
  36EXPORT_SYMBOL(bcm63xx_regs_enetdmac);
  37
  38static __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
  46static 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
  64static 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
  71static int shared_device_registered;
  72
  73static struct resource enet0_res[] = {
  74        {
  75                .start          = -1, /* filled at runtime */
  76                .end            = -1, /* filled at runtime */
  77                .flags          = IORESOURCE_MEM,
  78        },
  79        {
  80                .start          = -1, /* filled at runtime */
  81                .flags          = IORESOURCE_IRQ,
  82        },
  83        {
  84                .start          = -1, /* filled at runtime */
  85                .flags          = IORESOURCE_IRQ,
  86        },
  87        {
  88                .start          = -1, /* filled at runtime */
  89                .flags          = IORESOURCE_IRQ,
  90        },
  91};
  92
  93static struct bcm63xx_enet_platform_data enet0_pd;
  94
  95static struct platform_device bcm63xx_enet0_device = {
  96        .name           = "bcm63xx_enet",
  97        .id             = 0,
  98        .num_resources  = ARRAY_SIZE(enet0_res),
  99        .resource       = enet0_res,
 100        .dev            = {
 101                .platform_data = &enet0_pd,
 102        },
 103};
 104
 105static struct resource enet1_res[] = {
 106        {
 107                .start          = -1, /* filled at runtime */
 108                .end            = -1, /* filled at runtime */
 109                .flags          = IORESOURCE_MEM,
 110        },
 111        {
 112                .start          = -1, /* filled at runtime */
 113                .flags          = IORESOURCE_IRQ,
 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
 125static struct bcm63xx_enet_platform_data enet1_pd;
 126
 127static struct platform_device bcm63xx_enet1_device = {
 128        .name           = "bcm63xx_enet",
 129        .id             = 1,
 130        .num_resources  = ARRAY_SIZE(enet1_res),
 131        .resource       = enet1_res,
 132        .dev            = {
 133                .platform_data = &enet1_pd,
 134        },
 135};
 136
 137static struct resource enetsw_res[] = {
 138        {
 139                /* start & end filled at runtime */
 140                .flags          = IORESOURCE_MEM,
 141        },
 142        {
 143                /* start filled at runtime */
 144                .flags          = IORESOURCE_IRQ,
 145        },
 146        {
 147                /* start filled at runtime */
 148                .flags          = IORESOURCE_IRQ,
 149        },
 150};
 151
 152static struct bcm63xx_enetsw_platform_data enetsw_pd;
 153
 154static struct platform_device bcm63xx_enetsw_device = {
 155        .name           = "bcm63xx_enetsw",
 156        .num_resources  = ARRAY_SIZE(enetsw_res),
 157        .resource       = enetsw_res,
 158        .dev            = {
 159                .platform_data = &enetsw_pd,
 160        },
 161};
 162
 163static int __init register_shared(void)
 164{
 165        int ret, chan_count;
 166
 167        if (shared_device_registered)
 168                return 0;
 169
 170        bcm63xx_enetdmac_regs_init();
 171
 172        shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
 173        shared_res[0].end = shared_res[0].start;
 174        if (BCMCPU_IS_6345())
 175                shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1;
 176        else
 177                shared_res[0].end += (RSET_ENETDMA_SIZE)  - 1;
 178
 179        if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
 180                chan_count = 32;
 181        else if (BCMCPU_IS_6345())
 182                chan_count = 8;
 183        else
 184                chan_count = 16;
 185
 186        shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
 187        shared_res[1].end = shared_res[1].start;
 188        shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count)  - 1;
 189
 190        shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
 191        shared_res[2].end = shared_res[2].start;
 192        shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count)  - 1;
 193
 194        ret = platform_device_register(&bcm63xx_enet_shared_device);
 195        if (ret)
 196                return ret;
 197        shared_device_registered = 1;
 198
 199        return 0;
 200}
 201
 202int __init bcm63xx_enet_register(int unit,
 203                                 const struct bcm63xx_enet_platform_data *pd)
 204{
 205        struct platform_device *pdev;
 206        struct bcm63xx_enet_platform_data *dpd;
 207        int ret;
 208
 209        if (unit > 1)
 210                return -ENODEV;
 211
 212        if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345()))
 213                return -ENODEV;
 214
 215        ret = register_shared();
 216        if (ret)
 217                return ret;
 218
 219        if (unit == 0) {
 220                enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
 221                enet0_res[0].end = enet0_res[0].start;
 222                enet0_res[0].end += RSET_ENET_SIZE - 1;
 223                enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0);
 224                enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA);
 225                enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA);
 226                pdev = &bcm63xx_enet0_device;
 227        } else {
 228                enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1);
 229                enet1_res[0].end = enet1_res[0].start;
 230                enet1_res[0].end += RSET_ENET_SIZE - 1;
 231                enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1);
 232                enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA);
 233                enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA);
 234                pdev = &bcm63xx_enet1_device;
 235        }
 236
 237        /* copy given platform data */
 238        dpd = pdev->dev.platform_data;
 239        memcpy(dpd, pd, sizeof(*pd));
 240
 241        /* adjust them in case internal phy is used */
 242        if (dpd->use_internal_phy) {
 243
 244                /* internal phy only exists for enet0 */
 245                if (unit == 1)
 246                        return -ENODEV;
 247
 248                dpd->phy_id = 1;
 249                dpd->has_phy_interrupt = 1;
 250                dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
 251        }
 252
 253        dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
 254        dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
 255        if (BCMCPU_IS_6345()) {
 256                dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK;
 257                dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK;
 258                dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK;
 259                dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK;
 260                dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK;
 261                dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH;
 262                dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT;
 263        } else {
 264                dpd->dma_has_sram = true;
 265                dpd->dma_chan_width = ENETDMA_CHAN_WIDTH;
 266        }
 267
 268        ret = platform_device_register(pdev);
 269        if (ret)
 270                return ret;
 271        return 0;
 272}
 273
 274int __init
 275bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
 276{
 277        int ret;
 278
 279        if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
 280                return -ENODEV;
 281
 282        ret = register_shared();
 283        if (ret)
 284                return ret;
 285
 286        enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
 287        enetsw_res[0].end = enetsw_res[0].start;
 288        enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
 289        enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
 290        enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
 291        if (!enetsw_res[2].start)
 292                enetsw_res[2].start = -1;
 293
 294        memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
 295
 296        if (BCMCPU_IS_6328())
 297                enetsw_pd.num_ports = ENETSW_PORTS_6328;
 298        else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
 299                enetsw_pd.num_ports = ENETSW_PORTS_6368;
 300
 301        enetsw_pd.dma_has_sram = true;
 302        enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH;
 303        enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
 304        enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
 305
 306        ret = platform_device_register(&bcm63xx_enetsw_device);
 307        if (ret)
 308                return ret;
 309
 310        return 0;
 311}
 312