global2_avb.c (6545B)
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};