Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-dsa-microchip-implement-phy-loopback'

Oleksij Rempel says:

====================
net: dsa: microchip: implement PHY loopback
====================

Link: https://lore.kernel.org/r/20240124123314.734815-1-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+275 -136
+274 -136
drivers/net/dsa/microchip/ksz8795.c
··· 633 633 } 634 634 635 635 /** 636 + * ksz879x_get_loopback - KSZ879x specific function to get loopback 637 + * configuration status for a specific port 638 + * @dev: Pointer to the device structure 639 + * @port: Port number to query 640 + * @val: Pointer to store the result 641 + * 642 + * This function reads the SMI registers to determine whether loopback mode 643 + * is enabled for a specific port. 644 + * 645 + * Return: 0 on success, error code on failure. 646 + */ 647 + static int ksz879x_get_loopback(struct ksz_device *dev, u16 port, 648 + u16 *val) 649 + { 650 + u8 stat3; 651 + int ret; 652 + 653 + ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3); 654 + if (ret) 655 + return ret; 656 + 657 + if (stat3 & PORT_PHY_LOOPBACK) 658 + *val |= BMCR_LOOPBACK; 659 + 660 + return 0; 661 + } 662 + 663 + /** 664 + * ksz879x_set_loopback - KSZ879x specific function to set loopback mode for 665 + * a specific port 666 + * @dev: Pointer to the device structure. 667 + * @port: Port number to modify. 668 + * @val: Value indicating whether to enable or disable loopback mode. 669 + * 670 + * This function translates loopback bit of the BMCR register into the 671 + * corresponding hardware register bit value and writes it to the SMI interface. 672 + * 673 + * Return: 0 on success, error code on failure. 674 + */ 675 + static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val) 676 + { 677 + u8 stat3 = 0; 678 + 679 + if (val & BMCR_LOOPBACK) 680 + stat3 |= PORT_PHY_LOOPBACK; 681 + 682 + return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK, 683 + stat3); 684 + } 685 + 686 + /** 636 687 * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY 637 688 * Control register (Reg. 31). 638 689 * @dev: The KSZ device instance. ··· 727 676 return 0; 728 677 } 729 678 679 + /** 680 + * ksz8_r_phy_bmcr - Translates and reads from the SMI interface to a MIIM PHY 681 + * Basic mode control register (Reg. 0). 682 + * @dev: The KSZ device instance. 683 + * @port: The port number to be read. 684 + * @val: The value read from the SMI interface. 685 + * 686 + * This function reads the SMI interface and translates the hardware register 687 + * bit values into their corresponding control settings for a MIIM PHY Basic 688 + * mode control register. 689 + * 690 + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 691 + * ------------------------------------------------------------------- 692 + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit 693 + * ----------------------------+-----------------------------+---------------- 694 + * Bit 15 - Soft Reset | 0xF/4 | Not supported 695 + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) 696 + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 697 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 698 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 699 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported 700 + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 701 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 702 + * Bit 7 - Collision Test/Res. | Not supported | Not supported 703 + * Bit 6 - Reserved | Not supported | Not supported 704 + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 705 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 706 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 707 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 708 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 709 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 710 + * ------------------------------------------------------------------- 711 + * 712 + * Return: 0 on success, error code on failure. 713 + */ 714 + static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val) 715 + { 716 + const u16 *regs = dev->info->regs; 717 + u8 restart, speed, ctrl; 718 + int ret; 719 + 720 + *val = 0; 721 + 722 + ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); 723 + if (ret) 724 + return ret; 725 + 726 + ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); 727 + if (ret) 728 + return ret; 729 + 730 + ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); 731 + if (ret) 732 + return ret; 733 + 734 + if (ctrl & PORT_FORCE_100_MBIT) 735 + *val |= BMCR_SPEED100; 736 + 737 + if (ksz_is_ksz88x3(dev)) { 738 + if (restart & KSZ8873_PORT_PHY_LOOPBACK) 739 + *val |= BMCR_LOOPBACK; 740 + 741 + if ((ctrl & PORT_AUTO_NEG_ENABLE)) 742 + *val |= BMCR_ANENABLE; 743 + } else { 744 + ret = ksz879x_get_loopback(dev, port, val); 745 + if (ret) 746 + return ret; 747 + 748 + if (!(ctrl & PORT_AUTO_NEG_DISABLE)) 749 + *val |= BMCR_ANENABLE; 750 + } 751 + 752 + if (restart & PORT_POWER_DOWN) 753 + *val |= BMCR_PDOWN; 754 + 755 + if (restart & PORT_AUTO_NEG_RESTART) 756 + *val |= BMCR_ANRESTART; 757 + 758 + if (ctrl & PORT_FORCE_FULL_DUPLEX) 759 + *val |= BMCR_FULLDPLX; 760 + 761 + if (speed & PORT_HP_MDIX) 762 + *val |= KSZ886X_BMCR_HP_MDIX; 763 + 764 + if (restart & PORT_FORCE_MDIX) 765 + *val |= KSZ886X_BMCR_FORCE_MDI; 766 + 767 + if (restart & PORT_AUTO_MDIX_DISABLE) 768 + *val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; 769 + 770 + if (restart & PORT_TX_DISABLE) 771 + *val |= KSZ886X_BMCR_DISABLE_TRANSMIT; 772 + 773 + if (restart & PORT_LED_OFF) 774 + *val |= KSZ886X_BMCR_DISABLE_LED; 775 + 776 + return 0; 777 + } 778 + 730 779 int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) 731 780 { 732 - u8 restart, speed, ctrl, link; 781 + u8 ctrl, link, val1, val2; 733 782 int processed = true; 734 783 const u16 *regs; 735 - u8 val1, val2; 736 784 u16 data = 0; 737 - u8 p = phy; 785 + u16 p = phy; 738 786 int ret; 739 787 740 788 regs = dev->info->regs; 741 789 742 790 switch (reg) { 743 791 case MII_BMCR: 744 - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); 792 + ret = ksz8_r_phy_bmcr(dev, p, &data); 745 793 if (ret) 746 794 return ret; 747 - 748 - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); 749 - if (ret) 750 - return ret; 751 - 752 - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); 753 - if (ret) 754 - return ret; 755 - 756 - if (restart & PORT_PHY_LOOPBACK) 757 - data |= BMCR_LOOPBACK; 758 - if (ctrl & PORT_FORCE_100_MBIT) 759 - data |= BMCR_SPEED100; 760 - if (ksz_is_ksz88x3(dev)) { 761 - if ((ctrl & PORT_AUTO_NEG_ENABLE)) 762 - data |= BMCR_ANENABLE; 763 - } else { 764 - if (!(ctrl & PORT_AUTO_NEG_DISABLE)) 765 - data |= BMCR_ANENABLE; 766 - } 767 - if (restart & PORT_POWER_DOWN) 768 - data |= BMCR_PDOWN; 769 - if (restart & PORT_AUTO_NEG_RESTART) 770 - data |= BMCR_ANRESTART; 771 - if (ctrl & PORT_FORCE_FULL_DUPLEX) 772 - data |= BMCR_FULLDPLX; 773 - if (speed & PORT_HP_MDIX) 774 - data |= KSZ886X_BMCR_HP_MDIX; 775 - if (restart & PORT_FORCE_MDIX) 776 - data |= KSZ886X_BMCR_FORCE_MDI; 777 - if (restart & PORT_AUTO_MDIX_DISABLE) 778 - data |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; 779 - if (restart & PORT_TX_DISABLE) 780 - data |= KSZ886X_BMCR_DISABLE_TRANSMIT; 781 - if (restart & PORT_LED_OFF) 782 - data |= KSZ886X_BMCR_DISABLE_LED; 783 795 break; 784 796 case MII_BMSR: 785 797 ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); ··· 974 860 return ret; 975 861 } 976 862 863 + /** 864 + * ksz8_w_phy_bmcr - Translates and writes to the SMI interface from a MIIM PHY 865 + * Basic mode control register (Reg. 0). 866 + * @dev: The KSZ device instance. 867 + * @port: The port number to be configured. 868 + * @val: The register value to be written. 869 + * 870 + * This function translates control settings from a MIIM PHY Basic mode control 871 + * register into their corresponding hardware register bit values for the SMI 872 + * interface. 873 + * 874 + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 875 + * ------------------------------------------------------------------- 876 + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit 877 + * ----------------------------+-----------------------------+---------------- 878 + * Bit 15 - Soft Reset | 0xF/4 | Not supported 879 + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) 880 + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 881 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 882 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 883 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported 884 + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 885 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 886 + * Bit 7 - Collision Test/Res. | Not supported | Not supported 887 + * Bit 6 - Reserved | Not supported | Not supported 888 + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 889 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 890 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 891 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 892 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 893 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 894 + * ------------------------------------------------------------------- 895 + * 896 + * Return: 0 on success, error code on failure. 897 + */ 898 + static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) 899 + { 900 + u8 restart, speed, ctrl, restart_mask; 901 + const u16 *regs = dev->info->regs; 902 + int ret; 903 + 904 + /* Do not support PHY reset function. */ 905 + if (val & BMCR_RESET) 906 + return 0; 907 + 908 + speed = 0; 909 + if (val & KSZ886X_BMCR_HP_MDIX) 910 + speed |= PORT_HP_MDIX; 911 + 912 + ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed); 913 + if (ret) 914 + return ret; 915 + 916 + ctrl = 0; 917 + if (ksz_is_ksz88x3(dev)) { 918 + if ((val & BMCR_ANENABLE)) 919 + ctrl |= PORT_AUTO_NEG_ENABLE; 920 + } else { 921 + if (!(val & BMCR_ANENABLE)) 922 + ctrl |= PORT_AUTO_NEG_DISABLE; 923 + 924 + /* Fiber port does not support auto-negotiation. */ 925 + if (dev->ports[port].fiber) 926 + ctrl |= PORT_AUTO_NEG_DISABLE; 927 + } 928 + 929 + if (val & BMCR_SPEED100) 930 + ctrl |= PORT_FORCE_100_MBIT; 931 + 932 + if (val & BMCR_FULLDPLX) 933 + ctrl |= PORT_FORCE_FULL_DUPLEX; 934 + 935 + ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT | 936 + /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same 937 + * bits 938 + */ 939 + PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl); 940 + if (ret) 941 + return ret; 942 + 943 + restart = 0; 944 + restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART | 945 + PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX; 946 + 947 + if (val & KSZ886X_BMCR_DISABLE_LED) 948 + restart |= PORT_LED_OFF; 949 + 950 + if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) 951 + restart |= PORT_TX_DISABLE; 952 + 953 + if (val & BMCR_ANRESTART) 954 + restart |= PORT_AUTO_NEG_RESTART; 955 + 956 + if (val & BMCR_PDOWN) 957 + restart |= PORT_POWER_DOWN; 958 + 959 + if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) 960 + restart |= PORT_AUTO_MDIX_DISABLE; 961 + 962 + if (val & KSZ886X_BMCR_FORCE_MDI) 963 + restart |= PORT_FORCE_MDIX; 964 + 965 + if (ksz_is_ksz88x3(dev)) { 966 + restart_mask |= KSZ8873_PORT_PHY_LOOPBACK; 967 + 968 + if (val & BMCR_LOOPBACK) 969 + restart |= KSZ8873_PORT_PHY_LOOPBACK; 970 + } else { 971 + ret = ksz879x_set_loopback(dev, port, val); 972 + if (ret) 973 + return ret; 974 + } 975 + 976 + return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask, 977 + restart); 978 + } 979 + 977 980 int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) 978 981 { 979 - u8 restart, speed, ctrl, data; 980 982 const u16 *regs; 981 - u8 p = phy; 983 + u8 ctrl, data; 984 + u16 p = phy; 982 985 int ret; 983 986 984 987 regs = dev->info->regs; 985 988 986 989 switch (reg) { 987 990 case MII_BMCR: 988 - 989 - /* Do not support PHY reset function. */ 990 - if (val & BMCR_RESET) 991 - break; 992 - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); 991 + ret = ksz8_w_phy_bmcr(dev, p, val); 993 992 if (ret) 994 993 return ret; 995 - 996 - data = speed; 997 - if (val & KSZ886X_BMCR_HP_MDIX) 998 - data |= PORT_HP_MDIX; 999 - else 1000 - data &= ~PORT_HP_MDIX; 1001 - 1002 - if (data != speed) { 1003 - ret = ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); 1004 - if (ret) 1005 - return ret; 1006 - } 1007 - 1008 - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); 1009 - if (ret) 1010 - return ret; 1011 - 1012 - data = ctrl; 1013 - if (ksz_is_ksz88x3(dev)) { 1014 - if ((val & BMCR_ANENABLE)) 1015 - data |= PORT_AUTO_NEG_ENABLE; 1016 - else 1017 - data &= ~PORT_AUTO_NEG_ENABLE; 1018 - } else { 1019 - if (!(val & BMCR_ANENABLE)) 1020 - data |= PORT_AUTO_NEG_DISABLE; 1021 - else 1022 - data &= ~PORT_AUTO_NEG_DISABLE; 1023 - 1024 - /* Fiber port does not support auto-negotiation. */ 1025 - if (dev->ports[p].fiber) 1026 - data |= PORT_AUTO_NEG_DISABLE; 1027 - } 1028 - 1029 - if (val & BMCR_SPEED100) 1030 - data |= PORT_FORCE_100_MBIT; 1031 - else 1032 - data &= ~PORT_FORCE_100_MBIT; 1033 - if (val & BMCR_FULLDPLX) 1034 - data |= PORT_FORCE_FULL_DUPLEX; 1035 - else 1036 - data &= ~PORT_FORCE_FULL_DUPLEX; 1037 - 1038 - if (data != ctrl) { 1039 - ret = ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); 1040 - if (ret) 1041 - return ret; 1042 - } 1043 - 1044 - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); 1045 - if (ret) 1046 - return ret; 1047 - 1048 - data = restart; 1049 - if (val & KSZ886X_BMCR_DISABLE_LED) 1050 - data |= PORT_LED_OFF; 1051 - else 1052 - data &= ~PORT_LED_OFF; 1053 - if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) 1054 - data |= PORT_TX_DISABLE; 1055 - else 1056 - data &= ~PORT_TX_DISABLE; 1057 - if (val & BMCR_ANRESTART) 1058 - data |= PORT_AUTO_NEG_RESTART; 1059 - else 1060 - data &= ~(PORT_AUTO_NEG_RESTART); 1061 - if (val & BMCR_PDOWN) 1062 - data |= PORT_POWER_DOWN; 1063 - else 1064 - data &= ~PORT_POWER_DOWN; 1065 - if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) 1066 - data |= PORT_AUTO_MDIX_DISABLE; 1067 - else 1068 - data &= ~PORT_AUTO_MDIX_DISABLE; 1069 - if (val & KSZ886X_BMCR_FORCE_MDI) 1070 - data |= PORT_FORCE_MDIX; 1071 - else 1072 - data &= ~PORT_FORCE_MDIX; 1073 - if (val & BMCR_LOOPBACK) 1074 - data |= PORT_PHY_LOOPBACK; 1075 - else 1076 - data &= ~PORT_PHY_LOOPBACK; 1077 - 1078 - if (data != restart) { 1079 - ret = ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], 1080 - data); 1081 - if (ret) 1082 - return ret; 1083 - } 1084 994 break; 1085 995 case MII_ADVERTISE: 1086 996 ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
+1
drivers/net/dsa/microchip/ksz8795_reg.h
··· 265 265 #define PORT_AUTO_MDIX_DISABLE BIT(2) 266 266 #define PORT_FORCE_MDIX BIT(1) 267 267 #define PORT_MAC_LOOPBACK BIT(0) 268 + #define KSZ8873_PORT_PHY_LOOPBACK BIT(0) 268 269 269 270 #define REG_PORT_1_STATUS_2 0x1E 270 271 #define REG_PORT_2_STATUS_2 0x2E