[U-Boot, v2, 1/1]net: phy: add paged PHY register accessors

Lucien.Jheng lucienzx159 at gmail.com
Sun Nov 2 13:45:27 CET 2025


Hi

This is a gentle reminder for review of this patch.

Please let me know if there's any issue with the patch

Thank you

Lucien.Jheng 於 2025/10/6 下午 08:49 寫道:
> Synchronize paged PHY helpers with Linux v6.17.
>
> Add support for PHY devices that use paged register access by
> implementing the following functions:
> - phy_save_page(): Save current page number
> - phy_select_page(): Switch to a specific page and return previous page
> - phy_restore_page(): Restore previously saved page
>
> Also adds read_page and write_page callbacks to the phy_driver
> structure to enable driver-specific page handling.
>
> These helpers allow safe access to paged PHY registers by ensuring
> proper page selection and restoration,
> even in error conditions, which will be used by the Airoha PHY driver.
>
> Signed-off-by: Lucien.Jheng <lucienzx159 at gmail.com>
> ---
> Change in PATCH v2:
>   * Change the commit message from "Synchronize paged PHY helpers
>     with Linux v4.16" to "Linux v6.17."
>   * Remove unnecessary commit information.
>
> I have verified the patch by loading Airoha PHY firmware on Banana Pi BPI-R3 Mini.
> Since we need to switch pages to access en8811h PHY registers, this patch is necessary
> for initializing the PHY and loading the firmware correctly.
>
> 1. Implementation in air_en8811.c:
> ````air_en8811.c````
> /*
>   * Driver for Airoha EN8811H Ethernet PHY
>   */
> #define AIR_EXT_PAGE_ACCESS		0x1f
> ...
> ...
> static int en8811h_read_page(struct phy_device *phydev)
> {
> 	return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS);
> }
>
> static int en8811h_write_page(struct phy_device *phydev, int page)
> {
> 	return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page);
> }
>
> U_BOOT_PHY_DRIVER(en8811h) = {
> 	.name = "Airoha EN8811H",
> 	.uid = EN8811H_PHY_ID,
> 	.mask = 0x0ffffff0,
> 	.config = &en8811h_config,
> 	.probe = &en8811h_probe,
> 	.read_page = &en8811h_read_page,
> 	.write_page = &en8811h_write_page,
> 	.startup = &en8811h_startup,
> 	.shutdown = &genphy_shutdown,
> };
> ```````End of air_en8811.c`````
> 2. Test log:
> ````Test Log````
> Net:   16384 bytes read in 1 ms (15.6 MiB/s)
> 131072 bytes read in 9 ms (13.9 MiB/s)
> addr: 0x46000000, size: 0x24000
> Found Airoha Firmware.
> MD32 firmware version: 24112802
> ````End of Test Log````
>
>   drivers/net/phy/phy.c | 113 ++++++++++++++++++++++++++++++++++++++++++
>   include/phy.h         |   8 +++
>   2 files changed, 121 insertions(+)
>
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index 9702d042296..b58283fe3d5 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -1250,3 +1250,116 @@ bool phy_interface_is_ncsi(void)
>   	return 0;
>   #endif
>   }
> +
> +/**
> + * __phy_read_page() - read the current page
> + * @phydev: a pointer to a &struct phy_device
> + *
> + * Returns page index or < 0 on error
> + */
> +static int __phy_read_page(struct phy_device *phydev)
> +{
> +	struct phy_driver *drv = phydev->drv;
> +
> +	if (!drv->read_page) {
> +		debug("read_page callback not available, PHY driver not loaded?\n");
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return drv->read_page(phydev);
> +}
> +
> +/**
> + * __phy_write_page() - Write a new page
> + * @phydev: a pointer to a &struct phy_device
> + * @page: page index to select
> + *
> + * Returns 0 or < 0 on error.
> + */
> +static int __phy_write_page(struct phy_device *phydev, int page)
> +{
> +	struct phy_driver *drv = phydev->drv;
> +
> +	if (!drv->write_page) {
> +		debug("write_page callback not available, PHY driver not loaded?\n");
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return drv->write_page(phydev, page);
> +}
> +
> +/**
> + * phy_save_page() - save the current page
> + * @phydev: a pointer to a &struct phy_device
> + *
> + * Return the current page number. On error,
> + * returns a negative errno. phy_restore_page() must always be called
> + * after this, irrespective of success or failure of this call.
> + */
> +int phy_save_page(struct phy_device *phydev)
> +{
> +	return __phy_read_page(phydev);
> +}
> +
> +/**
> + * phy_select_page - Switch to a PHY page and return the previous page
> + * @phydev: a pointer to a &struct phy_device
> + * @page: desired page
> + *
> + * NOTE: Save the current PHY page, and set the current page.
> + * On error, returns a negative errno, otherwise returns the previous page number.
> + * phy_restore_page() must always be called after this, irrespective
> + * of success or failure of this call.
> + */
> +int phy_select_page(struct phy_device *phydev, int page)
> +{
> +	int ret, oldpage;
> +
> +	oldpage = ret = phy_save_page(phydev);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (oldpage != page) {
> +		ret = __phy_write_page(phydev, page);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return oldpage;
> +}
> +
> +/**
> + * phy_restore_page - Restore a previously saved page and propagate status
> + * @phydev: a pointer to a &struct phy_device
> + * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
> + * @ret: operation's return code
> + *
> + * Restoring @oldpage if it is a valid page.
> + * This function propagates the earliest error code from the group of
> + * operations.
> + *
> + * Returns:
> + *   @oldpage if it was a negative value, otherwise
> + *   @ret if it was a negative errno value, otherwise
> + *   phy_write_page()'s negative value if it were in error, otherwise
> + *   @ret.
> + */
> +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
> +{
> +	int r;
> +
> +	if (oldpage >= 0) {
> +		r = __phy_write_page(phydev, oldpage);
> +
> +		/* Propagate the operation return code if the page write
> +		 * was successful.
> +		 */
> +		if (ret >= 0 && r < 0)
> +			ret = r;
> +	} else {
> +		/* Propagate the phy page selection error code */
> +		ret = oldpage;
> +	}
> +
> +	return ret;
> +}
> \ No newline at end of file
> diff --git a/include/phy.h b/include/phy.h
> index 36354aaf774..ae9fd1652cc 100644
> --- a/include/phy.h
> +++ b/include/phy.h
> @@ -123,6 +123,11 @@ struct phy_driver {
>   	int (*write_mmd)(struct phy_device *phydev, int devad, int reg,
>   			 u16 val);
>
> +	/** @read_page: Return the current PHY register page number */
> +	int (*read_page)(struct phy_device *phydev);
> +	/** @write_page: Set the current PHY register page number */
> +	int (*write_page)(struct phy_device *phydev, int page);
> +
>   	/* driver private data */
>   	ulong data;
>   };
> @@ -314,6 +319,9 @@ int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
>   			   u16 mask, u16 set);
>   int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
>   		   u16 mask, u16 set);
> +int phy_save_page(struct phy_device *phydev);
> +int phy_select_page(struct phy_device *phydev, int page);
> +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret);
>
>   int phy_startup(struct phy_device *phydev);
>   int phy_config(struct phy_device *phydev);
> --
> 2.34.1
>


More information about the U-Boot mailing list