Commit e2dbda0f authored by David S. Miller's avatar David S. Miller

Merge branch 'am65-cpsw-suspend-resume'

Roger Quadros says:

====================
net: ethernet: ti: am65-cpsw: Add suspend/resume support

This series enables PM_SLEEP(suspend/resume) support to
the am65-cpsw network driver.

Dual-emac and Switch mode are tested to work with suspend/resume
on AM62-SK platform.

It can be verified on the following branch
https://github.com/rogerq/linux/commits/for-v6.2/am62-cpsw-lpm-1.0
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4e0243e7 1af3cb37
This diff is collapsed.
...@@ -55,12 +55,16 @@ struct am65_cpsw_port { ...@@ -55,12 +55,16 @@ struct am65_cpsw_port {
bool rx_ts_enabled; bool rx_ts_enabled;
struct am65_cpsw_qos qos; struct am65_cpsw_qos qos;
struct devlink_port devlink_port; struct devlink_port devlink_port;
/* Only for suspend resume context */
u32 vid_context;
}; };
struct am65_cpsw_host { struct am65_cpsw_host {
struct am65_cpsw_common *common; struct am65_cpsw_common *common;
void __iomem *port_base; void __iomem *port_base;
void __iomem *stat_base; void __iomem *stat_base;
/* Only for suspend resume context */
u32 vid_context;
}; };
struct am65_cpsw_tx_chn { struct am65_cpsw_tx_chn {
...@@ -145,6 +149,8 @@ struct am65_cpsw_common { ...@@ -145,6 +149,8 @@ struct am65_cpsw_common {
struct net_device *hw_bridge_dev; struct net_device *hw_bridge_dev;
struct notifier_block am65_cpsw_netdevice_nb; struct notifier_block am65_cpsw_netdevice_nb;
unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
/* only for suspend/resume context restore */
u32 *ale_context;
}; };
struct am65_cpsw_ndev_stats { struct am65_cpsw_ndev_stats {
......
...@@ -176,6 +176,16 @@ struct am65_cpts { ...@@ -176,6 +176,16 @@ struct am65_cpts {
u32 genf_enable; u32 genf_enable;
u32 hw_ts_enable; u32 hw_ts_enable;
struct sk_buff_head txq; 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 { struct am65_cpts_skb_cb_data {
...@@ -1029,6 +1039,72 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs, ...@@ -1029,6 +1039,72 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
} }
EXPORT_SYMBOL_GPL(am65_cpts_create); 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) static int am65_cpts_probe(struct platform_device *pdev)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
......
...@@ -28,6 +28,8 @@ u64 am65_cpts_ns_gettime(struct am65_cpts *cpts); ...@@ -28,6 +28,8 @@ u64 am65_cpts_ns_gettime(struct am65_cpts *cpts);
int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx, int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
struct am65_cpts_estf_cfg *cfg); struct am65_cpts_estf_cfg *cfg);
void am65_cpts_estf_disable(struct am65_cpts *cpts, int idx); 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 #else
static inline struct am65_cpts *am65_cpts_create(struct device *dev, static inline struct am65_cpts *am65_cpts_create(struct device *dev,
void __iomem *regs, void __iomem *regs,
...@@ -69,6 +71,14 @@ static inline int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx, ...@@ -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_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
#endif /* K3_CPTS_H_ */ #endif /* K3_CPTS_H_ */
...@@ -1452,6 +1452,16 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) ...@@ -1452,6 +1452,16 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
} }
} }
void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data)
{
int i;
for (i = 0; i < ale->params.ale_entries; i++) {
cpsw_ale_write(ale, i, data);
data += ALE_ENTRY_WORDS;
}
}
u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale) u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale)
{ {
return ale ? ale->params.ale_entries : 0; return ale ? ale->params.ale_entries : 0;
......
...@@ -127,6 +127,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); ...@@ -127,6 +127,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
int control, int value); int control, int value);
void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data); void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data);
void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data);
u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale); u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale);
static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid) static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment