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