linux/drivers/net/dsa/mv88e6xxx/global2_avb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Marvell 88E6xxx Switch Global 2 Registers support
   4 *
   5 * Copyright (c) 2008 Marvell Semiconductor
   6 *
   7 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
   8 *      Vivien Didelot <vivien.didelot@savoirfairelinux.com>
   9 *
  10 * Copyright (c) 2017 National Instruments
  11 *      Brandon Streiff <brandon.streiff@ni.com>
  12 */
  13
  14#include <linux/bitfield.h>
  15
  16#include "global2.h"
  17
  18/* Offset 0x16: AVB Command Register
  19 * Offset 0x17: AVB Data Register
  20 *
  21 * There are two different versions of this register interface:
  22 *    "6352": 3-bit "op" field, 4-bit "port" field.
  23 *    "6390": 2-bit "op" field, 5-bit "port" field.
  24 *
  25 * The "op" codes are different between the two, as well as the special
  26 * port fields for global PTP and TAI configuration.
  27 */
  28
  29/* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
  30 * The hardware supports snapshotting up to four contiguous registers.
  31 */
  32static int mv88e6xxx_g2_avb_wait(struct mv88e6xxx_chip *chip)
  33{
  34        int bit = __bf_shf(MV88E6352_G2_AVB_CMD_BUSY);
  35
  36        return mv88e6xxx_g2_wait_bit(chip, MV88E6352_G2_AVB_CMD, bit, 0);
  37}
  38
  39static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
  40                                 u16 *data, int len)
  41{
  42        int err;
  43        int i;
  44
  45        err = mv88e6xxx_g2_avb_wait(chip);
  46        if (err)
  47                return err;
  48
  49        /* Hardware can only snapshot four words. */
  50        if (len > 4)
  51                return -E2BIG;
  52
  53        err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
  54                                 MV88E6352_G2_AVB_CMD_BUSY | readop);
  55        if (err)
  56                return err;
  57
  58        err = mv88e6xxx_g2_avb_wait(chip);
  59        if (err)
  60                return err;
  61
  62        for (i = 0; i < len; ++i) {
  63                err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
  64                                        &data[i]);
  65                if (err)
  66                        return err;
  67        }
  68
  69        return 0;
  70}
  71
  72/* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
  73static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
  74                                  u16 data)
  75{
  76        int err;
  77
  78        err = mv88e6xxx_g2_avb_wait(chip);
  79        if (err)
  80                return err;
  81
  82        err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
  83        if (err)
  84                return err;
  85
  86        err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
  87                                 MV88E6352_G2_AVB_CMD_BUSY | writeop);
  88
  89        return mv88e6xxx_g2_avb_wait(chip);
  90}
  91
  92static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
  93                                          int port, int addr, u16 *data,
  94                                          int len)
  95{
  96        u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
  97                                 MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
  98                     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
  99                     addr;
 100
 101        return mv88e6xxx_g2_avb_read(chip, readop, data, len);
 102}
 103
 104static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
 105                                           int port, int addr, u16 data)
 106{
 107        u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
 108                      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
 109
 110        return mv88e6xxx_g2_avb_write(chip, writeop, data);
 111}
 112
 113static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
 114                                     u16 *data, int len)
 115{
 116        return mv88e6352_g2_avb_port_ptp_read(chip,
 117                                        MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
 118                                        addr, data, len);
 119}
 120
 121static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
 122                                      u16 data)
 123{
 124        return mv88e6352_g2_avb_port_ptp_write(chip,
 125                                        MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
 126                                        addr, data);
 127}
 128
 129static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
 130                                     u16 *data, int len)
 131{
 132        return mv88e6352_g2_avb_port_ptp_read(chip,
 133                                        MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
 134                                        addr, data, len);
 135}
 136
 137static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
 138                                      u16 data)
 139{
 140        return mv88e6352_g2_avb_port_ptp_write(chip,
 141                                        MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
 142                                        addr, data);
 143}
 144
 145const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
 146        .port_ptp_read          = mv88e6352_g2_avb_port_ptp_read,
 147        .port_ptp_write         = mv88e6352_g2_avb_port_ptp_write,
 148        .ptp_read               = mv88e6352_g2_avb_ptp_read,
 149        .ptp_write              = mv88e6352_g2_avb_ptp_write,
 150        .tai_read               = mv88e6352_g2_avb_tai_read,
 151        .tai_write              = mv88e6352_g2_avb_tai_write,
 152};
 153
 154static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
 155                                     u16 *data, int len)
 156{
 157        return mv88e6352_g2_avb_port_ptp_read(chip,
 158                                        MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
 159                                        addr, data, len);
 160}
 161
 162static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
 163                                      u16 data)
 164{
 165        return mv88e6352_g2_avb_port_ptp_write(chip,
 166                                        MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
 167                                        addr, data);
 168}
 169
 170const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
 171        .port_ptp_read          = mv88e6352_g2_avb_port_ptp_read,
 172        .port_ptp_write         = mv88e6352_g2_avb_port_ptp_write,
 173        .ptp_read               = mv88e6352_g2_avb_ptp_read,
 174        .ptp_write              = mv88e6352_g2_avb_ptp_write,
 175        .tai_read               = mv88e6165_g2_avb_tai_read,
 176        .tai_write              = mv88e6165_g2_avb_tai_write,
 177};
 178
 179static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
 180                                          int port, int addr, u16 *data,
 181                                          int len)
 182{
 183        u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
 184                                 MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
 185                     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
 186                     addr;
 187
 188        return mv88e6xxx_g2_avb_read(chip, readop, data, len);
 189}
 190
 191static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
 192                                           int port, int addr, u16 data)
 193{
 194        u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
 195                      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
 196
 197        return mv88e6xxx_g2_avb_write(chip, writeop, data);
 198}
 199
 200static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
 201                                     u16 *data, int len)
 202{
 203        return mv88e6390_g2_avb_port_ptp_read(chip,
 204                                        MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
 205                                        addr, data, len);
 206}
 207
 208static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
 209                                      u16 data)
 210{
 211        return mv88e6390_g2_avb_port_ptp_write(chip,
 212                                        MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
 213                                        addr, data);
 214}
 215
 216static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
 217                                     u16 *data, int len)
 218{
 219        return mv88e6390_g2_avb_port_ptp_read(chip,
 220                                        MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
 221                                        addr, data, len);
 222}
 223
 224static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
 225                                      u16 data)
 226{
 227        return mv88e6390_g2_avb_port_ptp_write(chip,
 228                                        MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
 229                                        addr, data);
 230}
 231
 232const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
 233        .port_ptp_read          = mv88e6390_g2_avb_port_ptp_read,
 234        .port_ptp_write         = mv88e6390_g2_avb_port_ptp_write,
 235        .ptp_read               = mv88e6390_g2_avb_ptp_read,
 236        .ptp_write              = mv88e6390_g2_avb_ptp_write,
 237        .tai_read               = mv88e6390_g2_avb_tai_read,
 238        .tai_write              = mv88e6390_g2_avb_tai_write,
 239};
 240