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