linux/arch/powerpc/sysdev/tsi108_dev.c
<<
>>
Prefs
   1/*
   2 * tsi108/109 device setup code
   3 *
   4 * Maintained by Roy Zang < tie-fei.zang@freescale.com >
   5 *
   6 * This program is free software; you can redistribute  it and/or modify it
   7 * under  the terms of  the GNU General  Public License as published by the
   8 * Free Software Foundation;  either version 2 of the  License, or (at your
   9 * option) any later version.
  10 */
  11
  12#include <linux/stddef.h>
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/errno.h>
  16#include <linux/major.h>
  17#include <linux/delay.h>
  18#include <linux/irq.h>
  19#include <linux/export.h>
  20#include <linux/device.h>
  21#include <linux/platform_device.h>
  22#include <linux/of_net.h>
  23#include <asm/tsi108.h>
  24
  25#include <linux/atomic.h>
  26#include <asm/io.h>
  27#include <asm/irq.h>
  28#include <asm/prom.h>
  29#include <mm/mmu_decl.h>
  30
  31#undef DEBUG
  32
  33#ifdef DEBUG
  34#define DBG(fmt...) do { printk(fmt); } while(0)
  35#else
  36#define DBG(fmt...) do { } while(0)
  37#endif
  38
  39static phys_addr_t tsi108_csr_base = -1;
  40
  41phys_addr_t get_csrbase(void)
  42{
  43        struct device_node *tsi;
  44
  45        if (tsi108_csr_base != -1)
  46                return tsi108_csr_base;
  47
  48        tsi = of_find_node_by_type(NULL, "tsi-bridge");
  49        if (tsi) {
  50                unsigned int size;
  51                const void *prop = of_get_property(tsi, "reg", &size);
  52                tsi108_csr_base = of_translate_address(tsi, prop);
  53                of_node_put(tsi);
  54        };
  55        return tsi108_csr_base;
  56}
  57
  58u32 get_vir_csrbase(void)
  59{
  60        return (u32) (ioremap(get_csrbase(), 0x10000));
  61}
  62
  63EXPORT_SYMBOL(get_csrbase);
  64EXPORT_SYMBOL(get_vir_csrbase);
  65
  66static int __init tsi108_eth_of_init(void)
  67{
  68        struct device_node *np;
  69        unsigned int i = 0;
  70        struct platform_device *tsi_eth_dev;
  71        struct resource res;
  72        int ret;
  73
  74        for_each_compatible_node(np, "network", "tsi108-ethernet") {
  75                struct resource r[2];
  76                struct device_node *phy, *mdio;
  77                hw_info tsi_eth_data;
  78                const unsigned int *phy_id;
  79                const void *mac_addr;
  80                const phandle *ph;
  81
  82                memset(r, 0, sizeof(r));
  83                memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
  84
  85                ret = of_address_to_resource(np, 0, &r[0]);
  86                DBG("%s: name:start->end = %s:%pR\n",
  87                    __func__, r[0].name, &r[0]);
  88                if (ret)
  89                        goto err;
  90
  91                r[1].name = "tx";
  92                r[1].start = irq_of_parse_and_map(np, 0);
  93                r[1].end = irq_of_parse_and_map(np, 0);
  94                r[1].flags = IORESOURCE_IRQ;
  95                DBG("%s: name:start->end = %s:%pR\n",
  96                        __func__, r[1].name, &r[1]);
  97
  98                tsi_eth_dev =
  99                    platform_device_register_simple("tsi-ethernet", i++, &r[0],
 100                                                    1);
 101
 102                if (IS_ERR(tsi_eth_dev)) {
 103                        ret = PTR_ERR(tsi_eth_dev);
 104                        goto err;
 105                }
 106
 107                mac_addr = of_get_mac_address(np);
 108                if (mac_addr)
 109                        memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
 110
 111                ph = of_get_property(np, "mdio-handle", NULL);
 112                mdio = of_find_node_by_phandle(*ph);
 113                ret = of_address_to_resource(mdio, 0, &res);
 114                of_node_put(mdio);
 115                if (ret)
 116                        goto unreg;
 117
 118                ph = of_get_property(np, "phy-handle", NULL);
 119                phy = of_find_node_by_phandle(*ph);
 120
 121                if (phy == NULL) {
 122                        ret = -ENODEV;
 123                        goto unreg;
 124                }
 125
 126                phy_id = of_get_property(phy, "reg", NULL);
 127
 128                tsi_eth_data.regs = r[0].start;
 129                tsi_eth_data.phyregs = res.start;
 130                tsi_eth_data.phy = *phy_id;
 131                tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0);
 132
 133                /* Some boards with the TSI108 bridge (e.g. Holly)
 134                 * have a miswiring of the ethernet PHYs which
 135                 * requires a workaround.  The special
 136                 * "txc-rxc-delay-disable" property enables this
 137                 * workaround.  FIXME: Need to port the tsi108_eth
 138                 * driver itself to phylib and use a non-misleading
 139                 * name for the workaround flag - it's not actually to
 140                 * do with the model of PHY in use */
 141                if (of_get_property(phy, "txc-rxc-delay-disable", NULL))
 142                        tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
 143                of_node_put(phy);
 144
 145                ret =
 146                    platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
 147                                             sizeof(hw_info));
 148                if (ret)
 149                        goto unreg;
 150        }
 151        return 0;
 152unreg:
 153        platform_device_unregister(tsi_eth_dev);
 154err:
 155        of_node_put(np);
 156        return ret;
 157}
 158
 159arch_initcall(tsi108_eth_of_init);
 160