162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> 462306a36Sopenharmony_ci * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/mdio.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/phy.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/bitfield.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define XWAY_MDIO_MIICTRL 0x17 /* mii control */ 1462306a36Sopenharmony_ci#define XWAY_MDIO_IMASK 0x19 /* interrupt mask */ 1562306a36Sopenharmony_ci#define XWAY_MDIO_ISTAT 0x1A /* interrupt status */ 1662306a36Sopenharmony_ci#define XWAY_MDIO_LED 0x1B /* led control */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12) 1962306a36Sopenharmony_ci#define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* bit 15:12 are reserved */ 2262306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */ 2362306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED2_EN BIT(10) /* Enable the integrated function of LED2 */ 2462306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED1_EN BIT(9) /* Enable the integrated function of LED1 */ 2562306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED0_EN BIT(8) /* Enable the integrated function of LED0 */ 2662306a36Sopenharmony_ci/* bit 7:4 are reserved */ 2762306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED3_DA BIT(3) /* Direct Access to LED3 */ 2862306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED2_DA BIT(2) /* Direct Access to LED2 */ 2962306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED1_DA BIT(1) /* Direct Access to LED1 */ 3062306a36Sopenharmony_ci#define XWAY_MDIO_LED_LED0_DA BIT(0) /* Direct Access to LED0 */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define XWAY_MDIO_INIT_WOL BIT(15) /* Wake-On-LAN */ 3362306a36Sopenharmony_ci#define XWAY_MDIO_INIT_MSRE BIT(14) 3462306a36Sopenharmony_ci#define XWAY_MDIO_INIT_NPRX BIT(13) 3562306a36Sopenharmony_ci#define XWAY_MDIO_INIT_NPTX BIT(12) 3662306a36Sopenharmony_ci#define XWAY_MDIO_INIT_ANE BIT(11) /* Auto-Neg error */ 3762306a36Sopenharmony_ci#define XWAY_MDIO_INIT_ANC BIT(10) /* Auto-Neg complete */ 3862306a36Sopenharmony_ci#define XWAY_MDIO_INIT_ADSC BIT(5) /* Link auto-downspeed detect */ 3962306a36Sopenharmony_ci#define XWAY_MDIO_INIT_MPIPC BIT(4) 4062306a36Sopenharmony_ci#define XWAY_MDIO_INIT_MDIXC BIT(3) 4162306a36Sopenharmony_ci#define XWAY_MDIO_INIT_DXMC BIT(2) /* Duplex mode change */ 4262306a36Sopenharmony_ci#define XWAY_MDIO_INIT_LSPC BIT(1) /* Link speed change */ 4362306a36Sopenharmony_ci#define XWAY_MDIO_INIT_LSTC BIT(0) /* Link state change */ 4462306a36Sopenharmony_ci#define XWAY_MDIO_INIT_MASK (XWAY_MDIO_INIT_LSTC | \ 4562306a36Sopenharmony_ci XWAY_MDIO_INIT_ADSC) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define ADVERTISED_MPD BIT(10) /* Multi-port device */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* LED Configuration */ 5062306a36Sopenharmony_ci#define XWAY_MMD_LEDCH 0x01E0 5162306a36Sopenharmony_ci/* Inverse of SCAN Function */ 5262306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_NONE 0x0000 5362306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_LINK 0x0001 5462306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_PDOWN 0x0002 5562306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_EEE 0x0003 5662306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_ANEG 0x0004 5762306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_ABIST 0x0005 5862306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_CDIAG 0x0006 5962306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_NACS_TEST 0x0007 6062306a36Sopenharmony_ci/* Slow Blink Frequency */ 6162306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SBF_F02HZ 0x0000 6262306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SBF_F04HZ 0x0010 6362306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SBF_F08HZ 0x0020 6462306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SBF_F16HZ 0x0030 6562306a36Sopenharmony_ci/* Fast Blink Frequency */ 6662306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_FBF_F02HZ 0x0000 6762306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_FBF_F04HZ 0x0040 6862306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_FBF_F08HZ 0x0080 6962306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_FBF_F16HZ 0x00C0 7062306a36Sopenharmony_ci/* LED Configuration */ 7162306a36Sopenharmony_ci#define XWAY_MMD_LEDCL 0x01E1 7262306a36Sopenharmony_ci/* Complex Blinking Configuration */ 7362306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_NONE 0x0000 7462306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_LINK 0x0001 7562306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_PDOWN 0x0002 7662306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_EEE 0x0003 7762306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_ANEG 0x0004 7862306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_ABIST 0x0005 7962306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_CDIAG 0x0006 8062306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_CBLINK_TEST 0x0007 8162306a36Sopenharmony_ci/* Complex SCAN Configuration */ 8262306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_NONE 0x0000 8362306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_LINK 0x0010 8462306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_PDOWN 0x0020 8562306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_EEE 0x0030 8662306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_ANEG 0x0040 8762306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_ABIST 0x0050 8862306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_CDIAG 0x0060 8962306a36Sopenharmony_ci#define XWAY_MMD_LEDCH_SCAN_TEST 0x0070 9062306a36Sopenharmony_ci/* Configuration for LED Pin x */ 9162306a36Sopenharmony_ci#define XWAY_MMD_LED0H 0x01E2 9262306a36Sopenharmony_ci/* Fast Blinking Configuration */ 9362306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_MASK 0x000F 9462306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_NONE 0x0000 9562306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK10 0x0001 9662306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK100 0x0002 9762306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK10X 0x0003 9862306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK1000 0x0004 9962306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK10_0 0x0005 10062306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK100X 0x0006 10162306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_LINK10XX 0x0007 10262306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_PDOWN 0x0008 10362306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_EEE 0x0009 10462306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_ANEG 0x000A 10562306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_ABIST 0x000B 10662306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_BLINKF_CDIAG 0x000C 10762306a36Sopenharmony_ci/* Constant On Configuration */ 10862306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_MASK 0x00F0 10962306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_NONE 0x0000 11062306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK10 0x0010 11162306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK100 0x0020 11262306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK10X 0x0030 11362306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK1000 0x0040 11462306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK10_0 0x0050 11562306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK100X 0x0060 11662306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_LINK10XX 0x0070 11762306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_PDOWN 0x0080 11862306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_EEE 0x0090 11962306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_ANEG 0x00A0 12062306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_ABIST 0x00B0 12162306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_CDIAG 0x00C0 12262306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_COPPER 0x00D0 12362306a36Sopenharmony_ci#define XWAY_MMD_LEDxH_CON_FIBER 0x00E0 12462306a36Sopenharmony_ci/* Configuration for LED Pin x */ 12562306a36Sopenharmony_ci#define XWAY_MMD_LED0L 0x01E3 12662306a36Sopenharmony_ci/* Pulsing Configuration */ 12762306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_PULSE_MASK 0x000F 12862306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_PULSE_NONE 0x0000 12962306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_PULSE_TXACT 0x0001 13062306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_PULSE_RXACT 0x0002 13162306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_PULSE_COL 0x0004 13262306a36Sopenharmony_ci/* Slow Blinking Configuration */ 13362306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_MASK 0x00F0 13462306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_NONE 0x0000 13562306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK10 0x0010 13662306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK100 0x0020 13762306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK10X 0x0030 13862306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK1000 0x0040 13962306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK10_0 0x0050 14062306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK100X 0x0060 14162306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_LINK10XX 0x0070 14262306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_PDOWN 0x0080 14362306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_EEE 0x0090 14462306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_ANEG 0x00A0 14562306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_ABIST 0x00B0 14662306a36Sopenharmony_ci#define XWAY_MMD_LEDxL_BLINKS_CDIAG 0x00C0 14762306a36Sopenharmony_ci#define XWAY_MMD_LED1H 0x01E4 14862306a36Sopenharmony_ci#define XWAY_MMD_LED1L 0x01E5 14962306a36Sopenharmony_ci#define XWAY_MMD_LED2H 0x01E6 15062306a36Sopenharmony_ci#define XWAY_MMD_LED2L 0x01E7 15162306a36Sopenharmony_ci#define XWAY_MMD_LED3H 0x01E8 15262306a36Sopenharmony_ci#define XWAY_MMD_LED3L 0x01E9 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define PHY_ID_PHY11G_1_3 0x030260D1 15562306a36Sopenharmony_ci#define PHY_ID_PHY22F_1_3 0x030260E1 15662306a36Sopenharmony_ci#define PHY_ID_PHY11G_1_4 0xD565A400 15762306a36Sopenharmony_ci#define PHY_ID_PHY22F_1_4 0xD565A410 15862306a36Sopenharmony_ci#define PHY_ID_PHY11G_1_5 0xD565A401 15962306a36Sopenharmony_ci#define PHY_ID_PHY22F_1_5 0xD565A411 16062306a36Sopenharmony_ci#define PHY_ID_PHY11G_VR9_1_1 0xD565A408 16162306a36Sopenharmony_ci#define PHY_ID_PHY22F_VR9_1_1 0xD565A418 16262306a36Sopenharmony_ci#define PHY_ID_PHY11G_VR9_1_2 0xD565A409 16362306a36Sopenharmony_ci#define PHY_ID_PHY22F_VR9_1_2 0xD565A419 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500, 16662306a36Sopenharmony_ci 3000, 3500}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int xway_gphy_rgmii_init(struct phy_device *phydev) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct device *dev = &phydev->mdio.dev; 17162306a36Sopenharmony_ci unsigned int delay_size = ARRAY_SIZE(xway_internal_delay); 17262306a36Sopenharmony_ci s32 int_delay; 17362306a36Sopenharmony_ci int val = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!phy_interface_is_rgmii(phydev)) 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Existing behavior was to use default pin strapping delay in rgmii 17962306a36Sopenharmony_ci * mode, but rgmii should have meant no delay. Warn existing users, 18062306a36Sopenharmony_ci * but do not change anything at the moment. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 18362306a36Sopenharmony_ci u16 txskew, rxskew; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci val = phy_read(phydev, XWAY_MDIO_MIICTRL); 18662306a36Sopenharmony_ci if (val < 0) 18762306a36Sopenharmony_ci return val; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 19062306a36Sopenharmony_ci rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (txskew > 0 || rxskew > 0) 19362306a36Sopenharmony_ci phydev_warn(phydev, 19462306a36Sopenharmony_ci "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n" 19562306a36Sopenharmony_ci "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n", 19662306a36Sopenharmony_ci xway_internal_delay[txskew], 19762306a36Sopenharmony_ci xway_internal_delay[rxskew]); 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 20262306a36Sopenharmony_ci phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 20362306a36Sopenharmony_ci int_delay = phy_get_internal_delay(phydev, dev, 20462306a36Sopenharmony_ci xway_internal_delay, 20562306a36Sopenharmony_ci delay_size, true); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* if rx-internal-delay-ps is missing, use default of 2.0 ns */ 20862306a36Sopenharmony_ci if (int_delay < 0) 20962306a36Sopenharmony_ci int_delay = 4; /* 2000 ps */ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 21562306a36Sopenharmony_ci phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 21662306a36Sopenharmony_ci int_delay = phy_get_internal_delay(phydev, dev, 21762306a36Sopenharmony_ci xway_internal_delay, 21862306a36Sopenharmony_ci delay_size, false); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* if tx-internal-delay-ps is missing, use default of 2.0 ns */ 22162306a36Sopenharmony_ci if (int_delay < 0) 22262306a36Sopenharmony_ci int_delay = 4; /* 2000 ps */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return phy_modify(phydev, XWAY_MDIO_MIICTRL, 22862306a36Sopenharmony_ci XWAY_MDIO_MIICTRL_RXSKEW_MASK | 22962306a36Sopenharmony_ci XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int xway_gphy_config_init(struct phy_device *phydev) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci int err; 23562306a36Sopenharmony_ci u32 ledxh; 23662306a36Sopenharmony_ci u32 ledxl; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Mask all interrupts */ 23962306a36Sopenharmony_ci err = phy_write(phydev, XWAY_MDIO_IMASK, 0); 24062306a36Sopenharmony_ci if (err) 24162306a36Sopenharmony_ci return err; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Clear all pending interrupts */ 24462306a36Sopenharmony_ci phy_read(phydev, XWAY_MDIO_ISTAT); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Ensure that integrated led function is enabled for all leds */ 24762306a36Sopenharmony_ci err = phy_write(phydev, XWAY_MDIO_LED, 24862306a36Sopenharmony_ci XWAY_MDIO_LED_LED0_EN | 24962306a36Sopenharmony_ci XWAY_MDIO_LED_LED1_EN | 25062306a36Sopenharmony_ci XWAY_MDIO_LED_LED2_EN | 25162306a36Sopenharmony_ci XWAY_MDIO_LED_LED3_EN); 25262306a36Sopenharmony_ci if (err) 25362306a36Sopenharmony_ci return err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH, 25662306a36Sopenharmony_ci XWAY_MMD_LEDCH_NACS_NONE | 25762306a36Sopenharmony_ci XWAY_MMD_LEDCH_SBF_F02HZ | 25862306a36Sopenharmony_ci XWAY_MMD_LEDCH_FBF_F16HZ); 25962306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL, 26062306a36Sopenharmony_ci XWAY_MMD_LEDCH_CBLINK_NONE | 26162306a36Sopenharmony_ci XWAY_MMD_LEDCH_SCAN_NONE); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /** 26462306a36Sopenharmony_ci * In most cases only one LED is connected to this phy, so 26562306a36Sopenharmony_ci * configure them all to constant on and pulse mode. LED3 is 26662306a36Sopenharmony_ci * only available in some packages, leave it in its reset 26762306a36Sopenharmony_ci * configuration. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX; 27062306a36Sopenharmony_ci ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT | 27162306a36Sopenharmony_ci XWAY_MMD_LEDxL_BLINKS_NONE; 27262306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh); 27362306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl); 27462306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh); 27562306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl); 27662306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); 27762306a36Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci err = xway_gphy_rgmii_init(phydev); 28062306a36Sopenharmony_ci if (err) 28162306a36Sopenharmony_ci return err; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int xway_gphy14_config_aneg(struct phy_device *phydev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci int reg, err; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Advertise as multi-port device, see IEEE802.3-2002 40.5.1.1 */ 29162306a36Sopenharmony_ci /* This is a workaround for an errata in rev < 1.5 devices */ 29262306a36Sopenharmony_ci reg = phy_read(phydev, MII_CTRL1000); 29362306a36Sopenharmony_ci reg |= ADVERTISED_MPD; 29462306a36Sopenharmony_ci err = phy_write(phydev, MII_CTRL1000, reg); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci return err; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return genphy_config_aneg(phydev); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int xway_gphy_ack_interrupt(struct phy_device *phydev) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci int reg; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci reg = phy_read(phydev, XWAY_MDIO_ISTAT); 30662306a36Sopenharmony_ci return (reg < 0) ? reg : 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int xway_gphy_config_intr(struct phy_device *phydev) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci u16 mask = 0; 31262306a36Sopenharmony_ci int err; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 31562306a36Sopenharmony_ci err = xway_gphy_ack_interrupt(phydev); 31662306a36Sopenharmony_ci if (err) 31762306a36Sopenharmony_ci return err; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci mask = XWAY_MDIO_INIT_MASK; 32062306a36Sopenharmony_ci err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci err = phy_write(phydev, XWAY_MDIO_IMASK, mask); 32362306a36Sopenharmony_ci if (err) 32462306a36Sopenharmony_ci return err; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci err = xway_gphy_ack_interrupt(phydev); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return err; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci int irq_status; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci irq_status = phy_read(phydev, XWAY_MDIO_ISTAT); 33762306a36Sopenharmony_ci if (irq_status < 0) { 33862306a36Sopenharmony_ci phy_error(phydev); 33962306a36Sopenharmony_ci return IRQ_NONE; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!(irq_status & XWAY_MDIO_INIT_MASK)) 34362306a36Sopenharmony_ci return IRQ_NONE; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci phy_trigger_machine(phydev); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return IRQ_HANDLED; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic struct phy_driver xway_gphy[] = { 35162306a36Sopenharmony_ci { 35262306a36Sopenharmony_ci .phy_id = PHY_ID_PHY11G_1_3, 35362306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 35462306a36Sopenharmony_ci .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3", 35562306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 35662306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 35762306a36Sopenharmony_ci .config_aneg = xway_gphy14_config_aneg, 35862306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 35962306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 36062306a36Sopenharmony_ci .suspend = genphy_suspend, 36162306a36Sopenharmony_ci .resume = genphy_resume, 36262306a36Sopenharmony_ci }, { 36362306a36Sopenharmony_ci .phy_id = PHY_ID_PHY22F_1_3, 36462306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 36562306a36Sopenharmony_ci .name = "Intel XWAY PHY22F (PEF 7061) v1.3", 36662306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 36762306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 36862306a36Sopenharmony_ci .config_aneg = xway_gphy14_config_aneg, 36962306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 37062306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 37162306a36Sopenharmony_ci .suspend = genphy_suspend, 37262306a36Sopenharmony_ci .resume = genphy_resume, 37362306a36Sopenharmony_ci }, { 37462306a36Sopenharmony_ci .phy_id = PHY_ID_PHY11G_1_4, 37562306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 37662306a36Sopenharmony_ci .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4", 37762306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 37862306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 37962306a36Sopenharmony_ci .config_aneg = xway_gphy14_config_aneg, 38062306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 38162306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 38262306a36Sopenharmony_ci .suspend = genphy_suspend, 38362306a36Sopenharmony_ci .resume = genphy_resume, 38462306a36Sopenharmony_ci }, { 38562306a36Sopenharmony_ci .phy_id = PHY_ID_PHY22F_1_4, 38662306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 38762306a36Sopenharmony_ci .name = "Intel XWAY PHY22F (PEF 7061) v1.4", 38862306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 38962306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 39062306a36Sopenharmony_ci .config_aneg = xway_gphy14_config_aneg, 39162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 39262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 39362306a36Sopenharmony_ci .suspend = genphy_suspend, 39462306a36Sopenharmony_ci .resume = genphy_resume, 39562306a36Sopenharmony_ci }, { 39662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY11G_1_5, 39762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 39862306a36Sopenharmony_ci .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6", 39962306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 40062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 40162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 40262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 40362306a36Sopenharmony_ci .suspend = genphy_suspend, 40462306a36Sopenharmony_ci .resume = genphy_resume, 40562306a36Sopenharmony_ci }, { 40662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY22F_1_5, 40762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 40862306a36Sopenharmony_ci .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6", 40962306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 41062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 41162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 41262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 41362306a36Sopenharmony_ci .suspend = genphy_suspend, 41462306a36Sopenharmony_ci .resume = genphy_resume, 41562306a36Sopenharmony_ci }, { 41662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY11G_VR9_1_1, 41762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 41862306a36Sopenharmony_ci .name = "Intel XWAY PHY11G (xRX v1.1 integrated)", 41962306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 42062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 42162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 42262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 42362306a36Sopenharmony_ci .suspend = genphy_suspend, 42462306a36Sopenharmony_ci .resume = genphy_resume, 42562306a36Sopenharmony_ci }, { 42662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY22F_VR9_1_1, 42762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 42862306a36Sopenharmony_ci .name = "Intel XWAY PHY22F (xRX v1.1 integrated)", 42962306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 43062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 43162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 43262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 43362306a36Sopenharmony_ci .suspend = genphy_suspend, 43462306a36Sopenharmony_ci .resume = genphy_resume, 43562306a36Sopenharmony_ci }, { 43662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY11G_VR9_1_2, 43762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 43862306a36Sopenharmony_ci .name = "Intel XWAY PHY11G (xRX v1.2 integrated)", 43962306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 44062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 44162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 44262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 44362306a36Sopenharmony_ci .suspend = genphy_suspend, 44462306a36Sopenharmony_ci .resume = genphy_resume, 44562306a36Sopenharmony_ci }, { 44662306a36Sopenharmony_ci .phy_id = PHY_ID_PHY22F_VR9_1_2, 44762306a36Sopenharmony_ci .phy_id_mask = 0xffffffff, 44862306a36Sopenharmony_ci .name = "Intel XWAY PHY22F (xRX v1.2 integrated)", 44962306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 45062306a36Sopenharmony_ci .config_init = xway_gphy_config_init, 45162306a36Sopenharmony_ci .handle_interrupt = xway_gphy_handle_interrupt, 45262306a36Sopenharmony_ci .config_intr = xway_gphy_config_intr, 45362306a36Sopenharmony_ci .suspend = genphy_suspend, 45462306a36Sopenharmony_ci .resume = genphy_resume, 45562306a36Sopenharmony_ci }, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_cimodule_phy_driver(xway_gphy); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { 46062306a36Sopenharmony_ci { PHY_ID_PHY11G_1_3, 0xffffffff }, 46162306a36Sopenharmony_ci { PHY_ID_PHY22F_1_3, 0xffffffff }, 46262306a36Sopenharmony_ci { PHY_ID_PHY11G_1_4, 0xffffffff }, 46362306a36Sopenharmony_ci { PHY_ID_PHY22F_1_4, 0xffffffff }, 46462306a36Sopenharmony_ci { PHY_ID_PHY11G_1_5, 0xffffffff }, 46562306a36Sopenharmony_ci { PHY_ID_PHY22F_1_5, 0xffffffff }, 46662306a36Sopenharmony_ci { PHY_ID_PHY11G_VR9_1_1, 0xffffffff }, 46762306a36Sopenharmony_ci { PHY_ID_PHY22F_VR9_1_1, 0xffffffff }, 46862306a36Sopenharmony_ci { PHY_ID_PHY11G_VR9_1_2, 0xffffffff }, 46962306a36Sopenharmony_ci { PHY_ID_PHY22F_VR9_1_2, 0xffffffff }, 47062306a36Sopenharmony_ci { } 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, xway_gphy_tbl); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel XWAY PHY driver"); 47562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 476