mvpp2_tai.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Marvell PP2.2 TAI support
  4. *
  5. * Note:
  6. * Do NOT use the event capture support.
  7. * Do Not even set the MPP muxes to allow PTP_EVENT_REQ to be used.
  8. * It will disrupt the operation of this driver, and there is nothing
  9. * that this driver can do to prevent that. Even using PTP_EVENT_REQ
  10. * as an output will be seen as a trigger input, which can't be masked.
  11. * When ever a trigger input is seen, the action in the TCFCR0_TCF
  12. * field will be performed - whether it is a set, increment, decrement
  13. * read, or frequency update.
  14. *
  15. * Other notes (useful, not specified in the documentation):
  16. * - PTP_PULSE_OUT (PTP_EVENT_REQ MPP)
  17. * It looks like the hardware can't generate a pulse at nsec=0. (The
  18. * output doesn't trigger if the nsec field is zero.)
  19. * Note: when configured as an output via the register at 0xfX441120,
  20. * the input is still very much alive, and will trigger the current TCF
  21. * function.
  22. * - PTP_CLK_OUT (PTP_TRIG_GEN MPP)
  23. * This generates a "PPS" signal determined by the CCC registers. It
  24. * seems this is not aligned to the TOD counter in any way (it may be
  25. * initially, but if you specify a non-round second interval, it won't,
  26. * and you can't easily get it back.)
  27. * - PTP_PCLK_OUT
  28. * This generates a 50% duty cycle clock based on the TOD counter, and
  29. * seems it can be set to any period of 1ns resolution. It is probably
  30. * limited by the TOD step size. Its period is defined by the PCLK_CCC
  31. * registers. Again, its alignment to the second is questionable.
  32. *
  33. * Consequently, we support none of these.
  34. */
  35. #include <linux/io.h>
  36. #include <linux/ptp_clock_kernel.h>
  37. #include <linux/slab.h>
  38. #include "mvpp2.h"
  39. #define CR0_SW_NRESET BIT(0)
  40. #define TCFCR0_PHASE_UPDATE_ENABLE BIT(8)
  41. #define TCFCR0_TCF_MASK (7 << 2)
  42. #define TCFCR0_TCF_UPDATE (0 << 2)
  43. #define TCFCR0_TCF_FREQUPDATE (1 << 2)
  44. #define TCFCR0_TCF_INCREMENT (2 << 2)
  45. #define TCFCR0_TCF_DECREMENT (3 << 2)
  46. #define TCFCR0_TCF_CAPTURE (4 << 2)
  47. #define TCFCR0_TCF_NOP (7 << 2)
  48. #define TCFCR0_TCF_TRIGGER BIT(0)
  49. #define TCSR_CAPTURE_1_VALID BIT(1)
  50. #define TCSR_CAPTURE_0_VALID BIT(0)
  51. struct mvpp2_tai {
  52. struct ptp_clock_info caps;
  53. struct ptp_clock *ptp_clock;
  54. void __iomem *base;
  55. spinlock_t lock;
  56. u64 period; // nanosecond period in 32.32 fixed point
  57. /* This timestamp is updated every two seconds */
  58. struct timespec64 stamp;
  59. };
  60. static void mvpp2_tai_modify(void __iomem *reg, u32 mask, u32 set)
  61. {
  62. u32 val;
  63. val = readl_relaxed(reg) & ~mask;
  64. val |= set & mask;
  65. writel(val, reg);
  66. }
  67. static void mvpp2_tai_write(u32 val, void __iomem *reg)
  68. {
  69. writel_relaxed(val & 0xffff, reg);
  70. }
  71. static u32 mvpp2_tai_read(void __iomem *reg)
  72. {
  73. return readl_relaxed(reg) & 0xffff;
  74. }
  75. static struct mvpp2_tai *ptp_to_tai(struct ptp_clock_info *ptp)
  76. {
  77. return container_of(ptp, struct mvpp2_tai, caps);
  78. }
  79. static void mvpp22_tai_read_ts(struct timespec64 *ts, void __iomem *base)
  80. {
  81. ts->tv_sec = (u64)mvpp2_tai_read(base + 0) << 32 |
  82. mvpp2_tai_read(base + 4) << 16 |
  83. mvpp2_tai_read(base + 8);
  84. ts->tv_nsec = mvpp2_tai_read(base + 12) << 16 |
  85. mvpp2_tai_read(base + 16);
  86. /* Read and discard fractional part */
  87. readl_relaxed(base + 20);
  88. readl_relaxed(base + 24);
  89. }
  90. static void mvpp2_tai_write_tlv(const struct timespec64 *ts, u32 frac,
  91. void __iomem *base)
  92. {
  93. mvpp2_tai_write(ts->tv_sec >> 32, base + MVPP22_TAI_TLV_SEC_HIGH);
  94. mvpp2_tai_write(ts->tv_sec >> 16, base + MVPP22_TAI_TLV_SEC_MED);
  95. mvpp2_tai_write(ts->tv_sec, base + MVPP22_TAI_TLV_SEC_LOW);
  96. mvpp2_tai_write(ts->tv_nsec >> 16, base + MVPP22_TAI_TLV_NANO_HIGH);
  97. mvpp2_tai_write(ts->tv_nsec, base + MVPP22_TAI_TLV_NANO_LOW);
  98. mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
  99. mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
  100. }
  101. static void mvpp2_tai_op(u32 op, void __iomem *base)
  102. {
  103. /* Trigger the operation. Note that an external unmaskable
  104. * event on PTP_EVENT_REQ will also trigger this action.
  105. */
  106. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
  107. TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
  108. op | TCFCR0_TCF_TRIGGER);
  109. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
  110. TCFCR0_TCF_NOP);
  111. }
  112. /* The adjustment has a range of +0.5ns to -0.5ns in 2^32 steps, so has units
  113. * of 2^-32 ns.
  114. *
  115. * units(s) = 1 / (2^32 * 10^9)
  116. * fractional = abs_scaled_ppm / (2^16 * 10^6)
  117. *
  118. * What we want to achieve:
  119. * freq_adjusted = freq_nominal * (1 + fractional)
  120. * freq_delta = freq_adjusted - freq_nominal => positive = faster
  121. * freq_delta = freq_nominal * (1 + fractional) - freq_nominal
  122. * So: freq_delta = freq_nominal * fractional
  123. *
  124. * However, we are dealing with periods, so:
  125. * period_adjusted = period_nominal / (1 + fractional)
  126. * period_delta = period_nominal - period_adjusted => positive = faster
  127. * period_delta = period_nominal * fractional / (1 + fractional)
  128. *
  129. * Hence:
  130. * period_delta = period_nominal * abs_scaled_ppm /
  131. * (2^16 * 10^6 + abs_scaled_ppm)
  132. *
  133. * To avoid overflow, we reduce both sides of the divide operation by a factor
  134. * of 16.
  135. */
  136. static u64 mvpp22_calc_frac_ppm(struct mvpp2_tai *tai, long abs_scaled_ppm)
  137. {
  138. u64 val = tai->period * abs_scaled_ppm >> 4;
  139. return div_u64(val, (1000000 << 12) + (abs_scaled_ppm >> 4));
  140. }
  141. static s32 mvpp22_calc_max_adj(struct mvpp2_tai *tai)
  142. {
  143. return 1000000;
  144. }
  145. static int mvpp22_tai_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
  146. {
  147. struct mvpp2_tai *tai = ptp_to_tai(ptp);
  148. unsigned long flags;
  149. void __iomem *base;
  150. bool neg_adj;
  151. s32 frac;
  152. u64 val;
  153. neg_adj = scaled_ppm < 0;
  154. if (neg_adj)
  155. scaled_ppm = -scaled_ppm;
  156. val = mvpp22_calc_frac_ppm(tai, scaled_ppm);
  157. /* Convert to a signed 32-bit adjustment */
  158. if (neg_adj) {
  159. /* -S32_MIN warns, -val < S32_MIN fails, so go for the easy
  160. * solution.
  161. */
  162. if (val > 0x80000000)
  163. return -ERANGE;
  164. frac = -val;
  165. } else {
  166. if (val > S32_MAX)
  167. return -ERANGE;
  168. frac = val;
  169. }
  170. base = tai->base;
  171. spin_lock_irqsave(&tai->lock, flags);
  172. mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
  173. mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
  174. mvpp2_tai_op(TCFCR0_TCF_FREQUPDATE, base);
  175. spin_unlock_irqrestore(&tai->lock, flags);
  176. return 0;
  177. }
  178. static int mvpp22_tai_adjtime(struct ptp_clock_info *ptp, s64 delta)
  179. {
  180. struct mvpp2_tai *tai = ptp_to_tai(ptp);
  181. struct timespec64 ts;
  182. unsigned long flags;
  183. void __iomem *base;
  184. u32 tcf;
  185. /* We can't deal with S64_MIN */
  186. if (delta == S64_MIN)
  187. return -ERANGE;
  188. if (delta < 0) {
  189. delta = -delta;
  190. tcf = TCFCR0_TCF_DECREMENT;
  191. } else {
  192. tcf = TCFCR0_TCF_INCREMENT;
  193. }
  194. ts = ns_to_timespec64(delta);
  195. base = tai->base;
  196. spin_lock_irqsave(&tai->lock, flags);
  197. mvpp2_tai_write_tlv(&ts, 0, base);
  198. mvpp2_tai_op(tcf, base);
  199. spin_unlock_irqrestore(&tai->lock, flags);
  200. return 0;
  201. }
  202. static int mvpp22_tai_gettimex64(struct ptp_clock_info *ptp,
  203. struct timespec64 *ts,
  204. struct ptp_system_timestamp *sts)
  205. {
  206. struct mvpp2_tai *tai = ptp_to_tai(ptp);
  207. unsigned long flags;
  208. void __iomem *base;
  209. u32 tcsr;
  210. int ret;
  211. base = tai->base;
  212. spin_lock_irqsave(&tai->lock, flags);
  213. /* XXX: the only way to read the PTP time is for the CPU to trigger
  214. * an event. However, there is no way to distinguish between the CPU
  215. * triggered event, and an external event on PTP_EVENT_REQ. So this
  216. * is incompatible with external use of PTP_EVENT_REQ.
  217. */
  218. ptp_read_system_prets(sts);
  219. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
  220. TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
  221. TCFCR0_TCF_CAPTURE | TCFCR0_TCF_TRIGGER);
  222. ptp_read_system_postts(sts);
  223. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
  224. TCFCR0_TCF_NOP);
  225. tcsr = readl(base + MVPP22_TAI_TCSR);
  226. if (tcsr & TCSR_CAPTURE_1_VALID) {
  227. mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV1_SEC_HIGH);
  228. ret = 0;
  229. } else if (tcsr & TCSR_CAPTURE_0_VALID) {
  230. mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV0_SEC_HIGH);
  231. ret = 0;
  232. } else {
  233. /* We don't seem to have a reading... */
  234. ret = -EBUSY;
  235. }
  236. spin_unlock_irqrestore(&tai->lock, flags);
  237. return ret;
  238. }
  239. static int mvpp22_tai_settime64(struct ptp_clock_info *ptp,
  240. const struct timespec64 *ts)
  241. {
  242. struct mvpp2_tai *tai = ptp_to_tai(ptp);
  243. unsigned long flags;
  244. void __iomem *base;
  245. base = tai->base;
  246. spin_lock_irqsave(&tai->lock, flags);
  247. mvpp2_tai_write_tlv(ts, 0, base);
  248. /* Trigger an update to load the value from the TLV registers
  249. * into the TOD counter. Note that an external unmaskable event on
  250. * PTP_EVENT_REQ will also trigger this action.
  251. */
  252. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
  253. TCFCR0_PHASE_UPDATE_ENABLE |
  254. TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
  255. TCFCR0_TCF_UPDATE | TCFCR0_TCF_TRIGGER);
  256. mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
  257. TCFCR0_TCF_NOP);
  258. spin_unlock_irqrestore(&tai->lock, flags);
  259. return 0;
  260. }
  261. static long mvpp22_tai_aux_work(struct ptp_clock_info *ptp)
  262. {
  263. struct mvpp2_tai *tai = ptp_to_tai(ptp);
  264. mvpp22_tai_gettimex64(ptp, &tai->stamp, NULL);
  265. return msecs_to_jiffies(2000);
  266. }
  267. static void mvpp22_tai_set_step(struct mvpp2_tai *tai)
  268. {
  269. void __iomem *base = tai->base;
  270. u32 nano, frac;
  271. nano = upper_32_bits(tai->period);
  272. frac = lower_32_bits(tai->period);
  273. /* As the fractional nanosecond is a signed offset, if the MSB (sign)
  274. * bit is set, we have to increment the whole nanoseconds.
  275. */
  276. if (frac >= 0x80000000)
  277. nano += 1;
  278. mvpp2_tai_write(nano, base + MVPP22_TAI_TOD_STEP_NANO_CR);
  279. mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TOD_STEP_FRAC_HIGH);
  280. mvpp2_tai_write(frac, base + MVPP22_TAI_TOD_STEP_FRAC_LOW);
  281. }
  282. static void mvpp22_tai_init(struct mvpp2_tai *tai)
  283. {
  284. void __iomem *base = tai->base;
  285. mvpp22_tai_set_step(tai);
  286. /* Release the TAI reset */
  287. mvpp2_tai_modify(base + MVPP22_TAI_CR0, CR0_SW_NRESET, CR0_SW_NRESET);
  288. }
  289. int mvpp22_tai_ptp_clock_index(struct mvpp2_tai *tai)
  290. {
  291. return ptp_clock_index(tai->ptp_clock);
  292. }
  293. void mvpp22_tai_tstamp(struct mvpp2_tai *tai, u32 tstamp,
  294. struct skb_shared_hwtstamps *hwtstamp)
  295. {
  296. struct timespec64 ts;
  297. int delta;
  298. /* The tstamp consists of 2 bits of seconds and 30 bits of nanoseconds.
  299. * We use our stored timestamp (tai->stamp) to form a full timestamp,
  300. * and we must read the seconds exactly once.
  301. */
  302. ts.tv_sec = READ_ONCE(tai->stamp.tv_sec);
  303. ts.tv_nsec = tstamp & 0x3fffffff;
  304. /* Calculate the delta in seconds between our stored timestamp and
  305. * the value read from the queue. Allow timestamps one second in the
  306. * past, otherwise consider them to be in the future.
  307. */
  308. delta = ((tstamp >> 30) - (ts.tv_sec & 3)) & 3;
  309. if (delta == 3)
  310. delta -= 4;
  311. ts.tv_sec += delta;
  312. memset(hwtstamp, 0, sizeof(*hwtstamp));
  313. hwtstamp->hwtstamp = timespec64_to_ktime(ts);
  314. }
  315. void mvpp22_tai_start(struct mvpp2_tai *tai)
  316. {
  317. long delay;
  318. delay = mvpp22_tai_aux_work(&tai->caps);
  319. ptp_schedule_worker(tai->ptp_clock, delay);
  320. }
  321. void mvpp22_tai_stop(struct mvpp2_tai *tai)
  322. {
  323. ptp_cancel_worker_sync(tai->ptp_clock);
  324. }
  325. static void mvpp22_tai_remove(void *priv)
  326. {
  327. struct mvpp2_tai *tai = priv;
  328. if (!IS_ERR(tai->ptp_clock))
  329. ptp_clock_unregister(tai->ptp_clock);
  330. }
  331. int mvpp22_tai_probe(struct device *dev, struct mvpp2 *priv)
  332. {
  333. struct mvpp2_tai *tai;
  334. int ret;
  335. tai = devm_kzalloc(dev, sizeof(*tai), GFP_KERNEL);
  336. if (!tai)
  337. return -ENOMEM;
  338. spin_lock_init(&tai->lock);
  339. tai->base = priv->iface_base;
  340. /* The step size consists of three registers - a 16-bit nanosecond step
  341. * size, and a 32-bit fractional nanosecond step size split over two
  342. * registers. The fractional nanosecond step size has units of 2^-32ns.
  343. *
  344. * To calculate this, we calculate:
  345. * (10^9 + freq / 2) / (freq * 2^-32)
  346. * which gives us the nanosecond step to the nearest integer in 16.32
  347. * fixed point format, and the fractional part of the step size with
  348. * the MSB inverted. With rounding of the fractional nanosecond, and
  349. * simplification, this becomes:
  350. * (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
  351. *
  352. * So:
  353. * div = (10^9 << 32 + freq << 31 + (freq + 1) >> 1) / freq
  354. * nano = upper_32_bits(div);
  355. * frac = lower_32_bits(div) ^ 0x80000000;
  356. * Will give the values for the registers.
  357. *
  358. * This is all seems perfect, but alas it is not when considering the
  359. * whole story. The system is clocked from 25MHz, which is multiplied
  360. * by a PLL to 1GHz, and then divided by three, giving 333333333Hz
  361. * (recurring). This gives exactly 3ns, but using 333333333Hz with
  362. * the above gives an error of 13*2^-32ns.
  363. *
  364. * Consequently, we use the period rather than calculating from the
  365. * frequency.
  366. */
  367. tai->period = 3ULL << 32;
  368. mvpp22_tai_init(tai);
  369. tai->caps.owner = THIS_MODULE;
  370. strscpy(tai->caps.name, "Marvell PP2.2", sizeof(tai->caps.name));
  371. tai->caps.max_adj = mvpp22_calc_max_adj(tai);
  372. tai->caps.adjfine = mvpp22_tai_adjfine;
  373. tai->caps.adjtime = mvpp22_tai_adjtime;
  374. tai->caps.gettimex64 = mvpp22_tai_gettimex64;
  375. tai->caps.settime64 = mvpp22_tai_settime64;
  376. tai->caps.do_aux_work = mvpp22_tai_aux_work;
  377. ret = devm_add_action(dev, mvpp22_tai_remove, tai);
  378. if (ret)
  379. return ret;
  380. tai->ptp_clock = ptp_clock_register(&tai->caps, dev);
  381. if (IS_ERR(tai->ptp_clock))
  382. return PTR_ERR(tai->ptp_clock);
  383. priv->tai = tai;
  384. return 0;
  385. }