^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Marvell 88E6xxx System Management Interface (SMI) support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2008 Marvell Semiconductor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "chip.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "smi.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /* The switch ADDR[4:1] configuration pins define the chip SMI device address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * is the only device connected to the SMI master. In this mode it responds to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * all 32 possible SMI addresses, and thus maps directly the internal devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * multiple devices to share the SMI interface. In this mode it responds to only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * 2 registers, used to indirectly access the internal SMI devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Some chips use a different scheme: Only the ADDR4 pin is used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * configuration, and the device responds to 16 of the 32 SMI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * addresses, allowing two to coexist on the same SMI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int dev, int reg, u16 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ret = mdiobus_read_nested(chip->bus, dev, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *data = ret & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int dev, int reg, u16 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ret = mdiobus_write_nested(chip->bus, dev, reg, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int dev, int reg, int bit, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) for (i = 0; i < 16; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!!(data & BIT(bit)) == !!val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .read = mv88e6xxx_smi_direct_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .write = mv88e6xxx_smi_direct_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int dev, int reg, u16 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int dev, int reg, u16 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .read = mv88e6xxx_smi_dual_direct_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .write = mv88e6xxx_smi_dual_direct_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* Offset 0x00: SMI Command Register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Offset 0x01: SMI Data Register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int dev, int reg, u16 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MV88E6XXX_SMI_CMD, 15, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) MV88E6XXX_SMI_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) MV88E6XXX_SMI_CMD_BUSY |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) MV88E6XXX_SMI_CMD_MODE_22 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) MV88E6XXX_SMI_CMD_OP_22_READ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) (dev << 5) | reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) MV88E6XXX_SMI_CMD, 15, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) MV88E6XXX_SMI_DATA, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int dev, int reg, u16 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) MV88E6XXX_SMI_CMD, 15, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) MV88E6XXX_SMI_DATA, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) MV88E6XXX_SMI_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) MV88E6XXX_SMI_CMD_BUSY |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) MV88E6XXX_SMI_CMD_MODE_22 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) MV88E6XXX_SMI_CMD_OP_22_WRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) (dev << 5) | reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) MV88E6XXX_SMI_CMD, 15, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .read = mv88e6xxx_smi_indirect_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .write = mv88e6xxx_smi_indirect_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct mii_bus *bus, int sw_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (chip->info->dual_chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) else if (sw_addr == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) chip->smi_ops = &mv88e6xxx_smi_direct_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) else if (chip->info->multi_chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) chip->bus = bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) chip->sw_addr = sw_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }