123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /*******************************************************************************
- Copyright (C) 2013 Vayavya Labs Pvt Ltd
- This implements all the API for managing HW timestamp & PTP.
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
- Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
- Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
- *******************************************************************************/
- #include <linux/io.h>
- #include <linux/delay.h>
- #include "common.h"
- #include "stmmac_ptp.h"
- static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
- {
- writel(data, ioaddr + PTP_TCR);
- }
- static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
- u32 ptp_clock, int gmac4)
- {
- u32 value = readl(ioaddr + PTP_TCR);
- unsigned long data;
- u32 reg_value;
- /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
- * formula = (1/ptp_clock) * 1000000000
- * where ptp_clock is 50MHz if fine method is used to update system
- */
- if (value & PTP_TCR_TSCFUPDT)
- data = (1000000000ULL / 50000000);
- else
- data = (1000000000ULL / ptp_clock);
- /* 0.465ns accuracy */
- if (!(value & PTP_TCR_TSCTRLSSR))
- data = (data * 1000) / 465;
- data &= PTP_SSIR_SSINC_MASK;
- reg_value = data;
- if (gmac4)
- reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT;
- writel(reg_value, ioaddr + PTP_SSIR);
- return data;
- }
- static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
- {
- int limit;
- u32 value;
- writel(sec, ioaddr + PTP_STSUR);
- writel(nsec, ioaddr + PTP_STNSUR);
- /* issue command to initialize the system time value */
- value = readl(ioaddr + PTP_TCR);
- value |= PTP_TCR_TSINIT;
- writel(value, ioaddr + PTP_TCR);
- /* wait for present system time initialize to complete */
- limit = 10;
- while (limit--) {
- if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
- break;
- mdelay(10);
- }
- if (limit < 0)
- return -EBUSY;
- return 0;
- }
- static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
- {
- u32 value;
- int limit;
- writel(addend, ioaddr + PTP_TAR);
- /* issue command to update the addend value */
- value = readl(ioaddr + PTP_TCR);
- value |= PTP_TCR_TSADDREG;
- writel(value, ioaddr + PTP_TCR);
- /* wait for present addend update to complete */
- limit = 10;
- while (limit--) {
- if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
- break;
- mdelay(10);
- }
- if (limit < 0)
- return -EBUSY;
- return 0;
- }
- static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
- int add_sub, int gmac4)
- {
- u32 value;
- int limit;
- if (add_sub) {
- /* If the new sec value needs to be subtracted with
- * the system time, then MAC_STSUR reg should be
- * programmed with (2^32 – <new_sec_value>)
- */
- if (gmac4)
- sec = (100000000ULL - sec);
- value = readl(ioaddr + PTP_TCR);
- if (value & PTP_TCR_TSCTRLSSR)
- nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
- else
- nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
- }
- writel(sec, ioaddr + PTP_STSUR);
- value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
- writel(value, ioaddr + PTP_STNSUR);
- /* issue command to initialize the system time value */
- value = readl(ioaddr + PTP_TCR);
- value |= PTP_TCR_TSUPDT;
- writel(value, ioaddr + PTP_TCR);
- /* wait for present system time adjust/update to complete */
- limit = 10;
- while (limit--) {
- if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
- break;
- mdelay(10);
- }
- if (limit < 0)
- return -EBUSY;
- return 0;
- }
- static u64 stmmac_get_systime(void __iomem *ioaddr)
- {
- u64 ns;
- /* Get the TSSS value */
- ns = readl(ioaddr + PTP_STNSR);
- /* Get the TSS and convert sec time value to nanosecond */
- ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
- return ns;
- }
- const struct stmmac_hwtimestamp stmmac_ptp = {
- .config_hw_tstamping = stmmac_config_hw_tstamping,
- .init_systime = stmmac_init_systime,
- .config_sub_second_increment = stmmac_config_sub_second_increment,
- .config_addend = stmmac_config_addend,
- .adjust_systime = stmmac_adjust_systime,
- .get_systime = stmmac_get_systime,
- };
|