linux/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
<<
>>
Prefs
   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 * 100) / 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