1/*******************************************************************************
2  Copyright (C) 2013  Vayavya Labs Pvt Ltd
3
4  This implements all the API for managing HW timestamp & PTP.
5
6  This program is free software; you can redistribute it and/or modify it
7  under the terms and conditions of the GNU General Public License,
8  version 2, as published by the Free Software Foundation.
9
10  This program is distributed in the hope it will be useful, but WITHOUT
11  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  more details.
14
15  You should have received a copy of the GNU General Public License along with
16  this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18
19  The full GNU General Public License is included in this distribution in
20  the file called "COPYING".
21
22  Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
23  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
24*******************************************************************************/
25
26#include <linux/io.h>
27#include <linux/delay.h>
28#include "common.h"
29#include "stmmac_ptp.h"
30
31static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
32{
33	writel(data, ioaddr + PTP_TCR);
34}
35
36static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
37{
38	u32 value = readl(ioaddr + PTP_TCR);
39	unsigned long data;
40
41	/* Convert the ptp_clock to nano second
42	 * formula = (1/ptp_clock) * 1000000000
43	 * where, ptp_clock = 50MHz.
44	 */
45	data = (1000000000ULL / 50000000);
46
47	/* 0.465ns accuracy */
48	if (!(value & PTP_TCR_TSCTRLSSR))
49		data = (data * 1000) / 465;
50
51	writel(data, ioaddr + PTP_SSIR);
52}
53
54static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
55{
56	int limit;
57	u32 value;
58
59	writel(sec, ioaddr + PTP_STSUR);
60	writel(nsec, ioaddr + PTP_STNSUR);
61	/* issue command to initialize the system time value */
62	value = readl(ioaddr + PTP_TCR);
63	value |= PTP_TCR_TSINIT;
64	writel(value, ioaddr + PTP_TCR);
65
66	/* wait for present system time initialize to complete */
67	limit = 10;
68	while (limit--) {
69		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
70			break;
71		mdelay(10);
72	}
73	if (limit < 0)
74		return -EBUSY;
75
76	return 0;
77}
78
79static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
80{
81	u32 value;
82	int limit;
83
84	writel(addend, ioaddr + PTP_TAR);
85	/* issue command to update the addend value */
86	value = readl(ioaddr + PTP_TCR);
87	value |= PTP_TCR_TSADDREG;
88	writel(value, ioaddr + PTP_TCR);
89
90	/* wait for present addend update to complete */
91	limit = 10;
92	while (limit--) {
93		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
94			break;
95		mdelay(10);
96	}
97	if (limit < 0)
98		return -EBUSY;
99
100	return 0;
101}
102
103static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
104				 int add_sub)
105{
106	u32 value;
107	int limit;
108
109	writel(sec, ioaddr + PTP_STSUR);
110	writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
111		ioaddr + PTP_STNSUR);
112	/* issue command to initialize the system time value */
113	value = readl(ioaddr + PTP_TCR);
114	value |= PTP_TCR_TSUPDT;
115	writel(value, ioaddr + PTP_TCR);
116
117	/* wait for present system time adjust/update to complete */
118	limit = 10;
119	while (limit--) {
120		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
121			break;
122		mdelay(10);
123	}
124	if (limit < 0)
125		return -EBUSY;
126
127	return 0;
128}
129
130static u64 stmmac_get_systime(void __iomem *ioaddr)
131{
132	u64 ns;
133
134	ns = readl(ioaddr + PTP_STNSR);
135	/* convert sec time value to nanosecond */
136	ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
137
138	return ns;
139}
140
141const struct stmmac_hwtimestamp stmmac_ptp = {
142	.config_hw_tstamping = stmmac_config_hw_tstamping,
143	.init_systime = stmmac_init_systime,
144	.config_sub_second_increment = stmmac_config_sub_second_increment,
145	.config_addend = stmmac_config_addend,
146	.adjust_systime = stmmac_adjust_systime,
147	.get_systime = stmmac_get_systime,
148};
149