root/drivers/net/dsa/mv88e6xxx/smi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mv88e6xxx_smi_direct_read
  2. mv88e6xxx_smi_direct_write
  3. mv88e6xxx_smi_direct_wait
  4. mv88e6xxx_smi_dual_direct_read
  5. mv88e6xxx_smi_dual_direct_write
  6. mv88e6xxx_smi_indirect_read
  7. mv88e6xxx_smi_indirect_write
  8. mv88e6xxx_smi_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Marvell 88E6xxx System Management Interface (SMI) support
   4  *
   5  * Copyright (c) 2008 Marvell Semiconductor
   6  *
   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 address
  14  * (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 it
  17  * is the only device connected to the SMI master. In this mode it responds to
  18  * 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, allowing
  21  * multiple devices to share the SMI interface. In this mode it responds to only
  22  * 2 registers, used to indirectly access the internal SMI devices.
  23  *
  24  * Some chips use a different scheme: Only the ADDR4 pin is used for
  25  * configuration, and the device responds to 16 of the 32 SMI
  26  * addresses, allowing two to coexist on the same SMI interface.
  27  */
  28 
  29 static 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 
  43 static 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 
  55 static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
  56                                      int dev, int reg, int bit, int val)
  57 {
  58         u16 data;
  59         int err;
  60         int i;
  61 
  62         for (i = 0; i < 16; i++) {
  63                 err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
  64                 if (err)
  65                         return err;
  66 
  67                 if (!!(data & BIT(bit)) == !!val)
  68                         return 0;
  69 
  70                 usleep_range(1000, 2000);
  71         }
  72 
  73         return -ETIMEDOUT;
  74 }
  75 
  76 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
  77         .read = mv88e6xxx_smi_direct_read,
  78         .write = mv88e6xxx_smi_direct_write,
  79 };
  80 
  81 static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
  82                                           int dev, int reg, u16 *data)
  83 {
  84         return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
  85 }
  86 
  87 static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
  88                                            int dev, int reg, u16 data)
  89 {
  90         return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
  91 }
  92 
  93 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
  94         .read = mv88e6xxx_smi_dual_direct_read,
  95         .write = mv88e6xxx_smi_dual_direct_write,
  96 };
  97 
  98 /* Offset 0x00: SMI Command Register
  99  * Offset 0x01: SMI Data Register
 100  */
 101 
 102 static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
 103                                        int dev, int reg, u16 *data)
 104 {
 105         int err;
 106 
 107         err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
 108                                         MV88E6XXX_SMI_CMD, 15, 0);
 109         if (err)
 110                 return err;
 111 
 112         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
 113                                          MV88E6XXX_SMI_CMD,
 114                                          MV88E6XXX_SMI_CMD_BUSY |
 115                                          MV88E6XXX_SMI_CMD_MODE_22 |
 116                                          MV88E6XXX_SMI_CMD_OP_22_READ |
 117                                          (dev << 5) | reg);
 118         if (err)
 119                 return err;
 120 
 121         err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
 122                                         MV88E6XXX_SMI_CMD, 15, 0);
 123         if (err)
 124                 return err;
 125 
 126         return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
 127                                          MV88E6XXX_SMI_DATA, data);
 128 }
 129 
 130 static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
 131                                         int dev, int reg, u16 data)
 132 {
 133         int err;
 134 
 135         err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
 136                                         MV88E6XXX_SMI_CMD, 15, 0);
 137         if (err)
 138                 return err;
 139 
 140         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
 141                                          MV88E6XXX_SMI_DATA, data);
 142         if (err)
 143                 return err;
 144 
 145         err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
 146                                          MV88E6XXX_SMI_CMD,
 147                                          MV88E6XXX_SMI_CMD_BUSY |
 148                                          MV88E6XXX_SMI_CMD_MODE_22 |
 149                                          MV88E6XXX_SMI_CMD_OP_22_WRITE |
 150                                          (dev << 5) | reg);
 151         if (err)
 152                 return err;
 153 
 154         return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
 155                                          MV88E6XXX_SMI_CMD, 15, 0);
 156 }
 157 
 158 static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
 159         .read = mv88e6xxx_smi_indirect_read,
 160         .write = mv88e6xxx_smi_indirect_write,
 161 };
 162 
 163 int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
 164                        struct mii_bus *bus, int sw_addr)
 165 {
 166         if (chip->info->dual_chip)
 167                 chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
 168         else if (sw_addr == 0)
 169                 chip->smi_ops = &mv88e6xxx_smi_direct_ops;
 170         else if (chip->info->multi_chip)
 171                 chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
 172         else
 173                 return -EINVAL;
 174 
 175         chip->bus = bus;
 176         chip->sw_addr = sw_addr;
 177 
 178         return 0;
 179 }

/* [<][>][^][v][top][bottom][index][help] */