From 9ea339d70cfa03d39fecfc3d980c758ed67c4639 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Fri, 16 Aug 2019 16:38:57 +0200 Subject: net: phy: Add support for AC200 EPHY The X-Powers AC200 mixed signal chip contains a 100Mbit/s Ethernet PHY. While its sporting a usable default setup, and can be controlled by the generic IEEE802.3-C22 PHY driver, the BSP sets up some extra registers, which this driver here covers. Add a PHY driver matching the AC200 EPHY ID registers, and which programs some PHY registers according to the BSP code. Signed-off-by: Jernej Skrabec Signed-off-by: Andre Przywara --- drivers/net/phy/Kconfig | 7 ++++ drivers/net/phy/Makefile | 1 + drivers/net/phy/ac200-phy.c | 82 +++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 drivers/net/phy/ac200-phy.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 01b235b3bb7e..be4670e6b266 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -84,6 +84,13 @@ config AIR_EN8811H_PHY help Currently supports the Airoha EN8811H PHY. +config AC200_PHY + tristate "AC200 EPHY" + depends on NVMEM + depends on OF + help + Fast ethernet PHY as found in X-Powers AC200 multi-function device. + config AMD_PHY tristate "AMD and Altima PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 90f886844381..4bba8c64bcc9 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_SFP) += sfp.o sfp-obj-$(CONFIG_SFP) += sfp-bus.o obj-y += $(sfp-obj-y) $(sfp-obj-m) +obj-$(CONFIG_AC200_PHY) += ac200-phy.o obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o diff --git a/drivers/net/phy/ac200-phy.c b/drivers/net/phy/ac200-phy.c new file mode 100644 index 000000000000..8499914f49b8 --- /dev/null +++ b/drivers/net/phy/ac200-phy.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/** + * Driver for AC200 Ethernet PHY + * + * Copyright (c) 2019 Jernej Skrabec + */ + +#include +#include +#include +#include + +#define AC200_EPHY_ID 0x00441400 +#define AC200_EPHY_ID_MASK 0x0ffffff0 + +static int ac200_ephy_config_init(struct phy_device *phydev) +{ + phy_write(phydev, 0x1f, 0x0100); /* Switch to Page 1 */ + phy_write(phydev, 0x12, 0x4824); /* Disable APS */ + + phy_write(phydev, 0x1f, 0x0200); /* Switch to Page 2 */ + phy_write(phydev, 0x18, 0x0000); /* PHYAFE TRX optimization */ + + phy_write(phydev, 0x1f, 0x0600); /* Switch to Page 6 */ + phy_write(phydev, 0x14, 0x708f); /* PHYAFE TX optimization */ + phy_write(phydev, 0x13, 0xF000); /* PHYAFE RX optimization */ + phy_write(phydev, 0x15, 0x1530); + + phy_write(phydev, 0x1f, 0x0800); /* Switch to Page 8 */ + phy_write(phydev, 0x18, 0x00bc); /* PHYAFE TRX optimization */ + + phy_write(phydev, 0x1f, 0x0100); /* switch to page 1 */ + phy_clear_bits(phydev, 0x17, BIT(3)); /* disable intelligent EEE */ + + /* disable 802.3az EEE */ + phy_write(phydev, 0x1f, 0x0200); /* switch to page 2 */ + phy_write(phydev, 0x18, 0x0000); + phy_write(phydev, 0x1f, 0x0000); /* switch to page 0 */ + phy_clear_bits_mmd(phydev, 0x7, 0x3c, BIT(1)); + + /* FIXME: This is probably H6 specific */ + phy_set_bits(phydev, 0x13, BIT(12)); + + return 0; +} + +static int ac200_ephy_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct clk *clk; + + clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "Failed to request clock\n"); + + return 0; +} + +static struct phy_driver ac200_ephy_driver[] = { + { + .phy_id = AC200_EPHY_ID, + .phy_id_mask = AC200_EPHY_ID_MASK, + .name = "Allwinner AC200 EPHY", + .soft_reset = genphy_soft_reset, + .config_init = ac200_ephy_config_init, + .probe = ac200_ephy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + } +}; +module_phy_driver(ac200_ephy_driver); + +MODULE_AUTHOR("Jernej Skrabec "); +MODULE_DESCRIPTION("AC200 Ethernet PHY driver"); +MODULE_LICENSE("GPL"); + +static const struct mdio_device_id __maybe_unused ac200_ephy_phy_tbl[] = { + { AC200_EPHY_ID, AC200_EPHY_ID_MASK }, + { } +}; +MODULE_DEVICE_TABLE(mdio, ac200_ephy_phy_tbl); -- 2.35.3