mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			213 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 5d2d78860f98eb5c03bc404eb024606878901ac8 Mon Sep 17 00:00:00 2001
 | |
| From: Daniel Golle <daniel@makrotopia.org>
 | |
| Date: Tue, 13 Jun 2023 03:27:14 +0100
 | |
| Subject: [PATCH] net: phy: mediatek-ge-soc: initialize MT7988 PHY LEDs default
 | |
|  state
 | |
| 
 | |
| Initialize LEDs and set sane default values.
 | |
| Read boottrap register and apply LED polarities accordingly to get
 | |
| uniform behavior from all LEDs on MT7988.
 | |
| Requires syscon phandle 'mediatek,pio' present in parenting MDIO bus
 | |
| which should point to the syscon holding the boottrap register.
 | |
| 
 | |
| Signed-off-by: Daniel Golle <daniel@makrotopia.org>
 | |
| ---
 | |
|  drivers/net/phy/mediatek-ge-soc.c | 144 ++++++++++++++++++++++++++++--
 | |
|  1 file changed, 136 insertions(+), 8 deletions(-)
 | |
| 
 | |
| --- a/drivers/net/phy/mediatek-ge-soc.c
 | |
| +++ b/drivers/net/phy/mediatek-ge-soc.c
 | |
| @@ -1,11 +1,13 @@
 | |
|  // SPDX-License-Identifier: GPL-2.0+
 | |
|  #include <linux/bitfield.h>
 | |
| +#include <linux/mfd/syscon.h>
 | |
|  #include <linux/module.h>
 | |
|  #include <linux/nvmem-consumer.h>
 | |
|  #include <linux/of_address.h>
 | |
|  #include <linux/of_platform.h>
 | |
|  #include <linux/pinctrl/consumer.h>
 | |
|  #include <linux/phy.h>
 | |
| +#include <linux/regmap.h>
 | |
|  
 | |
|  #define MTK_GPHY_ID_MT7981			0x03a29461
 | |
|  #define MTK_GPHY_ID_MT7988			0x03a29481
 | |
| @@ -208,9 +210,40 @@
 | |
|  #define MTK_PHY_DA_TX_R50_PAIR_C		0x53f
 | |
|  #define MTK_PHY_DA_TX_R50_PAIR_D		0x540
 | |
|  
 | |
| +/* Registers on MDIO_MMD_VEND2 */
 | |
| +#define MTK_PHY_LED0_ON_CTRL			0x24
 | |
| +#define MTK_PHY_LED1_ON_CTRL			0x26
 | |
| +#define   MTK_PHY_LED_ON_MASK			GENMASK(6, 0)
 | |
| +#define   MTK_PHY_LED_ON_LINK1000		BIT(0)
 | |
| +#define   MTK_PHY_LED_ON_LINK100		BIT(1)
 | |
| +#define   MTK_PHY_LED_ON_LINK10			BIT(2)
 | |
| +#define   MTK_PHY_LED_ON_LINKDOWN		BIT(3)
 | |
| +#define   MTK_PHY_LED_ON_FDX			BIT(4) /* Full duplex */
 | |
| +#define   MTK_PHY_LED_ON_HDX			BIT(5) /* Half duplex */
 | |
| +#define   MTK_PHY_LED_FORCE_ON			BIT(6)
 | |
| +#define   MTK_PHY_LED_POLARITY			BIT(14)
 | |
| +#define   MTK_PHY_LED_ENABLE			BIT(15)
 | |
| +
 | |
| +#define MTK_PHY_LED0_BLINK_CTRL			0x25
 | |
| +#define MTK_PHY_LED1_BLINK_CTRL			0x27
 | |
| +#define   MTK_PHY_LED_1000TX			BIT(0)
 | |
| +#define   MTK_PHY_LED_1000RX			BIT(1)
 | |
| +#define   MTK_PHY_LED_100TX			BIT(2)
 | |
| +#define   MTK_PHY_LED_100RX			BIT(3)
 | |
| +#define   MTK_PHY_LED_10TX			BIT(4)
 | |
| +#define   MTK_PHY_LED_10RX			BIT(5)
 | |
| +#define   MTK_PHY_LED_COLLISION			BIT(6)
 | |
| +#define   MTK_PHY_LED_RX_CRC_ERR		BIT(7)
 | |
| +#define   MTK_PHY_LED_RX_IDLE_ERR		BIT(8)
 | |
| +#define   MTK_PHY_LED_FORCE_BLINK		BIT(9)
 | |
| +
 | |
|  #define MTK_PHY_RG_BG_RASEL			0x115
 | |
|  #define   MTK_PHY_RG_BG_RASEL_MASK		GENMASK(2, 0)
 | |
|  
 | |
| +/* Register in boottrap syscon defining the initial state of the 4 PHY LEDs */
 | |
| +#define RG_GPIO_MISC_TPBANK0			0x6f0
 | |
| +#define   RG_GPIO_MISC_TPBANK0_BOOTMODE		GENMASK(11, 8)
 | |
| +
 | |
|  /* These macro privides efuse parsing for internal phy. */
 | |
|  #define EFS_DA_TX_I2MPB_A(x)			(((x) >> 0) & GENMASK(5, 0))
 | |
|  #define EFS_DA_TX_I2MPB_B(x)			(((x) >> 6) & GENMASK(5, 0))
 | |
| @@ -238,13 +271,6 @@ enum {
 | |
|  	PAIR_D,
 | |
|  };
 | |
|  
 | |
| -enum {
 | |
| -	GPHY_PORT0,
 | |
| -	GPHY_PORT1,
 | |
| -	GPHY_PORT2,
 | |
| -	GPHY_PORT3,
 | |
| -};
 | |
