net: ti: icss-iep: Add pwidth configuration for perout signal
authorMeghana Malladi <m-malladi@ti.com>
Tue, 4 Mar 2025 10:57:52 +0000 (16:27 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Apr 2025 08:45:44 +0000 (10:45 +0200)
[ Upstream commit e5b456a14215e3c0e84844c2926861b972e03632 ]

icss_iep_perout_enable_hw() is a common function for generating
both pps and perout signals. When enabling pps, the application needs
to only pass enable/disable argument, whereas for perout it supports
different flags to configure the signal.

But icss_iep_perout_enable_hw() function is missing to hook the
configuration params passed by the app, causing perout to behave
same a pps (except being able to configure the period). As duty cycle
is also one feature which can configured for perout, incorporate this
in the function to get the expected signal.

Signed-off-by: Meghana Malladi <m-malladi@ti.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Link: https://patch.msgid.link/20250304105753.1552159-2-m-malladi@ti.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 7349c9e99793 ("net: ti: icss-iep: Fix possible NULL pointer dereference for perout request")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/ti/icssg/icss_iep.c

index 3f9a030471fe2f7ca3ebfa3c24d6289a05f25214..923ac58c9de5b16ef63448e3903303da1447b26a 100644 (file)
@@ -476,9 +476,16 @@ static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns)
 static int icss_iep_perout_enable_hw(struct icss_iep *iep,
                                     struct ptp_perout_request *req, int on)
 {
+       struct timespec64 ts;
+       u64 ns_width;
        int ret;
        u64 cmp;
 
+       /* Calculate width of the signal for PPS/PEROUT handling */
+       ts.tv_sec = req->on.sec;
+       ts.tv_nsec = req->on.nsec;
+       ns_width = timespec64_to_ns(&ts);
+
        if (iep->ops && iep->ops->perout_enable) {
                ret = iep->ops->perout_enable(iep->clockops_data, req, on, &cmp);
                if (ret)
@@ -489,8 +496,9 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
                        regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
                        if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
                                regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
-                       /* Configure SYNC, 1ms pulse width */
-                       regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, 1000000);
+                       /* Configure SYNC, based on req on width */
+                       regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
+                                    div_u64(ns_width, iep->def_inc));
                        regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
                        regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, 0);
                        regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
@@ -517,6 +525,8 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
                                   + req->period.nsec;
                        icss_iep_update_to_next_boundary(iep, start_ns);
 
+                       regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
+                                    div_u64(ns_width, iep->def_inc));
                        /* Enable Sync in single shot mode  */
                        regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
                                     IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
@@ -544,7 +554,36 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
 static int icss_iep_perout_enable(struct icss_iep *iep,
                                  struct ptp_perout_request *req, int on)
 {
-       return -EOPNOTSUPP;
+       int ret = 0;
+
+       /* Reject requests with unsupported flags */
+       if (req->flags & ~PTP_PEROUT_DUTY_CYCLE)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&iep->ptp_clk_mutex);
+
+       if (iep->pps_enabled) {
+               ret = -EBUSY;
+               goto exit;
+       }
+
+       if (iep->perout_enabled == !!on)
+               goto exit;
+
+       /* Set default "on" time (1ms) for the signal if not passed by the app */
+       if (!(req->flags & PTP_PEROUT_DUTY_CYCLE)) {
+               req->on.sec = 0;
+               req->on.nsec = NSEC_PER_MSEC;
+       }
+
+       ret = icss_iep_perout_enable_hw(iep, req, on);
+       if (!ret)
+               iep->perout_enabled = !!on;
+
+exit:
+       mutex_unlock(&iep->ptp_clk_mutex);
+
+       return ret;
 }
 
 static int icss_iep_pps_enable(struct icss_iep *iep, int on)
@@ -572,6 +611,8 @@ static int icss_iep_pps_enable(struct icss_iep *iep, int on)
                rq.perout.period.nsec = 0;
                rq.perout.start.sec = ts.tv_sec + 2;
                rq.perout.start.nsec = 0;
+               rq.perout.on.sec = 0;
+               rq.perout.on.nsec = NSEC_PER_MSEC;
                ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);
        } else {
                ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);