191 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Marvell 88E6xxx System Management Interface (SMI) support4 *5 * Copyright (c) 2008 Marvell Semiconductor6 *7 * Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>8 */9 10#include "chip.h"11#include "smi.h"12 13/* The switch ADDR[4:1] configuration pins define the chip SMI device address14 * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).15 *16 * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it17 * is the only device connected to the SMI master. In this mode it responds to18 * all 32 possible SMI addresses, and thus maps directly the internal devices.19 *20 * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing21 * multiple devices to share the SMI interface. In this mode it responds to only22 * 2 registers, used to indirectly access the internal SMI devices.23 *24 * Some chips use a different scheme: Only the ADDR4 pin is used for25 * configuration, and the device responds to 16 of the 32 SMI26 * addresses, allowing two to coexist on the same SMI interface.27 */28 29static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,30 int dev, int reg, u16 *data)31{32 int ret;33 34 ret = mdiobus_read_nested(chip->bus, dev, reg);35 if (ret < 0)36 return ret;37 38 *data = ret & 0xffff;39 40 return 0;41}42 43static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,44 int dev, int reg, u16 data)45{46 int ret;47 48 ret = mdiobus_write_nested(chip->bus, dev, reg, data);49 if (ret < 0)50 return ret;51 52 return 0;53}54 55static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,56 int dev, int reg, int bit, int val)57{58 const unsigned long timeout = jiffies + msecs_to_jiffies(50);59 u16 data;60 int err;61 int i;62 63 /* Even if the initial poll takes longer than 50ms, always do64 * at least one more attempt.65 */66 for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {67 err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);68 if (err)69 return err;70 71 if (!!(data & BIT(bit)) == !!val)72 return 0;73 74 if (i < 2)75 cpu_relax();76 else77 usleep_range(1000, 2000);78 }79 80 return -ETIMEDOUT;81}82 83static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {84 .read = mv88e6xxx_smi_direct_read,85 .write = mv88e6xxx_smi_direct_write,86};87 88static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,89 int dev, int reg, u16 *data)90{91 return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);92}93 94static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,95 int dev, int reg, u16 data)96{97 return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);98}99 100static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {101 .read = mv88e6xxx_smi_dual_direct_read,102 .write = mv88e6xxx_smi_dual_direct_write,103};104 105/* Offset 0x00: SMI Command Register106 * Offset 0x01: SMI Data Register107 */108 109static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,110 int dev, int reg, u16 *data)111{112 int err;113 114 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,115 MV88E6XXX_SMI_CMD,116 MV88E6XXX_SMI_CMD_BUSY |117 MV88E6XXX_SMI_CMD_MODE_22 |118 MV88E6XXX_SMI_CMD_OP_22_READ |119 (dev << 5) | reg);120 if (err)121 return err;122 123 err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,124 MV88E6XXX_SMI_CMD, 15, 0);125 if (err)126 return err;127 128 return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,129 MV88E6XXX_SMI_DATA, data);130}131 132static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,133 int dev, int reg, u16 data)134{135 int err;136 137 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,138 MV88E6XXX_SMI_DATA, data);139 if (err)140 return err;141 142 err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,143 MV88E6XXX_SMI_CMD,144 MV88E6XXX_SMI_CMD_BUSY |145 MV88E6XXX_SMI_CMD_MODE_22 |146 MV88E6XXX_SMI_CMD_OP_22_WRITE |147 (dev << 5) | reg);148 if (err)149 return err;150 151 return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,152 MV88E6XXX_SMI_CMD, 15, 0);153}154 155static int mv88e6xxx_smi_indirect_init(struct mv88e6xxx_chip *chip)156{157 /* Ensure that the chip starts out in the ready state. As both158 * reads and writes always ensure this on return, they can159 * safely depend on the chip not being busy on entry.160 */161 return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,162 MV88E6XXX_SMI_CMD, 15, 0);163}164 165static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {166 .read = mv88e6xxx_smi_indirect_read,167 .write = mv88e6xxx_smi_indirect_write,168 .init = mv88e6xxx_smi_indirect_init,169};170 171int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,172 struct mii_bus *bus, int sw_addr)173{174 if (chip->info->dual_chip)175 chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;176 else if (sw_addr == 0)177 chip->smi_ops = &mv88e6xxx_smi_direct_ops;178 else if (chip->info->multi_chip)179 chip->smi_ops = &mv88e6xxx_smi_indirect_ops;180 else181 return -EINVAL;182 183 chip->bus = bus;184 chip->sw_addr = sw_addr;185 186 if (chip->smi_ops->init)187 return chip->smi_ops->init(chip);188 189 return 0;190}191