From patchwork Mon Sep 13 20:12:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Li X-Patchwork-Id: 511596 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 88B53C433F5 for ; Mon, 13 Sep 2021 20:37:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 655F4610F9 for ; Mon, 13 Sep 2021 20:37:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244852AbhIMUin (ORCPT ); Mon, 13 Sep 2021 16:38:43 -0400 Received: from pbmsgap02.intersil.com ([192.157.179.202]:45884 "EHLO pbmsgap02.intersil.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244538AbhIMUih (ORCPT ); Mon, 13 Sep 2021 16:38:37 -0400 Received: from pps.filterd (pbmsgap02.intersil.com [127.0.0.1]) by pbmsgap02.intersil.com (8.16.0.42/8.16.0.42) with SMTP id 18DK20PC021207; Mon, 13 Sep 2021 16:12:52 -0400 Received: from pbmxdp01.intersil.corp (pbmxdp01.pb.intersil.com [132.158.200.222]) by pbmsgap02.intersil.com with ESMTP id 3b0pmh0skk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Mon, 13 Sep 2021 16:12:51 -0400 Received: from pbmxdp03.intersil.corp (132.158.200.224) by pbmxdp01.intersil.corp (132.158.200.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.2242.4; Mon, 13 Sep 2021 16:12:49 -0400 Received: from localhost (132.158.202.109) by pbmxdp03.intersil.corp (132.158.200.224) with Microsoft SMTP Server id 15.1.2242.4 via Frontend Transport; Mon, 13 Sep 2021 16:12:48 -0400 From: To: CC: , , Min Li Subject: [PATCH net 1/3] ptp: ptp_clockmatrix: Remove idtcm_enable_tod_sync() Date: Mon, 13 Sep 2021 16:12:32 -0400 Message-ID: <1631563954-6700-1-git-send-email-min.li.xe@renesas.com> X-Mailer: git-send-email 2.7.4 X-TM-AS-MML: disable MIME-Version: 1.0 X-Proofpoint-GUID: m19rQYdHsL1hRJ1ySNAa3Zd_pp4hxV-l X-Proofpoint-ORIG-GUID: m19rQYdHsL1hRJ1ySNAa3Zd_pp4hxV-l X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.391, 18.0.790 definitions=2021-09-13_09:2021-09-09,2021-09-13 signatures=0 X-Proofpoint-Spam-Details: rule=junk_notspam policy=junk score=0 spamscore=0 adultscore=0 bulkscore=0 phishscore=0 suspectscore=0 malwarescore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109030001 definitions=main-2109130120 X-Proofpoint-Spam-Reason: mlx Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Min Li Not need since TCS firmware file will configure it properlly. Signed-off-by: Min Li --- drivers/ptp/ptp_clockmatrix.c | 229 +----------------------------------------- 1 file changed, 2 insertions(+), 227 deletions(-) diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index fa63695..9b1c6b2 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -353,8 +353,8 @@ static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm) apll &= SYS_APLL_LOSS_LOCK_LIVE_MASK; dpll &= DPLL_SYS_STATE_MASK; - if (apll == SYS_APLL_LOSS_LOCK_LIVE_LOCKED && - dpll == DPLL_STATE_LOCKED) { + if (apll == SYS_APLL_LOSS_LOCK_LIVE_LOCKED + && dpll == DPLL_STATE_LOCKED) { return 0; } else if (dpll == DPLL_STATE_FREERUN || dpll == DPLL_STATE_HOLDOVER || @@ -1675,222 +1675,6 @@ static int idtcm_enable(struct ptp_clock_info *ptp, return -EOPNOTSUPP; } -static int _enable_pll_tod_sync(struct idtcm *idtcm, - u8 pll, - u8 sync_src, - u8 qn, - u8 qn_plus_1) -{ - int err; - u8 val; - u16 dpll; - u16 out0 = 0, out1 = 0; - - if (qn == 0 && qn_plus_1 == 0) - return 0; - - switch (pll) { - case 0: - dpll = DPLL_0; - if (qn) - out0 = OUTPUT_0; - if (qn_plus_1) - out1 = OUTPUT_1; - break; - case 1: - dpll = DPLL_1; - if (qn) - out0 = OUTPUT_2; - if (qn_plus_1) - out1 = OUTPUT_3; - break; - case 2: - dpll = DPLL_2; - if (qn) - out0 = OUTPUT_4; - if (qn_plus_1) - out1 = OUTPUT_5; - break; - case 3: - dpll = DPLL_3; - if (qn) - out0 = OUTPUT_6; - if (qn_plus_1) - out1 = OUTPUT_7; - break; - case 4: - dpll = DPLL_4; - if (qn) - out0 = OUTPUT_8; - break; - case 5: - dpll = DPLL_5; - if (qn) - out0 = OUTPUT_9; - if (qn_plus_1) - out1 = OUTPUT_8; - break; - case 6: - dpll = DPLL_6; - if (qn) - out0 = OUTPUT_10; - if (qn_plus_1) - out1 = OUTPUT_11; - break; - case 7: - dpll = DPLL_7; - if (qn) - out0 = OUTPUT_11; - break; - default: - return -EINVAL; - } - - /* - * Enable OUTPUT OUT_SYNC. - */ - if (out0) { - err = idtcm_read(idtcm, out0, OUT_CTRL_1, &val, sizeof(val)); - if (err) - return err; - - val &= ~OUT_SYNC_DISABLE; - - err = idtcm_write(idtcm, out0, OUT_CTRL_1, &val, sizeof(val)); - if (err) - return err; - } - - if (out1) { - err = idtcm_read(idtcm, out1, OUT_CTRL_1, &val, sizeof(val)); - if (err) - return err; - - val &= ~OUT_SYNC_DISABLE; - - err = idtcm_write(idtcm, out1, OUT_CTRL_1, &val, sizeof(val)); - if (err) - return err; - } - - /* enable dpll sync tod pps, must be set before dpll_mode */ - err = idtcm_read(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val)); - if (err) - return err; - - val &= ~(TOD_SYNC_SOURCE_MASK << TOD_SYNC_SOURCE_SHIFT); - val |= (sync_src << TOD_SYNC_SOURCE_SHIFT); - val |= TOD_SYNC_EN; - - return idtcm_write(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val)); -} - -static int idtcm_enable_tod_sync(struct idtcm_channel *channel) -{ - struct idtcm *idtcm = channel->idtcm; - u8 pll; - u8 sync_src; - u8 qn; - u8 qn_plus_1; - u8 cfg; - int err = 0; - u16 output_mask = channel->output_mask; - u8 out8_mux = 0; - u8 out11_mux = 0; - u8 temp; - - /* - * set tod_out_sync_enable to 0. - */ - err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg)); - if (err) - return err; - - cfg &= ~TOD_OUT_SYNC_ENABLE; - - err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg)); - if (err) - return err; - - switch (channel->tod_n) { - case TOD_0: - sync_src = 0; - break; - case TOD_1: - sync_src = 1; - break; - case TOD_2: - sync_src = 2; - break; - case TOD_3: - sync_src = 3; - break; - default: - return -EINVAL; - } - - err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE, &temp, sizeof(temp)); - if (err) - return err; - - if ((temp & Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) == - Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) - out8_mux = 1; - - err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE, &temp, sizeof(temp)); - if (err) - return err; - - if ((temp & Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) == - Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) - out11_mux = 1; - - for (pll = 0; pll < 8; pll++) { - qn = 0; - qn_plus_1 = 0; - - if (pll < 4) { - /* First 4 pll has 2 outputs */ - qn = output_mask & 0x1; - output_mask = output_mask >> 1; - qn_plus_1 = output_mask & 0x1; - output_mask = output_mask >> 1; - } else if (pll == 4) { - if (out8_mux == 0) { - qn = output_mask & 0x1; - output_mask = output_mask >> 1; - } - } else if (pll == 5) { - if (out8_mux) { - qn_plus_1 = output_mask & 0x1; - output_mask = output_mask >> 1; - } - qn = output_mask & 0x1; - output_mask = output_mask >> 1; - } else if (pll == 6) { - qn = output_mask & 0x1; - output_mask = output_mask >> 1; - if (out11_mux) { - qn_plus_1 = output_mask & 0x1; - output_mask = output_mask >> 1; - } - } else if (pll == 7) { - if (out11_mux == 0) { - qn = output_mask & 0x1; - output_mask = output_mask >> 1; - } - } - - if (qn != 0 || qn_plus_1 != 0) - err = _enable_pll_tod_sync(idtcm, pll, sync_src, qn, - qn_plus_1); - if (err) - return err; - } - - return err; -} - static int idtcm_enable_tod(struct idtcm_channel *channel) { struct idtcm *idtcm = channel->idtcm; @@ -2101,15 +1885,6 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) snprintf(channel->caps.name, sizeof(channel->caps.name), "IDT CM TOD%u", index); - if (!idtcm->deprecated) { - err = idtcm_enable_tod_sync(channel); - if (err) { - dev_err(&idtcm->client->dev, - "Failed at line %d in %s!", __LINE__, __func__); - return err; - } - } - /* Sync pll mode with hardware */ err = idtcm_get_pll_mode(channel, &channel->pll_mode); if (err) { From patchwork Mon Sep 13 20:12:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Li X-Patchwork-Id: 511597 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-21.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A453C433EF for ; Mon, 13 Sep 2021 20:33:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6445F6108B for ; Mon, 13 Sep 2021 20:33:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243982AbhIMUeg (ORCPT ); Mon, 13 Sep 2021 16:34:36 -0400 Received: from pbmsgap02.intersil.com ([192.157.179.202]:45628 "EHLO pbmsgap02.intersil.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239327AbhIMUef (ORCPT ); Mon, 13 Sep 2021 16:34:35 -0400 X-Greylist: delayed 1225 seconds by postgrey-1.27 at vger.kernel.org; Mon, 13 Sep 2021 16:34:34 EDT Received: from pps.filterd (pbmsgap02.intersil.com [127.0.0.1]) by pbmsgap02.intersil.com (8.16.0.42/8.16.0.42) with SMTP id 18DK20PD021207; Mon, 13 Sep 2021 16:12:54 -0400 Received: from pbmxdp01.intersil.corp (pbmxdp01.pb.intersil.com [132.158.200.222]) by pbmsgap02.intersil.com with ESMTP id 3b0pmh0skm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Mon, 13 Sep 2021 16:12:54 -0400 Received: from pbmxdp03.intersil.corp (132.158.200.224) by pbmxdp01.intersil.corp (132.158.200.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.2242.4; Mon, 13 Sep 2021 16:12:52 -0400 Received: from localhost (132.158.202.109) by pbmxdp03.intersil.corp (132.158.200.224) with Microsoft SMTP Server id 15.1.2242.4 via Frontend Transport; Mon, 13 Sep 2021 16:12:52 -0400 From: To: CC: , , Min Li Subject: [PATCH net 2/3] ptp: ptp_clockmatrix: Add support for FW 5.2 (8A34005) Date: Mon, 13 Sep 2021 16:12:33 -0400 Message-ID: <1631563954-6700-2-git-send-email-min.li.xe@renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1631563954-6700-1-git-send-email-min.li.xe@renesas.com> References: <1631563954-6700-1-git-send-email-min.li.xe@renesas.com> X-TM-AS-MML: disable MIME-Version: 1.0 X-Proofpoint-GUID: Rh1_YT17UOQpLgRAHJER5lTQYznsVa1- X-Proofpoint-ORIG-GUID: Rh1_YT17UOQpLgRAHJER5lTQYznsVa1- X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.391, 18.0.790 definitions=2021-09-13_09:2021-09-09,2021-09-13 signatures=0 X-Proofpoint-Spam-Details: rule=junk_notspam policy=junk score=0 spamscore=0 adultscore=0 bulkscore=0 phishscore=0 suspectscore=0 malwarescore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109030001 definitions=main-2109130120 X-Proofpoint-Spam-Reason: mlx Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Min Li So far we don't need to support new 5.2 functions but different register addresses Signed-off-by: Min Li --- drivers/ptp/idt8a340_reg.h | 61 +++++++++++++- drivers/ptp/ptp_clockmatrix.c | 179 ++++++++++++++++++++++-------------------- drivers/ptp/ptp_clockmatrix.h | 17 ++-- 3 files changed, 165 insertions(+), 92 deletions(-) diff --git a/drivers/ptp/idt8a340_reg.h b/drivers/ptp/idt8a340_reg.h index ac524cf..dea8e1d 100644 --- a/drivers/ptp/idt8a340_reg.h +++ b/drivers/ptp/idt8a340_reg.h @@ -5,7 +5,7 @@ * https://github.com/richardcochran/regen * * Hand modified to include some HW registers. - * Based on 4.8.0, SCSR rev C commit a03c7ae5 + * Based on 5.2.0, Family Programming Guide (Sept 30, 2020) */ #ifndef HAVE_IDT8A340_REG #define HAVE_IDT8A340_REG @@ -100,6 +100,7 @@ #define RESET_CTRL 0xc000 #define SM_RESET 0x0012 +#define SM_RESET_V520 0x0013 #define SM_RESET_CMD 0x5A #define GENERAL_STATUS 0xc014 @@ -130,6 +131,8 @@ #define GPIO_USER_CONTROL 0xc160 #define GPIO0_TO_7_OUT 0x0000 #define GPIO8_TO_15_OUT 0x0001 +#define GPIO0_TO_7_OUT_V520 0x0002 +#define GPIO8_TO_15_OUT_V520 0x0003 #define STICKY_STATUS_CLEAR 0xc164 @@ -216,22 +219,27 @@ #define DPLL_REF_MODE 0x0035 #define DPLL_PHASE_MEASUREMENT_CFG 0x0036 #define DPLL_MODE 0x0037 +#define DPLL_MODE_V520 0x003B #define DPLL_1 0xc400 #define DPLL_2 0xc438 +#define DPLL_2_V520 0xc43c #define DPLL_3 0xc480 #define DPLL_4 0xc4b8 +#define DPLL_4_V520 0xc4bc #define DPLL_5 0xc500 #define DPLL_6 0xc538 +#define DPLL_6_V520 0xc53c #define DPLL_7 0xc580 #define SYS_DPLL 0xc5b8 +#define SYS_DPLL_V520 0xc5bc #define DPLL_CTRL_0 0xc600 #define DPLL_CTRL_DPLL_MANU_REF_CFG 0x0001 @@ -331,6 +339,7 @@ #define GPIO_ALERT_OUT_CFG 0x000e #define GPIO_TOD_NOTIFICATION_CFG 0x000f #define GPIO_CTRL 0x0010 +#define GPIO_CTRL_V520 0x0011 #define GPIO_1 0xc8d4 @@ -365,6 +374,7 @@ #define OUT_DIV_MUX 0xca12 #define OUTPUT_0 0xca14 +#define OUTPUT_0_V520 0xca20 /* FOD frequency output divider value */ #define OUT_DIV 0x0000 #define OUT_DUTY_CYCLE_HIGH 0x0004 @@ -374,28 +384,40 @@ #define OUT_PHASE_ADJ 0x000c #define OUTPUT_1 0xca24 +#define OUTPUT_1_V520 0xca30 #define OUTPUT_2 0xca34 +#define OUTPUT_2_V520 0xca40 #define OUTPUT_3 0xca44 +#define OUTPUT_3_V520 0xca50 #define OUTPUT_4 0xca54 +#define OUTPUT_4_V520 0xca60 #define OUTPUT_5 0xca64 +#define OUTPUT_5_V520 0xca80 #define OUTPUT_6 0xca80 +#define OUTPUT_6_V520 0xca90 #define OUTPUT_7 0xca90 +#define OUTPUT_7_V520 0xcaa0 #define OUTPUT_8 0xcaa0 +#define OUTPUT_8_V520 0xcab0 #define OUTPUT_9 0xcab0 +#define OUTPUT_9_V520 0xcac0 #define OUTPUT_10 0xcac0 +#define OUTPUT_10_V520 0xcad0 #define OUTPUT_11 0xcad0 +#define OUTPUT_11_V520 0xcae0 #define SERIAL 0xcae0 +#define SERIAL_V520 0xcaf0 #define PWM_ENCODER_0 0xcb00 @@ -416,50 +438,72 @@ #define PWM_DECODER_0 0xcb40 #define PWM_DECODER_1 0xcb48 +#define PWM_DECODER_1_V520 0xcb4a #define PWM_DECODER_2 0xcb50 +#define PWM_DECODER_2_V520 0xcb54 #define PWM_DECODER_3 0xcb58 +#define PWM_DECODER_3_V520 0xcb5e #define PWM_DECODER_4 0xcb60 +#define PWM_DECODER_4_V520 0xcb68 #define PWM_DECODER_5 0xcb68 +#define PWM_DECODER_5_V520 0xcb80 #define PWM_DECODER_6 0xcb70 +#define PWM_DECODER_6_V520 0xcb8a #define PWM_DECODER_7 0xcb80 +#define PWM_DECODER_7_V520 0xcb94 #define PWM_DECODER_8 0xcb88 +#define PWM_DECODER_8_V520 0xcb9e #define PWM_DECODER_9 0xcb90 +#define PWM_DECODER_9_V520 0xcba8 #define PWM_DECODER_10 0xcb98 +#define PWM_DECODER_10_V520 0xcbb2 #define PWM_DECODER_11 0xcba0 +#define PWM_DECODER_11_V520 0xcbbc #define PWM_DECODER_12 0xcba8 +#define PWM_DECODER_12_V520 0xcbc6 #define PWM_DECODER_13 0xcbb0 +#define PWM_DECODER_13_V520 0xcbd0 #define PWM_DECODER_14 0xcbb8 +#define PWM_DECODER_14_V520 0xcbda #define PWM_DECODER_15 0xcbc0 +#define PWM_DECODER_15_V520 0xcbe4 #define PWM_USER_DATA 0xcbc8 +#define PWM_USER_DATA_V520 0xcbf0 #define TOD_0 0xcbcc +#define TOD_0_V520 0xcc00 /* Enable TOD counter, output channel sync and even-PPS mode */ #define TOD_CFG 0x0000 +#define TOD_CFG_V520 0x0001 #define TOD_1 0xcbce +#define TOD_1_V520 0xcc02 #define TOD_2 0xcbd0 +#define TOD_2_V520 0xcc04 #define TOD_3 0xcbd2 +#define TOD_3_V520 0xcc06 #define TOD_WRITE_0 0xcc00 +#define TOD_WRITE_0_V520 0xcc10 /* 8-bit subns, 32-bit ns, 48-bit seconds */ #define TOD_WRITE 0x0000 /* Counter increments after TOD write is completed */ @@ -470,12 +514,16 @@ #define TOD_WRITE_CMD 0x000f #define TOD_WRITE_1 0xcc10 +#define TOD_WRITE_1_V520 0xcc20 #define TOD_WRITE_2 0xcc20 +#define TOD_WRITE_2_V520 0xcc30 #define TOD_WRITE_3 0xcc30 +#define TOD_WRITE_3_V520 0xcc40 #define TOD_READ_PRIMARY_0 0xcc40 +#define TOD_READ_PRIMARY_0_V520 0xcc50 /* 8-bit subns, 32-bit ns, 48-bit seconds */ #define TOD_READ_PRIMARY 0x0000 /* Counter increments after TOD write is completed */ @@ -484,22 +532,31 @@ #define TOD_READ_PRIMARY_SEL_CFG_0 0x000c /* Read trigger selection */ #define TOD_READ_PRIMARY_CMD 0x000e +#define TOD_READ_PRIMARY_CMD_V520 0x000f #define TOD_READ_PRIMARY_1 0xcc50 +#define TOD_READ_PRIMARY_1_V520 0xcc60 #define TOD_READ_PRIMARY_2 0xcc60 +#define TOD_READ_PRIMARY_2_V520 0xcc80 #define TOD_READ_PRIMARY_3 0xcc80 +#define TOD_READ_PRIMARY_3_V520 0xcc90 #define TOD_READ_SECONDARY_0 0xcc90 +#define TOD_READ_SECONDARY_0_V520 0xcca0 #define TOD_READ_SECONDARY_1 0xcca0 +#define TOD_READ_SECONDARY_1_V520 0xccb0 #define TOD_READ_SECONDARY_2 0xccb0 +#define TOD_READ_SECONDARY_2_V520 0xccc0 #define TOD_READ_SECONDARY_3 0xccc0 +#define TOD_READ_SECONDARY_3_V520 0xccd0 #define OUTPUT_TDC_CFG 0xccd0 +#define OUTPUT_TDC_CFG_V520 0xcce0 #define OUTPUT_TDC_0 0xcd00 @@ -512,8 +569,10 @@ #define INPUT_TDC 0xcd20 #define SCRATCH 0xcf50 +#define SCRATCH_V520 0xcf4c #define EEPROM 0xcf68 +#define EEPROM_V520 0xcf64 #define OTP 0xcf70 diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index 9b1c6b2..2c552a0 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -33,15 +33,21 @@ module_param(firmware, charp, 0); #define SETTIME_CORRECTION (0) -static int contains_full_configuration(const struct firmware *fw) +static int contains_full_configuration(struct idtcm *idtcm, + const struct firmware *fw) { - s32 full_count = FULL_FW_CFG_BYTES - FULL_FW_CFG_SKIPPED_BYTES; struct idtcm_fwrc *rec = (struct idtcm_fwrc *)fw->data; + u16 scratch = IDTCM_FW_REG(idtcm->fw_ver, V520, SCRATCH); + s32 full_count; s32 count = 0; u16 regaddr; u8 loaddr; s32 len; + /* 4 bytes skipped every 0x80 */ + full_count = (scratch - GPIO_USER_CONTROL) - + ((scratch >> 7) - (GPIO_USER_CONTROL >> 7)) * 4; + /* If the firmware contains 'full configuration' SM_RESET can be used * to ensure proper configuration. * @@ -57,7 +63,7 @@ static int contains_full_configuration(const struct firmware *fw) rec++; /* Top (status registers) and bottom are read-only */ - if (regaddr < GPIO_USER_CONTROL || regaddr >= SCRATCH) + if (regaddr < GPIO_USER_CONTROL || regaddr >= scratch) continue; /* Page size 128, last 4 bytes of page skipped */ @@ -152,6 +158,19 @@ static int idtcm_strverscmp(const char *version1, const char *version2) return 0; } +static enum fw_version idtcm_fw_version(const char *version) +{ + enum fw_version ver = V_DEFAULT; + + if (idtcm_strverscmp(version, "4.8.7") >= 0) + ver = V487; + + if (idtcm_strverscmp(version, "5.2.0") >= 0) + ver = V520; + + return ver; +} + static int idtcm_xfer_read(struct idtcm *idtcm, u8 regaddr, u8 *buf, @@ -353,8 +372,8 @@ static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm) apll &= SYS_APLL_LOSS_LOCK_LIVE_MASK; dpll &= DPLL_SYS_STATE_MASK; - if (apll == SYS_APLL_LOSS_LOCK_LIVE_LOCKED - && dpll == DPLL_STATE_LOCKED) { + if (apll == SYS_APLL_LOSS_LOCK_LIVE_LOCKED && + dpll == DPLL_STATE_LOCKED) { return 0; } else if (dpll == DPLL_STATE_FREERUN || dpll == DPLL_STATE_HOLDOVER || @@ -388,13 +407,14 @@ static int _idtcm_gettime(struct idtcm_channel *channel, struct timespec64 *ts) { struct idtcm *idtcm = channel->idtcm; + u16 tod_read_cmd = IDTCM_FW_REG(idtcm->fw_ver, V520, TOD_READ_PRIMARY_CMD); u8 buf[TOD_BYTE_COUNT]; u8 timeout = 10; u8 trigger; int err; err = idtcm_read(idtcm, channel->tod_read_primary, - TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger)); + tod_read_cmd, &trigger, sizeof(trigger)); if (err) return err; @@ -403,7 +423,7 @@ static int _idtcm_gettime(struct idtcm_channel *channel, trigger &= ~TOD_READ_TRIGGER_MODE; /* single shot */ err = idtcm_write(idtcm, channel->tod_read_primary, - TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger)); + tod_read_cmd, &trigger, sizeof(trigger)); if (err) return err; @@ -413,7 +433,7 @@ static int _idtcm_gettime(struct idtcm_channel *channel, idtcm->start_time = ktime_get_raw(); err = idtcm_read(idtcm, channel->tod_read_primary, - TOD_READ_PRIMARY_CMD, &trigger, + tod_read_cmd, &trigger, sizeof(trigger)); if (err) return err; @@ -559,35 +579,10 @@ static int _sync_pll_output(struct idtcm *idtcm, return err; } -static int sync_source_dpll_tod_pps(u16 tod_addr, u8 *sync_src) -{ - int err = 0; - - switch (tod_addr) { - case TOD_0: - *sync_src = SYNC_SOURCE_DPLL0_TOD_PPS; - break; - case TOD_1: - *sync_src = SYNC_SOURCE_DPLL1_TOD_PPS; - break; - case TOD_2: - *sync_src = SYNC_SOURCE_DPLL2_TOD_PPS; - break; - case TOD_3: - *sync_src = SYNC_SOURCE_DPLL3_TOD_PPS; - break; - default: - err = -EINVAL; - } - - return err; -} - static int idtcm_sync_pps_output(struct idtcm_channel *channel) { struct idtcm *idtcm = channel->idtcm; u8 pll; - u8 sync_src; u8 qn; u8 qn_plus_1; int err = 0; @@ -596,10 +591,6 @@ static int idtcm_sync_pps_output(struct idtcm_channel *channel) u8 temp; u16 output_mask = channel->output_mask; - err = sync_source_dpll_tod_pps(channel->tod_n, &sync_src); - if (err) - return err; - err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE, &temp, sizeof(temp)); if (err) @@ -655,8 +646,8 @@ static int idtcm_sync_pps_output(struct idtcm_channel *channel) } if (qn != 0 || qn_plus_1 != 0) - err = _sync_pll_output(idtcm, pll, sync_src, qn, - qn_plus_1); + err = _sync_pll_output(idtcm, pll, channel->sync_src, + qn, qn_plus_1); if (err) return err; @@ -793,46 +784,46 @@ static int _idtcm_set_dpll_scsr_tod(struct idtcm_channel *channel, return 0; } -static int get_output_base_addr(u8 outn) +static int get_output_base_addr(enum fw_version ver, u8 outn) { int base; switch (outn) { case 0: - base = OUTPUT_0; + base = IDTCM_FW_REG(ver, V520, OUTPUT_0); break; case 1: - base = OUTPUT_1; + base = IDTCM_FW_REG(ver, V520, OUTPUT_1); break; case 2: - base = OUTPUT_2; + base = IDTCM_FW_REG(ver, V520, OUTPUT_2); break; case 3: - base = OUTPUT_3; + base = IDTCM_FW_REG(ver, V520, OUTPUT_3); break; case 4: - base = OUTPUT_4; + base = IDTCM_FW_REG(ver, V520, OUTPUT_4); break; case 5: - base = OUTPUT_5; + base = IDTCM_FW_REG(ver, V520, OUTPUT_5); break; case 6: - base = OUTPUT_6; + base = IDTCM_FW_REG(ver, V520, OUTPUT_6); break; case 7: - base = OUTPUT_7; + base = IDTCM_FW_REG(ver, V520, OUTPUT_7); break; case 8: - base = OUTPUT_8; + base = IDTCM_FW_REG(ver, V520, OUTPUT_8); break; case 9: - base = OUTPUT_9; + base = IDTCM_FW_REG(ver, V520, OUTPUT_9); break; case 10: - base = OUTPUT_10; + base = IDTCM_FW_REG(ver, V520, OUTPUT_10); break; case 11: - base = OUTPUT_11; + base = IDTCM_FW_REG(ver, V520, OUTPUT_11); break; default: base = -EINVAL; @@ -1032,7 +1023,9 @@ static int idtcm_state_machine_reset(struct idtcm *idtcm) clear_boot_status(idtcm); - err = idtcm_write(idtcm, RESET_CTRL, SM_RESET, &byte, sizeof(byte)); + err = idtcm_write(idtcm, RESET_CTRL, + IDTCM_FW_REG(idtcm->fw_ver, V520, SM_RESET), + &byte, sizeof(byte)); if (!err) { for (i = 0; i < 30; i++) { @@ -1214,6 +1207,7 @@ static void display_pll_and_masks(struct idtcm *idtcm) static int idtcm_load_firmware(struct idtcm *idtcm, struct device *dev) { + u16 scratch = IDTCM_FW_REG(idtcm->fw_ver, V520, SCRATCH); char fname[128] = FW_FILENAME; const struct firmware *fw; struct idtcm_fwrc *rec; @@ -1239,7 +1233,7 @@ static int idtcm_load_firmware(struct idtcm *idtcm, rec = (struct idtcm_fwrc *) fw->data; - if (contains_full_configuration(fw)) + if (contains_full_configuration(idtcm, fw)) idtcm_state_machine_reset(idtcm); for (len = fw->size; len > 0; len -= sizeof(*rec)) { @@ -1263,7 +1257,7 @@ static int idtcm_load_firmware(struct idtcm *idtcm, err = 0; /* Top (status registers) and bottom are read-only */ - if (regaddr < GPIO_USER_CONTROL || regaddr >= SCRATCH) + if (regaddr < GPIO_USER_CONTROL || regaddr >= scratch) continue; /* Page size 128, last 4 bytes of page skipped */ @@ -1292,7 +1286,7 @@ static int idtcm_output_enable(struct idtcm_channel *channel, int err; u8 val; - base = get_output_base_addr(outn); + base = get_output_base_addr(idtcm->fw_ver, outn); if (!(base > 0)) { dev_err(&idtcm->client->dev, @@ -1366,7 +1360,8 @@ static int idtcm_get_pll_mode(struct idtcm_channel *channel, int err; u8 dpll_mode; - err = idtcm_read(idtcm, channel->dpll_n, DPLL_MODE, + err = idtcm_read(idtcm, channel->dpll_n, + IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_MODE), &dpll_mode, sizeof(dpll_mode)); if (err) return err; @@ -1383,7 +1378,8 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel, int err; u8 dpll_mode; - err = idtcm_read(idtcm, channel->dpll_n, DPLL_MODE, + err = idtcm_read(idtcm, channel->dpll_n, + IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_MODE), &dpll_mode, sizeof(dpll_mode)); if (err) return err; @@ -1394,7 +1390,8 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel, channel->pll_mode = pll_mode; - err = idtcm_write(idtcm, channel->dpll_n, DPLL_MODE, + err = idtcm_write(idtcm, channel->dpll_n, + IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_MODE), &dpll_mode, sizeof(dpll_mode)); if (err) return err; @@ -1404,8 +1401,8 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel, /* PTP Hardware Clock interface */ -/* - * Maximum absolute value for write phase offset in picoseconds +/** + * @brief Maximum absolute value for write phase offset in picoseconds * * Destination signed register is 32-bit register in resolution of 50ps * @@ -1679,23 +1676,31 @@ static int idtcm_enable_tod(struct idtcm_channel *channel) { struct idtcm *idtcm = channel->idtcm; struct timespec64 ts = {0, 0}; + u16 tod_cfg = IDTCM_FW_REG(idtcm->fw_ver, V520, TOD_CFG); u8 cfg; int err; + /* STEELAI-366 - Temporary workaround for ts2phc compatibility */ + if (0) { + err = idtcm_output_mask_enable(channel, false); + if (err) + return err; + } + /* * Start the TOD clock ticking. */ - err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg)); + err = idtcm_read(idtcm, channel->tod_n, tod_cfg, &cfg, sizeof(cfg)); if (err) return err; cfg |= TOD_ENABLE; - err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg)); + err = idtcm_write(idtcm, channel->tod_n, tod_cfg, &cfg, sizeof(cfg)); if (err) return err; - if (idtcm->deprecated) + if (idtcm->fw_ver < V487) return _idtcm_settime_deprecated(channel, &ts); else return _idtcm_settime(channel, &ts, @@ -1723,10 +1728,7 @@ static void idtcm_set_version_info(struct idtcm *idtcm) snprintf(idtcm->version, sizeof(idtcm->version), "%u.%u.%u", major, minor, hotfix); - if (idtcm_strverscmp(idtcm->version, "4.8.7") >= 0) - idtcm->deprecated = 0; - else - idtcm->deprecated = 1; + idtcm->fw_ver = idtcm_fw_version(idtcm->version); dev_info(&idtcm->client->dev, "%d.%d.%d, Id: 0x%04x HW Rev: %d OTP Config Select: %d", @@ -1760,6 +1762,7 @@ static const struct ptp_clock_info idtcm_caps_deprecated = { static int configure_channel_pll(struct idtcm_channel *channel) { + struct idtcm *idtcm = channel->idtcm; int err = 0; switch (channel->pll) { @@ -1781,7 +1784,7 @@ static int configure_channel_pll(struct idtcm_channel *channel) break; case 2: channel->dpll_freq = DPLL_FREQ_2; - channel->dpll_n = DPLL_2; + channel->dpll_n = IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_2); channel->hw_dpll_n = HW_DPLL_2; channel->dpll_phase = DPLL_PHASE_2; channel->dpll_ctrl_n = DPLL_CTRL_2; @@ -1797,7 +1800,7 @@ static int configure_channel_pll(struct idtcm_channel *channel) break; case 4: channel->dpll_freq = DPLL_FREQ_4; - channel->dpll_n = DPLL_4; + channel->dpll_n = IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_4); channel->hw_dpll_n = HW_DPLL_4; channel->dpll_phase = DPLL_PHASE_4; channel->dpll_ctrl_n = DPLL_CTRL_4; @@ -1813,7 +1816,7 @@ static int configure_channel_pll(struct idtcm_channel *channel) break; case 6: channel->dpll_freq = DPLL_FREQ_6; - channel->dpll_n = DPLL_6; + channel->dpll_n = IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_6); channel->hw_dpll_n = HW_DPLL_6; channel->dpll_phase = DPLL_PHASE_6; channel->dpll_ctrl_n = DPLL_CTRL_6; @@ -1836,6 +1839,7 @@ static int configure_channel_pll(struct idtcm_channel *channel) static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) { + enum fw_version fw_ver = idtcm->fw_ver; struct idtcm_channel *channel; int err; @@ -1843,6 +1847,7 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) return -EINVAL; channel = &idtcm->channel[index]; + channel->idtcm = idtcm; /* Set pll addresses */ err = configure_channel_pll(channel); @@ -1852,32 +1857,34 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) /* Set tod addresses */ switch (index) { case 0: - channel->tod_read_primary = TOD_READ_PRIMARY_0; - channel->tod_write = TOD_WRITE_0; - channel->tod_n = TOD_0; + channel->tod_read_primary = IDTCM_FW_REG(fw_ver, V520, TOD_READ_PRIMARY_0); + channel->tod_write = IDTCM_FW_REG(fw_ver, V520, TOD_WRITE_0); + channel->tod_n = IDTCM_FW_REG(fw_ver, V520, TOD_0); + channel->sync_src = SYNC_SOURCE_DPLL0_TOD_PPS; break; case 1: - channel->tod_read_primary = TOD_READ_PRIMARY_1; - channel->tod_write = TOD_WRITE_1; - channel->tod_n = TOD_1; + channel->tod_read_primary = IDTCM_FW_REG(fw_ver, V520, TOD_READ_PRIMARY_1); + channel->tod_write = IDTCM_FW_REG(fw_ver, V520, TOD_WRITE_1); + channel->tod_n = IDTCM_FW_REG(fw_ver, V520, TOD_1); + channel->sync_src = SYNC_SOURCE_DPLL1_TOD_PPS; break; case 2: - channel->tod_read_primary = TOD_READ_PRIMARY_2; - channel->tod_write = TOD_WRITE_2; - channel->tod_n = TOD_2; + channel->tod_read_primary = IDTCM_FW_REG(fw_ver, V520, TOD_READ_PRIMARY_2); + channel->tod_write = IDTCM_FW_REG(fw_ver, V520, TOD_WRITE_2); + channel->tod_n = IDTCM_FW_REG(fw_ver, V520, TOD_2); + channel->sync_src = SYNC_SOURCE_DPLL2_TOD_PPS; break; case 3: - channel->tod_read_primary = TOD_READ_PRIMARY_3; - channel->tod_write = TOD_WRITE_3; - channel->tod_n = TOD_3; + channel->tod_read_primary = IDTCM_FW_REG(fw_ver, V520, TOD_READ_PRIMARY_3); + channel->tod_write = IDTCM_FW_REG(fw_ver, V520, TOD_WRITE_3); + channel->tod_n = IDTCM_FW_REG(fw_ver, V520, TOD_3); + channel->sync_src = SYNC_SOURCE_DPLL3_TOD_PPS; break; default: return -EINVAL; } - channel->idtcm = idtcm; - - if (idtcm->deprecated) + if (idtcm->fw_ver < V487) channel->caps = idtcm_caps_deprecated; else channel->caps = idtcm_caps; diff --git a/drivers/ptp/ptp_clockmatrix.h b/drivers/ptp/ptp_clockmatrix.h index fb32327..843a9d7 100644 --- a/drivers/ptp/ptp_clockmatrix.h +++ b/drivers/ptp/ptp_clockmatrix.h @@ -57,10 +57,10 @@ #define IDTCM_MAX_WRITE_COUNT (512) -#define FULL_FW_CFG_BYTES (SCRATCH - GPIO_USER_CONTROL) -#define FULL_FW_CFG_SKIPPED_BYTES (((SCRATCH >> 7) \ - - (GPIO_USER_CONTROL >> 7)) \ - * 4) /* 4 bytes skipped every 0x80 */ +/* + * Return register address based on passed in firmware version + */ +#define IDTCM_FW_REG(FW, VER, REG) (((FW) < (VER)) ? (REG) : (REG##_##VER)) /* Values of DPLL_N.DPLL_MODE.PLL_MODE */ enum pll_mode { @@ -119,6 +119,12 @@ enum dpll_state { DPLL_STATE_MAX = DPLL_STATE_OPEN_LOOP, }; +enum fw_version { + V_DEFAULT = 0, + V487 = 1, + V520 = 2, +}; + struct idtcm; struct idtcm_channel { @@ -134,6 +140,7 @@ struct idtcm_channel { u16 tod_write; u16 tod_n; u16 hw_dpll_n; + u8 sync_src; enum pll_mode pll_mode; u8 pll; u16 output_mask; @@ -145,7 +152,7 @@ struct idtcm { u8 page_offset; u8 tod_mask; char version[16]; - u8 deprecated; + enum fw_version fw_ver; /* Overhead calculation for adjtime */ u8 calculate_overhead_flag; From patchwork Mon Sep 13 20:12:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Li X-Patchwork-Id: 510272 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9F9DC433F5 for ; Mon, 13 Sep 2021 20:37:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A746660F11 for ; Mon, 13 Sep 2021 20:37:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244382AbhIMUiP (ORCPT ); Mon, 13 Sep 2021 16:38:15 -0400 Received: from pbmsgap01.intersil.com ([192.157.179.201]:35442 "EHLO pbmsgap01.intersil.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241451AbhIMUiO (ORCPT ); Mon, 13 Sep 2021 16:38:14 -0400 Received: from pps.filterd (pbmsgap01.intersil.com [127.0.0.1]) by pbmsgap01.intersil.com (8.16.0.42/8.16.0.42) with SMTP id 18DK36rl026133; Mon, 13 Sep 2021 16:12:53 -0400 Received: from pbmxdp02.intersil.corp (pbmxdp02.pb.intersil.com [132.158.200.223]) by pbmsgap01.intersil.com with ESMTP id 3b0r038t56-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Mon, 13 Sep 2021 16:12:52 -0400 Received: from pbmxdp02.intersil.corp (132.158.200.223) by pbmxdp02.intersil.corp (132.158.200.223) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.2242.4; Mon, 13 Sep 2021 16:12:50 -0400 Received: from localhost (132.158.202.109) by pbmxdp02.intersil.corp (132.158.200.223) with Microsoft SMTP Server id 15.1.2242.4 via Frontend Transport; Mon, 13 Sep 2021 16:12:50 -0400 From: To: CC: , , Min Li Subject: [PATCH net 3/3] ptp: ptp_clockmatrix: Add support for pll_mode=0 and manual ref switch of WF and WP Date: Mon, 13 Sep 2021 16:12:34 -0400 Message-ID: <1631563954-6700-3-git-send-email-min.li.xe@renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1631563954-6700-1-git-send-email-min.li.xe@renesas.com> References: <1631563954-6700-1-git-send-email-min.li.xe@renesas.com> X-TM-AS-MML: disable MIME-Version: 1.0 X-Proofpoint-ORIG-GUID: kydTk9lugv6oQV-M2awbOv81H4-eTj92 X-Proofpoint-GUID: kydTk9lugv6oQV-M2awbOv81H4-eTj92 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.391, 18.0.790 definitions=2021-09-13_09:2021-09-09,2021-09-13 signatures=0 X-Proofpoint-Spam-Details: rule=junk_notspam policy=junk score=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 mlxscore=0 adultscore=0 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109030001 definitions=main-2109130120 X-Proofpoint-Spam-Reason: mlx Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Min Li Also correct how initialize_dco_operating_mode is called Signed-off-by: Min Li --- drivers/ptp/idt8a340_reg.h | 4 + drivers/ptp/ptp_clockmatrix.c | 372 +++++++++++++++++++++++++++++++++++++----- drivers/ptp/ptp_clockmatrix.h | 47 +++++- 3 files changed, 376 insertions(+), 47 deletions(-) diff --git a/drivers/ptp/idt8a340_reg.h b/drivers/ptp/idt8a340_reg.h index dea8e1d..1c52101 100644 --- a/drivers/ptp/idt8a340_reg.h +++ b/drivers/ptp/idt8a340_reg.h @@ -635,6 +635,10 @@ #define STATE_MODE_SHIFT (0) #define STATE_MODE_MASK (0x7) +/* Bit definitions for the DPLL_MANU_REF_CFG register */ +#define MANUAL_REFERENCE_SHIFT (0) +#define MANUAL_REFERENCE_MASK (0x1f) + /* Bit definitions for the GPIO_CFG_GBL register */ #define SUPPLY_MODE_SHIFT (0) #define SUPPLY_MODE_MASK (0x3) diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index 2c552a0..1a2e3c2 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -33,6 +33,8 @@ module_param(firmware, charp, 0); #define SETTIME_CORRECTION (0) +static int _idtcm_adjfine(struct idtcm_channel *channel, long scaled_ppm); + static int contains_full_configuration(struct idtcm *idtcm, const struct firmware *fw) { @@ -657,8 +659,8 @@ static int idtcm_sync_pps_output(struct idtcm_channel *channel) } static int _idtcm_set_dpll_hw_tod(struct idtcm_channel *channel, - struct timespec64 const *ts, - enum hw_tod_write_trig_sel wr_trig) + struct timespec64 const *ts, + enum hw_tod_write_trig_sel wr_trig) { struct idtcm *idtcm = channel->idtcm; u8 buf[TOD_BYTE_COUNT]; @@ -920,9 +922,9 @@ static int idtcm_start_phase_pull_in(struct idtcm_channel *channel) return err; } -static int idtcm_do_phase_pull_in(struct idtcm_channel *channel, - s32 offset_ns, - u32 max_ffo_ppb) +static int do_phase_pull_in_fw(struct idtcm_channel *channel, + s32 offset_ns, + u32 max_ffo_ppb) { int err; @@ -991,7 +993,7 @@ static int _idtcm_adjtime_deprecated(struct idtcm_channel *channel, s64 delta) s64 now; if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS_DEPRECATED) { - err = idtcm_do_phase_pull_in(channel, delta, 0); + err = channel->do_phase_pull_in(channel, delta, 0); } else { idtcm->calculate_overhead_flag = 1; @@ -1220,7 +1222,7 @@ static int idtcm_load_firmware(struct idtcm *idtcm, if (firmware) /* module parameter */ snprintf(fname, sizeof(fname), "%s", firmware); - dev_dbg(&idtcm->client->dev, "requesting firmware '%s'", fname); + dev_info(&idtcm->client->dev, "firmware '%s'", fname); err = request_firmware(&fw, fname, dev); if (err) { @@ -1354,7 +1356,7 @@ static int idtcm_perout_enable(struct idtcm_channel *channel, } static int idtcm_get_pll_mode(struct idtcm_channel *channel, - enum pll_mode *pll_mode) + enum pll_mode *mode) { struct idtcm *idtcm = channel->idtcm; int err; @@ -1366,13 +1368,13 @@ static int idtcm_get_pll_mode(struct idtcm_channel *channel, if (err) return err; - *pll_mode = (dpll_mode >> PLL_MODE_SHIFT) & PLL_MODE_MASK; + *mode = (dpll_mode >> PLL_MODE_SHIFT) & PLL_MODE_MASK; return 0; } static int idtcm_set_pll_mode(struct idtcm_channel *channel, - enum pll_mode pll_mode) + enum pll_mode mode) { struct idtcm *idtcm = channel->idtcm; int err; @@ -1386,23 +1388,298 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel, dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT); - dpll_mode |= (pll_mode << PLL_MODE_SHIFT); - - channel->pll_mode = pll_mode; + dpll_mode |= (mode << PLL_MODE_SHIFT); err = idtcm_write(idtcm, channel->dpll_n, IDTCM_FW_REG(idtcm->fw_ver, V520, DPLL_MODE), &dpll_mode, sizeof(dpll_mode)); + return err; +} + +static int idtcm_get_manual_reference(struct idtcm_channel *channel, + enum manual_reference *ref) +{ + struct idtcm *idtcm = channel->idtcm; + u8 dpll_manu_ref_cfg; + int err; + + err = idtcm_read(idtcm, channel->dpll_ctrl_n, + DPLL_CTRL_DPLL_MANU_REF_CFG, + &dpll_manu_ref_cfg, sizeof(dpll_manu_ref_cfg)); + if (err) + return err; + + dpll_manu_ref_cfg &= (MANUAL_REFERENCE_MASK << MANUAL_REFERENCE_SHIFT); + + *ref = dpll_manu_ref_cfg >> MANUAL_REFERENCE_SHIFT; + + return 0; +} + +static int idtcm_set_manual_reference(struct idtcm_channel *channel, + enum manual_reference ref) +{ + struct idtcm *idtcm = channel->idtcm; + u8 dpll_manu_ref_cfg; + int err; + + err = idtcm_read(idtcm, channel->dpll_ctrl_n, + DPLL_CTRL_DPLL_MANU_REF_CFG, + &dpll_manu_ref_cfg, sizeof(dpll_manu_ref_cfg)); + if (err) + return err; + + dpll_manu_ref_cfg &= ~(MANUAL_REFERENCE_MASK << MANUAL_REFERENCE_SHIFT); + + dpll_manu_ref_cfg |= (ref << MANUAL_REFERENCE_SHIFT); + + err = idtcm_write(idtcm, channel->dpll_ctrl_n, + DPLL_CTRL_DPLL_MANU_REF_CFG, + &dpll_manu_ref_cfg, sizeof(dpll_manu_ref_cfg)); + + return err; +} + +static int configure_dpll_mode_write_frequency(struct idtcm_channel *channel) +{ + struct idtcm *idtcm = channel->idtcm; + int err; + + err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY); + + if (err) + dev_err(&idtcm->client->dev, "Failed to set pll mode to write frequency"); + else + channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY; + + return err; +} + +static int configure_dpll_mode_write_phase(struct idtcm_channel *channel) +{ + struct idtcm *idtcm = channel->idtcm; + int err; + + err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE); + + if (err) + dev_err(&idtcm->client->dev, "Failed to set pll mode to write phase"); + else + channel->mode = PTP_PLL_MODE_WRITE_PHASE; + + return err; +} + +static int configure_manual_reference_write_frequency(struct idtcm_channel *channel) +{ + struct idtcm *idtcm = channel->idtcm; + int err; + + err = idtcm_set_manual_reference(channel, MANU_REF_WRITE_FREQUENCY); + + if (err) + dev_err(&idtcm->client->dev, "Failed to set manual reference to write frequency"); + else + channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY; + + return err; +} + +static int configure_manual_reference_write_phase(struct idtcm_channel *channel) +{ + struct idtcm *idtcm = channel->idtcm; + int err; + + err = idtcm_set_manual_reference(channel, MANU_REF_WRITE_PHASE); + + if (err) + dev_err(&idtcm->client->dev, "Failed to set manual reference to write phase"); + else + channel->mode = PTP_PLL_MODE_WRITE_PHASE; + + return err; +} + +static int idtcm_stop_phase_pull_in(struct idtcm_channel *channel) +{ + int err; + + err = _idtcm_adjfine(channel, channel->current_freq_scaled_ppm); if (err) return err; + channel->phase_pull_in = false; + return 0; } +static long idtcm_work_handler(struct ptp_clock_info *ptp) +{ + struct idtcm_channel *channel = container_of(ptp, struct idtcm_channel, caps); + struct idtcm *idtcm = channel->idtcm; + + mutex_lock(&idtcm->reg_lock); + + (void)idtcm_stop_phase_pull_in(channel); + + mutex_unlock(&idtcm->reg_lock); + + /* Return a negative value here to not reschedule */ + return -1; +} + +static s32 phase_pull_in_scaled_ppm(s32 current_ppm, s32 phase_pull_in_ppb) +{ + /* ppb = scaled_ppm * 125 / 2^13 */ + /* scaled_ppm = ppb * 2^13 / 125 */ + + s64 max_scaled_ppm = (PHASE_PULL_IN_MAX_PPB << 13) / 125; + s64 scaled_ppm = (phase_pull_in_ppb << 13) / 125; + + current_ppm += scaled_ppm; + + if (current_ppm > max_scaled_ppm) + current_ppm = max_scaled_ppm; + else if (current_ppm < -max_scaled_ppm) + current_ppm = -max_scaled_ppm; + + return current_ppm; +} + +static int do_phase_pull_in_sw(struct idtcm_channel *channel, + s32 delta_ns, + u32 max_ffo_ppb) +{ + s32 current_ppm = channel->current_freq_scaled_ppm; + u32 duration_ms = MSEC_PER_SEC; + s32 delta_ppm; + s32 ppb; + int err; + + /* If the ToD correction is less than PHASE_PULL_IN_MIN_THRESHOLD_NS, + * skip. The error introduced by the ToD adjustment procedure would + * be bigger than the required ToD correction + */ + if (abs(delta_ns) < PHASE_PULL_IN_MIN_THRESHOLD_NS) + return 0; + + if (max_ffo_ppb == 0) + max_ffo_ppb = PHASE_PULL_IN_MAX_PPB; + + /* For most cases, keep phase pull-in duration 1 second */ + ppb = delta_ns; + while (abs(ppb) > max_ffo_ppb) { + duration_ms *= 2; + ppb /= 2; + } + + delta_ppm = phase_pull_in_scaled_ppm(current_ppm, ppb); + + err = _idtcm_adjfine(channel, delta_ppm); + + if (err) + return err; + + /* schedule the worker to cancel phase pull-in */ + ptp_schedule_worker(channel->ptp_clock, + msecs_to_jiffies(duration_ms) - 1); + + channel->phase_pull_in = true; + + return 0; +} + +static int initialize_operating_mode_with_manual_reference(struct idtcm_channel *channel, + enum manual_reference ref) +{ + struct idtcm *idtcm = channel->idtcm; + + channel->mode = PTP_PLL_MODE_UNSUPPORTED; + channel->configure_write_frequency = configure_manual_reference_write_frequency; + channel->configure_write_phase = configure_manual_reference_write_phase; + channel->do_phase_pull_in = do_phase_pull_in_sw; + + switch (ref) { + case MANU_REF_WRITE_PHASE: + channel->mode = PTP_PLL_MODE_WRITE_PHASE; + break; + case MANU_REF_WRITE_FREQUENCY: + channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY; + break; + default: + dev_warn(&idtcm->client->dev, + "Unsupported MANUAL_REFERENCE: 0x%02x", ref); + } + + return 0; +} + +static int initialize_operating_mode_with_pll_mode(struct idtcm_channel *channel, + enum pll_mode mode) +{ + struct idtcm *idtcm = channel->idtcm; + int err = 0; + + channel->mode = PTP_PLL_MODE_UNSUPPORTED; + channel->configure_write_frequency = configure_dpll_mode_write_frequency; + channel->configure_write_phase = configure_dpll_mode_write_phase; + channel->do_phase_pull_in = do_phase_pull_in_fw; + + switch (mode) { + case PLL_MODE_WRITE_PHASE: + channel->mode = PTP_PLL_MODE_WRITE_PHASE; + break; + case PLL_MODE_WRITE_FREQUENCY: + channel->mode = PTP_PLL_MODE_WRITE_FREQUENCY; + break; + default: + dev_err(&idtcm->client->dev, + "Unsupported PLL_MODE: 0x%02x", mode); + err = -EINVAL; + } + + return err; +} + +static int initialize_dco_operating_mode(struct idtcm_channel *channel) +{ + enum manual_reference ref = MANU_REF_XO_DPLL; + enum pll_mode mode = PLL_MODE_DISABLED; + struct idtcm *idtcm = channel->idtcm; + int err; + + channel->mode = PTP_PLL_MODE_UNSUPPORTED; + + err = idtcm_get_pll_mode(channel, &mode); + if (err) { + dev_err(&idtcm->client->dev, "Unable to read pll mode!"); + return err; + } + + if (mode == PLL_MODE_PLL) { + err = idtcm_get_manual_reference(channel, &ref); + if (err) { + dev_err(&idtcm->client->dev, "Unable to read manual reference!"); + return err; + } + err = initialize_operating_mode_with_manual_reference(channel, ref); + } else { + err = initialize_operating_mode_with_pll_mode(channel, mode); + } + + if (channel->mode == PTP_PLL_MODE_WRITE_PHASE) + channel->configure_write_frequency(channel); + + return err; +} + /* PTP Hardware Clock interface */ /** - * @brief Maximum absolute value for write phase offset in picoseconds + * Maximum absolute value for write phase offset in picoseconds + * + * @channel: channel + * @delta_ns: delta in nanoseconds * * Destination signed register is 32-bit register in resolution of 50ps * @@ -1417,8 +1694,8 @@ static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns) s32 phase_50ps; s64 offset_ps; - if (channel->pll_mode != PLL_MODE_WRITE_PHASE) { - err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE); + if (channel->mode != PTP_PLL_MODE_WRITE_PHASE) { + err = channel->configure_write_phase(channel); if (err) return err; } @@ -1456,8 +1733,8 @@ static int _idtcm_adjfine(struct idtcm_channel *channel, long scaled_ppm) u8 buf[6] = {0}; s64 fcw; - if (channel->pll_mode != PLL_MODE_WRITE_FREQUENCY) { - err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY); + if (channel->mode != PTP_PLL_MODE_WRITE_FREQUENCY) { + err = channel->configure_write_frequency(channel); if (err) return err; } @@ -1574,29 +1851,29 @@ static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta) enum scsr_tod_write_type_sel type; int err; + if (channel->phase_pull_in == true) + return 0; + + mutex_lock(&idtcm->reg_lock); + if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS) { - err = idtcm_do_phase_pull_in(channel, delta, 0); + err = channel->do_phase_pull_in(channel, delta, 0); if (err) dev_err(&idtcm->client->dev, "Failed at line %d in %s!", __LINE__, __func__); - return err; - } - - if (delta >= 0) { - ts = ns_to_timespec64(delta); - type = SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS; } else { - ts = ns_to_timespec64(-delta); - type = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS; + if (delta >= 0) { + ts = ns_to_timespec64(delta); + type = SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS; + } else { + ts = ns_to_timespec64(-delta); + type = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS; + } + err = _idtcm_settime(channel, &ts, type); + if (err) + dev_err(&idtcm->client->dev, + "Failed at line %d in %s!", __LINE__, __func__); } - - mutex_lock(&idtcm->reg_lock); - - err = _idtcm_settime(channel, &ts, type); - if (err) - dev_err(&idtcm->client->dev, - "Failed at line %d in %s!", __LINE__, __func__); - mutex_unlock(&idtcm->reg_lock); return err; @@ -1626,15 +1903,21 @@ static int idtcm_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) struct idtcm *idtcm = channel->idtcm; int err; + if (channel->phase_pull_in == true) + return 0; + + if (scaled_ppm == channel->current_freq_scaled_ppm) + return 0; + mutex_lock(&idtcm->reg_lock); err = _idtcm_adjfine(channel, scaled_ppm); - if (err) - dev_err(&idtcm->client->dev, - "Failed at line %d in %s!", __LINE__, __func__); mutex_unlock(&idtcm->reg_lock); + if (!err) + channel->current_freq_scaled_ppm = scaled_ppm; + return err; } @@ -1746,6 +2029,7 @@ static const struct ptp_clock_info idtcm_caps = { .gettime64 = &idtcm_gettime, .settime64 = &idtcm_settime, .enable = &idtcm_enable, + .do_aux_work = &idtcm_work_handler, }; static const struct ptp_clock_info idtcm_caps_deprecated = { @@ -1758,6 +2042,7 @@ static const struct ptp_clock_info idtcm_caps_deprecated = { .gettime64 = &idtcm_gettime, .settime64 = &idtcm_settime_deprecated, .enable = &idtcm_enable, + .do_aux_work = &idtcm_work_handler, }; static int configure_channel_pll(struct idtcm_channel *channel) @@ -1847,7 +2132,9 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) return -EINVAL; channel = &idtcm->channel[index]; + channel->idtcm = idtcm; + channel->current_freq_scaled_ppm = 0; /* Set pll addresses */ err = configure_channel_pll(channel); @@ -1892,13 +2179,9 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) snprintf(channel->caps.name, sizeof(channel->caps.name), "IDT CM TOD%u", index); - /* Sync pll mode with hardware */ - err = idtcm_get_pll_mode(channel, &channel->pll_mode); - if (err) { - dev_err(&idtcm->client->dev, - "Error: %s - Unable to read pll mode", __func__); + err = initialize_dco_operating_mode(channel); + if (err) return err; - } err = idtcm_enable_tod(channel); if (err) { @@ -1931,7 +2214,6 @@ static void ptp_clock_unregister_all(struct idtcm *idtcm) for (i = 0; i < MAX_TOD; i++) { channel = &idtcm->channel[i]; - if (channel->ptp_clock) ptp_clock_unregister(channel->ptp_clock); } diff --git a/drivers/ptp/ptp_clockmatrix.h b/drivers/ptp/ptp_clockmatrix.h index 843a9d7..833e590 100644 --- a/drivers/ptp/ptp_clockmatrix.h +++ b/drivers/ptp/ptp_clockmatrix.h @@ -57,15 +57,27 @@ #define IDTCM_MAX_WRITE_COUNT (512) +#define PHASE_PULL_IN_MAX_PPB (144000) +#define PHASE_PULL_IN_MIN_THRESHOLD_NS (2) + /* * Return register address based on passed in firmware version */ #define IDTCM_FW_REG(FW, VER, REG) (((FW) < (VER)) ? (REG) : (REG##_##VER)) +/* PTP PLL Mode */ +enum ptp_pll_mode { + PTP_PLL_MODE_MIN = 0, + PTP_PLL_MODE_WRITE_FREQUENCY = PTP_PLL_MODE_MIN, + PTP_PLL_MODE_WRITE_PHASE, + PTP_PLL_MODE_UNSUPPORTED, + PTP_PLL_MODE_MAX = PTP_PLL_MODE_UNSUPPORTED, +}; + /* Values of DPLL_N.DPLL_MODE.PLL_MODE */ enum pll_mode { PLL_MODE_MIN = 0, - PLL_MODE_NORMAL = PLL_MODE_MIN, + PLL_MODE_PLL = PLL_MODE_MIN, PLL_MODE_WRITE_PHASE = 1, PLL_MODE_WRITE_FREQUENCY = 2, PLL_MODE_GPIO_INC_DEC = 3, @@ -75,6 +87,31 @@ enum pll_mode { PLL_MODE_MAX = PLL_MODE_DISABLED, }; +/* Values of DPLL_CTRL_n.DPLL_MANU_REF_CFG.MANUAL_REFERENCE */ +enum manual_reference { + MANU_REF_MIN = 0, + MANU_REF_CLK0 = MANU_REF_MIN, + MANU_REF_CLK1, + MANU_REF_CLK2, + MANU_REF_CLK3, + MANU_REF_CLK4, + MANU_REF_CLK5, + MANU_REF_CLK6, + MANU_REF_CLK7, + MANU_REF_CLK8, + MANU_REF_CLK9, + MANU_REF_CLK10, + MANU_REF_CLK11, + MANU_REF_CLK12, + MANU_REF_CLK13, + MANU_REF_CLK14, + MANU_REF_CLK15, + MANU_REF_WRITE_PHASE, + MANU_REF_WRITE_FREQUENCY, + MANU_REF_XO_DPLL, + MANU_REF_MAX = MANU_REF_XO_DPLL, +}; + enum hw_tod_write_trig_sel { HW_TOD_WR_TRIG_SEL_MIN = 0, HW_TOD_WR_TRIG_SEL_MSB = HW_TOD_WR_TRIG_SEL_MIN, @@ -141,7 +178,13 @@ struct idtcm_channel { u16 tod_n; u16 hw_dpll_n; u8 sync_src; - enum pll_mode pll_mode; + enum ptp_pll_mode mode; + int (*configure_write_frequency)(struct idtcm_channel *channel); + int (*configure_write_phase)(struct idtcm_channel *channel); + int (*do_phase_pull_in)(struct idtcm_channel *channel, + s32 offset_ns, u32 max_ffo_ppb); + s32 current_freq_scaled_ppm; + bool phase_pull_in; u8 pll; u16 output_mask; };