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 "global2.h" 15 16 /* Offset 0x16: AVB Command Register 17 * Offset 0x17: AVB Data Register 18 * 19 * There are two different versions of this register interface: 20 * "6352": 3-bit "op" field, 4-bit "port" field. 21 * "6390": 2-bit "op" field, 5-bit "port" field. 22 * 23 * The "op" codes are different between the two, as well as the special 24 * port fields for global PTP and TAI configuration. 25 */ 26 27 /* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words. 28 * The hardware supports snapshotting up to four contiguous registers. 29 */ 30 static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop, 31 u16 *data, int len) 32 { 33 int err; 34 int i; 35 36 /* Hardware can only snapshot four words. */ 37 if (len > 4) 38 return -E2BIG; 39 40 err = mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, readop); 41 if (err) 42 return err; 43 44 for (i = 0; i < len; ++i) { 45 err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA, 46 &data[i]); 47 if (err) 48 return err; 49 } 50 51 return 0; 52 } 53 54 /* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */ 55 static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop, 56 u16 data) 57 { 58 int err; 59 60 err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data); 61 if (err) 62 return err; 63 64 return mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, writeop); 65 } 66 67 static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, 68 int port, int addr, u16 *data, 69 int len) 70 { 71 u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ : 72 MV88E6352_G2_AVB_CMD_OP_READ_INCR) | 73 (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | 74 addr; 75 76 return mv88e6xxx_g2_avb_read(chip, readop, data, len); 77 } 78 79 static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip, 80 int port, int addr, u16 data) 81 { 82 u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) | 83 (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr; 84 85 return mv88e6xxx_g2_avb_write(chip, writeop, data); 86 } 87 88 static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr, 89 u16 *data, int len) 90 { 91 return mv88e6352_g2_avb_port_ptp_read(chip, 92 MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL, 93 addr, data, len); 94 } 95 96 static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr, 97 u16 data) 98 { 99 return mv88e6352_g2_avb_port_ptp_write(chip, 100 MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL, 101 addr, data); 102 } 103 104 static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr, 105 u16 *data, int len) 106 { 107 return mv88e6352_g2_avb_port_ptp_read(chip, 108 MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL, 109 addr, data, len); 110 } 111 112 static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, 113 u16 data) 114 { 115 return mv88e6352_g2_avb_port_ptp_write(chip, 116 MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL, 117 addr, data); 118 } 119 120 const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = { 121 .port_ptp_read = mv88e6352_g2_avb_port_ptp_read, 122 .port_ptp_write = mv88e6352_g2_avb_port_ptp_write, 123 .ptp_read = mv88e6352_g2_avb_ptp_read, 124 .ptp_write = mv88e6352_g2_avb_ptp_write, 125 .tai_read = mv88e6352_g2_avb_tai_read, 126 .tai_write = mv88e6352_g2_avb_tai_write, 127 }; 128 129 static int mv88e6165_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 MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL, 134 addr, data, len); 135 } 136 137 static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, 138 u16 data) 139 { 140 return mv88e6352_g2_avb_port_ptp_write(chip, 141 MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL, 142 addr, data); 143 } 144 145 const struct mv88e6xxx_avb_ops mv88e6165_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 = mv88e6165_g2_avb_tai_read, 151 .tai_write = mv88e6165_g2_avb_tai_write, 152 }; 153 154 static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, 155 int port, int addr, u16 *data, 156 int len) 157 { 158 u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ : 159 MV88E6390_G2_AVB_CMD_OP_READ_INCR) | 160 (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | 161 addr; 162 163 return mv88e6xxx_g2_avb_read(chip, readop, data, len); 164 } 165 166 static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip, 167 int port, int addr, u16 data) 168 { 169 u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) | 170 (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr; 171 172 return mv88e6xxx_g2_avb_write(chip, writeop, data); 173 } 174 175 static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr, 176 u16 *data, int len) 177 { 178 return mv88e6390_g2_avb_port_ptp_read(chip, 179 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, 180 addr, data, len); 181 } 182 183 static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr, 184 u16 data) 185 { 186 return mv88e6390_g2_avb_port_ptp_write(chip, 187 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, 188 addr, data); 189 } 190 191 static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr, 192 u16 *data, int len) 193 { 194 return mv88e6390_g2_avb_port_ptp_read(chip, 195 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, 196 addr, data, len); 197 } 198 199 static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, 200 u16 data) 201 { 202 return mv88e6390_g2_avb_port_ptp_write(chip, 203 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, 204 addr, data); 205 } 206 207 const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = { 208 .port_ptp_read = mv88e6390_g2_avb_port_ptp_read, 209 .port_ptp_write = mv88e6390_g2_avb_port_ptp_write, 210 .ptp_read = mv88e6390_g2_avb_ptp_read, 211 .ptp_write = mv88e6390_g2_avb_ptp_write, 212 .tai_read = mv88e6390_g2_avb_tai_read, 213 .tai_write = mv88e6390_g2_avb_tai_write, 214 }; 215