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 u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, 37 u32 ptp_clock) 38 { 39 u32 value = readl(ioaddr + PTP_TCR); 40 unsigned long data; 41 42 /* Convert the ptp_clock to nano second 43 * formula = (2/ptp_clock) * 1000000000 44 * where, ptp_clock = 50MHz. 45 */ 46 data = (2000000000ULL / ptp_clock); 47 48 /* 0.465ns accuracy */ 49 if (!(value & PTP_TCR_TSCTRLSSR)) 50 data = (data * 1000) / 465; 51 52 writel(data, ioaddr + PTP_SSIR); 53 54 return data; 55 } 56 57 static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) 58 { 59 int limit; 60 u32 value; 61 62 writel(sec, ioaddr + PTP_STSUR); 63 writel(nsec, ioaddr + PTP_STNSUR); 64 /* issue command to initialize the system time value */ 65 value = readl(ioaddr + PTP_TCR); 66 value |= PTP_TCR_TSINIT; 67 writel(value, ioaddr + PTP_TCR); 68 69 /* wait for present system time initialize to complete */ 70 limit = 10; 71 while (limit--) { 72 if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT)) 73 break; 74 mdelay(10); 75 } 76 if (limit < 0) 77 return -EBUSY; 78 79 return 0; 80 } 81 82 static int stmmac_config_addend(void __iomem *ioaddr, u32 addend) 83 { 84 u32 value; 85 int limit; 86 87 writel(addend, ioaddr + PTP_TAR); 88 /* issue command to update the addend value */ 89 value = readl(ioaddr + PTP_TCR); 90 value |= PTP_TCR_TSADDREG; 91 writel(value, ioaddr + PTP_TCR); 92 93 /* wait for present addend update to complete */ 94 limit = 10; 95 while (limit--) { 96 if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG)) 97 break; 98 mdelay(10); 99 } 100 if (limit < 0) 101 return -EBUSY; 102 103 return 0; 104 } 105 106 static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, 107 int add_sub) 108 { 109 u32 value; 110 int limit; 111 112 writel(sec, ioaddr + PTP_STSUR); 113 writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec), 114 ioaddr + PTP_STNSUR); 115 /* issue command to initialize the system time value */ 116 value = readl(ioaddr + PTP_TCR); 117 value |= PTP_TCR_TSUPDT; 118 writel(value, ioaddr + PTP_TCR); 119 120 /* wait for present system time adjust/update to complete */ 121 limit = 10; 122 while (limit--) { 123 if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT)) 124 break; 125 mdelay(10); 126 } 127 if (limit < 0) 128 return -EBUSY; 129 130 return 0; 131 } 132 133 static u64 stmmac_get_systime(void __iomem *ioaddr) 134 { 135 u64 ns; 136 137 ns = readl(ioaddr + PTP_STNSR); 138 /* convert sec time value to nanosecond */ 139 ns += readl(ioaddr + PTP_STSR) * 1000000000ULL; 140 141 return ns; 142 } 143 144 const struct stmmac_hwtimestamp stmmac_ptp = { 145 .config_hw_tstamping = stmmac_config_hw_tstamping, 146 .init_systime = stmmac_init_systime, 147 .config_sub_second_increment = stmmac_config_sub_second_increment, 148 .config_addend = stmmac_config_addend, 149 .adjust_systime = stmmac_adjust_systime, 150 .get_systime = stmmac_get_systime, 151 }; 152