cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ptp_dte.c (8292B)


      1/*
      2 * Copyright 2017 Broadcom
      3 *
      4 * This program is free software; you can redistribute it and/or
      5 * modify it under the terms of the GNU General Public License as
      6 * published by the Free Software Foundation version 2.
      7 *
      8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
      9 * kind, whether express or implied; without even the implied warranty
     10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 * GNU General Public License for more details.
     12 */
     13
     14#include <linux/err.h>
     15#include <linux/io.h>
     16#include <linux/module.h>
     17#include <linux/mod_devicetable.h>
     18#include <linux/platform_device.h>
     19#include <linux/ptp_clock_kernel.h>
     20#include <linux/types.h>
     21
     22#define DTE_NCO_LOW_TIME_REG	0x00
     23#define DTE_NCO_TIME_REG	0x04
     24#define DTE_NCO_OVERFLOW_REG	0x08
     25#define DTE_NCO_INC_REG		0x0c
     26
     27#define DTE_NCO_SUM2_MASK	0xffffffff
     28#define DTE_NCO_SUM2_SHIFT	4ULL
     29
     30#define DTE_NCO_SUM3_MASK	0xff
     31#define DTE_NCO_SUM3_SHIFT	36ULL
     32#define DTE_NCO_SUM3_WR_SHIFT	8
     33
     34#define DTE_NCO_TS_WRAP_MASK	0xfff
     35#define DTE_NCO_TS_WRAP_LSHIFT	32
     36
     37#define DTE_NCO_INC_DEFAULT	0x80000000
     38#define DTE_NUM_REGS_TO_RESTORE	4
     39
     40/* Full wrap around is 44bits in ns (~4.887 hrs) */
     41#define DTE_WRAP_AROUND_NSEC_SHIFT 44
     42
     43/* 44 bits NCO */
     44#define DTE_NCO_MAX_NS	0xFFFFFFFFFFFLL
     45
     46/* 125MHz with 3.29 reg cfg */
     47#define DTE_PPB_ADJ(ppb) (u32)(div64_u64((((u64)abs(ppb) * BIT(28)) +\
     48				      62500000ULL), 125000000ULL))
     49
     50/* ptp dte priv structure */
     51struct ptp_dte {
     52	void __iomem *regs;
     53	struct ptp_clock *ptp_clk;
     54	struct ptp_clock_info caps;
     55	struct device *dev;
     56	u32 ts_ovf_last;
     57	u32 ts_wrap_cnt;
     58	spinlock_t lock;
     59	u32 reg_val[DTE_NUM_REGS_TO_RESTORE];
     60};
     61
     62static void dte_write_nco(void __iomem *regs, s64 ns)
     63{
     64	u32 sum2, sum3;
     65
     66	sum2 = (u32)((ns >> DTE_NCO_SUM2_SHIFT) & DTE_NCO_SUM2_MASK);
     67	/* compensate for ignoring sum1 */
     68	if (sum2 != DTE_NCO_SUM2_MASK)
     69		sum2++;
     70
     71	/* to write sum3, bits [15:8] needs to be written */
     72	sum3 = (u32)(((ns >> DTE_NCO_SUM3_SHIFT) & DTE_NCO_SUM3_MASK) <<
     73		     DTE_NCO_SUM3_WR_SHIFT);
     74
     75	writel(0, (regs + DTE_NCO_LOW_TIME_REG));
     76	writel(sum2, (regs + DTE_NCO_TIME_REG));
     77	writel(sum3, (regs + DTE_NCO_OVERFLOW_REG));
     78}
     79
     80static s64 dte_read_nco(void __iomem *regs)
     81{
     82	u32 sum2, sum3;
     83	s64 ns;
     84
     85	/*
     86	 * ignoring sum1 (4 bits) gives a 16ns resolution, which
     87	 * works due to the async register read.
     88	 */
     89	sum3 = readl(regs + DTE_NCO_OVERFLOW_REG) & DTE_NCO_SUM3_MASK;
     90	sum2 = readl(regs + DTE_NCO_TIME_REG);
     91	ns = ((s64)sum3 << DTE_NCO_SUM3_SHIFT) |
     92		 ((s64)sum2 << DTE_NCO_SUM2_SHIFT);
     93
     94	return ns;
     95}
     96
     97static void dte_write_nco_delta(struct ptp_dte *ptp_dte, s64 delta)
     98{
     99	s64 ns;
    100
    101	ns = dte_read_nco(ptp_dte->regs);
    102
    103	/* handle wraparound conditions */
    104	if ((delta < 0) && (abs(delta) > ns)) {
    105		if (ptp_dte->ts_wrap_cnt) {
    106			ns += DTE_NCO_MAX_NS + delta;
    107			ptp_dte->ts_wrap_cnt--;
    108		} else {
    109			ns = 0;
    110		}
    111	} else {
    112		ns += delta;
    113		if (ns > DTE_NCO_MAX_NS) {
    114			ptp_dte->ts_wrap_cnt++;
    115			ns -= DTE_NCO_MAX_NS;
    116		}
    117	}
    118
    119	dte_write_nco(ptp_dte->regs, ns);
    120
    121	ptp_dte->ts_ovf_last = (ns >> DTE_NCO_TS_WRAP_LSHIFT) &
    122			DTE_NCO_TS_WRAP_MASK;
    123}
    124
    125static s64 dte_read_nco_with_ovf(struct ptp_dte *ptp_dte)
    126{
    127	u32 ts_ovf;
    128	s64 ns = 0;
    129
    130	ns = dte_read_nco(ptp_dte->regs);
    131
    132	/*Timestamp overflow: 8 LSB bits of sum3, 4 MSB bits of sum2 */
    133	ts_ovf = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & DTE_NCO_TS_WRAP_MASK;
    134
    135	/* Check for wrap around */
    136	if (ts_ovf < ptp_dte->ts_ovf_last)
    137		ptp_dte->ts_wrap_cnt++;
    138
    139	ptp_dte->ts_ovf_last = ts_ovf;
    140
    141	/* adjust for wraparounds */
    142	ns += (s64)(BIT_ULL(DTE_WRAP_AROUND_NSEC_SHIFT) * ptp_dte->ts_wrap_cnt);
    143
    144	return ns;
    145}
    146
    147static int ptp_dte_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
    148{
    149	u32 nco_incr;
    150	unsigned long flags;
    151	struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps);
    152
    153	if (abs(ppb) > ptp_dte->caps.max_adj) {
    154		dev_err(ptp_dte->dev, "ppb adj too big\n");
    155		return -EINVAL;
    156	}
    157
    158	if (ppb < 0)
    159		nco_incr = DTE_NCO_INC_DEFAULT - DTE_PPB_ADJ(ppb);
    160	else
    161		nco_incr = DTE_NCO_INC_DEFAULT + DTE_PPB_ADJ(ppb);
    162
    163	spin_lock_irqsave(&ptp_dte->lock, flags);
    164	writel(nco_incr, ptp_dte->regs + DTE_NCO_INC_REG);
    165	spin_unlock_irqrestore(&ptp_dte->lock, flags);
    166
    167	return 0;
    168}
    169
    170static int ptp_dte_adjtime(struct ptp_clock_info *ptp, s64 delta)
    171{
    172	unsigned long flags;
    173	struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps);
    174
    175	spin_lock_irqsave(&ptp_dte->lock, flags);
    176	dte_write_nco_delta(ptp_dte, delta);
    177	spin_unlock_irqrestore(&ptp_dte->lock, flags);
    178
    179	return 0;
    180}
    181
    182static int ptp_dte_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
    183{
    184	unsigned long flags;
    185	struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps);
    186
    187	spin_lock_irqsave(&ptp_dte->lock, flags);
    188	*ts = ns_to_timespec64(dte_read_nco_with_ovf(ptp_dte));
    189	spin_unlock_irqrestore(&ptp_dte->lock, flags);
    190
    191	return 0;
    192}
    193
    194static int ptp_dte_settime(struct ptp_clock_info *ptp,
    195			     const struct timespec64 *ts)
    196{
    197	unsigned long flags;
    198	struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps);
    199
    200	spin_lock_irqsave(&ptp_dte->lock, flags);
    201
    202	/* Disable nco increment */
    203	writel(0, ptp_dte->regs + DTE_NCO_INC_REG);
    204
    205	dte_write_nco(ptp_dte->regs, timespec64_to_ns(ts));
    206
    207	/* reset overflow and wrap counter */
    208	ptp_dte->ts_ovf_last = 0;
    209	ptp_dte->ts_wrap_cnt = 0;
    210
    211	/* Enable nco increment */
    212	writel(DTE_NCO_INC_DEFAULT, ptp_dte->regs + DTE_NCO_INC_REG);
    213
    214	spin_unlock_irqrestore(&ptp_dte->lock, flags);
    215
    216	return 0;
    217}
    218
    219static int ptp_dte_enable(struct ptp_clock_info *ptp,
    220			    struct ptp_clock_request *rq, int on)
    221{
    222	return -EOPNOTSUPP;
    223}
    224
    225static const struct ptp_clock_info ptp_dte_caps = {
    226	.owner		= THIS_MODULE,
    227	.name		= "DTE PTP timer",
    228	.max_adj	= 50000000,
    229	.n_ext_ts	= 0,
    230	.n_pins		= 0,
    231	.pps		= 0,
    232	.adjfreq	= ptp_dte_adjfreq,
    233	.adjtime	= ptp_dte_adjtime,
    234	.gettime64	= ptp_dte_gettime,
    235	.settime64	= ptp_dte_settime,
    236	.enable		= ptp_dte_enable,
    237};
    238
    239static int ptp_dte_probe(struct platform_device *pdev)
    240{
    241	struct ptp_dte *ptp_dte;
    242	struct device *dev = &pdev->dev;
    243
    244	ptp_dte = devm_kzalloc(dev, sizeof(struct ptp_dte), GFP_KERNEL);
    245	if (!ptp_dte)
    246		return -ENOMEM;
    247
    248	ptp_dte->regs = devm_platform_ioremap_resource(pdev, 0);
    249	if (IS_ERR(ptp_dte->regs))
    250		return PTR_ERR(ptp_dte->regs);
    251
    252	spin_lock_init(&ptp_dte->lock);
    253
    254	ptp_dte->dev = dev;
    255	ptp_dte->caps = ptp_dte_caps;
    256	ptp_dte->ptp_clk = ptp_clock_register(&ptp_dte->caps, &pdev->dev);
    257	if (IS_ERR(ptp_dte->ptp_clk)) {
    258		dev_err(dev,
    259			"%s: Failed to register ptp clock\n", __func__);
    260		return PTR_ERR(ptp_dte->ptp_clk);
    261	}
    262
    263	platform_set_drvdata(pdev, ptp_dte);
    264
    265	dev_info(dev, "ptp clk probe done\n");
    266
    267	return 0;
    268}
    269
    270static int ptp_dte_remove(struct platform_device *pdev)
    271{
    272	struct ptp_dte *ptp_dte = platform_get_drvdata(pdev);
    273	u8 i;
    274
    275	ptp_clock_unregister(ptp_dte->ptp_clk);
    276
    277	for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++)
    278		writel(0, ptp_dte->regs + (i * sizeof(u32)));
    279
    280	return 0;
    281}
    282
    283#ifdef CONFIG_PM_SLEEP
    284static int ptp_dte_suspend(struct device *dev)
    285{
    286	struct ptp_dte *ptp_dte = dev_get_drvdata(dev);
    287	u8 i;
    288
    289	for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) {
    290		ptp_dte->reg_val[i] =
    291			readl(ptp_dte->regs + (i * sizeof(u32)));
    292	}
    293
    294	/* disable the nco */
    295	writel(0, ptp_dte->regs + DTE_NCO_INC_REG);
    296
    297	return 0;
    298}
    299
    300static int ptp_dte_resume(struct device *dev)
    301{
    302	struct ptp_dte *ptp_dte = dev_get_drvdata(dev);
    303	u8 i;
    304
    305	for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) {
    306		if ((i * sizeof(u32)) != DTE_NCO_OVERFLOW_REG)
    307			writel(ptp_dte->reg_val[i],
    308				(ptp_dte->regs + (i * sizeof(u32))));
    309		else
    310			writel(((ptp_dte->reg_val[i] &
    311				DTE_NCO_SUM3_MASK) << DTE_NCO_SUM3_WR_SHIFT),
    312				(ptp_dte->regs + (i * sizeof(u32))));
    313	}
    314
    315	return 0;
    316}
    317
    318static const struct dev_pm_ops ptp_dte_pm_ops = {
    319	.suspend = ptp_dte_suspend,
    320	.resume = ptp_dte_resume
    321};
    322
    323#define PTP_DTE_PM_OPS	(&ptp_dte_pm_ops)
    324#else
    325#define PTP_DTE_PM_OPS	NULL
    326#endif
    327
    328static const struct of_device_id ptp_dte_of_match[] = {
    329	{ .compatible = "brcm,ptp-dte", },
    330	{},
    331};
    332MODULE_DEVICE_TABLE(of, ptp_dte_of_match);
    333
    334static struct platform_driver ptp_dte_driver = {
    335	.driver = {
    336		.name = "ptp-dte",
    337		.pm = PTP_DTE_PM_OPS,
    338		.of_match_table = ptp_dte_of_match,
    339	},
    340	.probe    = ptp_dte_probe,
    341	.remove   = ptp_dte_remove,
    342};
    343module_platform_driver(ptp_dte_driver);
    344
    345MODULE_AUTHOR("Broadcom");
    346MODULE_DESCRIPTION("Broadcom DTE PTP Clock driver");
    347MODULE_LICENSE("GPL v2");