Thomas Gleixner | 2874c5f | 2019-05-27 08:55:01 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Andrew Lunn | 6d91782 | 2017-05-26 01:03:21 +0200 | [diff] [blame] | 2 | /* |
| 3 | * Marvell 88E6xxx SERDES manipulation, via SMI bus |
| 4 | * |
| 5 | * Copyright (c) 2008 Marvell Semiconductor |
| 6 | * |
| 7 | * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> |
Andrew Lunn | 6d91782 | 2017-05-26 01:03:21 +0200 | [diff] [blame] | 8 | */ |
| 9 | |
| 10 | #ifndef _MV88E6XXX_SERDES_H |
| 11 | #define _MV88E6XXX_SERDES_H |
| 12 | |
Vivien Didelot | 4d5f2ba7 | 2017-06-02 17:06:15 -0400 | [diff] [blame] | 13 | #include "chip.h" |
Andrew Lunn | 6d91782 | 2017-05-26 01:03:21 +0200 | [diff] [blame] | 14 | |
| 15 | #define MV88E6352_ADDR_SERDES 0x0f |
| 16 | #define MV88E6352_SERDES_PAGE_FIBER 0x01 |
Andrew Lunn | 4382172 | 2018-09-02 18:13:15 +0200 | [diff] [blame] | 17 | #define MV88E6352_SERDES_IRQ 0x0b |
| 18 | #define MV88E6352_SERDES_INT_ENABLE 0x12 |
| 19 | #define MV88E6352_SERDES_INT_SPEED_CHANGE BIT(14) |
| 20 | #define MV88E6352_SERDES_INT_DUPLEX_CHANGE BIT(13) |
| 21 | #define MV88E6352_SERDES_INT_PAGE_RX BIT(12) |
| 22 | #define MV88E6352_SERDES_INT_AN_COMPLETE BIT(11) |
| 23 | #define MV88E6352_SERDES_INT_LINK_CHANGE BIT(10) |
| 24 | #define MV88E6352_SERDES_INT_SYMBOL_ERROR BIT(9) |
| 25 | #define MV88E6352_SERDES_INT_FALSE_CARRIER BIT(8) |
| 26 | #define MV88E6352_SERDES_INT_FIFO_OVER_UNDER BIT(7) |
| 27 | #define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4) |
| 28 | #define MV88E6352_SERDES_INT_STATUS 0x13 |
| 29 | |
Andrew Lunn | 6d91782 | 2017-05-26 01:03:21 +0200 | [diff] [blame] | 30 | |
Marek BehĂșn | d3cf7d8 | 2019-08-26 23:31:53 +0200 | [diff] [blame] | 31 | #define MV88E6341_PORT5_LANE 0x15 |
Marek BehĂșn | 5bafeb6e | 2018-05-04 19:26:10 +0200 | [diff] [blame] | 32 | |
Andrew Lunn | 6335e9f | 2017-05-26 01:03:23 +0200 | [diff] [blame] | 33 | #define MV88E6390_PORT9_LANE0 0x09 |
| 34 | #define MV88E6390_PORT9_LANE1 0x12 |
| 35 | #define MV88E6390_PORT9_LANE2 0x13 |
| 36 | #define MV88E6390_PORT9_LANE3 0x14 |
| 37 | #define MV88E6390_PORT10_LANE0 0x0a |
| 38 | #define MV88E6390_PORT10_LANE1 0x15 |
| 39 | #define MV88E6390_PORT10_LANE2 0x16 |
| 40 | #define MV88E6390_PORT10_LANE3 0x17 |
Andrew Lunn | 6335e9f | 2017-05-26 01:03:23 +0200 | [diff] [blame] | 41 | |
| 42 | /* 10GBASE-R and 10GBASE-X4/X2 */ |
Russell King | bf604bc | 2020-04-30 09:21:34 +0100 | [diff] [blame] | 43 | #define MV88E6390_10G_CTRL1 (0x1000 + MDIO_CTRL1) |
Russell King | 7019bba | 2020-04-30 09:21:39 +0100 | [diff] [blame] | 44 | #define MV88E6390_10G_STAT1 (0x1000 + MDIO_STAT1) |
Andrew Lunn | 6335e9f | 2017-05-26 01:03:23 +0200 | [diff] [blame] | 45 | |
| 46 | /* 1000BASE-X and SGMII */ |
Russell King | 4c8b735 | 2020-03-14 10:15:33 +0000 | [diff] [blame] | 47 | #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) |
Russell King | 7e0e624 | 2020-03-14 10:15:48 +0000 | [diff] [blame] | 48 | #define MV88E6390_SGMII_BMSR (0x2000 + MII_BMSR) |
Russell King | a5a6858 | 2020-03-14 10:15:43 +0000 | [diff] [blame] | 49 | #define MV88E6390_SGMII_ADVERTISE (0x2000 + MII_ADVERTISE) |
| 50 | #define MV88E6390_SGMII_LPA (0x2000 + MII_LPA) |
Andrew Lunn | efd1ba6 | 2018-08-09 15:38:48 +0200 | [diff] [blame] | 51 | #define MV88E6390_SGMII_INT_ENABLE 0xa001 |
| 52 | #define MV88E6390_SGMII_INT_SPEED_CHANGE BIT(14) |
| 53 | #define MV88E6390_SGMII_INT_DUPLEX_CHANGE BIT(13) |
| 54 | #define MV88E6390_SGMII_INT_PAGE_RX BIT(12) |
| 55 | #define MV88E6390_SGMII_INT_AN_COMPLETE BIT(11) |
| 56 | #define MV88E6390_SGMII_INT_LINK_DOWN BIT(10) |
| 57 | #define MV88E6390_SGMII_INT_LINK_UP BIT(9) |
| 58 | #define MV88E6390_SGMII_INT_SYMBOL_ERROR BIT(8) |
| 59 | #define MV88E6390_SGMII_INT_FALSE_CARRIER BIT(7) |
| 60 | #define MV88E6390_SGMII_INT_STATUS 0xa002 |
Heiner Kallweit | 72d8b4f | 2019-03-01 20:41:00 +0100 | [diff] [blame] | 61 | #define MV88E6390_SGMII_PHY_STATUS 0xa003 |
| 62 | #define MV88E6390_SGMII_PHY_STATUS_SPEED_MASK GENMASK(15, 14) |
| 63 | #define MV88E6390_SGMII_PHY_STATUS_SPEED_1000 0x8000 |
| 64 | #define MV88E6390_SGMII_PHY_STATUS_SPEED_100 0x4000 |
| 65 | #define MV88E6390_SGMII_PHY_STATUS_SPEED_10 0x0000 |
| 66 | #define MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL BIT(13) |
| 67 | #define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11) |
| 68 | #define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10) |
Russell King | a5a6858 | 2020-03-14 10:15:43 +0000 | [diff] [blame] | 69 | #define MV88E6390_SGMII_PHY_STATUS_TX_PAUSE BIT(3) |
| 70 | #define MV88E6390_SGMII_PHY_STATUS_RX_PAUSE BIT(2) |
Andrew Lunn | 6335e9f | 2017-05-26 01:03:23 +0200 | [diff] [blame] | 71 | |
Nikita Yushchenko | 0df9528 | 2019-12-25 08:22:38 +0300 | [diff] [blame] | 72 | /* Packet generator pad packet checker */ |
| 73 | #define MV88E6390_PG_CONTROL 0xf010 |
| 74 | #define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0) |
| 75 | |
Vivien Didelot | 5122d4e | 2019-08-31 16:18:30 -0400 | [diff] [blame] | 76 | u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); |
Vivien Didelot | 9db4a72 | 2019-08-31 16:18:31 -0400 | [diff] [blame] | 77 | u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); |
Vivien Didelot | 5122d4e | 2019-08-31 16:18:30 -0400 | [diff] [blame] | 78 | u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); |
| 79 | u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); |
Russell King | a5a6858 | 2020-03-14 10:15:43 +0000 | [diff] [blame] | 80 | int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, |
| 81 | u8 lane, unsigned int mode, |
| 82 | phy_interface_t interface, |
| 83 | const unsigned long *advertise); |
| 84 | int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, |
| 85 | u8 lane, unsigned int mode, |
| 86 | phy_interface_t interface, |
| 87 | const unsigned long *advertise); |
| 88 | int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, |
| 89 | u8 lane, struct phylink_link_state *state); |
| 90 | int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, |
| 91 | u8 lane, struct phylink_link_state *state); |
| 92 | int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, |
| 93 | u8 lane); |
| 94 | int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, |
| 95 | u8 lane); |
| 96 | int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, |
| 97 | u8 lane, int speed, int duplex); |
| 98 | int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, |
| 99 | u8 lane, int speed, int duplex); |
Vivien Didelot | 4241ef5 | 2019-08-31 16:18:29 -0400 | [diff] [blame] | 100 | unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, |
| 101 | int port); |
| 102 | unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, |
| 103 | int port); |
Vivien Didelot | dc272f6 | 2019-08-31 16:18:33 -0400 | [diff] [blame] | 104 | int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, |
| 105 | bool on); |
| 106 | int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, |
| 107 | bool on); |
Vivien Didelot | 61a46b4 | 2019-08-31 16:18:34 -0400 | [diff] [blame] | 108 | int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, |
| 109 | bool enable); |
| 110 | int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, |
| 111 | bool enable); |
Vivien Didelot | 907b9b9 | 2019-08-31 16:18:35 -0400 | [diff] [blame] | 112 | irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, |
| 113 | u8 lane); |
| 114 | irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, |
| 115 | u8 lane); |
Andrew Lunn | cda9f4a | 2018-03-01 02:02:31 +0100 | [diff] [blame] | 116 | int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); |
Andrew Lunn | 65f60e4 | 2018-03-28 23:50:28 +0200 | [diff] [blame] | 117 | int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, |
| 118 | int port, uint8_t *data); |
| 119 | int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, |
| 120 | uint64_t *data); |
Nikita Yushchenko | 0df9528 | 2019-12-25 08:22:38 +0300 | [diff] [blame] | 121 | int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); |
| 122 | int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, |
| 123 | int port, uint8_t *data); |
| 124 | int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, |
| 125 | uint64_t *data); |
Andrew Lunn | 4382172 | 2018-09-02 18:13:15 +0200 | [diff] [blame] | 126 | |
Andrew Lunn | d3f88a2 | 2020-02-16 18:54:14 +0100 | [diff] [blame] | 127 | int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port); |
| 128 | void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); |
Andrew Lunn | bf3504c | 2020-02-16 18:54:15 +0100 | [diff] [blame] | 129 | int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port); |
| 130 | void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); |
Andrew Lunn | d3f88a2 | 2020-02-16 18:54:14 +0100 | [diff] [blame] | 131 | |
Vivien Didelot | 5122d4e | 2019-08-31 16:18:30 -0400 | [diff] [blame] | 132 | /* Return the (first) SERDES lane address a port is using, 0 otherwise. */ |
| 133 | static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, |
| 134 | int port) |
| 135 | { |
| 136 | if (!chip->info->ops->serdes_get_lane) |
| 137 | return 0; |
| 138 | |
| 139 | return chip->info->ops->serdes_get_lane(chip, port); |
| 140 | } |
| 141 | |
Vivien Didelot | dc272f6 | 2019-08-31 16:18:33 -0400 | [diff] [blame] | 142 | static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip, |
| 143 | int port, u8 lane) |
| 144 | { |
| 145 | if (!chip->info->ops->serdes_power) |
| 146 | return -EOPNOTSUPP; |
| 147 | |
| 148 | return chip->info->ops->serdes_power(chip, port, lane, true); |
| 149 | } |
| 150 | |
| 151 | static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip, |
| 152 | int port, u8 lane) |
| 153 | { |
| 154 | if (!chip->info->ops->serdes_power) |
| 155 | return -EOPNOTSUPP; |
| 156 | |
| 157 | return chip->info->ops->serdes_power(chip, port, lane, false); |
| 158 | } |
| 159 | |
Vivien Didelot | 4241ef5 | 2019-08-31 16:18:29 -0400 | [diff] [blame] | 160 | static inline unsigned int |
| 161 | mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) |
| 162 | { |
| 163 | if (!chip->info->ops->serdes_irq_mapping) |
| 164 | return 0; |
| 165 | |
| 166 | return chip->info->ops->serdes_irq_mapping(chip, port); |
| 167 | } |
Andrew Lunn | 734447d | 2018-08-09 15:38:49 +0200 | [diff] [blame] | 168 | |
Vivien Didelot | 61a46b4 | 2019-08-31 16:18:34 -0400 | [diff] [blame] | 169 | static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip, |
| 170 | int port, u8 lane) |
| 171 | { |
| 172 | if (!chip->info->ops->serdes_irq_enable) |
| 173 | return -EOPNOTSUPP; |
| 174 | |
| 175 | return chip->info->ops->serdes_irq_enable(chip, port, lane, true); |
| 176 | } |
| 177 | |
| 178 | static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip, |
| 179 | int port, u8 lane) |
| 180 | { |
| 181 | if (!chip->info->ops->serdes_irq_enable) |
| 182 | return -EOPNOTSUPP; |
| 183 | |
| 184 | return chip->info->ops->serdes_irq_enable(chip, port, lane, false); |
| 185 | } |
| 186 | |
Vivien Didelot | 907b9b9 | 2019-08-31 16:18:35 -0400 | [diff] [blame] | 187 | static inline irqreturn_t |
| 188 | mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane) |
| 189 | { |
| 190 | if (!chip->info->ops->serdes_irq_status) |
| 191 | return IRQ_NONE; |
| 192 | |
| 193 | return chip->info->ops->serdes_irq_status(chip, port, lane); |
| 194 | } |
| 195 | |
Andrew Lunn | 6d91782 | 2017-05-26 01:03:21 +0200 | [diff] [blame] | 196 | #endif |