From: Masayuki Ohtak on
IEEE1588 driver of Topcliff PCH

Topcliff PCH is the platform controller hub that is going to be used in
Intel's upcoming general embedded platform. All IO peripherals in
Topcliff PCH are actually devices sitting on AMBA bus.
Topcliff PCH has IEEE1588 I/F. This driver enables IEEE1588 function on CAN or
Ethernet communications.

Signed-off-by: Masayuki Ohtake <masa-korg(a)dsn.okisemi.com>
---
drivers/char/Kconfig | 9 +
drivers/char/Makefile | 2 +
drivers/char/pch_ieee1588/Makefile | 1 +
drivers/char/pch_ieee1588/pch_ieee1588.c | 3947 ++++++++++++++++++++++++++++++
drivers/char/pch_ieee1588/pch_ieee1588.h | 528 ++++
5 files changed, 4487 insertions(+), 0 deletions(-)
create mode 100755 drivers/char/pch_ieee1588/Makefile
create mode 100644 drivers/char/pch_ieee1588/pch_ieee1588.c
create mode 100644 drivers/char/pch_ieee1588/pch_ieee1588.h

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7cfcc62..4784971 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -4,6 +4,15 @@

menu "Character devices"

+config PCH_IEEE1588
+ tristate "PCH IEEE1588 of Intel Topcliff"
+ depends on PCI
+ help
+ This driver is for PCH IEEE1588 of Topcliff which is an IOH for x86
+ embedded processor.
+ This driver enables IEEE1588 function on CAN or Ethernet
+ communications.
+
config VT
bool "Virtual terminal" if EMBEDDED
depends on !S390
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 88d6eac..81fb2d0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -113,6 +113,8 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o

+obj-$(CONFIG_PCH_IEEE1588) += pch_ieee1588/
+
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c

