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