net: lan743x: Add support for PTP-IO Event Output (Periodic Output)
Add support for PTP-IO Event Output (Periodic Output - perout) for PCI11010/PCI11414 chips Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
60942c397a
commit
e432dd3bee
@ -336,6 +336,7 @@
|
||||
#define INT_MOD_CFG9 (0x7E4)
|
||||
|
||||
#define PTP_CMD_CTL (0x0A00)
|
||||
#define PTP_CMD_CTL_PTP_LTC_TARGET_READ_ BIT(13)
|
||||
#define PTP_CMD_CTL_PTP_CLK_STP_NSEC_ BIT(6)
|
||||
#define PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_ BIT(5)
|
||||
#define PTP_CMD_CTL_PTP_CLOCK_LOAD_ BIT(4)
|
||||
@ -357,6 +358,30 @@
|
||||
(((value) & 0x7) << (1 + ((channel) << 2)))
|
||||
#define PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel) (BIT((channel) << 2))
|
||||
|
||||
#define HS_PTP_GENERAL_CONFIG (0x0A04)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(channel) \
|
||||
(0xf << (4 + ((channel) << 2)))
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_ (0)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_ (1)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_ (2)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_ (3)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_ (4)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_ (5)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_ (6)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_ (7)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_ (8)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_ (9)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_ (10)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_ (11)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_ (12)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ (13)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGG_ (14)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_INT_ (15)
|
||||
#define HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(channel, value) \
|
||||
(((value) & 0xf) << (4 + ((channel) << 2)))
|
||||
#define HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(channel) (BIT(1 + ((channel) * 2)))
|
||||
#define HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel) (BIT((channel) * 2))
|
||||
|
||||
#define PTP_INT_STS (0x0A08)
|
||||
#define PTP_INT_IO_FE_MASK_ GENMASK(31, 24)
|
||||
#define PTP_INT_IO_FE_SHIFT_ (24)
|
||||
@ -364,9 +389,17 @@
|
||||
#define PTP_INT_IO_RE_MASK_ GENMASK(23, 16)
|
||||
#define PTP_INT_IO_RE_SHIFT_ (16)
|
||||
#define PTP_INT_IO_RE_SET_(channel) BIT(16 + (channel))
|
||||
#define PTP_INT_TX_TS_OVRFL_INT_ BIT(14)
|
||||
#define PTP_INT_TX_SWTS_ERR_INT_ BIT(13)
|
||||
#define PTP_INT_TX_TS_INT_ BIT(12)
|
||||
#define PTP_INT_RX_TS_OVRFL_INT_ BIT(9)
|
||||
#define PTP_INT_RX_TS_INT_ BIT(8)
|
||||
#define PTP_INT_TIMER_INT_B_ BIT(1)
|
||||
#define PTP_INT_TIMER_INT_A_ BIT(0)
|
||||
#define PTP_INT_EN_SET (0x0A0C)
|
||||
#define PTP_INT_EN_FE_EN_SET_(channel) BIT(24 + (channel))
|
||||
#define PTP_INT_EN_RE_EN_SET_(channel) BIT(16 + (channel))
|
||||
#define PTP_INT_EN_TIMER_SET_(channel) BIT(channel)
|
||||
#define PTP_INT_EN_CLR (0x0A10)
|
||||
#define PTP_INT_EN_FE_EN_CLR_(channel) BIT(24 + (channel))
|
||||
#define PTP_INT_EN_RE_EN_CLR_(channel) BIT(16 + (channel))
|
||||
|
@ -689,6 +689,215 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lan743x_ptp_io_perout_off(struct lan743x_adapter *adapter,
|
||||
u32 index)
|
||||
{
|
||||
struct lan743x_ptp *ptp = &adapter->ptp;
|
||||
int perout_pin;
|
||||
int event_ch;
|
||||
u32 gen_cfg;
|
||||
int val;
|
||||
|
||||
event_ch = ptp->ptp_io_perout[index];
|
||||
if (event_ch >= 0) {
|
||||
/* set target to far in the future, effectively disabling it */
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_SEC_X(event_ch),
|
||||
0xFFFF0000);
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_NS_X(event_ch),
|
||||
0);
|
||||
|
||||
gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG);
|
||||
gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_
|
||||
(event_ch));
|
||||
gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch));
|
||||
gen_cfg |= HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch);
|
||||
lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg);
|
||||
if (event_ch)
|
||||
lan743x_csr_write(adapter, PTP_INT_STS,
|
||||
PTP_INT_TIMER_INT_B_);
|
||||
else
|
||||
lan743x_csr_write(adapter, PTP_INT_STS,
|
||||
PTP_INT_TIMER_INT_A_);
|
||||
lan743x_ptp_release_event_ch(adapter, event_ch);
|
||||
ptp->ptp_io_perout[index] = -1;
|
||||
}
|
||||
|
||||
perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index);
|
||||
|
||||
/* Deselect Event output */
|
||||
val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG);
|
||||
|
||||
/* Disables the output of Local Time Target compare events */
|
||||
val &= ~PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin);
|
||||
lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val);
|
||||
|
||||
/* Configured as an opendrain driver*/
|
||||
val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG);
|
||||
val &= ~PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin);
|
||||
lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val);
|
||||
/* Dummy read to make sure write operation success */
|
||||
val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG);
|
||||
}
|
||||
|
||||
static int lan743x_ptp_io_perout(struct lan743x_adapter *adapter, int on,
|
||||
struct ptp_perout_request *perout_request)
|
||||
{
|
||||
struct lan743x_ptp *ptp = &adapter->ptp;
|
||||
u32 period_sec, period_nsec;
|
||||
u32 start_sec, start_nsec;
|
||||
u32 pulse_sec, pulse_nsec;
|
||||
int pulse_width;
|
||||
int perout_pin;
|
||||
int event_ch;
|
||||
u32 gen_cfg;
|
||||
u32 index;
|
||||
int val;
|
||||
|
||||
index = perout_request->index;
|
||||
event_ch = ptp->ptp_io_perout[index];
|
||||
|
||||
if (on) {
|
||||
perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, index);
|
||||
if (perout_pin < 0)
|
||||
return -EBUSY;
|
||||
} else {
|
||||
lan743x_ptp_io_perout_off(adapter, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (event_ch >= LAN743X_PTP_N_EVENT_CHAN) {
|
||||
/* already on, turn off first */
|
||||
lan743x_ptp_io_perout_off(adapter, index);
|
||||
}
|
||||
|
||||
event_ch = lan743x_ptp_reserve_event_ch(adapter, index);
|
||||
if (event_ch < 0) {
|
||||
netif_warn(adapter, drv, adapter->netdev,
|
||||
"Failed to reserve event channel %d for PEROUT\n",
|
||||
index);
|
||||
goto failed;
|
||||
}
|
||||
ptp->ptp_io_perout[index] = event_ch;
|
||||
|
||||
if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) {
|
||||
pulse_sec = perout_request->on.sec;
|
||||
pulse_sec += perout_request->on.nsec / 1000000000;
|
||||
pulse_nsec = perout_request->on.nsec % 1000000000;
|
||||
} else {
|
||||
pulse_sec = perout_request->period.sec;
|
||||
pulse_sec += perout_request->period.nsec / 1000000000;
|
||||
pulse_nsec = perout_request->period.nsec % 1000000000;
|
||||
}
|
||||
|
||||
if (pulse_sec == 0) {
|
||||
if (pulse_nsec >= 400000000) {
|
||||
pulse_width = PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
|
||||
} else if (pulse_nsec >= 200000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100MS_;
|
||||
} else if (pulse_nsec >= 100000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50MS_;
|
||||
} else if (pulse_nsec >= 20000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_;
|
||||
} else if (pulse_nsec >= 10000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5MS_;
|
||||
} else if (pulse_nsec >= 2000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_;
|
||||
} else if (pulse_nsec >= 1000000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500US_;
|
||||
} else if (pulse_nsec >= 200000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_;
|
||||
} else if (pulse_nsec >= 100000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_50US_;
|
||||
} else if (pulse_nsec >= 20000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_;
|
||||
} else if (pulse_nsec >= 10000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_5US_;
|
||||
} else if (pulse_nsec >= 2000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_1US_;
|
||||
} else if (pulse_nsec >= 1000) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_500NS_;
|
||||
} else if (pulse_nsec >= 200) {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_;
|
||||
} else {
|
||||
netif_warn(adapter, drv, adapter->netdev,
|
||||
"perout period too small, min is 200nS\n");
|
||||
goto failed;
|
||||
}
|
||||
} else {
|
||||
pulse_width = HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_;
|
||||
}
|
||||
|
||||
/* turn off by setting target far in future */
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_SEC_X(event_ch),
|
||||
0xFFFF0000);
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_NS_X(event_ch), 0);
|
||||
|
||||
/* Configure to pulse every period */
|
||||
gen_cfg = lan743x_csr_read(adapter, HS_PTP_GENERAL_CONFIG);
|
||||
gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(event_ch));
|
||||
gen_cfg |= HS_PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_
|
||||
(event_ch, pulse_width);
|
||||
gen_cfg |= HS_PTP_GENERAL_CONFIG_EVENT_POL_X_(event_ch);
|
||||
gen_cfg &= ~(HS_PTP_GENERAL_CONFIG_RELOAD_ADD_X_(event_ch));
|
||||
lan743x_csr_write(adapter, HS_PTP_GENERAL_CONFIG, gen_cfg);
|
||||
|
||||
/* set the reload to one toggle cycle */
|
||||
period_sec = perout_request->period.sec;
|
||||
period_sec += perout_request->period.nsec / 1000000000;
|
||||
period_nsec = perout_request->period.nsec % 1000000000;
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_RELOAD_SEC_X(event_ch),
|
||||
period_sec);
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_RELOAD_NS_X(event_ch),
|
||||
period_nsec);
|
||||
|
||||
start_sec = perout_request->start.sec;
|
||||
start_sec += perout_request->start.nsec / 1000000000;
|
||||
start_nsec = perout_request->start.nsec % 1000000000;
|
||||
|
||||
/* set the start time */
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_SEC_X(event_ch),
|
||||
start_sec);
|
||||
lan743x_csr_write(adapter,
|
||||
PTP_CLOCK_TARGET_NS_X(event_ch),
|
||||
start_nsec);
|
||||
|
||||
/* Enable LTC Target Read */
|
||||
val = lan743x_csr_read(adapter, PTP_CMD_CTL);
|
||||
val |= PTP_CMD_CTL_PTP_LTC_TARGET_READ_;
|
||||
lan743x_csr_write(adapter, PTP_CMD_CTL, val);
|
||||
|
||||
/* Configure as an push/pull driver */
|
||||
val = lan743x_csr_read(adapter, PTP_IO_PIN_CFG);
|
||||
val |= PTP_IO_PIN_CFG_OBUF_TYPE_(perout_pin);
|
||||
lan743x_csr_write(adapter, PTP_IO_PIN_CFG, val);
|
||||
|
||||
/* Select Event output */
|
||||
val = lan743x_csr_read(adapter, PTP_IO_EVENT_OUTPUT_CFG);
|
||||
if (event_ch)
|
||||
/* Channel B as the output */
|
||||
val |= PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin);
|
||||
else
|
||||
/* Channel A as the output */
|
||||
val &= ~PTP_IO_EVENT_OUTPUT_CFG_SEL_(perout_pin);
|
||||
|
||||
/* Enables the output of Local Time Target compare events */
|
||||
val |= PTP_IO_EVENT_OUTPUT_CFG_EN_(perout_pin);
|
||||
lan743x_csr_write(adapter, PTP_IO_EVENT_OUTPUT_CFG, val);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
lan743x_ptp_io_perout_off(adapter, index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void lan743x_ptp_io_extts_off(struct lan743x_adapter *adapter,
|
||||
u32 index)
|
||||
{
|
||||
@ -812,9 +1021,14 @@ static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
|
||||
&request->extts);
|
||||
return -EINVAL;
|
||||
case PTP_CLK_REQ_PEROUT:
|
||||
if (request->perout.index < ptpci->n_per_out)
|
||||
return lan743x_ptp_perout(adapter, on,
|
||||
if (request->perout.index < ptpci->n_per_out) {
|
||||
if (adapter->is_pci11x1x)
|
||||
return lan743x_ptp_io_perout(adapter, on,
|
||||
&request->perout);
|
||||
else
|
||||
return lan743x_ptp_perout(adapter, on,
|
||||
&request->perout);
|
||||
}
|
||||
return -EINVAL;
|
||||
case PTP_CLK_REQ_PPS:
|
||||
return -EINVAL;
|
||||
|
@ -80,6 +80,7 @@ struct lan743x_ptp {
|
||||
|
||||
unsigned long used_event_ch;
|
||||
struct lan743x_ptp_perout perout[LAN743X_PTP_N_PEROUT];
|
||||
int ptp_io_perout[LAN743X_PTP_N_PEROUT]; /* PTP event channel (0=channel A, 1=channel B) */
|
||||
struct lan743x_extts extts[LAN743X_PTP_N_EXTTS];
|
||||
|
||||
bool leds_multiplexed;
|
||||
|
Loading…
Reference in New Issue
Block a user