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