brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · 556c8ad Raw
251 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*****************************************************************************3 *                                                                           *4 * File: mv88x201x.c                                                         *5 * $Revision: 1.12 $                                                         *6 * $Date: 2005/04/15 19:27:14 $                                              *7 * Description:                                                              *8 *  Marvell PHY (mv88x201x) functionality.                                   *9 *  part of the Chelsio 10Gb Ethernet Driver.                                *10 *                                                                           *11 *                                                                           *12 * http://www.chelsio.com                                                    *13 *                                                                           *14 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *15 * All rights reserved.                                                      *16 *                                                                           *17 * Maintainers: maintainers@chelsio.com                                      *18 *                                                                           *19 * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         *20 *          Tina Yang               <tainay@chelsio.com>                     *21 *          Felix Marti             <felix@chelsio.com>                      *22 *          Scott Bardone           <sbardone@chelsio.com>                   *23 *          Kurt Ottaway            <kottaway@chelsio.com>                   *24 *          Frank DiMambro          <frank@chelsio.com>                      *25 *                                                                           *26 * History:                                                                  *27 *                                                                           *28 ****************************************************************************/29 30#include "cphy.h"31#include "elmer0.h"32 33/*34 * The 88x2010 Rev C. requires some link status registers * to be read35 * twice in order to get the right values. Future * revisions will fix36 * this problem and then this macro * can disappear.37 */38#define MV88x2010_LINK_STATUS_BUGS    139 40static int led_init(struct cphy *cphy)41{42	/* Setup the LED registers so we can turn on/off.43	 * Writing these bits maps control to another44	 * register. mmd(0x1) addr(0x7)45	 */46	cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd);47	return 0;48}49 50static int led_link(struct cphy *cphy, u32 do_enable)51{52	u32 led = 0;53#define LINK_ENABLE_BIT 0x154 55	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led);56 57	if (do_enable & LINK_ENABLE_BIT) {58		led |= LINK_ENABLE_BIT;59		cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led);60	} else {61		led &= ~LINK_ENABLE_BIT;62		cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led);63	}64	return 0;65}66 67/* Port Reset */68static int mv88x201x_reset(struct cphy *cphy, int wait)69{70	/* This can be done through registers.  It is not required since71	 * a full chip reset is used.72	 */73	return 0;74}75 76static int mv88x201x_interrupt_enable(struct cphy *cphy)77{78	/* Enable PHY LASI interrupts. */79	cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,80			MDIO_PMA_LASI_LSALARM);81 82	/* Enable Marvell interrupts through Elmer0. */83	if (t1_is_asic(cphy->adapter)) {84		u32 elmer;85 86		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);87		elmer |= ELMER0_GP_BIT6;88		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);89	}90	return 0;91}92 93static int mv88x201x_interrupt_disable(struct cphy *cphy)94{95	/* Disable PHY LASI interrupts. */96	cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0);97 98	/* Disable Marvell interrupts through Elmer0. */99	if (t1_is_asic(cphy->adapter)) {100		u32 elmer;101 102		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);103		elmer &= ~ELMER0_GP_BIT6;104		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);105	}106	return 0;107}108 109static int mv88x201x_interrupt_clear(struct cphy *cphy)110{111	u32 elmer;112	u32 val;113 114#ifdef MV88x2010_LINK_STATUS_BUGS115	/* Required to read twice before clear takes affect. */116	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val);117	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val);118	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);119 120	/* Read this register after the others above it else121	 * the register doesn't clear correctly.122	 */123	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);124#endif125 126	/* Clear link status. */127	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);128	/* Clear PHY LASI interrupts. */129	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);130 131#ifdef MV88x2010_LINK_STATUS_BUGS132	/* Do it again. */133	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val);134	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val);135#endif136 137	/* Clear Marvell interrupts through Elmer0. */138	if (t1_is_asic(cphy->adapter)) {139		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);140		elmer |= ELMER0_GP_BIT6;141		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);142	}143	return 0;144}145 146static int mv88x201x_interrupt_handler(struct cphy *cphy)147{148	/* Clear interrupts */149	mv88x201x_interrupt_clear(cphy);150 151	/* We have only enabled link change interrupts and so152	 * cphy_cause must be a link change interrupt.153	 */154	return cphy_cause_link_change;155}156 157static int mv88x201x_set_loopback(struct cphy *cphy, int on)158{159	return 0;160}161 162static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok,163				     int *speed, int *duplex, int *fc)164{165	u32 val = 0;166 167	if (link_ok) {168		/* Read link status. */169		cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);170		val &= MDIO_STAT1_LSTATUS;171		*link_ok = (val == MDIO_STAT1_LSTATUS);172		/* Turn on/off Link LED */173		led_link(cphy, *link_ok);174	}175	if (speed)176		*speed = SPEED_10000;177	if (duplex)178		*duplex = DUPLEX_FULL;179	if (fc)180		*fc = PAUSE_RX | PAUSE_TX;181	return 0;182}183 184static void mv88x201x_destroy(struct cphy *cphy)185{186	kfree(cphy);187}188 189static const struct cphy_ops mv88x201x_ops = {190	.destroy           = mv88x201x_destroy,191	.reset             = mv88x201x_reset,192	.interrupt_enable  = mv88x201x_interrupt_enable,193	.interrupt_disable = mv88x201x_interrupt_disable,194	.interrupt_clear   = mv88x201x_interrupt_clear,195	.interrupt_handler = mv88x201x_interrupt_handler,196	.get_link_status   = mv88x201x_get_link_status,197	.set_loopback      = mv88x201x_set_loopback,198	.mmds              = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |199			      MDIO_DEVS_PHYXS | MDIO_DEVS_WIS),200};201 202static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr,203					 const struct mdio_ops *mdio_ops)204{205	u32 val;206	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);207 208	if (!cphy)209		return NULL;210 211	cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops);212 213	/* Commands the PHY to enable XFP's clock. */214	cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val);215	cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1);216 217	/* Clear link status. Required because of a bug in the PHY.  */218	cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val);219	cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val);220 221	/* Allows for Link,Ack LED turn on/off */222	led_init(cphy);223	return cphy;224}225 226/* Chip Reset */227static int mv88x201x_phy_reset(adapter_t *adapter)228{229	u32 val;230 231	t1_tpi_read(adapter, A_ELMER0_GPO, &val);232	val &= ~4;233	t1_tpi_write(adapter, A_ELMER0_GPO, val);234	msleep(100);235 236	t1_tpi_write(adapter, A_ELMER0_GPO, val | 4);237	msleep(1000);238 239	/* Now lets enable the Laser. Delay 100us */240	t1_tpi_read(adapter, A_ELMER0_GPO, &val);241	val |= 0x8000;242	t1_tpi_write(adapter, A_ELMER0_GPO, val);243	udelay(100);244	return 0;245}246 247const struct gphy t1_mv88x201x_ops = {248	.create = mv88x201x_phy_create,249	.reset = mv88x201x_phy_reset250};251