mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-14 12:56:46 +07:00
Merge branch 'PTP_CLK-pin-configuration-for-SJA1105-DSA-driver'
Vladimir Oltean says: ==================== PTP_CLK pin configuration for SJA1105 DSA driver This series adds support for the PTP_CLK pin on SJA1105 to be configured via the PTP subsystem, in the "periodic output" and "external timestamp input" modes. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9970de8b01
@ -38,10 +38,13 @@ struct sja1105_regs {
|
||||
u64 config;
|
||||
u64 sgmii;
|
||||
u64 rmii_pll1;
|
||||
u64 ptppinst;
|
||||
u64 ptppindur;
|
||||
u64 ptp_control;
|
||||
u64 ptpclkval;
|
||||
u64 ptpclkrate;
|
||||
u64 ptpclkcorp;
|
||||
u64 ptpsyncts;
|
||||
u64 ptpschtm;
|
||||
u64 ptpegr_ts[SJA1105_NUM_PORTS];
|
||||
u64 pad_mii_tx[SJA1105_NUM_PORTS];
|
||||
@ -214,5 +217,7 @@ size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op);
|
||||
size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op);
|
||||
size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op);
|
||||
|
||||
#endif
|
||||
|
@ -124,6 +124,9 @@
|
||||
#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD \
|
||||
SJA1105_SIZE_DYN_CMD
|
||||
|
||||
#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD \
|
||||
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
|
||||
|
||||
#define SJA1105_MAX_DYN_CMD_SIZE \
|
||||
SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD
|
||||
|
||||
@ -481,6 +484,18 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
||||
enum packing_op op)
|
||||
{
|
||||
u8 *p = buf + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
|
||||
const int size = SJA1105_SIZE_DYN_CMD;
|
||||
|
||||
sja1105_packing(p, &cmd->valid, 31, 31, size, op);
|
||||
sja1105_packing(p, &cmd->errors, 30, 30, size, op);
|
||||
sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
|
||||
}
|
||||
|
||||
#define OP_READ BIT(0)
|
||||
#define OP_WRITE BIT(1)
|
||||
#define OP_DEL BIT(2)
|
||||
@ -610,7 +625,14 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
|
||||
.addr = 0x38,
|
||||
},
|
||||
[BLK_IDX_L2_FORWARDING_PARAMS] = {0},
|
||||
[BLK_IDX_AVB_PARAMS] = {0},
|
||||
[BLK_IDX_AVB_PARAMS] = {
|
||||
.entry_packing = sja1105pqrs_avb_params_entry_packing,
|
||||
.cmd_packing = sja1105pqrs_avb_params_cmd_packing,
|
||||
.max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
|
||||
.access = (OP_READ | OP_WRITE),
|
||||
.packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
|
||||
.addr = 0x8003,
|
||||
},
|
||||
[BLK_IDX_GENERAL_PARAMS] = {
|
||||
.entry_packing = sja1105et_general_params_entry_packing,
|
||||
.cmd_packing = sja1105et_general_params_cmd_packing,
|
||||
|
@ -479,6 +479,43 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sja1105_init_avb_params(struct sja1105_private *priv)
|
||||
{
|
||||
struct sja1105_avb_params_entry *avb;
|
||||
struct sja1105_table *table;
|
||||
|
||||
table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS];
|
||||
|
||||
/* Discard previous AVB Parameters Table */
|
||||
if (table->entry_count) {
|
||||
kfree(table->entries);
|
||||
table->entry_count = 0;
|
||||
}
|
||||
|
||||
table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT,
|
||||
table->ops->unpacked_entry_size, GFP_KERNEL);
|
||||
if (!table->entries)
|
||||
return -ENOMEM;
|
||||
|
||||
table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT;
|
||||
|
||||
avb = table->entries;
|
||||
|
||||
/* Configure the MAC addresses for meta frames */
|
||||
avb->destmeta = SJA1105_META_DMAC;
|
||||
avb->srcmeta = SJA1105_META_SMAC;
|
||||
/* On P/Q/R/S, configure the direction of the PTP_CLK pin as input by
|
||||
* default. This is because there might be boards with a hardware
|
||||
* layout where enabling the pin as output might cause an electrical
|
||||
* clash. On E/T the pin is always an output, which the board designers
|
||||
* probably already knew, so even if there are going to be electrical
|
||||
* issues, there's nothing we can do.
|
||||
*/
|
||||
avb->cas_master = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000)
|
||||
|
||||
static void sja1105_setup_policer(struct sja1105_l2_policing_entry *policing,
|
||||
@ -567,6 +604,9 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = sja1105_init_general_params(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = sja1105_init_avb_params(priv);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -14,6 +14,17 @@
|
||||
#define SJA1105_MAX_ADJ_PPB 32000000
|
||||
#define SJA1105_SIZE_PTP_CMD 4
|
||||
|
||||
/* PTPSYNCTS has no interrupt or update mechanism, because the intended
|
||||
* hardware use case is for the timestamp to be collected synchronously,
|
||||
* immediately after the CAS_MASTER SJA1105 switch has triggered a CASSYNC
|
||||
* pulse on the PTP_CLK pin. When used as a generic extts source, it needs
|
||||
* polling and a comparison with the old value. The polling interval is just
|
||||
* the Nyquist rate of a canonical PPS input (e.g. from a GPS module).
|
||||
* Anything of higher frequency than 1 Hz will be lost, since there is no
|
||||
* timestamp FIFO.
|
||||
*/
|
||||
#define SJA1105_EXTTS_INTERVAL (HZ / 2)
|
||||
|
||||
/* This range is actually +/- SJA1105_MAX_ADJ_PPB
|
||||
* divided by 1000 (ppb -> ppm) and with a 16-bit
|
||||
* "fractional" part (actually fixed point).
|
||||
@ -39,44 +50,13 @@ enum sja1105_ptp_clk_mode {
|
||||
PTP_SET_MODE = 0,
|
||||
};
|
||||
|
||||
#define extts_to_data(d) \
|
||||
container_of((d), struct sja1105_ptp_data, extts_work)
|
||||
#define ptp_caps_to_data(d) \
|
||||
container_of((d), struct sja1105_ptp_data, caps)
|
||||
#define ptp_data_to_sja1105(d) \
|
||||
container_of((d), struct sja1105_private, ptp_data)
|
||||
|
||||
static int sja1105_init_avb_params(struct sja1105_private *priv,
|
||||
bool on)
|
||||
{
|
||||
struct sja1105_avb_params_entry *avb;
|
||||
struct sja1105_table *table;
|
||||
|
||||
table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS];
|
||||
|
||||
/* Discard previous AVB Parameters Table */
|
||||
if (table->entry_count) {
|
||||
kfree(table->entries);
|
||||
table->entry_count = 0;
|
||||
}
|
||||
|
||||
/* Configure the reception of meta frames only if requested */
|
||||
if (!on)
|
||||
return 0;
|
||||
|
||||
table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT,
|
||||
table->ops->unpacked_entry_size, GFP_KERNEL);
|
||||
if (!table->entries)
|
||||
return -ENOMEM;
|
||||
|
||||
table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT;
|
||||
|
||||
avb = table->entries;
|
||||
|
||||
avb->destmeta = SJA1105_META_DMAC;
|
||||
avb->srcmeta = SJA1105_META_SMAC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called only with priv->tagger_data.state bit
|
||||
* SJA1105_HWTS_RX_EN cleared
|
||||
*/
|
||||
@ -86,17 +66,12 @@ static int sja1105_change_rxtstamping(struct sja1105_private *priv,
|
||||
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
|
||||
struct sja1105_general_params_entry *general_params;
|
||||
struct sja1105_table *table;
|
||||
int rc;
|
||||
|
||||
table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
|
||||
general_params = table->entries;
|
||||
general_params->send_meta1 = on;
|
||||
general_params->send_meta0 = on;
|
||||
|
||||
rc = sja1105_init_avb_params(priv, on);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Initialize the meta state machine to a known state */
|
||||
if (priv->tagger_data.stampable_skb) {
|
||||
kfree_skb(priv->tagger_data.stampable_skb);
|
||||
@ -206,6 +181,8 @@ void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
|
||||
sja1105_packing(buf, &valid, 31, 31, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
|
||||
sja1105_packing(buf, &cmd->startptpcp, 28, 28, size, op);
|
||||
sja1105_packing(buf, &cmd->stopptpcp, 27, 27, size, op);
|
||||
sja1105_packing(buf, &cmd->resptp, 2, 2, size, op);
|
||||
sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op);
|
||||
@ -221,6 +198,8 @@ void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
|
||||
sja1105_packing(buf, &valid, 31, 31, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
|
||||
sja1105_packing(buf, &cmd->startptpcp, 28, 28, size, op);
|
||||
sja1105_packing(buf, &cmd->stopptpcp, 27, 27, size, op);
|
||||
sja1105_packing(buf, &cmd->resptp, 3, 3, size, op);
|
||||
sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op);
|
||||
sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op);
|
||||
@ -615,6 +594,227 @@ static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sja1105_ptp_extts_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct sja1105_ptp_data *ptp_data = extts_to_data(dw);
|
||||
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
struct ptp_clock_event event;
|
||||
u64 ptpsyncts = 0;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&ptp_data->lock);
|
||||
|
||||
rc = sja1105_xfer_u64(priv, SPI_READ, regs->ptpsyncts, &ptpsyncts,
|
||||
NULL);
|
||||
if (rc < 0)
|
||||
dev_err_ratelimited(priv->ds->dev,
|
||||
"Failed to read PTPSYNCTS: %d\n", rc);
|
||||
|
||||
if (ptpsyncts && ptp_data->ptpsyncts != ptpsyncts) {
|
||||
event.index = 0;
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.timestamp = ns_to_ktime(sja1105_ticks_to_ns(ptpsyncts));
|
||||
ptp_clock_event(ptp_data->clock, &event);
|
||||
|
||||
ptp_data->ptpsyncts = ptpsyncts;
|
||||
}
|
||||
|
||||
mutex_unlock(&ptp_data->lock);
|
||||
|
||||
schedule_delayed_work(&ptp_data->extts_work, SJA1105_EXTTS_INTERVAL);
|
||||
}
|
||||
|
||||
static int sja1105_change_ptp_clk_pin_func(struct sja1105_private *priv,
|
||||
enum ptp_pin_function func)
|
||||
{
|
||||
struct sja1105_avb_params_entry *avb;
|
||||
enum ptp_pin_function old_func;
|
||||
|
||||
avb = priv->static_config.tables[BLK_IDX_AVB_PARAMS].entries;
|
||||
|
||||
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||||
priv->info->device_id == SJA1105T_DEVICE_ID ||
|
||||
avb->cas_master)
|
||||
old_func = PTP_PF_PEROUT;
|
||||
else
|
||||
old_func = PTP_PF_EXTTS;
|
||||
|
||||
if (func == old_func)
|
||||
return 0;
|
||||
|
||||
avb->cas_master = (func == PTP_PF_PEROUT);
|
||||
|
||||
return sja1105_dynamic_config_write(priv, BLK_IDX_AVB_PARAMS, 0, avb,
|
||||
true);
|
||||
}
|
||||
|
||||
/* The PTP_CLK pin may be configured to toggle with a 50% duty cycle and a
|
||||
* frequency f:
|
||||
*
|
||||
* NSEC_PER_SEC
|
||||
* f = ----------------------
|
||||
* (PTPPINDUR * 8 ns) * 2
|
||||
*/
|
||||
static int sja1105_per_out_enable(struct sja1105_private *priv,
|
||||
struct ptp_perout_request *perout,
|
||||
bool on)
|
||||
{
|
||||
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
struct sja1105_ptp_cmd cmd = ptp_data->cmd;
|
||||
int rc;
|
||||
|
||||
/* We only support one channel */
|
||||
if (perout->index != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Reject requests with unsupported flags */
|
||||
if (perout->flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&ptp_data->lock);
|
||||
|
||||
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_PEROUT);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (on) {
|
||||
struct timespec64 pin_duration_ts = {
|
||||
.tv_sec = perout->period.sec,
|
||||
.tv_nsec = perout->period.nsec,
|
||||
};
|
||||
struct timespec64 pin_start_ts = {
|
||||
.tv_sec = perout->start.sec,
|
||||
.tv_nsec = perout->start.nsec,
|
||||
};
|
||||
u64 pin_duration = timespec64_to_ns(&pin_duration_ts);
|
||||
u64 pin_start = timespec64_to_ns(&pin_start_ts);
|
||||
u32 pin_duration32;
|
||||
u64 now;
|
||||
|
||||
/* ptppindur: 32 bit register which holds the interval between
|
||||
* 2 edges on PTP_CLK. So check for truncation which happens
|
||||
* at periods larger than around 68.7 seconds.
|
||||
*/
|
||||
pin_duration = ns_to_sja1105_ticks(pin_duration / 2);
|
||||
if (pin_duration > U32_MAX) {
|
||||
rc = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
pin_duration32 = pin_duration;
|
||||
|
||||
/* ptppins: 64 bit register which needs to hold a PTP time
|
||||
* larger than the current time, otherwise the startptpcp
|
||||
* command won't do anything. So advance the current time
|
||||
* by a number of periods in a way that won't alter the
|
||||
* phase offset.
|
||||
*/
|
||||
rc = __sja1105_ptp_gettimex(priv->ds, &now, NULL);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
pin_start = future_base_time(pin_start, pin_duration,
|
||||
now + 1ull * NSEC_PER_SEC);
|
||||
pin_start = ns_to_sja1105_ticks(pin_start);
|
||||
|
||||
rc = sja1105_xfer_u64(priv, SPI_WRITE, regs->ptppinst,
|
||||
&pin_start, NULL);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptppindur,
|
||||
&pin_duration32, NULL);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (on)
|
||||
cmd.startptpcp = true;
|
||||
else
|
||||
cmd.stopptpcp = true;
|
||||
|
||||
rc = sja1105_ptp_commit(priv->ds, &cmd, SPI_WRITE);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ptp_data->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sja1105_extts_enable(struct sja1105_private *priv,
|
||||
struct ptp_extts_request *extts,
|
||||
bool on)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* We only support one channel */
|
||||
if (extts->index != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Reject requests with unsupported flags */
|
||||
if (extts->flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_EXTTS);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (on)
|
||||
schedule_delayed_work(&priv->ptp_data.extts_work,
|
||||
SJA1105_EXTTS_INTERVAL);
|
||||
else
|
||||
cancel_delayed_work_sync(&priv->ptp_data.extts_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sja1105_ptp_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *req, int on)
|
||||
{
|
||||
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
||||
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
if (req->type == PTP_CLK_REQ_PEROUT)
|
||||
rc = sja1105_per_out_enable(priv, &req->perout, on);
|
||||
else if (req->type == PTP_CLK_REQ_EXTTS)
|
||||
rc = sja1105_extts_enable(priv, &req->extts, on);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sja1105_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
|
||||
enum ptp_pin_function func, unsigned int chan)
|
||||
{
|
||||
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
||||
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
|
||||
|
||||
if (chan != 0 || pin != 0)
|
||||
return -1;
|
||||
|
||||
switch (func) {
|
||||
case PTP_PF_NONE:
|
||||
case PTP_PF_PEROUT:
|
||||
break;
|
||||
case PTP_PF_EXTTS:
|
||||
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||||
priv->info->device_id == SJA1105T_DEVICE_ID)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ptp_pin_desc sja1105_ptp_pin = {
|
||||
.name = "ptp_clk",
|
||||
.index = 0,
|
||||
.func = PTP_PF_NONE,
|
||||
};
|
||||
|
||||
int sja1105_ptp_clock_register(struct dsa_switch *ds)
|
||||
{
|
||||
struct sja1105_private *priv = ds->priv;
|
||||
@ -628,8 +828,14 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds)
|
||||
.adjtime = sja1105_ptp_adjtime,
|
||||
.gettimex64 = sja1105_ptp_gettimex,
|
||||
.settime64 = sja1105_ptp_settime,
|
||||
.enable = sja1105_ptp_enable,
|
||||
.verify = sja1105_ptp_verify_pin,
|
||||
.do_aux_work = sja1105_rxtstamp_work,
|
||||
.max_adj = SJA1105_MAX_ADJ_PPB,
|
||||
.pin_config = &sja1105_ptp_pin,
|
||||
.n_pins = 1,
|
||||
.n_ext_ts = 1,
|
||||
.n_per_out = 1,
|
||||
};
|
||||
|
||||
skb_queue_head_init(&ptp_data->skb_rxtstamp_queue);
|
||||
@ -642,6 +848,8 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds)
|
||||
ptp_data->cmd.corrclk4ts = true;
|
||||
ptp_data->cmd.ptpclkadd = PTP_SET_MODE;
|
||||
|
||||
INIT_DELAYED_WORK(&ptp_data->extts_work, sja1105_ptp_extts_work);
|
||||
|
||||
return sja1105_ptp_reset(ds);
|
||||
}
|
||||
|
||||
@ -653,6 +861,7 @@ void sja1105_ptp_clock_unregister(struct dsa_switch *ds)
|
||||
if (IS_ERR_OR_NULL(ptp_data->clock))
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&ptp_data->extts_work);
|
||||
ptp_cancel_worker_sync(ptp_data->clock);
|
||||
skb_queue_purge(&ptp_data->skb_rxtstamp_queue);
|
||||
ptp_clock_unregister(ptp_data->clock);
|
||||
|
@ -21,7 +21,36 @@ static inline s64 sja1105_ticks_to_ns(s64 ticks)
|
||||
return ticks * SJA1105_TICK_NS;
|
||||
}
|
||||
|
||||
/* Calculate the first base_time in the future that satisfies this
|
||||
* relationship:
|
||||
*
|
||||
* future_base_time = base_time + N x cycle_time >= now, or
|
||||
*
|
||||
* now - base_time
|
||||
* N >= ---------------
|
||||
* cycle_time
|
||||
*
|
||||
* Because N is an integer, the ceiling value of the above "a / b" ratio
|
||||
* is in fact precisely the floor value of "(a + b - 1) / b", which is
|
||||
* easier to calculate only having integer division tools.
|
||||
*/
|
||||
static inline s64 future_base_time(s64 base_time, s64 cycle_time, s64 now)
|
||||
{
|
||||
s64 a, b, n;
|
||||
|
||||
if (base_time >= now)
|
||||
return base_time;
|
||||
|
||||
a = now - base_time;
|
||||
b = cycle_time;
|
||||
n = div_s64(a + b - 1, b);
|
||||
|
||||
return base_time + n * cycle_time;
|
||||
}
|
||||
|
||||
struct sja1105_ptp_cmd {
|
||||
u64 startptpcp; /* start toggling PTP_CLK pin */
|
||||
u64 stopptpcp; /* stop toggling PTP_CLK pin */
|
||||
u64 ptpstrtsch; /* start schedule */
|
||||
u64 ptpstopsch; /* stop schedule */
|
||||
u64 resptp; /* reset */
|
||||
@ -30,12 +59,14 @@ struct sja1105_ptp_cmd {
|
||||
};
|
||||
|
||||
struct sja1105_ptp_data {
|
||||
struct delayed_work extts_work;
|
||||
struct sk_buff_head skb_rxtstamp_queue;
|
||||
struct ptp_clock_info caps;
|
||||
struct ptp_clock *clock;
|
||||
struct sja1105_ptp_cmd cmd;
|
||||
/* Serializes all operations on the PTP hardware clock */
|
||||
struct mutex lock;
|
||||
u64 ptpsyncts;
|
||||
};
|
||||
|
||||
int sja1105_ptp_clock_register(struct dsa_switch *ds);
|
||||
|
@ -458,6 +458,8 @@ static struct sja1105_regs sja1105et_regs = {
|
||||
.rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
|
||||
.ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8},
|
||||
.ptpschtm = 0x12, /* Spans 0x12 to 0x13 */
|
||||
.ptppinst = 0x14,
|
||||
.ptppindur = 0x16,
|
||||
.ptp_control = 0x17,
|
||||
.ptpclkval = 0x18, /* Spans 0x18 to 0x19 */
|
||||
.ptpclkrate = 0x1A,
|
||||
@ -491,10 +493,13 @@ static struct sja1105_regs sja1105pqrs_regs = {
|
||||
.qlevel = {0x604, 0x614, 0x624, 0x634, 0x644},
|
||||
.ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0},
|
||||
.ptpschtm = 0x13, /* Spans 0x13 to 0x14 */
|
||||
.ptppinst = 0x15,
|
||||
.ptppindur = 0x17,
|
||||
.ptp_control = 0x18,
|
||||
.ptpclkval = 0x19,
|
||||
.ptpclkrate = 0x1B,
|
||||
.ptpclkcorp = 0x1E,
|
||||
.ptpsyncts = 0x1F,
|
||||
};
|
||||
|
||||
struct sja1105_info sja1105e_info = {
|
||||
|
@ -102,12 +102,13 @@ static size_t sja1105et_avb_params_entry_packing(void *buf, void *entry_ptr,
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op)
|
||||
size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op)
|
||||
{
|
||||
const size_t size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
|
||||
struct sja1105_avb_params_entry *entry = entry_ptr;
|
||||
|
||||
sja1105_packing(buf, &entry->cas_master, 126, 126, size, op);
|
||||
sja1105_packing(buf, &entry->destmeta, 125, 78, size, op);
|
||||
sja1105_packing(buf, &entry->srcmeta, 77, 30, size, op);
|
||||
return size;
|
||||
|
@ -230,6 +230,7 @@ struct sja1105_l2_policing_entry {
|
||||
};
|
||||
|
||||
struct sja1105_avb_params_entry {
|
||||
u64 cas_master;
|
||||
u64 destmeta;
|
||||
u64 srcmeta;
|
||||
};
|
||||
|
@ -28,33 +28,6 @@ static s64 sja1105_delta_to_ns(s64 delta)
|
||||
return delta * 200;
|
||||
}
|
||||
|
||||
/* Calculate the first base_time in the future that satisfies this
|
||||
* relationship:
|
||||
*
|
||||
* future_base_time = base_time + N x cycle_time >= now, or
|
||||
*
|
||||
* now - base_time
|
||||
* N >= ---------------
|
||||
* cycle_time
|
||||
*
|
||||
* Because N is an integer, the ceiling value of the above "a / b" ratio
|
||||
* is in fact precisely the floor value of "(a + b - 1) / b", which is
|
||||
* easier to calculate only having integer division tools.
|
||||
*/
|
||||
static s64 future_base_time(s64 base_time, s64 cycle_time, s64 now)
|
||||
{
|
||||
s64 a, b, n;
|
||||
|
||||
if (base_time >= now)
|
||||
return base_time;
|
||||
|
||||
a = now - base_time;
|
||||
b = cycle_time;
|
||||
n = div_s64(a + b - 1, b);
|
||||
|
||||
return base_time + n * cycle_time;
|
||||
}
|
||||
|
||||
static int sja1105_tas_set_runtime_params(struct sja1105_private *priv)
|
||||
{
|
||||
struct sja1105_tas_data *tas_data = &priv->tas_data;
|
||||
|
Loading…
Reference in New Issue
Block a user