162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Marvell 88E6xxx Switch Hidden Registers support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2019 Andrew Lunn <andrew@lunn.ch>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "chip.h"
1362306a36Sopenharmony_ci#include "port.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* The mv88e6390 and mv88e6341 have some hidden registers used for debug and
1662306a36Sopenharmony_ci * development. The errata also makes use of them.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ciint mv88e6xxx_port_hidden_write(struct mv88e6xxx_chip *chip, int block,
1962306a36Sopenharmony_ci				int port, int reg, u16 val)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	u16 ctrl;
2262306a36Sopenharmony_ci	int err;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
2562306a36Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, val);
2662306a36Sopenharmony_ci	if (err)
2762306a36Sopenharmony_ci		return err;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
3062306a36Sopenharmony_ci	       MV88E6XXX_PORT_RESERVED_1A_WRITE |
3162306a36Sopenharmony_ci	       block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
3262306a36Sopenharmony_ci	       port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
3362306a36Sopenharmony_ci	       reg;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
3662306a36Sopenharmony_ci				    MV88E6XXX_PORT_RESERVED_1A, ctrl);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciint mv88e6xxx_port_hidden_wait(struct mv88e6xxx_chip *chip)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_PORT_RESERVED_1A_BUSY);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return mv88e6xxx_port_wait_bit(chip,
4462306a36Sopenharmony_ci				       MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
4562306a36Sopenharmony_ci				       MV88E6XXX_PORT_RESERVED_1A, bit, 0);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciint mv88e6xxx_port_hidden_read(struct mv88e6xxx_chip *chip, int block, int port,
4962306a36Sopenharmony_ci			       int reg, u16 *val)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	u16 ctrl;
5262306a36Sopenharmony_ci	int err;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
5562306a36Sopenharmony_ci	       MV88E6XXX_PORT_RESERVED_1A_READ |
5662306a36Sopenharmony_ci	       block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
5762306a36Sopenharmony_ci	       port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
5862306a36Sopenharmony_ci	       reg;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
6162306a36Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, ctrl);
6262306a36Sopenharmony_ci	if (err)
6362306a36Sopenharmony_ci		return err;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	err = mv88e6xxx_port_hidden_wait(chip);
6662306a36Sopenharmony_ci	if (err)
6762306a36Sopenharmony_ci		return err;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return mv88e6xxx_port_read(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
7062306a36Sopenharmony_ci				   MV88E6XXX_PORT_RESERVED_1A, val);
7162306a36Sopenharmony_ci}
72