diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 094c5aa..9077a82 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -59,6 +59,23 @@ ping-add = <3>; }; + phy_provider0: gen_phy@0 { + compatible = "sandbox,phy"; + #phy-cells = <1>; + }; + + phy_provider1: gen_phy@1 { + compatible = "sandbox,phy"; + #phy-cells = <0>; + broken; + }; + + gen_phy_user: gen_phy_user { + compatible = "simple-bus"; + phys = <&phy_provider0 0>, <&phy_provider0 1>, <&phy_provider1>; + phy-names = "phy1", "phy2", "phy3"; + }; + some-bus { #address-cells = <1>; #size-cells = <0>; diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 64bb923..95630fc 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -172,6 +172,8 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y CONFIG_VIDEO_SANDBOX_SDL=y CONFIG_FS_CBFS=y CONFIG_FS_CRAMFS=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig index fb98ab8..26183af 100644 --- a/configs/sandbox_noblk_defconfig +++ b/configs/sandbox_noblk_defconfig @@ -174,6 +174,8 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y CONFIG_VIDEO_SANDBOX_SDL=y CONFIG_FS_CBFS=y CONFIG_FS_CRAMFS=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 9b7b1fe..9324353 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -178,6 +178,8 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y CONFIG_VIDEO_SANDBOX_SDL=y CONFIG_FS_CBFS=y CONFIG_FS_CRAMFS=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 0a74920..75f459d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -33,4 +33,12 @@ config SPL_PHY compatible as possible with the equivalent framework found in the linux kernel. +config PHY_SANDBOX + bool "Sandbox PHY support" + depends on SANDBOX + depends on PHY + help + This select a dummy sandbox PHY driver. It used only to implement + the unit tests for the phy framework + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 45f786a..fd037c3 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -6,3 +6,4 @@ # obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o +obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o diff --git a/drivers/phy/sandbox-phy.c b/drivers/phy/sandbox-phy.c new file mode 100644 index 0000000..9ad820c --- /dev/null +++ b/drivers/phy/sandbox-phy.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * Written by Jean-Jacques Hiblot + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct sandbox_phy_priv { + bool initialized; + bool on; + bool broken; +}; + +static int sandbox_phy_power_on(struct phy *phy) +{ + struct sandbox_phy_priv *priv = dev_get_priv(phy->dev); + + if (!priv->initialized) + return -EIO; + + if (priv->broken) + return -EIO; + + priv->on = true; + + return 0; +} + +static int sandbox_phy_power_off(struct phy *phy) +{ + struct sandbox_phy_priv *priv = dev_get_priv(phy->dev); + + if (!priv->initialized) + return -EIO; + + if (priv->broken) + return -EIO; + + /* + * for validation purpose, let's says that power off + * works only for PHY 0 + */ + if (phy->id) + return -EIO; + + priv->on = false; + + return 0; +} + +static int sandbox_phy_init(struct phy *phy) +{ + struct sandbox_phy_priv *priv = dev_get_priv(phy->dev); + + priv->initialized = true; + priv->on = true; + + return 0; +} + +static int sandbox_phy_exit(struct phy *phy) +{ + struct sandbox_phy_priv *priv = dev_get_priv(phy->dev); + + priv->initialized = false; + priv->on = false; + + return 0; +} + +static int sandbox_phy_probe(struct udevice *dev) +{ + struct sandbox_phy_priv *priv = dev_get_priv(dev); + + priv->initialized = false; + priv->on = false; + priv->broken = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), + "broken"); + + return 0; +} + +static struct phy_ops sandbox_phy_ops = { + .power_on = sandbox_phy_power_on, + .power_off = sandbox_phy_power_off, + .init = sandbox_phy_init, + .exit = sandbox_phy_exit, +}; + +static const struct udevice_id sandbox_phy_ids[] = { + { .compatible = "sandbox,phy" }, + { } +}; + +U_BOOT_DRIVER(phy_sandbox) = { + .name = "phy_sandbox", + .id = UCLASS_PHY, + .of_match = sandbox_phy_ids, + .ops = &sandbox_phy_ops, + .probe = sandbox_phy_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_phy_priv), +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index b15f1d0..513c456 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o obj-$(CONFIG_DM_PCI) += pci.o +obj-$(CONFIG_PHY) += phy.o obj-$(CONFIG_POWER_DOMAIN) += power-domain.o obj-$(CONFIG_DM_PWM) += pwm.o obj-$(CONFIG_RAM) += ram.o diff --git a/test/dm/phy.c b/test/dm/phy.c new file mode 100644 index 0000000..811045f --- /dev/null +++ b/test/dm/phy.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * Written by Jean-Jacques Hiblot + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* Base test of the phy uclass */ +static int dm_test_phy_base(struct unit_test_state *uts) +{ + struct udevice *dev; + struct phy phy1_method1; + struct phy phy1_method2; + struct phy phy2; + struct phy phy3; + struct udevice *parent; + + /* Get the device using the phy device*/ + ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, + "gen_phy_user", &parent)); + /* + * Get the same phy port in 2 different ways and compare. + */ + ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method1)) + ut_assertok(generic_phy_get_by_index(parent, 0, &phy1_method2)) + ut_asserteq(phy1_method1.id, phy1_method2.id); + + /* + * Get the second phy port. Check that the same phy provider (device) + * provides this 2nd phy port, but that the IDs are different + */ + ut_assertok(generic_phy_get_by_name(parent, "phy2", &phy2)) + ut_asserteq_ptr(phy1_method2.dev, phy2.dev); + ut_assert(phy1_method1.id != phy2.id); + + /* + * Get the third phy port. Check that the phy provider is different + */ + ut_assertok(generic_phy_get_by_name(parent, "phy3", &phy3)) + ut_assert(phy2.dev != phy3.dev); + + /* Try to get a non-existing phy */ + ut_asserteq(-ENODEV, uclass_get_device(UCLASS_PHY, 3, &dev)); + ut_assert(generic_phy_get_by_name(parent, "phy_not_existing", + &phy1_method1) < 0) + + return 0; +} +DM_TEST(dm_test_phy_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test of the phy uclass using the sandbox phy driver operations */ +static int dm_test_phy_ops(struct unit_test_state *uts) +{ + struct phy phy1; + struct phy phy2; + struct phy phy3; + struct udevice *parent; + + ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, + "gen_phy_user", &parent)); + + ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1)); + ut_assertok(generic_phy_get_by_name(parent, "phy2", &phy2)); + ut_assertok(generic_phy_get_by_name(parent, "phy3", &phy3)); + + /* test normal operations */ + ut_assertok(generic_phy_init(&phy1)); + ut_assertok(generic_phy_power_on(&phy1)); + ut_assertok(generic_phy_power_off(&phy1)); + + /* + * test operations after exit(). + * The sandbox phy driver does not allow it. + */ + ut_assertok(generic_phy_exit(&phy1)); + ut_assert(generic_phy_power_on(&phy1) != 0); + ut_assert(generic_phy_power_off(&phy1) != 0); + + /* + * test normal operations again (after re-init) + */ + ut_assertok(generic_phy_init(&phy1)); + ut_assertok(generic_phy_power_on(&phy1)); + ut_assertok(generic_phy_power_off(&phy1)); + + /* + * test calling unimplemented feature. + * The call is expected to succeed + */ + ut_assertok(generic_phy_reset(&phy1)); + + /* PHY2 has a known problem with power off */ + ut_assertok(generic_phy_init(&phy2)); + ut_assertok(generic_phy_power_on(&phy2)); + ut_assert(generic_phy_power_off(&phy2) == -EIO); + + /* PHY3 has a known problem with power off and power on*/ + ut_assertok(generic_phy_init(&phy3)); + ut_assert(generic_phy_power_off(&phy3) == -EIO); + ut_assert(generic_phy_power_off(&phy3) == -EIO); + + return 0; +} +DM_TEST(dm_test_phy_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);