162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 262306a36Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/netdevice.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/net_tstamp.h> 1062306a36Sopenharmony_ci#include "lan743x_main.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "lan743x_ptp.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define LAN743X_LED0_ENABLE 20 /* LED0 offset in HW_CFG */ 1562306a36Sopenharmony_ci#define LAN743X_LED_ENABLE(pin) BIT(LAN743X_LED0_ENABLE + (pin)) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB (31249999) 1862306a36Sopenharmony_ci#define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM (2047999934) 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter); 2162306a36Sopenharmony_cistatic void lan743x_ptp_enable(struct lan743x_adapter *adapter); 2262306a36Sopenharmony_cistatic void lan743x_ptp_disable(struct lan743x_adapter *adapter); 2362306a36Sopenharmony_cistatic void lan743x_ptp_reset(struct lan743x_adapter *adapter); 2462306a36Sopenharmony_cistatic void lan743x_ptp_clock_set(struct lan743x_adapter *adapter, 2562306a36Sopenharmony_ci u32 seconds, u32 nano_seconds, 2662306a36Sopenharmony_ci u32 sub_nano_seconds); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int lan743x_get_channel(u32 ch_map) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci int idx; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci for (idx = 0; idx < 32; idx++) { 3362306a36Sopenharmony_ci if (ch_map & (0x1 << idx)) 3462306a36Sopenharmony_ci return idx; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return -EINVAL; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ciint lan743x_gpio_init(struct lan743x_adapter *adapter) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct lan743x_gpio *gpio = &adapter->gpio; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci spin_lock_init(&gpio->gpio_lock); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */ 4762306a36Sopenharmony_ci gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */ 4862306a36Sopenharmony_ci gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */ 4962306a36Sopenharmony_ci gpio->gpio_cfg3 = 0;/* disable all 1588 output */ 5062306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 5162306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 5262306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2); 5362306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter, 5962306a36Sopenharmony_ci u32 bit_mask) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int timeout = 1000; 6262306a36Sopenharmony_ci u32 data = 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci while (timeout && 6562306a36Sopenharmony_ci (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) & 6662306a36Sopenharmony_ci bit_mask))) { 6762306a36Sopenharmony_ci usleep_range(1000, 20000); 6862306a36Sopenharmony_ci timeout--; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci if (data) { 7162306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 7262306a36Sopenharmony_ci "timeout waiting for cmd to be done, cmd = 0x%08X\n", 7362306a36Sopenharmony_ci bit_mask); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter, 7862306a36Sopenharmony_ci u32 seconds, u32 nano_seconds, 7962306a36Sopenharmony_ci u32 header) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 8462306a36Sopenharmony_ci if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 8562306a36Sopenharmony_ci ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds; 8662306a36Sopenharmony_ci ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds; 8762306a36Sopenharmony_ci ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header; 8862306a36Sopenharmony_ci ptp->tx_ts_queue_size++; 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 9162306a36Sopenharmony_ci "tx ts queue overflow\n"); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 9962306a36Sopenharmony_ci struct skb_shared_hwtstamps tstamps; 10062306a36Sopenharmony_ci u32 header, nseconds, seconds; 10162306a36Sopenharmony_ci bool ignore_sync = false; 10262306a36Sopenharmony_ci struct sk_buff *skb; 10362306a36Sopenharmony_ci int c, i; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 10662306a36Sopenharmony_ci c = ptp->tx_ts_skb_queue_size; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (c > ptp->tx_ts_queue_size) 10962306a36Sopenharmony_ci c = ptp->tx_ts_queue_size; 11062306a36Sopenharmony_ci if (c <= 0) 11162306a36Sopenharmony_ci goto done; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < c; i++) { 11462306a36Sopenharmony_ci ignore_sync = ((ptp->tx_ts_ignore_sync_queue & 11562306a36Sopenharmony_ci BIT(i)) != 0); 11662306a36Sopenharmony_ci skb = ptp->tx_ts_skb_queue[i]; 11762306a36Sopenharmony_ci nseconds = ptp->tx_ts_nseconds_queue[i]; 11862306a36Sopenharmony_ci seconds = ptp->tx_ts_seconds_queue[i]; 11962306a36Sopenharmony_ci header = ptp->tx_ts_header_queue[i]; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci memset(&tstamps, 0, sizeof(tstamps)); 12262306a36Sopenharmony_ci tstamps.hwtstamp = ktime_set(seconds, nseconds); 12362306a36Sopenharmony_ci if (!ignore_sync || 12462306a36Sopenharmony_ci ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) != 12562306a36Sopenharmony_ci PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_)) 12662306a36Sopenharmony_ci skb_tstamp_tx(skb, &tstamps); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci dev_kfree_skb(skb); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ptp->tx_ts_skb_queue[i] = NULL; 13162306a36Sopenharmony_ci ptp->tx_ts_seconds_queue[i] = 0; 13262306a36Sopenharmony_ci ptp->tx_ts_nseconds_queue[i] = 0; 13362306a36Sopenharmony_ci ptp->tx_ts_header_queue[i] = 0; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* shift queue */ 13762306a36Sopenharmony_ci ptp->tx_ts_ignore_sync_queue >>= c; 13862306a36Sopenharmony_ci for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) { 13962306a36Sopenharmony_ci ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i]; 14062306a36Sopenharmony_ci ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i]; 14162306a36Sopenharmony_ci ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i]; 14262306a36Sopenharmony_ci ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i]; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ptp->tx_ts_skb_queue[i] = NULL; 14562306a36Sopenharmony_ci ptp->tx_ts_seconds_queue[i] = 0; 14662306a36Sopenharmony_ci ptp->tx_ts_nseconds_queue[i] = 0; 14762306a36Sopenharmony_ci ptp->tx_ts_header_queue[i] = 0; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci ptp->tx_ts_skb_queue_size -= c; 15062306a36Sopenharmony_ci ptp->tx_ts_queue_size -= c; 15162306a36Sopenharmony_cidone: 15262306a36Sopenharmony_ci ptp->pending_tx_timestamps -= c; 15362306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter, 15762306a36Sopenharmony_ci int event_channel) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 16062306a36Sopenharmony_ci int result = -ENODEV; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 16362306a36Sopenharmony_ci if (!(test_bit(event_channel, &ptp->used_event_ch))) { 16462306a36Sopenharmony_ci ptp->used_event_ch |= BIT(event_channel); 16562306a36Sopenharmony_ci result = event_channel; 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 16862306a36Sopenharmony_ci "attempted to reserved a used event_channel = %d\n", 16962306a36Sopenharmony_ci event_channel); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 17262306a36Sopenharmony_ci return result; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter, 17662306a36Sopenharmony_ci int event_channel) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 18162306a36Sopenharmony_ci if (test_bit(event_channel, &ptp->used_event_ch)) { 18262306a36Sopenharmony_ci ptp->used_event_ch &= ~BIT(event_channel); 18362306a36Sopenharmony_ci } else { 18462306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 18562306a36Sopenharmony_ci "attempted release on a not used event_channel = %d\n", 18662306a36Sopenharmony_ci event_channel); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, 19262306a36Sopenharmony_ci u32 *seconds, u32 *nano_seconds, 19362306a36Sopenharmony_ci u32 *sub_nano_seconds); 19462306a36Sopenharmony_cistatic void lan743x_ptp_io_clock_get(struct lan743x_adapter *adapter, 19562306a36Sopenharmony_ci u32 *sec, u32 *nsec, u32 *sub_nsec); 19662306a36Sopenharmony_cistatic void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, 19762306a36Sopenharmony_ci s64 time_step_ns); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void lan743x_led_mux_enable(struct lan743x_adapter *adapter, 20062306a36Sopenharmony_ci int pin, bool enable) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (ptp->leds_multiplexed && 20562306a36Sopenharmony_ci ptp->led_enabled[pin]) { 20662306a36Sopenharmony_ci u32 val = lan743x_csr_read(adapter, HW_CFG); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (enable) 20962306a36Sopenharmony_ci val |= LAN743X_LED_ENABLE(pin); 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci val &= ~LAN743X_LED_ENABLE(pin); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci lan743x_csr_write(adapter, HW_CFG, val); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void lan743x_led_mux_save(struct lan743x_adapter *adapter) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 22062306a36Sopenharmony_ci u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (id_rev == ID_REV_ID_LAN7430_) { 22362306a36Sopenharmony_ci int i; 22462306a36Sopenharmony_ci u32 val = lan743x_csr_read(adapter, HW_CFG); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci for (i = 0; i < LAN7430_N_LED; i++) { 22762306a36Sopenharmony_ci bool led_enabled = (val & LAN743X_LED_ENABLE(i)) != 0; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ptp->led_enabled[i] = led_enabled; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci ptp->leds_multiplexed = true; 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci ptp->leds_multiplexed = false; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void lan743x_led_mux_restore(struct lan743x_adapter *adapter) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (id_rev == ID_REV_ID_LAN7430_) { 24262306a36Sopenharmony_ci int i; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < LAN7430_N_LED; i++) 24562306a36Sopenharmony_ci lan743x_led_mux_enable(adapter, i, true); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter, 25062306a36Sopenharmony_ci int pin, int event_channel) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct lan743x_gpio *gpio = &adapter->gpio; 25362306a36Sopenharmony_ci unsigned long irq_flags = 0; 25462306a36Sopenharmony_ci int bit_mask = BIT(pin); 25562306a36Sopenharmony_ci int ret = -EBUSY; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock_irqsave(&gpio->gpio_lock, irq_flags); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!(gpio->used_bits & bit_mask)) { 26062306a36Sopenharmony_ci gpio->used_bits |= bit_mask; 26162306a36Sopenharmony_ci gpio->output_bits |= bit_mask; 26262306a36Sopenharmony_ci gpio->ptp_bits |= bit_mask; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* assign pin to GPIO function */ 26562306a36Sopenharmony_ci lan743x_led_mux_enable(adapter, pin, false); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* set as output, and zero initial value */ 26862306a36Sopenharmony_ci gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(pin); 26962306a36Sopenharmony_ci gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); 27062306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* enable gpio, and set buffer type to push pull */ 27362306a36Sopenharmony_ci gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(pin); 27462306a36Sopenharmony_ci gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(pin); 27562306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* set 1588 polarity to high */ 27862306a36Sopenharmony_ci gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(pin); 27962306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (event_channel == 0) { 28262306a36Sopenharmony_ci /* use channel A */ 28362306a36Sopenharmony_ci gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(pin); 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci /* use channel B */ 28662306a36Sopenharmony_ci gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(pin); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(pin); 28962306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ret = pin; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void lan743x_gpio_release(struct lan743x_adapter *adapter, int pin) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct lan743x_gpio *gpio = &adapter->gpio; 30062306a36Sopenharmony_ci unsigned long irq_flags = 0; 30162306a36Sopenharmony_ci int bit_mask = BIT(pin); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci spin_lock_irqsave(&gpio->gpio_lock, irq_flags); 30462306a36Sopenharmony_ci if (gpio->used_bits & bit_mask) { 30562306a36Sopenharmony_ci gpio->used_bits &= ~bit_mask; 30662306a36Sopenharmony_ci if (gpio->output_bits & bit_mask) { 30762306a36Sopenharmony_ci gpio->output_bits &= ~bit_mask; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (gpio->ptp_bits & bit_mask) { 31062306a36Sopenharmony_ci gpio->ptp_bits &= ~bit_mask; 31162306a36Sopenharmony_ci /* disable ptp output */ 31262306a36Sopenharmony_ci gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(pin); 31362306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG3, 31462306a36Sopenharmony_ci gpio->gpio_cfg3); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci /* release gpio output */ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* disable gpio */ 31962306a36Sopenharmony_ci gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(pin); 32062306a36Sopenharmony_ci gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(pin); 32162306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* reset back to input */ 32462306a36Sopenharmony_ci gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(pin); 32562306a36Sopenharmony_ci gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); 32662306a36Sopenharmony_ci lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* assign pin to original function */ 32962306a36Sopenharmony_ci lan743x_led_mux_enable(adapter, pin, true); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct lan743x_ptp *ptp = 33862306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 33962306a36Sopenharmony_ci struct lan743x_adapter *adapter = 34062306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 34162306a36Sopenharmony_ci u32 lan743x_rate_adj = 0; 34262306a36Sopenharmony_ci u64 u64_delta; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) || 34562306a36Sopenharmony_ci scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) { 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* diff_by_scaled_ppm returns true if the difference is negative */ 35062306a36Sopenharmony_ci if (diff_by_scaled_ppm(1ULL << 35, scaled_ppm, &u64_delta)) 35162306a36Sopenharmony_ci lan743x_rate_adj = (u32)u64_delta; 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci lan743x_rate_adj = (u32)u64_delta | PTP_CLOCK_RATE_ADJ_DIR_; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ, 35662306a36Sopenharmony_ci lan743x_rate_adj); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct lan743x_ptp *ptp = 36462306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 36562306a36Sopenharmony_ci struct lan743x_adapter *adapter = 36662306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci lan743x_ptp_clock_step(adapter, delta); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci, 37462306a36Sopenharmony_ci struct timespec64 *ts) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct lan743x_ptp *ptp = 37762306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 37862306a36Sopenharmony_ci struct lan743x_adapter *adapter = 37962306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 38062306a36Sopenharmony_ci u32 nano_seconds = 0; 38162306a36Sopenharmony_ci u32 seconds = 0; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (adapter->is_pci11x1x) 38462306a36Sopenharmony_ci lan743x_ptp_io_clock_get(adapter, &seconds, &nano_seconds, 38562306a36Sopenharmony_ci NULL); 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL); 38862306a36Sopenharmony_ci ts->tv_sec = seconds; 38962306a36Sopenharmony_ci ts->tv_nsec = nano_seconds; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci, 39562306a36Sopenharmony_ci const struct timespec64 *ts) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct lan743x_ptp *ptp = 39862306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 39962306a36Sopenharmony_ci struct lan743x_adapter *adapter = 40062306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 40162306a36Sopenharmony_ci u32 nano_seconds = 0; 40262306a36Sopenharmony_ci u32 seconds = 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (ts) { 40562306a36Sopenharmony_ci if (ts->tv_sec > 0xFFFFFFFFLL || 40662306a36Sopenharmony_ci ts->tv_sec < 0) { 40762306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 40862306a36Sopenharmony_ci "ts->tv_sec out of range, %lld\n", 40962306a36Sopenharmony_ci ts->tv_sec); 41062306a36Sopenharmony_ci return -ERANGE; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci if (ts->tv_nsec >= 1000000000L || 41362306a36Sopenharmony_ci ts->tv_nsec < 0) { 41462306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 41562306a36Sopenharmony_ci "ts->tv_nsec out of range, %ld\n", 41662306a36Sopenharmony_ci ts->tv_nsec); 41762306a36Sopenharmony_ci return -ERANGE; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci seconds = ts->tv_sec; 42062306a36Sopenharmony_ci nano_seconds = ts->tv_nsec; 42162306a36Sopenharmony_ci lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0); 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n"); 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void lan743x_ptp_perout_off(struct lan743x_adapter *adapter, 43162306a36Sopenharmony_ci unsigned int index) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 43462306a36Sopenharmony_ci u32 general_config = 0; 43562306a36Sopenharmony_ci struct lan743x_ptp_perout *perout = &ptp->perout[index]; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (perout->gpio_pin >= 0) { 43862306a36Sopenharmony_ci lan743x_gpio_release(adapter, perout->gpio_pin); 43962306a36Sopenharmony_ci perout->gpio_pin = -1; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (perout->event_ch >= 0) { 44362306a36Sopenharmony_ci /* set target to far in the future, effectively disabling it */ 44462306a36Sopenharmony_ci lan743x_csr_write(adapter, 44562306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 44662306a36Sopenharmony_ci 0xFFFF0000); 44762306a36Sopenharmony_ci lan743x_csr_write(adapter, 44862306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(perout->event_ch), 44962306a36Sopenharmony_ci 0); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 45262306a36Sopenharmony_ci general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 45362306a36Sopenharmony_ci (perout->event_ch); 45462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 45562306a36Sopenharmony_ci lan743x_ptp_release_event_ch(adapter, perout->event_ch); 45662306a36Sopenharmony_ci perout->event_ch = -1; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, 46162306a36Sopenharmony_ci struct ptp_perout_request *perout_request) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 46462306a36Sopenharmony_ci u32 period_sec = 0, period_nsec = 0; 46562306a36Sopenharmony_ci u32 start_sec = 0, start_nsec = 0; 46662306a36Sopenharmony_ci u32 general_config = 0; 46762306a36Sopenharmony_ci int pulse_width = 0; 46862306a36Sopenharmony_ci int perout_pin = 0; 46962306a36Sopenharmony_ci unsigned int index = perout_request->index; 47062306a36Sopenharmony_ci struct lan743x_ptp_perout *perout = &ptp->perout[index]; 47162306a36Sopenharmony_ci int ret = 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 47462306a36Sopenharmony_ci if (perout_request->flags & ~PTP_PEROUT_DUTY_CYCLE) 47562306a36Sopenharmony_ci return -EOPNOTSUPP; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (on) { 47862306a36Sopenharmony_ci perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, 47962306a36Sopenharmony_ci perout_request->index); 48062306a36Sopenharmony_ci if (perout_pin < 0) 48162306a36Sopenharmony_ci return -EBUSY; 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci lan743x_ptp_perout_off(adapter, index); 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (perout->event_ch >= 0 || 48862306a36Sopenharmony_ci perout->gpio_pin >= 0) { 48962306a36Sopenharmony_ci /* already on, turn off first */ 49062306a36Sopenharmony_ci lan743x_ptp_perout_off(adapter, index); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci perout->event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (perout->event_ch < 0) { 49662306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 49762306a36Sopenharmony_ci "Failed to reserve event channel %d for PEROUT\n", 49862306a36Sopenharmony_ci index); 49962306a36Sopenharmony_ci ret = -EBUSY; 50062306a36Sopenharmony_ci goto failed; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci perout->gpio_pin = lan743x_gpio_rsrv_ptp_out(adapter, 50462306a36Sopenharmony_ci perout_pin, 50562306a36Sopenharmony_ci perout->event_ch); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (perout->gpio_pin < 0) { 50862306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 50962306a36Sopenharmony_ci "Failed to reserve gpio %d for PEROUT\n", 51062306a36Sopenharmony_ci perout_pin); 51162306a36Sopenharmony_ci ret = -EBUSY; 51262306a36Sopenharmony_ci goto failed; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci start_sec = perout_request->start.sec; 51662306a36Sopenharmony_ci start_sec += perout_request->start.nsec / 1000000000; 51762306a36Sopenharmony_ci start_nsec = perout_request->start.nsec % 1000000000; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci period_sec = perout_request->period.sec; 52062306a36Sopenharmony_ci period_sec += perout_request->period.nsec / 1000000000; 52162306a36Sopenharmony_ci period_nsec = perout_request->period.nsec % 1000000000; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 52462306a36Sopenharmony_ci struct timespec64 ts_on, ts_period; 52562306a36Sopenharmony_ci s64 wf_high, period64, half; 52662306a36Sopenharmony_ci s32 reminder; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ts_on.tv_sec = perout_request->on.sec; 52962306a36Sopenharmony_ci ts_on.tv_nsec = perout_request->on.nsec; 53062306a36Sopenharmony_ci wf_high = timespec64_to_ns(&ts_on); 53162306a36Sopenharmony_ci ts_period.tv_sec = perout_request->period.sec; 53262306a36Sopenharmony_ci ts_period.tv_nsec = perout_request->period.nsec; 53362306a36Sopenharmony_ci period64 = timespec64_to_ns(&ts_period); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (period64 < 200) { 53662306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 53762306a36Sopenharmony_ci "perout period too small, minimum is 200nS\n"); 53862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 53962306a36Sopenharmony_ci goto failed; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci if (wf_high >= period64) { 54262306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 54362306a36Sopenharmony_ci "pulse width must be smaller than period\n"); 54462306a36Sopenharmony_ci ret = -EINVAL; 54562306a36Sopenharmony_ci goto failed; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Check if we can do 50% toggle on an even value of period. 54962306a36Sopenharmony_ci * If the period number is odd, then check if the requested 55062306a36Sopenharmony_ci * pulse width is the same as one of pre-defined width values. 55162306a36Sopenharmony_ci * Otherwise, return failure. 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_ci half = div_s64_rem(period64, 2, &reminder); 55462306a36Sopenharmony_ci if (!reminder) { 55562306a36Sopenharmony_ci if (half == wf_high) { 55662306a36Sopenharmony_ci /* It's 50% match. Use the toggle option */ 55762306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_; 55862306a36Sopenharmony_ci /* In this case, devide period value by 2 */ 55962306a36Sopenharmony_ci ts_period = ns_to_timespec64(div_s64(period64, 2)); 56062306a36Sopenharmony_ci period_sec = ts_period.tv_sec; 56162306a36Sopenharmony_ci period_nsec = ts_period.tv_nsec; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci goto program; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci /* if we can't do toggle, then the width option needs to be the exact match */ 56762306a36Sopenharmony_ci if (wf_high == 200000000) { 56862306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 56962306a36Sopenharmony_ci } else if (wf_high == 10000000) { 57062306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 57162306a36Sopenharmony_ci } else if (wf_high == 1000000) { 57262306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 57362306a36Sopenharmony_ci } else if (wf_high == 100000) { 57462306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 57562306a36Sopenharmony_ci } else if (wf_high == 10000) { 57662306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 57762306a36Sopenharmony_ci } else if (wf_high == 100) { 57862306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 57962306a36Sopenharmony_ci } else { 58062306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 58162306a36Sopenharmony_ci "duty cycle specified is not supported\n"); 58262306a36Sopenharmony_ci ret = -EOPNOTSUPP; 58362306a36Sopenharmony_ci goto failed; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } else { 58662306a36Sopenharmony_ci if (period_sec == 0) { 58762306a36Sopenharmony_ci if (period_nsec >= 400000000) { 58862306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 58962306a36Sopenharmony_ci } else if (period_nsec >= 20000000) { 59062306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 59162306a36Sopenharmony_ci } else if (period_nsec >= 2000000) { 59262306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 59362306a36Sopenharmony_ci } else if (period_nsec >= 200000) { 59462306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 59562306a36Sopenharmony_ci } else if (period_nsec >= 20000) { 59662306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 59762306a36Sopenharmony_ci } else if (period_nsec >= 200) { 59862306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 59962306a36Sopenharmony_ci } else { 60062306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 60162306a36Sopenharmony_ci "perout period too small, minimum is 200nS\n"); 60262306a36Sopenharmony_ci ret = -EOPNOTSUPP; 60362306a36Sopenharmony_ci goto failed; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci } else { 60662306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ciprogram: 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* turn off by setting target far in future */ 61262306a36Sopenharmony_ci lan743x_csr_write(adapter, 61362306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 61462306a36Sopenharmony_ci 0xFFFF0000); 61562306a36Sopenharmony_ci lan743x_csr_write(adapter, 61662306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Configure to pulse every period */ 61962306a36Sopenharmony_ci general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); 62062306a36Sopenharmony_ci general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 62162306a36Sopenharmony_ci (perout->event_ch)); 62262306a36Sopenharmony_ci general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 62362306a36Sopenharmony_ci (perout->event_ch, pulse_width); 62462306a36Sopenharmony_ci general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_ 62562306a36Sopenharmony_ci (perout->event_ch); 62662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* set the reload to one toggle cycle */ 62962306a36Sopenharmony_ci lan743x_csr_write(adapter, 63062306a36Sopenharmony_ci PTP_CLOCK_TARGET_RELOAD_SEC_X(perout->event_ch), 63162306a36Sopenharmony_ci period_sec); 63262306a36Sopenharmony_ci lan743x_csr_write(adapter, 63362306a36Sopenharmony_ci PTP_CLOCK_TARGET_RELOAD_NS_X(perout->event_ch), 63462306a36Sopenharmony_ci period_nsec); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* set the start time */ 63762306a36Sopenharmony_ci lan743x_csr_write(adapter, 63862306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 63962306a36Sopenharmony_ci start_sec); 64062306a36Sopenharmony_ci lan743x_csr_write(adapter, 64162306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(perout->event_ch), 64262306a36Sopenharmony_ci start_nsec); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cifailed: 64762306a36Sopenharmony_ci lan743x_ptp_perout_off(adapter, index); 64862306a36Sopenharmony_ci return ret; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic void lan743x_ptp_io_perout_off(struct lan743x_adapter *adapter, 65262306a36Sopenharmony_ci u32 index) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 65562306a36Sopenharmony_ci int perout_pin; 65662306a36Sopenharmony_ci int event_ch; 65762306a36Sopenharmony_ci u32 gen_cfg; 65862306a36Sopenharmony_ci int val; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci event_ch = ptp->ptp_io_perout[index]; 66162306a36Sopenharmony_ci if (event_ch >= 0) { 66262306a36Sopenharmony_ci /* set target to far in the future, effectively disabling it */ 66362306a36Sopenharmony_ci lan743x_csr_write(adapter, 66462306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(event_ch), 66562306a36Sopenharmony_ci 0xFFFF0000); 66662306a36Sopenharmony_ci lan743x_csr_write(adapter, 66762306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(event_ch), 66862306a36Sopenharmony_ci 0); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 67162306a36Sopenharmony_ci gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ 67262306a36Sopenharmony_ci (event_ch)); 67362306a36Sopenharmony_ci gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch)); 67462306a36Sopenharmony_ci gen_cfg |= HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch); 67562306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 67662306a36Sopenharmony_ci if (event_ch) 67762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 67862306a36Sopenharmony_ci PTP_INT_TIMER_INT_B_); 67962306a36Sopenharmony_ci else 68062306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 68162306a36Sopenharmony_ci PTP_INT_TIMER_INT_A_); 68262306a36Sopenharmony_ci lan743x_ptp_release_event_ch(adapter, event_ch); 68362306a36Sopenharmony_ci ptp->ptp_io_perout[index] = -1; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Deselect Event output */ 68962306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* Disables the output of Local Time Target compare events */ 69262306a36Sopenharmony_ci val &= ~PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 69362306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Configured as an opendrain driver*/ 69662306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 69762306a36Sopenharmony_ci val &= ~PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 69862306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 69962306a36Sopenharmony_ci /* Dummy read to make sure write operation success */ 70062306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int lan743x_ptp_io_perout(struct lan743x_adapter *adapter, int on, 70462306a36Sopenharmony_ci struct ptp_perout_request *perout_request) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 70762306a36Sopenharmony_ci u32 period_sec, period_nsec; 70862306a36Sopenharmony_ci u32 start_sec, start_nsec; 70962306a36Sopenharmony_ci u32 pulse_sec, pulse_nsec; 71062306a36Sopenharmony_ci int pulse_width; 71162306a36Sopenharmony_ci int perout_pin; 71262306a36Sopenharmony_ci int event_ch; 71362306a36Sopenharmony_ci u32 gen_cfg; 71462306a36Sopenharmony_ci u32 index; 71562306a36Sopenharmony_ci int val; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci index = perout_request->index; 71862306a36Sopenharmony_ci event_ch = ptp->ptp_io_perout[index]; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (on) { 72162306a36Sopenharmony_ci perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index); 72262306a36Sopenharmony_ci if (perout_pin < 0) 72362306a36Sopenharmony_ci return -EBUSY; 72462306a36Sopenharmony_ci } else { 72562306a36Sopenharmony_ci lan743x_ptp_io_perout_off(adapter, index); 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (event_ch >= LAN743X_PTP_N_EVENT_CHAN) { 73062306a36Sopenharmony_ci /* already on, turn off first */ 73162306a36Sopenharmony_ci lan743x_ptp_io_perout_off(adapter, index); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci event_ch = lan743x_ptp_reserve_event_ch(adapter, index); 73562306a36Sopenharmony_ci if (event_ch < 0) { 73662306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 73762306a36Sopenharmony_ci "Failed to reserve event channel %d for PEROUT\n", 73862306a36Sopenharmony_ci index); 73962306a36Sopenharmony_ci goto failed; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci ptp->ptp_io_perout[index] = event_ch; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) { 74462306a36Sopenharmony_ci pulse_sec = perout_request->on.sec; 74562306a36Sopenharmony_ci pulse_sec += perout_request->on.nsec / 1000000000; 74662306a36Sopenharmony_ci pulse_nsec = perout_request->on.nsec % 1000000000; 74762306a36Sopenharmony_ci } else { 74862306a36Sopenharmony_ci pulse_sec = perout_request->period.sec; 74962306a36Sopenharmony_ci pulse_sec += perout_request->period.nsec / 1000000000; 75062306a36Sopenharmony_ci pulse_nsec = perout_request->period.nsec % 1000000000; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (pulse_sec == 0) { 75462306a36Sopenharmony_ci if (pulse_nsec >= 400000000) { 75562306a36Sopenharmony_ci pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 75662306a36Sopenharmony_ci } else if (pulse_nsec >= 200000000) { 75762306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_; 75862306a36Sopenharmony_ci } else if (pulse_nsec >= 100000000) { 75962306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_; 76062306a36Sopenharmony_ci } else if (pulse_nsec >= 20000000) { 76162306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_; 76262306a36Sopenharmony_ci } else if (pulse_nsec >= 10000000) { 76362306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_; 76462306a36Sopenharmony_ci } else if (pulse_nsec >= 2000000) { 76562306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_; 76662306a36Sopenharmony_ci } else if (pulse_nsec >= 1000000) { 76762306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_; 76862306a36Sopenharmony_ci } else if (pulse_nsec >= 200000) { 76962306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_; 77062306a36Sopenharmony_ci } else if (pulse_nsec >= 100000) { 77162306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_; 77262306a36Sopenharmony_ci } else if (pulse_nsec >= 20000) { 77362306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_; 77462306a36Sopenharmony_ci } else if (pulse_nsec >= 10000) { 77562306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_; 77662306a36Sopenharmony_ci } else if (pulse_nsec >= 2000) { 77762306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_; 77862306a36Sopenharmony_ci } else if (pulse_nsec >= 1000) { 77962306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_; 78062306a36Sopenharmony_ci } else if (pulse_nsec >= 200) { 78162306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_; 78262306a36Sopenharmony_ci } else { 78362306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 78462306a36Sopenharmony_ci "perout period too small, min is 200nS\n"); 78562306a36Sopenharmony_ci goto failed; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci } else { 78862306a36Sopenharmony_ci pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* turn off by setting target far in future */ 79262306a36Sopenharmony_ci lan743x_csr_write(adapter, 79362306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(event_ch), 79462306a36Sopenharmony_ci 0xFFFF0000); 79562306a36Sopenharmony_ci lan743x_csr_write(adapter, 79662306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(event_ch), 0); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* Configure to pulse every period */ 79962306a36Sopenharmony_ci gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG); 80062306a36Sopenharmony_ci gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(event_ch)); 80162306a36Sopenharmony_ci gen_cfg |= HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ 80262306a36Sopenharmony_ci (event_ch, pulse_width); 80362306a36Sopenharmony_ci gen_cfg |= HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch); 80462306a36Sopenharmony_ci gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch)); 80562306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* set the reload to one toggle cycle */ 80862306a36Sopenharmony_ci period_sec = perout_request->period.sec; 80962306a36Sopenharmony_ci period_sec += perout_request->period.nsec / 1000000000; 81062306a36Sopenharmony_ci period_nsec = perout_request->period.nsec % 1000000000; 81162306a36Sopenharmony_ci lan743x_csr_write(adapter, 81262306a36Sopenharmony_ci PTP_CLOCK_TARGET_RELOAD_SEC_X(event_ch), 81362306a36Sopenharmony_ci period_sec); 81462306a36Sopenharmony_ci lan743x_csr_write(adapter, 81562306a36Sopenharmony_ci PTP_CLOCK_TARGET_RELOAD_NS_X(event_ch), 81662306a36Sopenharmony_ci period_nsec); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci start_sec = perout_request->start.sec; 81962306a36Sopenharmony_ci start_sec += perout_request->start.nsec / 1000000000; 82062306a36Sopenharmony_ci start_nsec = perout_request->start.nsec % 1000000000; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* set the start time */ 82362306a36Sopenharmony_ci lan743x_csr_write(adapter, 82462306a36Sopenharmony_ci PTP_CLOCK_TARGET_SEC_X(event_ch), 82562306a36Sopenharmony_ci start_sec); 82662306a36Sopenharmony_ci lan743x_csr_write(adapter, 82762306a36Sopenharmony_ci PTP_CLOCK_TARGET_NS_X(event_ch), 82862306a36Sopenharmony_ci start_nsec); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* Enable LTC Target Read */ 83162306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_CMD_CTL); 83262306a36Sopenharmony_ci val |= PTP_CMD_CTL_PTP_LTC_TARGET_READ_; 83362306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, val); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* Configure as an push/pull driver */ 83662306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG); 83762306a36Sopenharmony_ci val |= PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin); 83862306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Select Event output */ 84162306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG); 84262306a36Sopenharmony_ci if (event_ch) 84362306a36Sopenharmony_ci /* Channel B as the output */ 84462306a36Sopenharmony_ci val |= PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 84562306a36Sopenharmony_ci else 84662306a36Sopenharmony_ci /* Channel A as the output */ 84762306a36Sopenharmony_ci val &= ~PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* Enables the output of Local Time Target compare events */ 85062306a36Sopenharmony_ci val |= PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin); 85162306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return 0; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cifailed: 85662306a36Sopenharmony_ci lan743x_ptp_io_perout_off(adapter, index); 85762306a36Sopenharmony_ci return -ENODEV; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void lan743x_ptp_io_extts_off(struct lan743x_adapter *adapter, 86162306a36Sopenharmony_ci u32 index) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 86462306a36Sopenharmony_ci struct lan743x_extts *extts; 86562306a36Sopenharmony_ci int val; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci extts = &ptp->extts[index]; 86862306a36Sopenharmony_ci /* PTP Interrupt Enable Clear Register */ 86962306a36Sopenharmony_ci if (extts->flags & PTP_FALLING_EDGE) 87062306a36Sopenharmony_ci val = PTP_INT_EN_FE_EN_CLR_(index); 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci val = PTP_INT_EN_RE_EN_CLR_(index); 87362306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_EN_CLR, val); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Disables PTP-IO edge lock */ 87662306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 87762306a36Sopenharmony_ci if (extts->flags & PTP_FALLING_EDGE) { 87862306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(index); 87962306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(index); 88062306a36Sopenharmony_ci } else { 88162306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(index); 88262306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(index); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* PTP-IO De-select register */ 88762306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_SEL); 88862306a36Sopenharmony_ci val &= ~PTP_IO_SEL_MASK_; 88962306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_SEL, val); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* Clear timestamp */ 89262306a36Sopenharmony_ci memset(&extts->ts, 0, sizeof(struct timespec64)); 89362306a36Sopenharmony_ci extts->flags = 0; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int lan743x_ptp_io_event_cap_en(struct lan743x_adapter *adapter, 89762306a36Sopenharmony_ci u32 flags, u32 channel) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 90062306a36Sopenharmony_ci int val; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if ((flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES) 90362306a36Sopenharmony_ci return -EOPNOTSUPP; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 90662306a36Sopenharmony_ci /* PTP-IO Event Capture Enable */ 90762306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_CAP_CONFIG); 90862306a36Sopenharmony_ci if (flags & PTP_FALLING_EDGE) { 90962306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 91062306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 91162306a36Sopenharmony_ci val |= PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 91262306a36Sopenharmony_ci val |= PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 91362306a36Sopenharmony_ci } else { 91462306a36Sopenharmony_ci /* Rising eventing as Default */ 91562306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_LOCK_FE_(channel); 91662306a36Sopenharmony_ci val &= ~PTP_IO_CAP_CONFIG_FE_CAP_EN_(channel); 91762306a36Sopenharmony_ci val |= PTP_IO_CAP_CONFIG_LOCK_RE_(channel); 91862306a36Sopenharmony_ci val |= PTP_IO_CAP_CONFIG_RE_CAP_EN_(channel); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_CAP_CONFIG, val); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* PTP-IO Select */ 92362306a36Sopenharmony_ci val = lan743x_csr_read(adapter, PTP_IO_SEL); 92462306a36Sopenharmony_ci val &= ~PTP_IO_SEL_MASK_; 92562306a36Sopenharmony_ci val |= channel << PTP_IO_SEL_SHIFT_; 92662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_IO_SEL, val); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* PTP Interrupt Enable Register */ 92962306a36Sopenharmony_ci if (flags & PTP_FALLING_EDGE) 93062306a36Sopenharmony_ci val = PTP_INT_EN_FE_EN_SET_(channel); 93162306a36Sopenharmony_ci else 93262306a36Sopenharmony_ci val = PTP_INT_EN_RE_EN_SET_(channel); 93362306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_EN_SET, val); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int lan743x_ptp_io_extts(struct lan743x_adapter *adapter, int on, 94162306a36Sopenharmony_ci struct ptp_extts_request *extts_request) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 94462306a36Sopenharmony_ci u32 flags = extts_request->flags; 94562306a36Sopenharmony_ci u32 index = extts_request->index; 94662306a36Sopenharmony_ci struct lan743x_extts *extts; 94762306a36Sopenharmony_ci int extts_pin; 94862306a36Sopenharmony_ci int ret = 0; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci extts = &ptp->extts[index]; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (on) { 95362306a36Sopenharmony_ci extts_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, index); 95462306a36Sopenharmony_ci if (extts_pin < 0) 95562306a36Sopenharmony_ci return -EBUSY; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci ret = lan743x_ptp_io_event_cap_en(adapter, flags, index); 95862306a36Sopenharmony_ci if (!ret) 95962306a36Sopenharmony_ci extts->flags = flags; 96062306a36Sopenharmony_ci } else { 96162306a36Sopenharmony_ci lan743x_ptp_io_extts_off(adapter, index); 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return ret; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_cistatic int lan743x_ptpci_enable(struct ptp_clock_info *ptpci, 96862306a36Sopenharmony_ci struct ptp_clock_request *request, int on) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct lan743x_ptp *ptp = 97162306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 97262306a36Sopenharmony_ci struct lan743x_adapter *adapter = 97362306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (request) { 97662306a36Sopenharmony_ci switch (request->type) { 97762306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 97862306a36Sopenharmony_ci if (request->extts.index < ptpci->n_ext_ts) 97962306a36Sopenharmony_ci return lan743x_ptp_io_extts(adapter, on, 98062306a36Sopenharmony_ci &request->extts); 98162306a36Sopenharmony_ci return -EINVAL; 98262306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 98362306a36Sopenharmony_ci if (request->perout.index < ptpci->n_per_out) { 98462306a36Sopenharmony_ci if (adapter->is_pci11x1x) 98562306a36Sopenharmony_ci return lan743x_ptp_io_perout(adapter, on, 98662306a36Sopenharmony_ci &request->perout); 98762306a36Sopenharmony_ci else 98862306a36Sopenharmony_ci return lan743x_ptp_perout(adapter, on, 98962306a36Sopenharmony_ci &request->perout); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci return -EINVAL; 99262306a36Sopenharmony_ci case PTP_CLK_REQ_PPS: 99362306a36Sopenharmony_ci return -EINVAL; 99462306a36Sopenharmony_ci default: 99562306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 99662306a36Sopenharmony_ci "request->type == %d, Unknown\n", 99762306a36Sopenharmony_ci request->type); 99862306a36Sopenharmony_ci break; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci } else { 100162306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, "request == NULL\n"); 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic int lan743x_ptpci_verify_pin_config(struct ptp_clock_info *ptp, 100762306a36Sopenharmony_ci unsigned int pin, 100862306a36Sopenharmony_ci enum ptp_pin_function func, 100962306a36Sopenharmony_ci unsigned int chan) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct lan743x_ptp *lan_ptp = 101262306a36Sopenharmony_ci container_of(ptp, struct lan743x_ptp, ptp_clock_info); 101362306a36Sopenharmony_ci struct lan743x_adapter *adapter = 101462306a36Sopenharmony_ci container_of(lan_ptp, struct lan743x_adapter, ptp); 101562306a36Sopenharmony_ci int result = 0; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* Confirm the requested function is supported. Parameter 101862306a36Sopenharmony_ci * validation is done by the caller. 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ci switch (func) { 102162306a36Sopenharmony_ci case PTP_PF_NONE: 102262306a36Sopenharmony_ci case PTP_PF_PEROUT: 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci case PTP_PF_EXTTS: 102562306a36Sopenharmony_ci if (!adapter->is_pci11x1x) 102662306a36Sopenharmony_ci result = -1; 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci case PTP_PF_PHYSYNC: 102962306a36Sopenharmony_ci default: 103062306a36Sopenharmony_ci result = -1; 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci return result; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic void lan743x_ptp_io_event_clock_get(struct lan743x_adapter *adapter, 103762306a36Sopenharmony_ci bool fe, u8 channel, 103862306a36Sopenharmony_ci struct timespec64 *ts) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 104162306a36Sopenharmony_ci struct lan743x_extts *extts; 104262306a36Sopenharmony_ci u32 sec, nsec; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 104562306a36Sopenharmony_ci if (fe) { 104662306a36Sopenharmony_ci sec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_SEC_CAP_X); 104762306a36Sopenharmony_ci nsec = lan743x_csr_read(adapter, PTP_IO_FE_LTC_NS_CAP_X); 104862306a36Sopenharmony_ci } else { 104962306a36Sopenharmony_ci sec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_SEC_CAP_X); 105062306a36Sopenharmony_ci nsec = lan743x_csr_read(adapter, PTP_IO_RE_LTC_NS_CAP_X); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Update Local timestamp */ 105662306a36Sopenharmony_ci extts = &ptp->extts[channel]; 105762306a36Sopenharmony_ci extts->ts.tv_sec = sec; 105862306a36Sopenharmony_ci extts->ts.tv_nsec = nsec; 105962306a36Sopenharmony_ci ts->tv_sec = sec; 106062306a36Sopenharmony_ci ts->tv_nsec = nsec; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci struct lan743x_ptp *ptp = 106662306a36Sopenharmony_ci container_of(ptpci, struct lan743x_ptp, ptp_clock_info); 106762306a36Sopenharmony_ci struct lan743x_adapter *adapter = 106862306a36Sopenharmony_ci container_of(ptp, struct lan743x_adapter, ptp); 106962306a36Sopenharmony_ci u32 cap_info, cause, header, nsec, seconds; 107062306a36Sopenharmony_ci bool new_timestamp_available = false; 107162306a36Sopenharmony_ci struct ptp_clock_event ptp_event; 107262306a36Sopenharmony_ci struct timespec64 ts; 107362306a36Sopenharmony_ci int ptp_int_sts; 107462306a36Sopenharmony_ci int count = 0; 107562306a36Sopenharmony_ci int channel; 107662306a36Sopenharmony_ci s64 ns; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 107962306a36Sopenharmony_ci while ((count < 100) && ptp_int_sts) { 108062306a36Sopenharmony_ci count++; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 108362306a36Sopenharmony_ci cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) { 108662306a36Sopenharmony_ci seconds = lan743x_csr_read(adapter, 108762306a36Sopenharmony_ci PTP_TX_EGRESS_SEC); 108862306a36Sopenharmony_ci nsec = lan743x_csr_read(adapter, 108962306a36Sopenharmony_ci PTP_TX_EGRESS_NS); 109062306a36Sopenharmony_ci cause = (nsec & 109162306a36Sopenharmony_ci PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_); 109262306a36Sopenharmony_ci header = lan743x_csr_read(adapter, 109362306a36Sopenharmony_ci PTP_TX_MSG_HEADER); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (cause == 109662306a36Sopenharmony_ci PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) { 109762306a36Sopenharmony_ci nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_; 109862306a36Sopenharmony_ci lan743x_ptp_tx_ts_enqueue_ts(adapter, 109962306a36Sopenharmony_ci seconds, 110062306a36Sopenharmony_ci nsec, 110162306a36Sopenharmony_ci header); 110262306a36Sopenharmony_ci new_timestamp_available = true; 110362306a36Sopenharmony_ci } else if (cause == 110462306a36Sopenharmony_ci PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) { 110562306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 110662306a36Sopenharmony_ci "Auto capture cause not supported\n"); 110762306a36Sopenharmony_ci } else { 110862306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 110962306a36Sopenharmony_ci "unknown tx timestamp capture cause\n"); 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } else { 111262306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 111362306a36Sopenharmony_ci "TX TS INT but no TX TS CNT\n"); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 111662306a36Sopenharmony_ci PTP_INT_BIT_TX_TS_); 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_IO_FE_MASK_) { 112062306a36Sopenharmony_ci do { 112162306a36Sopenharmony_ci channel = lan743x_get_channel((ptp_int_sts & 112262306a36Sopenharmony_ci PTP_INT_IO_FE_MASK_) >> 112362306a36Sopenharmony_ci PTP_INT_IO_FE_SHIFT_); 112462306a36Sopenharmony_ci if (channel >= 0 && 112562306a36Sopenharmony_ci channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 112662306a36Sopenharmony_ci lan743x_ptp_io_event_clock_get(adapter, 112762306a36Sopenharmony_ci true, 112862306a36Sopenharmony_ci channel, 112962306a36Sopenharmony_ci &ts); 113062306a36Sopenharmony_ci /* PTP Falling Event post */ 113162306a36Sopenharmony_ci ns = timespec64_to_ns(&ts); 113262306a36Sopenharmony_ci ptp_event.timestamp = ns; 113362306a36Sopenharmony_ci ptp_event.index = channel; 113462306a36Sopenharmony_ci ptp_event.type = PTP_CLOCK_EXTTS; 113562306a36Sopenharmony_ci ptp_clock_event(ptp->ptp_clock, 113662306a36Sopenharmony_ci &ptp_event); 113762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 113862306a36Sopenharmony_ci PTP_INT_IO_FE_SET_ 113962306a36Sopenharmony_ci (channel)); 114062306a36Sopenharmony_ci ptp_int_sts &= ~(1 << 114162306a36Sopenharmony_ci (PTP_INT_IO_FE_SHIFT_ + 114262306a36Sopenharmony_ci channel)); 114362306a36Sopenharmony_ci } else { 114462306a36Sopenharmony_ci /* Clear falling event interrupts */ 114562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 114662306a36Sopenharmony_ci PTP_INT_IO_FE_MASK_); 114762306a36Sopenharmony_ci ptp_int_sts &= ~PTP_INT_IO_FE_MASK_; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci } while (ptp_int_sts & PTP_INT_IO_FE_MASK_); 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_IO_RE_MASK_) { 115362306a36Sopenharmony_ci do { 115462306a36Sopenharmony_ci channel = lan743x_get_channel((ptp_int_sts & 115562306a36Sopenharmony_ci PTP_INT_IO_RE_MASK_) >> 115662306a36Sopenharmony_ci PTP_INT_IO_RE_SHIFT_); 115762306a36Sopenharmony_ci if (channel >= 0 && 115862306a36Sopenharmony_ci channel < PCI11X1X_PTP_IO_MAX_CHANNELS) { 115962306a36Sopenharmony_ci lan743x_ptp_io_event_clock_get(adapter, 116062306a36Sopenharmony_ci false, 116162306a36Sopenharmony_ci channel, 116262306a36Sopenharmony_ci &ts); 116362306a36Sopenharmony_ci /* PTP Rising Event post */ 116462306a36Sopenharmony_ci ns = timespec64_to_ns(&ts); 116562306a36Sopenharmony_ci ptp_event.timestamp = ns; 116662306a36Sopenharmony_ci ptp_event.index = channel; 116762306a36Sopenharmony_ci ptp_event.type = PTP_CLOCK_EXTTS; 116862306a36Sopenharmony_ci ptp_clock_event(ptp->ptp_clock, 116962306a36Sopenharmony_ci &ptp_event); 117062306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 117162306a36Sopenharmony_ci PTP_INT_IO_RE_SET_ 117262306a36Sopenharmony_ci (channel)); 117362306a36Sopenharmony_ci ptp_int_sts &= ~(1 << 117462306a36Sopenharmony_ci (PTP_INT_IO_RE_SHIFT_ + 117562306a36Sopenharmony_ci channel)); 117662306a36Sopenharmony_ci } else { 117762306a36Sopenharmony_ci /* Clear Rising event interrupt */ 117862306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 117962306a36Sopenharmony_ci PTP_INT_IO_RE_MASK_); 118062306a36Sopenharmony_ci ptp_int_sts &= ~PTP_INT_IO_RE_MASK_; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci } while (ptp_int_sts & PTP_INT_IO_RE_MASK_); 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (new_timestamp_available) 118962306a36Sopenharmony_ci lan743x_ptp_tx_ts_complete(adapter); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci return -1; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, 119762306a36Sopenharmony_ci u32 *seconds, u32 *nano_seconds, 119862306a36Sopenharmony_ci u32 *sub_nano_seconds) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 120562306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (seconds) 120862306a36Sopenharmony_ci (*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (nano_seconds) 121162306a36Sopenharmony_ci (*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (sub_nano_seconds) 121462306a36Sopenharmony_ci (*sub_nano_seconds) = 121562306a36Sopenharmony_ci lan743x_csr_read(adapter, PTP_CLOCK_SUBNS); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic void lan743x_ptp_io_clock_get(struct lan743x_adapter *adapter, 122162306a36Sopenharmony_ci u32 *sec, u32 *nsec, u32 *sub_nsec) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 122662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); 122762306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (sec) 123062306a36Sopenharmony_ci (*sec) = lan743x_csr_read(adapter, PTP_LTC_RD_SEC_LO); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (nsec) 123362306a36Sopenharmony_ci (*nsec) = lan743x_csr_read(adapter, PTP_LTC_RD_NS); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (sub_nsec) 123662306a36Sopenharmony_ci (*sub_nsec) = 123762306a36Sopenharmony_ci lan743x_csr_read(adapter, PTP_LTC_RD_SUBNS); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 124062306a36Sopenharmony_ci} 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, 124362306a36Sopenharmony_ci s64 time_step_ns) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 124662306a36Sopenharmony_ci u32 nano_seconds_step = 0; 124762306a36Sopenharmony_ci u64 abs_time_step_ns = 0; 124862306a36Sopenharmony_ci u32 unsigned_seconds = 0; 124962306a36Sopenharmony_ci u32 nano_seconds = 0; 125062306a36Sopenharmony_ci u32 remainder = 0; 125162306a36Sopenharmony_ci s32 seconds = 0; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (time_step_ns > 15000000000LL) { 125462306a36Sopenharmony_ci /* convert to clock set */ 125562306a36Sopenharmony_ci if (adapter->is_pci11x1x) 125662306a36Sopenharmony_ci lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 125762306a36Sopenharmony_ci &nano_seconds, NULL); 125862306a36Sopenharmony_ci else 125962306a36Sopenharmony_ci lan743x_ptp_clock_get(adapter, &unsigned_seconds, 126062306a36Sopenharmony_ci &nano_seconds, NULL); 126162306a36Sopenharmony_ci unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL, 126262306a36Sopenharmony_ci &remainder); 126362306a36Sopenharmony_ci nano_seconds += remainder; 126462306a36Sopenharmony_ci if (nano_seconds >= 1000000000) { 126562306a36Sopenharmony_ci unsigned_seconds++; 126662306a36Sopenharmony_ci nano_seconds -= 1000000000; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci lan743x_ptp_clock_set(adapter, unsigned_seconds, 126962306a36Sopenharmony_ci nano_seconds, 0); 127062306a36Sopenharmony_ci return; 127162306a36Sopenharmony_ci } else if (time_step_ns < -15000000000LL) { 127262306a36Sopenharmony_ci /* convert to clock set */ 127362306a36Sopenharmony_ci time_step_ns = -time_step_ns; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 127662306a36Sopenharmony_ci lan743x_ptp_io_clock_get(adapter, &unsigned_seconds, 127762306a36Sopenharmony_ci &nano_seconds, NULL); 127862306a36Sopenharmony_ci } else { 127962306a36Sopenharmony_ci lan743x_ptp_clock_get(adapter, &unsigned_seconds, 128062306a36Sopenharmony_ci &nano_seconds, NULL); 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL, 128362306a36Sopenharmony_ci &remainder); 128462306a36Sopenharmony_ci nano_seconds_step = remainder; 128562306a36Sopenharmony_ci if (nano_seconds < nano_seconds_step) { 128662306a36Sopenharmony_ci unsigned_seconds--; 128762306a36Sopenharmony_ci nano_seconds += 1000000000; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci nano_seconds -= nano_seconds_step; 129062306a36Sopenharmony_ci lan743x_ptp_clock_set(adapter, unsigned_seconds, 129162306a36Sopenharmony_ci nano_seconds, 0); 129262306a36Sopenharmony_ci return; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* do clock step */ 129662306a36Sopenharmony_ci if (time_step_ns >= 0) { 129762306a36Sopenharmony_ci abs_time_step_ns = (u64)(time_step_ns); 129862306a36Sopenharmony_ci seconds = (s32)div_u64_rem(abs_time_step_ns, 1000000000, 129962306a36Sopenharmony_ci &remainder); 130062306a36Sopenharmony_ci nano_seconds = (u32)remainder; 130162306a36Sopenharmony_ci } else { 130262306a36Sopenharmony_ci abs_time_step_ns = (u64)(-time_step_ns); 130362306a36Sopenharmony_ci seconds = -((s32)div_u64_rem(abs_time_step_ns, 1000000000, 130462306a36Sopenharmony_ci &remainder)); 130562306a36Sopenharmony_ci nano_seconds = (u32)remainder; 130662306a36Sopenharmony_ci if (nano_seconds > 0) { 130762306a36Sopenharmony_ci /* subtracting nano seconds is not allowed 130862306a36Sopenharmony_ci * convert to subtracting from seconds, 130962306a36Sopenharmony_ci * and adding to nanoseconds 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_ci seconds--; 131262306a36Sopenharmony_ci nano_seconds = (1000000000 - nano_seconds); 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (nano_seconds > 0) { 131762306a36Sopenharmony_ci /* add 8 ns to cover the likely normal increment */ 131862306a36Sopenharmony_ci nano_seconds += 8; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (nano_seconds >= 1000000000) { 132262306a36Sopenharmony_ci /* carry into seconds */ 132362306a36Sopenharmony_ci seconds++; 132462306a36Sopenharmony_ci nano_seconds -= 1000000000; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci while (seconds) { 132862306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 132962306a36Sopenharmony_ci if (seconds > 0) { 133062306a36Sopenharmony_ci u32 adjustment_value = (u32)seconds; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci if (adjustment_value > 0xF) 133362306a36Sopenharmony_ci adjustment_value = 0xF; 133462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 133562306a36Sopenharmony_ci PTP_CLOCK_STEP_ADJ_DIR_ | 133662306a36Sopenharmony_ci adjustment_value); 133762306a36Sopenharmony_ci seconds -= ((s32)adjustment_value); 133862306a36Sopenharmony_ci } else { 133962306a36Sopenharmony_ci u32 adjustment_value = (u32)(-seconds); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if (adjustment_value > 0xF) 134262306a36Sopenharmony_ci adjustment_value = 0xF; 134362306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 134462306a36Sopenharmony_ci adjustment_value); 134562306a36Sopenharmony_ci seconds += ((s32)adjustment_value); 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, 134862306a36Sopenharmony_ci PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 134962306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, 135062306a36Sopenharmony_ci PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_); 135162306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci if (nano_seconds) { 135462306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 135562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ, 135662306a36Sopenharmony_ci PTP_CLOCK_STEP_ADJ_DIR_ | 135762306a36Sopenharmony_ci (nano_seconds & 135862306a36Sopenharmony_ci PTP_CLOCK_STEP_ADJ_VALUE_MASK_)); 135962306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, 136062306a36Sopenharmony_ci PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 136162306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, 136262306a36Sopenharmony_ci PTP_CMD_CTL_PTP_CLK_STP_NSEC_); 136362306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_civoid lan743x_ptp_isr(void *context) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci struct lan743x_adapter *adapter = (struct lan743x_adapter *)context; 137062306a36Sopenharmony_ci struct lan743x_ptp *ptp = NULL; 137162306a36Sopenharmony_ci int enable_flag = 1; 137262306a36Sopenharmony_ci u32 ptp_int_sts = 0; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci ptp = &adapter->ptp; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS); 137962306a36Sopenharmony_ci ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_BIT_TX_TS_) { 138262306a36Sopenharmony_ci ptp_schedule_worker(ptp->ptp_clock, 0); 138362306a36Sopenharmony_ci enable_flag = 0;/* tasklet will re-enable later */ 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) { 138662306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 138762306a36Sopenharmony_ci "PTP TX Software Timestamp Error\n"); 138862306a36Sopenharmony_ci /* clear int status bit */ 138962306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 139062306a36Sopenharmony_ci PTP_INT_BIT_TX_SWTS_ERR_); 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) { 139362306a36Sopenharmony_ci /* clear int status bit */ 139462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 139562306a36Sopenharmony_ci PTP_INT_BIT_TIMER_B_); 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) { 139862306a36Sopenharmony_ci /* clear int status bit */ 139962306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_STS, 140062306a36Sopenharmony_ci PTP_INT_BIT_TIMER_A_); 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (enable_flag) { 140462306a36Sopenharmony_ci /* re-enable isr */ 140562306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter, 141062306a36Sopenharmony_ci struct sk_buff *skb, bool ignore_sync) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 141562306a36Sopenharmony_ci if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 141662306a36Sopenharmony_ci ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb; 141762306a36Sopenharmony_ci if (ignore_sync) 141862306a36Sopenharmony_ci ptp->tx_ts_ignore_sync_queue |= 141962306a36Sopenharmony_ci BIT(ptp->tx_ts_skb_queue_size); 142062306a36Sopenharmony_ci ptp->tx_ts_skb_queue_size++; 142162306a36Sopenharmony_ci } else { 142262306a36Sopenharmony_ci /* this should never happen, so long as the tx channel 142362306a36Sopenharmony_ci * calls and honors the result from 142462306a36Sopenharmony_ci * lan743x_ptp_request_tx_timestamp 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 142762306a36Sopenharmony_ci "tx ts skb queue overflow\n"); 142862306a36Sopenharmony_ci dev_kfree_skb(skb); 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_cistatic void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci struct timespec64 ts; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci ktime_get_clocktai_ts64(&ts); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci lan743x_ptp_clock_set(adapter, ts.tv_sec, ts.tv_nsec, 0); 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_civoid lan743x_ptp_update_latency(struct lan743x_adapter *adapter, 144362306a36Sopenharmony_ci u32 link_speed) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci switch (link_speed) { 144662306a36Sopenharmony_ci case 10: 144762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_LATENCY, 144862306a36Sopenharmony_ci PTP_LATENCY_TX_SET_(0) | 144962306a36Sopenharmony_ci PTP_LATENCY_RX_SET_(0)); 145062306a36Sopenharmony_ci break; 145162306a36Sopenharmony_ci case 100: 145262306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_LATENCY, 145362306a36Sopenharmony_ci PTP_LATENCY_TX_SET_(181) | 145462306a36Sopenharmony_ci PTP_LATENCY_RX_SET_(594)); 145562306a36Sopenharmony_ci break; 145662306a36Sopenharmony_ci case 1000: 145762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_LATENCY, 145862306a36Sopenharmony_ci PTP_LATENCY_TX_SET_(30) | 145962306a36Sopenharmony_ci PTP_LATENCY_RX_SET_(525)); 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ciint lan743x_ptp_init(struct lan743x_adapter *adapter) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 146762306a36Sopenharmony_ci int i; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci mutex_init(&ptp->command_lock); 147062306a36Sopenharmony_ci spin_lock_init(&ptp->tx_ts_lock); 147162306a36Sopenharmony_ci ptp->used_event_ch = 0; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci for (i = 0; i < LAN743X_PTP_N_EVENT_CHAN; i++) { 147462306a36Sopenharmony_ci ptp->perout[i].event_ch = -1; 147562306a36Sopenharmony_ci ptp->perout[i].gpio_pin = -1; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci lan743x_led_mux_save(adapter); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return 0; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ciint lan743x_ptp_open(struct lan743x_adapter *adapter) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 148662306a36Sopenharmony_ci int ret = -ENODEV; 148762306a36Sopenharmony_ci u32 temp; 148862306a36Sopenharmony_ci int i; 148962306a36Sopenharmony_ci int n_pins; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci lan743x_ptp_reset(adapter); 149262306a36Sopenharmony_ci lan743x_ptp_sync_to_system_clock(adapter); 149362306a36Sopenharmony_ci temp = lan743x_csr_read(adapter, PTP_TX_MOD2); 149462306a36Sopenharmony_ci temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_; 149562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_TX_MOD2, temp); 149662306a36Sopenharmony_ci lan743x_ptp_enable(adapter); 149762306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_); 149862306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_EN_SET, 149962306a36Sopenharmony_ci PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_); 150062306a36Sopenharmony_ci ptp->flags |= PTP_FLAG_ISR_ENABLED; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK)) 150362306a36Sopenharmony_ci return 0; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci switch (adapter->csr.id_rev & ID_REV_ID_MASK_) { 150662306a36Sopenharmony_ci case ID_REV_ID_LAN7430_: 150762306a36Sopenharmony_ci n_pins = LAN7430_N_GPIO; 150862306a36Sopenharmony_ci break; 150962306a36Sopenharmony_ci case ID_REV_ID_LAN7431_: 151062306a36Sopenharmony_ci case ID_REV_ID_A011_: 151162306a36Sopenharmony_ci case ID_REV_ID_A041_: 151262306a36Sopenharmony_ci n_pins = LAN7431_N_GPIO; 151362306a36Sopenharmony_ci break; 151462306a36Sopenharmony_ci default: 151562306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 151662306a36Sopenharmony_ci "Unknown LAN743x (%08x). Assuming no GPIO\n", 151762306a36Sopenharmony_ci adapter->csr.id_rev); 151862306a36Sopenharmony_ci n_pins = 0; 151962306a36Sopenharmony_ci break; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (n_pins > LAN743X_PTP_N_GPIO) 152362306a36Sopenharmony_ci n_pins = LAN743X_PTP_N_GPIO; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci for (i = 0; i < n_pins; i++) { 152662306a36Sopenharmony_ci struct ptp_pin_desc *ptp_pin = &ptp->pin_config[i]; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci snprintf(ptp_pin->name, 152962306a36Sopenharmony_ci sizeof(ptp_pin->name), "lan743x_ptp_pin_%02d", i); 153062306a36Sopenharmony_ci ptp_pin->index = i; 153162306a36Sopenharmony_ci ptp_pin->func = PTP_PF_NONE; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci ptp->ptp_clock_info.owner = THIS_MODULE; 153562306a36Sopenharmony_ci snprintf(ptp->ptp_clock_info.name, 16, "%pm", 153662306a36Sopenharmony_ci adapter->netdev->dev_addr); 153762306a36Sopenharmony_ci ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB; 153862306a36Sopenharmony_ci ptp->ptp_clock_info.n_alarm = 0; 153962306a36Sopenharmony_ci ptp->ptp_clock_info.n_ext_ts = LAN743X_PTP_N_EXTTS; 154062306a36Sopenharmony_ci ptp->ptp_clock_info.n_per_out = LAN743X_PTP_N_EVENT_CHAN; 154162306a36Sopenharmony_ci ptp->ptp_clock_info.n_pins = n_pins; 154262306a36Sopenharmony_ci ptp->ptp_clock_info.pps = LAN743X_PTP_N_PPS; 154362306a36Sopenharmony_ci ptp->ptp_clock_info.pin_config = ptp->pin_config; 154462306a36Sopenharmony_ci ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine; 154562306a36Sopenharmony_ci ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime; 154662306a36Sopenharmony_ci ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64; 154762306a36Sopenharmony_ci ptp->ptp_clock_info.getcrosststamp = NULL; 154862306a36Sopenharmony_ci ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64; 154962306a36Sopenharmony_ci ptp->ptp_clock_info.enable = lan743x_ptpci_enable; 155062306a36Sopenharmony_ci ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work; 155162306a36Sopenharmony_ci ptp->ptp_clock_info.verify = lan743x_ptpci_verify_pin_config; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info, 155462306a36Sopenharmony_ci &adapter->pdev->dev); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (IS_ERR(ptp->ptp_clock)) { 155762306a36Sopenharmony_ci netif_err(adapter, ifup, adapter->netdev, 155862306a36Sopenharmony_ci "ptp_clock_register failed\n"); 155962306a36Sopenharmony_ci goto done; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED; 156262306a36Sopenharmony_ci netif_info(adapter, ifup, adapter->netdev, 156362306a36Sopenharmony_ci "successfully registered ptp clock\n"); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci return 0; 156662306a36Sopenharmony_cidone: 156762306a36Sopenharmony_ci lan743x_ptp_close(adapter); 156862306a36Sopenharmony_ci return ret; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_civoid lan743x_ptp_close(struct lan743x_adapter *adapter) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 157462306a36Sopenharmony_ci int index; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) && 157762306a36Sopenharmony_ci (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED)) { 157862306a36Sopenharmony_ci ptp_clock_unregister(ptp->ptp_clock); 157962306a36Sopenharmony_ci ptp->ptp_clock = NULL; 158062306a36Sopenharmony_ci ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED; 158162306a36Sopenharmony_ci netif_info(adapter, drv, adapter->netdev, 158262306a36Sopenharmony_ci "ptp clock unregister\n"); 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (ptp->flags & PTP_FLAG_ISR_ENABLED) { 158662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_INT_EN_CLR, 158762306a36Sopenharmony_ci PTP_INT_BIT_TX_SWTS_ERR_ | 158862306a36Sopenharmony_ci PTP_INT_BIT_TX_TS_); 158962306a36Sopenharmony_ci lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_); 159062306a36Sopenharmony_ci ptp->flags &= ~PTP_FLAG_ISR_ENABLED; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* clean up pending timestamp requests */ 159462306a36Sopenharmony_ci lan743x_ptp_tx_ts_complete(adapter); 159562306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 159662306a36Sopenharmony_ci for (index = 0; 159762306a36Sopenharmony_ci index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; 159862306a36Sopenharmony_ci index++) { 159962306a36Sopenharmony_ci struct sk_buff *skb = ptp->tx_ts_skb_queue[index]; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci dev_kfree_skb(skb); 160262306a36Sopenharmony_ci ptp->tx_ts_skb_queue[index] = NULL; 160362306a36Sopenharmony_ci ptp->tx_ts_seconds_queue[index] = 0; 160462306a36Sopenharmony_ci ptp->tx_ts_nseconds_queue[index] = 0; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci ptp->tx_ts_skb_queue_size = 0; 160762306a36Sopenharmony_ci ptp->tx_ts_queue_size = 0; 160862306a36Sopenharmony_ci ptp->pending_tx_timestamps = 0; 160962306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci lan743x_led_mux_restore(adapter); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci lan743x_ptp_disable(adapter); 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter, 161762306a36Sopenharmony_ci bool ts_insert_enable) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (ts_insert_enable) 162262306a36Sopenharmony_ci ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 162362306a36Sopenharmony_ci else 162462306a36Sopenharmony_ci ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod); 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_) 163262306a36Sopenharmony_ci return true; 163362306a36Sopenharmony_ci return false; 163462306a36Sopenharmony_ci} 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_cistatic void lan743x_ptp_enable(struct lan743x_adapter *adapter) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (lan743x_ptp_is_enabled(adapter)) { 164362306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 164462306a36Sopenharmony_ci "PTP already enabled\n"); 164562306a36Sopenharmony_ci goto done; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_); 164862306a36Sopenharmony_cidone: 164962306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic void lan743x_ptp_disable(struct lan743x_adapter *adapter) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 165762306a36Sopenharmony_ci if (!lan743x_ptp_is_enabled(adapter)) { 165862306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 165962306a36Sopenharmony_ci "PTP already disabled\n"); 166062306a36Sopenharmony_ci goto done; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_); 166362306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_); 166462306a36Sopenharmony_cidone: 166562306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 166662306a36Sopenharmony_ci} 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_cistatic void lan743x_ptp_reset(struct lan743x_adapter *adapter) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci if (lan743x_ptp_is_enabled(adapter)) { 167562306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 167662306a36Sopenharmony_ci "Attempting reset while enabled\n"); 167762306a36Sopenharmony_ci goto done; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_); 168162306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_); 168262306a36Sopenharmony_cidone: 168362306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic void lan743x_ptp_clock_set(struct lan743x_adapter *adapter, 168762306a36Sopenharmony_ci u32 seconds, u32 nano_seconds, 168862306a36Sopenharmony_ci u32 sub_nano_seconds) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci mutex_lock(&ptp->command_lock); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds); 169562306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds); 169662306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 169962306a36Sopenharmony_ci lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_); 170062306a36Sopenharmony_ci mutex_unlock(&ptp->command_lock); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cibool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 170662306a36Sopenharmony_ci bool result = false; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 170962306a36Sopenharmony_ci if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { 171062306a36Sopenharmony_ci /* request granted */ 171162306a36Sopenharmony_ci ptp->pending_tx_timestamps++; 171262306a36Sopenharmony_ci result = true; 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 171562306a36Sopenharmony_ci return result; 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_civoid lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci struct lan743x_ptp *ptp = &adapter->ptp; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci spin_lock_bh(&ptp->tx_ts_lock); 172362306a36Sopenharmony_ci if (ptp->pending_tx_timestamps > 0) 172462306a36Sopenharmony_ci ptp->pending_tx_timestamps--; 172562306a36Sopenharmony_ci else 172662306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 172762306a36Sopenharmony_ci "unrequest failed, pending_tx_timestamps==0\n"); 172862306a36Sopenharmony_ci spin_unlock_bh(&ptp->tx_ts_lock); 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_civoid lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter, 173262306a36Sopenharmony_ci struct sk_buff *skb, bool ignore_sync) 173362306a36Sopenharmony_ci{ 173462306a36Sopenharmony_ci lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci lan743x_ptp_tx_ts_complete(adapter); 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ciint lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 174262306a36Sopenharmony_ci struct hwtstamp_config config; 174362306a36Sopenharmony_ci int ret = 0; 174462306a36Sopenharmony_ci int index; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (!ifr) { 174762306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 174862306a36Sopenharmony_ci "SIOCSHWTSTAMP, ifr == NULL\n"); 174962306a36Sopenharmony_ci return -EINVAL; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 175362306a36Sopenharmony_ci return -EFAULT; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci switch (config.tx_type) { 175662306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 175762306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; 175862306a36Sopenharmony_ci index++) 175962306a36Sopenharmony_ci lan743x_tx_set_timestamping_mode(&adapter->tx[index], 176062306a36Sopenharmony_ci false, false); 176162306a36Sopenharmony_ci lan743x_ptp_set_sync_ts_insert(adapter, false); 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 176462306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; 176562306a36Sopenharmony_ci index++) 176662306a36Sopenharmony_ci lan743x_tx_set_timestamping_mode(&adapter->tx[index], 176762306a36Sopenharmony_ci true, false); 176862306a36Sopenharmony_ci lan743x_ptp_set_sync_ts_insert(adapter, false); 176962306a36Sopenharmony_ci break; 177062306a36Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_SYNC: 177162306a36Sopenharmony_ci for (index = 0; index < adapter->used_tx_channels; 177262306a36Sopenharmony_ci index++) 177362306a36Sopenharmony_ci lan743x_tx_set_timestamping_mode(&adapter->tx[index], 177462306a36Sopenharmony_ci true, true); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci lan743x_ptp_set_sync_ts_insert(adapter, true); 177762306a36Sopenharmony_ci break; 177862306a36Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_P2P: 177962306a36Sopenharmony_ci ret = -ERANGE; 178062306a36Sopenharmony_ci break; 178162306a36Sopenharmony_ci default: 178262306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 178362306a36Sopenharmony_ci " tx_type = %d, UNKNOWN\n", config.tx_type); 178462306a36Sopenharmony_ci ret = -EINVAL; 178562306a36Sopenharmony_ci break; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci if (!ret) 178962306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, 179062306a36Sopenharmony_ci sizeof(config)) ? -EFAULT : 0; 179162306a36Sopenharmony_ci return ret; 179262306a36Sopenharmony_ci} 1793