18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Marvell 88E6xxx Switch Hidden Registers support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2019 Andrew Lunn <andrew@lunn.ch>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "chip.h"
138c2ecf20Sopenharmony_ci#include "port.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* The mv88e6390 and mv88e6341 have some hidden registers used for debug and
168c2ecf20Sopenharmony_ci * development. The errata also makes use of them.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ciint mv88e6xxx_port_hidden_write(struct mv88e6xxx_chip *chip, int block,
198c2ecf20Sopenharmony_ci				int port, int reg, u16 val)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	u16 ctrl;
228c2ecf20Sopenharmony_ci	int err;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
258c2ecf20Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, val);
268c2ecf20Sopenharmony_ci	if (err)
278c2ecf20Sopenharmony_ci		return err;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
308c2ecf20Sopenharmony_ci	       MV88E6XXX_PORT_RESERVED_1A_WRITE |
318c2ecf20Sopenharmony_ci	       block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
328c2ecf20Sopenharmony_ci	       port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
338c2ecf20Sopenharmony_ci	       reg;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
368c2ecf20Sopenharmony_ci				    MV88E6XXX_PORT_RESERVED_1A, ctrl);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciint mv88e6xxx_port_hidden_wait(struct mv88e6xxx_chip *chip)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_PORT_RESERVED_1A_BUSY);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return mv88e6xxx_wait_bit(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
448c2ecf20Sopenharmony_ci				  MV88E6XXX_PORT_RESERVED_1A, bit, 0);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciint mv88e6xxx_port_hidden_read(struct mv88e6xxx_chip *chip, int block, int port,
488c2ecf20Sopenharmony_ci			       int reg, u16 *val)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	u16 ctrl;
518c2ecf20Sopenharmony_ci	int err;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
548c2ecf20Sopenharmony_ci	       MV88E6XXX_PORT_RESERVED_1A_READ |
558c2ecf20Sopenharmony_ci	       block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
568c2ecf20Sopenharmony_ci	       port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
578c2ecf20Sopenharmony_ci	       reg;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
608c2ecf20Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, ctrl);
618c2ecf20Sopenharmony_ci	if (err)
628c2ecf20Sopenharmony_ci		return err;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	err = mv88e6xxx_port_hidden_wait(chip);
658c2ecf20Sopenharmony_ci	if (err)
668c2ecf20Sopenharmony_ci		return err;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return mv88e6xxx_port_read(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
698c2ecf20Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, val);
708c2ecf20Sopenharmony_ci}
71