107624df1SBryan Whitehead /* SPDX-License-Identifier: GPL-2.0+ */ 207624df1SBryan Whitehead /* Copyright (C) 2018 Microchip Technology Inc. */ 307624df1SBryan Whitehead 407624df1SBryan Whitehead #include <linux/netdevice.h> 507624df1SBryan Whitehead 69dc502d7SArnd Bergmann #include <linux/ptp_clock_kernel.h> 707624df1SBryan Whitehead #include <linux/module.h> 807624df1SBryan Whitehead #include <linux/pci.h> 907624df1SBryan Whitehead #include <linux/net_tstamp.h> 106f197fb6SRoelof Berg #include "lan743x_main.h" 1107624df1SBryan Whitehead 1207624df1SBryan Whitehead #include "lan743x_ptp.h" 1307624df1SBryan Whitehead 1422820017SJohn Efstathiades #define LAN743X_LED0_ENABLE 20 /* LED0 offset in HW_CFG */ 1522820017SJohn Efstathiades #define LAN743X_LED_ENABLE(pin) BIT(LAN743X_LED0_ENABLE + (pin)) 1622820017SJohn Efstathiades 1707624df1SBryan Whitehead #define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB (31249999) 1807624df1SBryan Whitehead #define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM (2047999934) 1907624df1SBryan Whitehead 2007624df1SBryan Whitehead static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter); 2107624df1SBryan Whitehead static void lan743x_ptp_enable(struct lan743x_adapter *adapter); 2207624df1SBryan Whitehead static void lan743x_ptp_disable(struct lan743x_adapter *adapter); 2307624df1SBryan Whitehead static void lan743x_ptp_reset(struct lan743x_adapter *adapter); 2407624df1SBryan Whitehead static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter, 2507624df1SBryan Whitehead u32 seconds, u32 nano_seconds, 2607624df1SBryan Whitehead u32 sub_nano_seconds); 2707624df1SBryan Whitehead 2860942c39SRaju Lakkaraju static int lan743x_get_channel(u32 ch_map) 2960942c39SRaju Lakkaraju { 3060942c39SRaju Lakkaraju int idx; 3160942c39SRaju Lakkaraju 3260942c39SRaju Lakkaraju for (idx = 0; idx < 32; idx++) { 3360942c39SRaju Lakkaraju if (ch_map & (0x1 << idx)) 3460942c39SRaju Lakkaraju return idx; 3560942c39SRaju Lakkaraju } 3660942c39SRaju Lakkaraju 3760942c39SRaju Lakkaraju return -EINVAL; 3860942c39SRaju Lakkaraju } 3960942c39SRaju Lakkaraju 4007624df1SBryan Whitehead int lan743x_gpio_init(struct lan743x_adapter *adapter) 4107624df1SBryan Whitehead { 4207624df1SBryan Whitehead struct lan743x_gpio *gpio = &adapter->gpio; 4307624df1SBryan Whitehead 4407624df1SBryan Whitehead spin_lock_init(&gpio->gpio_lock); 4507624df1SBryan Whitehead 4607624df1SBryan Whitehead gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */ 4707624df1SBryan Whitehead gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */ 4807624df1SBryan Whitehead gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */ 4907624df1SBryan Whitehead gpio->gpio_cfg3 = 0;/* disable all 1588 output */ 5007624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 5107624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 5207624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2); 5307624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); 5407624df1SBryan Whitehead 5507624df1SBryan Whitehead return 0; 5607624df1SBryan Whitehead } 5707624df1SBryan Whitehead 5807624df1SBryan Whitehead static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter, 5907624df1SBryan Whitehead u32 bit_mask) 6007624df1SBryan Whitehead { 6107624df1SBryan Whitehead int timeout = 1000; 6207624df1SBryan Whitehead u32 data = 0; 6307624df1SBryan Whitehead 6407624df1SBryan Whitehead while (timeout && 6507624df1SBryan Whitehead (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) & 6607624df1SBryan Whitehead bit_mask))) { 6707624df1SBryan Whitehead usleep_range(1000, 20000); 6807624df1SBryan Whitehead timeout--; 6907624df1SBryan Whitehead } 7007624df1SBryan Whitehead if (data) { 7107624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 7207624df1SBryan Whitehead "timeout waiting for cmd to be done, cmd = 0x%08X\n", 7307624df1SBryan Whitehead bit_mask); 7407624df1SBryan Whitehead } 7507624df1SBryan Whitehead } 7607624df1SBryan Whitehead 7707624df1SBryan Whitehead static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter, 7807624df1SBryan Whitehead u32 seconds, u32 nano_seconds, 7907624df1SBryan Whitehead u32 header) 8007624df1SBryan Whitehead { 8107624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 8207624df1SBryan Whitehead 8307624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 8407624df1SBryan Whitehead if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 8507624df1SBryan Whitehead ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds; 8607624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds; 8707624df1SBryan Whitehead ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header; 8807624df1SBryan Whitehead ptp->tx_ts_queue_size++; 8907624df1SBryan Whitehead } else { 9007624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 9107624df1SBryan Whitehead "tx ts queue overflow\n"); 9207624df1SBryan Whitehead } 9307624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 9407624df1SBryan Whitehead } 9507624df1SBryan Whitehead 9607624df1SBryan Whitehead static void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter) 9707624df1SBryan Whitehead { 9807624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 9907624df1SBryan Whitehead struct skb_shared_hwtstamps tstamps; 10007624df1SBryan Whitehead u32 header, nseconds, seconds; 10107624df1SBryan Whitehead bool ignore_sync = false; 10207624df1SBryan Whitehead struct sk_buff *skb; 10307624df1SBryan Whitehead int c, i; 10407624df1SBryan Whitehead 10507624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 10607624df1SBryan Whitehead c = ptp->tx_ts_skb_queue_size; 10707624df1SBryan Whitehead 10807624df1SBryan Whitehead if (c > ptp->tx_ts_queue_size) 10907624df1SBryan Whitehead c = ptp->tx_ts_queue_size; 11007624df1SBryan Whitehead if (c <= 0) 11107624df1SBryan Whitehead goto done; 11207624df1SBryan Whitehead 11307624df1SBryan Whitehead for (i = 0; i < c; i++) { 11407624df1SBryan Whitehead ignore_sync = ((ptp->tx_ts_ignore_sync_queue & 11507624df1SBryan Whitehead BIT(i)) != 0); 11607624df1SBryan Whitehead skb = ptp->tx_ts_skb_queue[i]; 11707624df1SBryan Whitehead nseconds = ptp->tx_ts_nseconds_queue[i]; 11807624df1SBryan Whitehead seconds = ptp->tx_ts_seconds_queue[i]; 11907624df1SBryan Whitehead header = ptp->tx_ts_header_queue[i]; 12007624df1SBryan Whitehead 12107624df1SBryan Whitehead memset(&tstamps, 0, sizeof(tstamps)); 12207624df1SBryan Whitehead tstamps.hwtstamp = ktime_set(seconds, nseconds); 12307624df1SBryan Whitehead if (!ignore_sync || 12407624df1SBryan Whitehead ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) != 12507624df1SBryan Whitehead PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_)) 12607624df1SBryan Whitehead skb_tstamp_tx(skb, &tstamps); 12707624df1SBryan Whitehead 12807624df1SBryan Whitehead dev_kfree_skb(skb); 12907624df1SBryan Whitehead 13007624df1SBryan Whitehead ptp->tx_ts_skb_queue[i] = NULL; 13107624df1SBryan Whitehead ptp->tx_ts_seconds_queue[i] = 0; 13207624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[i] = 0; 13307624df1SBryan Whitehead ptp->tx_ts_header_queue[i] = 0; 13407624df1SBryan Whitehead } 13507624df1SBryan Whitehead 13607624df1SBryan Whitehead /* shift queue */ 13707624df1SBryan Whitehead ptp->tx_ts_ignore_sync_queue >>= c; 13807624df1SBryan Whitehead for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) { 13907624df1SBryan Whitehead ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i]; 14007624df1SBryan Whitehead ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i]; 14107624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i]; 14207624df1SBryan Whitehead ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i]; 14307624df1SBryan Whitehead 14407624df1SBryan Whitehead ptp->tx_ts_skb_queue[i] = NULL; 14507624df1SBryan Whitehead ptp->tx_ts_seconds_queue[i] = 0; 14607624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[i] = 0; 14707624df1SBryan Whitehead ptp->tx_ts_header_queue[i] = 0; 14807624df1SBryan Whitehead } 14907624df1SBryan Whitehead ptp->tx_ts_skb_queue_size -= c; 15007624df1SBryan Whitehead ptp->tx_ts_queue_size -= c; 15107624df1SBryan Whitehead done: 15207624df1SBryan Whitehead ptp->pending_tx_timestamps -= c; 15307624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 15407624df1SBryan Whitehead } 15507624df1SBryan Whitehead 15622820017SJohn Efstathiades static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter, 15722820017SJohn Efstathiades int event_channel) 15807624df1SBryan Whitehead { 15907624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 16007624df1SBryan Whitehead int result = -ENODEV; 16107624df1SBryan Whitehead 16207624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 16322820017SJohn Efstathiades if (!(test_bit(event_channel, &ptp->used_event_ch))) { 16422820017SJohn Efstathiades ptp->used_event_ch |= BIT(event_channel); 16522820017SJohn Efstathiades result = event_channel; 16622820017SJohn Efstathiades } else { 16722820017SJohn Efstathiades netif_warn(adapter, drv, adapter->netdev, 16822820017SJohn Efstathiades "attempted to reserved a used event_channel = %d\n", 16922820017SJohn Efstathiades event_channel); 17007624df1SBryan Whitehead } 17107624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 17207624df1SBryan Whitehead return result; 17307624df1SBryan Whitehead } 17407624df1SBryan Whitehead 17507624df1SBryan Whitehead static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter, 17607624df1SBryan Whitehead int event_channel) 17707624df1SBryan Whitehead { 17807624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 17907624df1SBryan Whitehead 18007624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 18107624df1SBryan Whitehead if (test_bit(event_channel, &ptp->used_event_ch)) { 18207624df1SBryan Whitehead ptp->used_event_ch &= ~BIT(event_channel); 18307624df1SBryan Whitehead } else { 18407624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 18507624df1SBryan Whitehead "attempted release on a not used event_channel = %d\n", 18607624df1SBryan Whitehead event_channel); 18707624df1SBryan Whitehead } 18807624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 18907624df1SBryan Whitehead } 19007624df1SBryan Whitehead 19107624df1SBryan Whitehead static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, 19207624df1SBryan Whitehead u32 *seconds, u32 *nano_seconds, 19307624df1SBryan Whitehead u32 *sub_nano_seconds); 19460942c39SRaju Lakkaraju static void lan743x_ptp_io_clock_get(struct lan743x_adapter *adapter, 19560942c39SRaju Lakkaraju u32 *sec, u32 *nsec, u32 *sub_nsec); 19607624df1SBryan Whitehead static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, 19707624df1SBryan Whitehead s64 time_step_ns); 19807624df1SBryan Whitehead 19922820017SJohn Efstathiades static void lan743x_led_mux_enable(struct lan743x_adapter *adapter, 20022820017SJohn Efstathiades int pin, bool enable) 20122820017SJohn Efstathiades { 20222820017SJohn Efstathiades struct lan743x_ptp *ptp = &adapter->ptp; 20322820017SJohn Efstathiades 20422820017SJohn Efstathiades if (ptp->leds_multiplexed && 20522820017SJohn Efstathiades ptp->led_enabled[pin]) { 20622820017SJohn Efstathiades u32 val = lan743x_csr_read(adapter, HW_CFG); 20722820017SJohn Efstathiades 20822820017SJohn Efstathiades if (enable) 20922820017SJohn Efstathiades val |= LAN743X_LED_ENABLE(pin); 21022820017SJohn Efstathiades else 21122820017SJohn Efstathiades val &= ~LAN743X_LED_ENABLE(pin); 21222820017SJohn Efstathiades 21322820017SJohn Efstathiades lan743x_csr_write(adapter, HW_CFG, val); 21422820017SJohn Efstathiades } 21522820017SJohn Efstathiades } 21622820017SJohn Efstathiades 21722820017SJohn Efstathiades static void lan743x_led_mux_save(struct lan743x_adapter *adapter) 21822820017SJohn Efstathiades { 21922820017SJohn Efstathiades struct lan743x_ptp *ptp = &adapter->ptp; 22022820017SJohn Efstathiades u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; 22122820017SJohn Efstathiades 22222820017SJohn Efstathiades if (id_rev == ID_REV_ID_LAN7430_) { 22322820017SJohn Efstathiades int i; 22422820017SJohn Efstathiades u32 val = lan743x_csr_read(adapter, HW_CFG); 22522820017SJohn Efstathiades 22622820017SJohn Efstathiades for (i = 0; i < LAN7430_N_LED; i++) { 22722820017SJohn Efstathiades bool led_enabled = (val & LAN743X_LED_ENABLE(i)) != 0; 22822820017SJohn Efstathiades 22922820017SJohn Efstathiades ptp->led_enabled[i] = led_enabled; 23022820017SJohn Efstathiades } 23122820017SJohn Efstathiades ptp->leds_multiplexed = true; 23222820017SJohn Efstathiades } else { 23322820017SJohn Efstathiades ptp->leds_multiplexed = false; 23422820017SJohn Efstathiades } 23522820017SJohn Efstathiades } 23622820017SJohn Efstathiades 23722820017SJohn Efstathiades static void lan743x_led_mux_restore(struct lan743x_adapter *adapter) 23822820017SJohn Efstathiades { 23922820017SJohn Efstathiades u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; 24022820017SJohn Efstathiades 24122820017SJohn Efstathiades if (id_rev == ID_REV_ID_LAN7430_) { 24222820017SJohn Efstathiades int i; 24322820017SJohn Efstathiades 24422820017SJohn Efstathiades for (i = 0; i < LAN7430_N_LED; i++) 24522820017SJohn Efstathiades lan743x_led_mux_enable(adapter, i, true); 24622820017SJohn Efstathiades } 24722820017SJohn Efstathiades } 24822820017SJohn Efstathiades 24907624df1SBryan Whitehead static int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter, 25022820017SJohn Efstathiades int pin, int event_channel) 25107624df1SBryan Whitehead { 25207624df1SBryan Whitehead struct lan743x_gpio *gpio = &adapter->gpio; 25307624df1SBryan Whitehead unsigned long irq_flags = 0; 25422820017SJohn Efstathiades int bit_mask = BIT(pin); 25507624df1SBryan Whitehead int ret = -EBUSY; 25607624df1SBryan Whitehead 25707624df1SBryan Whitehead spin_lock_irqsave(&gpio->gpio_lock, irq_flags); 25807624df1SBryan Whitehead 25907624df1SBryan Whitehead if (!(gpio->used_bits & bit_mask)) { 26007624df1SBryan Whitehead gpio->used_bits |= bit_mask; 26107624df1SBryan Whitehead gpio->output_bits |= bit_mask; 26207624df1SBryan Whitehead gpio->ptp_bits |= bit_mask; 26307624df1SBryan Whitehead 26422820017SJohn Efstathiades /* assign pin to GPIO function */ 26522820017SJohn Efstathiades lan743x_led_mux_enable(adapter, pin, false); 26622820017SJohn Efstathiades 26707624df1SBryan Whitehead /* set as output, and zero initial value */ 26822820017SJohn Efstathiades gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(pin); 26922820017SJohn Efstathiades gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); 27007624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 27107624df1SBryan Whitehead 27207624df1SBryan Whitehead /* enable gpio, and set buffer type to push pull */ 27322820017SJohn Efstathiades gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(pin); 27422820017SJohn Efstathiades gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(pin); 27507624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 27607624df1SBryan Whitehead 27707624df1SBryan Whitehead /* set 1588 polarity to high */ 27822820017SJohn Efstathiades gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(pin); 27907624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2); 28007624df1SBryan Whitehead 28122820017SJohn Efstathiades if (event_channel == 0) { 28207624df1SBryan Whitehead /* use channel A */ 28322820017SJohn Efstathiades gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(pin); 28407624df1SBryan Whitehead } else { 28507624df1SBryan Whitehead /* use channel B */ 28622820017SJohn Efstathiades gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(pin); 28707624df1SBryan Whitehead } 28822820017SJohn Efstathiades gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(pin); 28907624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); 29007624df1SBryan Whitehead 29122820017SJohn Efstathiades ret = pin; 29207624df1SBryan Whitehead } 29307624df1SBryan Whitehead spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); 29407624df1SBryan Whitehead return ret; 29507624df1SBryan Whitehead } 29607624df1SBryan Whitehead 29722820017SJohn Efstathiades static void lan743x_gpio_release(struct lan743x_adapter *adapter, int pin) 29807624df1SBryan Whitehead { 29907624df1SBryan Whitehead struct lan743x_gpio *gpio = &adapter->gpio; 30007624df1SBryan Whitehead unsigned long irq_flags = 0; 30122820017SJohn Efstathiades int bit_mask = BIT(pin); 30207624df1SBryan Whitehead 30307624df1SBryan Whitehead spin_lock_irqsave(&gpio->gpio_lock, irq_flags); 30407624df1SBryan Whitehead if (gpio->used_bits & bit_mask) { 30507624df1SBryan Whitehead gpio->used_bits &= ~bit_mask; 30607624df1SBryan Whitehead if (gpio->output_bits & bit_mask) { 30707624df1SBryan Whitehead gpio->output_bits &= ~bit_mask; 30807624df1SBryan Whitehead 30907624df1SBryan Whitehead if (gpio->ptp_bits & bit_mask) { 31007624df1SBryan Whitehead gpio->ptp_bits &= ~bit_mask; 31107624df1SBryan Whitehead /* disable ptp output */ 31222820017SJohn Efstathiades gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(pin); 31307624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG3, 31407624df1SBryan Whitehead gpio->gpio_cfg3); 31507624df1SBryan Whitehead } 31607624df1SBryan Whitehead /* release gpio output */ 31707624df1SBryan Whitehead 31807624df1SBryan Whitehead /* disable gpio */ 31922820017SJohn Efstathiades gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(pin); 32022820017SJohn Efstathiades gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(pin); 32107624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 32207624df1SBryan Whitehead 32307624df1SBryan Whitehead /* reset back to input */ 32422820017SJohn Efstathiades gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(pin); 32522820017SJohn Efstathiades gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); 32607624df1SBryan Whitehead lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 32722820017SJohn Efstathiades 32822820017SJohn Efstathiades /* assign pin to original function */ 32922820017SJohn Efstathiades lan743x_led_mux_enable(adapter, pin, true); 33007624df1SBryan Whitehead } 33107624df1SBryan Whitehead } 33207624df1SBryan Whitehead spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); 33307624df1SBryan Whitehead } 33407624df1SBryan Whitehead 33507624df1SBryan Whitehead static int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm) 33607624df1SBryan Whitehead { 33707624df1SBryan Whitehead struct lan743x_ptp *ptp = 33807624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 33907624df1SBryan Whitehead struct lan743x_adapter *adapter = 34007624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 34107624df1SBryan Whitehead u32 lan743x_rate_adj = 0; 34207624df1SBryan Whitehead bool positive = true; 34307624df1SBryan Whitehead u64 u64_delta = 0; 34407624df1SBryan Whitehead 34507624df1SBryan Whitehead if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) || 34607624df1SBryan Whitehead scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) { 34707624df1SBryan Whitehead return -EINVAL; 34807624df1SBryan Whitehead } 34907624df1SBryan Whitehead if (scaled_ppm > 0) { 35007624df1SBryan Whitehead u64_delta = (u64)scaled_ppm; 35107624df1SBryan Whitehead positive = true; 35207624df1SBryan Whitehead } else { 35307624df1SBryan Whitehead u64_delta = (u64)(-scaled_ppm); 35407624df1SBryan Whitehead positive = false; 35507624df1SBryan Whitehead } 35607624df1SBryan Whitehead u64_delta = (u64_delta << 19); 35707624df1SBryan Whitehead lan743x_rate_adj = div_u64(u64_delta, 1000000); 35807624df1SBryan Whitehead 35907624df1SBryan Whitehead if (positive) 36007624df1SBryan Whitehead lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_; 36107624df1SBryan Whitehead 36207624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ, 36307624df1SBryan Whitehead lan743x_rate_adj); 36407624df1SBryan Whitehead 36507624df1SBryan Whitehead return 0; 36607624df1SBryan Whitehead } 36707624df1SBryan Whitehead 36807624df1SBryan Whitehead static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb) 36907624df1SBryan Whitehead { 37007624df1SBryan Whitehead struct lan743x_ptp *ptp = 37107624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 37207624df1SBryan Whitehead struct lan743x_adapter *adapter = 37307624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 37407624df1SBryan Whitehead u32 lan743x_rate_adj = 0; 37507624df1SBryan Whitehead bool positive = true; 37607624df1SBryan Whitehead u32 u32_delta = 0; 37707624df1SBryan Whitehead u64 u64_delta = 0; 37807624df1SBryan Whitehead 37907624df1SBryan Whitehead if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) || 38007624df1SBryan Whitehead delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) { 38107624df1SBryan Whitehead return -EINVAL; 38207624df1SBryan Whitehead } 38307624df1SBryan Whitehead if (delta_ppb > 0) { 38407624df1SBryan Whitehead u32_delta = (u32)delta_ppb; 38507624df1SBryan Whitehead positive = true; 38607624df1SBryan Whitehead } else { 38707624df1SBryan Whitehead u32_delta = (u32)(-delta_ppb); 38807624df1SBryan Whitehead positive = false; 38907624df1SBryan Whitehead } 39007624df1SBryan Whitehead u64_delta = (((u64)u32_delta) << 35); 39107624df1SBryan Whitehead lan743x_rate_adj = div_u64(u64_delta, 1000000000); 39207624df1SBryan Whitehead 39307624df1SBryan Whitehead if (positive) 39407624df1SBryan Whitehead lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_; 39507624df1SBryan Whitehead 39607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ, 39707624df1SBryan Whitehead lan743x_rate_adj); 39807624df1SBryan Whitehead 39907624df1SBryan Whitehead return 0; 40007624df1SBryan Whitehead } 40107624df1SBryan Whitehead 40207624df1SBryan Whitehead static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta) 40307624df1SBryan Whitehead { 40407624df1SBryan Whitehead struct lan743x_ptp *ptp = 40507624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 40607624df1SBryan Whitehead struct lan743x_adapter *adapter = 40707624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 40807624df1SBryan Whitehead 40907624df1SBryan Whitehead lan743x_ptp_clock_step(adapter, delta); 41007624df1SBryan Whitehead 41107624df1SBryan Whitehead return 0; 41207624df1SBryan Whitehead } 41307624df1SBryan Whitehead 41407624df1SBryan Whitehead static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci, 41507624df1SBryan Whitehead struct timespec64 *ts) 41607624df1SBryan Whitehead { 41707624df1SBryan Whitehead struct lan743x_ptp *ptp = 41807624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 41907624df1SBryan Whitehead struct lan743x_adapter *adapter = 42007624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 42107624df1SBryan Whitehead u32 nano_seconds = 0; 42207624df1SBryan Whitehead u32 seconds = 0; 42307624df1SBryan Whitehead 42460942c39SRaju Lakkaraju if (adapter->is_pci11x1x) 42560942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &seconds, &nano_seconds, 42660942c39SRaju Lakkaraju NULL); 42760942c39SRaju Lakkaraju else 42807624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL); 42907624df1SBryan Whitehead ts->tv_sec = seconds; 43007624df1SBryan Whitehead ts->tv_nsec = nano_seconds; 43107624df1SBryan Whitehead 43207624df1SBryan Whitehead return 0; 43307624df1SBryan Whitehead } 43407624df1SBryan Whitehead 43507624df1SBryan Whitehead static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci, 43607624df1SBryan Whitehead const struct timespec64 *ts) 43707624df1SBryan Whitehead { 43807624df1SBryan Whitehead struct lan743x_ptp *ptp = 43907624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 44007624df1SBryan Whitehead struct lan743x_adapter *adapter = 44107624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 44207624df1SBryan Whitehead u32 nano_seconds = 0; 44307624df1SBryan Whitehead u32 seconds = 0; 44407624df1SBryan Whitehead 44507624df1SBryan Whitehead if (ts) { 44607624df1SBryan Whitehead if (ts->tv_sec > 0xFFFFFFFFLL || 44707624df1SBryan Whitehead ts->tv_sec < 0) { 44807624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 44907624df1SBryan Whitehead "ts->tv_sec out of range, %lld\n", 45007624df1SBryan Whitehead ts->tv_sec); 45107624df1SBryan Whitehead return -ERANGE; 45207624df1SBryan Whitehead } 45307624df1SBryan Whitehead if (ts->tv_nsec >= 1000000000L || 45407624df1SBryan Whitehead ts->tv_nsec < 0) { 45507624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 45607624df1SBryan Whitehead "ts->tv_nsec out of range, %ld\n", 45707624df1SBryan Whitehead ts->tv_nsec); 45807624df1SBryan Whitehead return -ERANGE; 45907624df1SBryan Whitehead } 46007624df1SBryan Whitehead seconds = ts->tv_sec; 46107624df1SBryan Whitehead nano_seconds = ts->tv_nsec; 46207624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0); 46307624df1SBryan Whitehead } else { 46407624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n"); 46507624df1SBryan Whitehead return -EINVAL; 46607624df1SBryan Whitehead } 46707624df1SBryan Whitehead 46807624df1SBryan Whitehead return 0; 46907624df1SBryan Whitehead } 47007624df1SBryan Whitehead 47122820017SJohn Efstathiades static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter, 47222820017SJohn Efstathiades unsigned int index) 47307624df1SBryan Whitehead { 47407624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 47507624df1SBryan Whitehead u32 general_config = 0; 47622820017SJohn Efstathiades struct lan743x_ptp_perout *perout = &ptp->perout[index]; 47707624df1SBryan Whitehead 47822820017SJohn Efstathiades if (perout->gpio_pin >= 0) { 47922820017SJohn Efstathiades lan743x_gpio_release(adapter, perout->gpio_pin); 48022820017SJohn Efstathiades perout->gpio_pin = -1; 48107624df1SBryan Whitehead } 48207624df1SBryan Whitehead 48322820017SJohn Efstathiades if (perout->event_ch >= 0) { 48407624df1SBryan Whitehead /* set target to far in the future, effectively disabling it */ 48507624df1SBryan Whitehead lan743x_csr_write(adapter, 48622820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 48707624df1SBryan Whitehead 0xFFFF0000); 48807624df1SBryan Whitehead lan743x_csr_write(adapter, 48922820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 49007624df1SBryan Whitehead 0); 49107624df1SBryan Whitehead 49207624df1SBryan Whitehead general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 49307624df1SBryan Whitehead general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 49422820017SJohn Efstathiades (perout->event_ch); 49507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 49622820017SJohn Efstathiades lan743x_ptp_release_event_ch(adapter, perout->event_ch); 49722820017SJohn Efstathiades perout->event_ch = -1; 49807624df1SBryan Whitehead } 49907624df1SBryan Whitehead } 50007624df1SBryan Whitehead 50107624df1SBryan Whitehead static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, 50222820017SJohn Efstathiades struct ptp_perout_request *perout_request) 50307624df1SBryan Whitehead { 50407624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 50507624df1SBryan Whitehead u32 period_sec = 0, period_nsec = 0; 50607624df1SBryan Whitehead u32 start_sec = 0, start_nsec = 0; 50707624df1SBryan Whitehead u32 general_config = 0; 50807624df1SBryan Whitehead int pulse_width = 0; 50922820017SJohn Efstathiades int perout_pin = 0; 51022820017SJohn Efstathiades unsigned int index = perout_request->index; 51122820017SJohn Efstathiades struct lan743x_ptp_perout *perout = &ptp->perout[index]; 5124ece1ae4SYuiko Oshino int ret = 0; 51307624df1SBryan Whitehead 5147f9048f1SJacob Keller /* Reject requests with unsupported flags */ 5154ece1ae4SYuiko Oshino if (perout_request->flags & ~PTP_PEROUT_DUTY_CYCLE) 5167f9048f1SJacob Keller return -EOPNOTSUPP; 5177f9048f1SJacob Keller 51822820017SJohn Efstathiades if (on) { 51922820017SJohn Efstathiades perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, 52022820017SJohn Efstathiades perout_request->index); 52122820017SJohn Efstathiades if (perout_pin < 0) 52222820017SJohn Efstathiades return -EBUSY; 52322820017SJohn Efstathiades } else { 52422820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 52507624df1SBryan Whitehead return 0; 52607624df1SBryan Whitehead } 52707624df1SBryan Whitehead 52822820017SJohn Efstathiades if (perout->event_ch >= 0 || 52922820017SJohn Efstathiades perout->gpio_pin >= 0) { 53007624df1SBryan Whitehead /* already on, turn off first */ 53122820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 53207624df1SBryan Whitehead } 53307624df1SBryan Whitehead 53422820017SJohn Efstathiades perout->event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 53522820017SJohn Efstathiades 53622820017SJohn Efstathiades if (perout->event_ch < 0) { 53707624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 53822820017SJohn Efstathiades "Failed to reserve event channel %d for PEROUT\n", 53922820017SJohn Efstathiades index); 5404ece1ae4SYuiko Oshino ret = -EBUSY; 54107624df1SBryan Whitehead goto failed; 54207624df1SBryan Whitehead } 54307624df1SBryan Whitehead 54422820017SJohn Efstathiades perout->gpio_pin = lan743x_gpio_rsrv_ptp_out(adapter, 54522820017SJohn Efstathiades perout_pin, 54622820017SJohn Efstathiades perout->event_ch); 54707624df1SBryan Whitehead 54822820017SJohn Efstathiades if (perout->gpio_pin < 0) { 54907624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 55007624df1SBryan Whitehead "Failed to reserve gpio %d for PEROUT\n", 55122820017SJohn Efstathiades perout_pin); 5524ece1ae4SYuiko Oshino ret = -EBUSY; 55307624df1SBryan Whitehead goto failed; 55407624df1SBryan Whitehead } 55507624df1SBryan Whitehead 55622820017SJohn Efstathiades start_sec = perout_request->start.sec; 55722820017SJohn Efstathiades start_sec += perout_request->start.nsec / 1000000000; 55822820017SJohn Efstathiades start_nsec = perout_request->start.nsec % 1000000000; 55907624df1SBryan Whitehead 56022820017SJohn Efstathiades period_sec = perout_request->period.sec; 56122820017SJohn Efstathiades period_sec += perout_request->period.nsec / 1000000000; 56222820017SJohn Efstathiades period_nsec = perout_request->period.nsec % 1000000000; 56307624df1SBryan Whitehead 5644ece1ae4SYuiko Oshino if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 5654ece1ae4SYuiko Oshino struct timespec64 ts_on, ts_period; 5664ece1ae4SYuiko Oshino s64 wf_high, period64, half; 5674ece1ae4SYuiko Oshino s32 reminder; 5684ece1ae4SYuiko Oshino 5694ece1ae4SYuiko Oshino ts_on.tv_sec = perout_request->on.sec; 5704ece1ae4SYuiko Oshino ts_on.tv_nsec = perout_request->on.nsec; 5714ece1ae4SYuiko Oshino wf_high = timespec64_to_ns(&ts_on); 5724ece1ae4SYuiko Oshino ts_period.tv_sec = perout_request->period.sec; 5734ece1ae4SYuiko Oshino ts_period.tv_nsec = perout_request->period.nsec; 5744ece1ae4SYuiko Oshino period64 = timespec64_to_ns(&ts_period); 5754ece1ae4SYuiko Oshino 5764ece1ae4SYuiko Oshino if (period64 < 200) { 5774ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 5784ece1ae4SYuiko Oshino "perout period too small, minimum is 200nS\n"); 5794ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 5804ece1ae4SYuiko Oshino goto failed; 5814ece1ae4SYuiko Oshino } 5824ece1ae4SYuiko Oshino if (wf_high >= period64) { 5834ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 5844ece1ae4SYuiko Oshino "pulse width must be smaller than period\n"); 5854ece1ae4SYuiko Oshino ret = -EINVAL; 5864ece1ae4SYuiko Oshino goto failed; 5874ece1ae4SYuiko Oshino } 5884ece1ae4SYuiko Oshino 5894ece1ae4SYuiko Oshino /* Check if we can do 50% toggle on an even value of period. 5904ece1ae4SYuiko Oshino * If the period number is odd, then check if the requested 5914ece1ae4SYuiko Oshino * pulse width is the same as one of pre-defined width values. 5924ece1ae4SYuiko Oshino * Otherwise, return failure. 5934ece1ae4SYuiko Oshino */ 5944ece1ae4SYuiko Oshino half = div_s64_rem(period64, 2, &reminder); 5954ece1ae4SYuiko Oshino if (!reminder) { 5964ece1ae4SYuiko Oshino if (half == wf_high) { 5974ece1ae4SYuiko Oshino /* It's 50% match. Use the toggle option */ 5984ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_; 5994ece1ae4SYuiko Oshino /* In this case, devide period value by 2 */ 6004ece1ae4SYuiko Oshino ts_period = ns_to_timespec64(div_s64(period64, 2)); 6014ece1ae4SYuiko Oshino period_sec = ts_period.tv_sec; 6024ece1ae4SYuiko Oshino period_nsec = ts_period.tv_nsec; 6034ece1ae4SYuiko Oshino 6044ece1ae4SYuiko Oshino goto program; 6054ece1ae4SYuiko Oshino } 6064ece1ae4SYuiko Oshino } 6074ece1ae4SYuiko Oshino /* if we can't do toggle, then the width option needs to be the exact match */ 6084ece1ae4SYuiko Oshino if (wf_high == 200000000) { 6094ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 6104ece1ae4SYuiko Oshino } else if (wf_high == 10000000) { 6114ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 6124ece1ae4SYuiko Oshino } else if (wf_high == 1000000) { 6134ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 6144ece1ae4SYuiko Oshino } else if (wf_high == 100000) { 6154ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 6164ece1ae4SYuiko Oshino } else if (wf_high == 10000) { 6174ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 6184ece1ae4SYuiko Oshino } else if (wf_high == 100) { 6194ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 6204ece1ae4SYuiko Oshino } else { 6214ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 6224ece1ae4SYuiko Oshino "duty cycle specified is not supported\n"); 6234ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 6244ece1ae4SYuiko Oshino goto failed; 6254ece1ae4SYuiko Oshino } 6264ece1ae4SYuiko Oshino } else { 62707624df1SBryan Whitehead if (period_sec == 0) { 62807624df1SBryan Whitehead if (period_nsec >= 400000000) { 62907624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 63007624df1SBryan Whitehead } else if (period_nsec >= 20000000) { 63107624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 63207624df1SBryan Whitehead } else if (period_nsec >= 2000000) { 63307624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 63407624df1SBryan Whitehead } else if (period_nsec >= 200000) { 63507624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 63607624df1SBryan Whitehead } else if (period_nsec >= 20000) { 63707624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 63807624df1SBryan Whitehead } else if (period_nsec >= 200) { 63907624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 64007624df1SBryan Whitehead } else { 64107624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 64207624df1SBryan Whitehead "perout period too small, minimum is 200nS\n"); 6434ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 64407624df1SBryan Whitehead goto failed; 64507624df1SBryan Whitehead } 64607624df1SBryan Whitehead } else { 64707624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 64807624df1SBryan Whitehead } 6494ece1ae4SYuiko Oshino } 6504ece1ae4SYuiko Oshino program: 65107624df1SBryan Whitehead 65207624df1SBryan Whitehead /* turn off by setting target far in future */ 65307624df1SBryan Whitehead lan743x_csr_write(adapter, 65422820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 65507624df1SBryan Whitehead 0xFFFF0000); 65607624df1SBryan Whitehead lan743x_csr_write(adapter, 65722820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0); 65807624df1SBryan Whitehead 65907624df1SBryan Whitehead /* Configure to pulse every period */ 66007624df1SBryan Whitehead general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 66107624df1SBryan Whitehead general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 66222820017SJohn Efstathiades (perout->event_ch)); 66307624df1SBryan Whitehead general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 66422820017SJohn Efstathiades (perout->event_ch, pulse_width); 66507624df1SBryan Whitehead general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 66622820017SJohn Efstathiades (perout->event_ch); 66707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 66807624df1SBryan Whitehead 66907624df1SBryan Whitehead /* set the reload to one toggle cycle */ 67007624df1SBryan Whitehead lan743x_csr_write(adapter, 67122820017SJohn Efstathiades PTP_CLOCK_TARGET_RELOAD_SEC_X(perout->event_ch), 67207624df1SBryan Whitehead period_sec); 67307624df1SBryan Whitehead lan743x_csr_write(adapter, 67422820017SJohn Efstathiades PTP_CLOCK_TARGET_RELOAD_NS_X(perout->event_ch), 67507624df1SBryan Whitehead period_nsec); 67607624df1SBryan Whitehead 67707624df1SBryan Whitehead /* set the start time */ 67807624df1SBryan Whitehead lan743x_csr_write(adapter, 67922820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 68007624df1SBryan Whitehead start_sec); 68107624df1SBryan Whitehead lan743x_csr_write(adapter, 68222820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 68307624df1SBryan Whitehead start_nsec); 68407624df1SBryan Whitehead 68507624df1SBryan Whitehead return 0; 68607624df1SBryan Whitehead 68707624df1SBryan Whitehead failed: 68822820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 6894ece1ae4SYuiko Oshino return ret; 69007624df1SBryan Whitehead } 69107624df1SBryan Whitehead 692*e432dd3bSRaju Lakkaraju static void lan743x_ptp_io_perout_off(struct lan743x_adapter *adapter, 693*e432dd3bSRaju Lakkaraju u32 index) 694*e432dd3bSRaju Lakkaraju { 695*e432dd3bSRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 696*e432dd3bSRaju Lakkaraju int perout_pin; 697*e432dd3bSRaju Lakkaraju int event_ch; 698*e432dd3bSRaju Lakkaraju u32 gen_cfg; 699*e432dd3bSRaju Lakkaraju int val; 700*e432dd3bSRaju Lakkaraju 701*e432dd3bSRaju Lakkaraju event_ch = ptp->ptp_io_perout[index]; 702*e432dd3bSRaju Lakkaraju if (event_ch >= 0) { 703*e432dd3bSRaju Lakkaraju /* set target to far in the future, effectively disabling it */ 704*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 705*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 706*e432dd3bSRaju Lakkaraju 0xFFFF0000); 707*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 708*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 709*e432dd3bSRaju Lakkaraju 0); 710*e432dd3bSRaju Lakkaraju 711*e432dd3bSRaju Lakkaraju gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 712*e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 713*e432dd3bSRaju Lakkaraju (event_ch)); 714*e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch)); 715*e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch); 716*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 717*e432dd3bSRaju Lakkaraju if (event_ch) 718*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 719*e432dd3bSRaju Lakkaraju PTP_INT_TIMER_INT_B_); 720*e432dd3bSRaju Lakkaraju else 721*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 722*e432dd3bSRaju Lakkaraju PTP_INT_TIMER_INT_A_); 723*e432dd3bSRaju Lakkaraju lan743x_ptp_release_event_ch(adapter, event_ch); 724*e432dd3bSRaju Lakkaraju ptp->ptp_io_perout[index] = -1; 725*e432dd3bSRaju Lakkaraju } 726*e432dd3bSRaju Lakkaraju 727*e432dd3bSRaju Lakkaraju perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 728*e432dd3bSRaju Lakkaraju 729*e432dd3bSRaju Lakkaraju /* Deselect Event output */ 730*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 731*e432dd3bSRaju Lakkaraju 732*e432dd3bSRaju Lakkaraju /* Disables the output of Local Time Target compare events */ 733*e432dd3bSRaju Lakkaraju val &= ~PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 734*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 735*e432dd3bSRaju Lakkaraju 736*e432dd3bSRaju Lakkaraju /* Configured as an opendrain driver*/ 737*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 738*e432dd3bSRaju Lakkaraju val &= ~PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 739*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 740*e432dd3bSRaju Lakkaraju /* Dummy read to make sure write operation success */ 741*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 742*e432dd3bSRaju Lakkaraju } 743*e432dd3bSRaju Lakkaraju 744*e432dd3bSRaju Lakkaraju static int lan743x_ptp_io_perout(struct lan743x_adapter *adapter, int on, 745*e432dd3bSRaju Lakkaraju struct ptp_perout_request *perout_request) 746*e432dd3bSRaju Lakkaraju { 747*e432dd3bSRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 748*e432dd3bSRaju Lakkaraju u32 period_sec, period_nsec; 749*e432dd3bSRaju Lakkaraju u32 start_sec, start_nsec; 750*e432dd3bSRaju Lakkaraju u32 pulse_sec, pulse_nsec; 751*e432dd3bSRaju Lakkaraju int pulse_width; 752*e432dd3bSRaju Lakkaraju int perout_pin; 753*e432dd3bSRaju Lakkaraju int event_ch; 754*e432dd3bSRaju Lakkaraju u32 gen_cfg; 755*e432dd3bSRaju Lakkaraju u32 index; 756*e432dd3bSRaju Lakkaraju int val; 757*e432dd3bSRaju Lakkaraju 758*e432dd3bSRaju Lakkaraju index = perout_request->index; 759*e432dd3bSRaju Lakkaraju event_ch = ptp->ptp_io_perout[index]; 760*e432dd3bSRaju Lakkaraju 761*e432dd3bSRaju Lakkaraju if (on) { 762*e432dd3bSRaju Lakkaraju perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 763*e432dd3bSRaju Lakkaraju if (perout_pin < 0) 764*e432dd3bSRaju Lakkaraju return -EBUSY; 765*e432dd3bSRaju Lakkaraju } else { 766*e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 767*e432dd3bSRaju Lakkaraju return 0; 768*e432dd3bSRaju Lakkaraju } 769*e432dd3bSRaju Lakkaraju 770*e432dd3bSRaju Lakkaraju if (event_ch >= LAN743X_PTP_N_EVENT_CHAN) { 771*e432dd3bSRaju Lakkaraju /* already on, turn off first */ 772*e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 773*e432dd3bSRaju Lakkaraju } 774*e432dd3bSRaju Lakkaraju 775*e432dd3bSRaju Lakkaraju event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 776*e432dd3bSRaju Lakkaraju if (event_ch < 0) { 777*e432dd3bSRaju Lakkaraju netif_warn(adapter, drv, adapter->netdev, 778*e432dd3bSRaju Lakkaraju "Failed to reserve event channel %d for PEROUT\n", 779*e432dd3bSRaju Lakkaraju index); 780*e432dd3bSRaju Lakkaraju goto failed; 781*e432dd3bSRaju Lakkaraju } 782*e432dd3bSRaju Lakkaraju ptp->ptp_io_perout[index] = event_ch; 783*e432dd3bSRaju Lakkaraju 784*e432dd3bSRaju Lakkaraju if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 785*e432dd3bSRaju Lakkaraju pulse_sec = perout_request->on.sec; 786*e432dd3bSRaju Lakkaraju pulse_sec += perout_request->on.nsec / 1000000000; 787*e432dd3bSRaju Lakkaraju pulse_nsec = perout_request->on.nsec % 1000000000; 788*e432dd3bSRaju Lakkaraju } else { 789*e432dd3bSRaju Lakkaraju pulse_sec = perout_request->period.sec; 790*e432dd3bSRaju Lakkaraju pulse_sec += perout_request->period.nsec / 1000000000; 791*e432dd3bSRaju Lakkaraju pulse_nsec = perout_request->period.nsec % 1000000000; 792*e432dd3bSRaju Lakkaraju } 793*e432dd3bSRaju Lakkaraju 794*e432dd3bSRaju Lakkaraju if (pulse_sec == 0) { 795*e432dd3bSRaju Lakkaraju if (pulse_nsec >= 400000000) { 796*e432dd3bSRaju Lakkaraju pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 797*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200000000) { 798*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_; 799*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 100000000) { 800*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_; 801*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 20000000) { 802*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 803*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 10000000) { 804*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_; 805*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 2000000) { 806*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 807*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 1000000) { 808*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_; 809*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200000) { 810*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 811*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 100000) { 812*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_; 813*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 20000) { 814*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 815*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 10000) { 816*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_; 817*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 2000) { 818*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_; 819*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 1000) { 820*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_; 821*e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200) { 822*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 823*e432dd3bSRaju Lakkaraju } else { 824*e432dd3bSRaju Lakkaraju netif_warn(adapter, drv, adapter->netdev, 825*e432dd3bSRaju Lakkaraju "perout period too small, min is 200nS\n"); 826*e432dd3bSRaju Lakkaraju goto failed; 827*e432dd3bSRaju Lakkaraju } 828*e432dd3bSRaju Lakkaraju } else { 829*e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 830*e432dd3bSRaju Lakkaraju } 831*e432dd3bSRaju Lakkaraju 832*e432dd3bSRaju Lakkaraju /* turn off by setting target far in future */ 833*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 834*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 835*e432dd3bSRaju Lakkaraju 0xFFFF0000); 836*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 837*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 0); 838*e432dd3bSRaju Lakkaraju 839*e432dd3bSRaju Lakkaraju /* Configure to pulse every period */ 840*e432dd3bSRaju Lakkaraju gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 841*e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(event_ch)); 842*e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 843*e432dd3bSRaju Lakkaraju (event_ch, pulse_width); 844*e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch); 845*e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch)); 846*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 847*e432dd3bSRaju Lakkaraju 848*e432dd3bSRaju Lakkaraju /* set the reload to one toggle cycle */ 849*e432dd3bSRaju Lakkaraju period_sec = perout_request->period.sec; 850*e432dd3bSRaju Lakkaraju period_sec += perout_request->period.nsec / 1000000000; 851*e432dd3bSRaju Lakkaraju period_nsec = perout_request->period.nsec % 1000000000; 852*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 853*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_RELOAD_SEC_X(event_ch), 854*e432dd3bSRaju Lakkaraju period_sec); 855*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 856*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_RELOAD_NS_X(event_ch), 857*e432dd3bSRaju Lakkaraju period_nsec); 858*e432dd3bSRaju Lakkaraju 859*e432dd3bSRaju Lakkaraju start_sec = perout_request->start.sec; 860*e432dd3bSRaju Lakkaraju start_sec += perout_request->start.nsec / 1000000000; 861*e432dd3bSRaju Lakkaraju start_nsec = perout_request->start.nsec % 1000000000; 862*e432dd3bSRaju Lakkaraju 863*e432dd3bSRaju Lakkaraju /* set the start time */ 864*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 865*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 866*e432dd3bSRaju Lakkaraju start_sec); 867*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 868*e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 869*e432dd3bSRaju Lakkaraju start_nsec); 870*e432dd3bSRaju Lakkaraju 871*e432dd3bSRaju Lakkaraju /* Enable LTC Target Read */ 872*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_CMD_CTL); 873*e432dd3bSRaju Lakkaraju val |= PTP_CMD_CTL_PTP_LTC_TARGET_READ_; 874*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_CMD_CTL, val); 875*e432dd3bSRaju Lakkaraju 876*e432dd3bSRaju Lakkaraju /* Configure as an push/pull driver */ 877*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 878*e432dd3bSRaju Lakkaraju val |= PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 879*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 880*e432dd3bSRaju Lakkaraju 881*e432dd3bSRaju Lakkaraju /* Select Event output */ 882*e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 883*e432dd3bSRaju Lakkaraju if (event_ch) 884*e432dd3bSRaju Lakkaraju /* Channel B as the output */ 885*e432dd3bSRaju Lakkaraju val |= PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 886*e432dd3bSRaju Lakkaraju else 887*e432dd3bSRaju Lakkaraju /* Channel A as the output */ 888*e432dd3bSRaju Lakkaraju val &= ~PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 889*e432dd3bSRaju Lakkaraju 890*e432dd3bSRaju Lakkaraju /* Enables the output of Local Time Target compare events */ 891*e432dd3bSRaju Lakkaraju val |= PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 892*e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 893*e432dd3bSRaju Lakkaraju 894*e432dd3bSRaju Lakkaraju return 0; 895*e432dd3bSRaju Lakkaraju 896*e432dd3bSRaju Lakkaraju failed: 897*e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 898*e432dd3bSRaju Lakkaraju return -ENODEV; 899*e432dd3bSRaju Lakkaraju } 900*e432dd3bSRaju Lakkaraju 90160942c39SRaju Lakkaraju static void lan743x_ptp_io_extts_off(struct lan743x_adapter *adapter, 90260942c39SRaju Lakkaraju u32 index) 90360942c39SRaju Lakkaraju { 90460942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 90560942c39SRaju Lakkaraju struct lan743x_extts *extts; 90660942c39SRaju Lakkaraju int val; 90760942c39SRaju Lakkaraju 90860942c39SRaju Lakkaraju extts = &ptp->extts[index]; 90960942c39SRaju Lakkaraju /* PTP Interrupt Enable Clear Register */ 91060942c39SRaju Lakkaraju if (extts->flags & PTP_FALLING_EDGE) 91160942c39SRaju Lakkaraju val = PTP_INT_EN_FE_EN_CLR_(index); 91260942c39SRaju Lakkaraju else 91360942c39SRaju Lakkaraju val = PTP_INT_EN_RE_EN_CLR_(index); 91460942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_EN_CLR, val); 91560942c39SRaju Lakkaraju 91660942c39SRaju Lakkaraju /* Disables PTP-IO edge lock */ 91760942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 91860942c39SRaju Lakkaraju if (extts->flags & PTP_FALLING_EDGE) { 91960942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(index); 92060942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(index); 92160942c39SRaju Lakkaraju } else { 92260942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(index); 92360942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(index); 92460942c39SRaju Lakkaraju } 92560942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 92660942c39SRaju Lakkaraju 92760942c39SRaju Lakkaraju /* PTP-IO De-select register */ 92860942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_SEL); 92960942c39SRaju Lakkaraju val &= ~PTP_IO_SEL_MASK_; 93060942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_SEL, val); 93160942c39SRaju Lakkaraju 93260942c39SRaju Lakkaraju /* Clear timestamp */ 93360942c39SRaju Lakkaraju memset(&extts->ts, 0, sizeof(struct timespec64)); 93460942c39SRaju Lakkaraju extts->flags = 0; 93560942c39SRaju Lakkaraju } 93660942c39SRaju Lakkaraju 93760942c39SRaju Lakkaraju static int lan743x_ptp_io_event_cap_en(struct lan743x_adapter *adapter, 93860942c39SRaju Lakkaraju u32 flags, u32 channel) 93960942c39SRaju Lakkaraju { 94060942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 94160942c39SRaju Lakkaraju int val; 94260942c39SRaju Lakkaraju 94360942c39SRaju Lakkaraju if ((flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES) 94460942c39SRaju Lakkaraju return -EOPNOTSUPP; 94560942c39SRaju Lakkaraju 94660942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 94760942c39SRaju Lakkaraju /* PTP-IO Event Capture Enable */ 94860942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 94960942c39SRaju Lakkaraju if (flags & PTP_FALLING_EDGE) { 95060942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 95160942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 95260942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 95360942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 95460942c39SRaju Lakkaraju } else { 95560942c39SRaju Lakkaraju /* Rising eventing as Default */ 95660942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 95760942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 95860942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 95960942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 96060942c39SRaju Lakkaraju } 96160942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 96260942c39SRaju Lakkaraju 96360942c39SRaju Lakkaraju /* PTP-IO Select */ 96460942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_SEL); 96560942c39SRaju Lakkaraju val &= ~PTP_IO_SEL_MASK_; 96660942c39SRaju Lakkaraju val |= channel << PTP_IO_SEL_SHIFT_; 96760942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_SEL, val); 96860942c39SRaju Lakkaraju 96960942c39SRaju Lakkaraju /* PTP Interrupt Enable Register */ 97060942c39SRaju Lakkaraju if (flags & PTP_FALLING_EDGE) 97160942c39SRaju Lakkaraju val = PTP_INT_EN_FE_EN_SET_(channel); 97260942c39SRaju Lakkaraju else 97360942c39SRaju Lakkaraju val = PTP_INT_EN_RE_EN_SET_(channel); 97460942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_EN_SET, val); 97560942c39SRaju Lakkaraju 97660942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 97760942c39SRaju Lakkaraju 97860942c39SRaju Lakkaraju return 0; 97960942c39SRaju Lakkaraju } 98060942c39SRaju Lakkaraju 98160942c39SRaju Lakkaraju static int lan743x_ptp_io_extts(struct lan743x_adapter *adapter, int on, 98260942c39SRaju Lakkaraju struct ptp_extts_request *extts_request) 98360942c39SRaju Lakkaraju { 98460942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 98560942c39SRaju Lakkaraju u32 flags = extts_request->flags; 98660942c39SRaju Lakkaraju u32 index = extts_request->index; 98760942c39SRaju Lakkaraju struct lan743x_extts *extts; 98860942c39SRaju Lakkaraju int extts_pin; 98960942c39SRaju Lakkaraju int ret = 0; 99060942c39SRaju Lakkaraju 99160942c39SRaju Lakkaraju extts = &ptp->extts[index]; 99260942c39SRaju Lakkaraju 99360942c39SRaju Lakkaraju if (on) { 99460942c39SRaju Lakkaraju extts_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, index); 99560942c39SRaju Lakkaraju if (extts_pin < 0) 99660942c39SRaju Lakkaraju return -EBUSY; 99760942c39SRaju Lakkaraju 99860942c39SRaju Lakkaraju ret = lan743x_ptp_io_event_cap_en(adapter, flags, index); 99960942c39SRaju Lakkaraju if (!ret) 100060942c39SRaju Lakkaraju extts->flags = flags; 100160942c39SRaju Lakkaraju } else { 100260942c39SRaju Lakkaraju lan743x_ptp_io_extts_off(adapter, index); 100360942c39SRaju Lakkaraju } 100460942c39SRaju Lakkaraju 100560942c39SRaju Lakkaraju return ret; 100660942c39SRaju Lakkaraju } 100760942c39SRaju Lakkaraju 100807624df1SBryan Whitehead static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci, 100907624df1SBryan Whitehead struct ptp_clock_request *request, int on) 101007624df1SBryan Whitehead { 101107624df1SBryan Whitehead struct lan743x_ptp *ptp = 101207624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 101307624df1SBryan Whitehead struct lan743x_adapter *adapter = 101407624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 101507624df1SBryan Whitehead 101607624df1SBryan Whitehead if (request) { 101707624df1SBryan Whitehead switch (request->type) { 101807624df1SBryan Whitehead case PTP_CLK_REQ_EXTTS: 101960942c39SRaju Lakkaraju if (request->extts.index < ptpci->n_ext_ts) 102060942c39SRaju Lakkaraju return lan743x_ptp_io_extts(adapter, on, 102160942c39SRaju Lakkaraju &request->extts); 102207624df1SBryan Whitehead return -EINVAL; 102307624df1SBryan Whitehead case PTP_CLK_REQ_PEROUT: 1024*e432dd3bSRaju Lakkaraju if (request->perout.index < ptpci->n_per_out) { 1025*e432dd3bSRaju Lakkaraju if (adapter->is_pci11x1x) 1026*e432dd3bSRaju Lakkaraju return lan743x_ptp_io_perout(adapter, on, 1027*e432dd3bSRaju Lakkaraju &request->perout); 1028*e432dd3bSRaju Lakkaraju else 102907624df1SBryan Whitehead return lan743x_ptp_perout(adapter, on, 103007624df1SBryan Whitehead &request->perout); 1031*e432dd3bSRaju Lakkaraju } 103207624df1SBryan Whitehead return -EINVAL; 103307624df1SBryan Whitehead case PTP_CLK_REQ_PPS: 103407624df1SBryan Whitehead return -EINVAL; 103507624df1SBryan Whitehead default: 103607624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 103707624df1SBryan Whitehead "request->type == %d, Unknown\n", 103807624df1SBryan Whitehead request->type); 103907624df1SBryan Whitehead break; 104007624df1SBryan Whitehead } 104107624df1SBryan Whitehead } else { 104207624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, "request == NULL\n"); 104307624df1SBryan Whitehead } 104407624df1SBryan Whitehead return 0; 104507624df1SBryan Whitehead } 104607624df1SBryan Whitehead 104722820017SJohn Efstathiades static int lan743x_ptpci_verify_pin_config(struct ptp_clock_info *ptp, 104822820017SJohn Efstathiades unsigned int pin, 104922820017SJohn Efstathiades enum ptp_pin_function func, 105022820017SJohn Efstathiades unsigned int chan) 105122820017SJohn Efstathiades { 105222820017SJohn Efstathiades int result = 0; 105322820017SJohn Efstathiades 105422820017SJohn Efstathiades /* Confirm the requested function is supported. Parameter 105522820017SJohn Efstathiades * validation is done by the caller. 105622820017SJohn Efstathiades */ 105722820017SJohn Efstathiades switch (func) { 105822820017SJohn Efstathiades case PTP_PF_NONE: 105922820017SJohn Efstathiades case PTP_PF_PEROUT: 106022820017SJohn Efstathiades case PTP_PF_EXTTS: 106160942c39SRaju Lakkaraju break; 106222820017SJohn Efstathiades case PTP_PF_PHYSYNC: 106322820017SJohn Efstathiades default: 106422820017SJohn Efstathiades result = -1; 106522820017SJohn Efstathiades break; 106622820017SJohn Efstathiades } 106722820017SJohn Efstathiades return result; 106822820017SJohn Efstathiades } 106922820017SJohn Efstathiades 107060942c39SRaju Lakkaraju static void lan743x_ptp_io_event_clock_get(struct lan743x_adapter *adapter, 107160942c39SRaju Lakkaraju bool fe, u8 channel, 107260942c39SRaju Lakkaraju struct timespec64 *ts) 107360942c39SRaju Lakkaraju { 107460942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 107560942c39SRaju Lakkaraju struct lan743x_extts *extts; 107660942c39SRaju Lakkaraju u32 sec, nsec; 107760942c39SRaju Lakkaraju 107860942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 107960942c39SRaju Lakkaraju if (fe) { 108060942c39SRaju Lakkaraju sec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_SEC_CAP_X); 108160942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_NS_CAP_X); 108260942c39SRaju Lakkaraju } else { 108360942c39SRaju Lakkaraju sec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_SEC_CAP_X); 108460942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_NS_CAP_X); 108560942c39SRaju Lakkaraju } 108660942c39SRaju Lakkaraju 108760942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 108860942c39SRaju Lakkaraju 108960942c39SRaju Lakkaraju /* Update Local timestamp */ 109060942c39SRaju Lakkaraju extts = &ptp->extts[channel]; 109160942c39SRaju Lakkaraju extts->ts.tv_sec = sec; 109260942c39SRaju Lakkaraju extts->ts.tv_nsec = nsec; 109360942c39SRaju Lakkaraju ts->tv_sec = sec; 109460942c39SRaju Lakkaraju ts->tv_nsec = nsec; 109560942c39SRaju Lakkaraju } 109660942c39SRaju Lakkaraju 109707624df1SBryan Whitehead static long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci) 109807624df1SBryan Whitehead { 109907624df1SBryan Whitehead struct lan743x_ptp *ptp = 110007624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 110107624df1SBryan Whitehead struct lan743x_adapter *adapter = 110207624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 110307624df1SBryan Whitehead u32 cap_info, cause, header, nsec, seconds; 110407624df1SBryan Whitehead bool new_timestamp_available = false; 110560942c39SRaju Lakkaraju struct ptp_clock_event ptp_event; 110660942c39SRaju Lakkaraju struct timespec64 ts; 110760942c39SRaju Lakkaraju int ptp_int_sts; 110807624df1SBryan Whitehead int count = 0; 110960942c39SRaju Lakkaraju int channel; 111060942c39SRaju Lakkaraju s64 ns; 111107624df1SBryan Whitehead 111260942c39SRaju Lakkaraju ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 111360942c39SRaju Lakkaraju while ((count < 100) && ptp_int_sts) { 111407624df1SBryan Whitehead count++; 111560942c39SRaju Lakkaraju 111660942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 111707624df1SBryan Whitehead cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO); 111807624df1SBryan Whitehead 111907624df1SBryan Whitehead if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) { 112007624df1SBryan Whitehead seconds = lan743x_csr_read(adapter, 112107624df1SBryan Whitehead PTP_TX_EGRESS_SEC); 112260942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, 112360942c39SRaju Lakkaraju PTP_TX_EGRESS_NS); 112407624df1SBryan Whitehead cause = (nsec & 112507624df1SBryan Whitehead PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_); 112607624df1SBryan Whitehead header = lan743x_csr_read(adapter, 112707624df1SBryan Whitehead PTP_TX_MSG_HEADER); 112807624df1SBryan Whitehead 112960942c39SRaju Lakkaraju if (cause == 113060942c39SRaju Lakkaraju PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) { 113107624df1SBryan Whitehead nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_; 113207624df1SBryan Whitehead lan743x_ptp_tx_ts_enqueue_ts(adapter, 113360942c39SRaju Lakkaraju seconds, 113460942c39SRaju Lakkaraju nsec, 113507624df1SBryan Whitehead header); 113607624df1SBryan Whitehead new_timestamp_available = true; 113707624df1SBryan Whitehead } else if (cause == 113807624df1SBryan Whitehead PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) { 113907624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 114007624df1SBryan Whitehead "Auto capture cause not supported\n"); 114107624df1SBryan Whitehead } else { 114207624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 114307624df1SBryan Whitehead "unknown tx timestamp capture cause\n"); 114407624df1SBryan Whitehead } 114507624df1SBryan Whitehead } else { 114607624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 114707624df1SBryan Whitehead "TX TS INT but no TX TS CNT\n"); 114807624df1SBryan Whitehead } 114960942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 115060942c39SRaju Lakkaraju PTP_INT_BIT_TX_TS_); 115160942c39SRaju Lakkaraju } 115260942c39SRaju Lakkaraju 115360942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_IO_FE_MASK_) { 115460942c39SRaju Lakkaraju do { 115560942c39SRaju Lakkaraju channel = lan743x_get_channel((ptp_int_sts & 115660942c39SRaju Lakkaraju PTP_INT_IO_FE_MASK_) >> 115760942c39SRaju Lakkaraju PTP_INT_IO_FE_SHIFT_); 115860942c39SRaju Lakkaraju if (channel >= 0 && 115960942c39SRaju Lakkaraju channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 116060942c39SRaju Lakkaraju lan743x_ptp_io_event_clock_get(adapter, 116160942c39SRaju Lakkaraju true, 116260942c39SRaju Lakkaraju channel, 116360942c39SRaju Lakkaraju &ts); 116460942c39SRaju Lakkaraju /* PTP Falling Event post */ 116560942c39SRaju Lakkaraju ns = timespec64_to_ns(&ts); 116660942c39SRaju Lakkaraju ptp_event.timestamp = ns; 116760942c39SRaju Lakkaraju ptp_event.index = channel; 116860942c39SRaju Lakkaraju ptp_event.type = PTP_CLOCK_EXTTS; 116960942c39SRaju Lakkaraju ptp_clock_event(ptp->ptp_clock, 117060942c39SRaju Lakkaraju &ptp_event); 117160942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 117260942c39SRaju Lakkaraju PTP_INT_IO_FE_SET_ 117360942c39SRaju Lakkaraju (channel)); 117460942c39SRaju Lakkaraju ptp_int_sts &= ~(1 << 117560942c39SRaju Lakkaraju (PTP_INT_IO_FE_SHIFT_ + 117660942c39SRaju Lakkaraju channel)); 117760942c39SRaju Lakkaraju } else { 117860942c39SRaju Lakkaraju /* Clear falling event interrupts */ 117960942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 118060942c39SRaju Lakkaraju PTP_INT_IO_FE_MASK_); 118160942c39SRaju Lakkaraju ptp_int_sts &= ~PTP_INT_IO_FE_MASK_; 118260942c39SRaju Lakkaraju } 118360942c39SRaju Lakkaraju } while (ptp_int_sts & PTP_INT_IO_FE_MASK_); 118460942c39SRaju Lakkaraju } 118560942c39SRaju Lakkaraju 118660942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_IO_RE_MASK_) { 118760942c39SRaju Lakkaraju do { 118860942c39SRaju Lakkaraju channel = lan743x_get_channel((ptp_int_sts & 118960942c39SRaju Lakkaraju PTP_INT_IO_RE_MASK_) >> 119060942c39SRaju Lakkaraju PTP_INT_IO_RE_SHIFT_); 119160942c39SRaju Lakkaraju if (channel >= 0 && 119260942c39SRaju Lakkaraju channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 119360942c39SRaju Lakkaraju lan743x_ptp_io_event_clock_get(adapter, 119460942c39SRaju Lakkaraju false, 119560942c39SRaju Lakkaraju channel, 119660942c39SRaju Lakkaraju &ts); 119760942c39SRaju Lakkaraju /* PTP Rising Event post */ 119860942c39SRaju Lakkaraju ns = timespec64_to_ns(&ts); 119960942c39SRaju Lakkaraju ptp_event.timestamp = ns; 120060942c39SRaju Lakkaraju ptp_event.index = channel; 120160942c39SRaju Lakkaraju ptp_event.type = PTP_CLOCK_EXTTS; 120260942c39SRaju Lakkaraju ptp_clock_event(ptp->ptp_clock, 120360942c39SRaju Lakkaraju &ptp_event); 120460942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 120560942c39SRaju Lakkaraju PTP_INT_IO_RE_SET_ 120660942c39SRaju Lakkaraju (channel)); 120760942c39SRaju Lakkaraju ptp_int_sts &= ~(1 << 120860942c39SRaju Lakkaraju (PTP_INT_IO_RE_SHIFT_ + 120960942c39SRaju Lakkaraju channel)); 121060942c39SRaju Lakkaraju } else { 121160942c39SRaju Lakkaraju /* Clear Rising event interrupt */ 121260942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 121360942c39SRaju Lakkaraju PTP_INT_IO_RE_MASK_); 121460942c39SRaju Lakkaraju ptp_int_sts &= ~PTP_INT_IO_RE_MASK_; 121560942c39SRaju Lakkaraju } 121660942c39SRaju Lakkaraju } while (ptp_int_sts & PTP_INT_IO_RE_MASK_); 121760942c39SRaju Lakkaraju } 121860942c39SRaju Lakkaraju 121960942c39SRaju Lakkaraju ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 122007624df1SBryan Whitehead } 122107624df1SBryan Whitehead 122207624df1SBryan Whitehead if (new_timestamp_available) 122307624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 122407624df1SBryan Whitehead 122507624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 122607624df1SBryan Whitehead 122707624df1SBryan Whitehead return -1; 122807624df1SBryan Whitehead } 122907624df1SBryan Whitehead 123007624df1SBryan Whitehead static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, 123107624df1SBryan Whitehead u32 *seconds, u32 *nano_seconds, 123207624df1SBryan Whitehead u32 *sub_nano_seconds) 123307624df1SBryan Whitehead { 123407624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 123507624df1SBryan Whitehead 123607624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 123707624df1SBryan Whitehead 123807624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 123907624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 124007624df1SBryan Whitehead 124107624df1SBryan Whitehead if (seconds) 124207624df1SBryan Whitehead (*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC); 124307624df1SBryan Whitehead 124407624df1SBryan Whitehead if (nano_seconds) 124507624df1SBryan Whitehead (*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS); 124607624df1SBryan Whitehead 124707624df1SBryan Whitehead if (sub_nano_seconds) 124807624df1SBryan Whitehead (*sub_nano_seconds) = 124907624df1SBryan Whitehead lan743x_csr_read(adapter, PTP_CLOCK_SUBNS); 125007624df1SBryan Whitehead 125107624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 125207624df1SBryan Whitehead } 125307624df1SBryan Whitehead 125460942c39SRaju Lakkaraju static void lan743x_ptp_io_clock_get(struct lan743x_adapter *adapter, 125560942c39SRaju Lakkaraju u32 *sec, u32 *nsec, u32 *sub_nsec) 125660942c39SRaju Lakkaraju { 125760942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 125860942c39SRaju Lakkaraju 125960942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 126060942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 126160942c39SRaju Lakkaraju lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 126260942c39SRaju Lakkaraju 126360942c39SRaju Lakkaraju if (sec) 126460942c39SRaju Lakkaraju (*sec) = lan743x_csr_read(adapter, PTP_LTC_RD_SEC_LO); 126560942c39SRaju Lakkaraju 126660942c39SRaju Lakkaraju if (nsec) 126760942c39SRaju Lakkaraju (*nsec) = lan743x_csr_read(adapter, PTP_LTC_RD_NS); 126860942c39SRaju Lakkaraju 126960942c39SRaju Lakkaraju if (sub_nsec) 127060942c39SRaju Lakkaraju (*sub_nsec) = 127160942c39SRaju Lakkaraju lan743x_csr_read(adapter, PTP_LTC_RD_SUBNS); 127260942c39SRaju Lakkaraju 127360942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 127460942c39SRaju Lakkaraju } 127560942c39SRaju Lakkaraju 127607624df1SBryan Whitehead static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, 127707624df1SBryan Whitehead s64 time_step_ns) 127807624df1SBryan Whitehead { 127907624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 128007624df1SBryan Whitehead u32 nano_seconds_step = 0; 128107624df1SBryan Whitehead u64 abs_time_step_ns = 0; 128207624df1SBryan Whitehead u32 unsigned_seconds = 0; 128307624df1SBryan Whitehead u32 nano_seconds = 0; 128407624df1SBryan Whitehead u32 remainder = 0; 128507624df1SBryan Whitehead s32 seconds = 0; 128607624df1SBryan Whitehead 128707624df1SBryan Whitehead if (time_step_ns > 15000000000LL) { 128807624df1SBryan Whitehead /* convert to clock set */ 128960942c39SRaju Lakkaraju if (adapter->is_pci11x1x) 129060942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 129160942c39SRaju Lakkaraju &nano_seconds, NULL); 129260942c39SRaju Lakkaraju else 129307624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &unsigned_seconds, 129407624df1SBryan Whitehead &nano_seconds, NULL); 129507624df1SBryan Whitehead unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL, 129607624df1SBryan Whitehead &remainder); 129707624df1SBryan Whitehead nano_seconds += remainder; 129807624df1SBryan Whitehead if (nano_seconds >= 1000000000) { 129907624df1SBryan Whitehead unsigned_seconds++; 130007624df1SBryan Whitehead nano_seconds -= 1000000000; 130107624df1SBryan Whitehead } 130207624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, unsigned_seconds, 130307624df1SBryan Whitehead nano_seconds, 0); 130407624df1SBryan Whitehead return; 130507624df1SBryan Whitehead } else if (time_step_ns < -15000000000LL) { 130607624df1SBryan Whitehead /* convert to clock set */ 130707624df1SBryan Whitehead time_step_ns = -time_step_ns; 130807624df1SBryan Whitehead 130960942c39SRaju Lakkaraju if (adapter->is_pci11x1x) { 131060942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 131160942c39SRaju Lakkaraju &nano_seconds, NULL); 131260942c39SRaju Lakkaraju } else { 131307624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &unsigned_seconds, 131407624df1SBryan Whitehead &nano_seconds, NULL); 131560942c39SRaju Lakkaraju } 131607624df1SBryan Whitehead unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL, 131707624df1SBryan Whitehead &remainder); 131807624df1SBryan Whitehead nano_seconds_step = remainder; 131907624df1SBryan Whitehead if (nano_seconds < nano_seconds_step) { 132007624df1SBryan Whitehead unsigned_seconds--; 132107624df1SBryan Whitehead nano_seconds += 1000000000; 132207624df1SBryan Whitehead } 132307624df1SBryan Whitehead nano_seconds -= nano_seconds_step; 132407624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, unsigned_seconds, 132507624df1SBryan Whitehead nano_seconds, 0); 132607624df1SBryan Whitehead return; 132707624df1SBryan Whitehead } 132807624df1SBryan Whitehead 132907624df1SBryan Whitehead /* do clock step */ 133007624df1SBryan Whitehead if (time_step_ns >= 0) { 133107624df1SBryan Whitehead abs_time_step_ns = (u64)(time_step_ns); 133207624df1SBryan Whitehead seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000, 133307624df1SBryan Whitehead &remainder); 133407624df1SBryan Whitehead nano_seconds = (u32)remainder; 133507624df1SBryan Whitehead } else { 133607624df1SBryan Whitehead abs_time_step_ns = (u64)(-time_step_ns); 133707624df1SBryan Whitehead seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000, 133807624df1SBryan Whitehead &remainder)); 133907624df1SBryan Whitehead nano_seconds = (u32)remainder; 134007624df1SBryan Whitehead if (nano_seconds > 0) { 134107624df1SBryan Whitehead /* subtracting nano seconds is not allowed 134207624df1SBryan Whitehead * convert to subtracting from seconds, 134307624df1SBryan Whitehead * and adding to nanoseconds 134407624df1SBryan Whitehead */ 134507624df1SBryan Whitehead seconds--; 134607624df1SBryan Whitehead nano_seconds = (1000000000 - nano_seconds); 134707624df1SBryan Whitehead } 134807624df1SBryan Whitehead } 134907624df1SBryan Whitehead 135007624df1SBryan Whitehead if (nano_seconds > 0) { 135107624df1SBryan Whitehead /* add 8 ns to cover the likely normal increment */ 135207624df1SBryan Whitehead nano_seconds += 8; 135307624df1SBryan Whitehead } 135407624df1SBryan Whitehead 135507624df1SBryan Whitehead if (nano_seconds >= 1000000000) { 135607624df1SBryan Whitehead /* carry into seconds */ 135707624df1SBryan Whitehead seconds++; 135807624df1SBryan Whitehead nano_seconds -= 1000000000; 135907624df1SBryan Whitehead } 136007624df1SBryan Whitehead 136107624df1SBryan Whitehead while (seconds) { 136207624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 136307624df1SBryan Whitehead if (seconds > 0) { 136407624df1SBryan Whitehead u32 adjustment_value = (u32)seconds; 136507624df1SBryan Whitehead 136607624df1SBryan Whitehead if (adjustment_value > 0xF) 136707624df1SBryan Whitehead adjustment_value = 0xF; 136807624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 136907624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_DIR_ | 137007624df1SBryan Whitehead adjustment_value); 137107624df1SBryan Whitehead seconds -= ((s32)adjustment_value); 137207624df1SBryan Whitehead } else { 137307624df1SBryan Whitehead u32 adjustment_value = (u32)(-seconds); 137407624df1SBryan Whitehead 137507624df1SBryan Whitehead if (adjustment_value > 0xF) 137607624df1SBryan Whitehead adjustment_value = 0xF; 137707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 137807624df1SBryan Whitehead adjustment_value); 137907624df1SBryan Whitehead seconds += ((s32)adjustment_value); 138007624df1SBryan Whitehead } 138107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, 138207624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 138307624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, 138407624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 138507624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 138607624df1SBryan Whitehead } 138707624df1SBryan Whitehead if (nano_seconds) { 138807624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 138907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 139007624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_DIR_ | 139107624df1SBryan Whitehead (nano_seconds & 139207624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_VALUE_MASK_)); 139307624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, 139407624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 139507624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, 139607624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 139707624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 139807624df1SBryan Whitehead } 139907624df1SBryan Whitehead } 140007624df1SBryan Whitehead 140107624df1SBryan Whitehead void lan743x_ptp_isr(void *context) 140207624df1SBryan Whitehead { 140307624df1SBryan Whitehead struct lan743x_adapter *adapter = (struct lan743x_adapter *)context; 140407624df1SBryan Whitehead struct lan743x_ptp *ptp = NULL; 140507624df1SBryan Whitehead int enable_flag = 1; 140607624df1SBryan Whitehead u32 ptp_int_sts = 0; 140707624df1SBryan Whitehead 140807624df1SBryan Whitehead ptp = &adapter->ptp; 140907624df1SBryan Whitehead 141007624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 141107624df1SBryan Whitehead 141207624df1SBryan Whitehead ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 141307624df1SBryan Whitehead ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET); 141407624df1SBryan Whitehead 141507624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 141607624df1SBryan Whitehead ptp_schedule_worker(ptp->ptp_clock, 0); 141707624df1SBryan Whitehead enable_flag = 0;/* tasklet will re-enable later */ 141807624df1SBryan Whitehead } 141907624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) { 142007624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 142107624df1SBryan Whitehead "PTP TX Software Timestamp Error\n"); 142207624df1SBryan Whitehead /* clear int status bit */ 142307624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 142407624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_); 142507624df1SBryan Whitehead } 142607624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) { 142707624df1SBryan Whitehead /* clear int status bit */ 142807624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 142907624df1SBryan Whitehead PTP_INT_BIT_TIMER_B_); 143007624df1SBryan Whitehead } 143107624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) { 143207624df1SBryan Whitehead /* clear int status bit */ 143307624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 143407624df1SBryan Whitehead PTP_INT_BIT_TIMER_A_); 143507624df1SBryan Whitehead } 143607624df1SBryan Whitehead 143707624df1SBryan Whitehead if (enable_flag) { 143807624df1SBryan Whitehead /* re-enable isr */ 143907624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 144007624df1SBryan Whitehead } 144107624df1SBryan Whitehead } 144207624df1SBryan Whitehead 144307624df1SBryan Whitehead static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter, 144407624df1SBryan Whitehead struct sk_buff *skb, bool ignore_sync) 144507624df1SBryan Whitehead { 144607624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 144707624df1SBryan Whitehead 144807624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 144907624df1SBryan Whitehead if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 145007624df1SBryan Whitehead ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb; 145107624df1SBryan Whitehead if (ignore_sync) 145207624df1SBryan Whitehead ptp->tx_ts_ignore_sync_queue |= 145307624df1SBryan Whitehead BIT(ptp->tx_ts_skb_queue_size); 145407624df1SBryan Whitehead ptp->tx_ts_skb_queue_size++; 145507624df1SBryan Whitehead } else { 145607624df1SBryan Whitehead /* this should never happen, so long as the tx channel 145707624df1SBryan Whitehead * calls and honors the result from 145807624df1SBryan Whitehead * lan743x_ptp_request_tx_timestamp 145907624df1SBryan Whitehead */ 146007624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 146107624df1SBryan Whitehead "tx ts skb queue overflow\n"); 146207624df1SBryan Whitehead dev_kfree_skb(skb); 146307624df1SBryan Whitehead } 146407624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 146507624df1SBryan Whitehead } 146607624df1SBryan Whitehead 146707624df1SBryan Whitehead static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter) 146807624df1SBryan Whitehead { 146907624df1SBryan Whitehead struct timespec64 ts; 147007624df1SBryan Whitehead 14710b3e776eSArnd Bergmann ktime_get_clocktai_ts64(&ts); 147207624df1SBryan Whitehead 147307624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0); 147407624df1SBryan Whitehead } 147507624df1SBryan Whitehead 147607624df1SBryan Whitehead void lan743x_ptp_update_latency(struct lan743x_adapter *adapter, 147707624df1SBryan Whitehead u32 link_speed) 147807624df1SBryan Whitehead { 147907624df1SBryan Whitehead switch (link_speed) { 148007624df1SBryan Whitehead case 10: 148107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 148207624df1SBryan Whitehead PTP_LATENCY_TX_SET_(0) | 148307624df1SBryan Whitehead PTP_LATENCY_RX_SET_(0)); 148407624df1SBryan Whitehead break; 148507624df1SBryan Whitehead case 100: 148607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 148707624df1SBryan Whitehead PTP_LATENCY_TX_SET_(181) | 148807624df1SBryan Whitehead PTP_LATENCY_RX_SET_(594)); 148907624df1SBryan Whitehead break; 149007624df1SBryan Whitehead case 1000: 149107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 149207624df1SBryan Whitehead PTP_LATENCY_TX_SET_(30) | 149307624df1SBryan Whitehead PTP_LATENCY_RX_SET_(525)); 149407624df1SBryan Whitehead break; 149507624df1SBryan Whitehead } 149607624df1SBryan Whitehead } 149707624df1SBryan Whitehead 149807624df1SBryan Whitehead int lan743x_ptp_init(struct lan743x_adapter *adapter) 149907624df1SBryan Whitehead { 150007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 150122820017SJohn Efstathiades int i; 150207624df1SBryan Whitehead 150307624df1SBryan Whitehead mutex_init(&ptp->command_lock); 150407624df1SBryan Whitehead spin_lock_init(&ptp->tx_ts_lock); 150507624df1SBryan Whitehead ptp->used_event_ch = 0; 150622820017SJohn Efstathiades 150722820017SJohn Efstathiades for (i = 0; i < LAN743X_PTP_N_EVENT_CHAN; i++) { 150822820017SJohn Efstathiades ptp->perout[i].event_ch = -1; 150922820017SJohn Efstathiades ptp->perout[i].gpio_pin = -1; 151022820017SJohn Efstathiades } 151122820017SJohn Efstathiades 151222820017SJohn Efstathiades lan743x_led_mux_save(adapter); 151322820017SJohn Efstathiades 151407624df1SBryan Whitehead return 0; 151507624df1SBryan Whitehead } 151607624df1SBryan Whitehead 151707624df1SBryan Whitehead int lan743x_ptp_open(struct lan743x_adapter *adapter) 151807624df1SBryan Whitehead { 151907624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 152007624df1SBryan Whitehead int ret = -ENODEV; 152107624df1SBryan Whitehead u32 temp; 152222820017SJohn Efstathiades int i; 152322820017SJohn Efstathiades int n_pins; 152407624df1SBryan Whitehead 152507624df1SBryan Whitehead lan743x_ptp_reset(adapter); 152607624df1SBryan Whitehead lan743x_ptp_sync_to_system_clock(adapter); 152707624df1SBryan Whitehead temp = lan743x_csr_read(adapter, PTP_TX_MOD2); 152807624df1SBryan Whitehead temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_; 152907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_TX_MOD2, temp); 153007624df1SBryan Whitehead lan743x_ptp_enable(adapter); 153107624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 153207624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_EN_SET, 153307624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_); 153407624df1SBryan Whitehead ptp->flags |= PTP_FLAG_ISR_ENABLED; 153507624df1SBryan Whitehead 15369dc502d7SArnd Bergmann if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK)) 15379dc502d7SArnd Bergmann return 0; 15389dc502d7SArnd Bergmann 153922820017SJohn Efstathiades switch (adapter->csr.id_rev & ID_REV_ID_MASK_) { 154022820017SJohn Efstathiades case ID_REV_ID_LAN7430_: 154122820017SJohn Efstathiades n_pins = LAN7430_N_GPIO; 154222820017SJohn Efstathiades break; 154322820017SJohn Efstathiades case ID_REV_ID_LAN7431_: 154460942c39SRaju Lakkaraju case ID_REV_ID_A011_: 154560942c39SRaju Lakkaraju case ID_REV_ID_A041_: 154622820017SJohn Efstathiades n_pins = LAN7431_N_GPIO; 154722820017SJohn Efstathiades break; 154822820017SJohn Efstathiades default: 154922820017SJohn Efstathiades netif_warn(adapter, drv, adapter->netdev, 155022820017SJohn Efstathiades "Unknown LAN743x (%08x). Assuming no GPIO\n", 155122820017SJohn Efstathiades adapter->csr.id_rev); 155222820017SJohn Efstathiades n_pins = 0; 155322820017SJohn Efstathiades break; 155422820017SJohn Efstathiades } 155522820017SJohn Efstathiades 155622820017SJohn Efstathiades if (n_pins > LAN743X_PTP_N_GPIO) 155722820017SJohn Efstathiades n_pins = LAN743X_PTP_N_GPIO; 155822820017SJohn Efstathiades 155922820017SJohn Efstathiades for (i = 0; i < n_pins; i++) { 156022820017SJohn Efstathiades struct ptp_pin_desc *ptp_pin = &ptp->pin_config[i]; 156122820017SJohn Efstathiades 156222820017SJohn Efstathiades snprintf(ptp_pin->name, 156322820017SJohn Efstathiades sizeof(ptp_pin->name), "lan743x_ptp_pin_%02d", i); 156422820017SJohn Efstathiades ptp_pin->index = i; 156522820017SJohn Efstathiades ptp_pin->func = PTP_PF_NONE; 156622820017SJohn Efstathiades } 156707624df1SBryan Whitehead 156807624df1SBryan Whitehead ptp->ptp_clock_info.owner = THIS_MODULE; 156907624df1SBryan Whitehead snprintf(ptp->ptp_clock_info.name, 16, "%pm", 157007624df1SBryan Whitehead adapter->netdev->dev_addr); 157107624df1SBryan Whitehead ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB; 157207624df1SBryan Whitehead ptp->ptp_clock_info.n_alarm = 0; 157360942c39SRaju Lakkaraju ptp->ptp_clock_info.n_ext_ts = LAN743X_PTP_N_EXTTS; 157422820017SJohn Efstathiades ptp->ptp_clock_info.n_per_out = LAN743X_PTP_N_EVENT_CHAN; 157522820017SJohn Efstathiades ptp->ptp_clock_info.n_pins = n_pins; 157660942c39SRaju Lakkaraju ptp->ptp_clock_info.pps = LAN743X_PTP_N_PPS; 157722820017SJohn Efstathiades ptp->ptp_clock_info.pin_config = ptp->pin_config; 157807624df1SBryan Whitehead ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine; 157907624df1SBryan Whitehead ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq; 158007624df1SBryan Whitehead ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime; 158107624df1SBryan Whitehead ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64; 158207624df1SBryan Whitehead ptp->ptp_clock_info.getcrosststamp = NULL; 158307624df1SBryan Whitehead ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64; 158407624df1SBryan Whitehead ptp->ptp_clock_info.enable = lan743x_ptpci_enable; 158507624df1SBryan Whitehead ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work; 158622820017SJohn Efstathiades ptp->ptp_clock_info.verify = lan743x_ptpci_verify_pin_config; 158707624df1SBryan Whitehead 158807624df1SBryan Whitehead ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info, 158907624df1SBryan Whitehead &adapter->pdev->dev); 159007624df1SBryan Whitehead 159107624df1SBryan Whitehead if (IS_ERR(ptp->ptp_clock)) { 159207624df1SBryan Whitehead netif_err(adapter, ifup, adapter->netdev, 159307624df1SBryan Whitehead "ptp_clock_register failed\n"); 159407624df1SBryan Whitehead goto done; 159507624df1SBryan Whitehead } 159607624df1SBryan Whitehead ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED; 159707624df1SBryan Whitehead netif_info(adapter, ifup, adapter->netdev, 159807624df1SBryan Whitehead "successfully registered ptp clock\n"); 159907624df1SBryan Whitehead 160007624df1SBryan Whitehead return 0; 160107624df1SBryan Whitehead done: 160207624df1SBryan Whitehead lan743x_ptp_close(adapter); 160307624df1SBryan Whitehead return ret; 160407624df1SBryan Whitehead } 160507624df1SBryan Whitehead 160607624df1SBryan Whitehead void lan743x_ptp_close(struct lan743x_adapter *adapter) 160707624df1SBryan Whitehead { 160807624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 160907624df1SBryan Whitehead int index; 161007624df1SBryan Whitehead 16119dc502d7SArnd Bergmann if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) && 161222820017SJohn Efstathiades (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED)) { 161307624df1SBryan Whitehead ptp_clock_unregister(ptp->ptp_clock); 161407624df1SBryan Whitehead ptp->ptp_clock = NULL; 161507624df1SBryan Whitehead ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED; 161607624df1SBryan Whitehead netif_info(adapter, drv, adapter->netdev, 161707624df1SBryan Whitehead "ptp clock unregister\n"); 161807624df1SBryan Whitehead } 161907624df1SBryan Whitehead 162007624df1SBryan Whitehead if (ptp->flags & PTP_FLAG_ISR_ENABLED) { 162107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_EN_CLR, 162207624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_ | 162307624df1SBryan Whitehead PTP_INT_BIT_TX_TS_); 162407624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 162507624df1SBryan Whitehead ptp->flags &= ~PTP_FLAG_ISR_ENABLED; 162607624df1SBryan Whitehead } 162707624df1SBryan Whitehead 162807624df1SBryan Whitehead /* clean up pending timestamp requests */ 162907624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 163007624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 163107624df1SBryan Whitehead for (index = 0; 163207624df1SBryan Whitehead index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; 163307624df1SBryan Whitehead index++) { 163407624df1SBryan Whitehead struct sk_buff *skb = ptp->tx_ts_skb_queue[index]; 163507624df1SBryan Whitehead 163607624df1SBryan Whitehead dev_kfree_skb(skb); 163707624df1SBryan Whitehead ptp->tx_ts_skb_queue[index] = NULL; 163807624df1SBryan Whitehead ptp->tx_ts_seconds_queue[index] = 0; 163907624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[index] = 0; 164007624df1SBryan Whitehead } 164107624df1SBryan Whitehead ptp->tx_ts_skb_queue_size = 0; 164207624df1SBryan Whitehead ptp->tx_ts_queue_size = 0; 164307624df1SBryan Whitehead ptp->pending_tx_timestamps = 0; 164407624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 164507624df1SBryan Whitehead 164622820017SJohn Efstathiades lan743x_led_mux_restore(adapter); 164722820017SJohn Efstathiades 164807624df1SBryan Whitehead lan743x_ptp_disable(adapter); 164907624df1SBryan Whitehead } 165007624df1SBryan Whitehead 165105dcc712SYueHaibing static void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter, 165207624df1SBryan Whitehead bool ts_insert_enable) 165307624df1SBryan Whitehead { 165407624df1SBryan Whitehead u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD); 165507624df1SBryan Whitehead 165607624df1SBryan Whitehead if (ts_insert_enable) 165707624df1SBryan Whitehead ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 165807624df1SBryan Whitehead else 165907624df1SBryan Whitehead ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 166007624df1SBryan Whitehead 166107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod); 166207624df1SBryan Whitehead } 166307624df1SBryan Whitehead 166407624df1SBryan Whitehead static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter) 166507624df1SBryan Whitehead { 166607624df1SBryan Whitehead if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_) 166707624df1SBryan Whitehead return true; 166807624df1SBryan Whitehead return false; 166907624df1SBryan Whitehead } 167007624df1SBryan Whitehead 167107624df1SBryan Whitehead static void lan743x_ptp_enable(struct lan743x_adapter *adapter) 167207624df1SBryan Whitehead { 167307624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 167407624df1SBryan Whitehead 167507624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 167607624df1SBryan Whitehead 167707624df1SBryan Whitehead if (lan743x_ptp_is_enabled(adapter)) { 167807624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 167907624df1SBryan Whitehead "PTP already enabled\n"); 168007624df1SBryan Whitehead goto done; 168107624df1SBryan Whitehead } 168207624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_); 168307624df1SBryan Whitehead done: 168407624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 168507624df1SBryan Whitehead } 168607624df1SBryan Whitehead 168707624df1SBryan Whitehead static void lan743x_ptp_disable(struct lan743x_adapter *adapter) 168807624df1SBryan Whitehead { 168907624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 169007624df1SBryan Whitehead 169107624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 169207624df1SBryan Whitehead if (!lan743x_ptp_is_enabled(adapter)) { 169307624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 169407624df1SBryan Whitehead "PTP already disabled\n"); 169507624df1SBryan Whitehead goto done; 169607624df1SBryan Whitehead } 169707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_); 169807624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_); 169907624df1SBryan Whitehead done: 170007624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 170107624df1SBryan Whitehead } 170207624df1SBryan Whitehead 170307624df1SBryan Whitehead static void lan743x_ptp_reset(struct lan743x_adapter *adapter) 170407624df1SBryan Whitehead { 170507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 170607624df1SBryan Whitehead 170707624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 170807624df1SBryan Whitehead 170907624df1SBryan Whitehead if (lan743x_ptp_is_enabled(adapter)) { 171007624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 171107624df1SBryan Whitehead "Attempting reset while enabled\n"); 171207624df1SBryan Whitehead goto done; 171307624df1SBryan Whitehead } 171407624df1SBryan Whitehead 171507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_); 171607624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_); 171707624df1SBryan Whitehead done: 171807624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 171907624df1SBryan Whitehead } 172007624df1SBryan Whitehead 172107624df1SBryan Whitehead static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter, 172207624df1SBryan Whitehead u32 seconds, u32 nano_seconds, 172307624df1SBryan Whitehead u32 sub_nano_seconds) 172407624df1SBryan Whitehead { 172507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 172607624df1SBryan Whitehead 172707624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 172807624df1SBryan Whitehead 172907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds); 173007624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds); 173107624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds); 173207624df1SBryan Whitehead 173307624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 173407624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 173507624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 173607624df1SBryan Whitehead } 173707624df1SBryan Whitehead 173807624df1SBryan Whitehead bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter) 173907624df1SBryan Whitehead { 174007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 174107624df1SBryan Whitehead bool result = false; 174207624df1SBryan Whitehead 174307624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 174407624df1SBryan Whitehead if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 174507624df1SBryan Whitehead /* request granted */ 174607624df1SBryan Whitehead ptp->pending_tx_timestamps++; 174707624df1SBryan Whitehead result = true; 174807624df1SBryan Whitehead } 174907624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 175007624df1SBryan Whitehead return result; 175107624df1SBryan Whitehead } 175207624df1SBryan Whitehead 175307624df1SBryan Whitehead void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter) 175407624df1SBryan Whitehead { 175507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 175607624df1SBryan Whitehead 175707624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 175807624df1SBryan Whitehead if (ptp->pending_tx_timestamps > 0) 175907624df1SBryan Whitehead ptp->pending_tx_timestamps--; 176007624df1SBryan Whitehead else 176107624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 176207624df1SBryan Whitehead "unrequest failed, pending_tx_timestamps==0\n"); 176307624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 176407624df1SBryan Whitehead } 176507624df1SBryan Whitehead 176607624df1SBryan Whitehead void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter, 176707624df1SBryan Whitehead struct sk_buff *skb, bool ignore_sync) 176807624df1SBryan Whitehead { 176907624df1SBryan Whitehead lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync); 177007624df1SBryan Whitehead 177107624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 177207624df1SBryan Whitehead } 177307624df1SBryan Whitehead 177407624df1SBryan Whitehead int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 177507624df1SBryan Whitehead { 177607624df1SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev); 177707624df1SBryan Whitehead struct hwtstamp_config config; 177807624df1SBryan Whitehead int ret = 0; 177907624df1SBryan Whitehead int index; 178007624df1SBryan Whitehead 178107624df1SBryan Whitehead if (!ifr) { 178207624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 178307624df1SBryan Whitehead "SIOCSHWTSTAMP, ifr == NULL\n"); 178407624df1SBryan Whitehead return -EINVAL; 178507624df1SBryan Whitehead } 178607624df1SBryan Whitehead 178707624df1SBryan Whitehead if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 178807624df1SBryan Whitehead return -EFAULT; 178907624df1SBryan Whitehead 179007624df1SBryan Whitehead switch (config.tx_type) { 179107624df1SBryan Whitehead case HWTSTAMP_TX_OFF: 1792cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 179307624df1SBryan Whitehead index++) 179407624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 179507624df1SBryan Whitehead false, false); 179607624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, false); 179707624df1SBryan Whitehead break; 179807624df1SBryan Whitehead case HWTSTAMP_TX_ON: 1799cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 180007624df1SBryan Whitehead index++) 180107624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 180207624df1SBryan Whitehead true, false); 180307624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, false); 180407624df1SBryan Whitehead break; 180507624df1SBryan Whitehead case HWTSTAMP_TX_ONESTEP_SYNC: 1806cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 180707624df1SBryan Whitehead index++) 180807624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 180907624df1SBryan Whitehead true, true); 181007624df1SBryan Whitehead 181107624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, true); 181207624df1SBryan Whitehead break; 1813b6fd7b96SRichard Cochran case HWTSTAMP_TX_ONESTEP_P2P: 1814b6fd7b96SRichard Cochran ret = -ERANGE; 1815b6fd7b96SRichard Cochran break; 181607624df1SBryan Whitehead default: 181707624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 181807624df1SBryan Whitehead " tx_type = %d, UNKNOWN\n", config.tx_type); 181907624df1SBryan Whitehead ret = -EINVAL; 182007624df1SBryan Whitehead break; 182107624df1SBryan Whitehead } 182207624df1SBryan Whitehead 182307624df1SBryan Whitehead if (!ret) 182407624df1SBryan Whitehead return copy_to_user(ifr->ifr_data, &config, 182507624df1SBryan Whitehead sizeof(config)) ? -EFAULT : 0; 182607624df1SBryan Whitehead return ret; 182707624df1SBryan Whitehead } 1828