| -
 | |
|  enum calibration_mode {
 | |
|  	EFUSE_K,
 | |
|  	SW_K
 | |
| @@ -263,6 +289,10 @@ enum CAL_MODE {
 | |
|  	SW_M
 | |
|  };
 | |
|  
 | |
| +struct mtk_socphy_shared {
 | |
| +	u32			boottrap;
 | |
| +};
 | |
| +
 | |
|  static int mtk_socphy_read_page(struct phy_device *phydev)
 | |
|  {
 | |
|  	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
 | |
| @@ -1073,6 +1103,104 @@ static int mt798x_phy_config_init(struct
 | |
|  	return mt798x_phy_calibration(phydev);
 | |
|  }
 | |
|  
 | |
| +static int mt798x_phy_setup_led(struct phy_device *phydev, bool inverted)
 | |
| +{
 | |
| +	struct pinctrl *pinctrl;
 | |
| +	const u16 led_on_ctrl_defaults = MTK_PHY_LED_ENABLE      |
 | |
| +					 MTK_PHY_LED_ON_LINK1000 |
 | |
| +					 MTK_PHY_LED_ON_LINK100  |
 | |
| +					 MTK_PHY_LED_ON_LINK10;
 | |
| +	const u16 led_blink_defaults = MTK_PHY_LED_1000TX |
 | |
| +				       MTK_PHY_LED_1000RX |
 | |
| +				       MTK_PHY_LED_100TX  |
 | |
| +				       MTK_PHY_LED_100RX  |
 | |
| +				       MTK_PHY_LED_10TX   |
 | |
| +				       MTK_PHY_LED_10RX;
 | |
| +
 | |
| +	phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
 | |
| +		      led_on_ctrl_defaults ^
 | |
| +		      (inverted ? MTK_PHY_LED_POLARITY : 0));
 | |
| +
 | |
| +	phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
 | |
| +		      led_on_ctrl_defaults);
 | |
| +
 | |
| +	phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_BLINK_CTRL,
 | |
| +		      led_blink_defaults);
 | |
| +
 | |
| +	phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_BLINK_CTRL,
 | |
| +		      led_blink_defaults);
 | |
| +
 | |
| +	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
 | |
| +	if (IS_ERR(pinctrl))
 | |
| +		dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED\n");
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int mt7988_phy_probe_shared(struct phy_device *phydev)
 | |
| +{
 | |
| +	struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
 | |
| +	struct mtk_socphy_shared *priv = phydev->shared->priv;
 | |
| +	struct regmap *regmap;
 | |
| +	u32 reg;
 | |
| +	int ret;
 | |
| +
 | |
| +	/* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
 | |
| +	 * LED_C and LED_D respectively. At the same time those pins are used to
 | |
| +	 * bootstrap configuration of the reference clock source (LED_A),
 | |
| +	 * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
 | |
| +	 * In practise this is done using a LED and a resistor pulling the pin
 | |
| +	 * either to GND or to VIO.
 | |
| +	 * The detected value at boot time is accessible at run-time using the
 | |
| +	 * TPBANK0 register located in the gpio base of the pinctrl, in order
 | |
| +	 * to read it here it needs to be referenced by a phandle called
 | |
| +	 * 'mediatek,pio' in the MDIO bus hosting the PHY.
 | |
| +	 * The 4 bits in TPBANK0 are kept as package shared data and are used to
 | |
| +	 * set LED polarity for each of the LED0.
 | |
| +	 */
 | |
| +	regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
 | |
| +	if (IS_ERR(regmap))
 | |
| +		return PTR_ERR(regmap);
 | |
| +
 | |
| +	ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	priv->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static bool mt7988_phy_get_boottrap_polarity(struct phy_device *phydev)
 | |
| +{
 | |
| +	struct mtk_socphy_shared *priv = phydev->shared->priv;
 | |
| +
 | |
| +	if (priv->boottrap & BIT(phydev->mdio.addr))
 | |
| +		return false;
 | |
| +
 | |
| +	return true;
 | |
| +}
 | |
| +
 | |
| +static int mt7988_phy_probe(struct phy_device *phydev)
 | |
| +{
 | |
| +	int err;
 | |
| +
 | |
| +	err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
 | |
| +				    sizeof(struct mtk_socphy_shared));
 | |
| +	if (err)
 | |
| +		return err;
 | |
| +
 | |
| +	if (phy_package_probe_once(phydev)) {
 | |
| +		err = mt7988_phy_probe_shared(phydev);
 | |
| +		if (err)
 | |
| +			return err;
 | |
| +	}
 | |
| +
 | |
| +	mt798x_phy_setup_led(phydev, mt7988_phy_get_boottrap_polarity(phydev));
 | |
| +
 | |
| +	return mt798x_phy_calibration(phydev);
 | |
| +}
 | |
| +
 | |
|  static struct phy_driver mtk_socphy_driver[] = {
 | |
|  	{
 | |
|  		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
 | |
| @@ -1092,7 +1220,7 @@ static struct phy_driver mtk_socphy_driv
 | |
|  		.config_init	= mt798x_phy_config_init,
 | |
|  		.config_intr	= genphy_no_config_intr,
 | |
|  		.handle_interrupt = genphy_handle_interrupt_no_ack,
 | |
| -		.probe		= mt798x_phy_calibration,
 | |
| +		.probe		= mt7988_phy_probe,
 | |
|  		.suspend	= genphy_suspend,
 | |
|  		.resume		= genphy_resume,
 | |
|  		.read_page	= mtk_socphy_read_page,
 |