Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | /* SPDX-License-Identifier: GPL-2.0+ */ /* * TI Common Platform Time Sync * * Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com> * */ #ifndef _TI_CPTS_H_ #define _TI_CPTS_H_ #if IS_ENABLED(CONFIG_TI_CPTS) #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clocksource.h> #include <linux/device.h> #include <linux/list.h> #include <linux/of.h> #include <linux/ptp_clock_kernel.h> #include <linux/skbuff.h> #include <linux/ptp_classify.h> #include <linux/timecounter.h> struct cpsw_cpts { u32 idver; /* Identification and version */ u32 control; /* Time sync control */ u32 rftclk_sel; /* Reference Clock Select Register */ u32 ts_push; /* Time stamp event push */ u32 ts_load_val; /* Time stamp load value */ u32 ts_load_en; /* Time stamp load enable */ u32 res2[2]; u32 intstat_raw; /* Time sync interrupt status raw */ u32 intstat_masked; /* Time sync interrupt status masked */ u32 int_enable; /* Time sync interrupt enable */ u32 res3; u32 event_pop; /* Event interrupt pop */ u32 event_low; /* 32 Bit Event Time Stamp */ u32 event_high; /* Event Type Fields */ }; /* Bit definitions for the IDVER register */ #define TX_IDENT_SHIFT (16) /* TX Identification Value */ #define TX_IDENT_MASK (0xffff) #define RTL_VER_SHIFT (11) /* RTL Version Value */ #define RTL_VER_MASK (0x1f) #define MAJOR_VER_SHIFT (8) /* Major Version Value */ #define MAJOR_VER_MASK (0x7) #define MINOR_VER_SHIFT (0) /* Minor Version Value */ #define MINOR_VER_MASK (0xff) /* Bit definitions for the CONTROL register */ #define HW4_TS_PUSH_EN (1<<11) /* Hardware push 4 enable */ #define HW3_TS_PUSH_EN (1<<10) /* Hardware push 3 enable */ #define HW2_TS_PUSH_EN (1<<9) /* Hardware push 2 enable */ #define HW1_TS_PUSH_EN (1<<8) /* Hardware push 1 enable */ #define INT_TEST (1<<1) /* Interrupt Test */ #define CPTS_EN (1<<0) /* Time Sync Enable */ /* * Definitions for the single bit resisters: * TS_PUSH TS_LOAD_EN INTSTAT_RAW INTSTAT_MASKED INT_ENABLE EVENT_POP */ #define TS_PUSH (1<<0) /* Time stamp event push */ #define TS_LOAD_EN (1<<0) /* Time Stamp Load */ #define TS_PEND_RAW (1<<0) /* int read (before enable) */ #define TS_PEND (1<<0) /* masked interrupt read (after enable) */ #define TS_PEND_EN (1<<0) /* masked interrupt enable */ #define EVENT_POP (1<<0) /* writing discards one event */ /* Bit definitions for the EVENT_HIGH register */ #define PORT_NUMBER_SHIFT (24) /* Indicates Ethernet port or HW pin */ #define PORT_NUMBER_MASK (0x1f) #define EVENT_TYPE_SHIFT (20) /* Time sync event type */ #define EVENT_TYPE_MASK (0xf) #define MESSAGE_TYPE_SHIFT (16) /* PTP message type */ #define MESSAGE_TYPE_MASK (0xf) #define SEQUENCE_ID_SHIFT (0) /* PTP message sequence ID */ #define SEQUENCE_ID_MASK (0xffff) enum { CPTS_EV_PUSH, /* Time Stamp Push Event */ CPTS_EV_ROLL, /* Time Stamp Rollover Event */ CPTS_EV_HALF, /* Time Stamp Half Rollover Event */ CPTS_EV_HW, /* Hardware Time Stamp Push Event */ CPTS_EV_RX, /* Ethernet Receive Event */ CPTS_EV_TX, /* Ethernet Transmit Event */ }; #define CPTS_FIFO_DEPTH 16 #define CPTS_MAX_EVENTS 32 struct cpts_event { struct list_head list; unsigned long tmo; u32 high; u32 low; u64 timestamp; }; struct cpts { struct device *dev; struct cpsw_cpts __iomem *reg; int tx_enable; int rx_enable; struct ptp_clock_info info; struct ptp_clock *clock; spinlock_t lock; /* protects fifo/events */ u32 cc_mult; /* for the nominal frequency */ struct cyclecounter cc; struct timecounter tc; int phc_index; struct clk *refclk; struct list_head events; struct list_head pool; struct cpts_event pool_data[CPTS_MAX_EVENTS]; unsigned long ov_check_period; struct sk_buff_head txq; u64 cur_timestamp; u32 mult_new; struct mutex ptp_clk_mutex; /* sync PTP interface and worker */ bool irq_poll; struct completion ts_push_complete; u32 hw_ts_enable; }; void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb); void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb); int cpts_register(struct cpts *cpts); void cpts_unregister(struct cpts *cpts); struct cpts *cpts_create(struct device *dev, void __iomem *regs, struct device_node *node, u32 n_ext_ts); void cpts_release(struct cpts *cpts); void cpts_misc_interrupt(struct cpts *cpts); static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb) { unsigned int class = ptp_classify_raw(skb); if (class == PTP_CLASS_NONE) return false; return true; } static inline void cpts_set_irqpoll(struct cpts *cpts, bool en) { cpts->irq_poll = en; } #else struct cpts; static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb) { } static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb) { } static inline struct cpts *cpts_create(struct device *dev, void __iomem *regs, struct device_node *node, u32 n_ext_ts) { return NULL; } static inline void cpts_release(struct cpts *cpts) { } static inline int cpts_register(struct cpts *cpts) { return 0; } static inline void cpts_unregister(struct cpts *cpts) { } static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb) { return false; } static inline void cpts_misc_interrupt(struct cpts *cpts) { } static inline void cpts_set_irqpoll(struct cpts *cpts, bool en) { } #endif #endif |