From patchwork Fri Jan 20 09:53:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Tachici X-Patchwork-Id: 46273 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp109224wrn; Fri, 20 Jan 2023 01:58:06 -0800 (PST) X-Google-Smtp-Source: AMrXdXvi8yPe5B7DQatll01zJAFG3j4xBGgZ94nUU3Cy2O4QZgiI9E3jlfsP71x6RoHWDMeasKQ3 X-Received: by 2002:aa7:8a45:0:b0:58d:924e:e5de with SMTP id n5-20020aa78a45000000b0058d924ee5demr14673361pfa.11.1674208686621; Fri, 20 Jan 2023 01:58:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674208686; cv=none; d=google.com; s=arc-20160816; b=owZ5Jvghj5yDjBB1uTveCYM0bX9E7LiejnK0SimmBFNfD0enr95I2K2ARVWwYUjoWK ZkaRu8z6W/qK7CnGTUCKpkEwt6/gziFlG3mksie5xOU+4DwgVXPNgQgeWi3JZMy0C5Oi KqjUa0CKYTzsqR6E6mqE0l6mfCTcP82hxA11SrETRVGwT5hcKUgkL/YO9PP/gX+pnm1E FZ0js47qMsskxbfewOyNbvFQrtv45XKMKlvQMXjI8IsCqSefdGdL+0sttB2jWhdW+5Ju 8BdUmRX92Bx2R28Y0FPUeSFv/I42+cunc/dWsGh0m6pIZWmJcQvPN+qDFFEjUHRT3j2Z sENg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=ZArkowyWAYq39xL5VfOVL1iiSj8HtvNxfZxgMmQ84CE=; b=ZiOLiE6MLHEBuq1iOoFfTw+pNHIetfrfVzIvMW6YUsmWcn2AuACNc8hSp4h7551x8v YjxqoK9OKfV5gUHPw1SxumQI+3vVBaks/sBLaYSwO20aYVoG89y/0c38YbGyeHu2ji04 pLNM0E0NzXIuF8A4MOC90Ur3mtG+W8zIRsGR/762q51nwRFUlBNPYVkWPl4LT813elzw M1s0BQn3naW/Zn/aJWB4mYhvZpFSlgXn7AfGnc/lxUQJtFTUqe91N9MKNwcIpdyJHBFA iHzOGRyEdIZrsb3fDqFJrX+i3h/spG+1azatmDO7MLldEX2hfgVZ0HQnmYhnuyI2shW+ uq5A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id r3-20020a056a00216300b00574b46d3b26si39444842pff.334.2023.01.20.01.57.54; Fri, 20 Jan 2023 01:58:06 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230367AbjATJyl (ORCPT + 99 others); Fri, 20 Jan 2023 04:54:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230253AbjATJyc (ORCPT ); Fri, 20 Jan 2023 04:54:32 -0500 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DBD3B7AF20; Fri, 20 Jan 2023 01:54:22 -0800 (PST) Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30K7FRMG000520; Fri, 20 Jan 2023 04:54:12 -0500 Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n736yq3hj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:12 -0500 Received: from m0167088.ppops.net (m0167088.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30K9sBAs021025; Fri, 20 Jan 2023 04:54:11 -0500 Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n736yq3hg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:11 -0500 Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 30K9sAPV036482 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 20 Jan 2023 04:54:10 -0500 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.14; Fri, 20 Jan 2023 04:54:09 -0500 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.986.14 via Frontend Transport; Fri, 20 Jan 2023 04:54:09 -0500 Received: from tachici-Precision-5530.ad.analog.com ([10.48.65.139]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 30K9rqTw021132; Fri, 20 Jan 2023 04:54:05 -0500 From: Alexandru Tachici To: CC: , , , , , , , , , , , Subject: [net-next 1/3] net: ethernet: adi: adin1110: add PTP clock support Date: Fri, 20 Jan 2023 11:53:46 +0200 Message-ID: <20230120095348.26715-2-alexandru.tachici@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230120095348.26715-1-alexandru.tachici@analog.com> References: <20230120095348.26715-1-alexandru.tachici@analog.com> MIME-Version: 1.0 X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: eNSBwtdTTViAOrmikOTV41Djsyqf3jXr X-Proofpoint-ORIG-GUID: ffoC0GuLxGQYKPyKiitZ5vT6GagVkjwh X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-20_06,2023-01-19_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 impostorscore=0 spamscore=0 mlxlogscore=999 adultscore=0 malwarescore=0 lowpriorityscore=0 priorityscore=1501 clxscore=1015 mlxscore=0 bulkscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301200093 X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755535047759237807?= X-GMAIL-MSGID: =?utf-8?q?1755535047759237807?= Add control for the PHC inside the ADIN1110/2111. Device contains a syntonized counter driven by a 120 MHz clock with 8 ns resolution. Time is stored on two registers: a 32bit seconds register and a 32bit nanoseconds register. For adjusting the clock timing, device uses an addend register. Can generate an output signal on the TS_TIMER pin. For reading the timestamp the current tiem is saved by setting the TS_CAPT pin via gpio in order to snapshot both seconds and nanoseconds in different registers that the live ones. Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 385 ++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 0805f249fff2..3c2d58f07a4a 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +24,7 @@ #include #include #include +#include #include #include @@ -35,6 +38,8 @@ #define ADIN1110_CONFIG1 0x04 #define ADIN1110_CONFIG1_SYNC BIT(15) +#define ADIN1110_CONFIG1_FTSE BIT(7) +#define ADIN1110_CONFIG1_FTSS BIT(6) #define ADIN1110_CONFIG2 0x06 #define ADIN2111_P2_FWD_UNK2HOST BIT(12) @@ -78,6 +83,20 @@ #define ADIN1110_MAC_ADDR_MASK_UPR 0x70 #define ADIN1110_MAC_ADDR_MASK_LWR 0x71 +#define ADIN1110_MAC_TS_ADDEND 0x80 +#define ADIN1110_MAC_TS_SEC_CNT 0x82 +#define ADIN1110_MAC_TS_NS_CNT 0x83 +#define ADIN1110_MAC_TS_CFG 0x84 +#define ADIN1110_MAC_TS_CFG_EN BIT(0) +#define ADIN1110_MAC_TS_CFG_CLR BIT(1) +#define ADIN1110_MAC_TS_CFG_TIMER_STOP BIT(3) +#define ADIN1110_MAC_TS_CFG_CAPT_CNT BIT(4) +#define ADIN1110_MAC_TS_TIMER_HI 0x85 +#define ADIN1110_MAC_TS_TIMER_LO 0x86 +#define ADIN1110_MAC_TS_TIMER_START 0x88 +#define ADIN1110_MAC_TS_CAPT0 0x89 +#define ADIN1110_MAC_TS_CAPT1 0x8A + #define ADIN1110_RX_FSIZE 0x90 #define ADIN1110_RX 0x91 @@ -90,6 +109,19 @@ #define ADIN1110_MDIO_OP_WR 0x1 #define ADIN1110_MDIO_OP_RD 0x3 +/* ADIN2111 PHY PINMUX Controls */ +#define ADIN2111_PINMUX_CFG1 0x8C56 +#define ADIN2111_PINMUX_CFG1_DIGIO_TSCAPT GENMASK(5, 4) + +#define ADIN2111_PINMUX_CFG1_TSCAPT_TEST_1 BIT(5) +#define ADIN2111_PINMUX_CFG1_NOT_ASSIGNED GENMASK(5, 4) + +/* ADIN2111 PHY LEDs Controls */ +#define ADIN2111_LED_CNTRL 0x8C82 +#define ADIN2111_LED_CNTRL_LED0_FUNCTION GENMASK(4, 0) + +#define ADIN2111_LED_CNTRL_TS_TIMER 0x17 + #define ADIN1110_CD BIT(7) #define ADIN1110_WRITE BIT(5) @@ -114,6 +146,11 @@ #define ADIN_MAC_P2_ADDR_SLOT 3 #define ADIN_MAC_FDB_ADDR_SLOT 4 +#define ADIN_MAC_MAX_PTP_PINS 2 +#define ADIN_MAC_MAX_TS_SLOTS 3 + +#define adin1110_ptp_to_priv(x) container_of(x, struct adin1110_priv, ptp) + DECLARE_CRC8_TABLE(adin1110_crc_table); enum adin1110_chips_id { @@ -150,6 +187,11 @@ struct adin1110_port_priv { struct adin1110_priv { struct mutex lock; /* protect spi */ spinlock_t state_lock; /* protect RX mode */ + bool ts_rx_append; + struct ptp_clock_info ptp; + struct ptp_clock *ptp_clock; + struct gpio_desc *ts_capt; + struct ptp_pin_desc ptp_pins[ADIN_MAC_MAX_PTP_PINS]; struct mii_bus *mii_bus; struct spi_device *spidev; bool append_crc; @@ -1640,6 +1682,343 @@ static int adin1110_probe_netdevs(struct adin1110_priv *priv) return 0; } +/* ADIN1110 has a syntonized counter driven by an internal 120 MHz clock, a 64-bit + * counter in which the lower 32 bits represent nanoseconds with 1 LSB = 1 ns. + * Frequency is adjusted by modifying the addend register. + */ +static int adin1110_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + bool negative = false; + u64 ts_addend; + u64 diff; + u32 val; + int ret; + + mutex_lock(&priv->lock); + + ret = adin1110_read_reg(priv, ADIN1110_MAC_TS_ADDEND, &val); + if (ret < 0) + goto out; + + ts_addend = val; + + if (scaled_ppm < 0) { + negative = true; + scaled_ppm = -scaled_ppm; + } + + diff = mul_u64_u64_div_u64(ts_addend, (u64)scaled_ppm, 1000000ULL << 16); + if (negative) + val = ts_addend - diff; + else + val = ts_addend + diff; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_ADDEND, val); +out: + mutex_unlock(&priv->lock); + return ret; +} + +static int adin1110_ptp_read_ts_capt(struct adin1110_priv *priv, + struct timespec64 *ts, + struct ptp_system_timestamp *sts, + struct ktime_timestamps *snap) +{ + u32 val; + int ret; + + mutex_lock(&priv->lock); + + if (sts) + ptp_read_system_prets(sts); + + if (snap) + ktime_get_fast_timestamps(snap); + + gpiod_set_value(priv->ts_capt, 1); + fsleep(1); + gpiod_set_value(priv->ts_capt, 0); + + ret = adin1110_read_reg(priv, ADIN1110_MAC_TS_CAPT0, &val); + if (ret < 0) + goto out; + /* No TS captured when nsecs == 0 */ + if (!val) { + ret = -EINVAL; + goto out; + } + + ts->tv_nsec = val; + + ret = adin1110_read_reg(priv, ADIN1110_MAC_TS_CAPT1, &val); + if (ret < 0) + goto out; + if (sts) + ptp_read_system_postts(sts); + + ts->tv_sec = val; +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int adin1110_ptp_settime64(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + u32 addend; + int ret; + + mutex_lock(&priv->lock); + + ret = adin1110_read_reg(priv, ADIN1110_MAC_TS_ADDEND, &addend); + if (ret < 0) + goto out; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_ADDEND, 0); + if (ret < 0) + goto out; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_NS_CNT, + ALIGN(ts->tv_nsec, 16)); + if (ret < 0) + goto out; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_SEC_CNT, + ts->tv_sec); + if (ret < 0) + goto out; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_ADDEND, addend); +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int adin1110_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + struct timespec64 ts; + u64 dev_time; + int ret; + + ret = adin1110_ptp_read_ts_capt(priv, &ts, NULL, NULL); + if (ret < 0) + return ret; + + dev_time = timespec64_to_ns(&ts); + dev_time += delta; + + ts = ns_to_timespec64(dev_time); + + return adin1110_ptp_settime64(ptp, &ts); +} + +static int adin1110_ptp_gettimex64(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + + return adin1110_ptp_read_ts_capt(priv, ts, sts, NULL); +} + +static int adin1110_ptp_getcrosststamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *cts) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + struct ktime_timestamps snap; + struct timespec64 ts; + int ret; + + ret = adin1110_ptp_read_ts_capt(priv, &ts, NULL, &snap); + if (ret < 0) + return ret; + + cts->device = timespec64_to_ktime(ts); + cts->sys_realtime = snap.real; + cts->sys_monoraw = snap.mono; + + return 0; +} + +static int adin1110_enable_perout(struct adin1110_priv *priv, + struct ptp_perout_request perout, + int on) +{ + u32 on_nsec; + u32 phase; + u32 mask; + int ret; + + if (priv->cfg->id == ADIN2111_MAC) { + ret = phy_clear_bits_mmd(priv->ports[0]->phydev, MDIO_MMD_VEND1, + ADIN2111_LED_CNTRL, + ADIN2111_LED_CNTRL_LED0_FUNCTION); + if (ret < 0) + return ret; + + ret = phy_set_bits_mmd(priv->ports[0]->phydev, MDIO_MMD_VEND1, + ADIN2111_LED_CNTRL, + on ? ADIN2111_LED_CNTRL_TS_TIMER : 0); + if (ret < 0) + return ret; + } + + mutex_lock(&priv->lock); + + ret = adin1110_set_bits(priv, ADIN1110_MAC_TS_CFG, + ADIN1110_MAC_TS_CFG_CLR, + ADIN1110_MAC_TS_CFG_CLR); + if (ret < 0) + goto out; + + if (perout.flags & PTP_PEROUT_DUTY_CYCLE) + on_nsec = perout.on.nsec; + else + on_nsec = perout.period.nsec / 2; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_TIMER_HI, + ALIGN(on_nsec, 16)); + if (ret < 0) + goto out; + + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_TIMER_LO, + ALIGN((perout.period.nsec - on_nsec), 16)); + if (ret < 0) + goto out; + + if (perout.flags & PTP_PEROUT_PHASE) + phase = ALIGN(perout.phase.nsec, 16); + else + phase = 0; + + /* TS_TIMER_START reg must be written to a value >= 16 because of how + * the syntonized counter was implemented. + */ + if (phase < 16) + phase = 16; + + if (on) { + ret = adin1110_write_reg(priv, ADIN1110_MAC_TS_TIMER_START, + phase); + if (ret < 0) + goto out; + } + + mask = ADIN1110_MAC_TS_CFG_EN | ADIN1110_MAC_TS_CFG_TIMER_STOP; + ret = adin1110_set_bits(priv, ADIN1110_MAC_TS_CFG, mask, + on ? ADIN1110_MAC_TS_CFG_EN : ADIN1110_MAC_TS_CFG_TIMER_STOP); + if (ret < 0) + goto out; + + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, ADIN1110_CONFIG1_SYNC, + ADIN1110_CONFIG1_SYNC); +out: + mutex_unlock(&priv->lock); + return ret; +} + +static int adin1110_enable_extts(struct adin1110_priv *priv, + struct ptp_extts_request extts, + int on) +{ + u32 val; + int ret; + + if (extts.index >= priv->ptp.n_ext_ts) + return -EINVAL; + + if (priv->cfg->id == ADIN2111_MAC) { + ret = phy_clear_bits_mmd(priv->ports[0]->phydev, MDIO_MMD_VEND1, + ADIN2111_PINMUX_CFG1, + ADIN2111_PINMUX_CFG1_DIGIO_TSCAPT); + if (ret < 0) + return ret; + + val = on ? ADIN2111_PINMUX_CFG1_TSCAPT_TEST_1 : ADIN2111_PINMUX_CFG1_NOT_ASSIGNED; + ret = phy_set_bits_mmd(priv->ports[0]->phydev, MDIO_MMD_VEND1, + ADIN2111_PINMUX_CFG1_DIGIO_TSCAPT, val); + if (ret < 0) + return ret; + } + + mutex_lock(&priv->lock); + ret = adin1110_set_bits(priv, ADIN1110_MAC_TS_CFG, + ADIN1110_MAC_TS_CFG_EN, + on ? ADIN1110_MAC_TS_CFG_EN : 0); + if (ret < 0) + goto out; + + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, + ADIN1110_CONFIG1_SYNC, + ADIN1110_CONFIG1_SYNC); +out: + mutex_unlock(&priv->lock); + return ret; +} + +static int adin1110_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *request, int on) +{ + struct adin1110_priv *priv = adin1110_ptp_to_priv(ptp); + + switch (request->type) { + case PTP_CLK_REQ_EXTTS: + return adin1110_enable_extts(priv, request->extts, on); + case PTP_CLK_REQ_PEROUT: + return adin1110_enable_perout(priv, request->perout, on); + case PTP_CLK_REQ_PPS: + default: + return -EOPNOTSUPP; + } +} + +static int adin1110_setup_ptp(struct adin1110_priv *priv) +{ + priv->ts_capt = devm_gpiod_get_optional(&priv->spidev->dev, "ts-capt", + GPIOD_OUT_LOW); + if (!priv->ts_capt) + return 0; + + snprintf(priv->ptp_pins[0].name, 64, "%s-%u-ptp-per-out", + priv->cfg->name, priv->spidev->chip_select); + priv->ptp_pins[0].index = 0; + priv->ptp_pins[0].func = PTP_PF_PEROUT; + priv->ptp_pins[0].chan = 0; + + snprintf(priv->ptp_pins[1].name, 64, "%s-%u-ptp-ext-ts", + priv->cfg->name, priv->spidev->chip_select); + priv->ptp_pins[1].index = 1; + priv->ptp_pins[1].func = PTP_PF_EXTTS; + priv->ptp_pins[1].chan = 0; + + priv->ptp.owner = THIS_MODULE; + snprintf(priv->ptp.name, PTP_CLOCK_NAME_LEN, "%s-%u-ptp", + priv->cfg->name, priv->spidev->chip_select); + + priv->ptp.max_adj = 512000; + priv->ptp.n_ext_ts = 1; + priv->ptp.n_per_out = 1; + priv->ptp.n_pins = ADIN_MAC_MAX_PTP_PINS; + priv->ptp.pin_config = priv->ptp_pins; + priv->ptp.adjfine = adin1110_ptp_adjfine; + priv->ptp.adjtime = adin1110_ptp_adjtime; + priv->ptp.gettimex64 = adin1110_ptp_gettimex64; + priv->ptp.getcrosststamp = adin1110_ptp_getcrosststamp; + priv->ptp.settime64 = adin1110_ptp_settime64; + priv->ptp.enable = adin1110_ptp_enable; + + priv->ptp_clock = ptp_clock_register(&priv->ptp, &priv->spidev->dev); + if (IS_ERR(priv->ptp_clock)) + return PTR_ERR(priv->ptp_clock); + + return 0; +} + static int adin1110_probe(struct spi_device *spi) { const struct spi_device_id *dev_id = spi_get_device_id(spi); @@ -1680,6 +2059,12 @@ static int adin1110_probe(struct spi_device *spi) return ret; } + ret = adin1110_setup_ptp(priv); + if (ret < 0) { + dev_err(dev, "Could not register PTP clock %d\n", ret); + return ret; + } + return adin1110_probe_netdevs(priv); } From patchwork Fri Jan 20 09:53:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Tachici X-Patchwork-Id: 46272 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp108987wrn; Fri, 20 Jan 2023 01:57:20 -0800 (PST) X-Google-Smtp-Source: AMrXdXvzz1SDuPS/6ou8VhF4TdT1X9+AI50r2i1BSPgM42qfzyjUZ7Dz/dG6BX6/JPJroprdKoP0 X-Received: by 2002:a17:907:b68a:b0:86f:724b:726c with SMTP id vm10-20020a170907b68a00b0086f724b726cmr15877083ejc.59.1674208639865; Fri, 20 Jan 2023 01:57:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674208639; cv=none; d=google.com; s=arc-20160816; b=MB9rr7UdmuCT/E52UK8eLlQAQXHO9sGBqWGEtYo0EHFokWtIT6lHUinHuSkhBvQeiH zDejqZuRNLuGwn7V/bMPDxsn3NtIpRuo6Jex5/QlJ9OaVYyqVBZP/EkwOyhpxCPHwHQT QZZbk5zMd4O+6/JlccDRFC5K80CMG0cgX4D3qXsZsoXbRMWsF1hg4F991BMUlU9FbYBA aueuVyvdSFxUHSrb1u+cVvl7q6P9UkChHN75FTScDinTCy2Xue3e+1kczFbJ/SHca2kT bjUVfbZT/mHMcomeIvfy80egFgS3Fmif/CCIfjR5sHCr3S93OFXMiaL14hQk6EQWtHdA qUiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=lpCK1yo2r3q6SviRNrJA4ySRMMaBPEZrCvpKA34wP0Y=; b=UAg+VHtVsdDO2KtbxA+YZDeiafDoYDZebuXJ0AZxKaQrGHxhbQL22Jqv7ofOnNmk4A iUOC4DX0zXjUUt6I1s/M7V3xQP2dIzHHIbgi7lcb44dh+zm+InTj6tjZ3otZADKam6Vi NXYSWJbIYHWFQ1rJEoQKj9GWc0zrcSeSYsr2eQ0fxi8ARKGFMycvmJ4mCI6rqNgFCyqD z/D9ZFxI5PqWVhVTNNDVNuvgMNWxdhCXUuxBiSUeCCSPC/0TQaaFFwi5kToj3LRfYr7n zC81xINtUGYuDQIv/C6XFnLsW+o9guwKF25pkGsHeFdXj+fG0RbH60jY60AeVEJzS0PD WK/g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q18-20020a056402519200b004854e1d2682si9765417edd.249.2023.01.20.01.56.55; Fri, 20 Jan 2023 01:57:19 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230387AbjATJy6 (ORCPT + 99 others); Fri, 20 Jan 2023 04:54:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45206 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230318AbjATJyd (ORCPT ); Fri, 20 Jan 2023 04:54:33 -0500 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1058E78568; Fri, 20 Jan 2023 01:54:25 -0800 (PST) Received: from pps.filterd (m0167089.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30K8fphi023331; Fri, 20 Jan 2023 04:54:14 -0500 Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n7qnw09j3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:14 -0500 Received: from m0167089.ppops.net (m0167089.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30K9sEX0001936; Fri, 20 Jan 2023 04:54:14 -0500 Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n7qnw09hx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:14 -0500 Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 30K9sCkE036485 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 20 Jan 2023 04:54:12 -0500 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.14; Fri, 20 Jan 2023 04:54:12 -0500 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.14; Fri, 20 Jan 2023 04:54:11 -0500 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.986.14 via Frontend Transport; Fri, 20 Jan 2023 04:54:11 -0500 Received: from tachici-Precision-5530.ad.analog.com ([10.48.65.139]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 30K9rqTx021132; Fri, 20 Jan 2023 04:54:07 -0500 From: Alexandru Tachici To: CC: , , , , , , , , , , , Subject: [net-next 2/3] net: ethernet: adi: adin1110: add timestamping support Date: Fri, 20 Jan 2023 11:53:47 +0200 Message-ID: <20230120095348.26715-3-alexandru.tachici@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230120095348.26715-1-alexandru.tachici@analog.com> References: <20230120095348.26715-1-alexandru.tachici@analog.com> MIME-Version: 1.0 X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: EfaVVpHz-wzOP1mPu3ztzZ9BXuWb_5IT X-Proofpoint-ORIG-GUID: 3lVQuUG4kalDuPwiHHUgRpepcldhdPkd X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-20_06,2023-01-19_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 adultscore=0 mlxscore=0 bulkscore=0 phishscore=0 spamscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 malwarescore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301200093 X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755534998688300640?= X-GMAIL-MSGID: =?utf-8?q?1755534998688300640?= Add timestamping support for RX/TX. RX frames are automatically timestamped by the device at hardware level when the feature is enabled. Time of day is the one used by the MAC device. When sending a TX frame to the MAC device, driver needs to send a custom header ahead of the ethernet one where it specifies where the MAC device should store the timestamp after the frame has successfully been sent on the MII line. It has 3 timestamp slots that can be read afterwards. Host will be notified by the TX_RDY IRQ. Signed-off-by: Alexandru Tachici --- drivers/net/ethernet/adi/adin1110.c | 426 +++++++++++++++++++++++++++- 1 file changed, 416 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 3c2d58f07a4a..916972b91308 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -48,13 +48,27 @@ #define ADIN1110_FWD_UNK2HOST BIT(2) #define ADIN1110_STATUS0 0x08 +#define ADIN1110_TTSCAXM_P1(slot) BIT(8 + (slot)) #define ADIN1110_STATUS1 0x09 +#define ADIN1110_TTSCAXM_P2(slot) BIT(20 + (slot)) #define ADIN2111_P2_RX_RDY BIT(17) #define ADIN1110_SPI_ERR BIT(10) #define ADIN1110_RX_RDY BIT(4) +#define ADIN1110_TX_RDY BIT(3) + +#define ADIN1110_TTSCAXM_PY(slot, port) ((port) ? \ + ADIN1110_TTSCAXM_P2(slot) : \ + ADIN1110_TTSCAXM_P1(slot)) + +#define ADIN1110_P1_TTSCXH(slot) (0x10 + 2 * (slot)) +#define ADIN1110_P1_TTSCXL(slot) (0x11 + 2 * (slot)) + +#define ADIN1110_IMASK0 0x0C +#define ADIN1110_TTSCAXM_P1_IRQ(slot) BIT(8 + (slot)) #define ADIN1110_IMASK1 0x0D +#define ADIN1110_TTSCAXM_P2_IRQ(slot) BIT(20 + (slot)) #define ADIN2111_RX_RDY_IRQ BIT(17) #define ADIN1110_SPI_ERR_IRQ BIT(10) #define ADIN1110_RX_RDY_IRQ BIT(4) @@ -103,7 +117,19 @@ #define ADIN2111_RX_P2_FSIZE 0xC0 #define ADIN2111_RX_P2 0xC1 +#define ADIN1110_P2_TTSCXH(slot) (0xF0 + 2 * (slot)) +#define ADIN1110_P2_TTSCXL(slot) (0xF1 + 2 * (slot)) + +#define ADIN1110_PY_TTSCXH(slot, port) ((port) ? \ + ADIN1110_P2_TTSCXH(slot) : \ + ADIN1110_P1_TTSCXH(slot)) + +#define ADIN1110_PY_TTSCXL(slot, port) ((port) ? \ + ADIN1110_P2_TTSCXL(slot) \ + : ADIN1110_P1_TTSCXL(slot)) + #define ADIN1110_CLEAR_STATUS0 0xFFF +#define ADIN1110_CLEAR_STATUS1 0xFFFFFFFF /* MDIO_OP codes */ #define ADIN1110_MDIO_OP_WR 0x1 @@ -125,12 +151,18 @@ #define ADIN1110_CD BIT(7) #define ADIN1110_WRITE BIT(5) +/* ADIN1110 frame header fields */ +#define ADIN1110_FRAME_HEADER_PORT BIT(0) +#define ADIN1110_FRAME_HEADER_TS_SLOT GENMASK(7, 6) +#define ADIN1110_FRAME_HEADER_TS_PRESENT BIT(2) + #define ADIN1110_MAX_BUFF 2048 #define ADIN1110_MAX_FRAMES_READ 64 #define ADIN1110_WR_HEADER_LEN 2 #define ADIN1110_FRAME_HEADER_LEN 2 #define ADIN1110_INTERNAL_SIZE_HEADER_LEN 2 #define ADIN1110_RD_HEADER_LEN 3 +#define ADIN1110_TS_LEN 8 #define ADIN1110_REG_LEN 4 #define ADIN1110_FEC_LEN 4 @@ -181,6 +213,9 @@ struct adin1110_port_priv { struct sk_buff_head txq; u32 nr; u32 state; + bool ts_rx_en; + bool ts_tx_en; + struct sk_buff *ts_slots[ADIN_MAC_MAX_TS_SLOTS]; struct adin1110_cfg *cfg; }; @@ -197,7 +232,6 @@ struct adin1110_priv { bool append_crc; struct adin1110_cfg *cfg; u32 tx_space; - u32 irq_mask; bool forwarding; int irq; struct adin1110_port_priv *ports[ADIN_MAC_MAX_PORTS]; @@ -332,8 +366,29 @@ static int adin1110_round_len(int len) return len; } +static void adin1110_get_rx_timestamp(struct sk_buff *rxb, int offset) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(rxb); + struct timespec64 ts; + u16 frame_header; + + frame_header = get_unaligned_be16(&rxb->data[0]); + if (!(frame_header & ADIN1110_FRAME_HEADER_TS_PRESENT)) + return; + + /* First data after the custom SPI frame header is the timestamp, if + * it was signaled by the TS_PRESENT flag. + */ + ts.tv_sec = get_unaligned_be32(&rxb->data[offset]); + ts.tv_nsec = get_unaligned_be32(&rxb->data[offset + ADIN1110_REG_LEN]); + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = timespec64_to_ktime(ts); +} + static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) { + u32 frame_header_len = ADIN1110_FRAME_HEADER_LEN; struct adin1110_priv *priv = port_priv->priv; u32 header_len = ADIN1110_RD_HEADER_LEN; struct spi_transfer t; @@ -356,10 +411,14 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) if (ret < 0) return ret; - /* The read frame size includes the extra 2 bytes - * from the ADIN1110 frame header. + /* If timestamping is enabled the received data will also have an additional 8 bytes that + * make up the seconds + nanoseconds timestamp. */ - if (frame_size < ADIN1110_FRAME_HEADER_LEN + ADIN1110_FEC_LEN) + if (priv->ts_rx_append) + frame_header_len += ADIN1110_TS_LEN; + + /* the read frame size includes the extra 2 bytes from the ADIN1110 frame header */ + if (frame_size < frame_header_len + ADIN1110_FEC_LEN) return ret; round_len = adin1110_round_len(frame_size); @@ -393,7 +452,11 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) return ret; } - skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN); + if (priv->ts_rx_append) + adin1110_get_rx_timestamp(rxb, header_len + ADIN1110_FRAME_HEADER_LEN); + + skb_pull(rxb, header_len + frame_header_len); + rxb->protocol = eth_type_trans(rxb, port_priv->netdev); if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) || @@ -402,7 +465,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv) netif_rx(rxb); - port_priv->rx_bytes += frame_size - ADIN1110_FRAME_HEADER_LEN; + port_priv->rx_bytes += frame_size - frame_header_len; port_priv->rx_packets++; return 0; @@ -417,6 +480,7 @@ static int adin1110_write_fifo(struct adin1110_port_priv *port_priv, int padding = 0; int padded_len; int round_len; + u16 val = 0; int ret; /* Pad frame to 64 byte length, @@ -448,7 +512,14 @@ static int adin1110_write_fifo(struct adin1110_port_priv *port_priv, } /* mention the port on which to send the frame in the frame header */ - frame_header = cpu_to_be16(port_priv->nr); + val = FIELD_PREP(ADIN1110_FRAME_HEADER_PORT, port_priv->nr); + + /* Request TX capture for this frame in previously assign HW slot. */ + if (port_priv->ts_tx_en && (skb_shinfo(txb)->tx_flags & SKBTX_IN_PROGRESS)) + val |= FIELD_PREP(ADIN1110_FRAME_HEADER_TS_SLOT, + txb->cb[0] + 1); + + frame_header = cpu_to_be16(val); memcpy(&priv->data[header_len], &frame_header, ADIN1110_FRAME_HEADER_LEN); @@ -620,9 +691,72 @@ static void adin1110_wake_queues(struct adin1110_priv *priv) netif_wake_queue(priv->ports[i]->netdev); } +static int adin1110_read_tx_timestamp(struct adin1110_priv *priv, + int port, int slot) +{ + struct skb_shared_hwtstamps shhwtstamps; + struct timespec64 ts; + struct sk_buff *skb; + u32 val; + int ret; + + spin_lock(&priv->state_lock); + skb = priv->ports[port]->ts_slots[slot]; + priv->ports[port]->ts_slots[slot] = NULL; + spin_unlock(&priv->state_lock); + + /* Check if a SKB requested a timestamp from this slot. */ + if (!skb) + return 0; + + ret = adin1110_read_reg(priv, ADIN1110_PY_TTSCXH(slot, port), &val); + if (ret < 0) + goto out; + + ts.tv_sec = val; + + ret = adin1110_read_reg(priv, ADIN1110_PY_TTSCXL(slot, port), &val); + if (ret < 0) + goto out; + + ts.tv_nsec = val; + + /* Check if there is a timestamp actually saved. */ + if (!ts.tv_sec && !ts.tv_nsec) + return 0; + + shhwtstamps.hwtstamp = timespec64_to_ktime(ts); + skb_tstamp_tx(skb, &shhwtstamps); +out: + dev_kfree_skb(skb); + + return ret; +} + +static int adin1110_handle_tx_timestamps(struct adin1110_priv *priv, u32 status) +{ + int port; + int slot; + int ret; + + for (port = 0; port < priv->cfg->ports_nr; port++) { + if (!priv->ports[port]->ts_tx_en || !(status & ADIN1110_TX_RDY)) + continue; + + for (slot = 0; slot < ADIN_MAC_MAX_TS_SLOTS; slot++) { + ret = adin1110_read_tx_timestamp(priv, port, slot); + if (ret < 0) + return ret; + } + } + + return 0; +} + static irqreturn_t adin1110_irq(int irq, void *p) { struct adin1110_priv *priv = p; + u32 status0; u32 status1; u32 val; int ret; @@ -630,6 +764,10 @@ static irqreturn_t adin1110_irq(int irq, void *p) mutex_lock(&priv->lock); + ret = adin1110_read_reg(priv, ADIN1110_STATUS1, &status0); + if (ret < 0) + goto out; + ret = adin1110_read_reg(priv, ADIN1110_STATUS1, &status1); if (ret < 0) goto out; @@ -638,6 +776,10 @@ static irqreturn_t adin1110_irq(int irq, void *p) dev_warn_ratelimited(&priv->spidev->dev, "SPI CRC error on write.\n"); + ret = adin1110_handle_tx_timestamps(priv, status1); + if (ret < 0) + goto out; + ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val); if (ret < 0) goto out; @@ -653,7 +795,7 @@ static irqreturn_t adin1110_irq(int irq, void *p) /* clear IRQ sources */ adin1110_write_reg(priv, ADIN1110_STATUS0, ADIN1110_CLEAR_STATUS0); - adin1110_write_reg(priv, ADIN1110_STATUS1, priv->irq_mask); + adin1110_write_reg(priv, ADIN1110_STATUS1, ADIN1110_CLEAR_STATUS1); out: mutex_unlock(&priv->lock); @@ -824,11 +966,193 @@ static int adin1110_ndo_set_mac_address(struct net_device *netdev, void *addr) return adin1110_set_mac_address(netdev, sa->sa_data); } +static int adin1110_hw_timestamping(struct adin1110_priv *priv, bool enable) +{ + int ret; + + mutex_lock(&priv->lock); + + ret = adin1110_set_bits(priv, ADIN1110_MAC_TS_CFG, + ADIN1110_MAC_TS_CFG_EN, + enable ? ADIN1110_MAC_TS_CFG_EN : 0); + if (ret < 0) + goto out; + + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, + ADIN1110_CONFIG1_FTSE, + enable ? ADIN1110_CONFIG1_FTSE : 0); + if (ret < 0) + goto out; + + /* use only 64 bit timestamps */ + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, ADIN1110_CONFIG1_FTSS, + enable ? ADIN1110_CONFIG1_FTSS : 0); + if (ret < 0) + goto out; + + /* Even if timestamping is enabled just for TX frames, RX frames + * will start showing up with timestamps appended. Need to know + * this when receivng frames from the SPI. + */ + priv->ts_rx_append = enable; + + ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, ADIN1110_CONFIG1_SYNC, + ADIN1110_CONFIG1_SYNC); +out: + mutex_unlock(&priv->lock); + + return ret; +} + +/* ADIN1110 can track for each port 3 TX frames at a time that are stored + * for transfer in the FIFOs. When a TX frame will be sent by the MAC-PHY, + * a timestamp will be stored and an IRQ will be trigger, signaling + * the capture of the timestamp. + */ +static int adin1110_tx_ts_rdy_irq(struct adin1110_port_priv *port_priv, + bool enable) +{ + struct adin1110_priv *priv = port_priv->priv; + int ret; + u32 val; + + if (port_priv->nr) + val = ADIN1110_TTSCAXM_P2_IRQ(0) | ADIN1110_TTSCAXM_P2_IRQ(1) | + ADIN1110_TTSCAXM_P2_IRQ(2); + else + val = ADIN1110_TTSCAXM_P1_IRQ(0) | ADIN1110_TTSCAXM_P1_IRQ(1) | + ADIN1110_TTSCAXM_P1_IRQ(2); + + mutex_lock(&priv->lock); + if (port_priv->nr) + ret = adin1110_set_bits(priv, ADIN1110_IMASK1, val, + enable ? 0 : val); + else + ret = adin1110_set_bits(priv, ADIN1110_IMASK0, val, + enable ? 0 : val); + mutex_unlock(&priv->lock); + if (ret < 0) + return ret; + + return 0; +} + +static int adin1110_hw_tx_timestamp_enable(struct adin1110_port_priv *port_priv) +{ + struct adin1110_priv *priv = port_priv->priv; + int ret; + + ret = adin1110_tx_ts_rdy_irq(port_priv, true); + if (ret < 0) + return ret; + + port_priv->ts_tx_en = true; + + return adin1110_hw_timestamping(priv, true); +} + +static int adin1110_hw_tx_timestamp_disable(struct adin1110_port_priv *port_priv) +{ + struct adin1110_priv *priv = port_priv->priv; + int ret; + + ret = adin1110_tx_ts_rdy_irq(port_priv, false); + if (ret < 0) + return ret; + + port_priv->ts_tx_en = false; + + return adin1110_hw_timestamping(priv, false); +} + +static int adin1110_hw_rx_timestamp_enable(struct adin1110_port_priv *port_priv) +{ + struct adin1110_priv *priv = port_priv->priv; + + port_priv->ts_rx_en = true; + + return adin1110_hw_timestamping(priv, true); +} + +static int adin1110_hw_rx_timestamp_disable(struct adin1110_port_priv *port_priv) +{ + struct adin1110_priv *priv = port_priv->priv; + + port_priv->ts_rx_en = false; + + return adin1110_hw_timestamping(priv, false); +} + +static int adin1110_ioctl_hw_timestamp(struct net_device *netdev, + struct ifreq *rq) +{ + struct adin1110_port_priv *port_priv = netdev_priv(netdev); + struct hwtstamp_config config; + int ret; + + if (copy_from_user(&config, rq->ifr_data, sizeof(config))) + return -EFAULT; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + ret = adin1110_hw_tx_timestamp_disable(port_priv); + break; + case HWTSTAMP_TX_ON: + ret = adin1110_hw_tx_timestamp_enable(port_priv); + break; + default: + return -ERANGE; + } + + if (ret < 0) + return ret; + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + ret = adin1110_hw_rx_timestamp_disable(port_priv); + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: + ret = adin1110_hw_rx_timestamp_enable(port_priv); + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + break; + default: + return -ERANGE; + } + + if (ret < 0) + return ret; + + if (copy_to_user(rq->ifr_data, &config, sizeof(config))) + return -EFAULT; + + return 0; +} + static int adin1110_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) { + struct adin1110_port_priv *port_priv = netdev_priv(netdev); + struct adin1110_priv *priv = port_priv->priv; + if (!netif_running(netdev)) return -EINVAL; + if (priv->ptp_clock && cmd == SIOCSHWTSTAMP) + return adin1110_ioctl_hw_timestamp(netdev, rq); + return phy_do_ioctl(netdev, rq, cmd); } @@ -940,7 +1264,6 @@ static int adin1110_net_open(struct net_device *net_dev) if (priv->cfg->id == ADIN2111_MAC) val |= ADIN2111_RX_RDY_IRQ; - priv->irq_mask = val; ret = adin1110_write_reg(priv, ADIN1110_IMASK1, ~val); if (ret < 0) { netdev_err(net_dev, "Failed to enable chip IRQs: %d\n", ret); @@ -995,6 +1318,14 @@ static int adin1110_net_stop(struct net_device *net_dev) if (ret < 0) return ret; + ret = adin1110_hw_rx_timestamp_disable(port_priv); + if (ret < 0) + return ret; + + ret = adin1110_hw_tx_timestamp_disable(port_priv); + if (ret < 0) + return ret; + netif_stop_queue(port_priv->netdev); flush_work(&port_priv->tx_work); phy_stop(port_priv->phydev); @@ -1015,17 +1346,62 @@ static void adin1110_tx_work(struct work_struct *work) mutex_lock(&priv->lock); while ((txb = skb_dequeue(&port_priv->txq))) { + if (skb_shinfo(txb)->tx_flags & SKBTX_SW_TSTAMP) + skb_tx_timestamp(txb); + ret = adin1110_write_fifo(port_priv, txb); if (ret < 0) dev_err_ratelimited(&priv->spidev->dev, "Frame write error: %d\n", ret); - dev_kfree_skb(txb); + /* If we do not expect a HW timestamp for the SKB free it here */ + if (!(skb_shinfo(txb)->tx_flags & SKBTX_IN_PROGRESS)) + dev_kfree_skb(txb); } mutex_unlock(&priv->lock); } +static void adin1110_assign_ts_slot(struct adin1110_port_priv *port_priv, + struct sk_buff *skb) +{ + struct adin1110_priv *priv = port_priv->priv; + int i; + + if (!port_priv->ts_tx_en) + return; + + spin_lock(&priv->state_lock); + + for (i = 0; i < ADIN_MAC_MAX_TS_SLOTS; i++) { + if (!port_priv->ts_slots[i]) + break; + } + + /* This should not happen. Report that an error occurred. */ + if (i == ADIN_MAC_MAX_TS_SLOTS) { + for (i = 0; i < ADIN_MAC_MAX_TS_SLOTS; i++) { + dev_kfree_skb(port_priv->ts_slots[i]); + port_priv->ts_slots[i] = NULL; + } + + dev_warn_ratelimited(&priv->spidev->dev, + "Time stamps slots full.\n"); + i = 0; + } + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + /* Need to store the slot number we will be using to return + * the TX timestamp. This information will be shared with the device + * when frame is sent over SPI. + */ + skb->cb[0] = i; + port_priv->ts_slots[i] = skb; + + spin_unlock(&priv->state_lock); +} + static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct adin1110_port_priv *port_priv = netdev_priv(dev); @@ -1038,6 +1414,9 @@ static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *d netif_stop_queue(dev); netdev_ret = NETDEV_TX_BUSY; } else { + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) + adin1110_assign_ts_slot(port_priv, skb); + priv->tx_space -= tx_space_needed; skb_queue_tail(&port_priv->txq, skb); } @@ -1104,9 +1483,36 @@ static void adin1110_get_drvinfo(struct net_device *dev, strscpy(di->bus_info, dev_name(dev->dev.parent), sizeof(di->bus_info)); } +static int adin1110_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) +{ + struct adin1110_port_priv *port_priv = netdev_priv(dev); + struct adin1110_priv *priv = port_priv->priv; + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->tx_types = BIT(HWTSTAMP_TX_OFF) | + BIT(HWTSTAMP_TX_ON); + + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_ALL); + + if (priv->ptp_clock) + info->phc_index = ptp_clock_index(priv->ptp_clock); + else + info->phc_index = -1; + + return 0; +} + static const struct ethtool_ops adin1110_ethtool_ops = { .get_drvinfo = adin1110_get_drvinfo, .get_link = ethtool_op_get_link, + .get_ts_info = adin1110_get_ts_info, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, }; From patchwork Fri Jan 20 09:53:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Tachici X-Patchwork-Id: 46271 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp108905wrn; Fri, 20 Jan 2023 01:56:58 -0800 (PST) X-Google-Smtp-Source: AMrXdXtss1EREmi8W2xDzP7jIs7BGvmWzyPzJXBHVTs7XlhmDjZolq6gsFQmDUfvcCEaVMepEG+0 X-Received: by 2002:a50:ed91:0:b0:48e:c073:9453 with SMTP id h17-20020a50ed91000000b0048ec0739453mr29552356edr.15.1674208618640; Fri, 20 Jan 2023 01:56:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674208618; cv=none; d=google.com; s=arc-20160816; b=gAv/I/E6z1Gw6G3d6c/UnFgNHZEorfYguGDvfECV4c3hGdr4J4gwhmyN1c2yKbzzZh rD26sUmhEiTfPPIY2AnmoPOM/KKIqFLpdJ9ntPSYmmN/K+qqV2CmNFZdyFABjFaqLtx3 SZDafE29vMlR6fHPECKoc1mSnPAUYVqd3cP2gLcDuTWPVVSP/eoep1/75ly6hyKpUSkx z9BgoGgsCTl9C0eNI188M7XwUrpQvJCOZa4vnMd6KOhyRaodr61lVLYI8layG0RZmceb dMArFk5dN8BmmH42m1TVvQ3OatUUxSxAGMe/+7etxX2y91n2vXKWlQiwyHGhFTz8/jHl 6NnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=J693kKZeJdhpiw2O3MSvK8L/jztUYWbh7ScmVFxd+SI=; b=PlwJUxE8jBFC+cihP8WRM/6MsIn7YvuUwGFEWHTDUCA5Pnew+D13Pc6K6D8KLCy304 KVH2G4UW0zaOV/u98iqBqtxDZLqSS69cgrNaWwCGa4MOyutUTuE/C739HVKdgA8r+H6w Zj4pJR/rpUAeSYfggX/CBRzQJcYQvKnaVGcuGZaNJdI6IpbbabY+8YIPtq3wmi+vxs52 FfxTjGNOqwTnOHurebk+UgEWm49zPArrCN94X+akTigVmBx/0TzbmlQTez9gC83ue0jZ 6QTpw6GVd8GHCLh2QYnnVzo4msg+DEG7XVrY636GcnsuyCciCd/YApsIdTwofspabxXg DQyA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ez10-20020a056402450a00b004844b4fe450si12129711edb.407.2023.01.20.01.56.34; Fri, 20 Jan 2023 01:56:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=analog.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230354AbjATJye (ORCPT + 99 others); Fri, 20 Jan 2023 04:54:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229767AbjATJyb (ORCPT ); Fri, 20 Jan 2023 04:54:31 -0500 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E06B8518F6; Fri, 20 Jan 2023 01:54:24 -0800 (PST) Received: from pps.filterd (m0167089.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30K8fqbH023335; Fri, 20 Jan 2023 04:54:16 -0500 Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n7qnw09j8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:16 -0500 Received: from m0167089.ppops.net (m0167089.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30K9sGjb001974; Fri, 20 Jan 2023 04:54:16 -0500 Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 3n7qnw09j5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 20 Jan 2023 04:54:15 -0500 Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 30K9sECh036494 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 20 Jan 2023 04:54:14 -0500 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.14; Fri, 20 Jan 2023 04:54:13 -0500 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.986.14 via Frontend Transport; Fri, 20 Jan 2023 04:54:13 -0500 Received: from tachici-Precision-5530.ad.analog.com ([10.48.65.139]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 30K9rqU0021132; Fri, 20 Jan 2023 04:54:09 -0500 From: Alexandru Tachici To: CC: , , , , , , , , , , , Subject: [net-next 3/3] dt-bindings: net: adin1110: Document ts-capt pin Date: Fri, 20 Jan 2023 11:53:48 +0200 Message-ID: <20230120095348.26715-4-alexandru.tachici@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230120095348.26715-1-alexandru.tachici@analog.com> References: <20230120095348.26715-1-alexandru.tachici@analog.com> MIME-Version: 1.0 X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: YDNBpWrcHGfszGd-G8B6bCenBJZ8bm7d X-Proofpoint-ORIG-GUID: 4XgliSjMGY250yf6wsqSYqB3E4URa4XP X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-20_06,2023-01-19_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 adultscore=0 mlxscore=0 bulkscore=0 phishscore=0 spamscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 malwarescore=0 mlxlogscore=888 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301200093 X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755534976521291437?= X-GMAIL-MSGID: =?utf-8?q?1755534976521291437?= Add documentation for the use of the timestamp capture pin. Signed-off-by: Alexandru Tachici Acked-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/net/adi,adin1110.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/net/adi,adin1110.yaml b/Documentation/devicetree/bindings/net/adi,adin1110.yaml index 9de865295d7a..f2db919c166b 100644 --- a/Documentation/devicetree/bindings/net/adi,adin1110.yaml +++ b/Documentation/devicetree/bindings/net/adi,adin1110.yaml @@ -50,6 +50,13 @@ properties: maxItems: 1 description: GPIO connected to active low reset + ts-capt-gpios: + maxItems: 1 + description: | + Optional active high GPIO. Connected to the TS_TIMER pin of ADIN1110. + When pulled up device will save a timestamp containing both the + seconds and nanoseconds part simultaneously. + required: - compatible - reg