240 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Marvell 88E6xxx Switch Global 2 Registers support4 *5 * Copyright (c) 2008 Marvell Semiconductor6 *7 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.8 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>9 *10 * Copyright (c) 2017 National Instruments11 * Brandon Streiff <brandon.streiff@ni.com>12 */13 14#include <linux/bitfield.h>15 16#include "global2.h"17 18/* Offset 0x16: AVB Command Register19 * Offset 0x17: AVB Data Register20 *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 special26 * 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