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