12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20d632c3dSBrandon Streiff /*
30d632c3dSBrandon Streiff * Marvell 88E6xxx Switch Global 2 Registers support
40d632c3dSBrandon Streiff *
50d632c3dSBrandon Streiff * Copyright (c) 2008 Marvell Semiconductor
60d632c3dSBrandon Streiff *
70d632c3dSBrandon Streiff * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
80d632c3dSBrandon Streiff * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
90d632c3dSBrandon Streiff *
100d632c3dSBrandon Streiff * Copyright (c) 2017 National Instruments
110d632c3dSBrandon Streiff * Brandon Streiff <brandon.streiff@ni.com>
120d632c3dSBrandon Streiff */
130d632c3dSBrandon Streiff
1428ae1e96SVivien Didelot #include <linux/bitfield.h>
1528ae1e96SVivien Didelot
160d632c3dSBrandon Streiff #include "global2.h"
170d632c3dSBrandon Streiff
180d632c3dSBrandon Streiff /* Offset 0x16: AVB Command Register
190d632c3dSBrandon Streiff * Offset 0x17: AVB Data Register
200d632c3dSBrandon Streiff *
210d632c3dSBrandon Streiff * There are two different versions of this register interface:
220d632c3dSBrandon Streiff * "6352": 3-bit "op" field, 4-bit "port" field.
230d632c3dSBrandon Streiff * "6390": 2-bit "op" field, 5-bit "port" field.
240d632c3dSBrandon Streiff *
250d632c3dSBrandon Streiff * The "op" codes are different between the two, as well as the special
260d632c3dSBrandon Streiff * port fields for global PTP and TAI configuration.
270d632c3dSBrandon Streiff */
280d632c3dSBrandon Streiff
290d632c3dSBrandon Streiff /* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
300d632c3dSBrandon Streiff * The hardware supports snapshotting up to four contiguous registers.
310d632c3dSBrandon Streiff */
mv88e6xxx_g2_avb_wait(struct mv88e6xxx_chip * chip)3228ae1e96SVivien Didelot static int mv88e6xxx_g2_avb_wait(struct mv88e6xxx_chip *chip)
3328ae1e96SVivien Didelot {
3428ae1e96SVivien Didelot int bit = __bf_shf(MV88E6352_G2_AVB_CMD_BUSY);
3528ae1e96SVivien Didelot
3628ae1e96SVivien Didelot return mv88e6xxx_g2_wait_bit(chip, MV88E6352_G2_AVB_CMD, bit, 0);
3728ae1e96SVivien Didelot }
3828ae1e96SVivien Didelot
mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip * chip,u16 readop,u16 * data,int len)390d632c3dSBrandon Streiff static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
400d632c3dSBrandon Streiff u16 *data, int len)
410d632c3dSBrandon Streiff {
420d632c3dSBrandon Streiff int err;
430d632c3dSBrandon Streiff int i;
440d632c3dSBrandon Streiff
4528ae1e96SVivien Didelot err = mv88e6xxx_g2_avb_wait(chip);
4628ae1e96SVivien Didelot if (err)
4728ae1e96SVivien Didelot return err;
4828ae1e96SVivien Didelot
490d632c3dSBrandon Streiff /* Hardware can only snapshot four words. */
500d632c3dSBrandon Streiff if (len > 4)
510d632c3dSBrandon Streiff return -E2BIG;
520d632c3dSBrandon Streiff
5328ae1e96SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
5428ae1e96SVivien Didelot MV88E6352_G2_AVB_CMD_BUSY | readop);
5528ae1e96SVivien Didelot if (err)
5628ae1e96SVivien Didelot return err;
5728ae1e96SVivien Didelot
5828ae1e96SVivien Didelot err = mv88e6xxx_g2_avb_wait(chip);
590d632c3dSBrandon Streiff if (err)
600d632c3dSBrandon Streiff return err;
610d632c3dSBrandon Streiff
620d632c3dSBrandon Streiff for (i = 0; i < len; ++i) {
630d632c3dSBrandon Streiff err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
640d632c3dSBrandon Streiff &data[i]);
650d632c3dSBrandon Streiff if (err)
660d632c3dSBrandon Streiff return err;
670d632c3dSBrandon Streiff }
680d632c3dSBrandon Streiff
690d632c3dSBrandon Streiff return 0;
700d632c3dSBrandon Streiff }
710d632c3dSBrandon Streiff
720d632c3dSBrandon Streiff /* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip * chip,u16 writeop,u16 data)730d632c3dSBrandon Streiff static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
740d632c3dSBrandon Streiff u16 data)
750d632c3dSBrandon Streiff {
760d632c3dSBrandon Streiff int err;
770d632c3dSBrandon Streiff
7828ae1e96SVivien Didelot err = mv88e6xxx_g2_avb_wait(chip);
7928ae1e96SVivien Didelot if (err)
8028ae1e96SVivien Didelot return err;
8128ae1e96SVivien Didelot
820d632c3dSBrandon Streiff err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
830d632c3dSBrandon Streiff if (err)
840d632c3dSBrandon Streiff return err;
850d632c3dSBrandon Streiff
8628ae1e96SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
8728ae1e96SVivien Didelot MV88E6352_G2_AVB_CMD_BUSY | writeop);
8828ae1e96SVivien Didelot
8928ae1e96SVivien Didelot return mv88e6xxx_g2_avb_wait(chip);
900d632c3dSBrandon Streiff }
910d632c3dSBrandon Streiff
mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip * chip,int port,int addr,u16 * data,int len)920d632c3dSBrandon Streiff static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
930d632c3dSBrandon Streiff int port, int addr, u16 *data,
940d632c3dSBrandon Streiff int len)
950d632c3dSBrandon Streiff {
960d632c3dSBrandon Streiff u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
970d632c3dSBrandon Streiff MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
980d632c3dSBrandon Streiff (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
990d632c3dSBrandon Streiff addr;
1000d632c3dSBrandon Streiff
1010d632c3dSBrandon Streiff return mv88e6xxx_g2_avb_read(chip, readop, data, len);
1020d632c3dSBrandon Streiff }
1030d632c3dSBrandon Streiff
mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip * chip,int port,int addr,u16 data)1040d632c3dSBrandon Streiff static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
1050d632c3dSBrandon Streiff int port, int addr, u16 data)
1060d632c3dSBrandon Streiff {
1070d632c3dSBrandon Streiff u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
1080d632c3dSBrandon Streiff (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
1090d632c3dSBrandon Streiff
1100d632c3dSBrandon Streiff return mv88e6xxx_g2_avb_write(chip, writeop, data);
1110d632c3dSBrandon Streiff }
1120d632c3dSBrandon Streiff
mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip * chip,int addr,u16 * data,int len)1130d632c3dSBrandon Streiff static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
1140d632c3dSBrandon Streiff u16 *data, int len)
1150d632c3dSBrandon Streiff {
1160d632c3dSBrandon Streiff return mv88e6352_g2_avb_port_ptp_read(chip,
1170d632c3dSBrandon Streiff MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
1180d632c3dSBrandon Streiff addr, data, len);
1190d632c3dSBrandon Streiff }
1200d632c3dSBrandon Streiff
mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip * chip,int addr,u16 data)1210d632c3dSBrandon Streiff static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
1220d632c3dSBrandon Streiff u16 data)
1230d632c3dSBrandon Streiff {
1240d632c3dSBrandon Streiff return mv88e6352_g2_avb_port_ptp_write(chip,
1250d632c3dSBrandon Streiff MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
1260d632c3dSBrandon Streiff addr, data);
1270d632c3dSBrandon Streiff }
1280d632c3dSBrandon Streiff
mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip * chip,int addr,u16 * data,int len)1290d632c3dSBrandon Streiff static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
1300d632c3dSBrandon Streiff u16 *data, int len)
1310d632c3dSBrandon Streiff {
1320d632c3dSBrandon Streiff return mv88e6352_g2_avb_port_ptp_read(chip,
1330d632c3dSBrandon Streiff MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
1340d632c3dSBrandon Streiff addr, data, len);
1350d632c3dSBrandon Streiff }
1360d632c3dSBrandon Streiff
mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip * chip,int addr,u16 data)1370d632c3dSBrandon Streiff static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
1380d632c3dSBrandon Streiff u16 data)
1390d632c3dSBrandon Streiff {
1400d632c3dSBrandon Streiff return mv88e6352_g2_avb_port_ptp_write(chip,
1410d632c3dSBrandon Streiff MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
1420d632c3dSBrandon Streiff addr, data);
1430d632c3dSBrandon Streiff }
1440d632c3dSBrandon Streiff
1450d632c3dSBrandon Streiff const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
1460d632c3dSBrandon Streiff .port_ptp_read = mv88e6352_g2_avb_port_ptp_read,
1470d632c3dSBrandon Streiff .port_ptp_write = mv88e6352_g2_avb_port_ptp_write,
1480d632c3dSBrandon Streiff .ptp_read = mv88e6352_g2_avb_ptp_read,
1490d632c3dSBrandon Streiff .ptp_write = mv88e6352_g2_avb_ptp_write,
1500d632c3dSBrandon Streiff .tai_read = mv88e6352_g2_avb_tai_read,
1510d632c3dSBrandon Streiff .tai_write = mv88e6352_g2_avb_tai_write,
1520d632c3dSBrandon Streiff };
1530d632c3dSBrandon Streiff
mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip * chip,int addr,u16 * data,int len)154a469a612SAndrew Lunn static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
155a469a612SAndrew Lunn u16 *data, int len)
156a469a612SAndrew Lunn {
157a469a612SAndrew Lunn return mv88e6352_g2_avb_port_ptp_read(chip,
158a469a612SAndrew Lunn MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
159a469a612SAndrew Lunn addr, data, len);
160a469a612SAndrew Lunn }
161a469a612SAndrew Lunn
mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip * chip,int addr,u16 data)162a469a612SAndrew Lunn static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
163a469a612SAndrew Lunn u16 data)
164a469a612SAndrew Lunn {
165a469a612SAndrew Lunn return mv88e6352_g2_avb_port_ptp_write(chip,
166a469a612SAndrew Lunn MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
167a469a612SAndrew Lunn addr, data);
168a469a612SAndrew Lunn }
169a469a612SAndrew Lunn
170a469a612SAndrew Lunn const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
171a469a612SAndrew Lunn .port_ptp_read = mv88e6352_g2_avb_port_ptp_read,
172a469a612SAndrew Lunn .port_ptp_write = mv88e6352_g2_avb_port_ptp_write,
173a469a612SAndrew Lunn .ptp_read = mv88e6352_g2_avb_ptp_read,
174a469a612SAndrew Lunn .ptp_write = mv88e6352_g2_avb_ptp_write,
175a469a612SAndrew Lunn .tai_read = mv88e6165_g2_avb_tai_read,
176a469a612SAndrew Lunn .tai_write = mv88e6165_g2_avb_tai_write,
177a469a612SAndrew Lunn };
178a469a612SAndrew Lunn
mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip * chip,int port,int addr,u16 * data,int len)1790d632c3dSBrandon Streiff static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
1800d632c3dSBrandon Streiff int port, int addr, u16 *data,
1810d632c3dSBrandon Streiff int len)
1820d632c3dSBrandon Streiff {
1830d632c3dSBrandon Streiff u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
1840d632c3dSBrandon Streiff MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
1850d632c3dSBrandon Streiff (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
1860d632c3dSBrandon Streiff addr;
1870d632c3dSBrandon Streiff
1880d632c3dSBrandon Streiff return mv88e6xxx_g2_avb_read(chip, readop, data, len);
1890d632c3dSBrandon Streiff }
1900d632c3dSBrandon Streiff
mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip * chip,int port,int addr,u16 data)1910d632c3dSBrandon Streiff static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
1920d632c3dSBrandon Streiff int port, int addr, u16 data)
1930d632c3dSBrandon Streiff {
1940d632c3dSBrandon Streiff u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
1950d632c3dSBrandon Streiff (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
1960d632c3dSBrandon Streiff
1970d632c3dSBrandon Streiff return mv88e6xxx_g2_avb_write(chip, writeop, data);
1980d632c3dSBrandon Streiff }
1990d632c3dSBrandon Streiff
mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip * chip,int addr,u16 * data,int len)2000d632c3dSBrandon Streiff static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
2010d632c3dSBrandon Streiff u16 *data, int len)
2020d632c3dSBrandon Streiff {
2030d632c3dSBrandon Streiff return mv88e6390_g2_avb_port_ptp_read(chip,
2040d632c3dSBrandon Streiff MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
2050d632c3dSBrandon Streiff addr, data, len);
2060d632c3dSBrandon Streiff }
2070d632c3dSBrandon Streiff
mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip * chip,int addr,u16 data)2080d632c3dSBrandon Streiff static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
2090d632c3dSBrandon Streiff u16 data)
2100d632c3dSBrandon Streiff {
2110d632c3dSBrandon Streiff return mv88e6390_g2_avb_port_ptp_write(chip,
2120d632c3dSBrandon Streiff MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
2130d632c3dSBrandon Streiff addr, data);
2140d632c3dSBrandon Streiff }
2150d632c3dSBrandon Streiff
mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip * chip,int addr,u16 * data,int len)2160d632c3dSBrandon Streiff static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
2170d632c3dSBrandon Streiff u16 *data, int len)
2180d632c3dSBrandon Streiff {
2190d632c3dSBrandon Streiff return mv88e6390_g2_avb_port_ptp_read(chip,
2200d632c3dSBrandon Streiff MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
2210d632c3dSBrandon Streiff addr, data, len);
2220d632c3dSBrandon Streiff }
2230d632c3dSBrandon Streiff
mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip * chip,int addr,u16 data)2240d632c3dSBrandon Streiff static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
2250d632c3dSBrandon Streiff u16 data)
2260d632c3dSBrandon Streiff {
2270d632c3dSBrandon Streiff return mv88e6390_g2_avb_port_ptp_write(chip,
2280d632c3dSBrandon Streiff MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
2290d632c3dSBrandon Streiff addr, data);
2300d632c3dSBrandon Streiff }
2310d632c3dSBrandon Streiff
2320d632c3dSBrandon Streiff const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
2330d632c3dSBrandon Streiff .port_ptp_read = mv88e6390_g2_avb_port_ptp_read,
2340d632c3dSBrandon Streiff .port_ptp_write = mv88e6390_g2_avb_port_ptp_write,
2350d632c3dSBrandon Streiff .ptp_read = mv88e6390_g2_avb_ptp_read,
2360d632c3dSBrandon Streiff .ptp_write = mv88e6390_g2_avb_ptp_write,
2370d632c3dSBrandon Streiff .tai_read = mv88e6390_g2_avb_tai_read,
2380d632c3dSBrandon Streiff .tai_write = mv88e6390_g2_avb_tai_write,
2390d632c3dSBrandon Streiff };
240