1a935c052SVivien Didelot /* 2a935c052SVivien Didelot * Marvell 88E6xxx Switch Global (1) Registers support 3a935c052SVivien Didelot * 4a935c052SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 5a935c052SVivien Didelot * 6a935c052SVivien Didelot * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com> 7a935c052SVivien Didelot * 8a935c052SVivien Didelot * This program is free software; you can redistribute it and/or modify 9a935c052SVivien Didelot * it under the terms of the GNU General Public License as published by 10a935c052SVivien Didelot * the Free Software Foundation; either version 2 of the License, or 11a935c052SVivien Didelot * (at your option) any later version. 12a935c052SVivien Didelot */ 13a935c052SVivien Didelot 14a935c052SVivien Didelot #include "mv88e6xxx.h" 15a935c052SVivien Didelot #include "global1.h" 16a935c052SVivien Didelot 17a935c052SVivien Didelot int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) 18a935c052SVivien Didelot { 19a935c052SVivien Didelot int addr = chip->info->global1_addr; 20a935c052SVivien Didelot 21a935c052SVivien Didelot return mv88e6xxx_read(chip, addr, reg, val); 22a935c052SVivien Didelot } 23a935c052SVivien Didelot 24a935c052SVivien Didelot int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val) 25a935c052SVivien Didelot { 26a935c052SVivien Didelot int addr = chip->info->global1_addr; 27a935c052SVivien Didelot 28a935c052SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 29a935c052SVivien Didelot } 30a935c052SVivien Didelot 31a935c052SVivien Didelot int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) 32a935c052SVivien Didelot { 33a935c052SVivien Didelot return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask); 34a935c052SVivien Didelot } 35a605a0feSAndrew Lunn 3633641994SAndrew Lunn /* Offset 0x1a: Monitor Control */ 3733641994SAndrew Lunn /* Offset 0x1a: Monitor & MGMT Control on some devices */ 3833641994SAndrew Lunn 3933641994SAndrew Lunn int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) 4033641994SAndrew Lunn { 4133641994SAndrew Lunn u16 reg; 4233641994SAndrew Lunn int err; 4333641994SAndrew Lunn 4433641994SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); 4533641994SAndrew Lunn if (err) 4633641994SAndrew Lunn return err; 4733641994SAndrew Lunn 4833641994SAndrew Lunn reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK | 4933641994SAndrew Lunn GLOBAL_MONITOR_CONTROL_EGRESS_MASK); 5033641994SAndrew Lunn 5133641994SAndrew Lunn reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT | 5233641994SAndrew Lunn port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT; 5333641994SAndrew Lunn 5433641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 5533641994SAndrew Lunn } 5633641994SAndrew Lunn 5733641994SAndrew Lunn /* Older generations also call this the ARP destination. It has been 5833641994SAndrew Lunn * generalized in more modern devices such that more than ARP can 5933641994SAndrew Lunn * egress it 6033641994SAndrew Lunn */ 6133641994SAndrew Lunn int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) 6233641994SAndrew Lunn { 6333641994SAndrew Lunn u16 reg; 6433641994SAndrew Lunn int err; 6533641994SAndrew Lunn 6633641994SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); 6733641994SAndrew Lunn if (err) 6833641994SAndrew Lunn return err; 6933641994SAndrew Lunn 7033641994SAndrew Lunn reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK; 7133641994SAndrew Lunn reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT; 7233641994SAndrew Lunn 7333641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 7433641994SAndrew Lunn } 7533641994SAndrew Lunn 7633641994SAndrew Lunn static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, 7733641994SAndrew Lunn u16 pointer, u8 data) 7833641994SAndrew Lunn { 7933641994SAndrew Lunn u16 reg; 8033641994SAndrew Lunn 8133641994SAndrew Lunn reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data; 8233641994SAndrew Lunn 8333641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 8433641994SAndrew Lunn } 8533641994SAndrew Lunn 8633641994SAndrew Lunn int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) 8733641994SAndrew Lunn { 8833641994SAndrew Lunn int err; 8933641994SAndrew Lunn 9033641994SAndrew Lunn err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS, 9133641994SAndrew Lunn port); 9233641994SAndrew Lunn if (err) 9333641994SAndrew Lunn return err; 9433641994SAndrew Lunn 9533641994SAndrew Lunn return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS, 9633641994SAndrew Lunn port); 9733641994SAndrew Lunn } 9833641994SAndrew Lunn 9933641994SAndrew Lunn int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) 10033641994SAndrew Lunn { 10133641994SAndrew Lunn return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST, 10233641994SAndrew Lunn port); 10333641994SAndrew Lunn } 10433641994SAndrew Lunn 105de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */ 106de227387SAndrew Lunn 107de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) 108de227387SAndrew Lunn { 109de227387SAndrew Lunn u16 val; 110de227387SAndrew Lunn int err; 111de227387SAndrew Lunn 112de227387SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val); 113de227387SAndrew Lunn if (err) 114de227387SAndrew Lunn return err; 115de227387SAndrew Lunn 116de227387SAndrew Lunn val |= GLOBAL_CONTROL_2_HIST_RX_TX; 117de227387SAndrew Lunn 118de227387SAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val); 119de227387SAndrew Lunn 120de227387SAndrew Lunn return err; 121de227387SAndrew Lunn } 122de227387SAndrew Lunn 123de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */ 124de227387SAndrew Lunn 1257f9ef3afSAndrew Lunn int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip) 126a605a0feSAndrew Lunn { 127a605a0feSAndrew Lunn return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY); 128a605a0feSAndrew Lunn } 129a605a0feSAndrew Lunn 130a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 131a605a0feSAndrew Lunn { 132a605a0feSAndrew Lunn int err; 133a605a0feSAndrew Lunn 134a605a0feSAndrew Lunn /* Snapshot the hardware statistics counters for this port. */ 135a605a0feSAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 136a605a0feSAndrew Lunn GLOBAL_STATS_OP_CAPTURE_PORT | 137a605a0feSAndrew Lunn GLOBAL_STATS_OP_HIST_RX_TX | port); 138a605a0feSAndrew Lunn if (err) 139a605a0feSAndrew Lunn return err; 140a605a0feSAndrew Lunn 141a605a0feSAndrew Lunn /* Wait for the snapshotting to complete. */ 142a605a0feSAndrew Lunn return mv88e6xxx_g1_stats_wait(chip); 143a605a0feSAndrew Lunn } 144a605a0feSAndrew Lunn 145a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 146a605a0feSAndrew Lunn { 147a605a0feSAndrew Lunn port = (port + 1) << 5; 148a605a0feSAndrew Lunn 149a605a0feSAndrew Lunn return mv88e6xxx_g1_stats_snapshot(chip, port); 150a605a0feSAndrew Lunn } 15179523473SAndrew Lunn 15279523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 15379523473SAndrew Lunn { 15479523473SAndrew Lunn int err; 15579523473SAndrew Lunn 15679523473SAndrew Lunn port = (port + 1) << 5; 15779523473SAndrew Lunn 15879523473SAndrew Lunn /* Snapshot the hardware statistics counters for this port. */ 15979523473SAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 16079523473SAndrew Lunn GLOBAL_STATS_OP_CAPTURE_PORT | port); 16179523473SAndrew Lunn if (err) 16279523473SAndrew Lunn return err; 16379523473SAndrew Lunn 16479523473SAndrew Lunn /* Wait for the snapshotting to complete. */ 16579523473SAndrew Lunn return mv88e6xxx_g1_stats_wait(chip); 16679523473SAndrew Lunn } 1677f9ef3afSAndrew Lunn 1687f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val) 1697f9ef3afSAndrew Lunn { 1707f9ef3afSAndrew Lunn u32 value; 1717f9ef3afSAndrew Lunn u16 reg; 1727f9ef3afSAndrew Lunn int err; 1737f9ef3afSAndrew Lunn 1747f9ef3afSAndrew Lunn *val = 0; 1757f9ef3afSAndrew Lunn 1767f9ef3afSAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 1777f9ef3afSAndrew Lunn GLOBAL_STATS_OP_READ_CAPTURED | stat); 1787f9ef3afSAndrew Lunn if (err) 1797f9ef3afSAndrew Lunn return; 1807f9ef3afSAndrew Lunn 1817f9ef3afSAndrew Lunn err = mv88e6xxx_g1_stats_wait(chip); 1827f9ef3afSAndrew Lunn if (err) 1837f9ef3afSAndrew Lunn return; 1847f9ef3afSAndrew Lunn 1857f9ef3afSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, ®); 1867f9ef3afSAndrew Lunn if (err) 1877f9ef3afSAndrew Lunn return; 1887f9ef3afSAndrew Lunn 1897f9ef3afSAndrew Lunn value = reg << 16; 1907f9ef3afSAndrew Lunn 1917f9ef3afSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, ®); 1927f9ef3afSAndrew Lunn if (err) 1937f9ef3afSAndrew Lunn return; 1947f9ef3afSAndrew Lunn 1957f9ef3afSAndrew Lunn *val = value | reg; 1967f9ef3afSAndrew Lunn } 197