162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/gpio/machine.h>
562306a36Sopenharmony_ci#include <linux/gpio/driver.h>
662306a36Sopenharmony_ci#include <linux/gpio/property.h>
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/clkdev.h>
962306a36Sopenharmony_ci#include <linux/i2c.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/regmap.h>
1362306a36Sopenharmony_ci#include <linux/pcs/pcs-xpcs.h>
1462306a36Sopenharmony_ci#include <linux/phylink.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "../libwx/wx_type.h"
1762306a36Sopenharmony_ci#include "../libwx/wx_lib.h"
1862306a36Sopenharmony_ci#include "../libwx/wx_hw.h"
1962306a36Sopenharmony_ci#include "txgbe_type.h"
2062306a36Sopenharmony_ci#include "txgbe_phy.h"
2162306a36Sopenharmony_ci#include "txgbe_hw.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int txgbe_swnodes_register(struct txgbe *txgbe)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct txgbe_nodes *nodes = &txgbe->nodes;
2662306a36Sopenharmony_ci	struct pci_dev *pdev = txgbe->wx->pdev;
2762306a36Sopenharmony_ci	struct software_node *swnodes;
2862306a36Sopenharmony_ci	u32 id;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	id = pci_dev_id(pdev);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id);
3362306a36Sopenharmony_ci	snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id);
3462306a36Sopenharmony_ci	snprintf(nodes->sfp_name, sizeof(nodes->sfp_name), "txgbe_sfp-%x", id);
3562306a36Sopenharmony_ci	snprintf(nodes->phylink_name, sizeof(nodes->phylink_name), "txgbe_phylink-%x", id);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	swnodes = nodes->swnodes;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* GPIO 0: tx fault
4062306a36Sopenharmony_ci	 * GPIO 1: tx disable
4162306a36Sopenharmony_ci	 * GPIO 2: sfp module absent
4262306a36Sopenharmony_ci	 * GPIO 3: rx signal lost
4362306a36Sopenharmony_ci	 * GPIO 4: rate select, 1G(0) 10G(1)
4462306a36Sopenharmony_ci	 * GPIO 5: rate select, 1G(0) 10G(1)
4562306a36Sopenharmony_ci	 */
4662306a36Sopenharmony_ci	nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default");
4762306a36Sopenharmony_ci	swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props);
4862306a36Sopenharmony_ci	nodes->gpio0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 0, GPIO_ACTIVE_HIGH);
4962306a36Sopenharmony_ci	nodes->gpio1_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 1, GPIO_ACTIVE_HIGH);
5062306a36Sopenharmony_ci	nodes->gpio2_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 2, GPIO_ACTIVE_LOW);
5162306a36Sopenharmony_ci	nodes->gpio3_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 3, GPIO_ACTIVE_HIGH);
5262306a36Sopenharmony_ci	nodes->gpio4_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 4, GPIO_ACTIVE_HIGH);
5362306a36Sopenharmony_ci	nodes->gpio5_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 5, GPIO_ACTIVE_HIGH);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("compatible", "snps,designware-i2c");
5662306a36Sopenharmony_ci	nodes->i2c_props[1] = PROPERTY_ENTRY_BOOL("wx,i2c-snps-model");
5762306a36Sopenharmony_ci	nodes->i2c_props[2] = PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ);
5862306a36Sopenharmony_ci	swnodes[SWNODE_I2C] = NODE_PROP(nodes->i2c_name, nodes->i2c_props);
5962306a36Sopenharmony_ci	nodes->i2c_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_I2C]);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	nodes->sfp_props[0] = PROPERTY_ENTRY_STRING("compatible", "sff,sfp");
6262306a36Sopenharmony_ci	nodes->sfp_props[1] = PROPERTY_ENTRY_REF_ARRAY("i2c-bus", nodes->i2c_ref);
6362306a36Sopenharmony_ci	nodes->sfp_props[2] = PROPERTY_ENTRY_REF_ARRAY("tx-fault-gpios", nodes->gpio0_ref);
6462306a36Sopenharmony_ci	nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios", nodes->gpio1_ref);
6562306a36Sopenharmony_ci	nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios", nodes->gpio2_ref);
6662306a36Sopenharmony_ci	nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios", nodes->gpio3_ref);
6762306a36Sopenharmony_ci	nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select1-gpios", nodes->gpio4_ref);
6862306a36Sopenharmony_ci	nodes->sfp_props[7] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios", nodes->gpio5_ref);
6962306a36Sopenharmony_ci	swnodes[SWNODE_SFP] = NODE_PROP(nodes->sfp_name, nodes->sfp_props);
7062306a36Sopenharmony_ci	nodes->sfp_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_SFP]);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	nodes->phylink_props[0] = PROPERTY_ENTRY_STRING("managed", "in-band-status");
7362306a36Sopenharmony_ci	nodes->phylink_props[1] = PROPERTY_ENTRY_REF_ARRAY("sfp", nodes->sfp_ref);
7462306a36Sopenharmony_ci	swnodes[SWNODE_PHYLINK] = NODE_PROP(nodes->phylink_name, nodes->phylink_props);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	nodes->group[SWNODE_GPIO] = &swnodes[SWNODE_GPIO];
7762306a36Sopenharmony_ci	nodes->group[SWNODE_I2C] = &swnodes[SWNODE_I2C];
7862306a36Sopenharmony_ci	nodes->group[SWNODE_SFP] = &swnodes[SWNODE_SFP];
7962306a36Sopenharmony_ci	nodes->group[SWNODE_PHYLINK] = &swnodes[SWNODE_PHYLINK];
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return software_node_register_node_group(nodes->group);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int txgbe_pcs_read(struct mii_bus *bus, int addr, int devnum, int regnum)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct wx *wx  = bus->priv;
8762306a36Sopenharmony_ci	u32 offset, val;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (addr)
9062306a36Sopenharmony_ci		return -EOPNOTSUPP;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	offset = devnum << 16 | regnum;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Set the LAN port indicator to IDA_ADDR */
9562306a36Sopenharmony_ci	wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Read the data from IDA_DATA register */
9862306a36Sopenharmony_ci	val = rd32(wx, TXGBE_XPCS_IDA_DATA);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return (u16)val;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct wx *wx = bus->priv;
10662306a36Sopenharmony_ci	u32 offset;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (addr)
10962306a36Sopenharmony_ci		return -EOPNOTSUPP;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	offset = devnum << 16 | regnum;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Set the LAN port indicator to IDA_ADDR */
11462306a36Sopenharmony_ci	wr32(wx, TXGBE_XPCS_IDA_ADDR, offset);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Write the data to IDA_DATA register */
11762306a36Sopenharmony_ci	wr32(wx, TXGBE_XPCS_IDA_DATA, val);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int txgbe_mdio_pcs_init(struct txgbe *txgbe)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct mii_bus *mii_bus;
12562306a36Sopenharmony_ci	struct dw_xpcs *xpcs;
12662306a36Sopenharmony_ci	struct pci_dev *pdev;
12762306a36Sopenharmony_ci	struct wx *wx;
12862306a36Sopenharmony_ci	int ret = 0;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	wx = txgbe->wx;
13162306a36Sopenharmony_ci	pdev = wx->pdev;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	mii_bus = devm_mdiobus_alloc(&pdev->dev);
13462306a36Sopenharmony_ci	if (!mii_bus)
13562306a36Sopenharmony_ci		return -ENOMEM;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	mii_bus->name = "txgbe_pcs_mdio_bus";
13862306a36Sopenharmony_ci	mii_bus->read_c45 = &txgbe_pcs_read;
13962306a36Sopenharmony_ci	mii_bus->write_c45 = &txgbe_pcs_write;
14062306a36Sopenharmony_ci	mii_bus->parent = &pdev->dev;
14162306a36Sopenharmony_ci	mii_bus->phy_mask = ~0;
14262306a36Sopenharmony_ci	mii_bus->priv = wx;
14362306a36Sopenharmony_ci	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x",
14462306a36Sopenharmony_ci		 pci_dev_id(pdev));
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ret = devm_mdiobus_register(&pdev->dev, mii_bus);
14762306a36Sopenharmony_ci	if (ret)
14862306a36Sopenharmony_ci		return ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	xpcs = xpcs_create_mdiodev(mii_bus, 0, PHY_INTERFACE_MODE_10GBASER);
15162306a36Sopenharmony_ci	if (IS_ERR(xpcs))
15262306a36Sopenharmony_ci		return PTR_ERR(xpcs);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	txgbe->xpcs = xpcs;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *config,
16062306a36Sopenharmony_ci						    phy_interface_t interface)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (interface == PHY_INTERFACE_MODE_10GBASER)
16562306a36Sopenharmony_ci		return &txgbe->xpcs->pcs;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return NULL;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
17162306a36Sopenharmony_ci			     const struct phylink_link_state *state)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void txgbe_mac_link_down(struct phylink_config *config,
17662306a36Sopenharmony_ci				unsigned int mode, phy_interface_t interface)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct wx *wx = netdev_priv(to_net_dev(config->dev));
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void txgbe_mac_link_up(struct phylink_config *config,
18462306a36Sopenharmony_ci			      struct phy_device *phy,
18562306a36Sopenharmony_ci			      unsigned int mode, phy_interface_t interface,
18662306a36Sopenharmony_ci			      int speed, int duplex,
18762306a36Sopenharmony_ci			      bool tx_pause, bool rx_pause)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct wx *wx = netdev_priv(to_net_dev(config->dev));
19062306a36Sopenharmony_ci	u32 txcfg, wdg;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	txcfg = rd32(wx, WX_MAC_TX_CFG);
19362306a36Sopenharmony_ci	txcfg &= ~WX_MAC_TX_CFG_SPEED_MASK;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	switch (speed) {
19662306a36Sopenharmony_ci	case SPEED_10000:
19762306a36Sopenharmony_ci		txcfg |= WX_MAC_TX_CFG_SPEED_10G;
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	case SPEED_1000:
20062306a36Sopenharmony_ci	case SPEED_100:
20162306a36Sopenharmony_ci	case SPEED_10:
20262306a36Sopenharmony_ci		txcfg |= WX_MAC_TX_CFG_SPEED_1G;
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	default:
20562306a36Sopenharmony_ci		break;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	wr32(wx, WX_MAC_TX_CFG, txcfg | WX_MAC_TX_CFG_TE);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* Re configure MAC Rx */
21162306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
21262306a36Sopenharmony_ci	wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
21362306a36Sopenharmony_ci	wdg = rd32(wx, WX_MAC_WDG_TIMEOUT);
21462306a36Sopenharmony_ci	wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
21862306a36Sopenharmony_ci			     phy_interface_t interface)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct wx *wx = netdev_priv(to_net_dev(config->dev));
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
22362306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return txgbe_disable_sec_tx_path(wx);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
22962306a36Sopenharmony_ci			    phy_interface_t interface)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct wx *wx = netdev_priv(to_net_dev(config->dev));
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	txgbe_enable_sec_tx_path(wx);
23462306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct phylink_mac_ops txgbe_mac_ops = {
24062306a36Sopenharmony_ci	.mac_select_pcs = txgbe_phylink_mac_select,
24162306a36Sopenharmony_ci	.mac_prepare = txgbe_mac_prepare,
24262306a36Sopenharmony_ci	.mac_finish = txgbe_mac_finish,
24362306a36Sopenharmony_ci	.mac_config = txgbe_mac_config,
24462306a36Sopenharmony_ci	.mac_link_down = txgbe_mac_link_down,
24562306a36Sopenharmony_ci	.mac_link_up = txgbe_mac_link_up,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int txgbe_phylink_init(struct txgbe *txgbe)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct fwnode_handle *fwnode = NULL;
25162306a36Sopenharmony_ci	struct phylink_config *config;
25262306a36Sopenharmony_ci	struct wx *wx = txgbe->wx;
25362306a36Sopenharmony_ci	phy_interface_t phy_mode;
25462306a36Sopenharmony_ci	struct phylink *phylink;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	config = devm_kzalloc(&wx->pdev->dev, sizeof(*config), GFP_KERNEL);
25762306a36Sopenharmony_ci	if (!config)
25862306a36Sopenharmony_ci		return -ENOMEM;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	config->dev = &wx->netdev->dev;
26162306a36Sopenharmony_ci	config->type = PHYLINK_NETDEV;
26262306a36Sopenharmony_ci	config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
26362306a36Sopenharmony_ci				   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (wx->media_type == sp_media_copper) {
26662306a36Sopenharmony_ci		phy_mode = PHY_INTERFACE_MODE_XAUI;
26762306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
26862306a36Sopenharmony_ci	} else {
26962306a36Sopenharmony_ci		phy_mode = PHY_INTERFACE_MODE_10GBASER;
27062306a36Sopenharmony_ci		fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
27162306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
27262306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
27362306a36Sopenharmony_ci		__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
27762306a36Sopenharmony_ci	if (IS_ERR(phylink))
27862306a36Sopenharmony_ci		return PTR_ERR(phylink);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (wx->phydev) {
28162306a36Sopenharmony_ci		int ret;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		ret = phylink_connect_phy(phylink, wx->phydev);
28462306a36Sopenharmony_ci		if (ret) {
28562306a36Sopenharmony_ci			phylink_destroy(phylink);
28662306a36Sopenharmony_ci			return ret;
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	txgbe->phylink = phylink;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(chip);
29862306a36Sopenharmony_ci	int val;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	val = rd32m(wx, WX_GPIO_EXT, BIT(offset));
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return !!(val & BIT(offset));
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int txgbe_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(chip);
30862306a36Sopenharmony_ci	u32 val;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	val = rd32(wx, WX_GPIO_DDR);
31162306a36Sopenharmony_ci	if (BIT(offset) & val)
31262306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_OUT;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return GPIO_LINE_DIRECTION_IN;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int txgbe_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(chip);
32062306a36Sopenharmony_ci	unsigned long flags;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
32362306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_DDR, BIT(offset), 0);
32462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset,
33062306a36Sopenharmony_ci				    int val)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(chip);
33362306a36Sopenharmony_ci	unsigned long flags;
33462306a36Sopenharmony_ci	u32 set;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	set = val ? BIT(offset) : 0;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
33962306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_DR, BIT(offset), set);
34062306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_DDR, BIT(offset), BIT(offset));
34162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return 0;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void txgbe_gpio_irq_ack(struct irq_data *d)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
34962306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
35062306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(gc);
35162306a36Sopenharmony_ci	unsigned long flags;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
35462306a36Sopenharmony_ci	wr32(wx, WX_GPIO_EOI, BIT(hwirq));
35562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void txgbe_gpio_irq_mask(struct irq_data *d)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
36162306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
36262306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(gc);
36362306a36Sopenharmony_ci	unsigned long flags;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	gpiochip_disable_irq(gc, hwirq);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
36862306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq));
36962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void txgbe_gpio_irq_unmask(struct irq_data *d)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
37562306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
37662306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(gc);
37762306a36Sopenharmony_ci	unsigned long flags;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	gpiochip_enable_irq(gc, hwirq);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
38262306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0);
38362306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic void txgbe_toggle_trigger(struct gpio_chip *gc, unsigned int offset)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(gc);
38962306a36Sopenharmony_ci	u32 pol, val;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	pol = rd32(wx, WX_GPIO_POLARITY);
39262306a36Sopenharmony_ci	val = rd32(wx, WX_GPIO_EXT);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (val & BIT(offset))
39562306a36Sopenharmony_ci		pol &= ~BIT(offset);
39662306a36Sopenharmony_ci	else
39762306a36Sopenharmony_ci		pol |= BIT(offset);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	wr32(wx, WX_GPIO_POLARITY, pol);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int txgbe_gpio_set_type(struct irq_data *d, unsigned int type)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
40562306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
40662306a36Sopenharmony_ci	struct wx *wx = gpiochip_get_data(gc);
40762306a36Sopenharmony_ci	u32 level, polarity, mask;
40862306a36Sopenharmony_ci	unsigned long flags;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	mask = BIT(hwirq);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (type & IRQ_TYPE_LEVEL_MASK) {
41362306a36Sopenharmony_ci		level = 0;
41462306a36Sopenharmony_ci		irq_set_handler_locked(d, handle_level_irq);
41562306a36Sopenharmony_ci	} else {
41662306a36Sopenharmony_ci		level = mask;
41762306a36Sopenharmony_ci		irq_set_handler_locked(d, handle_edge_irq);
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
42162306a36Sopenharmony_ci		polarity = mask;
42262306a36Sopenharmony_ci	else
42362306a36Sopenharmony_ci		polarity = 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	raw_spin_lock_irqsave(&wx->gpio_lock, flags);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_INTEN, mask, mask);
42862306a36Sopenharmony_ci	wr32m(wx, WX_GPIO_INTTYPE_LEVEL, mask, level);
42962306a36Sopenharmony_ci	if (type == IRQ_TYPE_EDGE_BOTH)
43062306a36Sopenharmony_ci		txgbe_toggle_trigger(gc, hwirq);
43162306a36Sopenharmony_ci	else
43262306a36Sopenharmony_ci		wr32m(wx, WX_GPIO_POLARITY, mask, polarity);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic const struct irq_chip txgbe_gpio_irq_chip = {
44062306a36Sopenharmony_ci	.name = "txgbe_gpio_irq",
44162306a36Sopenharmony_ci	.irq_ack = txgbe_gpio_irq_ack,
44262306a36Sopenharmony_ci	.irq_mask = txgbe_gpio_irq_mask,
44362306a36Sopenharmony_ci	.irq_unmask = txgbe_gpio_irq_unmask,
44462306a36Sopenharmony_ci	.irq_set_type = txgbe_gpio_set_type,
44562306a36Sopenharmony_ci	.flags = IRQCHIP_IMMUTABLE,
44662306a36Sopenharmony_ci	GPIOCHIP_IRQ_RESOURCE_HELPERS,
44762306a36Sopenharmony_ci};
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic void txgbe_irq_handler(struct irq_desc *desc)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
45262306a36Sopenharmony_ci	struct wx *wx = irq_desc_get_handler_data(desc);
45362306a36Sopenharmony_ci	struct txgbe *txgbe = wx->priv;
45462306a36Sopenharmony_ci	irq_hw_number_t hwirq;
45562306a36Sopenharmony_ci	unsigned long gpioirq;
45662306a36Sopenharmony_ci	struct gpio_chip *gc;
45762306a36Sopenharmony_ci	unsigned long flags;
45862306a36Sopenharmony_ci	u32 eicr;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	eicr = wx_misc_isb(wx, WX_ISB_MISC);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	chained_irq_enter(chip, desc);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	gpioirq = rd32(wx, WX_GPIO_INTSTATUS);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	gc = txgbe->gpio;
46762306a36Sopenharmony_ci	for_each_set_bit(hwirq, &gpioirq, gc->ngpio) {
46862306a36Sopenharmony_ci		int gpio = irq_find_mapping(gc->irq.domain, hwirq);
46962306a36Sopenharmony_ci		u32 irq_type = irq_get_trigger_type(gpio);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		generic_handle_domain_irq(gc->irq.domain, hwirq);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
47462306a36Sopenharmony_ci			raw_spin_lock_irqsave(&wx->gpio_lock, flags);
47562306a36Sopenharmony_ci			txgbe_toggle_trigger(gc, hwirq);
47662306a36Sopenharmony_ci			raw_spin_unlock_irqrestore(&wx->gpio_lock, flags);
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	chained_irq_exit(chip, desc);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
48362306a36Sopenharmony_ci		    TXGBE_PX_MISC_ETH_AN)) {
48462306a36Sopenharmony_ci		u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* unmask interrupt */
49062306a36Sopenharmony_ci	wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int txgbe_gpio_init(struct txgbe *txgbe)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct gpio_irq_chip *girq;
49662306a36Sopenharmony_ci	struct gpio_chip *gc;
49762306a36Sopenharmony_ci	struct device *dev;
49862306a36Sopenharmony_ci	struct wx *wx;
49962306a36Sopenharmony_ci	int ret;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	wx = txgbe->wx;
50262306a36Sopenharmony_ci	dev = &wx->pdev->dev;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	raw_spin_lock_init(&wx->gpio_lock);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
50762306a36Sopenharmony_ci	if (!gc)
50862306a36Sopenharmony_ci		return -ENOMEM;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	gc->label = devm_kasprintf(dev, GFP_KERNEL, "txgbe_gpio-%x",
51162306a36Sopenharmony_ci				   pci_dev_id(wx->pdev));
51262306a36Sopenharmony_ci	if (!gc->label)
51362306a36Sopenharmony_ci		return -ENOMEM;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	gc->base = -1;
51662306a36Sopenharmony_ci	gc->ngpio = 6;
51762306a36Sopenharmony_ci	gc->owner = THIS_MODULE;
51862306a36Sopenharmony_ci	gc->parent = dev;
51962306a36Sopenharmony_ci	gc->fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_GPIO]);
52062306a36Sopenharmony_ci	gc->get = txgbe_gpio_get;
52162306a36Sopenharmony_ci	gc->get_direction = txgbe_gpio_get_direction;
52262306a36Sopenharmony_ci	gc->direction_input = txgbe_gpio_direction_in;
52362306a36Sopenharmony_ci	gc->direction_output = txgbe_gpio_direction_out;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	girq = &gc->irq;
52662306a36Sopenharmony_ci	gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip);
52762306a36Sopenharmony_ci	girq->parent_handler = txgbe_irq_handler;
52862306a36Sopenharmony_ci	girq->parent_handler_data = wx;
52962306a36Sopenharmony_ci	girq->num_parents = 1;
53062306a36Sopenharmony_ci	girq->parents = devm_kcalloc(dev, girq->num_parents,
53162306a36Sopenharmony_ci				     sizeof(*girq->parents), GFP_KERNEL);
53262306a36Sopenharmony_ci	if (!girq->parents)
53362306a36Sopenharmony_ci		return -ENOMEM;
53462306a36Sopenharmony_ci	girq->parents[0] = wx->msix_entries[wx->num_q_vectors].vector;
53562306a36Sopenharmony_ci	girq->default_type = IRQ_TYPE_NONE;
53662306a36Sopenharmony_ci	girq->handler = handle_bad_irq;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(dev, gc, wx);
53962306a36Sopenharmony_ci	if (ret)
54062306a36Sopenharmony_ci		return ret;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	txgbe->gpio = gc;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return 0;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic int txgbe_clock_register(struct txgbe *txgbe)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct pci_dev *pdev = txgbe->wx->pdev;
55062306a36Sopenharmony_ci	struct clk_lookup *clock;
55162306a36Sopenharmony_ci	char clk_name[32];
55262306a36Sopenharmony_ci	struct clk *clk;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	snprintf(clk_name, sizeof(clk_name), "i2c_dw.%d",
55562306a36Sopenharmony_ci		 pci_dev_id(pdev));
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000);
55862306a36Sopenharmony_ci	if (IS_ERR(clk))
55962306a36Sopenharmony_ci		return PTR_ERR(clk);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	clock = clkdev_create(clk, NULL, clk_name);
56262306a36Sopenharmony_ci	if (!clock) {
56362306a36Sopenharmony_ci		clk_unregister(clk);
56462306a36Sopenharmony_ci		return -ENOMEM;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	txgbe->clk = clk;
56862306a36Sopenharmony_ci	txgbe->clock = clock;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int txgbe_i2c_read(void *context, unsigned int reg, unsigned int *val)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct wx *wx = context;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	*val = rd32(wx, reg + TXGBE_I2C_BASE);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return 0;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic int txgbe_i2c_write(void *context, unsigned int reg, unsigned int val)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct wx *wx = context;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	wr32(wx, reg + TXGBE_I2C_BASE, val);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic const struct regmap_config i2c_regmap_config = {
59262306a36Sopenharmony_ci	.reg_bits = 32,
59362306a36Sopenharmony_ci	.val_bits = 32,
59462306a36Sopenharmony_ci	.reg_read = txgbe_i2c_read,
59562306a36Sopenharmony_ci	.reg_write = txgbe_i2c_write,
59662306a36Sopenharmony_ci	.fast_io = true,
59762306a36Sopenharmony_ci};
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic int txgbe_i2c_register(struct txgbe *txgbe)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct platform_device_info info = {};
60262306a36Sopenharmony_ci	struct platform_device *i2c_dev;
60362306a36Sopenharmony_ci	struct regmap *i2c_regmap;
60462306a36Sopenharmony_ci	struct pci_dev *pdev;
60562306a36Sopenharmony_ci	struct wx *wx;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	wx = txgbe->wx;
60862306a36Sopenharmony_ci	pdev = wx->pdev;
60962306a36Sopenharmony_ci	i2c_regmap = devm_regmap_init(&pdev->dev, NULL, wx, &i2c_regmap_config);
61062306a36Sopenharmony_ci	if (IS_ERR(i2c_regmap)) {
61162306a36Sopenharmony_ci		wx_err(wx, "failed to init I2C regmap\n");
61262306a36Sopenharmony_ci		return PTR_ERR(i2c_regmap);
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	info.parent = &pdev->dev;
61662306a36Sopenharmony_ci	info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]);
61762306a36Sopenharmony_ci	info.name = "i2c_designware";
61862306a36Sopenharmony_ci	info.id = pci_dev_id(pdev);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	info.res = &DEFINE_RES_IRQ(pdev->irq);
62162306a36Sopenharmony_ci	info.num_res = 1;
62262306a36Sopenharmony_ci	i2c_dev = platform_device_register_full(&info);
62362306a36Sopenharmony_ci	if (IS_ERR(i2c_dev))
62462306a36Sopenharmony_ci		return PTR_ERR(i2c_dev);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	txgbe->i2c_dev = i2c_dev;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int txgbe_sfp_register(struct txgbe *txgbe)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct pci_dev *pdev = txgbe->wx->pdev;
63462306a36Sopenharmony_ci	struct platform_device_info info = {};
63562306a36Sopenharmony_ci	struct platform_device *sfp_dev;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	info.parent = &pdev->dev;
63862306a36Sopenharmony_ci	info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]);
63962306a36Sopenharmony_ci	info.name = "sfp";
64062306a36Sopenharmony_ci	info.id = pci_dev_id(pdev);
64162306a36Sopenharmony_ci	sfp_dev = platform_device_register_full(&info);
64262306a36Sopenharmony_ci	if (IS_ERR(sfp_dev))
64362306a36Sopenharmony_ci		return PTR_ERR(sfp_dev);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	txgbe->sfp_dev = sfp_dev;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return 0;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
65162306a36Sopenharmony_ci			  int devnum, int regnum)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct wx *wx = bus->priv;
65462306a36Sopenharmony_ci	u32 val, command;
65562306a36Sopenharmony_ci	int ret;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* setup and write the address cycle command */
65862306a36Sopenharmony_ci	command = WX_MSCA_RA(regnum) |
65962306a36Sopenharmony_ci		  WX_MSCA_PA(phy_addr) |
66062306a36Sopenharmony_ci		  WX_MSCA_DA(devnum);
66162306a36Sopenharmony_ci	wr32(wx, WX_MSCA, command);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
66462306a36Sopenharmony_ci	wr32(wx, WX_MSCC, command);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* wait to complete */
66762306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
66862306a36Sopenharmony_ci				100000, false, wx, WX_MSCC);
66962306a36Sopenharmony_ci	if (ret) {
67062306a36Sopenharmony_ci		wx_err(wx, "Mdio read c45 command did not complete.\n");
67162306a36Sopenharmony_ci		return ret;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return (u16)rd32(wx, WX_MSCC);
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
67862306a36Sopenharmony_ci			   int devnum, int regnum, u16 value)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct wx *wx = bus->priv;
68162306a36Sopenharmony_ci	int ret, command;
68262306a36Sopenharmony_ci	u16 val;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* setup and write the address cycle command */
68562306a36Sopenharmony_ci	command = WX_MSCA_RA(regnum) |
68662306a36Sopenharmony_ci		  WX_MSCA_PA(phy_addr) |
68762306a36Sopenharmony_ci		  WX_MSCA_DA(devnum);
68862306a36Sopenharmony_ci	wr32(wx, WX_MSCA, command);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
69162306a36Sopenharmony_ci	wr32(wx, WX_MSCC, command);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* wait to complete */
69462306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
69562306a36Sopenharmony_ci				100000, false, wx, WX_MSCC);
69662306a36Sopenharmony_ci	if (ret)
69762306a36Sopenharmony_ci		wx_err(wx, "Mdio write c45 command did not complete.\n");
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	return ret;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int txgbe_ext_phy_init(struct txgbe *txgbe)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct phy_device *phydev;
70562306a36Sopenharmony_ci	struct mii_bus *mii_bus;
70662306a36Sopenharmony_ci	struct pci_dev *pdev;
70762306a36Sopenharmony_ci	struct wx *wx;
70862306a36Sopenharmony_ci	int ret = 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	wx = txgbe->wx;
71162306a36Sopenharmony_ci	pdev = wx->pdev;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	mii_bus = devm_mdiobus_alloc(&pdev->dev);
71462306a36Sopenharmony_ci	if (!mii_bus)
71562306a36Sopenharmony_ci		return -ENOMEM;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	mii_bus->name = "txgbe_mii_bus";
71862306a36Sopenharmony_ci	mii_bus->read_c45 = &txgbe_phy_read;
71962306a36Sopenharmony_ci	mii_bus->write_c45 = &txgbe_phy_write;
72062306a36Sopenharmony_ci	mii_bus->parent = &pdev->dev;
72162306a36Sopenharmony_ci	mii_bus->phy_mask = GENMASK(31, 1);
72262306a36Sopenharmony_ci	mii_bus->priv = wx;
72362306a36Sopenharmony_ci	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
72462306a36Sopenharmony_ci		 (pdev->bus->number << 8) | pdev->devfn);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	ret = devm_mdiobus_register(&pdev->dev, mii_bus);
72762306a36Sopenharmony_ci	if (ret) {
72862306a36Sopenharmony_ci		wx_err(wx, "failed to register MDIO bus: %d\n", ret);
72962306a36Sopenharmony_ci		return ret;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	phydev = phy_find_first(mii_bus);
73362306a36Sopenharmony_ci	if (!phydev) {
73462306a36Sopenharmony_ci		wx_err(wx, "no PHY found\n");
73562306a36Sopenharmony_ci		return -ENODEV;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	phy_attached_info(phydev);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	wx->link = 0;
74162306a36Sopenharmony_ci	wx->speed = 0;
74262306a36Sopenharmony_ci	wx->duplex = 0;
74362306a36Sopenharmony_ci	wx->phydev = phydev;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	ret = txgbe_phylink_init(txgbe);
74662306a36Sopenharmony_ci	if (ret) {
74762306a36Sopenharmony_ci		wx_err(wx, "failed to init phylink: %d\n", ret);
74862306a36Sopenharmony_ci		return ret;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return 0;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ciint txgbe_init_phy(struct txgbe *txgbe)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	int ret;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (txgbe->wx->media_type == sp_media_copper)
75962306a36Sopenharmony_ci		return txgbe_ext_phy_init(txgbe);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	ret = txgbe_swnodes_register(txgbe);
76262306a36Sopenharmony_ci	if (ret) {
76362306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to register software nodes\n");
76462306a36Sopenharmony_ci		return ret;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	ret = txgbe_mdio_pcs_init(txgbe);
76862306a36Sopenharmony_ci	if (ret) {
76962306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret);
77062306a36Sopenharmony_ci		goto err_unregister_swnode;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	ret = txgbe_phylink_init(txgbe);
77462306a36Sopenharmony_ci	if (ret) {
77562306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to init phylink\n");
77662306a36Sopenharmony_ci		goto err_destroy_xpcs;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	ret = txgbe_gpio_init(txgbe);
78062306a36Sopenharmony_ci	if (ret) {
78162306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to init gpio\n");
78262306a36Sopenharmony_ci		goto err_destroy_phylink;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ret = txgbe_clock_register(txgbe);
78662306a36Sopenharmony_ci	if (ret) {
78762306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to register clock: %d\n", ret);
78862306a36Sopenharmony_ci		goto err_destroy_phylink;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	ret = txgbe_i2c_register(txgbe);
79262306a36Sopenharmony_ci	if (ret) {
79362306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
79462306a36Sopenharmony_ci		goto err_unregister_clk;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	ret = txgbe_sfp_register(txgbe);
79862306a36Sopenharmony_ci	if (ret) {
79962306a36Sopenharmony_ci		wx_err(txgbe->wx, "failed to register sfp\n");
80062306a36Sopenharmony_ci		goto err_unregister_i2c;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return 0;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cierr_unregister_i2c:
80662306a36Sopenharmony_ci	platform_device_unregister(txgbe->i2c_dev);
80762306a36Sopenharmony_cierr_unregister_clk:
80862306a36Sopenharmony_ci	clkdev_drop(txgbe->clock);
80962306a36Sopenharmony_ci	clk_unregister(txgbe->clk);
81062306a36Sopenharmony_cierr_destroy_phylink:
81162306a36Sopenharmony_ci	phylink_destroy(txgbe->phylink);
81262306a36Sopenharmony_cierr_destroy_xpcs:
81362306a36Sopenharmony_ci	xpcs_destroy(txgbe->xpcs);
81462306a36Sopenharmony_cierr_unregister_swnode:
81562306a36Sopenharmony_ci	software_node_unregister_node_group(txgbe->nodes.group);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	return ret;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_civoid txgbe_remove_phy(struct txgbe *txgbe)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	if (txgbe->wx->media_type == sp_media_copper) {
82362306a36Sopenharmony_ci		phylink_disconnect_phy(txgbe->phylink);
82462306a36Sopenharmony_ci		phylink_destroy(txgbe->phylink);
82562306a36Sopenharmony_ci		return;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	platform_device_unregister(txgbe->sfp_dev);
82962306a36Sopenharmony_ci	platform_device_unregister(txgbe->i2c_dev);
83062306a36Sopenharmony_ci	clkdev_drop(txgbe->clock);
83162306a36Sopenharmony_ci	clk_unregister(txgbe->clk);
83262306a36Sopenharmony_ci	phylink_destroy(txgbe->phylink);
83362306a36Sopenharmony_ci	xpcs_destroy(txgbe->xpcs);
83462306a36Sopenharmony_ci	software_node_unregister_node_group(txgbe->nodes.group);
83562306a36Sopenharmony_ci}
836