net: ethernet: ti: am65-cpsw/cpts: Add suspend/resume helpers
authorRoger Quadros <rogerq@kernel.org>
Fri, 4 Nov 2022 13:23:06 +0000 (15:23 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 7 Nov 2022 12:20:03 +0000 (12:20 +0000)
CPTS looses context on suspend (e.g. on AM62).
Provide suspend/resume hooks in CPTS driver. These will be
invoked by CPSW driver if CPTS was instantiated by CPSW.

Signed-off-by: Roger Quadros <rogerq@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/am65-cpts.c
drivers/net/ethernet/ti/am65-cpts.h

index e2f0fb286143b3d8b6cd731ece27695f3a48d92b..7f928c34342601258d7fa5c5d1d0994ef67b1373 100644 (file)
@@ -176,6 +176,16 @@ struct am65_cpts {
        u32 genf_enable;
        u32 hw_ts_enable;
        struct sk_buff_head txq;
+       /* context save/restore */
+       u64 sr_cpts_ns;
+       u64 sr_ktime_ns;
+       u32 sr_control;
+       u32 sr_int_enable;
+       u32 sr_rftclk_sel;
+       u32 sr_ts_ppm_hi;
+       u32 sr_ts_ppm_low;
+       struct am65_genf_regs sr_genf[AM65_CPTS_GENF_MAX_NUM];
+       struct am65_genf_regs sr_estf[AM65_CPTS_ESTF_MAX_NUM];
 };
 
 struct am65_cpts_skb_cb_data {
@@ -1029,6 +1039,72 @@ refclk_disable:
 }
 EXPORT_SYMBOL_GPL(am65_cpts_create);
 
+void am65_cpts_suspend(struct am65_cpts *cpts)
+{
+       /* save state and disable CPTS */
+       cpts->sr_control = am65_cpts_read32(cpts, control);
+       cpts->sr_int_enable = am65_cpts_read32(cpts, int_enable);
+       cpts->sr_rftclk_sel = am65_cpts_read32(cpts, rftclk_sel);
+       cpts->sr_ts_ppm_hi = am65_cpts_read32(cpts, ts_ppm_hi);
+       cpts->sr_ts_ppm_low = am65_cpts_read32(cpts, ts_ppm_low);
+       cpts->sr_cpts_ns = am65_cpts_gettime(cpts, NULL);
+       cpts->sr_ktime_ns = ktime_to_ns(ktime_get_real());
+       am65_cpts_disable(cpts);
+       clk_disable(cpts->refclk);
+
+       /* Save GENF state */
+       memcpy_fromio(&cpts->sr_genf, &cpts->reg->genf, sizeof(cpts->sr_genf));
+
+       /* Save ESTF state */
+       memcpy_fromio(&cpts->sr_estf, &cpts->reg->estf, sizeof(cpts->sr_estf));
+}
+EXPORT_SYMBOL_GPL(am65_cpts_suspend);
+
+void am65_cpts_resume(struct am65_cpts *cpts)
+{
+       int i;
+       s64 ktime_ns;
+
+       /* restore state and enable CPTS */
+       clk_enable(cpts->refclk);
+       am65_cpts_write32(cpts, cpts->sr_rftclk_sel, rftclk_sel);
+       am65_cpts_set_add_val(cpts);
+       am65_cpts_write32(cpts, cpts->sr_control, control);
+       am65_cpts_write32(cpts, cpts->sr_int_enable, int_enable);
+
+       /* Restore time to saved CPTS time + time in suspend/resume */
+       ktime_ns = ktime_to_ns(ktime_get_real());
+       ktime_ns -= cpts->sr_ktime_ns;
+       am65_cpts_settime(cpts, cpts->sr_cpts_ns + ktime_ns);
+
+       /* Restore compensation (PPM) */
+       am65_cpts_write32(cpts, cpts->sr_ts_ppm_hi, ts_ppm_hi);
+       am65_cpts_write32(cpts, cpts->sr_ts_ppm_low, ts_ppm_low);
+
+       /* Restore GENF state */
+       for (i = 0; i < AM65_CPTS_GENF_MAX_NUM; i++) {
+               am65_cpts_write32(cpts, 0, genf[i].length);     /* TRM sequence */
+               am65_cpts_write32(cpts, cpts->sr_genf[i].comp_hi, genf[i].comp_hi);
+               am65_cpts_write32(cpts, cpts->sr_genf[i].comp_lo, genf[i].comp_lo);
+               am65_cpts_write32(cpts, cpts->sr_genf[i].length, genf[i].length);
+               am65_cpts_write32(cpts, cpts->sr_genf[i].control, genf[i].control);
+               am65_cpts_write32(cpts, cpts->sr_genf[i].ppm_hi, genf[i].ppm_hi);
+               am65_cpts_write32(cpts, cpts->sr_genf[i].ppm_low, genf[i].ppm_low);
+       }
+
+       /* Restore ESTTF state */
+       for (i = 0; i < AM65_CPTS_ESTF_MAX_NUM; i++) {
+               am65_cpts_write32(cpts, 0, estf[i].length);     /* TRM sequence */
+               am65_cpts_write32(cpts, cpts->sr_estf[i].comp_hi, estf[i].comp_hi);
+               am65_cpts_write32(cpts, cpts->sr_estf[i].comp_lo, estf[i].comp_lo);
+               am65_cpts_write32(cpts, cpts->sr_estf[i].length, estf[i].length);
+               am65_cpts_write32(cpts, cpts->sr_estf[i].control, estf[i].control);
+               am65_cpts_write32(cpts, cpts->sr_estf[i].ppm_hi, estf[i].ppm_hi);
+               am65_cpts_write32(cpts, cpts->sr_estf[i].ppm_low, estf[i].ppm_low);
+       }
+}
+EXPORT_SYMBOL_GPL(am65_cpts_resume);
+
 static int am65_cpts_probe(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
index cf9fbc28fd032c795b80e0dba2c89d04d81cbddb..bd08f4b2edd2d69ad8b905a62e0b86f39a53261b 100644 (file)
@@ -28,6 +28,8 @@ u64 am65_cpts_ns_gettime(struct am65_cpts *cpts);
 int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
                          struct am65_cpts_estf_cfg *cfg);
 void am65_cpts_estf_disable(struct am65_cpts *cpts, int idx);
+void am65_cpts_suspend(struct am65_cpts *cpts);
+void am65_cpts_resume(struct am65_cpts *cpts);
 #else
 static inline struct am65_cpts *am65_cpts_create(struct device *dev,
                                                 void __iomem *regs,
@@ -69,6 +71,14 @@ static inline int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
 static inline void am65_cpts_estf_disable(struct am65_cpts *cpts, int idx)
 {
 }
+
+static inline void am65_cpts_suspend(struct am65_cpts *cpts)
+{
+}
+
+static inline void am65_cpts_resume(struct am65_cpts *cpts)
+{
+}
 #endif
 
 #endif /* K3_CPTS_H_ */