cavium_ptp.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* cavium_ptp.c - PTP 1588 clock on Cavium hardware
  3. * Copyright (c) 2003-2015, 2017 Cavium, Inc.
  4. */
  5. #include <linux/device.h>
  6. #include <linux/module.h>
  7. #include <linux/timecounter.h>
  8. #include <linux/pci.h>
  9. #include "cavium_ptp.h"
  10. #define DRV_NAME "cavium_ptp"
  11. #define PCI_DEVICE_ID_CAVIUM_PTP 0xA00C
  12. #define PCI_DEVICE_ID_CAVIUM_RST 0xA00E
  13. #define PCI_PTP_BAR_NO 0
  14. #define PCI_RST_BAR_NO 0
  15. #define PTP_CLOCK_CFG 0xF00ULL
  16. #define PTP_CLOCK_CFG_PTP_EN BIT(0)
  17. #define PTP_CLOCK_LO 0xF08ULL
  18. #define PTP_CLOCK_HI 0xF10ULL
  19. #define PTP_CLOCK_COMP 0xF18ULL
  20. #define RST_BOOT 0x1600ULL
  21. #define CLOCK_BASE_RATE 50000000ULL
  22. static u64 ptp_cavium_clock_get(void)
  23. {
  24. struct pci_dev *pdev;
  25. void __iomem *base;
  26. u64 ret = CLOCK_BASE_RATE * 16;
  27. pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
  28. PCI_DEVICE_ID_CAVIUM_RST, NULL);
  29. if (!pdev)
  30. goto error;
  31. base = pci_ioremap_bar(pdev, PCI_RST_BAR_NO);
  32. if (!base)
  33. goto error_put_pdev;
  34. ret = CLOCK_BASE_RATE * ((readq(base + RST_BOOT) >> 33) & 0x3f);
  35. iounmap(base);
  36. error_put_pdev:
  37. pci_dev_put(pdev);
  38. error:
  39. return ret;
  40. }
  41. struct cavium_ptp *cavium_ptp_get(void)
  42. {
  43. struct cavium_ptp *ptp;
  44. struct pci_dev *pdev;
  45. pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
  46. PCI_DEVICE_ID_CAVIUM_PTP, NULL);
  47. if (!pdev)
  48. return ERR_PTR(-ENODEV);
  49. ptp = pci_get_drvdata(pdev);
  50. if (!ptp)
  51. ptp = ERR_PTR(-EPROBE_DEFER);
  52. if (IS_ERR(ptp))
  53. pci_dev_put(pdev);
  54. return ptp;
  55. }
  56. EXPORT_SYMBOL(cavium_ptp_get);
  57. void cavium_ptp_put(struct cavium_ptp *ptp)
  58. {
  59. if (!ptp)
  60. return;
  61. pci_dev_put(ptp->pdev);
  62. }
  63. EXPORT_SYMBOL(cavium_ptp_put);
  64. /**
  65. * cavium_ptp_adjfine() - Adjust ptp frequency
  66. * @ptp: PTP clock info
  67. * @scaled_ppm: how much to adjust by, in parts per million, but with a
  68. * 16 bit binary fractional field
  69. */
  70. static int cavium_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
  71. {
  72. struct cavium_ptp *clock =
  73. container_of(ptp_info, struct cavium_ptp, ptp_info);
  74. unsigned long flags;
  75. u64 comp;
  76. u64 adj;
  77. bool neg_adj = false;
  78. if (scaled_ppm < 0) {
  79. neg_adj = true;
  80. scaled_ppm = -scaled_ppm;
  81. }
  82. /* The hardware adds the clock compensation value to the PTP clock
  83. * on every coprocessor clock cycle. Typical convention is that it
  84. * represent number of nanosecond betwen each cycle. In this
  85. * convention compensation value is in 64 bit fixed-point
  86. * representation where upper 32 bits are number of nanoseconds
  87. * and lower is fractions of nanosecond.
  88. * The scaled_ppm represent the ratio in "parts per bilion" by which the
  89. * compensation value should be corrected.
  90. * To calculate new compenstation value we use 64bit fixed point
  91. * arithmetic on following formula
  92. * comp = tbase + tbase * scaled_ppm / (1M * 2^16)
  93. * where tbase is the basic compensation value calculated initialy
  94. * in cavium_ptp_init() -> tbase = 1/Hz. Then we use endian
  95. * independent structure definition to write data to PTP register.
  96. */
  97. comp = ((u64)1000000000ull << 32) / clock->clock_rate;
  98. adj = comp * scaled_ppm;
  99. adj >>= 16;
  100. adj = div_u64(adj, 1000000ull);
  101. comp = neg_adj ? comp - adj : comp + adj;
  102. spin_lock_irqsave(&clock->spin_lock, flags);
  103. writeq(comp, clock->reg_base + PTP_CLOCK_COMP);
  104. spin_unlock_irqrestore(&clock->spin_lock, flags);
  105. return 0;
  106. }
  107. /**
  108. * cavium_ptp_adjtime() - Adjust ptp time
  109. * @ptp: PTP clock info
  110. * @delta: how much to adjust by, in nanosecs
  111. */
  112. static int cavium_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
  113. {
  114. struct cavium_ptp *clock =
  115. container_of(ptp_info, struct cavium_ptp, ptp_info);
  116. unsigned long flags;
  117. spin_lock_irqsave(&clock->spin_lock, flags);
  118. timecounter_adjtime(&clock->time_counter, delta);
  119. spin_unlock_irqrestore(&clock->spin_lock, flags);
  120. /* Sync, for network driver to get latest value */
  121. smp_mb();
  122. return 0;
  123. }
  124. /**
  125. * cavium_ptp_gettime() - Get hardware clock time with adjustment
  126. * @ptp: PTP clock info
  127. * @ts: timespec
  128. */
  129. static int cavium_ptp_gettime(struct ptp_clock_info *ptp_info,
  130. struct timespec64 *ts)
  131. {
  132. struct cavium_ptp *clock =
  133. container_of(ptp_info, struct cavium_ptp, ptp_info);
  134. unsigned long flags;
  135. u64 nsec;
  136. spin_lock_irqsave(&clock->spin_lock, flags);
  137. nsec = timecounter_read(&clock->time_counter);
  138. spin_unlock_irqrestore(&clock->spin_lock, flags);
  139. *ts = ns_to_timespec64(nsec);
  140. return 0;
  141. }
  142. /**
  143. * cavium_ptp_settime() - Set hardware clock time. Reset adjustment
  144. * @ptp: PTP clock info
  145. * @ts: timespec
  146. */
  147. static int cavium_ptp_settime(struct ptp_clock_info *ptp_info,
  148. const struct timespec64 *ts)
  149. {
  150. struct cavium_ptp *clock =
  151. container_of(ptp_info, struct cavium_ptp, ptp_info);
  152. unsigned long flags;
  153. u64 nsec;
  154. nsec = timespec64_to_ns(ts);
  155. spin_lock_irqsave(&clock->spin_lock, flags);
  156. timecounter_init(&clock->time_counter, &clock->cycle_counter, nsec);
  157. spin_unlock_irqrestore(&clock->spin_lock, flags);
  158. return 0;
  159. }
  160. /**
  161. * cavium_ptp_enable() - Request to enable or disable an ancillary feature.
  162. * @ptp: PTP clock info
  163. * @rq: request
  164. * @on: is it on
  165. */
  166. static int cavium_ptp_enable(struct ptp_clock_info *ptp_info,
  167. struct ptp_clock_request *rq, int on)
  168. {
  169. return -EOPNOTSUPP;
  170. }
  171. static u64 cavium_ptp_cc_read(const struct cyclecounter *cc)
  172. {
  173. struct cavium_ptp *clock =
  174. container_of(cc, struct cavium_ptp, cycle_counter);
  175. return readq(clock->reg_base + PTP_CLOCK_HI);
  176. }
  177. static int cavium_ptp_probe(struct pci_dev *pdev,
  178. const struct pci_device_id *ent)
  179. {
  180. struct device *dev = &pdev->dev;
  181. struct cavium_ptp *clock;
  182. struct cyclecounter *cc;
  183. u64 clock_cfg;
  184. u64 clock_comp;
  185. int err;
  186. clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
  187. if (!clock) {
  188. err = -ENOMEM;
  189. goto error;
  190. }
  191. clock->pdev = pdev;
  192. err = pcim_enable_device(pdev);
  193. if (err)
  194. goto error_free;
  195. err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
  196. if (err)
  197. goto error_free;
  198. clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
  199. spin_lock_init(&clock->spin_lock);
  200. cc = &clock->cycle_counter;
  201. cc->read = cavium_ptp_cc_read;
  202. cc->mask = CYCLECOUNTER_MASK(64);
  203. cc->mult = 1;
  204. cc->shift = 0;
  205. timecounter_init(&clock->time_counter, &clock->cycle_counter,
  206. ktime_to_ns(ktime_get_real()));
  207. clock->clock_rate = ptp_cavium_clock_get();
  208. clock->ptp_info = (struct ptp_clock_info) {
  209. .owner = THIS_MODULE,
  210. .name = "ThunderX PTP",
  211. .max_adj = 1000000000ull,
  212. .n_ext_ts = 0,
  213. .n_pins = 0,
  214. .pps = 0,
  215. .adjfine = cavium_ptp_adjfine,
  216. .adjtime = cavium_ptp_adjtime,
  217. .gettime64 = cavium_ptp_gettime,
  218. .settime64 = cavium_ptp_settime,
  219. .enable = cavium_ptp_enable,
  220. };
  221. clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
  222. clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
  223. writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
  224. clock_comp = ((u64)1000000000ull << 32) / clock->clock_rate;
  225. writeq(clock_comp, clock->reg_base + PTP_CLOCK_COMP);
  226. clock->ptp_clock = ptp_clock_register(&clock->ptp_info, dev);
  227. if (!clock->ptp_clock) {
  228. err = -ENODEV;
  229. goto error_stop;
  230. }
  231. if (IS_ERR(clock->ptp_clock)) {
  232. err = PTR_ERR(clock->ptp_clock);
  233. goto error_stop;
  234. }
  235. pci_set_drvdata(pdev, clock);
  236. return 0;
  237. error_stop:
  238. clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
  239. clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
  240. writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
  241. pcim_iounmap_regions(pdev, 1 << PCI_PTP_BAR_NO);
  242. error_free:
  243. devm_kfree(dev, clock);
  244. error:
  245. /* For `cavium_ptp_get()` we need to differentiate between the case
  246. * when the core has not tried to probe this device and the case when
  247. * the probe failed. In the later case we pretend that the
  248. * initialization was successful and keep the error in
  249. * `dev->driver_data`.
  250. */
  251. pci_set_drvdata(pdev, ERR_PTR(err));
  252. return 0;
  253. }
  254. static void cavium_ptp_remove(struct pci_dev *pdev)
  255. {
  256. struct cavium_ptp *clock = pci_get_drvdata(pdev);
  257. u64 clock_cfg;
  258. if (IS_ERR_OR_NULL(clock))
  259. return;
  260. ptp_clock_unregister(clock->ptp_clock);
  261. clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
  262. clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
  263. writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
  264. }
  265. static const struct pci_device_id cavium_ptp_id_table[] = {
  266. { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_PTP) },
  267. { 0, }
  268. };
  269. static struct pci_driver cavium_ptp_driver = {
  270. .name = DRV_NAME,
  271. .id_table = cavium_ptp_id_table,
  272. .probe = cavium_ptp_probe,
  273. .remove = cavium_ptp_remove,
  274. };
  275. module_pci_driver(cavium_ptp_driver);
  276. MODULE_DESCRIPTION(DRV_NAME);
  277. MODULE_AUTHOR("Cavium Networks <support@cavium.com>");
  278. MODULE_LICENSE("GPL v2");
  279. MODULE_DEVICE_TABLE(pci, cavium_ptp_id_table);