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; 342*8bc900cbSJacob Keller u64 u64_delta; 34307624df1SBryan Whitehead 34407624df1SBryan Whitehead if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) || 34507624df1SBryan Whitehead scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) { 34607624df1SBryan Whitehead return -EINVAL; 34707624df1SBryan Whitehead } 34807624df1SBryan Whitehead 349*8bc900cbSJacob Keller /* diff_by_scaled_ppm returns true if the difference is negative */ 350*8bc900cbSJacob Keller if (diff_by_scaled_ppm(1ULL << 35, scaled_ppm, &u64_delta)) 351*8bc900cbSJacob Keller lan743x_rate_adj = (u32)u64_delta; 352*8bc900cbSJacob Keller else 353*8bc900cbSJacob Keller lan743x_rate_adj = (u32)u64_delta | PTP_CLOCK_RATE_ADJ_DIR_; 35407624df1SBryan Whitehead 35507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ, 35607624df1SBryan Whitehead lan743x_rate_adj); 35707624df1SBryan Whitehead 35807624df1SBryan Whitehead return 0; 35907624df1SBryan Whitehead } 36007624df1SBryan Whitehead 36107624df1SBryan Whitehead static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta) 36207624df1SBryan Whitehead { 36307624df1SBryan Whitehead struct lan743x_ptp *ptp = 36407624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 36507624df1SBryan Whitehead struct lan743x_adapter *adapter = 36607624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 36707624df1SBryan Whitehead 36807624df1SBryan Whitehead lan743x_ptp_clock_step(adapter, delta); 36907624df1SBryan Whitehead 37007624df1SBryan Whitehead return 0; 37107624df1SBryan Whitehead } 37207624df1SBryan Whitehead 37307624df1SBryan Whitehead static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci, 37407624df1SBryan Whitehead struct timespec64 *ts) 37507624df1SBryan Whitehead { 37607624df1SBryan Whitehead struct lan743x_ptp *ptp = 37707624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 37807624df1SBryan Whitehead struct lan743x_adapter *adapter = 37907624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 38007624df1SBryan Whitehead u32 nano_seconds = 0; 38107624df1SBryan Whitehead u32 seconds = 0; 38207624df1SBryan Whitehead 38360942c39SRaju Lakkaraju if (adapter->is_pci11x1x) 38460942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &seconds, &nano_seconds, 38560942c39SRaju Lakkaraju NULL); 38660942c39SRaju Lakkaraju else 38707624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL); 38807624df1SBryan Whitehead ts->tv_sec = seconds; 38907624df1SBryan Whitehead ts->tv_nsec = nano_seconds; 39007624df1SBryan Whitehead 39107624df1SBryan Whitehead return 0; 39207624df1SBryan Whitehead } 39307624df1SBryan Whitehead 39407624df1SBryan Whitehead static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci, 39507624df1SBryan Whitehead const struct timespec64 *ts) 39607624df1SBryan Whitehead { 39707624df1SBryan Whitehead struct lan743x_ptp *ptp = 39807624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 39907624df1SBryan Whitehead struct lan743x_adapter *adapter = 40007624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 40107624df1SBryan Whitehead u32 nano_seconds = 0; 40207624df1SBryan Whitehead u32 seconds = 0; 40307624df1SBryan Whitehead 40407624df1SBryan Whitehead if (ts) { 40507624df1SBryan Whitehead if (ts->tv_sec > 0xFFFFFFFFLL || 40607624df1SBryan Whitehead ts->tv_sec < 0) { 40707624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 40807624df1SBryan Whitehead "ts->tv_sec out of range, %lld\n", 40907624df1SBryan Whitehead ts->tv_sec); 41007624df1SBryan Whitehead return -ERANGE; 41107624df1SBryan Whitehead } 41207624df1SBryan Whitehead if (ts->tv_nsec >= 1000000000L || 41307624df1SBryan Whitehead ts->tv_nsec < 0) { 41407624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 41507624df1SBryan Whitehead "ts->tv_nsec out of range, %ld\n", 41607624df1SBryan Whitehead ts->tv_nsec); 41707624df1SBryan Whitehead return -ERANGE; 41807624df1SBryan Whitehead } 41907624df1SBryan Whitehead seconds = ts->tv_sec; 42007624df1SBryan Whitehead nano_seconds = ts->tv_nsec; 42107624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0); 42207624df1SBryan Whitehead } else { 42307624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n"); 42407624df1SBryan Whitehead return -EINVAL; 42507624df1SBryan Whitehead } 42607624df1SBryan Whitehead 42707624df1SBryan Whitehead return 0; 42807624df1SBryan Whitehead } 42907624df1SBryan Whitehead 43022820017SJohn Efstathiades static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter, 43122820017SJohn Efstathiades unsigned int index) 43207624df1SBryan Whitehead { 43307624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 43407624df1SBryan Whitehead u32 general_config = 0; 43522820017SJohn Efstathiades struct lan743x_ptp_perout *perout = &ptp->perout[index]; 43607624df1SBryan Whitehead 43722820017SJohn Efstathiades if (perout->gpio_pin >= 0) { 43822820017SJohn Efstathiades lan743x_gpio_release(adapter, perout->gpio_pin); 43922820017SJohn Efstathiades perout->gpio_pin = -1; 44007624df1SBryan Whitehead } 44107624df1SBryan Whitehead 44222820017SJohn Efstathiades if (perout->event_ch >= 0) { 44307624df1SBryan Whitehead /* set target to far in the future, effectively disabling it */ 44407624df1SBryan Whitehead lan743x_csr_write(adapter, 44522820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 44607624df1SBryan Whitehead 0xFFFF0000); 44707624df1SBryan Whitehead lan743x_csr_write(adapter, 44822820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 44907624df1SBryan Whitehead 0); 45007624df1SBryan Whitehead 45107624df1SBryan Whitehead general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 45207624df1SBryan Whitehead general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 45322820017SJohn Efstathiades (perout->event_ch); 45407624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 45522820017SJohn Efstathiades lan743x_ptp_release_event_ch(adapter, perout->event_ch); 45622820017SJohn Efstathiades perout->event_ch = -1; 45707624df1SBryan Whitehead } 45807624df1SBryan Whitehead } 45907624df1SBryan Whitehead 46007624df1SBryan Whitehead static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, 46122820017SJohn Efstathiades struct ptp_perout_request *perout_request) 46207624df1SBryan Whitehead { 46307624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 46407624df1SBryan Whitehead u32 period_sec = 0, period_nsec = 0; 46507624df1SBryan Whitehead u32 start_sec = 0, start_nsec = 0; 46607624df1SBryan Whitehead u32 general_config = 0; 46707624df1SBryan Whitehead int pulse_width = 0; 46822820017SJohn Efstathiades int perout_pin = 0; 46922820017SJohn Efstathiades unsigned int index = perout_request->index; 47022820017SJohn Efstathiades struct lan743x_ptp_perout *perout = &ptp->perout[index]; 4714ece1ae4SYuiko Oshino int ret = 0; 47207624df1SBryan Whitehead 4737f9048f1SJacob Keller /* Reject requests with unsupported flags */ 4744ece1ae4SYuiko Oshino if (perout_request->flags & ~PTP_PEROUT_DUTY_CYCLE) 4757f9048f1SJacob Keller return -EOPNOTSUPP; 4767f9048f1SJacob Keller 47722820017SJohn Efstathiades if (on) { 47822820017SJohn Efstathiades perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, 47922820017SJohn Efstathiades perout_request->index); 48022820017SJohn Efstathiades if (perout_pin < 0) 48122820017SJohn Efstathiades return -EBUSY; 48222820017SJohn Efstathiades } else { 48322820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 48407624df1SBryan Whitehead return 0; 48507624df1SBryan Whitehead } 48607624df1SBryan Whitehead 48722820017SJohn Efstathiades if (perout->event_ch >= 0 || 48822820017SJohn Efstathiades perout->gpio_pin >= 0) { 48907624df1SBryan Whitehead /* already on, turn off first */ 49022820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 49107624df1SBryan Whitehead } 49207624df1SBryan Whitehead 49322820017SJohn Efstathiades perout->event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 49422820017SJohn Efstathiades 49522820017SJohn Efstathiades if (perout->event_ch < 0) { 49607624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 49722820017SJohn Efstathiades "Failed to reserve event channel %d for PEROUT\n", 49822820017SJohn Efstathiades index); 4994ece1ae4SYuiko Oshino ret = -EBUSY; 50007624df1SBryan Whitehead goto failed; 50107624df1SBryan Whitehead } 50207624df1SBryan Whitehead 50322820017SJohn Efstathiades perout->gpio_pin = lan743x_gpio_rsrv_ptp_out(adapter, 50422820017SJohn Efstathiades perout_pin, 50522820017SJohn Efstathiades perout->event_ch); 50607624df1SBryan Whitehead 50722820017SJohn Efstathiades if (perout->gpio_pin < 0) { 50807624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 50907624df1SBryan Whitehead "Failed to reserve gpio %d for PEROUT\n", 51022820017SJohn Efstathiades perout_pin); 5114ece1ae4SYuiko Oshino ret = -EBUSY; 51207624df1SBryan Whitehead goto failed; 51307624df1SBryan Whitehead } 51407624df1SBryan Whitehead 51522820017SJohn Efstathiades start_sec = perout_request->start.sec; 51622820017SJohn Efstathiades start_sec += perout_request->start.nsec / 1000000000; 51722820017SJohn Efstathiades start_nsec = perout_request->start.nsec % 1000000000; 51807624df1SBryan Whitehead 51922820017SJohn Efstathiades period_sec = perout_request->period.sec; 52022820017SJohn Efstathiades period_sec += perout_request->period.nsec / 1000000000; 52122820017SJohn Efstathiades period_nsec = perout_request->period.nsec % 1000000000; 52207624df1SBryan Whitehead 5234ece1ae4SYuiko Oshino if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 5244ece1ae4SYuiko Oshino struct timespec64 ts_on, ts_period; 5254ece1ae4SYuiko Oshino s64 wf_high, period64, half; 5264ece1ae4SYuiko Oshino s32 reminder; 5274ece1ae4SYuiko Oshino 5284ece1ae4SYuiko Oshino ts_on.tv_sec = perout_request->on.sec; 5294ece1ae4SYuiko Oshino ts_on.tv_nsec = perout_request->on.nsec; 5304ece1ae4SYuiko Oshino wf_high = timespec64_to_ns(&ts_on); 5314ece1ae4SYuiko Oshino ts_period.tv_sec = perout_request->period.sec; 5324ece1ae4SYuiko Oshino ts_period.tv_nsec = perout_request->period.nsec; 5334ece1ae4SYuiko Oshino period64 = timespec64_to_ns(&ts_period); 5344ece1ae4SYuiko Oshino 5354ece1ae4SYuiko Oshino if (period64 < 200) { 5364ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 5374ece1ae4SYuiko Oshino "perout period too small, minimum is 200nS\n"); 5384ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 5394ece1ae4SYuiko Oshino goto failed; 5404ece1ae4SYuiko Oshino } 5414ece1ae4SYuiko Oshino if (wf_high >= period64) { 5424ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 5434ece1ae4SYuiko Oshino "pulse width must be smaller than period\n"); 5444ece1ae4SYuiko Oshino ret = -EINVAL; 5454ece1ae4SYuiko Oshino goto failed; 5464ece1ae4SYuiko Oshino } 5474ece1ae4SYuiko Oshino 5484ece1ae4SYuiko Oshino /* Check if we can do 50% toggle on an even value of period. 5494ece1ae4SYuiko Oshino * If the period number is odd, then check if the requested 5504ece1ae4SYuiko Oshino * pulse width is the same as one of pre-defined width values. 5514ece1ae4SYuiko Oshino * Otherwise, return failure. 5524ece1ae4SYuiko Oshino */ 5534ece1ae4SYuiko Oshino half = div_s64_rem(period64, 2, &reminder); 5544ece1ae4SYuiko Oshino if (!reminder) { 5554ece1ae4SYuiko Oshino if (half == wf_high) { 5564ece1ae4SYuiko Oshino /* It's 50% match. Use the toggle option */ 5574ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_; 5584ece1ae4SYuiko Oshino /* In this case, devide period value by 2 */ 5594ece1ae4SYuiko Oshino ts_period = ns_to_timespec64(div_s64(period64, 2)); 5604ece1ae4SYuiko Oshino period_sec = ts_period.tv_sec; 5614ece1ae4SYuiko Oshino period_nsec = ts_period.tv_nsec; 5624ece1ae4SYuiko Oshino 5634ece1ae4SYuiko Oshino goto program; 5644ece1ae4SYuiko Oshino } 5654ece1ae4SYuiko Oshino } 5664ece1ae4SYuiko Oshino /* if we can't do toggle, then the width option needs to be the exact match */ 5674ece1ae4SYuiko Oshino if (wf_high == 200000000) { 5684ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 5694ece1ae4SYuiko Oshino } else if (wf_high == 10000000) { 5704ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 5714ece1ae4SYuiko Oshino } else if (wf_high == 1000000) { 5724ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 5734ece1ae4SYuiko Oshino } else if (wf_high == 100000) { 5744ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 5754ece1ae4SYuiko Oshino } else if (wf_high == 10000) { 5764ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 5774ece1ae4SYuiko Oshino } else if (wf_high == 100) { 5784ece1ae4SYuiko Oshino pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 5794ece1ae4SYuiko Oshino } else { 5804ece1ae4SYuiko Oshino netif_warn(adapter, drv, adapter->netdev, 5814ece1ae4SYuiko Oshino "duty cycle specified is not supported\n"); 5824ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 5834ece1ae4SYuiko Oshino goto failed; 5844ece1ae4SYuiko Oshino } 5854ece1ae4SYuiko Oshino } else { 58607624df1SBryan Whitehead if (period_sec == 0) { 58707624df1SBryan Whitehead if (period_nsec >= 400000000) { 58807624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 58907624df1SBryan Whitehead } else if (period_nsec >= 20000000) { 59007624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 59107624df1SBryan Whitehead } else if (period_nsec >= 2000000) { 59207624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 59307624df1SBryan Whitehead } else if (period_nsec >= 200000) { 59407624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 59507624df1SBryan Whitehead } else if (period_nsec >= 20000) { 59607624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 59707624df1SBryan Whitehead } else if (period_nsec >= 200) { 59807624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 59907624df1SBryan Whitehead } else { 60007624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 60107624df1SBryan Whitehead "perout period too small, minimum is 200nS\n"); 6024ece1ae4SYuiko Oshino ret = -EOPNOTSUPP; 60307624df1SBryan Whitehead goto failed; 60407624df1SBryan Whitehead } 60507624df1SBryan Whitehead } else { 60607624df1SBryan Whitehead pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 60707624df1SBryan Whitehead } 6084ece1ae4SYuiko Oshino } 6094ece1ae4SYuiko Oshino program: 61007624df1SBryan Whitehead 61107624df1SBryan Whitehead /* turn off by setting target far in future */ 61207624df1SBryan Whitehead lan743x_csr_write(adapter, 61322820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 61407624df1SBryan Whitehead 0xFFFF0000); 61507624df1SBryan Whitehead lan743x_csr_write(adapter, 61622820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0); 61707624df1SBryan Whitehead 61807624df1SBryan Whitehead /* Configure to pulse every period */ 61907624df1SBryan Whitehead general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 62007624df1SBryan Whitehead general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 62122820017SJohn Efstathiades (perout->event_ch)); 62207624df1SBryan Whitehead general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 62322820017SJohn Efstathiades (perout->event_ch, pulse_width); 62407624df1SBryan Whitehead general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 62522820017SJohn Efstathiades (perout->event_ch); 62607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 62707624df1SBryan Whitehead 62807624df1SBryan Whitehead /* set the reload to one toggle cycle */ 62907624df1SBryan Whitehead lan743x_csr_write(adapter, 63022820017SJohn Efstathiades PTP_CLOCK_TARGET_RELOAD_SEC_X(perout->event_ch), 63107624df1SBryan Whitehead period_sec); 63207624df1SBryan Whitehead lan743x_csr_write(adapter, 63322820017SJohn Efstathiades PTP_CLOCK_TARGET_RELOAD_NS_X(perout->event_ch), 63407624df1SBryan Whitehead period_nsec); 63507624df1SBryan Whitehead 63607624df1SBryan Whitehead /* set the start time */ 63707624df1SBryan Whitehead lan743x_csr_write(adapter, 63822820017SJohn Efstathiades PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 63907624df1SBryan Whitehead start_sec); 64007624df1SBryan Whitehead lan743x_csr_write(adapter, 64122820017SJohn Efstathiades PTP_CLOCK_TARGET_NS_X(perout->event_ch), 64207624df1SBryan Whitehead start_nsec); 64307624df1SBryan Whitehead 64407624df1SBryan Whitehead return 0; 64507624df1SBryan Whitehead 64607624df1SBryan Whitehead failed: 64722820017SJohn Efstathiades lan743x_ptp_perout_off(adapter, index); 6484ece1ae4SYuiko Oshino return ret; 64907624df1SBryan Whitehead } 65007624df1SBryan Whitehead 651e432dd3bSRaju Lakkaraju static void lan743x_ptp_io_perout_off(struct lan743x_adapter *adapter, 652e432dd3bSRaju Lakkaraju u32 index) 653e432dd3bSRaju Lakkaraju { 654e432dd3bSRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 655e432dd3bSRaju Lakkaraju int perout_pin; 656e432dd3bSRaju Lakkaraju int event_ch; 657e432dd3bSRaju Lakkaraju u32 gen_cfg; 658e432dd3bSRaju Lakkaraju int val; 659e432dd3bSRaju Lakkaraju 660e432dd3bSRaju Lakkaraju event_ch = ptp->ptp_io_perout[index]; 661e432dd3bSRaju Lakkaraju if (event_ch >= 0) { 662e432dd3bSRaju Lakkaraju /* set target to far in the future, effectively disabling it */ 663e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 664e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 665e432dd3bSRaju Lakkaraju 0xFFFF0000); 666e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 667e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 668e432dd3bSRaju Lakkaraju 0); 669e432dd3bSRaju Lakkaraju 670e432dd3bSRaju Lakkaraju gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 671e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 672e432dd3bSRaju Lakkaraju (event_ch)); 673e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch)); 674e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch); 675e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 676e432dd3bSRaju Lakkaraju if (event_ch) 677e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 678e432dd3bSRaju Lakkaraju PTP_INT_TIMER_INT_B_); 679e432dd3bSRaju Lakkaraju else 680e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 681e432dd3bSRaju Lakkaraju PTP_INT_TIMER_INT_A_); 682e432dd3bSRaju Lakkaraju lan743x_ptp_release_event_ch(adapter, event_ch); 683e432dd3bSRaju Lakkaraju ptp->ptp_io_perout[index] = -1; 684e432dd3bSRaju Lakkaraju } 685e432dd3bSRaju Lakkaraju 686e432dd3bSRaju Lakkaraju perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 687e432dd3bSRaju Lakkaraju 688e432dd3bSRaju Lakkaraju /* Deselect Event output */ 689e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 690e432dd3bSRaju Lakkaraju 691e432dd3bSRaju Lakkaraju /* Disables the output of Local Time Target compare events */ 692e432dd3bSRaju Lakkaraju val &= ~PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 693e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 694e432dd3bSRaju Lakkaraju 695e432dd3bSRaju Lakkaraju /* Configured as an opendrain driver*/ 696e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 697e432dd3bSRaju Lakkaraju val &= ~PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 698e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 699e432dd3bSRaju Lakkaraju /* Dummy read to make sure write operation success */ 700e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 701e432dd3bSRaju Lakkaraju } 702e432dd3bSRaju Lakkaraju 703e432dd3bSRaju Lakkaraju static int lan743x_ptp_io_perout(struct lan743x_adapter *adapter, int on, 704e432dd3bSRaju Lakkaraju struct ptp_perout_request *perout_request) 705e432dd3bSRaju Lakkaraju { 706e432dd3bSRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 707e432dd3bSRaju Lakkaraju u32 period_sec, period_nsec; 708e432dd3bSRaju Lakkaraju u32 start_sec, start_nsec; 709e432dd3bSRaju Lakkaraju u32 pulse_sec, pulse_nsec; 710e432dd3bSRaju Lakkaraju int pulse_width; 711e432dd3bSRaju Lakkaraju int perout_pin; 712e432dd3bSRaju Lakkaraju int event_ch; 713e432dd3bSRaju Lakkaraju u32 gen_cfg; 714e432dd3bSRaju Lakkaraju u32 index; 715e432dd3bSRaju Lakkaraju int val; 716e432dd3bSRaju Lakkaraju 717e432dd3bSRaju Lakkaraju index = perout_request->index; 718e432dd3bSRaju Lakkaraju event_ch = ptp->ptp_io_perout[index]; 719e432dd3bSRaju Lakkaraju 720e432dd3bSRaju Lakkaraju if (on) { 721e432dd3bSRaju Lakkaraju perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 722e432dd3bSRaju Lakkaraju if (perout_pin < 0) 723e432dd3bSRaju Lakkaraju return -EBUSY; 724e432dd3bSRaju Lakkaraju } else { 725e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 726e432dd3bSRaju Lakkaraju return 0; 727e432dd3bSRaju Lakkaraju } 728e432dd3bSRaju Lakkaraju 729e432dd3bSRaju Lakkaraju if (event_ch >= LAN743X_PTP_N_EVENT_CHAN) { 730e432dd3bSRaju Lakkaraju /* already on, turn off first */ 731e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 732e432dd3bSRaju Lakkaraju } 733e432dd3bSRaju Lakkaraju 734e432dd3bSRaju Lakkaraju event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 735e432dd3bSRaju Lakkaraju if (event_ch < 0) { 736e432dd3bSRaju Lakkaraju netif_warn(adapter, drv, adapter->netdev, 737e432dd3bSRaju Lakkaraju "Failed to reserve event channel %d for PEROUT\n", 738e432dd3bSRaju Lakkaraju index); 739e432dd3bSRaju Lakkaraju goto failed; 740e432dd3bSRaju Lakkaraju } 741e432dd3bSRaju Lakkaraju ptp->ptp_io_perout[index] = event_ch; 742e432dd3bSRaju Lakkaraju 743e432dd3bSRaju Lakkaraju if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 744e432dd3bSRaju Lakkaraju pulse_sec = perout_request->on.sec; 745e432dd3bSRaju Lakkaraju pulse_sec += perout_request->on.nsec / 1000000000; 746e432dd3bSRaju Lakkaraju pulse_nsec = perout_request->on.nsec % 1000000000; 747e432dd3bSRaju Lakkaraju } else { 748e432dd3bSRaju Lakkaraju pulse_sec = perout_request->period.sec; 749e432dd3bSRaju Lakkaraju pulse_sec += perout_request->period.nsec / 1000000000; 750e432dd3bSRaju Lakkaraju pulse_nsec = perout_request->period.nsec % 1000000000; 751e432dd3bSRaju Lakkaraju } 752e432dd3bSRaju Lakkaraju 753e432dd3bSRaju Lakkaraju if (pulse_sec == 0) { 754e432dd3bSRaju Lakkaraju if (pulse_nsec >= 400000000) { 755e432dd3bSRaju Lakkaraju pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 756e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200000000) { 757e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_; 758e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 100000000) { 759e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_; 760e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 20000000) { 761e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 762e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 10000000) { 763e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_; 764e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 2000000) { 765e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 766e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 1000000) { 767e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_; 768e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200000) { 769e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 770e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 100000) { 771e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_; 772e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 20000) { 773e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 774e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 10000) { 775e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_; 776e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 2000) { 777e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_; 778e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 1000) { 779e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_; 780e432dd3bSRaju Lakkaraju } else if (pulse_nsec >= 200) { 781e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 782e432dd3bSRaju Lakkaraju } else { 783e432dd3bSRaju Lakkaraju netif_warn(adapter, drv, adapter->netdev, 784e432dd3bSRaju Lakkaraju "perout period too small, min is 200nS\n"); 785e432dd3bSRaju Lakkaraju goto failed; 786e432dd3bSRaju Lakkaraju } 787e432dd3bSRaju Lakkaraju } else { 788e432dd3bSRaju Lakkaraju pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 789e432dd3bSRaju Lakkaraju } 790e432dd3bSRaju Lakkaraju 791e432dd3bSRaju Lakkaraju /* turn off by setting target far in future */ 792e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 793e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 794e432dd3bSRaju Lakkaraju 0xFFFF0000); 795e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 796e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 0); 797e432dd3bSRaju Lakkaraju 798e432dd3bSRaju Lakkaraju /* Configure to pulse every period */ 799e432dd3bSRaju Lakkaraju gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 800e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(event_ch)); 801e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 802e432dd3bSRaju Lakkaraju (event_ch, pulse_width); 803e432dd3bSRaju Lakkaraju gen_cfg |= HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch); 804e432dd3bSRaju Lakkaraju gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch)); 805e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 806e432dd3bSRaju Lakkaraju 807e432dd3bSRaju Lakkaraju /* set the reload to one toggle cycle */ 808e432dd3bSRaju Lakkaraju period_sec = perout_request->period.sec; 809e432dd3bSRaju Lakkaraju period_sec += perout_request->period.nsec / 1000000000; 810e432dd3bSRaju Lakkaraju period_nsec = perout_request->period.nsec % 1000000000; 811e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 812e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_RELOAD_SEC_X(event_ch), 813e432dd3bSRaju Lakkaraju period_sec); 814e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 815e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_RELOAD_NS_X(event_ch), 816e432dd3bSRaju Lakkaraju period_nsec); 817e432dd3bSRaju Lakkaraju 818e432dd3bSRaju Lakkaraju start_sec = perout_request->start.sec; 819e432dd3bSRaju Lakkaraju start_sec += perout_request->start.nsec / 1000000000; 820e432dd3bSRaju Lakkaraju start_nsec = perout_request->start.nsec % 1000000000; 821e432dd3bSRaju Lakkaraju 822e432dd3bSRaju Lakkaraju /* set the start time */ 823e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 824e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_SEC_X(event_ch), 825e432dd3bSRaju Lakkaraju start_sec); 826e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, 827e432dd3bSRaju Lakkaraju PTP_CLOCK_TARGET_NS_X(event_ch), 828e432dd3bSRaju Lakkaraju start_nsec); 829e432dd3bSRaju Lakkaraju 830e432dd3bSRaju Lakkaraju /* Enable LTC Target Read */ 831e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_CMD_CTL); 832e432dd3bSRaju Lakkaraju val |= PTP_CMD_CTL_PTP_LTC_TARGET_READ_; 833e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_CMD_CTL, val); 834e432dd3bSRaju Lakkaraju 835e432dd3bSRaju Lakkaraju /* Configure as an push/pull driver */ 836e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 837e432dd3bSRaju Lakkaraju val |= PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 838e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 839e432dd3bSRaju Lakkaraju 840e432dd3bSRaju Lakkaraju /* Select Event output */ 841e432dd3bSRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 842e432dd3bSRaju Lakkaraju if (event_ch) 843e432dd3bSRaju Lakkaraju /* Channel B as the output */ 844e432dd3bSRaju Lakkaraju val |= PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 845e432dd3bSRaju Lakkaraju else 846e432dd3bSRaju Lakkaraju /* Channel A as the output */ 847e432dd3bSRaju Lakkaraju val &= ~PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 848e432dd3bSRaju Lakkaraju 849e432dd3bSRaju Lakkaraju /* Enables the output of Local Time Target compare events */ 850e432dd3bSRaju Lakkaraju val |= PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 851e432dd3bSRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 852e432dd3bSRaju Lakkaraju 853e432dd3bSRaju Lakkaraju return 0; 854e432dd3bSRaju Lakkaraju 855e432dd3bSRaju Lakkaraju failed: 856e432dd3bSRaju Lakkaraju lan743x_ptp_io_perout_off(adapter, index); 857e432dd3bSRaju Lakkaraju return -ENODEV; 858e432dd3bSRaju Lakkaraju } 859e432dd3bSRaju Lakkaraju 86060942c39SRaju Lakkaraju static void lan743x_ptp_io_extts_off(struct lan743x_adapter *adapter, 86160942c39SRaju Lakkaraju u32 index) 86260942c39SRaju Lakkaraju { 86360942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 86460942c39SRaju Lakkaraju struct lan743x_extts *extts; 86560942c39SRaju Lakkaraju int val; 86660942c39SRaju Lakkaraju 86760942c39SRaju Lakkaraju extts = &ptp->extts[index]; 86860942c39SRaju Lakkaraju /* PTP Interrupt Enable Clear Register */ 86960942c39SRaju Lakkaraju if (extts->flags & PTP_FALLING_EDGE) 87060942c39SRaju Lakkaraju val = PTP_INT_EN_FE_EN_CLR_(index); 87160942c39SRaju Lakkaraju else 87260942c39SRaju Lakkaraju val = PTP_INT_EN_RE_EN_CLR_(index); 87360942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_EN_CLR, val); 87460942c39SRaju Lakkaraju 87560942c39SRaju Lakkaraju /* Disables PTP-IO edge lock */ 87660942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 87760942c39SRaju Lakkaraju if (extts->flags & PTP_FALLING_EDGE) { 87860942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(index); 87960942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(index); 88060942c39SRaju Lakkaraju } else { 88160942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(index); 88260942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(index); 88360942c39SRaju Lakkaraju } 88460942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 88560942c39SRaju Lakkaraju 88660942c39SRaju Lakkaraju /* PTP-IO De-select register */ 88760942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_SEL); 88860942c39SRaju Lakkaraju val &= ~PTP_IO_SEL_MASK_; 88960942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_SEL, val); 89060942c39SRaju Lakkaraju 89160942c39SRaju Lakkaraju /* Clear timestamp */ 89260942c39SRaju Lakkaraju memset(&extts->ts, 0, sizeof(struct timespec64)); 89360942c39SRaju Lakkaraju extts->flags = 0; 89460942c39SRaju Lakkaraju } 89560942c39SRaju Lakkaraju 89660942c39SRaju Lakkaraju static int lan743x_ptp_io_event_cap_en(struct lan743x_adapter *adapter, 89760942c39SRaju Lakkaraju u32 flags, u32 channel) 89860942c39SRaju Lakkaraju { 89960942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 90060942c39SRaju Lakkaraju int val; 90160942c39SRaju Lakkaraju 90260942c39SRaju Lakkaraju if ((flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES) 90360942c39SRaju Lakkaraju return -EOPNOTSUPP; 90460942c39SRaju Lakkaraju 90560942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 90660942c39SRaju Lakkaraju /* PTP-IO Event Capture Enable */ 90760942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 90860942c39SRaju Lakkaraju if (flags & PTP_FALLING_EDGE) { 90960942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 91060942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 91160942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 91260942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 91360942c39SRaju Lakkaraju } else { 91460942c39SRaju Lakkaraju /* Rising eventing as Default */ 91560942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 91660942c39SRaju Lakkaraju val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 91760942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 91860942c39SRaju Lakkaraju val |= PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 91960942c39SRaju Lakkaraju } 92060942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 92160942c39SRaju Lakkaraju 92260942c39SRaju Lakkaraju /* PTP-IO Select */ 92360942c39SRaju Lakkaraju val = lan743x_csr_read(adapter, PTP_IO_SEL); 92460942c39SRaju Lakkaraju val &= ~PTP_IO_SEL_MASK_; 92560942c39SRaju Lakkaraju val |= channel << PTP_IO_SEL_SHIFT_; 92660942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_IO_SEL, val); 92760942c39SRaju Lakkaraju 92860942c39SRaju Lakkaraju /* PTP Interrupt Enable Register */ 92960942c39SRaju Lakkaraju if (flags & PTP_FALLING_EDGE) 93060942c39SRaju Lakkaraju val = PTP_INT_EN_FE_EN_SET_(channel); 93160942c39SRaju Lakkaraju else 93260942c39SRaju Lakkaraju val = PTP_INT_EN_RE_EN_SET_(channel); 93360942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_EN_SET, val); 93460942c39SRaju Lakkaraju 93560942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 93660942c39SRaju Lakkaraju 93760942c39SRaju Lakkaraju return 0; 93860942c39SRaju Lakkaraju } 93960942c39SRaju Lakkaraju 94060942c39SRaju Lakkaraju static int lan743x_ptp_io_extts(struct lan743x_adapter *adapter, int on, 94160942c39SRaju Lakkaraju struct ptp_extts_request *extts_request) 94260942c39SRaju Lakkaraju { 94360942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 94460942c39SRaju Lakkaraju u32 flags = extts_request->flags; 94560942c39SRaju Lakkaraju u32 index = extts_request->index; 94660942c39SRaju Lakkaraju struct lan743x_extts *extts; 94760942c39SRaju Lakkaraju int extts_pin; 94860942c39SRaju Lakkaraju int ret = 0; 94960942c39SRaju Lakkaraju 95060942c39SRaju Lakkaraju extts = &ptp->extts[index]; 95160942c39SRaju Lakkaraju 95260942c39SRaju Lakkaraju if (on) { 95360942c39SRaju Lakkaraju extts_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, index); 95460942c39SRaju Lakkaraju if (extts_pin < 0) 95560942c39SRaju Lakkaraju return -EBUSY; 95660942c39SRaju Lakkaraju 95760942c39SRaju Lakkaraju ret = lan743x_ptp_io_event_cap_en(adapter, flags, index); 95860942c39SRaju Lakkaraju if (!ret) 95960942c39SRaju Lakkaraju extts->flags = flags; 96060942c39SRaju Lakkaraju } else { 96160942c39SRaju Lakkaraju lan743x_ptp_io_extts_off(adapter, index); 96260942c39SRaju Lakkaraju } 96360942c39SRaju Lakkaraju 96460942c39SRaju Lakkaraju return ret; 96560942c39SRaju Lakkaraju } 96660942c39SRaju Lakkaraju 96707624df1SBryan Whitehead static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci, 96807624df1SBryan Whitehead struct ptp_clock_request *request, int on) 96907624df1SBryan Whitehead { 97007624df1SBryan Whitehead struct lan743x_ptp *ptp = 97107624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 97207624df1SBryan Whitehead struct lan743x_adapter *adapter = 97307624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 97407624df1SBryan Whitehead 97507624df1SBryan Whitehead if (request) { 97607624df1SBryan Whitehead switch (request->type) { 97707624df1SBryan Whitehead case PTP_CLK_REQ_EXTTS: 97860942c39SRaju Lakkaraju if (request->extts.index < ptpci->n_ext_ts) 97960942c39SRaju Lakkaraju return lan743x_ptp_io_extts(adapter, on, 98060942c39SRaju Lakkaraju &request->extts); 98107624df1SBryan Whitehead return -EINVAL; 98207624df1SBryan Whitehead case PTP_CLK_REQ_PEROUT: 983e432dd3bSRaju Lakkaraju if (request->perout.index < ptpci->n_per_out) { 984e432dd3bSRaju Lakkaraju if (adapter->is_pci11x1x) 985e432dd3bSRaju Lakkaraju return lan743x_ptp_io_perout(adapter, on, 986e432dd3bSRaju Lakkaraju &request->perout); 987e432dd3bSRaju Lakkaraju else 98807624df1SBryan Whitehead return lan743x_ptp_perout(adapter, on, 98907624df1SBryan Whitehead &request->perout); 990e432dd3bSRaju Lakkaraju } 99107624df1SBryan Whitehead return -EINVAL; 99207624df1SBryan Whitehead case PTP_CLK_REQ_PPS: 99307624df1SBryan Whitehead return -EINVAL; 99407624df1SBryan Whitehead default: 99507624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 99607624df1SBryan Whitehead "request->type == %d, Unknown\n", 99707624df1SBryan Whitehead request->type); 99807624df1SBryan Whitehead break; 99907624df1SBryan Whitehead } 100007624df1SBryan Whitehead } else { 100107624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, "request == NULL\n"); 100207624df1SBryan Whitehead } 100307624df1SBryan Whitehead return 0; 100407624df1SBryan Whitehead } 100507624df1SBryan Whitehead 100622820017SJohn Efstathiades static int lan743x_ptpci_verify_pin_config(struct ptp_clock_info *ptp, 100722820017SJohn Efstathiades unsigned int pin, 100822820017SJohn Efstathiades enum ptp_pin_function func, 100922820017SJohn Efstathiades unsigned int chan) 101022820017SJohn Efstathiades { 1011cb4b1207SRaju Lakkaraju struct lan743x_ptp *lan_ptp = 1012cb4b1207SRaju Lakkaraju container_of(ptp, struct lan743x_ptp, ptp_clock_info); 1013cb4b1207SRaju Lakkaraju struct lan743x_adapter *adapter = 1014cb4b1207SRaju Lakkaraju container_of(lan_ptp, struct lan743x_adapter, ptp); 101522820017SJohn Efstathiades int result = 0; 101622820017SJohn Efstathiades 101722820017SJohn Efstathiades /* Confirm the requested function is supported. Parameter 101822820017SJohn Efstathiades * validation is done by the caller. 101922820017SJohn Efstathiades */ 102022820017SJohn Efstathiades switch (func) { 102122820017SJohn Efstathiades case PTP_PF_NONE: 102222820017SJohn Efstathiades case PTP_PF_PEROUT: 1023cb4b1207SRaju Lakkaraju break; 102422820017SJohn Efstathiades case PTP_PF_EXTTS: 1025cb4b1207SRaju Lakkaraju if (!adapter->is_pci11x1x) 1026cb4b1207SRaju Lakkaraju result = -1; 102760942c39SRaju Lakkaraju break; 102822820017SJohn Efstathiades case PTP_PF_PHYSYNC: 102922820017SJohn Efstathiades default: 103022820017SJohn Efstathiades result = -1; 103122820017SJohn Efstathiades break; 103222820017SJohn Efstathiades } 103322820017SJohn Efstathiades return result; 103422820017SJohn Efstathiades } 103522820017SJohn Efstathiades 103660942c39SRaju Lakkaraju static void lan743x_ptp_io_event_clock_get(struct lan743x_adapter *adapter, 103760942c39SRaju Lakkaraju bool fe, u8 channel, 103860942c39SRaju Lakkaraju struct timespec64 *ts) 103960942c39SRaju Lakkaraju { 104060942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 104160942c39SRaju Lakkaraju struct lan743x_extts *extts; 104260942c39SRaju Lakkaraju u32 sec, nsec; 104360942c39SRaju Lakkaraju 104460942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 104560942c39SRaju Lakkaraju if (fe) { 104660942c39SRaju Lakkaraju sec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_SEC_CAP_X); 104760942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_NS_CAP_X); 104860942c39SRaju Lakkaraju } else { 104960942c39SRaju Lakkaraju sec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_SEC_CAP_X); 105060942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_NS_CAP_X); 105160942c39SRaju Lakkaraju } 105260942c39SRaju Lakkaraju 105360942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 105460942c39SRaju Lakkaraju 105560942c39SRaju Lakkaraju /* Update Local timestamp */ 105660942c39SRaju Lakkaraju extts = &ptp->extts[channel]; 105760942c39SRaju Lakkaraju extts->ts.tv_sec = sec; 105860942c39SRaju Lakkaraju extts->ts.tv_nsec = nsec; 105960942c39SRaju Lakkaraju ts->tv_sec = sec; 106060942c39SRaju Lakkaraju ts->tv_nsec = nsec; 106160942c39SRaju Lakkaraju } 106260942c39SRaju Lakkaraju 106307624df1SBryan Whitehead static long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci) 106407624df1SBryan Whitehead { 106507624df1SBryan Whitehead struct lan743x_ptp *ptp = 106607624df1SBryan Whitehead container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 106707624df1SBryan Whitehead struct lan743x_adapter *adapter = 106807624df1SBryan Whitehead container_of(ptp, struct lan743x_adapter, ptp); 106907624df1SBryan Whitehead u32 cap_info, cause, header, nsec, seconds; 107007624df1SBryan Whitehead bool new_timestamp_available = false; 107160942c39SRaju Lakkaraju struct ptp_clock_event ptp_event; 107260942c39SRaju Lakkaraju struct timespec64 ts; 107360942c39SRaju Lakkaraju int ptp_int_sts; 107407624df1SBryan Whitehead int count = 0; 107560942c39SRaju Lakkaraju int channel; 107660942c39SRaju Lakkaraju s64 ns; 107707624df1SBryan Whitehead 107860942c39SRaju Lakkaraju ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 107960942c39SRaju Lakkaraju while ((count < 100) && ptp_int_sts) { 108007624df1SBryan Whitehead count++; 108160942c39SRaju Lakkaraju 108260942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 108307624df1SBryan Whitehead cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO); 108407624df1SBryan Whitehead 108507624df1SBryan Whitehead if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) { 108607624df1SBryan Whitehead seconds = lan743x_csr_read(adapter, 108707624df1SBryan Whitehead PTP_TX_EGRESS_SEC); 108860942c39SRaju Lakkaraju nsec = lan743x_csr_read(adapter, 108960942c39SRaju Lakkaraju PTP_TX_EGRESS_NS); 109007624df1SBryan Whitehead cause = (nsec & 109107624df1SBryan Whitehead PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_); 109207624df1SBryan Whitehead header = lan743x_csr_read(adapter, 109307624df1SBryan Whitehead PTP_TX_MSG_HEADER); 109407624df1SBryan Whitehead 109560942c39SRaju Lakkaraju if (cause == 109660942c39SRaju Lakkaraju PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) { 109707624df1SBryan Whitehead nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_; 109807624df1SBryan Whitehead lan743x_ptp_tx_ts_enqueue_ts(adapter, 109960942c39SRaju Lakkaraju seconds, 110060942c39SRaju Lakkaraju nsec, 110107624df1SBryan Whitehead header); 110207624df1SBryan Whitehead new_timestamp_available = true; 110307624df1SBryan Whitehead } else if (cause == 110407624df1SBryan Whitehead PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) { 110507624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 110607624df1SBryan Whitehead "Auto capture cause not supported\n"); 110707624df1SBryan Whitehead } else { 110807624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 110907624df1SBryan Whitehead "unknown tx timestamp capture cause\n"); 111007624df1SBryan Whitehead } 111107624df1SBryan Whitehead } else { 111207624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 111307624df1SBryan Whitehead "TX TS INT but no TX TS CNT\n"); 111407624df1SBryan Whitehead } 111560942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 111660942c39SRaju Lakkaraju PTP_INT_BIT_TX_TS_); 111760942c39SRaju Lakkaraju } 111860942c39SRaju Lakkaraju 111960942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_IO_FE_MASK_) { 112060942c39SRaju Lakkaraju do { 112160942c39SRaju Lakkaraju channel = lan743x_get_channel((ptp_int_sts & 112260942c39SRaju Lakkaraju PTP_INT_IO_FE_MASK_) >> 112360942c39SRaju Lakkaraju PTP_INT_IO_FE_SHIFT_); 112460942c39SRaju Lakkaraju if (channel >= 0 && 112560942c39SRaju Lakkaraju channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 112660942c39SRaju Lakkaraju lan743x_ptp_io_event_clock_get(adapter, 112760942c39SRaju Lakkaraju true, 112860942c39SRaju Lakkaraju channel, 112960942c39SRaju Lakkaraju &ts); 113060942c39SRaju Lakkaraju /* PTP Falling Event post */ 113160942c39SRaju Lakkaraju ns = timespec64_to_ns(&ts); 113260942c39SRaju Lakkaraju ptp_event.timestamp = ns; 113360942c39SRaju Lakkaraju ptp_event.index = channel; 113460942c39SRaju Lakkaraju ptp_event.type = PTP_CLOCK_EXTTS; 113560942c39SRaju Lakkaraju ptp_clock_event(ptp->ptp_clock, 113660942c39SRaju Lakkaraju &ptp_event); 113760942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 113860942c39SRaju Lakkaraju PTP_INT_IO_FE_SET_ 113960942c39SRaju Lakkaraju (channel)); 114060942c39SRaju Lakkaraju ptp_int_sts &= ~(1 << 114160942c39SRaju Lakkaraju (PTP_INT_IO_FE_SHIFT_ + 114260942c39SRaju Lakkaraju channel)); 114360942c39SRaju Lakkaraju } else { 114460942c39SRaju Lakkaraju /* Clear falling event interrupts */ 114560942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 114660942c39SRaju Lakkaraju PTP_INT_IO_FE_MASK_); 114760942c39SRaju Lakkaraju ptp_int_sts &= ~PTP_INT_IO_FE_MASK_; 114860942c39SRaju Lakkaraju } 114960942c39SRaju Lakkaraju } while (ptp_int_sts & PTP_INT_IO_FE_MASK_); 115060942c39SRaju Lakkaraju } 115160942c39SRaju Lakkaraju 115260942c39SRaju Lakkaraju if (ptp_int_sts & PTP_INT_IO_RE_MASK_) { 115360942c39SRaju Lakkaraju do { 115460942c39SRaju Lakkaraju channel = lan743x_get_channel((ptp_int_sts & 115560942c39SRaju Lakkaraju PTP_INT_IO_RE_MASK_) >> 115660942c39SRaju Lakkaraju PTP_INT_IO_RE_SHIFT_); 115760942c39SRaju Lakkaraju if (channel >= 0 && 115860942c39SRaju Lakkaraju channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 115960942c39SRaju Lakkaraju lan743x_ptp_io_event_clock_get(adapter, 116060942c39SRaju Lakkaraju false, 116160942c39SRaju Lakkaraju channel, 116260942c39SRaju Lakkaraju &ts); 116360942c39SRaju Lakkaraju /* PTP Rising Event post */ 116460942c39SRaju Lakkaraju ns = timespec64_to_ns(&ts); 116560942c39SRaju Lakkaraju ptp_event.timestamp = ns; 116660942c39SRaju Lakkaraju ptp_event.index = channel; 116760942c39SRaju Lakkaraju ptp_event.type = PTP_CLOCK_EXTTS; 116860942c39SRaju Lakkaraju ptp_clock_event(ptp->ptp_clock, 116960942c39SRaju Lakkaraju &ptp_event); 117060942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 117160942c39SRaju Lakkaraju PTP_INT_IO_RE_SET_ 117260942c39SRaju Lakkaraju (channel)); 117360942c39SRaju Lakkaraju ptp_int_sts &= ~(1 << 117460942c39SRaju Lakkaraju (PTP_INT_IO_RE_SHIFT_ + 117560942c39SRaju Lakkaraju channel)); 117660942c39SRaju Lakkaraju } else { 117760942c39SRaju Lakkaraju /* Clear Rising event interrupt */ 117860942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_INT_STS, 117960942c39SRaju Lakkaraju PTP_INT_IO_RE_MASK_); 118060942c39SRaju Lakkaraju ptp_int_sts &= ~PTP_INT_IO_RE_MASK_; 118160942c39SRaju Lakkaraju } 118260942c39SRaju Lakkaraju } while (ptp_int_sts & PTP_INT_IO_RE_MASK_); 118360942c39SRaju Lakkaraju } 118460942c39SRaju Lakkaraju 118560942c39SRaju Lakkaraju ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 118607624df1SBryan Whitehead } 118707624df1SBryan Whitehead 118807624df1SBryan Whitehead if (new_timestamp_available) 118907624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 119007624df1SBryan Whitehead 119107624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 119207624df1SBryan Whitehead 119307624df1SBryan Whitehead return -1; 119407624df1SBryan Whitehead } 119507624df1SBryan Whitehead 119607624df1SBryan Whitehead static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, 119707624df1SBryan Whitehead u32 *seconds, u32 *nano_seconds, 119807624df1SBryan Whitehead u32 *sub_nano_seconds) 119907624df1SBryan Whitehead { 120007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 120107624df1SBryan Whitehead 120207624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 120307624df1SBryan Whitehead 120407624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 120507624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 120607624df1SBryan Whitehead 120707624df1SBryan Whitehead if (seconds) 120807624df1SBryan Whitehead (*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC); 120907624df1SBryan Whitehead 121007624df1SBryan Whitehead if (nano_seconds) 121107624df1SBryan Whitehead (*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS); 121207624df1SBryan Whitehead 121307624df1SBryan Whitehead if (sub_nano_seconds) 121407624df1SBryan Whitehead (*sub_nano_seconds) = 121507624df1SBryan Whitehead lan743x_csr_read(adapter, PTP_CLOCK_SUBNS); 121607624df1SBryan Whitehead 121707624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 121807624df1SBryan Whitehead } 121907624df1SBryan Whitehead 122060942c39SRaju Lakkaraju static void lan743x_ptp_io_clock_get(struct lan743x_adapter *adapter, 122160942c39SRaju Lakkaraju u32 *sec, u32 *nsec, u32 *sub_nsec) 122260942c39SRaju Lakkaraju { 122360942c39SRaju Lakkaraju struct lan743x_ptp *ptp = &adapter->ptp; 122460942c39SRaju Lakkaraju 122560942c39SRaju Lakkaraju mutex_lock(&ptp->command_lock); 122660942c39SRaju Lakkaraju lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 122760942c39SRaju Lakkaraju lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 122860942c39SRaju Lakkaraju 122960942c39SRaju Lakkaraju if (sec) 123060942c39SRaju Lakkaraju (*sec) = lan743x_csr_read(adapter, PTP_LTC_RD_SEC_LO); 123160942c39SRaju Lakkaraju 123260942c39SRaju Lakkaraju if (nsec) 123360942c39SRaju Lakkaraju (*nsec) = lan743x_csr_read(adapter, PTP_LTC_RD_NS); 123460942c39SRaju Lakkaraju 123560942c39SRaju Lakkaraju if (sub_nsec) 123660942c39SRaju Lakkaraju (*sub_nsec) = 123760942c39SRaju Lakkaraju lan743x_csr_read(adapter, PTP_LTC_RD_SUBNS); 123860942c39SRaju Lakkaraju 123960942c39SRaju Lakkaraju mutex_unlock(&ptp->command_lock); 124060942c39SRaju Lakkaraju } 124160942c39SRaju Lakkaraju 124207624df1SBryan Whitehead static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, 124307624df1SBryan Whitehead s64 time_step_ns) 124407624df1SBryan Whitehead { 124507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 124607624df1SBryan Whitehead u32 nano_seconds_step = 0; 124707624df1SBryan Whitehead u64 abs_time_step_ns = 0; 124807624df1SBryan Whitehead u32 unsigned_seconds = 0; 124907624df1SBryan Whitehead u32 nano_seconds = 0; 125007624df1SBryan Whitehead u32 remainder = 0; 125107624df1SBryan Whitehead s32 seconds = 0; 125207624df1SBryan Whitehead 125307624df1SBryan Whitehead if (time_step_ns > 15000000000LL) { 125407624df1SBryan Whitehead /* convert to clock set */ 125560942c39SRaju Lakkaraju if (adapter->is_pci11x1x) 125660942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 125760942c39SRaju Lakkaraju &nano_seconds, NULL); 125860942c39SRaju Lakkaraju else 125907624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &unsigned_seconds, 126007624df1SBryan Whitehead &nano_seconds, NULL); 126107624df1SBryan Whitehead unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL, 126207624df1SBryan Whitehead &remainder); 126307624df1SBryan Whitehead nano_seconds += remainder; 126407624df1SBryan Whitehead if (nano_seconds >= 1000000000) { 126507624df1SBryan Whitehead unsigned_seconds++; 126607624df1SBryan Whitehead nano_seconds -= 1000000000; 126707624df1SBryan Whitehead } 126807624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, unsigned_seconds, 126907624df1SBryan Whitehead nano_seconds, 0); 127007624df1SBryan Whitehead return; 127107624df1SBryan Whitehead } else if (time_step_ns < -15000000000LL) { 127207624df1SBryan Whitehead /* convert to clock set */ 127307624df1SBryan Whitehead time_step_ns = -time_step_ns; 127407624df1SBryan Whitehead 127560942c39SRaju Lakkaraju if (adapter->is_pci11x1x) { 127660942c39SRaju Lakkaraju lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 127760942c39SRaju Lakkaraju &nano_seconds, NULL); 127860942c39SRaju Lakkaraju } else { 127907624df1SBryan Whitehead lan743x_ptp_clock_get(adapter, &unsigned_seconds, 128007624df1SBryan Whitehead &nano_seconds, NULL); 128160942c39SRaju Lakkaraju } 128207624df1SBryan Whitehead unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL, 128307624df1SBryan Whitehead &remainder); 128407624df1SBryan Whitehead nano_seconds_step = remainder; 128507624df1SBryan Whitehead if (nano_seconds < nano_seconds_step) { 128607624df1SBryan Whitehead unsigned_seconds--; 128707624df1SBryan Whitehead nano_seconds += 1000000000; 128807624df1SBryan Whitehead } 128907624df1SBryan Whitehead nano_seconds -= nano_seconds_step; 129007624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, unsigned_seconds, 129107624df1SBryan Whitehead nano_seconds, 0); 129207624df1SBryan Whitehead return; 129307624df1SBryan Whitehead } 129407624df1SBryan Whitehead 129507624df1SBryan Whitehead /* do clock step */ 129607624df1SBryan Whitehead if (time_step_ns >= 0) { 129707624df1SBryan Whitehead abs_time_step_ns = (u64)(time_step_ns); 129807624df1SBryan Whitehead seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000, 129907624df1SBryan Whitehead &remainder); 130007624df1SBryan Whitehead nano_seconds = (u32)remainder; 130107624df1SBryan Whitehead } else { 130207624df1SBryan Whitehead abs_time_step_ns = (u64)(-time_step_ns); 130307624df1SBryan Whitehead seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000, 130407624df1SBryan Whitehead &remainder)); 130507624df1SBryan Whitehead nano_seconds = (u32)remainder; 130607624df1SBryan Whitehead if (nano_seconds > 0) { 130707624df1SBryan Whitehead /* subtracting nano seconds is not allowed 130807624df1SBryan Whitehead * convert to subtracting from seconds, 130907624df1SBryan Whitehead * and adding to nanoseconds 131007624df1SBryan Whitehead */ 131107624df1SBryan Whitehead seconds--; 131207624df1SBryan Whitehead nano_seconds = (1000000000 - nano_seconds); 131307624df1SBryan Whitehead } 131407624df1SBryan Whitehead } 131507624df1SBryan Whitehead 131607624df1SBryan Whitehead if (nano_seconds > 0) { 131707624df1SBryan Whitehead /* add 8 ns to cover the likely normal increment */ 131807624df1SBryan Whitehead nano_seconds += 8; 131907624df1SBryan Whitehead } 132007624df1SBryan Whitehead 132107624df1SBryan Whitehead if (nano_seconds >= 1000000000) { 132207624df1SBryan Whitehead /* carry into seconds */ 132307624df1SBryan Whitehead seconds++; 132407624df1SBryan Whitehead nano_seconds -= 1000000000; 132507624df1SBryan Whitehead } 132607624df1SBryan Whitehead 132707624df1SBryan Whitehead while (seconds) { 132807624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 132907624df1SBryan Whitehead if (seconds > 0) { 133007624df1SBryan Whitehead u32 adjustment_value = (u32)seconds; 133107624df1SBryan Whitehead 133207624df1SBryan Whitehead if (adjustment_value > 0xF) 133307624df1SBryan Whitehead adjustment_value = 0xF; 133407624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 133507624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_DIR_ | 133607624df1SBryan Whitehead adjustment_value); 133707624df1SBryan Whitehead seconds -= ((s32)adjustment_value); 133807624df1SBryan Whitehead } else { 133907624df1SBryan Whitehead u32 adjustment_value = (u32)(-seconds); 134007624df1SBryan Whitehead 134107624df1SBryan Whitehead if (adjustment_value > 0xF) 134207624df1SBryan Whitehead adjustment_value = 0xF; 134307624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 134407624df1SBryan Whitehead adjustment_value); 134507624df1SBryan Whitehead seconds += ((s32)adjustment_value); 134607624df1SBryan Whitehead } 134707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, 134807624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 134907624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, 135007624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 135107624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 135207624df1SBryan Whitehead } 135307624df1SBryan Whitehead if (nano_seconds) { 135407624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 135507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 135607624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_DIR_ | 135707624df1SBryan Whitehead (nano_seconds & 135807624df1SBryan Whitehead PTP_CLOCK_STEP_ADJ_VALUE_MASK_)); 135907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, 136007624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 136107624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, 136207624df1SBryan Whitehead PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 136307624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 136407624df1SBryan Whitehead } 136507624df1SBryan Whitehead } 136607624df1SBryan Whitehead 136707624df1SBryan Whitehead void lan743x_ptp_isr(void *context) 136807624df1SBryan Whitehead { 136907624df1SBryan Whitehead struct lan743x_adapter *adapter = (struct lan743x_adapter *)context; 137007624df1SBryan Whitehead struct lan743x_ptp *ptp = NULL; 137107624df1SBryan Whitehead int enable_flag = 1; 137207624df1SBryan Whitehead u32 ptp_int_sts = 0; 137307624df1SBryan Whitehead 137407624df1SBryan Whitehead ptp = &adapter->ptp; 137507624df1SBryan Whitehead 137607624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 137707624df1SBryan Whitehead 137807624df1SBryan Whitehead ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 137907624df1SBryan Whitehead ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET); 138007624df1SBryan Whitehead 138107624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 138207624df1SBryan Whitehead ptp_schedule_worker(ptp->ptp_clock, 0); 138307624df1SBryan Whitehead enable_flag = 0;/* tasklet will re-enable later */ 138407624df1SBryan Whitehead } 138507624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) { 138607624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 138707624df1SBryan Whitehead "PTP TX Software Timestamp Error\n"); 138807624df1SBryan Whitehead /* clear int status bit */ 138907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 139007624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_); 139107624df1SBryan Whitehead } 139207624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) { 139307624df1SBryan Whitehead /* clear int status bit */ 139407624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 139507624df1SBryan Whitehead PTP_INT_BIT_TIMER_B_); 139607624df1SBryan Whitehead } 139707624df1SBryan Whitehead if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) { 139807624df1SBryan Whitehead /* clear int status bit */ 139907624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_STS, 140007624df1SBryan Whitehead PTP_INT_BIT_TIMER_A_); 140107624df1SBryan Whitehead } 140207624df1SBryan Whitehead 140307624df1SBryan Whitehead if (enable_flag) { 140407624df1SBryan Whitehead /* re-enable isr */ 140507624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 140607624df1SBryan Whitehead } 140707624df1SBryan Whitehead } 140807624df1SBryan Whitehead 140907624df1SBryan Whitehead static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter, 141007624df1SBryan Whitehead struct sk_buff *skb, bool ignore_sync) 141107624df1SBryan Whitehead { 141207624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 141307624df1SBryan Whitehead 141407624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 141507624df1SBryan Whitehead if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 141607624df1SBryan Whitehead ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb; 141707624df1SBryan Whitehead if (ignore_sync) 141807624df1SBryan Whitehead ptp->tx_ts_ignore_sync_queue |= 141907624df1SBryan Whitehead BIT(ptp->tx_ts_skb_queue_size); 142007624df1SBryan Whitehead ptp->tx_ts_skb_queue_size++; 142107624df1SBryan Whitehead } else { 142207624df1SBryan Whitehead /* this should never happen, so long as the tx channel 142307624df1SBryan Whitehead * calls and honors the result from 142407624df1SBryan Whitehead * lan743x_ptp_request_tx_timestamp 142507624df1SBryan Whitehead */ 142607624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 142707624df1SBryan Whitehead "tx ts skb queue overflow\n"); 142807624df1SBryan Whitehead dev_kfree_skb(skb); 142907624df1SBryan Whitehead } 143007624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 143107624df1SBryan Whitehead } 143207624df1SBryan Whitehead 143307624df1SBryan Whitehead static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter) 143407624df1SBryan Whitehead { 143507624df1SBryan Whitehead struct timespec64 ts; 143607624df1SBryan Whitehead 14370b3e776eSArnd Bergmann ktime_get_clocktai_ts64(&ts); 143807624df1SBryan Whitehead 143907624df1SBryan Whitehead lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0); 144007624df1SBryan Whitehead } 144107624df1SBryan Whitehead 144207624df1SBryan Whitehead void lan743x_ptp_update_latency(struct lan743x_adapter *adapter, 144307624df1SBryan Whitehead u32 link_speed) 144407624df1SBryan Whitehead { 144507624df1SBryan Whitehead switch (link_speed) { 144607624df1SBryan Whitehead case 10: 144707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 144807624df1SBryan Whitehead PTP_LATENCY_TX_SET_(0) | 144907624df1SBryan Whitehead PTP_LATENCY_RX_SET_(0)); 145007624df1SBryan Whitehead break; 145107624df1SBryan Whitehead case 100: 145207624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 145307624df1SBryan Whitehead PTP_LATENCY_TX_SET_(181) | 145407624df1SBryan Whitehead PTP_LATENCY_RX_SET_(594)); 145507624df1SBryan Whitehead break; 145607624df1SBryan Whitehead case 1000: 145707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_LATENCY, 145807624df1SBryan Whitehead PTP_LATENCY_TX_SET_(30) | 145907624df1SBryan Whitehead PTP_LATENCY_RX_SET_(525)); 146007624df1SBryan Whitehead break; 146107624df1SBryan Whitehead } 146207624df1SBryan Whitehead } 146307624df1SBryan Whitehead 146407624df1SBryan Whitehead int lan743x_ptp_init(struct lan743x_adapter *adapter) 146507624df1SBryan Whitehead { 146607624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 146722820017SJohn Efstathiades int i; 146807624df1SBryan Whitehead 146907624df1SBryan Whitehead mutex_init(&ptp->command_lock); 147007624df1SBryan Whitehead spin_lock_init(&ptp->tx_ts_lock); 147107624df1SBryan Whitehead ptp->used_event_ch = 0; 147222820017SJohn Efstathiades 147322820017SJohn Efstathiades for (i = 0; i < LAN743X_PTP_N_EVENT_CHAN; i++) { 147422820017SJohn Efstathiades ptp->perout[i].event_ch = -1; 147522820017SJohn Efstathiades ptp->perout[i].gpio_pin = -1; 147622820017SJohn Efstathiades } 147722820017SJohn Efstathiades 147822820017SJohn Efstathiades lan743x_led_mux_save(adapter); 147922820017SJohn Efstathiades 148007624df1SBryan Whitehead return 0; 148107624df1SBryan Whitehead } 148207624df1SBryan Whitehead 148307624df1SBryan Whitehead int lan743x_ptp_open(struct lan743x_adapter *adapter) 148407624df1SBryan Whitehead { 148507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 148607624df1SBryan Whitehead int ret = -ENODEV; 148707624df1SBryan Whitehead u32 temp; 148822820017SJohn Efstathiades int i; 148922820017SJohn Efstathiades int n_pins; 149007624df1SBryan Whitehead 149107624df1SBryan Whitehead lan743x_ptp_reset(adapter); 149207624df1SBryan Whitehead lan743x_ptp_sync_to_system_clock(adapter); 149307624df1SBryan Whitehead temp = lan743x_csr_read(adapter, PTP_TX_MOD2); 149407624df1SBryan Whitehead temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_; 149507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_TX_MOD2, temp); 149607624df1SBryan Whitehead lan743x_ptp_enable(adapter); 149707624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 149807624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_EN_SET, 149907624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_); 150007624df1SBryan Whitehead ptp->flags |= PTP_FLAG_ISR_ENABLED; 150107624df1SBryan Whitehead 15029dc502d7SArnd Bergmann if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK)) 15039dc502d7SArnd Bergmann return 0; 15049dc502d7SArnd Bergmann 150522820017SJohn Efstathiades switch (adapter->csr.id_rev & ID_REV_ID_MASK_) { 150622820017SJohn Efstathiades case ID_REV_ID_LAN7430_: 150722820017SJohn Efstathiades n_pins = LAN7430_N_GPIO; 150822820017SJohn Efstathiades break; 150922820017SJohn Efstathiades case ID_REV_ID_LAN7431_: 151060942c39SRaju Lakkaraju case ID_REV_ID_A011_: 151160942c39SRaju Lakkaraju case ID_REV_ID_A041_: 151222820017SJohn Efstathiades n_pins = LAN7431_N_GPIO; 151322820017SJohn Efstathiades break; 151422820017SJohn Efstathiades default: 151522820017SJohn Efstathiades netif_warn(adapter, drv, adapter->netdev, 151622820017SJohn Efstathiades "Unknown LAN743x (%08x). Assuming no GPIO\n", 151722820017SJohn Efstathiades adapter->csr.id_rev); 151822820017SJohn Efstathiades n_pins = 0; 151922820017SJohn Efstathiades break; 152022820017SJohn Efstathiades } 152122820017SJohn Efstathiades 152222820017SJohn Efstathiades if (n_pins > LAN743X_PTP_N_GPIO) 152322820017SJohn Efstathiades n_pins = LAN743X_PTP_N_GPIO; 152422820017SJohn Efstathiades 152522820017SJohn Efstathiades for (i = 0; i < n_pins; i++) { 152622820017SJohn Efstathiades struct ptp_pin_desc *ptp_pin = &ptp->pin_config[i]; 152722820017SJohn Efstathiades 152822820017SJohn Efstathiades snprintf(ptp_pin->name, 152922820017SJohn Efstathiades sizeof(ptp_pin->name), "lan743x_ptp_pin_%02d", i); 153022820017SJohn Efstathiades ptp_pin->index = i; 153122820017SJohn Efstathiades ptp_pin->func = PTP_PF_NONE; 153222820017SJohn Efstathiades } 153307624df1SBryan Whitehead 153407624df1SBryan Whitehead ptp->ptp_clock_info.owner = THIS_MODULE; 153507624df1SBryan Whitehead snprintf(ptp->ptp_clock_info.name, 16, "%pm", 153607624df1SBryan Whitehead adapter->netdev->dev_addr); 153707624df1SBryan Whitehead ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB; 153807624df1SBryan Whitehead ptp->ptp_clock_info.n_alarm = 0; 153960942c39SRaju Lakkaraju ptp->ptp_clock_info.n_ext_ts = LAN743X_PTP_N_EXTTS; 154022820017SJohn Efstathiades ptp->ptp_clock_info.n_per_out = LAN743X_PTP_N_EVENT_CHAN; 154122820017SJohn Efstathiades ptp->ptp_clock_info.n_pins = n_pins; 154260942c39SRaju Lakkaraju ptp->ptp_clock_info.pps = LAN743X_PTP_N_PPS; 154322820017SJohn Efstathiades ptp->ptp_clock_info.pin_config = ptp->pin_config; 154407624df1SBryan Whitehead ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine; 154507624df1SBryan Whitehead ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime; 154607624df1SBryan Whitehead ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64; 154707624df1SBryan Whitehead ptp->ptp_clock_info.getcrosststamp = NULL; 154807624df1SBryan Whitehead ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64; 154907624df1SBryan Whitehead ptp->ptp_clock_info.enable = lan743x_ptpci_enable; 155007624df1SBryan Whitehead ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work; 155122820017SJohn Efstathiades ptp->ptp_clock_info.verify = lan743x_ptpci_verify_pin_config; 155207624df1SBryan Whitehead 155307624df1SBryan Whitehead ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info, 155407624df1SBryan Whitehead &adapter->pdev->dev); 155507624df1SBryan Whitehead 155607624df1SBryan Whitehead if (IS_ERR(ptp->ptp_clock)) { 155707624df1SBryan Whitehead netif_err(adapter, ifup, adapter->netdev, 155807624df1SBryan Whitehead "ptp_clock_register failed\n"); 155907624df1SBryan Whitehead goto done; 156007624df1SBryan Whitehead } 156107624df1SBryan Whitehead ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED; 156207624df1SBryan Whitehead netif_info(adapter, ifup, adapter->netdev, 156307624df1SBryan Whitehead "successfully registered ptp clock\n"); 156407624df1SBryan Whitehead 156507624df1SBryan Whitehead return 0; 156607624df1SBryan Whitehead done: 156707624df1SBryan Whitehead lan743x_ptp_close(adapter); 156807624df1SBryan Whitehead return ret; 156907624df1SBryan Whitehead } 157007624df1SBryan Whitehead 157107624df1SBryan Whitehead void lan743x_ptp_close(struct lan743x_adapter *adapter) 157207624df1SBryan Whitehead { 157307624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 157407624df1SBryan Whitehead int index; 157507624df1SBryan Whitehead 15769dc502d7SArnd Bergmann if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) && 157722820017SJohn Efstathiades (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED)) { 157807624df1SBryan Whitehead ptp_clock_unregister(ptp->ptp_clock); 157907624df1SBryan Whitehead ptp->ptp_clock = NULL; 158007624df1SBryan Whitehead ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED; 158107624df1SBryan Whitehead netif_info(adapter, drv, adapter->netdev, 158207624df1SBryan Whitehead "ptp clock unregister\n"); 158307624df1SBryan Whitehead } 158407624df1SBryan Whitehead 158507624df1SBryan Whitehead if (ptp->flags & PTP_FLAG_ISR_ENABLED) { 158607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_INT_EN_CLR, 158707624df1SBryan Whitehead PTP_INT_BIT_TX_SWTS_ERR_ | 158807624df1SBryan Whitehead PTP_INT_BIT_TX_TS_); 158907624df1SBryan Whitehead lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 159007624df1SBryan Whitehead ptp->flags &= ~PTP_FLAG_ISR_ENABLED; 159107624df1SBryan Whitehead } 159207624df1SBryan Whitehead 159307624df1SBryan Whitehead /* clean up pending timestamp requests */ 159407624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 159507624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 159607624df1SBryan Whitehead for (index = 0; 159707624df1SBryan Whitehead index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; 159807624df1SBryan Whitehead index++) { 159907624df1SBryan Whitehead struct sk_buff *skb = ptp->tx_ts_skb_queue[index]; 160007624df1SBryan Whitehead 160107624df1SBryan Whitehead dev_kfree_skb(skb); 160207624df1SBryan Whitehead ptp->tx_ts_skb_queue[index] = NULL; 160307624df1SBryan Whitehead ptp->tx_ts_seconds_queue[index] = 0; 160407624df1SBryan Whitehead ptp->tx_ts_nseconds_queue[index] = 0; 160507624df1SBryan Whitehead } 160607624df1SBryan Whitehead ptp->tx_ts_skb_queue_size = 0; 160707624df1SBryan Whitehead ptp->tx_ts_queue_size = 0; 160807624df1SBryan Whitehead ptp->pending_tx_timestamps = 0; 160907624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 161007624df1SBryan Whitehead 161122820017SJohn Efstathiades lan743x_led_mux_restore(adapter); 161222820017SJohn Efstathiades 161307624df1SBryan Whitehead lan743x_ptp_disable(adapter); 161407624df1SBryan Whitehead } 161507624df1SBryan Whitehead 161605dcc712SYueHaibing static void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter, 161707624df1SBryan Whitehead bool ts_insert_enable) 161807624df1SBryan Whitehead { 161907624df1SBryan Whitehead u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD); 162007624df1SBryan Whitehead 162107624df1SBryan Whitehead if (ts_insert_enable) 162207624df1SBryan Whitehead ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 162307624df1SBryan Whitehead else 162407624df1SBryan Whitehead ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 162507624df1SBryan Whitehead 162607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod); 162707624df1SBryan Whitehead } 162807624df1SBryan Whitehead 162907624df1SBryan Whitehead static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter) 163007624df1SBryan Whitehead { 163107624df1SBryan Whitehead if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_) 163207624df1SBryan Whitehead return true; 163307624df1SBryan Whitehead return false; 163407624df1SBryan Whitehead } 163507624df1SBryan Whitehead 163607624df1SBryan Whitehead static void lan743x_ptp_enable(struct lan743x_adapter *adapter) 163707624df1SBryan Whitehead { 163807624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 163907624df1SBryan Whitehead 164007624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 164107624df1SBryan Whitehead 164207624df1SBryan Whitehead if (lan743x_ptp_is_enabled(adapter)) { 164307624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 164407624df1SBryan Whitehead "PTP already enabled\n"); 164507624df1SBryan Whitehead goto done; 164607624df1SBryan Whitehead } 164707624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_); 164807624df1SBryan Whitehead done: 164907624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 165007624df1SBryan Whitehead } 165107624df1SBryan Whitehead 165207624df1SBryan Whitehead static void lan743x_ptp_disable(struct lan743x_adapter *adapter) 165307624df1SBryan Whitehead { 165407624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 165507624df1SBryan Whitehead 165607624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 165707624df1SBryan Whitehead if (!lan743x_ptp_is_enabled(adapter)) { 165807624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 165907624df1SBryan Whitehead "PTP already disabled\n"); 166007624df1SBryan Whitehead goto done; 166107624df1SBryan Whitehead } 166207624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_); 166307624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_); 166407624df1SBryan Whitehead done: 166507624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 166607624df1SBryan Whitehead } 166707624df1SBryan Whitehead 166807624df1SBryan Whitehead static void lan743x_ptp_reset(struct lan743x_adapter *adapter) 166907624df1SBryan Whitehead { 167007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 167107624df1SBryan Whitehead 167207624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 167307624df1SBryan Whitehead 167407624df1SBryan Whitehead if (lan743x_ptp_is_enabled(adapter)) { 167507624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 167607624df1SBryan Whitehead "Attempting reset while enabled\n"); 167707624df1SBryan Whitehead goto done; 167807624df1SBryan Whitehead } 167907624df1SBryan Whitehead 168007624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_); 168107624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_); 168207624df1SBryan Whitehead done: 168307624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 168407624df1SBryan Whitehead } 168507624df1SBryan Whitehead 168607624df1SBryan Whitehead static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter, 168707624df1SBryan Whitehead u32 seconds, u32 nano_seconds, 168807624df1SBryan Whitehead u32 sub_nano_seconds) 168907624df1SBryan Whitehead { 169007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 169107624df1SBryan Whitehead 169207624df1SBryan Whitehead mutex_lock(&ptp->command_lock); 169307624df1SBryan Whitehead 169407624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds); 169507624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds); 169607624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds); 169707624df1SBryan Whitehead 169807624df1SBryan Whitehead lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 169907624df1SBryan Whitehead lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 170007624df1SBryan Whitehead mutex_unlock(&ptp->command_lock); 170107624df1SBryan Whitehead } 170207624df1SBryan Whitehead 170307624df1SBryan Whitehead bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter) 170407624df1SBryan Whitehead { 170507624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 170607624df1SBryan Whitehead bool result = false; 170707624df1SBryan Whitehead 170807624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 170907624df1SBryan Whitehead if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 171007624df1SBryan Whitehead /* request granted */ 171107624df1SBryan Whitehead ptp->pending_tx_timestamps++; 171207624df1SBryan Whitehead result = true; 171307624df1SBryan Whitehead } 171407624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 171507624df1SBryan Whitehead return result; 171607624df1SBryan Whitehead } 171707624df1SBryan Whitehead 171807624df1SBryan Whitehead void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter) 171907624df1SBryan Whitehead { 172007624df1SBryan Whitehead struct lan743x_ptp *ptp = &adapter->ptp; 172107624df1SBryan Whitehead 172207624df1SBryan Whitehead spin_lock_bh(&ptp->tx_ts_lock); 172307624df1SBryan Whitehead if (ptp->pending_tx_timestamps > 0) 172407624df1SBryan Whitehead ptp->pending_tx_timestamps--; 172507624df1SBryan Whitehead else 172607624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 172707624df1SBryan Whitehead "unrequest failed, pending_tx_timestamps==0\n"); 172807624df1SBryan Whitehead spin_unlock_bh(&ptp->tx_ts_lock); 172907624df1SBryan Whitehead } 173007624df1SBryan Whitehead 173107624df1SBryan Whitehead void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter, 173207624df1SBryan Whitehead struct sk_buff *skb, bool ignore_sync) 173307624df1SBryan Whitehead { 173407624df1SBryan Whitehead lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync); 173507624df1SBryan Whitehead 173607624df1SBryan Whitehead lan743x_ptp_tx_ts_complete(adapter); 173707624df1SBryan Whitehead } 173807624df1SBryan Whitehead 173907624df1SBryan Whitehead int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 174007624df1SBryan Whitehead { 174107624df1SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev); 174207624df1SBryan Whitehead struct hwtstamp_config config; 174307624df1SBryan Whitehead int ret = 0; 174407624df1SBryan Whitehead int index; 174507624df1SBryan Whitehead 174607624df1SBryan Whitehead if (!ifr) { 174707624df1SBryan Whitehead netif_err(adapter, drv, adapter->netdev, 174807624df1SBryan Whitehead "SIOCSHWTSTAMP, ifr == NULL\n"); 174907624df1SBryan Whitehead return -EINVAL; 175007624df1SBryan Whitehead } 175107624df1SBryan Whitehead 175207624df1SBryan Whitehead if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 175307624df1SBryan Whitehead return -EFAULT; 175407624df1SBryan Whitehead 175507624df1SBryan Whitehead switch (config.tx_type) { 175607624df1SBryan Whitehead case HWTSTAMP_TX_OFF: 1757cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 175807624df1SBryan Whitehead index++) 175907624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 176007624df1SBryan Whitehead false, false); 176107624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, false); 176207624df1SBryan Whitehead break; 176307624df1SBryan Whitehead case HWTSTAMP_TX_ON: 1764cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 176507624df1SBryan Whitehead index++) 176607624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 176707624df1SBryan Whitehead true, false); 176807624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, false); 176907624df1SBryan Whitehead break; 177007624df1SBryan Whitehead case HWTSTAMP_TX_ONESTEP_SYNC: 1771cf9aaea8SRaju Lakkaraju for (index = 0; index < adapter->used_tx_channels; 177207624df1SBryan Whitehead index++) 177307624df1SBryan Whitehead lan743x_tx_set_timestamping_mode(&adapter->tx[index], 177407624df1SBryan Whitehead true, true); 177507624df1SBryan Whitehead 177607624df1SBryan Whitehead lan743x_ptp_set_sync_ts_insert(adapter, true); 177707624df1SBryan Whitehead break; 1778b6fd7b96SRichard Cochran case HWTSTAMP_TX_ONESTEP_P2P: 1779b6fd7b96SRichard Cochran ret = -ERANGE; 1780b6fd7b96SRichard Cochran break; 178107624df1SBryan Whitehead default: 178207624df1SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, 178307624df1SBryan Whitehead " tx_type = %d, UNKNOWN\n", config.tx_type); 178407624df1SBryan Whitehead ret = -EINVAL; 178507624df1SBryan Whitehead break; 178607624df1SBryan Whitehead } 178707624df1SBryan Whitehead 178807624df1SBryan Whitehead if (!ret) 178907624df1SBryan Whitehead return copy_to_user(ifr->ifr_data, &config, 179007624df1SBryan Whitehead sizeof(config)) ? -EFAULT : 0; 179107624df1SBryan Whitehead return ret; 179207624df1SBryan Whitehead } 1793