8 #include <hal_ublaze/temac.h>
17 static constexpr
unsigned REG_RXCONFIG = 0x404 / 4;
18 static constexpr
unsigned REG_TXCONFIG = 0x408 / 4;
19 static constexpr
unsigned REG_FILTER = 0x708 / 4;
20 static constexpr
unsigned REG_AVB_RX_BASE = 0x10000 / 4;
21 static constexpr
unsigned REG_AVB_TX_BASE = 0x11000 / 4;
22 static constexpr
unsigned REG_AVB_TX_CTRL = 0x12000 / 4;
23 static constexpr
unsigned REG_AVB_RX_CTRL = 0x12004 / 4;
24 static constexpr
unsigned REG_AVB_OFFS_NSEC = 0x12800 / 4;
25 static constexpr
unsigned REG_AVB_OFFS_SECL = 0x12808 / 4;
26 static constexpr
unsigned REG_AVB_OFFS_SECH = 0x1280C / 4;
27 static constexpr
unsigned REG_AVB_RATE = 0x12810 / 4;
28 static constexpr
unsigned REG_AVB_NOW_NSEC = 0x12814 / 4;
29 static constexpr
unsigned REG_AVB_NOW_SECL = 0x12818 / 4;
30 static constexpr
unsigned REG_AVB_NOW_SECH = 0x1281C / 4;
33 static constexpr u32 AVB_RATE_MAX = 0x3FFFFFFu;
36 static constexpr
unsigned AVB_RXBUF_DATA = 0;
37 static constexpr
unsigned AVB_RXBUF_TIME = 252;
38 static constexpr
unsigned AVB_RXBUF_SIZE = 256;
39 static constexpr
unsigned AVB_RXBUF_DLEN = AVB_RXBUF_TIME - AVB_RXBUF_DATA;
40 static constexpr
unsigned AVB_TXBUF_LEN = 0;
41 static constexpr
unsigned AVB_TXBUF_DATA = 8;
42 static constexpr
unsigned AVB_TXBUF_TIME = 252;
43 static constexpr
unsigned AVB_TXBUF_SIZE = 256;
44 static constexpr
unsigned AVB_TXBUF_DLEN = AVB_TXBUF_TIME - AVB_TXBUF_DATA;
47 static constexpr
unsigned AVB_TX_SYNC = 0;
48 static constexpr
unsigned AVB_TX_FOLLOW_UP = 1;
49 static constexpr
unsigned AVB_TX_DLY_REQ = 2;
50 static constexpr
unsigned AVB_TX_DLY_RESP = 3;
51 static constexpr
unsigned AVB_TX_ANNOUNCE = 4;
54 static constexpr u8 PTP_TYPE_MASK = 0x0F;
55 static constexpr u8 PTP_TYPE_SYNC = 0x0;
56 static constexpr u8 PTP_TYPE_DLY_REQ = 0x1;
57 static constexpr u8 PTP_TYPE_PATH_DLY_REQ = 0x2;
58 static constexpr u8 PTP_TYPE_FOLLOW_UP = 0x8;
59 static constexpr u8 PTP_TYPE_DLY_RESP = 0x9;
60 static constexpr u8 PTP_TYPE_ANNOUNCE = 0xB;
62 Temac::Temac(uintptr_t baseaddr)
63 : m_regs((volatile u32*) baseaddr)
65 m_regs[REG_RXCONFIG] = 0x90000000u;
66 m_regs[REG_TXCONFIG] = 0x90000000u;
67 m_regs[REG_FILTER] = 0x80000100u;
72 , satcat5::io::ReadableRedirect(&m_rxbuff)
73 , satcat5::irq::Handler(
"TemacAVB", irq_idx)
74 , m_txbuff(m_txrawbuff, sizeof(m_txrawbuff), 16)
75 , m_rxbuff(m_rxrawbuff, sizeof(m_rxrawbuff), 16)
76 , m_tx_callback(nullptr)
78 , m_frames_waiting(0x00)
81 m_regs[REG_AVB_TX_CTRL] = 0;
82 m_regs[REG_AVB_RX_CTRL] = 1;
84 (void) m_regs[REG_AVB_RX_CTRL];
93 m_tx_callback = tx_callback;
99 u32 time_n = m_regs[REG_AVB_NOW_NSEC];
100 u64 time_s = m_regs[REG_AVB_NOW_SECL];
101 u64 time_e = m_regs[REG_AVB_NOW_SECH];
102 time_s += (time_e << 32);
109 if (incr > AVB_RATE_MAX) incr = AVB_RATE_MAX;
110 m_regs[REG_AVB_RATE] = incr;
116 m_regs[REG_AVB_OFFS_SECH] = (u32)(delta.sec >> 32);
117 m_regs[REG_AVB_OFFS_SECL] = (u32)(delta.sec >> 0);
118 m_regs[REG_AVB_OFFS_NSEC] = delta.nsec;
125 if (amount.
abs() < satcat5::ptp::ONE_SECOND)
135 constexpr s32 NOMINAL = (8 << 20);
136 constexpr s32 MAX_OFFSET = (1 << 20);
137 if (offset < -MAX_OFFSET) offset = -MAX_OFFSET;
138 if (offset > MAX_OFFSET) offset = MAX_OFFSET;
140 s32 rate = NOMINAL + (s32)offset;
147 return Time(now.sec, now.nsec);
154 u32 rx_status = m_regs[REG_AVB_RX_CTRL];
157 u32 ringbuf_end = ((rx_status >> 8) + 1) & 0xF;
160 while (m_prev_buf_idx != ringbuf_end) {
162 const u8* rx_ptp_buf = (
const u8*)(m_regs + REG_AVB_RX_BASE);
163 rx_ptp_buf += AVB_RXBUF_SIZE * m_prev_buf_idx;
167 const u8* pdata = (
const u8*)(rx_ptp_buf + AVB_RXBUF_DATA);
168 const u32* ptime = (
const u32*)(rx_ptp_buf + AVB_RXBUF_TIME);
172 m_rxbuff.write_u32(*ptime);
176 m_prev_buf_idx = (m_prev_buf_idx + 1) & 0xF;
185 check_frames_waiting();
188 void TemacAvb::check_frames_waiting()
191 u8 new_frames_waiting = (u8) (m_regs[REG_AVB_TX_CTRL] >> 8);
192 u8 frame_updates = new_frames_waiting ^ m_frames_waiting;
193 if (frame_updates == 0) {
198 for (u32 i = 0; i < 8; i++) {
199 if (((frame_updates >> i) & 0x1) == 0) {
202 if (((new_frames_waiting >> i) & 0x1) == 0) {
207 const u8* tx_ptp_buf = (
const u8*)(m_regs + REG_AVB_TX_BASE);
208 tx_ptp_buf += AVB_TXBUF_SIZE * i;
209 const u32* ptime = (
const u32*)(tx_ptp_buf + AVB_TXBUF_TIME);
212 s64 tx_time_sec = now.sec;
213 u32 tx_time_nsec = *ptime;
214 if (now.nsec < tx_time_nsec && now.sec > 0) {
217 Time tx_time(tx_time_sec, tx_time_nsec);
220 m_frames_waiting = new_frames_waiting;
226 m_tx_callback->
tx_sync(tx_time);
236 Log(LOG_DEBUG,
"Frame was silently queued to buffer #").
write10(i);
237 m_frames_waiting = new_frames_waiting;
246 if (buf_len < 14+34) {
247 Log(LOG_WARNING,
"Runt frame passed to TemacAvb::send_frame(), ignoring...");
253 u8 ptp_type = buf[14] & 0x0F;
254 u8 avb_tx_buf_idx = 0;
258 avb_tx_buf_idx = AVB_TX_SYNC;
260 case PTP_TYPE_FOLLOW_UP:
261 avb_tx_buf_idx = AVB_TX_FOLLOW_UP;
263 case PTP_TYPE_DLY_REQ:
264 case PTP_TYPE_PATH_DLY_REQ:
266 avb_tx_buf_idx = AVB_TX_DLY_REQ;
268 case PTP_TYPE_DLY_RESP:
269 avb_tx_buf_idx = AVB_TX_DLY_RESP;
271 case PTP_TYPE_ANNOUNCE:
272 avb_tx_buf_idx = AVB_TX_ANNOUNCE;
275 Log(LOG_WARNING,
"TemacAvb::send_frame() was passed a PTP ethernet frame "
276 "with unsupported PTP type").
write10((u32) ptp_type);
281 check_frames_waiting();
282 if (m_frames_waiting & (1 << avb_tx_buf_idx)) {
284 Log(LOG_INFO,
"A new PTP frame was requested in a pending buffer and "
285 "will not be overwritten.");
291 const u8* tx_ptp_buf = (
const u8*)(m_regs + REG_AVB_TX_BASE);
292 tx_ptp_buf += AVB_TXBUF_SIZE * avb_tx_buf_idx;
293 u8* plen = (u8*)(tx_ptp_buf + AVB_TXBUF_LEN);
294 *plen = (u8) buf_len;
295 u32* pdata = (u32*)(tx_ptp_buf + AVB_TXBUF_DATA);
296 memcpy(pdata, buf, buf_len);
299 m_regs[REG_AVB_TX_CTRL] = (1 << avb_tx_buf_idx);
302 m_frames_waiting |= (1 << avb_tx_buf_idx);
303 check_frames_waiting();
bool write_finalize() override
Mark end of frame and release temporary working data.
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
const char *const m_label
Human-readable label, for debugging.
The Log class creates and formats one log message.
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
High-precision timestamp for use with PTP / IEEE1588.
satcat5::ptp::Time abs() const
Standard arithmetic operations.
u32 round_nsec() const
Return "nanoseconds" field after rounding to the nearest nanosecond.
s64 round_secs() const
Return "seconds" field after rounding to the nearest nanosecond.
Xilinx TEMAC with Audio-Video-Bridge (AVB) functionality.
void irq_event() override
Method called whenever an interrupt is triggered.
void avb_set_rate(u32 incr)
Update AVB rate register.
void avb_jump_by(const satcat5::ublaze::TemacTime &delta)
One-time increment of the AVB internal timer.
satcat5::ublaze::TemacTime avb_get_time()
Read current time from the AVB internal timer.
void set_tx_callback(TemacAvbTxCallback *tx_callback)
Register callbacks for transmitted timestamps for PTP packets.
void poll_always() override
Child class MUST override this method.
satcat5::ptp::Time clock_adjust(const satcat5::ptp::Time &amount) override
Clock-adjustment API for ptp::TrackingClock.
void send_frame(const u8 *buf, unsigned buflen)
Send an arbitrary PTP frame with Ethernet header.
void clock_rate(s64 offset) override
Clock-adjustment API for ptp::TrackingClock.
satcat5::ptp::Time clock_now() override
Clock-adjustment API for ptp::TrackingClock.
TemacAvb(uintptr_t baseaddr, int irq_idx)
Initialize the core and link to specified instance.
Defines callback methods for timestamped egress times.
virtual void tx_sync(const satcat5::ptp::Time &sync_egress)
Callback for PTP "Sync" messages.
virtual void tx_delay_req(const satcat5::ptp::Time &delay_req_egress)
Callback for PTP "Delay request" messages.
Basic Xilinx TEMAC functionality.
Diagnostic logging to UART and/or Ethernet ports.
Timestamp format used by the AVB core.
Miscellaneous mathematical utility functions.