18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Marvell 88E6xxx Switch Global 2 Registers support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
88c2ecf20Sopenharmony_ci *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "chip.h"
168c2ecf20Sopenharmony_ci#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
178c2ecf20Sopenharmony_ci#include "global2.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciint mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciint mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciint mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
308c2ecf20Sopenharmony_ci			  bit, int val)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	return mv88e6xxx_wait_bit(chip, chip->info->global2_addr, reg,
338c2ecf20Sopenharmony_ci				  bit, val);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Offset 0x00: Interrupt Source Register */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	/* Read (and clear most of) the Interrupt Source bits */
418c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Offset 0x01: Interrupt Mask Register */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Offset 0x02: Management Enable 2x */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Offset 0x03: Management Enable 0x */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* Offset 0x05: Switch Management Register */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
688c2ecf20Sopenharmony_ci					     bool enable)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	u16 val;
718c2ecf20Sopenharmony_ci	int err;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
748c2ecf20Sopenharmony_ci	if (err)
758c2ecf20Sopenharmony_ci		return err;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (enable)
788c2ecf20Sopenharmony_ci		val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
798c2ecf20Sopenharmony_ci	else
808c2ecf20Sopenharmony_ci		val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciint mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	int err;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Consider the frames with reserved multicast destination
908c2ecf20Sopenharmony_ci	 * addresses matching 01:80:c2:00:00:0x as MGMT.
918c2ecf20Sopenharmony_ci	 */
928c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
938c2ecf20Sopenharmony_ci	if (err)
948c2ecf20Sopenharmony_ci		return err;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int err;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* Consider the frames with reserved multicast destination
1048c2ecf20Sopenharmony_ci	 * addresses matching 01:80:c2:00:00:2x as MGMT.
1058c2ecf20Sopenharmony_ci	 */
1068c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
1078c2ecf20Sopenharmony_ci	if (err)
1088c2ecf20Sopenharmony_ci		return err;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return mv88e6185_g2_mgmt_rsvd2cpu(chip);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* Offset 0x06: Device Mapping Table register */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
1168c2ecf20Sopenharmony_ci				      int port)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	u16 val = (target << 8) | (port & 0x1f);
1198c2ecf20Sopenharmony_ci	/* Modern chips use 5 bits to define a device mapping port,
1208c2ecf20Sopenharmony_ci	 * but bit 4 is reserved on older chips, so it is safe to use.
1218c2ecf20Sopenharmony_ci	 */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_DEVICE_MAPPING,
1248c2ecf20Sopenharmony_ci				  MV88E6XXX_G2_DEVICE_MAPPING_UPDATE | val);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/* Offset 0x07: Trunk Mask Table register */
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
1308c2ecf20Sopenharmony_ci					 bool hash, u16 mask)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (hash)
1358c2ecf20Sopenharmony_ci		val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MASK,
1388c2ecf20Sopenharmony_ci				  MV88E6XXX_G2_TRUNK_MASK_UPDATE | val);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* Offset 0x08: Trunk Mapping Table register */
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
1448c2ecf20Sopenharmony_ci					    u16 map)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
1478c2ecf20Sopenharmony_ci	u16 val = (id << 11) | (map & port_mask);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MAPPING,
1508c2ecf20Sopenharmony_ci				  MV88E6XXX_G2_TRUNK_MAPPING_UPDATE | val);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ciint mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
1568c2ecf20Sopenharmony_ci	int i, err;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* Clear all eight possible Trunk Mask vectors */
1598c2ecf20Sopenharmony_ci	for (i = 0; i < 8; ++i) {
1608c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
1618c2ecf20Sopenharmony_ci		if (err)
1628c2ecf20Sopenharmony_ci			return err;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Clear all sixteen possible Trunk ID routing vectors */
1668c2ecf20Sopenharmony_ci	for (i = 0; i < 16; ++i) {
1678c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
1688c2ecf20Sopenharmony_ci		if (err)
1698c2ecf20Sopenharmony_ci			return err;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* Offset 0x09: Ingress Rate Command register
1768c2ecf20Sopenharmony_ci * Offset 0x0A: Ingress Rate Data register
1778c2ecf20Sopenharmony_ci */
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_G2_IRL_CMD_BUSY);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_IRL_CMD, bit, 0);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
1878c2ecf20Sopenharmony_ci			       int res, int reg)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	int err;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
1928c2ecf20Sopenharmony_ci				 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
1938c2ecf20Sopenharmony_ci				 (res << 5) | reg);
1948c2ecf20Sopenharmony_ci	if (err)
1958c2ecf20Sopenharmony_ci		return err;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_irl_wait(chip);
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ciint mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
2038c2ecf20Sopenharmony_ci				   0, 0);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciint mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
2098c2ecf20Sopenharmony_ci				   0, 0);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
2138c2ecf20Sopenharmony_ci * Offset 0x0C: Cross-chip Port VLAN Data Register
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_G2_PVT_ADDR_BUSY);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_PVT_ADDR, bit, 0);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
2248c2ecf20Sopenharmony_ci			       int src_port, u16 op)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	int err;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
2298c2ecf20Sopenharmony_ci	 * cleared, source device is 5-bit, source port is 4-bit.
2308c2ecf20Sopenharmony_ci	 */
2318c2ecf20Sopenharmony_ci	op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
2328c2ecf20Sopenharmony_ci	op |= (src_dev & 0x1f) << 4;
2338c2ecf20Sopenharmony_ci	op |= (src_port & 0xf);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
2368c2ecf20Sopenharmony_ci	if (err)
2378c2ecf20Sopenharmony_ci		return err;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_pvt_op_wait(chip);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ciint mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
2438c2ecf20Sopenharmony_ci			   int src_port, u16 data)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int err;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_pvt_op_wait(chip);
2488c2ecf20Sopenharmony_ci	if (err)
2498c2ecf20Sopenharmony_ci		return err;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
2528c2ecf20Sopenharmony_ci	if (err)
2538c2ecf20Sopenharmony_ci		return err;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
2568c2ecf20Sopenharmony_ci				   MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/* Offset 0x0D: Switch MAC/WoL/WoF register */
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
2628c2ecf20Sopenharmony_ci					 unsigned int pointer, u8 data)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	u16 val = (pointer << 8) | data;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MAC,
2678c2ecf20Sopenharmony_ci				  MV88E6XXX_G2_SWITCH_MAC_UPDATE | val);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciint mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	int i, err;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
2758c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
2768c2ecf20Sopenharmony_ci		if (err)
2778c2ecf20Sopenharmony_ci			break;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return err;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* Offset 0x0E: ATU Statistics */
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ciint mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_ATU_STATS,
2888c2ecf20Sopenharmony_ci				  kind | bin);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciint mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, stats);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/* Offset 0x0F: Priority Override Table */
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
2998c2ecf20Sopenharmony_ci				  u8 data)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	u16 val = (pointer << 8) | (data & 0x7);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PRIO_OVERRIDE,
3048c2ecf20Sopenharmony_ci				  MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE | val);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ciint mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	int i, err;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* Clear all sixteen possible Priority Override entries */
3128c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
3138c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_pot_write(chip, i, 0);
3148c2ecf20Sopenharmony_ci		if (err)
3158c2ecf20Sopenharmony_ci			break;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return err;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/* Offset 0x14: EEPROM Command
3228c2ecf20Sopenharmony_ci * Offset 0x15: EEPROM Data (for 16-bit data access)
3238c2ecf20Sopenharmony_ci * Offset 0x15: EEPROM Addr (for 8-bit data access)
3248c2ecf20Sopenharmony_ci */
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
3298c2ecf20Sopenharmony_ci	int err;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
3328c2ecf20Sopenharmony_ci	if (err)
3338c2ecf20Sopenharmony_ci		return err;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_RUNNING);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	int err;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
3458c2ecf20Sopenharmony_ci				 MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
3468c2ecf20Sopenharmony_ci	if (err)
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_eeprom_wait(chip);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
3538c2ecf20Sopenharmony_ci				     u16 addr, u8 *data)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
3568c2ecf20Sopenharmony_ci	int err;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_wait(chip);
3598c2ecf20Sopenharmony_ci	if (err)
3608c2ecf20Sopenharmony_ci		return err;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
3638c2ecf20Sopenharmony_ci	if (err)
3648c2ecf20Sopenharmony_ci		return err;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
3678c2ecf20Sopenharmony_ci	if (err)
3688c2ecf20Sopenharmony_ci		return err;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
3718c2ecf20Sopenharmony_ci	if (err)
3728c2ecf20Sopenharmony_ci		return err;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	*data = cmd & 0xff;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	return 0;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
3808c2ecf20Sopenharmony_ci				      u16 addr, u8 data)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
3838c2ecf20Sopenharmony_ci		MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
3848c2ecf20Sopenharmony_ci	int err;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_wait(chip);
3878c2ecf20Sopenharmony_ci	if (err)
3888c2ecf20Sopenharmony_ci		return err;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
3918c2ecf20Sopenharmony_ci	if (err)
3928c2ecf20Sopenharmony_ci		return err;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
3988c2ecf20Sopenharmony_ci				      u8 addr, u16 *data)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
4018c2ecf20Sopenharmony_ci	int err;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_wait(chip);
4048c2ecf20Sopenharmony_ci	if (err)
4058c2ecf20Sopenharmony_ci		return err;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
4088c2ecf20Sopenharmony_ci	if (err)
4098c2ecf20Sopenharmony_ci		return err;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
4158c2ecf20Sopenharmony_ci				       u8 addr, u16 data)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
4188c2ecf20Sopenharmony_ci	int err;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_eeprom_wait(chip);
4218c2ecf20Sopenharmony_ci	if (err)
4228c2ecf20Sopenharmony_ci		return err;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
4258c2ecf20Sopenharmony_ci	if (err)
4268c2ecf20Sopenharmony_ci		return err;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciint mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
4328c2ecf20Sopenharmony_ci			     struct ethtool_eeprom *eeprom, u8 *data)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	unsigned int offset = eeprom->offset;
4358c2ecf20Sopenharmony_ci	unsigned int len = eeprom->len;
4368c2ecf20Sopenharmony_ci	int err;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	eeprom->len = 0;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	while (len) {
4418c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
4428c2ecf20Sopenharmony_ci		if (err)
4438c2ecf20Sopenharmony_ci			return err;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		eeprom->len++;
4468c2ecf20Sopenharmony_ci		offset++;
4478c2ecf20Sopenharmony_ci		data++;
4488c2ecf20Sopenharmony_ci		len--;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return 0;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ciint mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
4558c2ecf20Sopenharmony_ci			     struct ethtool_eeprom *eeprom, u8 *data)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	unsigned int offset = eeprom->offset;
4588c2ecf20Sopenharmony_ci	unsigned int len = eeprom->len;
4598c2ecf20Sopenharmony_ci	int err;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	eeprom->len = 0;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	while (len) {
4648c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
4658c2ecf20Sopenharmony_ci		if (err)
4668c2ecf20Sopenharmony_ci			return err;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		eeprom->len++;
4698c2ecf20Sopenharmony_ci		offset++;
4708c2ecf20Sopenharmony_ci		data++;
4718c2ecf20Sopenharmony_ci		len--;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	return 0;
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciint mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
4788c2ecf20Sopenharmony_ci			      struct ethtool_eeprom *eeprom, u8 *data)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	unsigned int offset = eeprom->offset;
4818c2ecf20Sopenharmony_ci	unsigned int len = eeprom->len;
4828c2ecf20Sopenharmony_ci	u16 val;
4838c2ecf20Sopenharmony_ci	int err;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	eeprom->len = 0;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (offset & 1) {
4888c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
4898c2ecf20Sopenharmony_ci		if (err)
4908c2ecf20Sopenharmony_ci			return err;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		*data++ = (val >> 8) & 0xff;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		offset++;
4958c2ecf20Sopenharmony_ci		len--;
4968c2ecf20Sopenharmony_ci		eeprom->len++;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	while (len >= 2) {
5008c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
5018c2ecf20Sopenharmony_ci		if (err)
5028c2ecf20Sopenharmony_ci			return err;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		*data++ = val & 0xff;
5058c2ecf20Sopenharmony_ci		*data++ = (val >> 8) & 0xff;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		offset += 2;
5088c2ecf20Sopenharmony_ci		len -= 2;
5098c2ecf20Sopenharmony_ci		eeprom->len += 2;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (len) {
5138c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
5148c2ecf20Sopenharmony_ci		if (err)
5158c2ecf20Sopenharmony_ci			return err;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		*data++ = val & 0xff;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		offset++;
5208c2ecf20Sopenharmony_ci		len--;
5218c2ecf20Sopenharmony_ci		eeprom->len++;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ciint mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
5288c2ecf20Sopenharmony_ci			      struct ethtool_eeprom *eeprom, u8 *data)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	unsigned int offset = eeprom->offset;
5318c2ecf20Sopenharmony_ci	unsigned int len = eeprom->len;
5328c2ecf20Sopenharmony_ci	u16 val;
5338c2ecf20Sopenharmony_ci	int err;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Ensure the RO WriteEn bit is set */
5368c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
5378c2ecf20Sopenharmony_ci	if (err)
5388c2ecf20Sopenharmony_ci		return err;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
5418c2ecf20Sopenharmony_ci		return -EROFS;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	eeprom->len = 0;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	if (offset & 1) {
5468c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
5478c2ecf20Sopenharmony_ci		if (err)
5488c2ecf20Sopenharmony_ci			return err;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		val = (*data++ << 8) | (val & 0xff);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
5538c2ecf20Sopenharmony_ci		if (err)
5548c2ecf20Sopenharmony_ci			return err;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		offset++;
5578c2ecf20Sopenharmony_ci		len--;
5588c2ecf20Sopenharmony_ci		eeprom->len++;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	while (len >= 2) {
5628c2ecf20Sopenharmony_ci		val = *data++;
5638c2ecf20Sopenharmony_ci		val |= *data++ << 8;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
5668c2ecf20Sopenharmony_ci		if (err)
5678c2ecf20Sopenharmony_ci			return err;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		offset += 2;
5708c2ecf20Sopenharmony_ci		len -= 2;
5718c2ecf20Sopenharmony_ci		eeprom->len += 2;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	if (len) {
5758c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
5768c2ecf20Sopenharmony_ci		if (err)
5778c2ecf20Sopenharmony_ci			return err;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		val = (val & 0xff00) | *data++;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
5828c2ecf20Sopenharmony_ci		if (err)
5838c2ecf20Sopenharmony_ci			return err;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		offset++;
5868c2ecf20Sopenharmony_ci		len--;
5878c2ecf20Sopenharmony_ci		eeprom->len++;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci/* Offset 0x18: SMI PHY Command Register
5948c2ecf20Sopenharmony_ci * Offset 0x19: SMI PHY Data Register
5958c2ecf20Sopenharmony_ci */
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	int bit = __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_SMI_PHY_CMD, bit, 0);
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	int err;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
6098c2ecf20Sopenharmony_ci				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
6108c2ecf20Sopenharmony_ci	if (err)
6118c2ecf20Sopenharmony_ci		return err;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_wait(chip);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
6178c2ecf20Sopenharmony_ci				       bool external, bool c45, u16 op, int dev,
6188c2ecf20Sopenharmony_ci				       int reg)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	u16 cmd = op;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (external)
6238c2ecf20Sopenharmony_ci		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
6248c2ecf20Sopenharmony_ci	else
6258c2ecf20Sopenharmony_ci		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (c45)
6288c2ecf20Sopenharmony_ci		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
6298c2ecf20Sopenharmony_ci	else
6308c2ecf20Sopenharmony_ci		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
6338c2ecf20Sopenharmony_ci	cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
6348c2ecf20Sopenharmony_ci	cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
6408c2ecf20Sopenharmony_ci					   bool external, u16 op, int dev,
6418c2ecf20Sopenharmony_ci					   int reg)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/* IEEE 802.3 Clause 22 Read Data Register */
6478c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
6488c2ecf20Sopenharmony_ci					      bool external, int dev, int reg,
6498c2ecf20Sopenharmony_ci					      u16 *data)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
6528c2ecf20Sopenharmony_ci	int err;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_wait(chip);
6558c2ecf20Sopenharmony_ci	if (err)
6568c2ecf20Sopenharmony_ci		return err;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
6598c2ecf20Sopenharmony_ci	if (err)
6608c2ecf20Sopenharmony_ci		return err;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/* IEEE 802.3 Clause 22 Write Data Register */
6668c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
6678c2ecf20Sopenharmony_ci					       bool external, int dev, int reg,
6688c2ecf20Sopenharmony_ci					       u16 data)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
6718c2ecf20Sopenharmony_ci	int err;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_wait(chip);
6748c2ecf20Sopenharmony_ci	if (err)
6758c2ecf20Sopenharmony_ci		return err;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
6788c2ecf20Sopenharmony_ci	if (err)
6798c2ecf20Sopenharmony_ci		return err;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
6858c2ecf20Sopenharmony_ci					   bool external, u16 op, int port,
6868c2ecf20Sopenharmony_ci					   int dev)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci/* IEEE 802.3 Clause 45 Write Address Register */
6928c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
6938c2ecf20Sopenharmony_ci					       bool external, int port, int dev,
6948c2ecf20Sopenharmony_ci					       int addr)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
6978c2ecf20Sopenharmony_ci	int err;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_wait(chip);
7008c2ecf20Sopenharmony_ci	if (err)
7018c2ecf20Sopenharmony_ci		return err;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
7048c2ecf20Sopenharmony_ci	if (err)
7058c2ecf20Sopenharmony_ci		return err;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci/* IEEE 802.3 Clause 45 Read Data Register */
7118c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
7128c2ecf20Sopenharmony_ci					      bool external, int port, int dev,
7138c2ecf20Sopenharmony_ci					      u16 *data)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
7168c2ecf20Sopenharmony_ci	int err;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
7198c2ecf20Sopenharmony_ci	if (err)
7208c2ecf20Sopenharmony_ci		return err;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
7268c2ecf20Sopenharmony_ci					 bool external, int port, int reg,
7278c2ecf20Sopenharmony_ci					 u16 *data)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	int dev = (reg >> 16) & 0x1f;
7308c2ecf20Sopenharmony_ci	int addr = reg & 0xffff;
7318c2ecf20Sopenharmony_ci	int err;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
7348c2ecf20Sopenharmony_ci						  addr);
7358c2ecf20Sopenharmony_ci	if (err)
7368c2ecf20Sopenharmony_ci		return err;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
7398c2ecf20Sopenharmony_ci						  data);
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci/* IEEE 802.3 Clause 45 Write Data Register */
7438c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
7448c2ecf20Sopenharmony_ci					       bool external, int port, int dev,
7458c2ecf20Sopenharmony_ci					       u16 data)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
7488c2ecf20Sopenharmony_ci	int err;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
7518c2ecf20Sopenharmony_ci	if (err)
7528c2ecf20Sopenharmony_ci		return err;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
7588c2ecf20Sopenharmony_ci					  bool external, int port, int reg,
7598c2ecf20Sopenharmony_ci					  u16 data)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	int dev = (reg >> 16) & 0x1f;
7628c2ecf20Sopenharmony_ci	int addr = reg & 0xffff;
7638c2ecf20Sopenharmony_ci	int err;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
7668c2ecf20Sopenharmony_ci						  addr);
7678c2ecf20Sopenharmony_ci	if (err)
7688c2ecf20Sopenharmony_ci		return err;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
7718c2ecf20Sopenharmony_ci						   data);
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ciint mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
7758c2ecf20Sopenharmony_ci			      int addr, int reg, u16 *val)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
7788c2ecf20Sopenharmony_ci	bool external = mdio_bus->external;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (reg & MII_ADDR_C45)
7818c2ecf20Sopenharmony_ci		return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
7828c2ecf20Sopenharmony_ci						     val);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
7858c2ecf20Sopenharmony_ci						  val);
7868c2ecf20Sopenharmony_ci}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ciint mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
7898c2ecf20Sopenharmony_ci			       int addr, int reg, u16 val)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
7928c2ecf20Sopenharmony_ci	bool external = mdio_bus->external;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (reg & MII_ADDR_C45)
7958c2ecf20Sopenharmony_ci		return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
7968c2ecf20Sopenharmony_ci						      val);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
7998c2ecf20Sopenharmony_ci						   val);
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/* Offset 0x1B: Watchdog Control */
8038c2ecf20Sopenharmony_cistatic int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	u16 reg;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	u16 reg;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
8218c2ecf20Sopenharmony_ci		 MV88E6352_G2_WDOG_CTL_QC_ENABLE);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
8298c2ecf20Sopenharmony_ci				  MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
8308c2ecf20Sopenharmony_ci				  MV88E6352_G2_WDOG_CTL_QC_ENABLE |
8318c2ecf20Sopenharmony_ci				  MV88E6352_G2_WDOG_CTL_SWRESET);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ciconst struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
8358c2ecf20Sopenharmony_ci	.irq_action = mv88e6097_watchdog_action,
8368c2ecf20Sopenharmony_ci	.irq_setup = mv88e6097_watchdog_setup,
8378c2ecf20Sopenharmony_ci	.irq_free = mv88e6097_watchdog_free,
8388c2ecf20Sopenharmony_ci};
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	u16 reg;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, &reg);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
8478c2ecf20Sopenharmony_ci		 MV88E6250_G2_WDOG_CTL_QC_ENABLE);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg);
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL,
8558c2ecf20Sopenharmony_ci				  MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
8568c2ecf20Sopenharmony_ci				  MV88E6250_G2_WDOG_CTL_QC_ENABLE |
8578c2ecf20Sopenharmony_ci				  MV88E6250_G2_WDOG_CTL_SWRESET);
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ciconst struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
8618c2ecf20Sopenharmony_ci	.irq_action = mv88e6097_watchdog_action,
8628c2ecf20Sopenharmony_ci	.irq_setup = mv88e6250_watchdog_setup,
8638c2ecf20Sopenharmony_ci	.irq_free = mv88e6250_watchdog_free,
8648c2ecf20Sopenharmony_ci};
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8698c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_UPDATE |
8708c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
8718c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
8728c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
8738c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_EGRESS |
8748c2ecf20Sopenharmony_ci				  MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	u16 reg;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8828c2ecf20Sopenharmony_ci			   MV88E6390_G2_WDOG_CTL_PTR_EVENT);
8838c2ecf20Sopenharmony_ci	mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	dev_info(chip->dev, "Watchdog event: 0x%04x",
8868c2ecf20Sopenharmony_ci		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8898c2ecf20Sopenharmony_ci			   MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
8908c2ecf20Sopenharmony_ci	mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	dev_info(chip->dev, "Watchdog history: 0x%04x",
8938c2ecf20Sopenharmony_ci		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* Trigger a software reset to try to recover the switch */
8968c2ecf20Sopenharmony_ci	if (chip->info->ops->reset)
8978c2ecf20Sopenharmony_ci		chip->info->ops->reset(chip);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	mv88e6390_watchdog_setup(chip);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
9078c2ecf20Sopenharmony_ci			   MV88E6390_G2_WDOG_CTL_UPDATE |
9088c2ecf20Sopenharmony_ci			   MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ciconst struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
9128c2ecf20Sopenharmony_ci	.irq_action = mv88e6390_watchdog_action,
9138c2ecf20Sopenharmony_ci	.irq_setup = mv88e6390_watchdog_setup,
9148c2ecf20Sopenharmony_ci	.irq_free = mv88e6390_watchdog_free,
9158c2ecf20Sopenharmony_ci};
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = dev_id;
9208c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
9238c2ecf20Sopenharmony_ci	if (chip->info->ops->watchdog_ops->irq_action)
9248c2ecf20Sopenharmony_ci		ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
9258c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return ret;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
9338c2ecf20Sopenharmony_ci	if (chip->info->ops->watchdog_ops->irq_free)
9348c2ecf20Sopenharmony_ci		chip->info->ops->watchdog_ops->irq_free(chip);
9358c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	free_irq(chip->watchdog_irq, chip);
9388c2ecf20Sopenharmony_ci	irq_dispose_mapping(chip->watchdog_irq);
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	int err;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
9468c2ecf20Sopenharmony_ci					      MV88E6XXX_G2_INT_SOURCE_WATCHDOG);
9478c2ecf20Sopenharmony_ci	if (chip->watchdog_irq < 0)
9488c2ecf20Sopenharmony_ci		return chip->watchdog_irq;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	snprintf(chip->watchdog_irq_name, sizeof(chip->watchdog_irq_name),
9518c2ecf20Sopenharmony_ci		 "mv88e6xxx-%s-watchdog", dev_name(chip->dev));
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	err = request_threaded_irq(chip->watchdog_irq, NULL,
9548c2ecf20Sopenharmony_ci				   mv88e6xxx_g2_watchdog_thread_fn,
9558c2ecf20Sopenharmony_ci				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
9568c2ecf20Sopenharmony_ci				   chip->watchdog_irq_name, chip);
9578c2ecf20Sopenharmony_ci	if (err)
9588c2ecf20Sopenharmony_ci		return err;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
9618c2ecf20Sopenharmony_ci	if (chip->info->ops->watchdog_ops->irq_setup)
9628c2ecf20Sopenharmony_ci		err = chip->info->ops->watchdog_ops->irq_setup(chip);
9638c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	return err;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci/* Offset 0x1D: Misc Register */
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
9718c2ecf20Sopenharmony_ci					bool port_5_bit)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	u16 val;
9748c2ecf20Sopenharmony_ci	int err;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val);
9778c2ecf20Sopenharmony_ci	if (err)
9788c2ecf20Sopenharmony_ci		return err;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if (port_5_bit)
9818c2ecf20Sopenharmony_ci		val |= MV88E6XXX_G2_MISC_5_BIT_PORT;
9828c2ecf20Sopenharmony_ci	else
9838c2ecf20Sopenharmony_ci		val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val);
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ciint mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_misc_5_bit_port(chip, false);
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic void mv88e6xxx_g2_irq_mask(struct irq_data *d)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
9968c2ecf20Sopenharmony_ci	unsigned int n = d->hwirq;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	chip->g2_irq.masked |= (1 << n);
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_cistatic void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
10028c2ecf20Sopenharmony_ci{
10038c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
10048c2ecf20Sopenharmony_ci	unsigned int n = d->hwirq;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	chip->g2_irq.masked &= ~(1 << n);
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_cistatic irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = dev_id;
10128c2ecf20Sopenharmony_ci	unsigned int nhandled = 0;
10138c2ecf20Sopenharmony_ci	unsigned int sub_irq;
10148c2ecf20Sopenharmony_ci	unsigned int n;
10158c2ecf20Sopenharmony_ci	int err;
10168c2ecf20Sopenharmony_ci	u16 reg;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
10198c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_int_source(chip, &reg);
10208c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
10218c2ecf20Sopenharmony_ci	if (err)
10228c2ecf20Sopenharmony_ci		goto out;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	for (n = 0; n < 16; ++n) {
10258c2ecf20Sopenharmony_ci		if (reg & (1 << n)) {
10268c2ecf20Sopenharmony_ci			sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
10278c2ecf20Sopenharmony_ci			handle_nested_irq(sub_irq);
10288c2ecf20Sopenharmony_ci			++nhandled;
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ciout:
10328c2ecf20Sopenharmony_ci	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cistatic void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cistatic void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
10458c2ecf20Sopenharmony_ci	int err;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
10488c2ecf20Sopenharmony_ci	if (err)
10498c2ecf20Sopenharmony_ci		dev_err(chip->dev, "failed to mask interrupts\n");
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic const struct irq_chip mv88e6xxx_g2_irq_chip = {
10558c2ecf20Sopenharmony_ci	.name			= "mv88e6xxx-g2",
10568c2ecf20Sopenharmony_ci	.irq_mask		= mv88e6xxx_g2_irq_mask,
10578c2ecf20Sopenharmony_ci	.irq_unmask		= mv88e6xxx_g2_irq_unmask,
10588c2ecf20Sopenharmony_ci	.irq_bus_lock		= mv88e6xxx_g2_irq_bus_lock,
10598c2ecf20Sopenharmony_ci	.irq_bus_sync_unlock	= mv88e6xxx_g2_irq_bus_sync_unlock,
10608c2ecf20Sopenharmony_ci};
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
10638c2ecf20Sopenharmony_ci				       unsigned int irq,
10648c2ecf20Sopenharmony_ci				       irq_hw_number_t hwirq)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct mv88e6xxx_chip *chip = d->host_data;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	irq_set_chip_data(irq, d->host_data);
10698c2ecf20Sopenharmony_ci	irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
10708c2ecf20Sopenharmony_ci	irq_set_noprobe(irq);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	return 0;
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_cistatic const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
10768c2ecf20Sopenharmony_ci	.map	= mv88e6xxx_g2_irq_domain_map,
10778c2ecf20Sopenharmony_ci	.xlate	= irq_domain_xlate_twocell,
10788c2ecf20Sopenharmony_ci};
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_civoid mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	int irq, virq;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	mv88e6xxx_g2_watchdog_free(chip);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	free_irq(chip->device_irq, chip);
10878c2ecf20Sopenharmony_ci	irq_dispose_mapping(chip->device_irq);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	for (irq = 0; irq < 16; irq++) {
10908c2ecf20Sopenharmony_ci		virq = irq_find_mapping(chip->g2_irq.domain, irq);
10918c2ecf20Sopenharmony_ci		irq_dispose_mapping(virq);
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	irq_domain_remove(chip->g2_irq.domain);
10958c2ecf20Sopenharmony_ci}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ciint mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	int err, irq, virq;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	chip->g2_irq.masked = ~0;
11028c2ecf20Sopenharmony_ci	mv88e6xxx_reg_lock(chip);
11038c2ecf20Sopenharmony_ci	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
11048c2ecf20Sopenharmony_ci	mv88e6xxx_reg_unlock(chip);
11058c2ecf20Sopenharmony_ci	if (err)
11068c2ecf20Sopenharmony_ci		return err;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	chip->g2_irq.domain = irq_domain_add_simple(
11098c2ecf20Sopenharmony_ci		chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
11108c2ecf20Sopenharmony_ci	if (!chip->g2_irq.domain)
11118c2ecf20Sopenharmony_ci		return -ENOMEM;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	for (irq = 0; irq < 16; irq++)
11148c2ecf20Sopenharmony_ci		irq_create_mapping(chip->g2_irq.domain, irq);
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
11198c2ecf20Sopenharmony_ci					    MV88E6XXX_G1_STS_IRQ_DEVICE);
11208c2ecf20Sopenharmony_ci	if (chip->device_irq < 0) {
11218c2ecf20Sopenharmony_ci		err = chip->device_irq;
11228c2ecf20Sopenharmony_ci		goto out;
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	snprintf(chip->device_irq_name, sizeof(chip->device_irq_name),
11268c2ecf20Sopenharmony_ci		 "mv88e6xxx-%s-g2", dev_name(chip->dev));
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	err = request_threaded_irq(chip->device_irq, NULL,
11298c2ecf20Sopenharmony_ci				   mv88e6xxx_g2_irq_thread_fn,
11308c2ecf20Sopenharmony_ci				   IRQF_ONESHOT, chip->device_irq_name, chip);
11318c2ecf20Sopenharmony_ci	if (err)
11328c2ecf20Sopenharmony_ci		goto out;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	return mv88e6xxx_g2_watchdog_setup(chip);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ciout:
11378c2ecf20Sopenharmony_ci	for (irq = 0; irq < 16; irq++) {
11388c2ecf20Sopenharmony_ci		virq = irq_find_mapping(chip->g2_irq.domain, irq);
11398c2ecf20Sopenharmony_ci		irq_dispose_mapping(virq);
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	irq_domain_remove(chip->g2_irq.domain);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	return err;
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ciint mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip,
11488c2ecf20Sopenharmony_ci				struct mii_bus *bus)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	int phy, irq, err, err_phy;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	for (phy = 0; phy < chip->info->num_internal_phys; phy++) {
11538c2ecf20Sopenharmony_ci		irq = irq_find_mapping(chip->g2_irq.domain, phy);
11548c2ecf20Sopenharmony_ci		if (irq < 0) {
11558c2ecf20Sopenharmony_ci			err = irq;
11568c2ecf20Sopenharmony_ci			goto out;
11578c2ecf20Sopenharmony_ci		}
11588c2ecf20Sopenharmony_ci		bus->irq[chip->info->phy_base_addr + phy] = irq;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci	return 0;
11618c2ecf20Sopenharmony_ciout:
11628c2ecf20Sopenharmony_ci	err_phy = phy;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	for (phy = 0; phy < err_phy; phy++)
11658c2ecf20Sopenharmony_ci		irq_dispose_mapping(bus->irq[phy]);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	return err;
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_civoid mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip,
11718c2ecf20Sopenharmony_ci				struct mii_bus *bus)
11728c2ecf20Sopenharmony_ci{
11738c2ecf20Sopenharmony_ci	int phy;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	for (phy = 0; phy < chip->info->num_internal_phys; phy++)
11768c2ecf20Sopenharmony_ci		irq_dispose_mapping(bus->irq[phy]);
11778c2ecf20Sopenharmony_ci}
1178