Skip to content

Commit 7d2eba0

Browse files
committed
Merge branch 'add-perout-library-for-rds-ptp-supported-phys'
Divya Koppera says: ==================== Add PEROUT library for RDS PTP supported phys Adds support for PEROUT library, where phy can generate periodic output signal on supported pin out. ==================== Link: https://patch.msgid.link/20250115090634.12941-1-divya.koppera@microchip.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 3030e3d + 9335919 commit 7d2eba0

File tree

3 files changed

+307
-1
lines changed

3 files changed

+307
-1
lines changed

drivers/net/phy/microchip_rds_ptp.c

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,243 @@ static int mchp_rds_phy_set_bits_mmd(struct mchp_rds_ptp_clock *clock,
5454
return phy_set_bits_mmd(phydev, PTP_MMD(clock), addr, val);
5555
}
5656

57+
static int mchp_get_pulsewidth(struct phy_device *phydev,
58+
struct ptp_perout_request *perout_request,
59+
int *pulse_width)
60+
{
61+
struct timespec64 ts_period;
62+
s64 ts_on_nsec, period_nsec;
63+
struct timespec64 ts_on;
64+
static const s64 sup_on_necs[] = {
65+
100, /* 100ns */
66+
500, /* 500ns */
67+
1000, /* 1us */
68+
5000, /* 5us */
69+
10000, /* 10us */
70+
50000, /* 50us */
71+
100000, /* 100us */
72+
500000, /* 500us */
73+
1000000, /* 1ms */
74+
5000000, /* 5ms */
75+
10000000, /* 10ms */
76+
50000000, /* 50ms */
77+
100000000, /* 100ms */
78+
200000000, /* 200ms */
79+
};
80+
81+
ts_period.tv_sec = perout_request->period.sec;
82+
ts_period.tv_nsec = perout_request->period.nsec;
83+
84+
ts_on.tv_sec = perout_request->on.sec;
85+
ts_on.tv_nsec = perout_request->on.nsec;
86+
ts_on_nsec = timespec64_to_ns(&ts_on);
87+
period_nsec = timespec64_to_ns(&ts_period);
88+
89+
if (period_nsec < 200) {
90+
phydev_warn(phydev, "perout period small, minimum is 200ns\n");
91+
return -EOPNOTSUPP;
92+
}
93+
94+
for (int i = 0; i < ARRAY_SIZE(sup_on_necs); i++) {
95+
if (ts_on_nsec <= sup_on_necs[i]) {
96+
*pulse_width = i;
97+
break;
98+
}
99+
}
100+
101+
phydev_info(phydev, "pulse width is %d\n", *pulse_width);
102+
return 0;
103+
}
104+
105+
static int mchp_general_event_config(struct mchp_rds_ptp_clock *clock,
106+
int pulse_width)
107+
{
108+
int general_config;
109+
110+
general_config = mchp_rds_phy_read_mmd(clock, MCHP_RDS_PTP_GEN_CFG,
111+
MCHP_RDS_PTP_CLOCK);
112+
if (general_config < 0)
113+
return general_config;
114+
115+
general_config &= ~MCHP_RDS_PTP_GEN_CFG_LTC_EVT_MASK;
116+
general_config |= MCHP_RDS_PTP_GEN_CFG_LTC_EVT_SET(pulse_width);
117+
general_config &= ~MCHP_RDS_PTP_GEN_CFG_RELOAD_ADD;
118+
general_config |= MCHP_RDS_PTP_GEN_CFG_POLARITY;
119+
120+
return mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_GEN_CFG,
121+
MCHP_RDS_PTP_CLOCK, general_config);
122+
}
123+
124+
static int mchp_set_clock_reload(struct mchp_rds_ptp_clock *clock,
125+
s64 period_sec, u32 period_nsec)
126+
{
127+
int rc;
128+
129+
rc = mchp_rds_phy_write_mmd(clock,
130+
MCHP_RDS_PTP_CLK_TRGT_RELOAD_SEC_LO,
131+
MCHP_RDS_PTP_CLOCK,
132+
lower_16_bits(period_sec));
133+
if (rc < 0)
134+
return rc;
135+
136+
rc = mchp_rds_phy_write_mmd(clock,
137+
MCHP_RDS_PTP_CLK_TRGT_RELOAD_SEC_HI,
138+
MCHP_RDS_PTP_CLOCK,
139+
upper_16_bits(period_sec));
140+
if (rc < 0)
141+
return rc;
142+
143+
rc = mchp_rds_phy_write_mmd(clock,
144+
MCHP_RDS_PTP_CLK_TRGT_RELOAD_NS_LO,
145+
MCHP_RDS_PTP_CLOCK,
146+
lower_16_bits(period_nsec));
147+
if (rc < 0)
148+
return rc;
149+
150+
return mchp_rds_phy_write_mmd(clock,
151+
MCHP_RDS_PTP_CLK_TRGT_RELOAD_NS_HI,
152+
MCHP_RDS_PTP_CLOCK,
153+
upper_16_bits(period_nsec) & 0x3fff);
154+
}
155+
156+
static int mchp_set_clock_target(struct mchp_rds_ptp_clock *clock,
157+
s64 start_sec, u32 start_nsec)
158+
{
159+
int rc;
160+
161+
/* Set the start time */
162+
rc = mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_CLK_TRGT_SEC_LO,
163+
MCHP_RDS_PTP_CLOCK,
164+
lower_16_bits(start_sec));
165+
if (rc < 0)
166+
return rc;
167+
168+
rc = mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_CLK_TRGT_SEC_HI,
169+
MCHP_RDS_PTP_CLOCK,
170+
upper_16_bits(start_sec));
171+
if (rc < 0)
172+
return rc;
173+
174+
rc = mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_CLK_TRGT_NS_LO,
175+
MCHP_RDS_PTP_CLOCK,
176+
lower_16_bits(start_nsec));
177+
if (rc < 0)
178+
return rc;
179+
180+
return mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_CLK_TRGT_NS_HI,
181+
MCHP_RDS_PTP_CLOCK,
182+
upper_16_bits(start_nsec) & 0x3fff);
183+
}
184+
185+
static int mchp_rds_ptp_perout_off(struct mchp_rds_ptp_clock *clock)
186+
{
187+
u16 general_config;
188+
int rc;
189+
190+
/* Set target to too far in the future, effectively disabling it */
191+
rc = mchp_set_clock_target(clock, 0xFFFFFFFF, 0);
192+
if (rc < 0)
193+
return rc;
194+
195+
general_config = mchp_rds_phy_read_mmd(clock, MCHP_RDS_PTP_GEN_CFG,
196+
MCHP_RDS_PTP_CLOCK);
197+
general_config |= MCHP_RDS_PTP_GEN_CFG_RELOAD_ADD;
198+
rc = mchp_rds_phy_write_mmd(clock, MCHP_RDS_PTP_GEN_CFG,
199+
MCHP_RDS_PTP_CLOCK, general_config);
200+
if (rc < 0)
201+
return rc;
202+
203+
clock->mchp_rds_ptp_event = -1;
204+
205+
return 0;
206+
}
207+
208+
static bool mchp_get_event(struct mchp_rds_ptp_clock *clock, int pin)
209+
{
210+
if (clock->mchp_rds_ptp_event < 0 && pin == clock->event_pin) {
211+
clock->mchp_rds_ptp_event = pin;
212+
return true;
213+
}
214+
215+
return false;
216+
}
217+
218+
static int mchp_rds_ptp_perout(struct ptp_clock_info *ptpci,
219+
struct ptp_perout_request *perout, int on)
220+
{
221+
struct mchp_rds_ptp_clock *clock = container_of(ptpci,
222+
struct mchp_rds_ptp_clock,
223+
caps);
224+
struct phy_device *phydev = clock->phydev;
225+
int ret, event_pin, pulsewidth;
226+
227+
/* Reject requests with unsupported flags */
228+
if (perout->flags & ~PTP_PEROUT_DUTY_CYCLE)
229+
return -EOPNOTSUPP;
230+
231+
event_pin = ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT,
232+
perout->index);
233+
if (event_pin != clock->event_pin)
234+
return -EINVAL;
235+
236+
if (!on) {
237+
ret = mchp_rds_ptp_perout_off(clock);
238+
return ret;
239+
}
240+
241+
if (!mchp_get_event(clock, event_pin))
242+
return -EINVAL;
243+
244+
ret = mchp_get_pulsewidth(phydev, perout, &pulsewidth);
245+
if (ret < 0)
246+
return ret;
247+
248+
/* Configure to pulse every period */
249+
ret = mchp_general_event_config(clock, pulsewidth);
250+
if (ret < 0)
251+
return ret;
252+
253+
ret = mchp_set_clock_target(clock, perout->start.sec,
254+
perout->start.nsec);
255+
if (ret < 0)
256+
return ret;
257+
258+
return mchp_set_clock_reload(clock, perout->period.sec,
259+
perout->period.nsec);
260+
}
261+
262+
static int mchp_rds_ptpci_enable(struct ptp_clock_info *ptpci,
263+
struct ptp_clock_request *request, int on)
264+
{
265+
switch (request->type) {
266+
case PTP_CLK_REQ_PEROUT:
267+
return mchp_rds_ptp_perout(ptpci, &request->perout, on);
268+
default:
269+
return -EINVAL;
270+
}
271+
}
272+
273+
static int mchp_rds_ptpci_verify(struct ptp_clock_info *ptpci, unsigned int pin,
274+
enum ptp_pin_function func, unsigned int chan)
275+
{
276+
struct mchp_rds_ptp_clock *clock = container_of(ptpci,
277+
struct mchp_rds_ptp_clock,
278+
caps);
279+
280+
if (!(pin == clock->event_pin && chan == 0))
281+
return -1;
282+
283+
switch (func) {
284+
case PTP_PF_NONE:
285+
case PTP_PF_PEROUT:
286+
break;
287+
default:
288+
return -1;
289+
}
290+
291+
return 0;
292+
}
293+
57294
static int mchp_rds_ptp_flush_fifo(struct mchp_rds_ptp_clock *clock,
58295
enum mchp_rds_ptp_fifo_dir dir)
59296
{
@@ -479,6 +716,16 @@ static int mchp_rds_ptp_ltc_adjtime(struct ptp_clock_info *info, s64 delta)
479716
MCHP_RDS_PTP_CMD_CTL_LTC_STEP_NSEC);
480717
}
481718

