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