diff --git a/drivers/char/pch_ieee1588/Makefile b/drivers/char/pch_ieee1588/Makefile
new file mode 100755
index 0000000..e5199ac
--- /dev/null
+++ b/drivers/char/pch_ieee1588/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PCH_IEEE1588) += pch_ieee1588.o
diff --git a/drivers/char/pch_ieee1588/pch_ieee1588.c b/drivers/char/pch_ieee1588/pch_ieee1588.c
new file mode 100644
index 0000000..ad51c41
--- /dev/null
+++ b/drivers/char/pch_ieee1588/pch_ieee1588.c
@@ -0,0 +1,3947 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+
+#include "pch_ieee1588.h"
+
+static struct pch_tim_val pch_target_time; /* This variable is updated
+ from the target time
+ reached callback */
+
+static struct pch_auxtimeioctl pch_aux_time; /* This variable is updated
+ from the Auxiliary
+ master/slave time
+ captured callback */
+
+
+static u32 pch_pps_time; /* This variable is updated from the Pulse per
+ second match callback */
+
+#define PCH_IOC_TBL_ENTRIES \
+ (sizeof pch_ioc_tbl_data / sizeof pch_ioc_tbl_data[0])
+
+static void (*pch_tt_cbptr) (struct pch_tim_val tgt_time,
+ struct pch_dev *pch_pdata);
+static void (*pch_am_cbptr) (enum pch_auxmode aux_mode,
+ struct pch_tim_val aux_time, struct pch_dev *pch_pdata);
+static void (*pch_as_cbptr) (enum pch_auxmode aux_mode,
+ struct pch_tim_val aux_time, struct pch_dev *pch_pdata);
+
+static void (*pch_pps_cbptr) (u32 pps, struct pch_dev *pch_pdata);
+
+static struct pch_stats pch_stats = { 0, 0 }; /* The transmit and
+ receive timestamp
+ statistics */
+
+static struct pch_regs_set pch_regs; /* To save the state of all
+ registers of the module */
+
+/* structure to hold the module parameters */
+static struct pch_params_ pch_param = {
+ 1, 0, 0, "00:00:00:00:00:00"
+};
+
+static DEFINE_MUTEX(pch_1588_mutex);
+
+static inline void pch_pps_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+
+ /* Enable PPS Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline void pch_amms_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Auxiliary Master Mode Snapshot Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline void pch_asms_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Auxiliary Slave Mode Snapshot Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline void pch_ttm_imask_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Enable Target Time Interrupt */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline u32 pch_pps_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get PPS Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline u32 pch_amms_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Auxiliary Master Mode Snapshot Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline u32 pch_asms_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Auxiliary Slave Mode Snapshot Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline u32 pch_ttm_imask_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get Target Time Interrupt Mask value */
+ return PCH_BIT_SET_CHECK(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline void pch_pps_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable PPS Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_PPSM_MASK);
+}
+
+static inline void pch_amms_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Auxiliary Master Mode Snapshot Interrupt. */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_AMMS_MASK);
+}
+
+static inline void pch_asms_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Auxiliary Slave Mode Snapshot Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_ASMS_MASK);
+}
+
+static inline void pch_ttm_imask_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Disable Target Time Interrupt */
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_TTM_MASK);
+}
+
+static inline void pch_block_reset(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Reset Hardware Assist block */
+ PCH_SET_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_RESET);
+
+ PCH_CLR_ADDR_BIT(p + PCH_TSC_OFFSET, PCH_TSC_RESET);
+}
+
+static inline u32 pch_pps_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for PPS event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_PPS);
+}
+
+static inline u32 pch_amms_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Auxiliary Master Mode Snapshot Captured event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_SNM);
+}
+
+static inline u32 pch_asms_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Auxiliary Slave Mode Snapshot Captured event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_SNS);
+}
+
+static inline u32 pch_ttm_evt_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Poll for Target Time Reached event */
+ return PCH_BIT_SET_CHECK(p + PCH_TSE_OFFSET, PCH_TSE_TTIPEND);
+}
+
+static inline void pch_pps_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear PPS event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_PPS);
+}
+
+static inline void pch_amms_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Auxiliary Master Mode Snapshot Captured event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_SNM);
+}
+
+static inline void pch_asms_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Auxiliary Slave Mode Snapshot Captured event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_SNS);
+}
+
+static inline void pch_ttm_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Target Time Reached event */
+ PCH_SET_ADDR_BIT(p + PCH_TSE_OFFSET, PCH_TSE_TTIPEND);
+}
+
+/**
+ * pch_sys_snap_set() - Set System Time value
+ * @sys_time_low: The system time low.
+ * @sys_time_high: The system time high.
+ */
+static inline void pch_sys_snap_set(u32 sys_time_low, u32 sys_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the System Time Low Register contents */
+ PCH_REG_32_WRITE(p + PCH_STL_OFFSET, sys_time_low);
+
+ /* Update the System Time High Register contents */
+ PCH_REG_32_WRITE(p + PCH_STH_OFFSET, sys_time_high);
+}
+
+/**
+ * pch_sys_snap_get() - Get System Time Low value
+ * @sys_time_low: The system time low.
+ * @sys_time_high: The system time high.
+ */
+static inline void pch_sys_snap_get(u32 *sys_time_low, u32 *sys_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the System Time Low Register contents */
+ PCH_REG_32_READ(p + PCH_STL_OFFSET, sys_time_low);
+
+ /* Get the System Time High Register contents */
+ PCH_REG_32_READ(p + PCH_STH_OFFSET, sys_time_high);
+}
+
+/**
+ * pch_tgt_snap_set() - Set Target Time value
+ * @tgt_time_low: The target time low.
+ * @tgt_time_high: The target time high.
+ */
+static inline void pch_tgt_snap_set(u32 tgt_time_low, u32 tgt_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the Target Time Low Register contents */
+ PCH_REG_32_WRITE(p + PCH_TTL_OFFSET, tgt_time_low);
+
+ /* Update the Target Time High Register contents */
+ PCH_REG_32_WRITE(p + PCH_TTH_OFFSET, tgt_time_high);
+}
+
+/**
+ * pch_tgt_snap_get() - et Target Time value
+ * @tgt_time_low: The target time low.
+ * @tgt_time_high: The target time high.
+ */
+static inline void pch_tgt_snap_get(u32 *tgt_time_low, u32 *tgt_time_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Target Time Low Register contents */
+ PCH_REG_32_READ(p + PCH_TTL_OFFSET, tgt_time_low);
+
+ /* Get the Target Time High Register contents */
+ PCH_REG_32_READ(p + PCH_TTH_OFFSET, tgt_time_high);
+}
+
+/**
+ * pch_addend_set() - Set Frequency Scaling Value
+ * @fsv: Frequency.
+ */
+static inline void pch_addend_set(u32 fsv, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the Addend Register contents */
+ PCH_REG_32_WRITE(p + PCH_ADD_OFFSET, fsv);
+}
+
+/**
+ * pch_addend_get() - Get Frequency Scaling Value
+ * @fsv: The frequency.
+ * One can provide multiple line descriptions
+ * for arguments.
+ */
+static inline void pch_addend_get(u32 *fsv, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Addend Register contents */
+ PCH_REG_32_READ(p + PCH_ADD_OFFSET, fsv);
+}
+
+/**
+ * pch_pps_set() - Set Pulse Per Second Value
+ * @pps: The pulse per second value.
+ */
+static inline void pch_pps_set(u32 pps, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Update the PPS Compare Register contents */
+ PCH_REG_32_WRITE(p + PCH_PPS_OFFSET, pps);
+}
+
+/**
+ * pch_pps_get() - Get Pulse Per Second Value
+ * @pps: Get Pulse Per Second Value.
+ */
+static inline void pch_pps_get(u32 *pps, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the PPS Compare Register contents */
+ PCH_REG_32_READ(p + PCH_PPS_OFFSET, pps);
+}
+
+/**
+ * pch_aux_master_snap_get() - Get AMMS value
+ * @amms_low: AMMS low value.
+ * @amms_high: AMMS high value.
+ */
+static inline void pch_aux_master_snap_get(u32 *amms_low, u32 *amms_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Auxiliary Master Mode Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_AMSL_OFFSET, amms_low);
+
+ /* Get the Auxiliary Master Mode Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_AMSH_OFFSET, amms_high);
+}
+
+/**
+ * pch_aux_slave_snap_get() - Get ASMS value
+ * @asms_low: The ASMS low value.
+ * @asms_high: The ASMS high value.
+ */
+static inline void pch_aux_slave_snap_get(u32 *asms_low, u32 *asms_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Auxiliary Slave Mode Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_ASSL_OFFSET, asms_low);
+
+ /* Get the Auxiliary Slave Mode Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_ASSH_OFFSET, asms_high);
+}
+
+/**
+ * pch_master_mode_set() - Set the channel mode to 1588 Master/Slave
+ * @master_mode: The channel mode.
+ */
+static inline void pch_master_mode_set(u32 master_mode, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET or CLEAR the Master Mode */
+ if (master_mode) {
+ /* SET the mm bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_MM);
+ } else {
+ /* CLEAR the mm bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_MM);
+ }
+}
+
+static inline u32 pch_master_mode_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Check for 1588 master mode of channel */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_MM);
+}
+
+/**
+ * pch_timestamp_all_set() - Set Timestamp all or only PTP messages flag
+ * @all_msg: All/PTP messages.
+ */
+static inline void pch_timestamp_all_set(u32 all_msg, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET or CLEAR the All Message Timestamping */
+ if (all_msg) {
+ /* SET the ta bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_TA);
+ } else { /* else of if (TRUE == all_msg) */
+ /* CLEAR the ta bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_TA);
+ }
+}
+
+static inline u32 pch_timestamp_all_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Check for Timestamp all OR only PTP messages flag */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_TA);
+}
+
+/**
+ * pch_version_set() - Set the 1588 version number
+ * @version_val: The version value.
+ */
+static inline void pch_version_set(u32 version_val, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ if (version_val == TRUE) {
+ /* SET the version bit */
+ PCH_SET_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+ } else {
+ /* CLEAR the version bit */
+ PCH_CLR_ADDR_BIT(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+ }
+}
+
+static inline u32 pch_version_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the 1588 version number */
+ return PCH_BIT_SET_CHECK(p + PCH_CC_OFFSET, PCH_CC_VERSION);
+}
+
+static inline u32 pch_can_snap_valid(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* CAN Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CCE_OFFSET, PCH_CE_VAL);
+}
+
+static inline u32 pch_can_snap_ovr(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* CAN Timestamp overrun */
+ return PCH_BIT_SET_CHECK(p + PCH_CCE_OFFSET, PCH_CE_OVR);
+}
+
+static inline void pch_can_snap_valid_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear CAN Timestamp valid flag */
+ PCH_REG_32_WRITE(p + PCH_CCE_OFFSET, PCH_CE_VAL);
+}
+
+static inline void pch_can_snap_ovr_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear CAN Timestamp overrun flag */
+ PCH_REG_32_WRITE(p + PCH_CCE_OFFSET, PCH_CE_OVR);
+}
+
+static inline u32 pch_rx_snap_evt(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Receive Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CE_OFFSET, PCH_CE_RXS);
+}
+
+static inline u32 pch_tx_snap_evt(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Transmit Timestamp available */
+ return PCH_BIT_SET_CHECK(p + PCH_CE_OFFSET, PCH_CE_TXS);
+}
+
+static inline void pch_rx_snap_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Receive Timestamp available event */
+ PCH_REG_32_WRITE(p + PCH_CE_OFFSET, PCH_CE_RXS);
+}
+
+static inline void pch_tx_snap_evt_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear Transmit Timestamp available event */
+ PCH_REG_32_WRITE(p + PCH_CE_OFFSET, PCH_CE_TXS);
+}
+
+/**
+ * pch_can_snap_get() - Get PTP CAN Port Timestamp value
+ * @rxs_low: The CAN Rx low value.
+ * @rxs_high: The CAN Rx high value.
+ */
+static inline void pch_can_snap_get(u32 *rxs_low, u32 *rxs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Receive Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_CXSL_OFFSET, rxs_low);
+
+ /* Get the Receive Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_CXSH_OFFSET, rxs_high);
+}
+
+/**
+ * pch_rx_snap_get() - Get PTP Port Rx Timestamp value
+ * @rxs_low: The Snap Rx value.
+ * @rxs_high: The Snap Rx Value.
+ */
+static inline void pch_rx_snap_get(u32 *rxs_low, u32 *rxs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Receive Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_RSL_OFFSET, rxs_low);
+
+ /* Get the Receive Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_RSH_OFFSET, rxs_high);
+}
+
+/**
+ * pch_tx_snap_get() - Get PTP Port Tx Timestamp value
+ * @txs_low: The Port Tx value low.
+ * @txs_high: The Port Tx value high.
+ */
+static inline void pch_tx_snap_get(u32 *txs_low, u32 *txs_high,
+ struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Get the Transmit Timestamp/Snapshot Low Register contents */
+ PCH_REG_32_READ(p + PCH_XSL_OFFSET, txs_low);
+
+ /* Get the Transmit Timestamp/Snapshot High Register contents */
+ PCH_REG_32_READ(p + PCH_XSH_OFFSET, txs_high);
+}
+
+/**
+ * pch_uuid_seqid_get() - Get UUID and Sequence ID of PTP message
+ * @uuid_low: The UUID low value.
+ * @uuid_high: The UUID high value.
+ * @seq_id: The sequence ID.
+ */
+static inline void pch_uuid_seqid_get(u32 *uuid_low, u32 *uuid_high,
+ u32 *seq_id, struct pch_dev *chip)
+{
+ u32 regval;
+ void __iomem *p = chip->mem_virt;
+
+ /* Get the UUID Low Register contents */
+ PCH_REG_32_READ(p + PCH_UID_OFFSET, uuid_low);
+
+ /* Get the Sequence ID and Source UUID High Register contents */
+ PCH_REG_32_READ(p + PCH_SID_OFFSET, &regval);
+
+ *seq_id = regval >> PCH_SID_LOC;
+ *uuid_high = regval & PCH_LSB_SHORT_MASK;
+}
+
+/**
+ * pch_op_mode_set() - Sets the operation mode
+ * @mode: Sets the operation mode.
+ */
+static inline void pch_op_mode_set(u32 mode, struct pch_dev *chip)
+{
+ u32 regval;
+ void __iomem *p = chip->mem_virt;
+
+ PCH_REG_32_READ(p + PCH_CC_OFFSET, &regval);
+ regval = (regval & ~PCH_CC_MODE_MASK) | (mode << PCH_CC_MODE_SHIFT);
+ /* set the operaion mode bits */
+ PCH_REG_32_WRITE(p + PCH_CC_OFFSET, regval);
+}
+
+static inline u32 pch_op_mode_get(struct pch_dev *chip)
+{
+ u32 regval;
+ u32 mode;
+ void __iomem *p = chip->mem_virt;
+
+ PCH_REG_32_READ(p + PCH_CC_OFFSET, &regval);
+ /* get the operaion mode bits */
+ mode = (regval & PCH_CC_MODE_MASK) >> PCH_CC_MODE_SHIFT;
+
+ return mode;
+}
+
+static inline void pch_eth_enable_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET the eth_enable bit */
+ PCH_SET_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline void pch_eth_enable_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear the eth_enable bit */
+ PCH_CLR_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline u32 pch_eth_enable_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Is eth_enable bit set? */
+ return PCH_BIT_SET_CHECK(p + PCH_ECS_OFFSET, PCH_ECS_ETH);
+}
+
+static inline void pch_can_enable_set(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* SET the can_enable bit */
+ PCH_SET_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+static inline void pch_can_enable_clear(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Clear the can_enable bit */
+ PCH_CLR_ADDR_BIT(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+static inline u32 pch_can_enable_get(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Gets the CAN enable status */
+ return PCH_BIT_SET_CHECK(p + PCH_ECS_OFFSET, PCH_ECS_CAN);
+}
+
+/**
+ * pch_station_set() - Set the station[1-6] address to be used in
+ * PTP message
+ * @station: station ID.
+ * @value: station address value.
+ */
+static inline void
+pch_station_set(u32 station, u32 value, struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ /* Set the Station Address Register contents */
+ PCH_REG_32_WRITE(p + PCH_STA_OFFSET + station * sizeof(s32), value);
+}
+
+/**
+ * pch_station_get() - Get the station[1-6] address used in PTP message
+ * @station: station ID.
+ * @value: Pointer to set station address value.
+ */
+static inline u32 pch_station_get(u32 station, struct pch_dev *chip)
+{
+ u32 value;
+ void __iomem *p = chip->mem_virt;
+
+ /* Get the Station Address Register contents */
+ PCH_REG_32_READ(p + PCH_STA_OFFSET + station * sizeof(s32), &value);
+ value &= 0xFF; /* only one byte */
+
+ return value;
+}
+
+static enum pch_status pch_disable_interrupts(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ if (p != 0) {
+ pch_ttm_imask_clear(chip);
+ pch_asms_imask_clear(chip);
+ pch_amms_imask_clear(chip);
+ pch_pps_imask_clear(chip);
+ }
+ return 0;
+}
+
+/**
+ * pch_interrupt_pending() - Check whether there is any pending interrupts
+ * from the 1588 device
+ * @pending: Pending flag which set to TRUE if there is any pending
+ * interrupt.
+ * @pch_pdata: Private data for PCH.
+ */
+static u32 pch_interrupt_pending(struct pch_dev *pch_pdata)
+{
+ u32 pending;
+
+ if (pch_pps_evt_get(pch_pdata) || pch_amms_evt_get(pch_pdata) ||
+ pch_asms_evt_get(pch_pdata) || pch_ttm_evt_get(pch_pdata)) {
+ pending = FALSE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt pending\n", __func__);
+ pending = TRUE;
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO interrupt pending\n", __func__);
+ }
+ return pending;
+}
+
+/**
+ * pch_port_mode_get() - Function to determine the port mode
+ * @ptpport: Interested port (GBE_0).
+ * @qq: aa.
+ */
+static enum pch_ptpportmode
+pch_port_mode_get(enum pch_ptpport ptpport, struct pch_dev *pch_pdata)
+{
+ /* Local variables */
+ u32 master_mode = FALSE;
+ u32 any_mode = FALSE;
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_SLAVE;
+
+ /* Get the Mode of the PTP Port */
+ master_mode = pch_master_mode_get(pch_pdata);
+ any_mode = pch_timestamp_all_get(pch_pdata);
+
+ /* Is ANY mode (all message timestamp mode) on? */
+ if (any_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:all messages being timestamped\n", __func__);
+ /*
+ * When Any mode is set, all messages are time stamped,
+ * irrespective of the Master/Slave mode bit
+ */
+ port_mode = PCH_1588PTP_PORT_ANYMODE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_ANYMODE\n", __func__);
+ } else {
+ /* Is Master mode on? */
+ if (master_mode) {
+ port_mode = PCH_1588PTP_PORT_MASTER;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_MASTER\n", __func__);
+ } else {
+ port_mode = PCH_1588PTP_PORT_SLAVE;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode = PCH_1588PTP_PORT_SLAVE\n", __func__);
+ }
+ }
+
+ return port_mode;
+}
+
+/**
+ * pch_blpl_base_address_set() - Function sets the virtual address of
+ * registers
+ * @base_addr: Virtual address of IEEE 1588 module registers.
+ *
+ * This API will set the starting virtual addresses for the 1588 hardware
+ * registers.
+ */
+static void pch_blpl_base_address_set(struct pch_dev *chip)
+{
+ /* Initialize the callback pointers */
+ pch_tt_cbptr = NULL;
+ pch_am_cbptr = NULL;
+ pch_as_cbptr = NULL;
+ pch_pps_cbptr = NULL;
+
+ /* Reset the statistics counters */
+ pch_stats.rxmsgs = pch_stats.txmsgs = 0;
+
+ /* Clear availability of various events */
+ pch_pps_evt_clear(chip);
+ pch_ttm_evt_clear(chip);
+ pch_amms_evt_clear(chip);
+ pch_asms_evt_clear(chip);
+}
+
+/**
+ * pch_ptp_port_config_set() - Configure IEEE 1588 Hardware Assist message
+ * detection on a given PTP port
+ * @ptpport: port on which PTP message detection to be enabled.
+ * @ptpportmode: Master/Slave/All messages.
+ *
+ * This API enables the time stamping on a particular PTP port.
+ */
+static enum pch_status
+pch_ptp_port_config_set(enum pch_ptpport ptpport,
+ enum pch_ptpportmode ptpportmode,
+ struct pch_dev *pch_pdata)
+{
+ u32 master_mode, timestamp_set;
+ /* Verify the parameters for proper values */
+ if (ptpport != PCH_GBE_0_1588PTP_PORT) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid ptp port returning PCH_GBE_0_1588PTP_PORT\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ if (ptpportmode == PCH_1588PTP_PORT_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_MASTER\n", __func__);
+ master_mode = TRUE;
+ timestamp_set = FALSE;
+ } else if (ptpportmode == PCH_1588PTP_PORT_SLAVE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_SLAVE\n", __func__);
+ master_mode = FALSE;
+ timestamp_set = FALSE;
+ } else if (ptpportmode == PCH_1588PTP_PORT_ANYMODE) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port_mode=PCH_1588PTP_PORT_ANYMODE\n", __func__);
+ master_mode = FALSE;
+ timestamp_set = TRUE;
+ } else {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port Mode (%d) returning "
+ "PCH_INVALIDPARAM\n", __func__, ptpportmode);
+ return PCH_INVALIDPARAM;
+ }
+ pch_master_mode_set(master_mode, pch_pdata);
+ pch_timestamp_all_set(timestamp_set, pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_port_config_get() - Get the configuration of IEEE 1588 Hardware
+ * Assist message detection for given PTP port
+ * @ptpport: port for which PTP message configuration to be obtained.
+ * @ptpportmode: Master/Slave/All messages.
+ *
+ * This API retrieves the time stamping configuration of the given PTP port.
+ */
+static enum pch_status
+pch_ptp_port_config_get(enum pch_ptpport ptpport,
+ enum pch_ptpportmode *ptpportmode,
+ struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpportmode == (enum pch_ptpportmode *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port_mode or port returning PCH_INVALIDPARAM\n",
+ __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the Mode of the PTP Port */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_port_mode_get\n", __func__);
+ *ptpportmode = pch_port_mode_get(ptpport, pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_ptp_rx_poll() - Poll the IEEE 1588 Hardware Assist receive side
+ * message/time stamp detection status for given PTP
+ * Port
+ * @ptpport: port on which time stamp availability to be checked.
+ * @ptpmsgdata: Captured time stamp and other message information.
+ *
+ * This API will poll for the availability of a time stamp on the received
+ * Sync (in slave mode) or Delay_Req (in master mode) messages.
+ */
+static enum pch_status
+pch_ptp_rx_poll(enum pch_ptpport ptpport, struct pch_ptpmsgdata *ptpmsgdata,
+ struct pch_dev *pch_pdata)
+{
+ u32 locked_mode = FALSE;
+
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_MODE_INVALID;
+ enum pch_ptpversion ptpversion = PCH_1588PTP_VERSION_INVALID;
+ enum pch_ptpope_mode op_mode = PCH_1588PTP_OP_MODE_INVALID;
+
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpmsgdata == (struct pch_ptpmsgdata *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port or ptp message "
+ "returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the PTP version */
+ ptpversion = pch_version_get(pch_pdata);
+
+ /* check if locked/unlocked mode */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ /* Get the Mode of the PTP Port if only PTPv1 is supported */
+ port_mode = pch_port_mode_get(ptpport, pch_pdata);
+ if (port_mode != PCH_1588PTP_PORT_ANYMODE)
+ locked_mode = TRUE;
+ } else { /* PTP v1 & v2 */
+
+ /* get operation mode */
+ op_mode = pch_op_mode_get(pch_pdata);
+ if ((op_mode != PCH_1588PTP_OP_MODE_V1_ALL_MSGS) &&
+ (op_mode != PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS)) {
+ locked_mode = TRUE;
+ }
+ }
+
+ /* if locked mode,check event flag */
+ if (locked_mode && (!pch_rx_snap_evt(pch_pdata))) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:locked mode-event flag not set. "
+ "NO TIMESTAMP returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* Fetch the receive timestamp */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_rx_snap_get\n", __func__);
+
+ pch_rx_snap_get(&ptpmsgdata->ptptimestamp.tim_val_low_word,
+ &ptpmsgdata->ptptimestamp.tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s Snapshot (Hi:Low): %x : %x\n",
+ __func__, ptpmsgdata->ptptimestamp.tim_val_high_word,
+ ptpmsgdata->ptptimestamp.tim_val_low_word);
+
+ /* Fetch the UUID & Seq# of PTP messages in 'Master/Slave Mode' only */
+ if ((locked_mode) && (PCH_1588PTP_VERSION_0 == ptpversion)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_uuid_seqid_get\n", __func__);
+ pch_uuid_seqid_get(&ptpmsgdata->ptpuuid.uuid_val_low_word,
+ &ptpmsgdata->ptpuuid.
+ uuid_val_high_half_word,
+ &ptpmsgdata->ptpsequencenumber,
+ pch_pdata);
+ }
+ /* Clear-off the UUID & Seq# of all the messages in 'Any Mode' */
+ else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:port mode is ANYMODE,clearing off UUID & SeqNumber\n",
+ __func__);
+ ptpmsgdata->ptpuuid.uuid_val_low_word = 0;
+ ptpmsgdata->ptpuuid.uuid_val_high_half_word = 0;
+ ptpmsgdata->ptpsequencenumber = 0;
+ }
+
+ /* Increment receive timestamp counter
+ * Note:In unlocked modes,this will get incremented
+ * for every rx time stamp poll.
+ */
+ pch_stats.rxmsgs++;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:incremented rcv timestamp counter=%d\n",
+ __func__, pch_stats.rxmsgs);
+
+ /*
+ * Fill-in the PTP message type.This can be done
+ * only when PTP v1 alone is supported and mode
+ * is master/slave.Set the message type as unknown
+ * for all other cases.
+ */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ switch (port_mode) {
+ case PCH_1588PTP_PORT_MASTER:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_DELAYREQ\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_DELAYREQ;
+ break;
+ case PCH_1588PTP_PORT_SLAVE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_SYNC\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_SYNC;
+ break;
+ case PCH_1588PTP_PORT_ANYMODE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type=PCH_1588PTP_MSGTYP"
+ "E_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ break;
+ default:
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port "
+ "Mode returning PCH_FAILED\n", __func__);
+ return PCH_FAILED;
+ }
+ } else { /* PTP v1 & v2 */
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ }
+
+ /* If locked mode allow next timestamp to be captured */
+ if (locked_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_rx_snap_evt_clear\n", __func__);
+ pch_rx_snap_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_ptp_tx_poll() - Poll the IEEE 1588 Hardware Assist transmit side
+ * message/time stamp detection status for given PTP
+ * Port
+ * @ptpport: port on which time stamp availability to be checked.
+ * @ptpmsgdata: Captured time stamp and other message information.
+ *
+ * This API will poll for the availability of a time stamp on the transmit side
+ * Sync (in master mode) or Delay_Req (in slave mode) messages.
+ */
+static enum pch_status
+pch_ptp_tx_poll(enum pch_ptpport ptpport, struct pch_ptpmsgdata *ptpmsgdata,
+ struct pch_dev *pch_pdata)
+{
+ u32 locked_mode = FALSE;
+
+ enum pch_ptpportmode port_mode = PCH_1588PTP_PORT_MODE_INVALID;
+ enum pch_ptpversion ptpversion = PCH_1588PTP_VERSION_INVALID;
+ enum pch_ptpope_mode op_mode = PCH_1588PTP_OP_MODE_INVALID;
+
+ /* Verify the parameters for proper values */
+ if ((ptpport != PCH_GBE_0_1588PTP_PORT) ||
+ (ptpmsgdata == (struct pch_ptpmsgdata *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid port or ptp message "
+ "returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get the PTP version */
+ ptpversion = pch_version_get(pch_pdata);
+
+ /*check if locked/unlocked mode */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ /* Get the Mode of the PTP Port if only PTPv1 is supported */
+ port_mode = pch_port_mode_get(ptpport, pch_pdata);
+ if (port_mode != PCH_1588PTP_PORT_ANYMODE)
+ locked_mode = TRUE;
+ } else { /* PTP v1 & v2 */
+
+ /* get operation mode */
+ op_mode = pch_op_mode_get(pch_pdata);
+ if ((op_mode != PCH_1588PTP_OP_MODE_V1_ALL_MSGS) &&
+ (op_mode != PCH_1588PTP_OP_MODE_V1_V2_ALL_MSGS)) {
+ locked_mode = TRUE;
+ }
+ }
+
+ /* if locked mode,check event flag */
+ if ((locked_mode) && (!pch_tx_snap_evt(pch_pdata))) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:locked mode-event flag not set."
+ "NO TIMESTAMP returning PCH_NOTIMESTAMP\n", __func__);
+ return PCH_NOTIMESTAMP;
+ }
+
+ /* read time stamp registers */
+ pch_tx_snap_get(&ptpmsgdata->ptptimestamp.tim_val_low_word,
+ &ptpmsgdata->ptptimestamp.tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Snapshot (Hi:Low): %x : %x\n", __func__,
+ ptpmsgdata->ptptimestamp.tim_val_high_word,
+ ptpmsgdata->ptptimestamp.tim_val_low_word);
+ /*
+ * Fill the UUID and Seq# with invalid values (zeros)
+ * since they are not relevant for transmit timestamp
+ */
+ ptpmsgdata->ptpuuid.uuid_val_low_word = 0;
+ ptpmsgdata->ptpuuid.uuid_val_high_half_word = 0;
+ ptpmsgdata->ptpsequencenumber = 0;
+
+ /*
+ * Increment transmit timestamp counter
+ * Note:In unlocked modes,this will get incremented
+ * for every tx time stamp poll
+ */
+ pch_stats.txmsgs++;
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:incremented tx timestamp counter=%d\n", __func__,
+ pch_stats.txmsgs);
+
+ /*
+ * Fill-in the PTP message type.This can be done
+ * only when PTP v1 alone is supported and mode
+ * is master/slave.Set the message type as unknown
+ * for all other cases.
+ */
+ if (ptpversion == PCH_1588PTP_VERSION_0) { /* PTP v1 only */
+ switch (port_mode) {
+ case PCH_1588PTP_PORT_MASTER:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_SYNC\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_SYNC;
+ break;
+ case PCH_1588PTP_PORT_SLAVE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_DELAYREQ\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_DELAYREQ;
+ break;
+ case PCH_1588PTP_PORT_ANYMODE:
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ break;
+ default:
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: Invalid Port Mode returning PCH_FAILED\n",
+ __func__);
+ return PCH_FAILED;
+ }
+ } else { /* PTP v1 & v2 */
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PTP message type="
+ "PCH_1588PTP_MSGTYPE_UNKNOWN\n", __func__);
+ ptpmsgdata->ptpmsgtype = PCH_1588PTP_MSGTYPE_UNKNOWN;
+ }
+
+ /* If locked mode allow next timestamp to be captured */
+ if (locked_mode) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invoking pch_tx_snap_evt_clear\n", __func__);
+ pch_tx_snap_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_system_time_set() - Sets the system time to given value
+ * @systemTime: value to set the system time.
+ */
+static enum pch_status pch_system_time_set(struct pch_tim_val systemTime,
+ struct pch_dev *chip)
+{
+ u32 old_fsv;
+
+ /* Retrieve old Frequency Scaling Value */
+ pch_addend_get(&old_fsv, chip);
+
+ /*
+ * Set the Frequency Scaling Value to zero (0) so that
+ * System Time doesn't get incremented while it is being written to
+ */
+ pch_addend_set(0, chip);
+
+ /* Update System Time with user specified values */
+ pch_sys_snap_set(systemTime.tim_val_low_word,
+ systemTime.tim_val_high_word, chip);
+
+ /*
+ * Let the hardware assist re-evaluate the target time reached
+ * condition based on the new system time
+ */
+ pch_ttm_evt_clear(chip);
+
+ /*
+ * Restore old Frequency Scaling Value so that System Time
+ * can be incremented
+ */
+ pch_addend_set(old_fsv, chip);
+
+ return 0;
+}
+
+/**
+ * pch_system_time_get() - Gets the System Time from the IEEE 1588 hardware
+ * assist block
+ * @systemTime: Address to which system time is to be returned.
+ * @qq: aa.
+ */
+static enum pch_status pch_system_time_get(struct pch_tim_val *systemTime,
+ struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (systemTime == (struct pch_tim_val *) NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Fetch System Time */
+ pch_sys_snap_get(&systemTime->tim_val_low_word,
+ &systemTime->tim_val_high_word, chip);
+
+ return 0;
+}
+
+/**
+ * pch_tick_rate_set() - Sets the Frequency Scaling Value in the IEEE 1588
+ * hardware assist block
+ * @tickrate: Frequency scaling value.
+ *
+ * This API sets the Tick Rate (Frequency Scaling Value) in the IEEE 1588 block.
+ * This value determines the progress at which the System time advances.
+ * Note: For the A1 hardware sample, the addend register value configured in
+ * the hardware is calculated as follows:
+ * Addend register value = Logical right shift tickrate by 1 and set MSB to 1
+ */
+static enum pch_status pch_tick_rate_set(u32 tickrate, struct pch_dev *chip)
+{
+ /* Update the Frequency Scaling Value */
+ pch_addend_set(tickrate, chip);
+
+ return 0;
+}
+
+/**
+ * pch_tick_rate_get() - Gets the Frequency Scaling Value from the
+ * IEEE 1588 hardware assist block
+ * @tickrate: Address where current Frequency scaling value is returned.
+ *
+ * This API gets the Tick Rate (Frequency Scaling Value) used in the IEEE 1588
+ * block.This value determines the progress at which the System time advances.
+ */
+static enum pch_status pch_tick_rate_get(u32 *tickrate, struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (tickrate == (u32 *)NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Retrieve Current Frequency Scaling Value */
+ pch_addend_get(tickrate, chip);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_interrupt_enable() - Enable the target time
+ * reached/exceeded system time
+ * interrupt
+ * @callBack: Routine to be invoked when target time reached interrupt occurs.
+ */
+static enum pch_status pch_target_time_interrupt_enable
+ (void (*callBack) (struct pch_tim_val, struct pch_dev *),
+ struct pch_dev *chip)
+{
+ /* Verify the parameter */
+ if (callBack == NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Register the Callback */
+ pch_tt_cbptr = callBack;
+
+ /* Set target time interrupt mask */
+ pch_ttm_imask_set(chip);
+
+ return 0;
+}
+
+static enum pch_status pch_target_time_interrupt_disable(struct pch_dev *chip)
+{
+ /* Clear target time interrupt mask */
+ pch_ttm_imask_clear(chip);
+
+ /* Unregister the Callback */
+ pch_tt_cbptr = NULL;
+
+ return 0;
+}
+
+
+/**
+ * pch_target_time_poll() - Poll to verify whether the System time is
+ * greater or equal to the Target time in the
+ * IEEE 1588 hardware assist block.
+ * @ttm_poll_flag: Flag means like below
+ * TRUE if target time has reached system time
+ * FALSE if target time has not reached system time
+ * @target_tim: Snap shot of target time captured.
+ */
+static enum pch_status
+pch_target_time_poll(u32 *ttm_poll_flag,
+ struct pch_tim_val *target_tim, struct pch_dev *pch_pdata)
+{
+ unsigned long flags;
+ /* Verify the parameters */
+ if ((ttm_poll_flag == (u32 *)NULL) ||
+ (target_tim == (struct pch_tim_val *) NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s: invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_tt_cbptr != NULL) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:returning PCH_INTERRUPTMODEINUSE\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the System Time reached or exceeded Target Time? */
+ *ttm_poll_flag = pch_ttm_evt_get(pch_pdata);
+ if (!*ttm_poll_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:target time not reached\n", __func__);
+ /* Target Time not to be returned yet */
+ target_tim->tim_val_low_word = 0;
+ target_tim->tim_val_high_word = 0;
+
+ return 0;
+ }
+
+ dev_dbg(&pch_pdata->pdev->dev, "%s:target time reached\n", __func__);
+ /* Get the Target Time */
+ spin_lock_irqsave(&pch_pdata->lock, flags);/*need*/
+ pch_tgt_snap_get(&target_tim->tim_val_low_word,
+ &target_tim->tim_val_high_word, pch_pdata);
+ spin_unlock_irqrestore(&pch_pdata->lock, flags);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:target time:low=%x high=%x\n", __func__,
+ target_tim->tim_val_low_word, target_tim->tim_val_high_word);
+
+ /* Clear the target time reached condition (ttipend bit) */
+ pch_ttm_evt_clear(pch_pdata);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_set() - Sets the Target Time in the IEEE 1588 hardware
+ * assist block
+ * @target_tim: Target time to set.
+ */
+static enum pch_status pch_target_time_set(struct pch_tim_val target_tim,
+ struct pch_dev *chip)
+{
+ unsigned long flags;
+ u32 old_mask = FALSE;
+
+ /* Retrieve existing target time interrupt mask value */
+ old_mask = pch_ttm_imask_get(chip);
+
+ /*
+ * Clear the target time interrupt mask so that the interrupt will not
+ * come
+ * during the time we manipulate the registers.
+ */
+ pch_ttm_imask_clear(chip);
+
+ /* Update Target Time with user specified values */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_set(target_tim.tim_val_low_word,
+ target_tim.tim_val_high_word, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /*
+ * Let the hardware assist re-evaluate the target time reached
+ * condition based on the new target time
+ */
+ pch_ttm_evt_clear(chip);
+
+ /* Restore the preserved target time interrupt mask value */
+ if (old_mask == TRUE)
+ pch_ttm_imask_set(chip);
+
+ return 0;
+}
+
+/**
+ * pch_target_time_get() - Gets the Target Time in the IEEE 1588 hardware
+ * assist block
+ * @target_tim: Address to which target time is to be returned.
+ */
+static enum pch_status pch_target_time_get(struct pch_tim_val *target_tim,
+ struct pch_dev *chip)
+{
+ unsigned long flags;
+ /* Verify the parameter */
+ if (target_tim == (struct pch_tim_val *) NULL)
+ return PCH_INVALIDPARAM;
+
+ /* Get Target Time */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_get(&target_tim->tim_val_low_word,
+ &target_tim->tim_val_high_word, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_interrupt_enable() - Enables the interrupt for the
+ * Auxiliary Master/Slave mode for Time
+ * Stamp in the IEEE 1588 hardware assist
+ * block
+ * @auxmode: Auxiliary slave or master mode.
+ * @callBack: Callback to be invoked when interrupt fires.
+ */
+
+static enum pch_status
+pch_aux_time_interrupt_enable(enum pch_auxmode auxmode,
+ void (*callBack) (enum pch_auxmode,
+ struct pch_tim_val, struct pch_dev *),
+ struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters */
+ if ((PCH_AUXMODE_INVALID <= auxmode) || (callBack == NULL)) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Register the Callback and SET the amm/asm bits on */
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_MASTER invoking pch_amms_imask_set\n",
+ __func__);
+ pch_am_cbptr = callBack;
+ pch_amms_imask_set(pch_pdata);
+
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_SLAVE invoking pch_asms_imask_set\n", __func__);
+ pch_as_cbptr = callBack;
+ pch_asms_imask_set(pch_pdata);
+ }
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_interrupt_disable() - Disables the interrupt
+ * @auxmode: uxiliary slave or master mode.
+ *
+ * Disables the interrupt for the Auxiliary Master/Slave mode for Time Stamp in
+ * the IEEE 1588 hardware assist block.
+ */
+static enum pch_status pch_aux_time_interrupt_disable
+ (enum pch_auxmode auxmode, struct pch_dev *pch_pdata)
+{
+ /* Verify the parameters */
+ if (PCH_AUXMODE_INVALID <= auxmode) {
+ dev_err(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev, "%s: PCH_AUXMODE_MASTER invoking"
+ " pch_amms_imask_clear\n", __func__);
+ pch_amms_imask_clear(pch_pdata);
+ pch_am_cbptr = NULL;
+ } else {
+ dev_dbg(&pch_pdata->pdev->dev, "%s:PCH_AUXMODE_SLAVE invoking"
+ " pch_asms_imask_clear\n", __func__);
+ pch_asms_imask_clear(pch_pdata);
+ pch_as_cbptr = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_aux_time_poll() - Poll for the Auxiliary Time Stamp captured event
+ * for the mode requested
+ * @auxmode: Auxiliary Snapshot Register(Master/Slave) to be checked.
+ * @poll_flag: TRUE if time stamp captured in aux snapshot register.
+ * @auxtime: Buffer for returning captured Auxiliary Snapshot time.
+ *
+ * Polls for the Time stamp in the appropriate Auxiliary Snapshot Registers
+ * based on the mode specified. Return true and the contents of the Auxiliary
+ * snapshot if it is available otherwise return false.
+ */
+
+static enum pch_status
+pch_aux_time_poll(enum pch_auxmode auxmode, u32 *poll_flag,
+ struct pch_tim_val *auxtime, struct pch_dev *pch_pdata)
+{
+ u32 amms_flag = FALSE;
+ u32 asms_flag = FALSE;
+
+ /* Verify the parameters */
+ if ((poll_flag == (u32 *)NULL) ||
+ (PCH_AUXMODE_INVALID <= auxmode) ||
+ (auxtime == (struct pch_tim_val *) NULL)) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:invalid param returning PCH_INVALIDPARAM\n", __func__);
+ return PCH_INVALIDPARAM;
+ }
+
+ /* Get Auxiliary Master/Slave Mode Snapshot */
+ if (auxmode == PCH_AUXMODE_MASTER) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_MASTER\n", __func__);
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_am_cbptr != NULL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt mode in use\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the Auxiliary Master Mode Snapshot available? */
+ amms_flag = pch_amms_evt_get(pch_pdata);
+ if (!amms_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO Auxiliary Master Mode Snapshot available\n",
+ __func__);
+ *poll_flag = FALSE;
+ auxtime->tim_val_low_word = 0;
+ auxtime->tim_val_high_word = 0;
+ return 0;
+ }
+
+ /* Get Auxiliary Master Snapshot */
+ pch_aux_master_snap_get(&auxtime->tim_val_low_word,
+ &auxtime->tim_val_high_word, pch_pdata);
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Master Snapshot low=%x,high=%x\n",
+ __func__, auxtime->tim_val_low_word,
+ auxtime->tim_val_high_word);
+
+ *poll_flag = TRUE;
+
+ pch_amms_evt_clear(pch_pdata);
+ } else { /* PCH_AUXMODE_SLAVE == auxmode */
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:PCH_AUXMODE_SLAVE\n", __func__);
+ /* Is interrupt mode of processing is enabled? */
+ if (pch_as_cbptr != NULL) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:interrupt mode in use\n", __func__);
+ return PCH_INTERRUPTMODEINUSE;
+ }
+
+ /* Is the Auxiliary Slave Mode Snapshot available? */
+ asms_flag = pch_asms_evt_get(pch_pdata);
+ if (!asms_flag) {
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:NO Auxiliary Slave Mode Snapshot available\n",
+ __func__);
+ *poll_flag = FALSE;
+ auxtime->tim_val_low_word = 0;
+ auxtime->tim_val_high_word = 0;
+ return 0;
+ }
+
+ /* Get Auxiliary Slave Snapshot */
+
+ pch_aux_slave_snap_get(&auxtime->tim_val_low_word,
+ &auxtime->tim_val_high_word, pch_pdata);
+
+ dev_dbg(&pch_pdata->pdev->dev,
+ "%s:Auxiliary Slave Snapshot low=%x,high=%x\n",
+ __func__, auxtime->tim_val_low_word,
+ auxtime->tim_val_high_word);
+
+ *poll_flag = TRUE;
+
+ /* Clear the snapshot availability condition */
+ pch_asms_evt_clear(pch_pdata);
+ }
+
+ return 0;
+}
+
+/* This function enables all 64 bits in system time registers [high & low].
+This is a work-around for non continuous value in the SystemTime Register*/
+static void pch_set_system_time_count(struct pch_dev *chip)
+{
+ void __iomem *p = chip->mem_virt;
+ PCH_REG_32_WRITE((p + 0xC0), 0x1);
+ PCH_REG_32_WRITE((p + 0xC4), 0xFFFFFFFF);
+ PCH_REG_32_WRITE((p + 0xC0), 0x0);
+}
+
+static enum pch_status pch_reset(struct pch_dev *chip)
+{
+ /* Reset Hardware Assist */
+ pch_block_reset(chip);
+
+ /* Clear Stats */
+ pch_stats.rxmsgs = 0;
+ pch_stats.txmsgs = 0;
+
+ /* Unregister any Callback Routines */
+ pch_pps_cbptr = NULL;
+ pch_tt_cbptr = NULL;
+ pch_am_cbptr = NULL;
+ pch_as_cbptr = NULL;
+
+ /* enable all 32 bits in system time registers */
+ pch_set_system_time_count(chip);
+
+ return 0;
+}
+
+/**
+ * pch_stats_get() - Returns the pch1588 Statistics
+ * @stats: Buffer for returning the statistics counter values.
+ */
+static enum pch_status pch_stats_get(struct pch_stats *stats)
+{
+ /* Verify the parameter */
+ if (stats == (struct pch_stats *) NULL)
+ return PCH_INVALIDPARAM;
+
+
+ /* Return the statistics */
+ stats->rxmsgs = pch_stats.rxmsgs;
+ stats->txmsgs = pch_stats.txmsgs;
+
+ return 0;
+}
+
+static void pch_stats_reset(void)
+{
+ /* Clear the statistics */
+ pch_stats.rxmsgs = 0;
+ pch_stats.txmsgs = 0;
+
+ return;
+}
+
+static void pch_save_state(struct pci_dev *pdev)
+{
+ s32 i;
+ u32 val;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+ unsigned long flags;
+
+ /* Time stamp control register */
+ pch_regs.ts_control =
+ (pch_ttm_imask_get(chip) << PCH_TSC_TTM_SHIFT) |
+ (pch_asms_imask_get(chip) << PCH_TSC_ASMS_SHIFT) |
+ (pch_amms_imask_get(chip) << PCH_TSC_AMMS_SHIFT) |
+ (pch_pps_imask_get(chip) << PCH_TSC_PPSM_SHIFT);
+ dev_dbg(&pdev->dev,
+ "%s:TS_CONTROL reg=%x\n", __func__, pch_regs.ts_control);
+
+ /*
+ * Time stamp event register; clear on write,
+ * so no point in reading and then saving;
+ * Will be cleared on restore to start in a clean slate
+ */
+ pch_regs.ts_event = PCH_TSE_TTIPEND | PCH_TSE_SNS |
+ PCH_TSE_SNM | PCH_TSE_PPS;
+ dev_dbg(&pdev->dev,
+ "%s:TS_EVENT reg=%x\n", __func__, pch_regs.ts_event);
+
+ /* Addend register */
+ pch_addend_get(&pch_regs.ts_addend, chip);
+ dev_dbg(&pdev->dev,
+ "%s:TS_ADDEND reg=%x\n", __func__, pch_regs.ts_addend);
+
+ /* PPS comapre register */
+ pch_pps_get(&pch_regs.ts_compare, chip);
+ dev_dbg(&pdev->dev,
+ "%s:TS_COMPARE reg=%x\n", __func__, pch_regs.ts_compare);
+
+ /* System time Low and Hi registers */
+ pch_sys_snap_get(&pch_regs.ts_syslo, &pch_regs.ts_syshi, chip);
+ dev_dbg(&pdev->dev,
+ "%s:sys time reg-low =%x,high=%x\n",
+ __func__, pch_regs.ts_syslo, pch_regs.ts_syshi);
+
+ /* Target time Low and Hi registers */
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_get(&pch_regs.ts_tgtlo, &pch_regs.ts_tgthi, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+ dev_dbg(&pdev->dev, "%s:target time reg-low =%x,high=%x\n",
+ __func__, pch_regs.ts_tgtlo, pch_regs.ts_tgthi);
+
+#if 0
+ /*
+ * Below registers are read only, so no point in reading/storing, since
+ * we can't restore them
+ */
+ /* Slave mode snapshot Low and Hi registers */
+ pch_aux_slave_snap_get(&pch_regs.ts_asmslo,
+ &pch_regs.ts_asmshi);
+
+ /* Master mode snapshot Low and Hi registers */
+ pch_aux_master_snap_get(&pch_regs.ts_ammslo,
+ &pch_regs.ts_ammshi);
+#endif
+ pch_regs.ts_cc =
+ (pch_master_mode_get(chip) << PCH_CC_MM_SHIFT) |
+ (pch_timestamp_all_get(chip) << PCH_CC_TA_SHIFT) |
+ (pch_op_mode_get(chip) << PCH_CC_MODE_SHIFT) |
+ (pch_version_get(chip) << PCH_CC_VERSION_SHIFT);
+ dev_dbg(&pdev->dev, "%s:TS_CC reg=%x\n", __func__, pch_regs.ts_cc);
+
+ /* Channel event register, not saved - will be cleared on restore */
+ pch_regs.ts_ce = PCH_CE_TXS | PCH_CE_RXS;
+
+#if 0
+ /*
+ * Below registers are read only, so no point in reading/storing, since
+ * we can't restore them
+ */
+ pch_rx_snap_get(&pch_regs.ts_xslo, &pch_regs.ts_xshi);
+ pch_tx_snap_get(&pch_regs.ts_rslo, &pch_regs.ts_rshi);
+ pch_uuid_seqid_get(&pch_regs.ts_uuidlo,
+ &pch_regs.ts_uuidhi);
+
+ /* CAN */
+ pch_can_snap_get(&pch_regs.ts_cxslo, &pch_regs.ts_cxshi);
+#endif
+
+ /* CAN Channel event register, not saved - will be cleared on restore */
+ pch_regs.ts_cce = PCH_CE_OVR | PCH_CE_VAL;
+
+ /* Ethernet CAN selector register */
+ pch_regs.ts_sel =
+ (pch_eth_enable_get(chip) << PCH_ECS_ETH_SHIFT) |
+ (pch_can_enable_get(chip) << PCH_ECS_CAN_SHIFT);
+ dev_dbg(&pdev->dev, "%s:TS_SEL reg=%x\n", __func__, pch_regs.ts_sel);
+
+ /* Station Address registers */
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ val = pch_station_get(i, chip);
+ pch_regs.ts_sti[i] = val & 0xff;
+ dev_dbg(&pdev->dev,
+ "%s:TS_ST[%d] reg=%d\n", __func__, i, pch_regs.ts_sti[i]);
+ }
+}
+
+static void pch_restore_state(struct pci_dev *pdev)
+{
+ s32 i;
+ unsigned long flags;
+ struct pch_dev *chip = pci_get_drvdata(pdev);
+
+ /* Time stamp control register */
+ if (pch_regs.ts_control & PCH_TSC_TTM_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_ttm_imask_set\n", __func__);
+ pch_ttm_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_ASMS_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_asms_imask_set\n", __func__);
+ pch_asms_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_AMMS_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_amms_imask_set\n", __func__);
+ pch_amms_imask_set(chip);
+ }
+ if (pch_regs.ts_control & PCH_TSC_PPSM_MASK) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_pps_imask_set\n", __func__);
+ pch_pps_imask_set(chip);
+ }
+
+ /* Time stamp event register; clear all events */
+ pch_ttm_evt_clear(chip);
+ pch_asms_evt_clear(chip);
+ pch_amms_evt_clear(chip);
+ pch_pps_evt_clear(chip);
+
+ /* enable all 32 bits in system time registers */
+ pch_set_system_time_count(chip);
+
+ /* Addend register */
+ dev_dbg(&pdev->dev, "%s:invoking pch_addend_set\n", __func__);
+ pch_addend_set(pch_regs.ts_addend, chip);
+
+ /* PPS comapre register */
+ dev_dbg(&pdev->dev, "%s:invoking pch_pps_set\n", __func__);
+ pch_pps_set(pch_regs.ts_compare, chip);
+
+ /* System time Low and Hi registers */
+ dev_dbg(&pdev->dev, "%s:invoking pch_sys_snap_set\n", __func__);
+ pch_sys_snap_set(pch_regs.ts_syslo, pch_regs.ts_syshi, chip);
+
+ /* Target time Low and Hi registers */
+ dev_dbg(&pdev->dev, "%s:invoking pch_tgt_snap_set\n", __func__);
+ spin_lock_irqsave(&chip->lock, flags);/*need*/
+ pch_tgt_snap_set(pch_regs.ts_tgtlo, pch_regs.ts_tgthi, chip);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ /* Ethernet Channel Control register */
+ if (pch_regs.ts_cc & PCH_CC_MM) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_master_mode_set with TRUE as parameter\n",
+ __func__);
+ pch_master_mode_set(TRUE, chip);
+ }
+ if (pch_regs.ts_cc & PCH_CC_TA) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_timestamp_all_set with TRUE as parameter\n",
+ __func__);
+ pch_timestamp_all_set(TRUE, chip);
+ }
+ dev_dbg(&pdev->dev, "%s:invoking pch_op_mode_set\n", __func__);
+ pch_op_mode_set((pch_regs.ts_cc & PCH_CC_MODE_MASK) >>
+ PCH_CC_MODE_SHIFT, chip);
+ if (pch_regs.ts_cc & PCH_CC_VERSION) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_version_set with PCH_1588PTP_VERSION_1"
+ " as parameter\n", __func__);
+ pch_version_set(PCH_1588PTP_VERSION_1, chip);
+ }
+
+ /* Channel event register, cleared on restore */
+ dev_dbg(&pdev->dev, "%s:invoking pch_rx_snap_evt_clear\n", __func__);
+ pch_rx_snap_evt_clear(chip);
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_evt_clear\n", __func__);
+ pch_tx_snap_evt_clear(chip);
+
+ /* CAN Channel event register, cleared on restore */
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_ovr_clear\n", __func__);
+ pch_can_snap_ovr_clear(chip);
+ dev_dbg(&pdev->dev, "%s:invoking pch_tx_snap_valid_clear\n", __func__);
+ pch_can_snap_valid_clear(chip);
+
+ /* Ethernet CAN selector register */
+ if (pch_regs.ts_sel & PCH_ECS_ETH) {
+ dev_dbg(&pdev->dev, "%s:invoking pch_eth_enable_set\n",
+ __func__);
+ pch_eth_enable_set(chip);
+ }
+ if (pch_regs.ts_sel & PCH_ECS_CAN) {
+ dev_dbg(&pdev->dev, "%s:invoking pch_can_enable_set\n",
+ __func__);
+ pch_can_enable_set(chip);
+ }
+
+ /* Station Address registers */
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ dev_dbg(&pdev->dev,
+ "%s:invoking pch_station_set for station=%d\n", __func__, i);
+ pch_station_set(i, pch_regs.ts_sti[i], chip);
+ }
+}
+
+static enum pch_status pch_show(struct pch_dev *pch_pdata)
+{
+ s32 i;
+ u32 flag;
+ u32 reg_low;
+ u32 reg_hi;
+ u32 seq_id;
+ u32 uuid_low;
+ u32 uuid_hi;
+ void __iomem *p = pch_pdata->mem_virt;
+ unsigned long flags;
+
+ /* dump all register as such */
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Control Register offset = %x,content = %x\n",
+ PCH_TSC_OFFSET, ioread32(p + PCH_TSC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Event Register offset = %x,content = %x\n",
+ PCH_TSE_OFFSET, ioread32(p + PCH_TSE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Addend Register offset = %x,content = %x\n",
+ PCH_ADD_OFFSET, ioread32(p + PCH_ADD_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Accumulator Register offset = %x,content = %x\n",
+ PCH_ACC_OFFSET, ioread32(p + PCH_ACC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Test Register offset = %x,content = %x\n",
+ PCH_TST_OFFSET, ioread32(p + PCH_TST_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS PPS Compare Register offset = %x,content = %x\n",
+ PCH_PPS_OFFSET, ioread32(p + PCH_PPS_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS System Time Low Register offset = %x,content = %x\n",
+ PCH_STL_OFFSET, ioread32(p + PCH_STL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS System Time High Register offset = %x,content = %x\n",
+ PCH_STH_OFFSET, ioread32(p + PCH_STH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Target Time Low Register offset = %x,content = %x\n",
+ PCH_TTL_OFFSET, ioread32(p + PCH_TTL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Target Time High Register offset = %x,content = %x\n",
+ PCH_TTH_OFFSET, ioread32(p + PCH_TTH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Slave Mode Snapshot Low Register offset = %x,content = %x\n",
+ PCH_ASSL_OFFSET, ioread32(p + PCH_ASSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Slave Mode Snapshot High Register offset = %x,content = %x\n",
+ PCH_ASSH_OFFSET, ioread32(p + PCH_ASSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Master Mode Snapshot Low Register offset = %x,content = %x\n",
+ PCH_AMSL_OFFSET, ioread32(p + PCH_AMSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Aux Master Mode Snapshot High Register offset = %x,content = %x\n",
+ PCH_AMSH_OFFSET, ioread32(p + PCH_AMSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Channel Control Register offset = %x,content = %x\n",
+ PCH_CC_OFFSET, ioread32(p + PCH_CC_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Channel Event Register offset = %x,content = %x\n",
+ PCH_CE_OFFSET, ioread32(p + PCH_CE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Tx Snapshot High Register offset = %x,content = %x\n",
+ PCH_XSH_OFFSET, ioread32(p + PCH_XSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Tx Snapshot Low Register offset = %x,content = %x\n",
+ PCH_XSL_OFFSET, ioread32(p + PCH_XSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Rx Snapshot Low Register offset = %x,content = %x\n",
+ PCH_RSL_OFFSET, ioread32(p + PCH_RSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Rx Snapshot High Register offset = %x,content = %x\n",
+ PCH_RSH_OFFSET, ioread32(p + PCH_RSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Source UUID Low Register offset = %x,content = %x\n",
+ PCH_UID_OFFSET, ioread32(p + PCH_UID_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Source UUID High/SequenceID Register offset = %x,content = %x\n",
+ PCH_SID_OFFSET, ioread32(p + PCH_SID_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Channel Status Register offset = %x,content = %x\n",
+ PCH_CCE_OFFSET, ioread32(p + PCH_CCE_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Snapshot Low Register offset = %x,content = %x\n",
+ PCH_CXSL_OFFSET, ioread32(p + PCH_CXSL_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS CAN Snapshot High Register offset = %x,content = %x\n",
+ PCH_CXSH_OFFSET, ioread32(p + PCH_CXSH_OFFSET));
+ dev_info(&pch_pdata->pdev->dev,
+ "TS Ethernet/CAN Selecti Register offset = %x,content = %x\n",
+ PCH_ECS_OFFSET, ioread32(p + PCH_ECS_OFFSET));
+ /* Station Address registers */
+ dev_info(&pch_pdata->pdev->dev, "TS Station Address [1-6]");
+ for (i = 0; i < PCH_STATION_BYTES; i++) {
+ reg_low = pch_station_get(i, pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, ":%02x", reg_low);
+ }
+ dev_info(&pch_pdata->pdev->dev, "\n");
+
+ /* Target time reached interrupt mask */
+ flag = pch_ttm_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "Target Time Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Slave Mode Snapshot interrupt mask */
+ flag = pch_asms_imask_get(pch_pdata);
+ dev_info(&pch_pdata->pdev->dev, "ASMS Interrupt Mask: %s\n",
+ ((flag == TRUE) ? "Set" : "Clear"));
+
+ /* Auxiliary Master Mode Snapshot interrupt mask */
+ flag = pch_amms_imask_get(pch_pdata);
+ dev_in