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