| /* |
| * Marvell 88E6xxx Switch Global 2 Registers support |
| * |
| * Copyright (c) 2008 Marvell Semiconductor |
| * |
| * Copyright (c) 2016-2017 Savoir-faire Linux Inc. |
| * Vivien Didelot <vivien.didelot@savoirfairelinux.com> |
| * |
| * Copyright (c) 2017 National Instruments |
| * Brandon Streiff <brandon.streiff@ni.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| */ |
| |
| #include "global2.h" |
| |
| /* Offset 0x16: AVB Command Register |
| * Offset 0x17: AVB Data Register |
| * |
| * There are two different versions of this register interface: |
| * "6352": 3-bit "op" field, 4-bit "port" field. |
| * "6390": 2-bit "op" field, 5-bit "port" field. |
| * |
| * The "op" codes are different between the two, as well as the special |
| * port fields for global PTP and TAI configuration. |
| */ |
| |
| /* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words. |
| * The hardware supports snapshotting up to four contiguous registers. |
| */ |
| static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop, |
| u16 *data, int len) |
| { |
| int err; |
| int i; |
| |
| /* Hardware can only snapshot four words. */ |
| if (len > 4) |
| return -E2BIG; |
| |
| err = mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, readop); |
| if (err) |
| return err; |
| |
| for (i = 0; i < len; ++i) { |
| err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA, |
| &data[i]); |
| if (err) |
| return err; |
| } |
| |
| return 0; |
| } |
| |
| /* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */ |
| static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop, |
| u16 data) |
| { |
| int err; |
| |
| err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data); |
| if (err) |
| return err; |
| |
| return mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, writeop); |
| } |
| |
| static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, |
| int port, int addr, u16 *data, |
| int len) |
| { |
| u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ : |
| MV88E6352_G2_AVB_CMD_OP_READ_INCR) | |
| (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | |
| addr; |
| |
| return mv88e6xxx_g2_avb_read(chip, readop, data, len); |
| } |
| |
| static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip, |
| int port, int addr, u16 data) |
| { |
| u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) | |
| (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr; |
| |
| return mv88e6xxx_g2_avb_write(chip, writeop, data); |
| } |
| |
| static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr, |
| u16 *data, int len) |
| { |
| return mv88e6352_g2_avb_port_ptp_read(chip, |
| MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL, |
| addr, data, len); |
| } |
| |
| static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr, |
| u16 data) |
| { |
| return mv88e6352_g2_avb_port_ptp_write(chip, |
| MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL, |
| addr, data); |
| } |
| |
| static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr, |
| u16 *data, int len) |
| { |
| return mv88e6352_g2_avb_port_ptp_read(chip, |
| MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL, |
| addr, data, len); |
| } |
| |
| static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, |
| u16 data) |
| { |
| return mv88e6352_g2_avb_port_ptp_write(chip, |
| MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL, |
| addr, data); |
| } |
| |
| const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = { |
| .port_ptp_read = mv88e6352_g2_avb_port_ptp_read, |
| .port_ptp_write = mv88e6352_g2_avb_port_ptp_write, |
| .ptp_read = mv88e6352_g2_avb_ptp_read, |
| .ptp_write = mv88e6352_g2_avb_ptp_write, |
| .tai_read = mv88e6352_g2_avb_tai_read, |
| .tai_write = mv88e6352_g2_avb_tai_write, |
| }; |
| |
| static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, |
| int port, int addr, u16 *data, |
| int len) |
| { |
| u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ : |
| MV88E6390_G2_AVB_CMD_OP_READ_INCR) | |
| (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | |
| addr; |
| |
| return mv88e6xxx_g2_avb_read(chip, readop, data, len); |
| } |
| |
| static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip, |
| int port, int addr, u16 data) |
| { |
| u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) | |
| (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr; |
| |
| return mv88e6xxx_g2_avb_write(chip, writeop, data); |
| } |
| |
| static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr, |
| u16 *data, int len) |
| { |
| return mv88e6390_g2_avb_port_ptp_read(chip, |
| MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, |
| addr, data, len); |
| } |
| |
| static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr, |
| u16 data) |
| { |
| return mv88e6390_g2_avb_port_ptp_write(chip, |
| MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL, |
| addr, data); |
| } |
| |
| static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr, |
| u16 *data, int len) |
| { |
| return mv88e6390_g2_avb_port_ptp_read(chip, |
| MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, |
| addr, data, len); |
| } |
| |
| static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr, |
| u16 data) |
| { |
| return mv88e6390_g2_avb_port_ptp_write(chip, |
| MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL, |
| addr, data); |
| } |
| |
| const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = { |
| .port_ptp_read = mv88e6390_g2_avb_port_ptp_read, |
| .port_ptp_write = mv88e6390_g2_avb_port_ptp_write, |
| .ptp_read = mv88e6390_g2_avb_ptp_read, |
| .ptp_write = mv88e6390_g2_avb_ptp_write, |
| .tai_read = mv88e6390_g2_avb_tai_read, |
| .tai_write = mv88e6390_g2_avb_tai_write, |
| }; |