linux/drivers/net/ethernet/chelsio/cxgb/my3126.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* $Date: 2005/11/12 02:13:49 $ $RCSfile: my3126.c,v $ $Revision: 1.15 $ */
   3#include "cphy.h"
   4#include "elmer0.h"
   5#include "suni1x10gexp_regs.h"
   6
   7/* Port Reset */
   8static int my3126_reset(struct cphy *cphy, int wait)
   9{
  10        /*
  11         * This can be done through registers.  It is not required since
  12         * a full chip reset is used.
  13         */
  14        return 0;
  15}
  16
  17static int my3126_interrupt_enable(struct cphy *cphy)
  18{
  19        schedule_delayed_work(&cphy->phy_update, HZ/30);
  20        t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
  21        return 0;
  22}
  23
  24static int my3126_interrupt_disable(struct cphy *cphy)
  25{
  26        cancel_delayed_work_sync(&cphy->phy_update);
  27        return 0;
  28}
  29
  30static int my3126_interrupt_clear(struct cphy *cphy)
  31{
  32        return 0;
  33}
  34
  35#define OFFSET(REG_ADDR)    (REG_ADDR << 2)
  36
  37static int my3126_interrupt_handler(struct cphy *cphy)
  38{
  39        u32 val;
  40        u16 val16;
  41        u16 status;
  42        u32 act_count;
  43        adapter_t *adapter;
  44        adapter = cphy->adapter;
  45
  46        if (cphy->count == 50) {
  47                cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);
  48                val16 = (u16) val;
  49                status = cphy->bmsr ^ val16;
  50
  51                if (status & MDIO_STAT1_LSTATUS)
  52                        t1_link_changed(adapter, 0);
  53                cphy->bmsr = val16;
  54
  55                /* We have only enabled link change interrupts so it
  56                   must be that
  57                 */
  58                cphy->count = 0;
  59        }
  60
  61        t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL),
  62                SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
  63        t1_tpi_read(adapter,
  64                OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count);
  65        t1_tpi_read(adapter,
  66                OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val);
  67        act_count += val;
  68
  69        /* Populate elmer_gpo with the register value */
  70        t1_tpi_read(adapter, A_ELMER0_GPO, &val);
  71        cphy->elmer_gpo = val;
  72
  73        if ( (val & (1 << 8)) || (val & (1 << 19)) ||
  74             (cphy->act_count == act_count) || cphy->act_on ) {
  75                if (is_T2(adapter))
  76                        val |= (1 << 9);
  77                else if (t1_is_T1B(adapter))
  78                        val |= (1 << 20);
  79                cphy->act_on = 0;
  80        } else {
  81                if (is_T2(adapter))
  82                        val &= ~(1 << 9);
  83                else if (t1_is_T1B(adapter))
  84                        val &= ~(1 << 20);
  85                cphy->act_on = 1;
  86        }
  87
  88        t1_tpi_write(adapter, A_ELMER0_GPO, val);
  89
  90        cphy->elmer_gpo = val;
  91        cphy->act_count = act_count;
  92        cphy->count++;
  93
  94        return cphy_cause_link_change;
  95}
  96
  97static void my3126_poll(struct work_struct *work)
  98{
  99        struct cphy *cphy = container_of(work, struct cphy, phy_update.work);
 100
 101        my3126_interrupt_handler(cphy);
 102}
 103
 104static int my3126_set_loopback(struct cphy *cphy, int on)
 105{
 106        return 0;
 107}
 108
 109/* To check the activity LED */
 110static int my3126_get_link_status(struct cphy *cphy,
 111                        int *link_ok, int *speed, int *duplex, int *fc)
 112{
 113        u32 val;
 114        u16 val16;
 115        adapter_t *adapter;
 116
 117        adapter = cphy->adapter;
 118        cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);
 119        val16 = (u16) val;
 120
 121        /* Populate elmer_gpo with the register value */
 122        t1_tpi_read(adapter, A_ELMER0_GPO, &val);
 123        cphy->elmer_gpo = val;
 124
 125        *link_ok = (val16 & MDIO_STAT1_LSTATUS);
 126
 127        if (*link_ok) {
 128                /* Turn on the LED. */
 129                if (is_T2(adapter))
 130                         val &= ~(1 << 8);
 131                else if (t1_is_T1B(adapter))
 132                         val &= ~(1 << 19);
 133        } else {
 134                /* Turn off the LED. */
 135                if (is_T2(adapter))
 136                         val |= (1 << 8);
 137                else if (t1_is_T1B(adapter))
 138                         val |= (1 << 19);
 139        }
 140
 141        t1_tpi_write(adapter, A_ELMER0_GPO, val);
 142        cphy->elmer_gpo = val;
 143        *speed = SPEED_10000;
 144        *duplex = DUPLEX_FULL;
 145
 146        /* need to add flow control */
 147        if (fc)
 148                *fc = PAUSE_RX | PAUSE_TX;
 149
 150        return 0;
 151}
 152
 153static void my3126_destroy(struct cphy *cphy)
 154{
 155        kfree(cphy);
 156}
 157
 158static const struct cphy_ops my3126_ops = {
 159        .destroy                = my3126_destroy,
 160        .reset                  = my3126_reset,
 161        .interrupt_enable       = my3126_interrupt_enable,
 162        .interrupt_disable      = my3126_interrupt_disable,
 163        .interrupt_clear        = my3126_interrupt_clear,
 164        .interrupt_handler      = my3126_interrupt_handler,
 165        .get_link_status        = my3126_get_link_status,
 166        .set_loopback           = my3126_set_loopback,
 167        .mmds                   = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
 168                                   MDIO_DEVS_PHYXS),
 169};
 170
 171static struct cphy *my3126_phy_create(struct net_device *dev,
 172                        int phy_addr, const struct mdio_ops *mdio_ops)
 173{
 174        struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
 175
 176        if (!cphy)
 177                return NULL;
 178
 179        cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops);
 180        INIT_DELAYED_WORK(&cphy->phy_update, my3126_poll);
 181        cphy->bmsr = 0;
 182
 183        return cphy;
 184}
 185
 186/* Chip Reset */
 187static int my3126_phy_reset(adapter_t * adapter)
 188{
 189        u32 val;
 190
 191        t1_tpi_read(adapter, A_ELMER0_GPO, &val);
 192        val &= ~4;
 193        t1_tpi_write(adapter, A_ELMER0_GPO, val);
 194        msleep(100);
 195
 196        t1_tpi_write(adapter, A_ELMER0_GPO, val | 4);
 197        msleep(1000);
 198
 199        /* Now lets enable the Laser. Delay 100us */
 200        t1_tpi_read(adapter, A_ELMER0_GPO, &val);
 201        val |= 0x8000;
 202        t1_tpi_write(adapter, A_ELMER0_GPO, val);
 203        udelay(100);
 204        return 0;
 205}
 206
 207const struct gphy t1_my3126_ops = {
 208        .create = my3126_phy_create,
 209        .reset = my3126_phy_reset
 210};
 211