1*4aabe35cSRussell King (Oracle) // SPDX-License-Identifier: GPL-2.0-or-later 2*4aabe35cSRussell King (Oracle) /* 3*4aabe35cSRussell King (Oracle) * Marvell 88E6185 family SERDES PCS support 4*4aabe35cSRussell King (Oracle) * 5*4aabe35cSRussell King (Oracle) * Copyright (c) 2008 Marvell Semiconductor 6*4aabe35cSRussell King (Oracle) * 7*4aabe35cSRussell King (Oracle) * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> 8*4aabe35cSRussell King (Oracle) */ 9*4aabe35cSRussell King (Oracle) #include <linux/phylink.h> 10*4aabe35cSRussell King (Oracle) 11*4aabe35cSRussell King (Oracle) #include "global2.h" 12*4aabe35cSRussell King (Oracle) #include "port.h" 13*4aabe35cSRussell King (Oracle) #include "serdes.h" 14*4aabe35cSRussell King (Oracle) 15*4aabe35cSRussell King (Oracle) struct mv88e6185_pcs { 16*4aabe35cSRussell King (Oracle) struct phylink_pcs phylink_pcs; 17*4aabe35cSRussell King (Oracle) unsigned int irq; 18*4aabe35cSRussell King (Oracle) char name[64]; 19*4aabe35cSRussell King (Oracle) 20*4aabe35cSRussell King (Oracle) struct mv88e6xxx_chip *chip; 21*4aabe35cSRussell King (Oracle) int port; 22*4aabe35cSRussell King (Oracle) }; 23*4aabe35cSRussell King (Oracle) 24*4aabe35cSRussell King (Oracle) static struct mv88e6185_pcs *pcs_to_mv88e6185_pcs(struct phylink_pcs *pcs) 25*4aabe35cSRussell King (Oracle) { 26*4aabe35cSRussell King (Oracle) return container_of(pcs, struct mv88e6185_pcs, phylink_pcs); 27*4aabe35cSRussell King (Oracle) } 28*4aabe35cSRussell King (Oracle) 29*4aabe35cSRussell King (Oracle) static irqreturn_t mv88e6185_pcs_handle_irq(int irq, void *dev_id) 30*4aabe35cSRussell King (Oracle) { 31*4aabe35cSRussell King (Oracle) struct mv88e6185_pcs *mpcs = dev_id; 32*4aabe35cSRussell King (Oracle) struct mv88e6xxx_chip *chip; 33*4aabe35cSRussell King (Oracle) irqreturn_t ret = IRQ_NONE; 34*4aabe35cSRussell King (Oracle) bool link_up; 35*4aabe35cSRussell King (Oracle) u16 status; 36*4aabe35cSRussell King (Oracle) int port; 37*4aabe35cSRussell King (Oracle) int err; 38*4aabe35cSRussell King (Oracle) 39*4aabe35cSRussell King (Oracle) chip = mpcs->chip; 40*4aabe35cSRussell King (Oracle) port = mpcs->port; 41*4aabe35cSRussell King (Oracle) 42*4aabe35cSRussell King (Oracle) mv88e6xxx_reg_lock(chip); 43*4aabe35cSRussell King (Oracle) err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status); 44*4aabe35cSRussell King (Oracle) mv88e6xxx_reg_unlock(chip); 45*4aabe35cSRussell King (Oracle) 46*4aabe35cSRussell King (Oracle) if (!err) { 47*4aabe35cSRussell King (Oracle) link_up = !!(status & MV88E6XXX_PORT_STS_LINK); 48*4aabe35cSRussell King (Oracle) 49*4aabe35cSRussell King (Oracle) phylink_pcs_change(&mpcs->phylink_pcs, link_up); 50*4aabe35cSRussell King (Oracle) 51*4aabe35cSRussell King (Oracle) ret = IRQ_HANDLED; 52*4aabe35cSRussell King (Oracle) } 53*4aabe35cSRussell King (Oracle) 54*4aabe35cSRussell King (Oracle) return ret; 55*4aabe35cSRussell King (Oracle) } 56*4aabe35cSRussell King (Oracle) 57*4aabe35cSRussell King (Oracle) static void mv88e6185_pcs_get_state(struct phylink_pcs *pcs, 58*4aabe35cSRussell King (Oracle) struct phylink_link_state *state) 59*4aabe35cSRussell King (Oracle) { 60*4aabe35cSRussell King (Oracle) struct mv88e6185_pcs *mpcs = pcs_to_mv88e6185_pcs(pcs); 61*4aabe35cSRussell King (Oracle) struct mv88e6xxx_chip *chip = mpcs->chip; 62*4aabe35cSRussell King (Oracle) int port = mpcs->port; 63*4aabe35cSRussell King (Oracle) u16 status; 64*4aabe35cSRussell King (Oracle) int err; 65*4aabe35cSRussell King (Oracle) 66*4aabe35cSRussell King (Oracle) mv88e6xxx_reg_lock(chip); 67*4aabe35cSRussell King (Oracle) err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status); 68*4aabe35cSRussell King (Oracle) mv88e6xxx_reg_unlock(chip); 69*4aabe35cSRussell King (Oracle) 70*4aabe35cSRussell King (Oracle) if (err) 71*4aabe35cSRussell King (Oracle) status = 0; 72*4aabe35cSRussell King (Oracle) 73*4aabe35cSRussell King (Oracle) state->link = !!(status & MV88E6XXX_PORT_STS_LINK); 74*4aabe35cSRussell King (Oracle) if (state->link) { 75*4aabe35cSRussell King (Oracle) state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ? 76*4aabe35cSRussell King (Oracle) DUPLEX_FULL : DUPLEX_HALF; 77*4aabe35cSRussell King (Oracle) 78*4aabe35cSRussell King (Oracle) switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) { 79*4aabe35cSRussell King (Oracle) case MV88E6XXX_PORT_STS_SPEED_1000: 80*4aabe35cSRussell King (Oracle) state->speed = SPEED_1000; 81*4aabe35cSRussell King (Oracle) break; 82*4aabe35cSRussell King (Oracle) 83*4aabe35cSRussell King (Oracle) case MV88E6XXX_PORT_STS_SPEED_100: 84*4aabe35cSRussell King (Oracle) state->speed = SPEED_100; 85*4aabe35cSRussell King (Oracle) break; 86*4aabe35cSRussell King (Oracle) 87*4aabe35cSRussell King (Oracle) case MV88E6XXX_PORT_STS_SPEED_10: 88*4aabe35cSRussell King (Oracle) state->speed = SPEED_10; 89*4aabe35cSRussell King (Oracle) break; 90*4aabe35cSRussell King (Oracle) 91*4aabe35cSRussell King (Oracle) default: 92*4aabe35cSRussell King (Oracle) state->link = false; 93*4aabe35cSRussell King (Oracle) break; 94*4aabe35cSRussell King (Oracle) } 95*4aabe35cSRussell King (Oracle) } 96*4aabe35cSRussell King (Oracle) } 97*4aabe35cSRussell King (Oracle) 98*4aabe35cSRussell King (Oracle) static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int mode, 99*4aabe35cSRussell King (Oracle) phy_interface_t interface, 100*4aabe35cSRussell King (Oracle) const unsigned long *advertising, 101*4aabe35cSRussell King (Oracle) bool permit_pause_to_mac) 102*4aabe35cSRussell King (Oracle) { 103*4aabe35cSRussell King (Oracle) return 0; 104*4aabe35cSRussell King (Oracle) } 105*4aabe35cSRussell King (Oracle) 106*4aabe35cSRussell King (Oracle) static void mv88e6185_pcs_an_restart(struct phylink_pcs *pcs) 107*4aabe35cSRussell King (Oracle) { 108*4aabe35cSRussell King (Oracle) } 109*4aabe35cSRussell King (Oracle) 110*4aabe35cSRussell King (Oracle) static const struct phylink_pcs_ops mv88e6185_phylink_pcs_ops = { 111*4aabe35cSRussell King (Oracle) .pcs_get_state = mv88e6185_pcs_get_state, 112*4aabe35cSRussell King (Oracle) .pcs_config = mv88e6185_pcs_config, 113*4aabe35cSRussell King (Oracle) .pcs_an_restart = mv88e6185_pcs_an_restart, 114*4aabe35cSRussell King (Oracle) }; 115*4aabe35cSRussell King (Oracle) 116*4aabe35cSRussell King (Oracle) static int mv88e6185_pcs_init(struct mv88e6xxx_chip *chip, int port) 117*4aabe35cSRussell King (Oracle) { 118*4aabe35cSRussell King (Oracle) struct mv88e6185_pcs *mpcs; 119*4aabe35cSRussell King (Oracle) struct device *dev; 120*4aabe35cSRussell King (Oracle) unsigned int irq; 121*4aabe35cSRussell King (Oracle) int err; 122*4aabe35cSRussell King (Oracle) 123*4aabe35cSRussell King (Oracle) /* There are no configurable serdes lanes on this switch chip, so 124*4aabe35cSRussell King (Oracle) * we use the static cmode configuration to determine whether we 125*4aabe35cSRussell King (Oracle) * have a PCS or not. 126*4aabe35cSRussell King (Oracle) */ 127*4aabe35cSRussell King (Oracle) if (chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_SERDES && 128*4aabe35cSRussell King (Oracle) chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_1000BASE_X) 129*4aabe35cSRussell King (Oracle) return 0; 130*4aabe35cSRussell King (Oracle) 131*4aabe35cSRussell King (Oracle) dev = chip->dev; 132*4aabe35cSRussell King (Oracle) 133*4aabe35cSRussell King (Oracle) mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); 134*4aabe35cSRussell King (Oracle) if (!mpcs) 135*4aabe35cSRussell King (Oracle) return -ENOMEM; 136*4aabe35cSRussell King (Oracle) 137*4aabe35cSRussell King (Oracle) mpcs->chip = chip; 138*4aabe35cSRussell King (Oracle) mpcs->port = port; 139*4aabe35cSRussell King (Oracle) mpcs->phylink_pcs.ops = &mv88e6185_phylink_pcs_ops; 140*4aabe35cSRussell King (Oracle) 141*4aabe35cSRussell King (Oracle) irq = mv88e6xxx_serdes_irq_mapping(chip, port); 142*4aabe35cSRussell King (Oracle) if (irq) { 143*4aabe35cSRussell King (Oracle) snprintf(mpcs->name, sizeof(mpcs->name), 144*4aabe35cSRussell King (Oracle) "mv88e6xxx-%s-serdes-%d", dev_name(dev), port); 145*4aabe35cSRussell King (Oracle) 146*4aabe35cSRussell King (Oracle) err = request_threaded_irq(irq, NULL, mv88e6185_pcs_handle_irq, 147*4aabe35cSRussell King (Oracle) IRQF_ONESHOT, mpcs->name, mpcs); 148*4aabe35cSRussell King (Oracle) if (err) { 149*4aabe35cSRussell King (Oracle) kfree(mpcs); 150*4aabe35cSRussell King (Oracle) return err; 151*4aabe35cSRussell King (Oracle) } 152*4aabe35cSRussell King (Oracle) 153*4aabe35cSRussell King (Oracle) mpcs->irq = irq; 154*4aabe35cSRussell King (Oracle) } else { 155*4aabe35cSRussell King (Oracle) mpcs->phylink_pcs.poll = true; 156*4aabe35cSRussell King (Oracle) } 157*4aabe35cSRussell King (Oracle) 158*4aabe35cSRussell King (Oracle) chip->ports[port].pcs_private = &mpcs->phylink_pcs; 159*4aabe35cSRussell King (Oracle) 160*4aabe35cSRussell King (Oracle) return 0; 161*4aabe35cSRussell King (Oracle) } 162*4aabe35cSRussell King (Oracle) 163*4aabe35cSRussell King (Oracle) static void mv88e6185_pcs_teardown(struct mv88e6xxx_chip *chip, int port) 164*4aabe35cSRussell King (Oracle) { 165*4aabe35cSRussell King (Oracle) struct mv88e6185_pcs *mpcs; 166*4aabe35cSRussell King (Oracle) 167*4aabe35cSRussell King (Oracle) mpcs = chip->ports[port].pcs_private; 168*4aabe35cSRussell King (Oracle) if (!mpcs) 169*4aabe35cSRussell King (Oracle) return; 170*4aabe35cSRussell King (Oracle) 171*4aabe35cSRussell King (Oracle) if (mpcs->irq) 172*4aabe35cSRussell King (Oracle) free_irq(mpcs->irq, mpcs); 173*4aabe35cSRussell King (Oracle) 174*4aabe35cSRussell King (Oracle) kfree(mpcs); 175*4aabe35cSRussell King (Oracle) 176*4aabe35cSRussell King (Oracle) chip->ports[port].pcs_private = NULL; 177*4aabe35cSRussell King (Oracle) } 178*4aabe35cSRussell King (Oracle) 179*4aabe35cSRussell King (Oracle) static struct phylink_pcs *mv88e6185_pcs_select(struct mv88e6xxx_chip *chip, 180*4aabe35cSRussell King (Oracle) int port, 181*4aabe35cSRussell King (Oracle) phy_interface_t interface) 182*4aabe35cSRussell King (Oracle) { 183*4aabe35cSRussell King (Oracle) return chip->ports[port].pcs_private; 184*4aabe35cSRussell King (Oracle) } 185*4aabe35cSRussell King (Oracle) 186*4aabe35cSRussell King (Oracle) const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops = { 187*4aabe35cSRussell King (Oracle) .pcs_init = mv88e6185_pcs_init, 188*4aabe35cSRussell King (Oracle) .pcs_teardown = mv88e6185_pcs_teardown, 189*4aabe35cSRussell King (Oracle) .pcs_select = mv88e6185_pcs_select, 190*4aabe35cSRussell King (Oracle) }; 191