211 lines · c
1// SPDX-License-Identifier: GPL-2.02/* $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 since12 * 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 it56 must be that57 */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_reset210};211