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 31 static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data) 32 { 33 writel(data, ioaddr + PTP_TCR); 34 } 35 36 static 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 54 static 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 79 static 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 103 static 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 130 static 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 141 const 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