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

net: lan743x: Add support for PTP-IO Event Output (Periodic Output)

Add support for PTP-IO Event Output (Periodic Output - perout) for
PCI11010/PCI11414 chips

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Raju Lakkaraju and committed by
David S. Miller
e432dd3b 60942c39

+250 -2
+33
drivers/net/ethernet/microchip/lan743x_main.h
··· 336 336 #define INT_MOD_CFG9 (0x7E4) 337 337 338 338 #define PTP_CMD_CTL (0x0A00) 339 + #define PTP_CMD_CTL_PTP_LTC_TARGET_READ_ BIT(13) 339 340 #define PTP_CMD_CTL_PTP_CLK_STP_NSEC_ BIT(6) 340 341 #define PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_ BIT(5) 341 342 #define PTP_CMD_CTL_PTP_CLOCK_LOAD_ BIT(4) ··· 358 357 (((value) & 0x7) << (1 + ((channel) << 2))) 359 358 #define PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel) (BIT((channel) << 2)) 360 359 360 + #define HS_PTP_GENERAL_CONFIG (0x0A04) 361 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(channel) \ 362 + (0xf << (4 + ((channel) << 2))) 363 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_ (0) 364 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_ (1) 365 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_ (2) 366 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_ (3) 367 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_ (4) 368 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_ (5) 369 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_ (6) 370 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_ (7) 371 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_ (8) 372 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_ (9) 373 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_ (10) 374 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_ (11) 375 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_ (12) 376 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ (13) 377 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGG_ (14) 378 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_INT_ (15) 379 + #define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(channel, value) \ 380 + (((value) & 0xf) << (4 + ((channel) << 2))) 381 + #define HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(channel) (BIT(1 + ((channel) * 2))) 382 + #define HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel) (BIT((channel) * 2)) 383 + 361 384 #define PTP_INT_STS (0x0A08) 362 385 #define PTP_INT_IO_FE_MASK_ GENMASK(31, 24) 363 386 #define PTP_INT_IO_FE_SHIFT_ (24) ··· 389 364 #define PTP_INT_IO_RE_MASK_ GENMASK(23, 16) 390 365 #define PTP_INT_IO_RE_SHIFT_ (16) 391 366 #define PTP_INT_IO_RE_SET_(channel) BIT(16 + (channel)) 367 + #define PTP_INT_TX_TS_OVRFL_INT_ BIT(14) 368 + #define PTP_INT_TX_SWTS_ERR_INT_ BIT(13) 369 + #define PTP_INT_TX_TS_INT_ BIT(12) 370 + #define PTP_INT_RX_TS_OVRFL_INT_ BIT(9) 371 + #define PTP_INT_RX_TS_INT_ BIT(8) 372 + #define PTP_INT_TIMER_INT_B_ BIT(1) 373 + #define PTP_INT_TIMER_INT_A_ BIT(0) 392 374 #define PTP_INT_EN_SET (0x0A0C) 393 375 #define PTP_INT_EN_FE_EN_SET_(channel) BIT(24 + (channel)) 394 376 #define PTP_INT_EN_RE_EN_SET_(channel) BIT(16 + (channel)) 377 + #define PTP_INT_EN_TIMER_SET_(channel) BIT(channel) 395 378 #define PTP_INT_EN_CLR (0x0A10) 396 379 #define PTP_INT_EN_FE_EN_CLR_(channel) BIT(24 + (channel)) 397 380 #define PTP_INT_EN_RE_EN_CLR_(channel) BIT(16 + (channel))
+216 -2
drivers/net/ethernet/microchip/lan743x_ptp.c
··· 689 689 return ret; 690 690 } 691 691 692 + static void lan743x_ptp_io_perout_off(struct lan743x_adapter *adapter, 693 + u32 index) 694 + { 695 + struct lan743x_ptp *ptp = &adapter->ptp; 696 + int perout_pin; 697 + int event_ch; 698 + u32 gen_cfg; 699 + int val; 700 + 701 + event_ch = ptp->ptp_io_perout[index]; 702 + if (event_ch >= 0) { 703 + /* set target to far in the future, effectively disabling it */ 704 + lan743x_csr_write(adapter, 705 + PTP_CLOCK_TARGET_SEC_X(event_ch), 706 + 0xFFFF0000); 707 + lan743x_csr_write(adapter, 708 + PTP_CLOCK_TARGET_NS_X(event_ch), 709 + 0); 710 + 711 + gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 712 + gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 713 + (event_ch)); 714 + gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch)); 715 + gen_cfg |= HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch); 716 + lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 717 + if (event_ch) 718 + lan743x_csr_write(adapter, PTP_INT_STS, 719 + PTP_INT_TIMER_INT_B_); 720 + else 721 + lan743x_csr_write(adapter, PTP_INT_STS, 722 + PTP_INT_TIMER_INT_A_); 723 + lan743x_ptp_release_event_ch(adapter, event_ch); 724 + ptp->ptp_io_perout[index] = -1; 725 + } 726 + 727 + perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 728 + 729 + /* Deselect Event output */ 730 + val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 731 + 732 + /* Disables the output of Local Time Target compare events */ 733 + val &= ~PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 734 + lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 735 + 736 + /* Configured as an opendrain driver*/ 737 + val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 738 + val &= ~PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 739 + lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 740 + /* Dummy read to make sure write operation success */ 741 + val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 742 + } 743 + 744 + static int lan743x_ptp_io_perout(struct lan743x_adapter *adapter, int on, 745 + struct ptp_perout_request *perout_request) 746 + { 747 + struct lan743x_ptp *ptp = &adapter->ptp; 748 + u32 period_sec, period_nsec; 749 + u32 start_sec, start_nsec; 750 + u32 pulse_sec, pulse_nsec; 751 + int pulse_width; 752 + int perout_pin; 753 + int event_ch; 754 + u32 gen_cfg; 755 + u32 index; 756 + int val; 757 + 758 + index = perout_request->index; 759 + event_ch = ptp->ptp_io_perout[index]; 760 + 761 + if (on) { 762 + perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 763 + if (perout_pin < 0) 764 + return -EBUSY; 765 + } else { 766 + lan743x_ptp_io_perout_off(adapter, index); 767 + return 0; 768 + } 769 + 770 + if (event_ch >= LAN743X_PTP_N_EVENT_CHAN) { 771 + /* already on, turn off first */ 772 + lan743x_ptp_io_perout_off(adapter, index); 773 + } 774 + 775 + event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 776 + if (event_ch < 0) { 777 + netif_warn(adapter, drv, adapter->netdev, 778 + "Failed to reserve event channel %d for PEROUT\n", 779 + index); 780 + goto failed; 781 + } 782 + ptp->ptp_io_perout[index] = event_ch; 783 + 784 + if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 785 + pulse_sec = perout_request->on.sec; 786 + pulse_sec += perout_request->on.nsec / 1000000000; 787 + pulse_nsec = perout_request->on.nsec % 1000000000; 788 + } else { 789 + pulse_sec = perout_request->period.sec; 790 + pulse_sec += perout_request->period.nsec / 1000000000; 791 + pulse_nsec = perout_request->period.nsec % 1000000000; 792 + } 793 + 794 + if (pulse_sec == 0) { 795 + if (pulse_nsec >= 400000000) { 796 + pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 797 + } else if (pulse_nsec >= 200000000) { 798 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_; 799 + } else if (pulse_nsec >= 100000000) { 800 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_; 801 + } else if (pulse_nsec >= 20000000) { 802 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 803 + } else if (pulse_nsec >= 10000000) { 804 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_; 805 + } else if (pulse_nsec >= 2000000) { 806 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 807 + } else if (pulse_nsec >= 1000000) { 808 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_; 809 + } else if (pulse_nsec >= 200000) { 810 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 811 + } else if (pulse_nsec >= 100000) { 812 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_; 813 + } else if (pulse_nsec >= 20000) { 814 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 815 + } else if (pulse_nsec >= 10000) { 816 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_; 817 + } else if (pulse_nsec >= 2000) { 818 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_; 819 + } else if (pulse_nsec >= 1000) { 820 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_; 821 + } else if (pulse_nsec >= 200) { 822 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 823 + } else { 824 + netif_warn(adapter, drv, adapter->netdev, 825 + "perout period too small, min is 200nS\n"); 826 + goto failed; 827 + } 828 + } else { 829 + pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 830 + } 831 + 832 + /* turn off by setting target far in future */ 833 + lan743x_csr_write(adapter, 834 + PTP_CLOCK_TARGET_SEC_X(event_ch), 835 + 0xFFFF0000); 836 + lan743x_csr_write(adapter, 837 + PTP_CLOCK_TARGET_NS_X(event_ch), 0); 838 + 839 + /* Configure to pulse every period */ 840 + gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 841 + gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(event_ch)); 842 + gen_cfg |= HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 843 + (event_ch, pulse_width); 844 + gen_cfg |= HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch); 845 + gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch)); 846 + lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 847 + 848 + /* set the reload to one toggle cycle */ 849 + period_sec = perout_request->period.sec; 850 + period_sec += perout_request->period.nsec / 1000000000; 851 + period_nsec = perout_request->period.nsec % 1000000000; 852 + lan743x_csr_write(adapter, 853 + PTP_CLOCK_TARGET_RELOAD_SEC_X(event_ch), 854 + period_sec); 855 + lan743x_csr_write(adapter, 856 + PTP_CLOCK_TARGET_RELOAD_NS_X(event_ch), 857 + period_nsec); 858 + 859 + start_sec = perout_request->start.sec; 860 + start_sec += perout_request->start.nsec / 1000000000; 861 + start_nsec = perout_request->start.nsec % 1000000000; 862 + 863 + /* set the start time */ 864 + lan743x_csr_write(adapter, 865 + PTP_CLOCK_TARGET_SEC_X(event_ch), 866 + start_sec); 867 + lan743x_csr_write(adapter, 868 + PTP_CLOCK_TARGET_NS_X(event_ch), 869 + start_nsec); 870 + 871 + /* Enable LTC Target Read */ 872 + val = lan743x_csr_read(adapter, PTP_CMD_CTL); 873 + val |= PTP_CMD_CTL_PTP_LTC_TARGET_READ_; 874 + lan743x_csr_write(adapter, PTP_CMD_CTL, val); 875 + 876 + /* Configure as an push/pull driver */ 877 + val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 878 + val |= PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 879 + lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 880 + 881 + /* Select Event output */ 882 + val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 883 + if (event_ch) 884 + /* Channel B as the output */ 885 + val |= PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 886 + else 887 + /* Channel A as the output */ 888 + val &= ~PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 889 + 890 + /* Enables the output of Local Time Target compare events */ 891 + val |= PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 892 + lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 893 + 894 + return 0; 895 + 896 + failed: 897 + lan743x_ptp_io_perout_off(adapter, index); 898 + return -ENODEV; 899 + } 900 + 692 901 static void lan743x_ptp_io_extts_off(struct lan743x_adapter *adapter, 693 902 u32 index) 694 903 { ··· 1021 812 &request->extts); 1022 813 return -EINVAL; 1023 814 case PTP_CLK_REQ_PEROUT: 1024 - if (request->perout.index < ptpci->n_per_out) 1025 - return lan743x_ptp_perout(adapter, on, 815 + if (request->perout.index < ptpci->n_per_out) { 816 + if (adapter->is_pci11x1x) 817 + return lan743x_ptp_io_perout(adapter, on, 818 + &request->perout); 819 + else 820 + return lan743x_ptp_perout(adapter, on, 1026 821 &request->perout); 822 + } 1027 823 return -EINVAL; 1028 824 case PTP_CLK_REQ_PPS: 1029 825 return -EINVAL;
+1
drivers/net/ethernet/microchip/lan743x_ptp.h
··· 80 80 81 81 unsigned long used_event_ch; 82 82 struct lan743x_ptp_perout perout[LAN743X_PTP_N_PEROUT]; 83 + int ptp_io_perout[LAN743X_PTP_N_PEROUT]; /* PTP event channel (0=channel A, 1=channel B) */ 83 84 struct lan743x_extts extts[LAN743X_PTP_N_EXTTS]; 84 85 85 86 bool leds_multiplexed;