Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Marvell 88E6xxx System Management Interface (SMI) support
0004  *
0005  * Copyright (c) 2008 Marvell Semiconductor
0006  *
0007  * Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
0008  */
0009 
0010 #include "chip.h"
0011 #include "smi.h"
0012 
0013 /* The switch ADDR[4:1] configuration pins define the chip SMI device address
0014  * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
0015  *
0016  * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
0017  * is the only device connected to the SMI master. In this mode it responds to
0018  * all 32 possible SMI addresses, and thus maps directly the internal devices.
0019  *
0020  * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
0021  * multiple devices to share the SMI interface. In this mode it responds to only
0022  * 2 registers, used to indirectly access the internal SMI devices.
0023  *
0024  * Some chips use a different scheme: Only the ADDR4 pin is used for
0025  * configuration, and the device responds to 16 of the 32 SMI
0026  * addresses, allowing two to coexist on the same SMI interface.
0027  */
0028 
0029 static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
0030                      int dev, int reg, u16 *data)
0031 {
0032     int ret;
0033 
0034     ret = mdiobus_read_nested(chip->bus, dev, reg);
0035     if (ret < 0)
0036         return ret;
0037 
0038     *data = ret & 0xffff;
0039 
0040     return 0;
0041 }
0042 
0043 static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,
0044                       int dev, int reg, u16 data)
0045 {
0046     int ret;
0047 
0048     ret = mdiobus_write_nested(chip->bus, dev, reg, data);
0049     if (ret < 0)
0050         return ret;
0051 
0052     return 0;
0053 }
0054 
0055 static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
0056                      int dev, int reg, int bit, int val)
0057 {
0058     const unsigned long timeout = jiffies + msecs_to_jiffies(50);
0059     u16 data;
0060     int err;
0061     int i;
0062 
0063     /* Even if the initial poll takes longer than 50ms, always do
0064      * at least one more attempt.
0065      */
0066     for (i = 0; time_before(jiffies, timeout) || (i < 2); i++) {
0067         err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
0068         if (err)
0069             return err;
0070 
0071         if (!!(data & BIT(bit)) == !!val)
0072             return 0;
0073 
0074         if (i < 2)
0075             cpu_relax();
0076         else
0077             usleep_range(1000, 2000);
0078     }
0079 
0080     return -ETIMEDOUT;
0081 }
0082 
0083 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
0084     .read = mv88e6xxx_smi_direct_read,
0085     .write = mv88e6xxx_smi_direct_write,
0086 };
0087 
0088 static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
0089                       int dev, int reg, u16 *data)
0090 {
0091     return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
0092 }
0093 
0094 static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
0095                        int dev, int reg, u16 data)
0096 {
0097     return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
0098 }
0099 
0100 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
0101     .read = mv88e6xxx_smi_dual_direct_read,
0102     .write = mv88e6xxx_smi_dual_direct_write,
0103 };
0104 
0105 /* Offset 0x00: SMI Command Register
0106  * Offset 0x01: SMI Data Register
0107  */
0108 
0109 static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
0110                        int dev, int reg, u16 *data)
0111 {
0112     int err;
0113 
0114     err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0115                      MV88E6XXX_SMI_CMD,
0116                      MV88E6XXX_SMI_CMD_BUSY |
0117                      MV88E6XXX_SMI_CMD_MODE_22 |
0118                      MV88E6XXX_SMI_CMD_OP_22_READ |
0119                      (dev << 5) | reg);
0120     if (err)
0121         return err;
0122 
0123     err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0124                     MV88E6XXX_SMI_CMD, 15, 0);
0125     if (err)
0126         return err;
0127 
0128     return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
0129                      MV88E6XXX_SMI_DATA, data);
0130 }
0131 
0132 static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
0133                     int dev, int reg, u16 data)
0134 {
0135     int err;
0136 
0137     err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0138                      MV88E6XXX_SMI_DATA, data);
0139     if (err)
0140         return err;
0141 
0142     err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
0143                      MV88E6XXX_SMI_CMD,
0144                      MV88E6XXX_SMI_CMD_BUSY |
0145                      MV88E6XXX_SMI_CMD_MODE_22 |
0146                      MV88E6XXX_SMI_CMD_OP_22_WRITE |
0147                      (dev << 5) | reg);
0148     if (err)
0149         return err;
0150 
0151     return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0152                      MV88E6XXX_SMI_CMD, 15, 0);
0153 }
0154 
0155 static int mv88e6xxx_smi_indirect_init(struct mv88e6xxx_chip *chip)
0156 {
0157     /* Ensure that the chip starts out in the ready state. As both
0158      * reads and writes always ensure this on return, they can
0159      * safely depend on the chip not being busy on entry.
0160      */
0161     return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
0162                      MV88E6XXX_SMI_CMD, 15, 0);
0163 }
0164 
0165 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
0166     .read = mv88e6xxx_smi_indirect_read,
0167     .write = mv88e6xxx_smi_indirect_write,
0168     .init = mv88e6xxx_smi_indirect_init,
0169 };
0170 
0171 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
0172                struct mii_bus *bus, int sw_addr)
0173 {
0174     if (chip->info->dual_chip)
0175         chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
0176     else if (sw_addr == 0)
0177         chip->smi_ops = &mv88e6xxx_smi_direct_ops;
0178     else if (chip->info->multi_chip)
0179         chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
0180     else
0181         return -EINVAL;
0182 
0183     chip->bus = bus;
0184     chip->sw_addr = sw_addr;
0185 
0186     if (chip->smi_ops->init)
0187         return chip->smi_ops->init(chip);
0188 
0189     return 0;
0190 }