719+
mutex_unlock(&clock->ptp_lock);
720+
info->gettime64(info, &ts);
721+
mutex_lock(&clock->ptp_lock);
722+
723+
/* Target update is required for pulse generation on events that
724+
* are enabled
725+
*/
726+
if (clock->mchp_rds_ptp_event >= 0)
727+
mchp_set_clock_target(clock,
728+
ts.tv_sec + MCHP_RDS_PTP_BUFFER_TIME, 0);
482729
out_unlock:
483730
mutex_unlock(&clock->ptp_lock);
484731

@@ -989,16 +1236,37 @@ struct mchp_rds_ptp_clock *mchp_rds_ptp_probe(struct phy_device *phydev, u8 mmd,
9891236
clock->mmd = mmd;
9901237

9911238
mutex_init(&clock->ptp_lock);
1239+
clock->pin_config = devm_kmalloc_array(&phydev->mdio.dev,
1240+
MCHP_RDS_PTP_N_PIN,
1241+
sizeof(*clock->pin_config),
1242+
GFP_KERNEL);
1243+
if (!clock->pin_config)
1244+
return ERR_PTR(-ENOMEM);
1245+
1246+
for (int i = 0; i < MCHP_RDS_PTP_N_PIN; ++i) {
1247+
struct ptp_pin_desc *p = &clock->pin_config[i];
1248+
1249+
memset(p, 0, sizeof(*p));
1250+
snprintf(p->name, sizeof(p->name), "pin%d", i);
1251+
p->index = i;
1252+
p->func = PTP_PF_NONE;
1253+
}
9921254
/* Register PTP clock */
9931255
clock->caps.owner = THIS_MODULE;
9941256
snprintf(clock->caps.name, 30, "%s", phydev->drv->name);
9951257
clock->caps.max_adj = MCHP_RDS_PTP_MAX_ADJ;
9961258
clock->caps.n_ext_ts = 0;
9971259
clock->caps.pps = 0;
1260+
clock->caps.n_pins = MCHP_RDS_PTP_N_PIN;
1261+
clock->caps.n_per_out = MCHP_RDS_PTP_N_PEROUT;
1262+
clock->caps.pin_config = clock->pin_config;
9981263
clock->caps.adjfine = mchp_rds_ptp_ltc_adjfine;
9991264
clock->caps.adjtime = mchp_rds_ptp_ltc_adjtime;
10001265
clock->caps.gettime64 = mchp_rds_ptp_ltc_gettime64;
10011266
clock->caps.settime64 = mchp_rds_ptp_ltc_settime64;
1267+
clock->caps.enable = mchp_rds_ptpci_enable;
1268+
clock->caps.verify = mchp_rds_ptpci_verify;
1269+
clock->caps.getcrosststamp = NULL;
10021270
clock->ptp_clock = ptp_clock_register(&clock->caps,
10031271
&phydev->mdio.dev);
10041272
if (IS_ERR(clock->ptp_clock))
@@ -1021,6 +1289,8 @@ struct mchp_rds_ptp_clock *mchp_rds_ptp_probe(struct phy_device *phydev, u8 mmd,
10211289

10221290
phydev->mii_ts = &clock->mii_ts;
10231291

1292+
clock->mchp_rds_ptp_event = -1;
1293+
10241294
/* Timestamp selected by default to keep legacy API */
10251295
phydev->default_timestamp = true;
10261296

drivers/net/phy/microchip_rds_ptp.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@
130130
#define MCHP_RDS_PTP_TSU_HARD_RESET 0xc1
131131
#define MCHP_RDS_PTP_TSU_HARDRESET BIT(0)
132132

133+
#define MCHP_RDS_PTP_CLK_TRGT_SEC_HI 0x15
134+
#define MCHP_RDS_PTP_CLK_TRGT_SEC_LO 0x16
135+
#define MCHP_RDS_PTP_CLK_TRGT_NS_HI 0x17
136+
#define MCHP_RDS_PTP_CLK_TRGT_NS_LO 0x18
137+
138+
#define MCHP_RDS_PTP_CLK_TRGT_RELOAD_SEC_HI 0x19
139+
#define MCHP_RDS_PTP_CLK_TRGT_RELOAD_SEC_LO 0x1a
140+
#define MCHP_RDS_PTP_CLK_TRGT_RELOAD_NS_HI 0x1b
141+
#define MCHP_RDS_PTP_CLK_TRGT_RELOAD_NS_LO 0x1c
142+
143+
#define MCHP_RDS_PTP_GEN_CFG 0x01
144+
#define MCHP_RDS_PTP_GEN_CFG_LTC_EVT_MASK GENMASK(11, 8)
145+
146+
#define MCHP_RDS_PTP_GEN_CFG_LTC_EVT_SET(value) (((value) & 0xF) << 4)
147+
#define MCHP_RDS_PTP_GEN_CFG_RELOAD_ADD BIT(0)
148+
#define MCHP_RDS_PTP_GEN_CFG_POLARITY BIT(1)
149+
133150
/* Represents 1ppm adjustment in 2^32 format with
134151
* each nsec contains 4 clock cycles in 250MHz.
135152
* The value is calculated as following: (1/1000000)/((2^-32)/4)
@@ -138,6 +155,10 @@
138155
#define MCHP_RDS_PTP_FIFO_SIZE 8
139156
#define MCHP_RDS_PTP_MAX_ADJ 31249999
140157

158+
#define MCHP_RDS_PTP_BUFFER_TIME 2
159+
#define MCHP_RDS_PTP_N_PIN 4
160+
#define MCHP_RDS_PTP_N_PEROUT 1
161+
141162
#define BASE_CLK(p) ((p)->clk_base_addr)
142163
#define BASE_PORT(p) ((p)->port_base_addr)
143164
#define PTP_MMD(p) ((p)->mmd)
@@ -176,6 +197,9 @@ struct mchp_rds_ptp_clock {
176197
/* Lock for phc */
177198
struct mutex ptp_lock;
178199
u8 mmd;
200+
int mchp_rds_ptp_event;
201+
int event_pin;
202+
struct ptp_pin_desc *pin_config;
179203
};
180204

181205
struct mchp_rds_ptp_rx_ts {

drivers/net/phy/microchip_t1.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@
238238
#define LAN887X_INT_MSK_LINK_UP_MSK BIT(1)
239239
#define LAN887X_INT_MSK_LINK_DOWN_MSK BIT(0)
240240

241+
#define LAN887X_MX_CHIP_TOP_REG_CONTROL1 0xF002
242+
#define LAN887X_MX_CHIP_TOP_REG_CONTROL1_EVT_EN BIT(8)
243+
241244
#define LAN887X_MX_CHIP_TOP_LINK_MSK (LAN887X_INT_MSK_LINK_UP_MSK |\
242245
LAN887X_INT_MSK_LINK_DOWN_MSK)
243246

@@ -1286,6 +1289,15 @@ static int lan887x_phy_init(struct phy_device *phydev)
12861289
if (IS_ERR(priv->clock))
12871290
return PTR_ERR(priv->clock);
12881291

1292+
/* Enable pin mux for EVT */
1293+
phy_modify_mmd(phydev, MDIO_MMD_VEND1,
1294+
LAN887X_MX_CHIP_TOP_REG_CONTROL1,
1295+
LAN887X_MX_CHIP_TOP_REG_CONTROL1_EVT_EN,
1296+
LAN887X_MX_CHIP_TOP_REG_CONTROL1_EVT_EN);
1297+
1298+
/* Initialize pin numbers specific to PEROUT */
1299+
priv->clock->event_pin = 3;
1300+
12891301
priv->init_done = true;
12901302
}
12911303

@@ -2154,7 +2166,7 @@ static struct phy_driver microchip_t1_phy_driver[] = {
21542166

21552167
module_phy_driver(microchip_t1_phy_driver);
21562168

2157-
static const struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
2169+
static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
21582170
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
21592171
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
21602172
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) },

0 commit comments

Comments
 (0)