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 */ 32 static 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 39 static 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. */ 73 static 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 92 static 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 104 static 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 113 static 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 121 static 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 129 static 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 137 static 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 145 const 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 154 static 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 162 static 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 170 const 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 179 static 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 191 static 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 200 static 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 208 static 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 216 static 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 224 static 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 232 const 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