1*6c6fa1a0SYoshihiro Shimoda // SPDX-License-Identifier: GPL-2.0
2*6c6fa1a0SYoshihiro Shimoda /* Renesas R-Car Gen4 gPTP device driver
3*6c6fa1a0SYoshihiro Shimoda  *
4*6c6fa1a0SYoshihiro Shimoda  * Copyright (C) 2022 Renesas Electronics Corporation
5*6c6fa1a0SYoshihiro Shimoda  */
6*6c6fa1a0SYoshihiro Shimoda 
7*6c6fa1a0SYoshihiro Shimoda #include <linux/err.h>
8*6c6fa1a0SYoshihiro Shimoda #include <linux/etherdevice.h>
9*6c6fa1a0SYoshihiro Shimoda #include <linux/kernel.h>
10*6c6fa1a0SYoshihiro Shimoda #include <linux/module.h>
11*6c6fa1a0SYoshihiro Shimoda #include <linux/platform_device.h>
12*6c6fa1a0SYoshihiro Shimoda #include <linux/slab.h>
13*6c6fa1a0SYoshihiro Shimoda 
14*6c6fa1a0SYoshihiro Shimoda #include "rcar_gen4_ptp.h"
15*6c6fa1a0SYoshihiro Shimoda #define ptp_to_priv(ptp)	container_of(ptp, struct rcar_gen4_ptp_private, info)
16*6c6fa1a0SYoshihiro Shimoda 
17*6c6fa1a0SYoshihiro Shimoda static const struct rcar_gen4_ptp_reg_offset s4_offs = {
18*6c6fa1a0SYoshihiro Shimoda 	.enable = PTPTMEC,
19*6c6fa1a0SYoshihiro Shimoda 	.disable = PTPTMDC,
20*6c6fa1a0SYoshihiro Shimoda 	.increment = PTPTIVC0,
21*6c6fa1a0SYoshihiro Shimoda 	.config_t0 = PTPTOVC00,
22*6c6fa1a0SYoshihiro Shimoda 	.config_t1 = PTPTOVC10,
23*6c6fa1a0SYoshihiro Shimoda 	.config_t2 = PTPTOVC20,
24*6c6fa1a0SYoshihiro Shimoda 	.monitor_t0 = PTPGPTPTM00,
25*6c6fa1a0SYoshihiro Shimoda 	.monitor_t1 = PTPGPTPTM10,
26*6c6fa1a0SYoshihiro Shimoda 	.monitor_t2 = PTPGPTPTM20,
27*6c6fa1a0SYoshihiro Shimoda };
28*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)29*6c6fa1a0SYoshihiro Shimoda static int rcar_gen4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
30*6c6fa1a0SYoshihiro Shimoda {
31*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
32*6c6fa1a0SYoshihiro Shimoda 	bool neg_adj = scaled_ppm < 0 ? true : false;
33*6c6fa1a0SYoshihiro Shimoda 	s64 addend = ptp_priv->default_addend;
34*6c6fa1a0SYoshihiro Shimoda 	s64 diff;
35*6c6fa1a0SYoshihiro Shimoda 
36*6c6fa1a0SYoshihiro Shimoda 	if (neg_adj)
37*6c6fa1a0SYoshihiro Shimoda 		scaled_ppm = -scaled_ppm;
38*6c6fa1a0SYoshihiro Shimoda 	diff = div_s64(addend * scaled_ppm_to_ppb(scaled_ppm), NSEC_PER_SEC);
39*6c6fa1a0SYoshihiro Shimoda 	addend = neg_adj ? addend - diff : addend + diff;
40*6c6fa1a0SYoshihiro Shimoda 
41*6c6fa1a0SYoshihiro Shimoda 	iowrite32(addend, ptp_priv->addr + ptp_priv->offs->increment);
42*6c6fa1a0SYoshihiro Shimoda 
43*6c6fa1a0SYoshihiro Shimoda 	return 0;
44*6c6fa1a0SYoshihiro Shimoda }
45*6c6fa1a0SYoshihiro Shimoda 
46*6c6fa1a0SYoshihiro Shimoda /* Caller must hold the lock */
_rcar_gen4_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)47*6c6fa1a0SYoshihiro Shimoda static void _rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
48*6c6fa1a0SYoshihiro Shimoda 				   struct timespec64 *ts)
49*6c6fa1a0SYoshihiro Shimoda {
50*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
51*6c6fa1a0SYoshihiro Shimoda 
52*6c6fa1a0SYoshihiro Shimoda 	ts->tv_nsec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t0);
53*6c6fa1a0SYoshihiro Shimoda 	ts->tv_sec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t1) |
54*6c6fa1a0SYoshihiro Shimoda 		     ((s64)ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t2) << 32);
55*6c6fa1a0SYoshihiro Shimoda }
56*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)57*6c6fa1a0SYoshihiro Shimoda static int rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
58*6c6fa1a0SYoshihiro Shimoda 				 struct timespec64 *ts)
59*6c6fa1a0SYoshihiro Shimoda {
60*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
61*6c6fa1a0SYoshihiro Shimoda 	unsigned long flags;
62*6c6fa1a0SYoshihiro Shimoda 
63*6c6fa1a0SYoshihiro Shimoda 	spin_lock_irqsave(&ptp_priv->lock, flags);
64*6c6fa1a0SYoshihiro Shimoda 	_rcar_gen4_ptp_gettime(ptp, ts);
65*6c6fa1a0SYoshihiro Shimoda 	spin_unlock_irqrestore(&ptp_priv->lock, flags);
66*6c6fa1a0SYoshihiro Shimoda 
67*6c6fa1a0SYoshihiro Shimoda 	return 0;
68*6c6fa1a0SYoshihiro Shimoda }
69*6c6fa1a0SYoshihiro Shimoda 
70*6c6fa1a0SYoshihiro Shimoda /* Caller must hold the lock */
_rcar_gen4_ptp_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)71*6c6fa1a0SYoshihiro Shimoda static void _rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
72*6c6fa1a0SYoshihiro Shimoda 				   const struct timespec64 *ts)
73*6c6fa1a0SYoshihiro Shimoda {
74*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
75*6c6fa1a0SYoshihiro Shimoda 
76*6c6fa1a0SYoshihiro Shimoda 	iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
77*6c6fa1a0SYoshihiro Shimoda 	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t2);
78*6c6fa1a0SYoshihiro Shimoda 	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t1);
79*6c6fa1a0SYoshihiro Shimoda 	iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t0);
80*6c6fa1a0SYoshihiro Shimoda 	iowrite32(1, ptp_priv->addr + ptp_priv->offs->enable);
81*6c6fa1a0SYoshihiro Shimoda 	iowrite32(ts->tv_sec >> 32, ptp_priv->addr + ptp_priv->offs->config_t2);
82*6c6fa1a0SYoshihiro Shimoda 	iowrite32(ts->tv_sec, ptp_priv->addr + ptp_priv->offs->config_t1);
83*6c6fa1a0SYoshihiro Shimoda 	iowrite32(ts->tv_nsec, ptp_priv->addr + ptp_priv->offs->config_t0);
84*6c6fa1a0SYoshihiro Shimoda }
85*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)86*6c6fa1a0SYoshihiro Shimoda static int rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
87*6c6fa1a0SYoshihiro Shimoda 				 const struct timespec64 *ts)
88*6c6fa1a0SYoshihiro Shimoda {
89*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
90*6c6fa1a0SYoshihiro Shimoda 	unsigned long flags;
91*6c6fa1a0SYoshihiro Shimoda 
92*6c6fa1a0SYoshihiro Shimoda 	spin_lock_irqsave(&ptp_priv->lock, flags);
93*6c6fa1a0SYoshihiro Shimoda 	_rcar_gen4_ptp_settime(ptp, ts);
94*6c6fa1a0SYoshihiro Shimoda 	spin_unlock_irqrestore(&ptp_priv->lock, flags);
95*6c6fa1a0SYoshihiro Shimoda 
96*6c6fa1a0SYoshihiro Shimoda 	return 0;
97*6c6fa1a0SYoshihiro Shimoda }
98*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)99*6c6fa1a0SYoshihiro Shimoda static int rcar_gen4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
100*6c6fa1a0SYoshihiro Shimoda {
101*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
102*6c6fa1a0SYoshihiro Shimoda 	struct timespec64 ts;
103*6c6fa1a0SYoshihiro Shimoda 	unsigned long flags;
104*6c6fa1a0SYoshihiro Shimoda 	s64 now;
105*6c6fa1a0SYoshihiro Shimoda 
106*6c6fa1a0SYoshihiro Shimoda 	spin_lock_irqsave(&ptp_priv->lock, flags);
107*6c6fa1a0SYoshihiro Shimoda 	_rcar_gen4_ptp_gettime(ptp, &ts);
108*6c6fa1a0SYoshihiro Shimoda 	now = ktime_to_ns(timespec64_to_ktime(ts));
109*6c6fa1a0SYoshihiro Shimoda 	ts = ns_to_timespec64(now + delta);
110*6c6fa1a0SYoshihiro Shimoda 	_rcar_gen4_ptp_settime(ptp, &ts);
111*6c6fa1a0SYoshihiro Shimoda 	spin_unlock_irqrestore(&ptp_priv->lock, flags);
112*6c6fa1a0SYoshihiro Shimoda 
113*6c6fa1a0SYoshihiro Shimoda 	return 0;
114*6c6fa1a0SYoshihiro Shimoda }
115*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)116*6c6fa1a0SYoshihiro Shimoda static int rcar_gen4_ptp_enable(struct ptp_clock_info *ptp,
117*6c6fa1a0SYoshihiro Shimoda 				struct ptp_clock_request *rq, int on)
118*6c6fa1a0SYoshihiro Shimoda {
119*6c6fa1a0SYoshihiro Shimoda 	return -EOPNOTSUPP;
120*6c6fa1a0SYoshihiro Shimoda }
121*6c6fa1a0SYoshihiro Shimoda 
122*6c6fa1a0SYoshihiro Shimoda static struct ptp_clock_info rcar_gen4_ptp_info = {
123*6c6fa1a0SYoshihiro Shimoda 	.owner = THIS_MODULE,
124*6c6fa1a0SYoshihiro Shimoda 	.name = "rcar_gen4_ptp",
125*6c6fa1a0SYoshihiro Shimoda 	.max_adj = 50000000,
126*6c6fa1a0SYoshihiro Shimoda 	.adjfine = rcar_gen4_ptp_adjfine,
127*6c6fa1a0SYoshihiro Shimoda 	.adjtime = rcar_gen4_ptp_adjtime,
128*6c6fa1a0SYoshihiro Shimoda 	.gettime64 = rcar_gen4_ptp_gettime,
129*6c6fa1a0SYoshihiro Shimoda 	.settime64 = rcar_gen4_ptp_settime,
130*6c6fa1a0SYoshihiro Shimoda 	.enable = rcar_gen4_ptp_enable,
131*6c6fa1a0SYoshihiro Shimoda };
132*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private * ptp_priv,enum rcar_gen4_ptp_reg_layout layout)133*6c6fa1a0SYoshihiro Shimoda static void rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
134*6c6fa1a0SYoshihiro Shimoda 				   enum rcar_gen4_ptp_reg_layout layout)
135*6c6fa1a0SYoshihiro Shimoda {
136*6c6fa1a0SYoshihiro Shimoda 	WARN_ON(layout != RCAR_GEN4_PTP_REG_LAYOUT_S4);
137*6c6fa1a0SYoshihiro Shimoda 
138*6c6fa1a0SYoshihiro Shimoda 	ptp_priv->offs = &s4_offs;
139*6c6fa1a0SYoshihiro Shimoda }
140*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_register(struct rcar_gen4_ptp_private * ptp_priv,enum rcar_gen4_ptp_reg_layout layout,u32 clock)141*6c6fa1a0SYoshihiro Shimoda int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
142*6c6fa1a0SYoshihiro Shimoda 			   enum rcar_gen4_ptp_reg_layout layout, u32 clock)
143*6c6fa1a0SYoshihiro Shimoda {
144*6c6fa1a0SYoshihiro Shimoda 	if (ptp_priv->initialized)
145*6c6fa1a0SYoshihiro Shimoda 		return 0;
146*6c6fa1a0SYoshihiro Shimoda 
147*6c6fa1a0SYoshihiro Shimoda 	spin_lock_init(&ptp_priv->lock);
148*6c6fa1a0SYoshihiro Shimoda 
149*6c6fa1a0SYoshihiro Shimoda 	rcar_gen4_ptp_set_offs(ptp_priv, layout);
150*6c6fa1a0SYoshihiro Shimoda 
151*6c6fa1a0SYoshihiro Shimoda 	ptp_priv->default_addend = clock;
152*6c6fa1a0SYoshihiro Shimoda 	iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment);
153*6c6fa1a0SYoshihiro Shimoda 	ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL);
154*6c6fa1a0SYoshihiro Shimoda 	if (IS_ERR(ptp_priv->clock))
155*6c6fa1a0SYoshihiro Shimoda 		return PTR_ERR(ptp_priv->clock);
156*6c6fa1a0SYoshihiro Shimoda 
157*6c6fa1a0SYoshihiro Shimoda 	iowrite32(0x01, ptp_priv->addr + ptp_priv->offs->enable);
158*6c6fa1a0SYoshihiro Shimoda 	ptp_priv->initialized = true;
159*6c6fa1a0SYoshihiro Shimoda 
160*6c6fa1a0SYoshihiro Shimoda 	return 0;
161*6c6fa1a0SYoshihiro Shimoda }
162*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private * ptp_priv)163*6c6fa1a0SYoshihiro Shimoda int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
164*6c6fa1a0SYoshihiro Shimoda {
165*6c6fa1a0SYoshihiro Shimoda 	iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
166*6c6fa1a0SYoshihiro Shimoda 
167*6c6fa1a0SYoshihiro Shimoda 	return ptp_clock_unregister(ptp_priv->clock);
168*6c6fa1a0SYoshihiro Shimoda }
169*6c6fa1a0SYoshihiro Shimoda 
rcar_gen4_ptp_alloc(struct platform_device * pdev)170*6c6fa1a0SYoshihiro Shimoda struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
171*6c6fa1a0SYoshihiro Shimoda {
172*6c6fa1a0SYoshihiro Shimoda 	struct rcar_gen4_ptp_private *ptp;
173*6c6fa1a0SYoshihiro Shimoda 
174*6c6fa1a0SYoshihiro Shimoda 	ptp = devm_kzalloc(&pdev->dev, sizeof(*ptp), GFP_KERNEL);
175*6c6fa1a0SYoshihiro Shimoda 	if (!ptp)
176*6c6fa1a0SYoshihiro Shimoda 		return NULL;
177*6c6fa1a0SYoshihiro Shimoda 
178*6c6fa1a0SYoshihiro Shimoda 	ptp->info = rcar_gen4_ptp_info;
179*6c6fa1a0SYoshihiro Shimoda 
180*6c6fa1a0SYoshihiro Shimoda 	return ptp;
181*6c6fa1a0SYoshihiro Shimoda }
182