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 mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, 134 int port, int addr, u16 *data, 135 int len) 136 { 137 u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ : 138 MV88E6390_G2_AVB_CMD_OP_READ_INCR) | 139 (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | 140 addr; 141 142 return mv88e6xxx_g2_avb_read(chip, readop, data, len); 143 } 144 145 static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip, 146 int port, int addr, u16 data) 147 { 148 u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) | 149 (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr; 150 151 return mv88e6xxx_g2_avb_write(chip, writeop, data); 152 } 153 154 static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr, 155 u16 *data, int len) 156 { 157 return mv88e6390_g2_avb_port_ptp_read(chip, 158 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, 159 addr, data, len); 160 } 161 162 static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr, 163 u16 data) 164 { 165 return mv88e6390_g2_avb_port_ptp_write(chip, 166 MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, 167 addr, data); 168 } 169 170 static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr, 171 u16 *data, int len) 172 { 173 return mv88e6390_g2_avb_port_ptp_read(chip, 174 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, 175 addr, data, len); 176 } 177 178 static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, 179 u16 data) 180 { 181 return mv88e6390_g2_avb_port_ptp_write(chip, 182 MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, 183 addr, data); 184 } 185 186 const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = { 187 .port_ptp_read = mv88e6390_g2_avb_port_ptp_read, 188 .port_ptp_write = mv88e6390_g2_avb_port_ptp_write, 189 .ptp_read = mv88e6390_g2_avb_ptp_read, 190 .ptp_write = mv88e6390_g2_avb_ptp_write, 191 .tai_read = mv88e6390_g2_avb_tai_read, 192 .tai_write = mv88e6390_g2_avb_tai_write, 193 }; 194