提交 14260e91 编写于 作者: D David S. Miller

Merge branch 'PTP-support-for-mv88e6165-family'

Andrew Lunn says:

====================
PTP support for mv88e6165 family

The mv88e6165 family of switches supports PTP. It is however not fully
compatible with the current PTP support in the mv88e6xxx driver. This
patchset adds a level of abstraction to the PTP code, and then adds
the code needed to support the mv88e6165 family.

v2: Correctly cluster local variables in mv88e6xxx_ptp_setup()
    Added Acked-by: Richard Cochran <richardcochran@gmail.com>
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -2810,6 +2810,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { ...@@ -2810,6 +2810,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.reset = mv88e6352_g1_reset, .reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6165_avb_ops,
.ptp_ops = &mv88e6165_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6165_ops = { static const struct mv88e6xxx_ops mv88e6165_ops = {
...@@ -2838,6 +2840,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { ...@@ -2838,6 +2840,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.reset = mv88e6352_g1_reset, .reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6165_avb_ops,
.ptp_ops = &mv88e6165_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6171_ops = { static const struct mv88e6xxx_ops mv88e6171_ops = {
...@@ -3134,6 +3138,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { ...@@ -3134,6 +3138,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6240_ops = { static const struct mv88e6xxx_ops mv88e6240_ops = {
...@@ -3176,6 +3182,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { ...@@ -3176,6 +3182,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.serdes_power = mv88e6352_serdes_power, .serdes_power = mv88e6352_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops, .avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6290_ops = { static const struct mv88e6xxx_ops mv88e6290_ops = {
...@@ -3215,6 +3222,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { ...@@ -3215,6 +3222,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6320_ops = { static const struct mv88e6xxx_ops mv88e6320_ops = {
...@@ -3253,6 +3261,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { ...@@ -3253,6 +3261,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops, .avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6321_ops = { static const struct mv88e6xxx_ops mv88e6321_ops = {
...@@ -3289,6 +3298,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { ...@@ -3289,6 +3298,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops, .avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6341_ops = { static const struct mv88e6xxx_ops mv88e6341_ops = {
...@@ -3329,6 +3339,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { ...@@ -3329,6 +3339,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6350_ops = { static const struct mv88e6xxx_ops mv88e6350_ops = {
...@@ -3402,6 +3413,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { ...@@ -3402,6 +3413,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6352_avb_ops, .avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6352_ops = { static const struct mv88e6xxx_ops mv88e6352_ops = {
...@@ -3444,6 +3456,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { ...@@ -3444,6 +3456,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.serdes_power = mv88e6352_serdes_power, .serdes_power = mv88e6352_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops, .avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
.serdes_get_sset_count = mv88e6352_serdes_get_sset_count, .serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
.serdes_get_strings = mv88e6352_serdes_get_strings, .serdes_get_strings = mv88e6352_serdes_get_strings,
.serdes_get_stats = mv88e6352_serdes_get_stats, .serdes_get_stats = mv88e6352_serdes_get_stats,
...@@ -3488,6 +3501,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { ...@@ -3488,6 +3501,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_ops mv88e6390x_ops = { static const struct mv88e6xxx_ops mv88e6390x_ops = {
...@@ -3529,6 +3543,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { ...@@ -3529,6 +3543,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
}; };
static const struct mv88e6xxx_info mv88e6xxx_table[] = { static const struct mv88e6xxx_info mv88e6xxx_table[] = {
...@@ -3680,6 +3695,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -3680,6 +3695,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.pvt = true, .pvt = true,
.multi_chip = true, .multi_chip = true,
.tag_protocol = DSA_TAG_PROTO_EDSA, .tag_protocol = DSA_TAG_PROTO_EDSA,
.ptp_support = true,
.ops = &mv88e6161_ops, .ops = &mv88e6161_ops,
}, },
...@@ -3702,6 +3718,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -3702,6 +3718,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.pvt = true, .pvt = true,
.multi_chip = true, .multi_chip = true,
.tag_protocol = DSA_TAG_PROTO_DSA, .tag_protocol = DSA_TAG_PROTO_DSA,
.ptp_support = true,
.ops = &mv88e6165_ops, .ops = &mv88e6165_ops,
}, },
......
...@@ -155,6 +155,7 @@ struct mv88e6xxx_bus_ops; ...@@ -155,6 +155,7 @@ struct mv88e6xxx_bus_ops;
struct mv88e6xxx_irq_ops; struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops; struct mv88e6xxx_gpio_ops;
struct mv88e6xxx_avb_ops; struct mv88e6xxx_avb_ops;
struct mv88e6xxx_ptp_ops;
struct mv88e6xxx_irq { struct mv88e6xxx_irq {
u16 masked; u16 masked;
...@@ -273,6 +274,7 @@ struct mv88e6xxx_chip { ...@@ -273,6 +274,7 @@ struct mv88e6xxx_chip {
struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO]; struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO];
u16 trig_config; u16 trig_config;
u16 evcap_config; u16 evcap_config;
u16 enable_count;
/* Per-port timestamping resources. */ /* Per-port timestamping resources. */
struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS]; struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
...@@ -439,6 +441,9 @@ struct mv88e6xxx_ops { ...@@ -439,6 +441,9 @@ struct mv88e6xxx_ops {
/* Remote Management Unit operations */ /* Remote Management Unit operations */
int (*rmu_disable)(struct mv88e6xxx_chip *chip); int (*rmu_disable)(struct mv88e6xxx_chip *chip);
/* Precision Time Protocol operations */
const struct mv88e6xxx_ptp_ops *ptp_ops;
}; };
struct mv88e6xxx_irq_ops { struct mv88e6xxx_irq_ops {
...@@ -486,6 +491,24 @@ struct mv88e6xxx_avb_ops { ...@@ -486,6 +491,24 @@ struct mv88e6xxx_avb_ops {
int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data); int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
}; };
struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(const struct cyclecounter *cc);
int (*ptp_enable)(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
int (*ptp_verify)(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
void (*event_work)(struct work_struct *ugly);
int (*port_enable)(struct mv88e6xxx_chip *chip, int port);
int (*port_disable)(struct mv88e6xxx_chip *chip, int port);
int (*global_enable)(struct mv88e6xxx_chip *chip);
int (*global_disable)(struct mv88e6xxx_chip *chip);
int n_ext_ts;
int arr0_sts_reg;
int arr1_sts_reg;
int dep_sts_reg;
u32 rx_filters;
};
#define STATS_TYPE_PORT BIT(0) #define STATS_TYPE_PORT BIT(0)
#define STATS_TYPE_BANK0 BIT(1) #define STATS_TYPE_BANK0 BIT(1)
#define STATS_TYPE_BANK1 BIT(2) #define STATS_TYPE_BANK1 BIT(2)
......
...@@ -160,6 +160,7 @@ ...@@ -160,6 +160,7 @@
#define MV88E6390_G2_AVB_CMD_OP_WRITE 0x6000 #define MV88E6390_G2_AVB_CMD_OP_WRITE 0x6000
#define MV88E6352_G2_AVB_CMD_PORT_MASK 0x0f00 #define MV88E6352_G2_AVB_CMD_PORT_MASK 0x0f00
#define MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL 0xe #define MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL 0xe
#define MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL 0xf
#define MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL 0xf #define MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL 0xf
#define MV88E6390_G2_AVB_CMD_PORT_MASK 0x1f00 #define MV88E6390_G2_AVB_CMD_PORT_MASK 0x1f00
#define MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL 0x1e #define MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL 0x1e
...@@ -335,6 +336,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target, ...@@ -335,6 +336,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops;
extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops; extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops;
extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops; extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops;
...@@ -484,6 +486,7 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip) ...@@ -484,6 +486,7 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {}; static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {}; static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {}; static const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {}; static const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {};
......
...@@ -130,6 +130,31 @@ const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = { ...@@ -130,6 +130,31 @@ const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
.tai_write = mv88e6352_g2_avb_tai_write, .tai_write = mv88e6352_g2_avb_tai_write,
}; };
static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
u16 *data, int len)
{
return mv88e6352_g2_avb_port_ptp_read(chip,
MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
addr, data, len);
}
static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
u16 data)
{
return mv88e6352_g2_avb_port_ptp_write(chip,
MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
addr, data);
}
const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
.port_ptp_read = mv88e6352_g2_avb_port_ptp_read,
.port_ptp_write = mv88e6352_g2_avb_port_ptp_write,
.ptp_read = mv88e6352_g2_avb_ptp_read,
.ptp_write = mv88e6352_g2_avb_ptp_write,
.tai_read = mv88e6165_g2_avb_tai_read,
.tai_write = mv88e6165_g2_avb_tai_write,
};
static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip, static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
int port, int addr, u16 *data, int port, int addr, u16 *data,
int len) int len)
......
...@@ -51,17 +51,30 @@ static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr, ...@@ -51,17 +51,30 @@ static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
return chip->info->ops->avb_ops->ptp_write(chip, addr, data); return chip->info->ops->avb_ops->ptp_write(chip, addr, data);
} }
static int mv88e6xxx_ptp_read(struct mv88e6xxx_chip *chip, int addr,
u16 *data)
{
if (!chip->info->ops->avb_ops->ptp_read)
return -EOPNOTSUPP;
return chip->info->ops->avb_ops->ptp_read(chip, addr, data, 1);
}
/* TX_TSTAMP_TIMEOUT: This limits the time spent polling for a TX /* TX_TSTAMP_TIMEOUT: This limits the time spent polling for a TX
* timestamp. When working properly, hardware will produce a timestamp * timestamp. When working properly, hardware will produce a timestamp
* within 1ms. Software may enounter delays due to MDIO contention, so * within 1ms. Software may enounter delays due to MDIO contention, so
* the timeout is set accordingly. * the timeout is set accordingly.
*/ */
#define TX_TSTAMP_TIMEOUT msecs_to_jiffies(20) #define TX_TSTAMP_TIMEOUT msecs_to_jiffies(40)
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port, int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info) struct ethtool_ts_info *info)
{ {
struct mv88e6xxx_chip *chip = ds->priv; const struct mv88e6xxx_ptp_ops *ptp_ops;
struct mv88e6xxx_chip *chip;
chip = ds->priv;
ptp_ops = chip->info->ops->ptp_ops;
if (!chip->info->ptp_support) if (!chip->info->ptp_support)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -74,17 +87,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port, ...@@ -74,17 +87,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
info->tx_types = info->tx_types =
(1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON); (1 << HWTSTAMP_TX_ON);
info->rx_filters = info->rx_filters = ptp_ops->rx_filters;
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
return 0; return 0;
} }
...@@ -92,10 +95,9 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port, ...@@ -92,10 +95,9 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port, static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
struct hwtstamp_config *config) struct hwtstamp_config *config)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port]; struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
bool tstamp_enable = false; bool tstamp_enable = false;
u16 port_config0;
int err;
/* Prevent the TX/RX paths from trying to interact with the /* Prevent the TX/RX paths from trying to interact with the
* timestamp hardware while we reconfigure it. * timestamp hardware while we reconfigure it.
...@@ -120,6 +122,14 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port, ...@@ -120,6 +122,14 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
/* The switch supports timestamping both L2 and L4; one cannot be /* The switch supports timestamping both L2 and L4; one cannot be
* disabled independently of the other. * disabled independently of the other.
*/ */
if (!(BIT(config->rx_filter) & ptp_ops->rx_filters)) {
config->rx_filter = HWTSTAMP_FILTER_NONE;
dev_dbg(chip->dev, "Unsupported rx_filter %d\n",
config->rx_filter);
return -ERANGE;
}
switch (config->rx_filter) { switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE: case HWTSTAMP_FILTER_NONE:
tstamp_enable = false; tstamp_enable = false;
...@@ -141,24 +151,22 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port, ...@@ -141,24 +151,22 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
return -ERANGE; return -ERANGE;
} }
mutex_lock(&chip->reg_lock);
if (tstamp_enable) { if (tstamp_enable) {
/* Disable transportSpecific value matching, so that packets chip->enable_count += 1;
* with either 1588 (0) and 802.1AS (1) will be timestamped. if (chip->enable_count == 1 && ptp_ops->global_enable)
*/ ptp_ops->global_enable(chip);
port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH; if (ptp_ops->port_enable)
ptp_ops->port_enable(chip, port);
} else { } else {
/* Disable PTP. This disables both RX and TX timestamping. */ if (ptp_ops->port_disable)
port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP; ptp_ops->port_disable(chip, port);
chip->enable_count -= 1;
if (chip->enable_count == 0 && ptp_ops->global_disable)
ptp_ops->global_disable(chip);
} }
mutex_lock(&chip->reg_lock);
err = mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
port_config0);
mutex_unlock(&chip->reg_lock); mutex_unlock(&chip->reg_lock);
if (err < 0)
return err;
/* Once hardware has been configured, enable timestamp checks /* Once hardware has been configured, enable timestamp checks
* in the RX/TX paths. * in the RX/TX paths.
*/ */
...@@ -338,17 +346,18 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip, ...@@ -338,17 +346,18 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip, static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_port_hwtstamp *ps) struct mv88e6xxx_port_hwtstamp *ps)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct sk_buff *skb; struct sk_buff *skb;
skb = skb_dequeue(&ps->rx_queue); skb = skb_dequeue(&ps->rx_queue);
if (skb) if (skb)
mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR0_STS, mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr0_sts_reg,
&ps->rx_queue); &ps->rx_queue);
skb = skb_dequeue(&ps->rx_queue2); skb = skb_dequeue(&ps->rx_queue2);
if (skb) if (skb)
mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR1_STS, mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr1_sts_reg,
&ps->rx_queue2); &ps->rx_queue2);
} }
...@@ -389,6 +398,7 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port, ...@@ -389,6 +398,7 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip, static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_port_hwtstamp *ps) struct mv88e6xxx_port_hwtstamp *ps)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct skb_shared_hwtstamps shhwtstamps; struct skb_shared_hwtstamps shhwtstamps;
u16 departure_block[4], status; u16 departure_block[4], status;
struct sk_buff *tmp_skb; struct sk_buff *tmp_skb;
...@@ -401,7 +411,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip, ...@@ -401,7 +411,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
mutex_lock(&chip->reg_lock); mutex_lock(&chip->reg_lock);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id, err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
MV88E6XXX_PORT_PTP_DEP_STS, ptp_ops->dep_sts_reg,
departure_block, departure_block,
ARRAY_SIZE(departure_block)); ARRAY_SIZE(departure_block));
mutex_unlock(&chip->reg_lock); mutex_unlock(&chip->reg_lock);
...@@ -425,8 +435,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip, ...@@ -425,8 +435,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
/* We have the timestamp; go ahead and clear valid now */ /* We have the timestamp; go ahead and clear valid now */
mutex_lock(&chip->reg_lock); mutex_lock(&chip->reg_lock);
mv88e6xxx_port_ptp_write(chip, ps->port_id, mv88e6xxx_port_ptp_write(chip, ps->port_id, ptp_ops->dep_sts_reg, 0);
MV88E6XXX_PORT_PTP_DEP_STS, 0);
mutex_unlock(&chip->reg_lock); mutex_unlock(&chip->reg_lock);
status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK; status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
...@@ -522,8 +531,48 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port, ...@@ -522,8 +531,48 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
return true; return true;
} }
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
{
u16 val;
int err;
err = mv88e6xxx_ptp_read(chip, MV88E6165_PTP_CFG, &val);
if (err)
return err;
val |= MV88E6165_PTP_CFG_DISABLE_PTP;
return mv88e6xxx_ptp_write(chip, MV88E6165_PTP_CFG, val);
}
int mv88e6165_global_enable(struct mv88e6xxx_chip *chip)
{
u16 val;
int err;
err = mv88e6xxx_ptp_read(chip, MV88E6165_PTP_CFG, &val);
if (err)
return err;
val &= ~(MV88E6165_PTP_CFG_DISABLE_PTP | MV88E6165_PTP_CFG_TSPEC_MASK);
return mv88e6xxx_ptp_write(chip, MV88E6165_PTP_CFG, val);
}
int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port)
{
return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP);
}
int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port)
{
return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH);
}
static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port]; struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
ps->port_id = port; ps->port_id = port;
...@@ -531,12 +580,15 @@ static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port) ...@@ -531,12 +580,15 @@ static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
skb_queue_head_init(&ps->rx_queue); skb_queue_head_init(&ps->rx_queue);
skb_queue_head_init(&ps->rx_queue2); skb_queue_head_init(&ps->rx_queue2);
return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0, if (ptp_ops->port_disable)
MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP); return ptp_ops->port_disable(chip, port);
return 0;
} }
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip) int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
int err; int err;
int i; int i;
...@@ -547,6 +599,18 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip) ...@@ -547,6 +599,18 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return err; return err;
} }
/* Disable PTP globally */
if (ptp_ops->global_disable) {
err = ptp_ops->global_disable(chip);
if (err)
return err;
}
/* Set the ethertype of L2 PTP messages */
err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_GC_ETYPE, ETH_P_1588);
if (err)
return err;
/* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to /* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
* timestamp. This affects all ports that have timestamping enabled, * timestamp. This affects all ports that have timestamping enabled,
* but the timestamp config is per-port; thus we configure all events * but the timestamp config is per-port; thus we configure all events
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "chip.h" #include "chip.h"
/* Global PTP registers */ /* Global 6352 PTP registers */
/* Offset 0x00: PTP EtherType */ /* Offset 0x00: PTP EtherType */
#define MV88E6XXX_PTP_ETHERTYPE 0x00 #define MV88E6XXX_PTP_ETHERTYPE 0x00
...@@ -34,6 +34,12 @@ ...@@ -34,6 +34,12 @@
/* Offset 0x02: Timestamp Arrival Capture Pointers */ /* Offset 0x02: Timestamp Arrival Capture Pointers */
#define MV88E6XXX_PTP_TS_ARRIVAL_PTR 0x02 #define MV88E6XXX_PTP_TS_ARRIVAL_PTR 0x02
/* Offset 0x05: PTP Global Configuration */
#define MV88E6165_PTP_CFG 0x05
#define MV88E6165_PTP_CFG_TSPEC_MASK 0xf000
#define MV88E6165_PTP_CFG_DISABLE_TS_OVERWRITE BIT(1)
#define MV88E6165_PTP_CFG_DISABLE_PTP BIT(0)
/* Offset 0x07: PTP Global Configuration */ /* Offset 0x07: PTP Global Configuration */
#define MV88E6341_PTP_CFG 0x07 #define MV88E6341_PTP_CFG 0x07
#define MV88E6341_PTP_CFG_UPDATE 0x8000 #define MV88E6341_PTP_CFG_UPDATE 0x8000
...@@ -46,7 +52,7 @@ ...@@ -46,7 +52,7 @@
/* Offset 0x08: PTP Interrupt Status */ /* Offset 0x08: PTP Interrupt Status */
#define MV88E6XXX_PTP_IRQ_STATUS 0x08 #define MV88E6XXX_PTP_IRQ_STATUS 0x08
/* Per-Port PTP Registers */ /* Per-Port 6352 PTP Registers */
/* Offset 0x00: PTP Configuration 0 */ /* Offset 0x00: PTP Configuration 0 */
#define MV88E6XXX_PORT_PTP_CFG0 0x00 #define MV88E6XXX_PORT_PTP_CFG0 0x00
#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_SHIFT 12 #define MV88E6XXX_PORT_PTP_CFG0_TSPEC_SHIFT 12
...@@ -123,6 +129,10 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port, ...@@ -123,6 +129,10 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip); int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip); void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port);
int mv88e6165_global_enable(struct mv88e6xxx_chip *chip);
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip);
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */ #else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chip.h" #include "chip.h"
#include "global2.h" #include "global2.h"
#include "hwtstamp.h"
#include "ptp.h" #include "ptp.h"
/* Raw timestamps are in units of 8-ns clock periods. */ /* Raw timestamps are in units of 8-ns clock periods. */
...@@ -50,7 +51,7 @@ static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data) ...@@ -50,7 +51,7 @@ static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data)
} }
/* TODO: places where this are called should be using pinctrl */ /* TODO: places where this are called should be using pinctrl */
static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin, static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
int func, int input) int func, int input)
{ {
int err; int err;
...@@ -65,7 +66,7 @@ static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin, ...@@ -65,7 +66,7 @@ static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
return chip->info->ops->gpio_ops->set_pctl(chip, pin, func); return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
} }
static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc) static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc)
{ {
struct mv88e6xxx_chip *chip = cc_to_chip(cc); struct mv88e6xxx_chip *chip = cc_to_chip(cc);
u16 phc_time[2]; u16 phc_time[2];
...@@ -79,13 +80,27 @@ static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc) ...@@ -79,13 +80,27 @@ static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
return ((u32)phc_time[1] << 16) | phc_time[0]; return ((u32)phc_time[1] << 16) | phc_time[0];
} }
/* mv88e6xxx_config_eventcap - configure TAI event capture static u64 mv88e6165_ptp_clock_read(const struct cyclecounter *cc)
{
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
u16 phc_time[2];
int err;
err = mv88e6xxx_tai_read(chip, MV88E6XXX_PTP_GC_TIME_LO, phc_time,
ARRAY_SIZE(phc_time));
if (err)
return 0;
else
return ((u32)phc_time[1] << 16) | phc_time[0];
}
/* mv88e6352_config_eventcap - configure TAI event capture
* @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external) * @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external)
* @rising: zero for falling-edge trigger, else rising-edge trigger * @rising: zero for falling-edge trigger, else rising-edge trigger
* *
* This will also reset the capture sequence counter. * This will also reset the capture sequence counter.
*/ */
static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event, static int mv88e6352_config_eventcap(struct mv88e6xxx_chip *chip, int event,
int rising) int rising)
{ {
u16 global_config; u16 global_config;
...@@ -118,7 +133,7 @@ static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event, ...@@ -118,7 +133,7 @@ static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event,
return err; return err;
} }
static void mv88e6xxx_tai_event_work(struct work_struct *ugly) static void mv88e6352_tai_event_work(struct work_struct *ugly)
{ {
struct delayed_work *dw = to_delayed_work(ugly); struct delayed_work *dw = to_delayed_work(ugly);
struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw); struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw);
...@@ -232,7 +247,7 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp, ...@@ -232,7 +247,7 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
return 0; return 0;
} }
static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip, static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
struct ptp_clock_request *rq, int on) struct ptp_clock_request *rq, int on)
{ {
int rising = (rq->extts.flags & PTP_RISING_EDGE); int rising = (rq->extts.flags & PTP_RISING_EDGE);
...@@ -250,18 +265,18 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip, ...@@ -250,18 +265,18 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
if (on) { if (on) {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ; func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
err = mv88e6xxx_set_gpio_func(chip, pin, func, true); err = mv88e6352_set_gpio_func(chip, pin, func, true);
if (err) if (err)
goto out; goto out;
schedule_delayed_work(&chip->tai_event_work, schedule_delayed_work(&chip->tai_event_work,
TAI_EVENT_WORK_INTERVAL); TAI_EVENT_WORK_INTERVAL);
err = mv88e6xxx_config_eventcap(chip, PTP_CLOCK_EXTTS, rising); err = mv88e6352_config_eventcap(chip, PTP_CLOCK_EXTTS, rising);
} else { } else {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO; func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
err = mv88e6xxx_set_gpio_func(chip, pin, func, true); err = mv88e6352_set_gpio_func(chip, pin, func, true);
cancel_delayed_work_sync(&chip->tai_event_work); cancel_delayed_work_sync(&chip->tai_event_work);
} }
...@@ -272,20 +287,20 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip, ...@@ -272,20 +287,20 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
return err; return err;
} }
static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp, static int mv88e6352_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on) struct ptp_clock_request *rq, int on)
{ {
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp); struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
switch (rq->type) { switch (rq->type) {
case PTP_CLK_REQ_EXTTS: case PTP_CLK_REQ_EXTTS:
return mv88e6xxx_ptp_enable_extts(chip, rq, on); return mv88e6352_ptp_enable_extts(chip, rq, on);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, static int mv88e6352_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan) enum ptp_pin_function func, unsigned int chan)
{ {
switch (func) { switch (func) {
...@@ -299,6 +314,55 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, ...@@ -299,6 +314,55 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
return 0; return 0;
} }
const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.clock_read = mv88e6352_ptp_clock_read,
.ptp_enable = mv88e6352_ptp_enable,
.ptp_verify = mv88e6352_ptp_verify,
.event_work = mv88e6352_tai_event_work,
.port_enable = mv88e6352_hwtstamp_port_enable,
.port_disable = mv88e6352_hwtstamp_port_disable,
.n_ext_ts = 1,
.arr0_sts_reg = MV88E6XXX_PORT_PTP_ARR0_STS,
.arr1_sts_reg = MV88E6XXX_PORT_PTP_ARR1_STS,
.dep_sts_reg = MV88E6XXX_PORT_PTP_DEP_STS,
.rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
};
const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
.clock_read = mv88e6165_ptp_clock_read,
.global_enable = mv88e6165_global_enable,
.global_disable = mv88e6165_global_disable,
.arr0_sts_reg = MV88E6165_PORT_PTP_ARR0_STS,
.arr1_sts_reg = MV88E6165_PORT_PTP_ARR1_STS,
.dep_sts_reg = MV88E6165_PORT_PTP_DEP_STS,
.rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
};
static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
{
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
if (chip->info->ops->ptp_ops->clock_read)
return chip->info->ops->ptp_ops->clock_read(cc);
return 0;
}
/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3 /* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
* seconds; this task forces periodic reads so that we don't miss any. * seconds; this task forces periodic reads so that we don't miss any.
*/ */
...@@ -317,6 +381,7 @@ static void mv88e6xxx_ptp_overflow_check(struct work_struct *work) ...@@ -317,6 +381,7 @@ static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{ {
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
int i; int i;
/* Set up the cycle counter */ /* Set up the cycle counter */
...@@ -330,14 +395,15 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) ...@@ -330,14 +395,15 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
ktime_to_ns(ktime_get_real())); ktime_to_ns(ktime_get_real()));
INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check); INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
INIT_DELAYED_WORK(&chip->tai_event_work, mv88e6xxx_tai_event_work); if (ptp_ops->event_work)
INIT_DELAYED_WORK(&chip->tai_event_work, ptp_ops->event_work);
chip->ptp_clock_info.owner = THIS_MODULE; chip->ptp_clock_info.owner = THIS_MODULE;
snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name), snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
dev_name(chip->dev)); dev_name(chip->dev));
chip->ptp_clock_info.max_adj = 1000000; chip->ptp_clock_info.max_adj = 1000000;
chip->ptp_clock_info.n_ext_ts = 1; chip->ptp_clock_info.n_ext_ts = ptp_ops->n_ext_ts;
chip->ptp_clock_info.n_per_out = 0; chip->ptp_clock_info.n_per_out = 0;
chip->ptp_clock_info.n_pins = mv88e6xxx_num_gpio(chip); chip->ptp_clock_info.n_pins = mv88e6xxx_num_gpio(chip);
chip->ptp_clock_info.pps = 0; chip->ptp_clock_info.pps = 0;
...@@ -355,8 +421,8 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) ...@@ -355,8 +421,8 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime; chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime;
chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime; chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime; chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable; chip->ptp_clock_info.enable = ptp_ops->ptp_enable;
chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify; chip->ptp_clock_info.verify = ptp_ops->ptp_verify;
chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work; chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev); chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
...@@ -373,7 +439,8 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip) ...@@ -373,7 +439,8 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{ {
if (chip->ptp_clock) { if (chip->ptp_clock) {
cancel_delayed_work_sync(&chip->overflow_work); cancel_delayed_work_sync(&chip->overflow_work);
cancel_delayed_work_sync(&chip->tai_event_work); if (chip->info->ops->ptp_ops->event_work)
cancel_delayed_work_sync(&chip->tai_event_work);
ptp_clock_unregister(chip->ptp_clock); ptp_clock_unregister(chip->ptp_clock);
chip->ptp_clock = NULL; chip->ptp_clock = NULL;
......
...@@ -78,6 +78,71 @@ ...@@ -78,6 +78,71 @@
/* Offset 0x12: Lock Status */ /* Offset 0x12: Lock Status */
#define MV88E6XXX_TAI_LOCK_STATUS 0x12 #define MV88E6XXX_TAI_LOCK_STATUS 0x12
/* Offset 0x00: Ether Type */
#define MV88E6XXX_PTP_GC_ETYPE 0x00
/* 6165 Global Control Registers */
/* Offset 0x00: Ether Type */
#define MV88E6XXX_PTP_GC_ETYPE 0x00
/* Offset 0x01: Message ID */
#define MV88E6XXX_PTP_GC_MESSAGE_ID 0x01
/* Offset 0x02: Time Stamp Arrive Time */
#define MV88E6XXX_PTP_GC_TS_ARR_PTR 0x02
/* Offset 0x03: Port Arrival Interrupt Enable */
#define MV88E6XXX_PTP_GC_PORT_ARR_INT_EN 0x03
/* Offset 0x04: Port Departure Interrupt Enable */
#define MV88E6XXX_PTP_GC_PORT_DEP_INT_EN 0x04
/* Offset 0x05: Configuration */
#define MV88E6XXX_PTP_GC_CONFIG 0x05
#define MV88E6XXX_PTP_GC_CONFIG_DIS_OVERWRITE BIT(1)
#define MV88E6XXX_PTP_GC_CONFIG_DIS_TS BIT(0)
/* Offset 0x8: Interrupt Status */
#define MV88E6XXX_PTP_GC_INT_STATUS 0x08
/* Offset 0x9/0xa: Global Time */
#define MV88E6XXX_PTP_GC_TIME_LO 0x09
#define MV88E6XXX_PTP_GC_TIME_HI 0x0A
/* 6165 Per Port Registers */
/* Offset 0: Arrival Time 0 Status */
#define MV88E6165_PORT_PTP_ARR0_STS 0x00
/* Offset 0x01/0x02: PTP Arrival 0 Time */
#define MV88E6165_PORT_PTP_ARR0_TIME_LO 0x01
#define MV88E6165_PORT_PTP_ARR0_TIME_HI 0x02
/* Offset 0x03: PTP Arrival 0 Sequence ID */
#define MV88E6165_PORT_PTP_ARR0_SEQID 0x03
/* Offset 0x04: PTP Arrival 1 Status */
#define MV88E6165_PORT_PTP_ARR1_STS 0x04
/* Offset 0x05/0x6E: PTP Arrival 1 Time */
#define MV88E6165_PORT_PTP_ARR1_TIME_LO 0x05
#define MV88E6165_PORT_PTP_ARR1_TIME_HI 0x06
/* Offset 0x07: PTP Arrival 1 Sequence ID */
#define MV88E6165_PORT_PTP_ARR1_SEQID 0x07
/* Offset 0x08: PTP Departure Status */
#define MV88E6165_PORT_PTP_DEP_STS 0x08
/* Offset 0x09/0x0a: PTP Deperture Time */
#define MV88E6165_PORT_PTP_DEP_TIME_LO 0x09
#define MV88E6165_PORT_PTP_DEP_TIME_HI 0x0a
/* Offset 0x0b: PTP Departure Sequence ID */
#define MV88E6165_PORT_PTP_DEP_SEQID 0x0b
/* Offset 0x0d: Port Status */
#define MV88E6164_PORT_STATUS 0x0d
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP #ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp); long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
...@@ -87,6 +152,9 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip); ...@@ -87,6 +152,9 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \ #define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
ptp_clock_info) ptp_clock_info)
extern const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops;
extern const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops;
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */ #else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
static inline long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp) static inline long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
...@@ -103,6 +171,9 @@ static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip) ...@@ -103,6 +171,9 @@ static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{ {
} }
static const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {};
static const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {};
#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */ #endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
#endif /* _MV88E6XXX_PTP_H */ #endif /* _MV88E6XXX_PTP_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册