; ; Copyright (C) 2021-2023 Texas Instruments Incorporated ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; ; Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; ; Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the ; distribution. ; ; Neither the name of Texas Instruments Incorporated nor the names of ; its contributors may be used to endorse or promote products derived ; from this software without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; .include "memory.inc" .include "defines.inc" .include "macros.inc" .ref PUSH_FIFO_2B_8x .ref WAIT_TX_FIFO_FREE .ref qm_add .ref calc_rssi .ref send_stuffing .ref datalink_wait_vsynch .if $defined("HDSL_MULTICHANNEL") .ref send_header_300m .else .ref send_header .endif .ref send_header_modified .ref send_trailer .ref wait_delay .ref datalink_loadfw .ref recv_dec .ref transport_on_h_frame .ref datalink_abort_jmp .ref receive .ref datalink_abort .global datalink_reset .global datalink_init_start ; part 1 code starts here .sect ".text:part1" ;-------------------------------------------------------------------------------------------------- ;Function: check_test_pattern (RET_ADDR1) ;This function checks if the test pattern was received ;input: ; r18-r20: data ;output: ; REG_FNC.b0: 1 if true ;modifies: ; REG_TMP0, REG_FNC ;-------------------------------------------------------------------------------------------------- check_test_pattern: ;load test pattern and mask from memory lbco ®_TMP0, MASTER_REGS_CONST, TEST_PATTERN0, 12 ;rm switch bit and REG_TMP11, r19, REG_TMP2 ldi REG_TMP2, 0xff8 and REG_TMP2, r19, REG_TMP2 lsl REG_TMP2, REG_TMP2, 1 or REG_TMP11, REG_TMP2, REG_TMP11 ;if found go to next step qbne check_test_pattern_false, r20, REG_TMP0 qbne check_test_pattern_false, REG_TMP11, REG_TMP1 check_test_pattern_true: ldi REG_FNC.b0, 1 RET1 check_test_pattern_false: ldi REG_FNC.b0, 0 RET1 ;-------------------------------------------------------------------------------------------------- ;Function: sync_pulse (RET_ADDR1) ;functions bussy waits for sync pulse ;input: ;modifies: ;-------------------------------------------------------------------------------------------------- ;stores sync pulse period in R20 in unit of cycles sync_pulse: lbco ®_TMP1, c1, IEP_CAPR6_RISE, 4 wait_next_pulse: lbco &R20, c1, IEP_CAPR6_RISE, 4 QBEQ wait_next_pulse, R20, REG_TMP1 SUB R20, R20, REG_TMP1 RET1 ; common code starts here .sect ".text" datalink_init_start: datalink_reset: ; Synchronization and loading overlaid part of firmware for TXPRU (Channel 2) is needed, ; only if channel 0 and 2 are enabled .if !$defined(CHANNEL_2) ; For channel 2, we always need to check for synchronization, so this code is not needed LBCO ®_TMP0.b0, MASTER_REGS_CONST, CHANNEL_MASK, 1 qbne skip_overlay_load1, REG_TMP0.b0, ((1<<0) | (1<<2)) .endif ; Set sync bit and wait for all channels SET_SYNC_BIT REG_TMP0 CALL WAIT_SYNC_SET_ALL .if $defined(CHANNEL_0) ; Following part of code on channel 0 loads the part 1 of overlaid firmware for ; TXPRU (Channel 2) ; Disable TXPRU1 before writing into IMEM LDI32 REG_TMP0, TXPRU1_CTRL LBBO ®_TMP1, REG_TMP0, 0, 4 clr REG_TMP1, REG_TMP1, 1 SBBO ®_TMP1, REG_TMP0, 0, 4 ; Load the load address, run address and size of part 1 of overlaid firmware ; for TXPRU (Channel 2) ZERO ®_TMP0, 12 LBCO ®_TMP0.w0, MASTER_REGS_CONST, PART1_LOAD_START, 2 LBCO ®_TMP1.w0, MASTER_REGS_CONST, PART1_RUN_START, 2 ; Add IMEM base address to run address LDI32 REG_TMP2, TXPRU1_IMEM_BASE ADD REG_TMP1.w0, REG_TMP1.w0, REG_TMP2.w0 ADC REG_TMP1.w2, REG_TMP1.w2, REG_TMP2.w2 LBCO ®_TMP2.w0, MASTER_REGS_CONST, PART1_SIZE, 2 LDI REG_TMP2.w2, 0x0 memcpy_loop1: LBBO &SPEED.b0, REG_TMP0, REG_TMP2.w2, 32 SBBO &SPEED.b0, REG_TMP1, REG_TMP2.w2, 32 ADD REG_TMP2.w2, REG_TMP2.w2, 32 QBLE memcpy_loop1, REG_TMP2.w0, REG_TMP2.w2 ZERO &SPEED, (4*8) ; Enable TXPRU1 before writing into IMEM LDI32 REG_TMP0, TXPRU1_CTRL LBBO ®_TMP1, REG_TMP0, 0, 4 set REG_TMP1, REG_TMP1, 1 SBBO ®_TMP1, REG_TMP0, 0, 4 ; Clear sync bit on RTUPRU (Channel 0). ; PRU (Channel 1) and TXPRU (Channel 2) will pend on this bit clear. CLEAR_SYNC_BIT REG_TMP1 .endif .if $defined(CHANNEL_1) ; Wait for RTUPRU (Channel 0) to clear sync bit and clear sync bit on PRU (Channel 1) ; which signals completion of overlay part 1 load WAIT_SYNC_CLEAR_CH0 REG_TMP0, REG_TMP1 CLEAR_SYNC_BIT REG_TMP1 .endif .if $defined(CHANNEL_2) ; Wait for RTUPRU (Channel 0) to clear sync bit and clear sync bit on TXPRU (Channel 2) ; which signals completion of overlay part 1 load WAIT_SYNC_CLEAR_CH0 REG_TMP0, REG_TMP1 CLEAR_SYNC_BIT REG_TMP1 .endif skip_overlay_load1: jmp datalink_reset_after_fw_load ; part 1 code starts here .if $defined(CHANNEL_2) .sect ".text:part1" .else .sect ".text" .endif datalink_reset_after_fw_load: ;State RESET ; Clear all registers zero &r0, 124 ;setup ICSS encoder peripheral for Hiperface DSL TX_EN SET_TX_CH0 REINIT_TX TX_FRAME_SIZE 0, REG_TMP0 .if $defined("HDSL_MULTICHANNEL") TX_CLK_DIV CLKDIV_FAST, REG_TMP0 .else TX_CLK_DIV CLKDIV_NORMAL, REG_TMP0 .endif ; set the VERSION and VERSION2 register ldi REG_TMP0.b0, ICSS_FIRMWARE_RELEASE sbco ®_TMP0.b0, MASTER_REGS_CONST, VERSION, 1 sbco ®_TMP0.b0, MASTER_REGS_CONST, VERSION2, 1 ;init transport layer here ;Initialize transport layer here transport_init: ;resert short msg ctrl ldi REG_TMP0.b0, 0x3f sbco ®_TMP0.b0, MASTER_REGS_CONST, SLAVE_REG_CTRL, 1 ;initialize acc_err_cnt to 0 sbco &SPEED.b0, MASTER_REGS_CONST, ACC_ERR_CNT, 1 sbco &SPEED.b0, MASTER_REGS_CONST, POS4, 8 ;reset rel. pos sbco &SPEED, MASTER_REGS_CONST, REL_POS0, 4 transport_init_abs_err_loop: ldi REG_TMP0.b0, 0 sbco ®_TMP0.b0, MASTER_REGS_CONST, ALIGN_PH, 1 exit_transport_init: ;QualityMonitor is initialized with 8 ldi QM, 8 ;reset PRST bit in SYS_CTRL lbco ®_TMP0, MASTER_REGS_CONST, SYS_CTRL, 1 clr REG_TMP0.b0, REG_TMP0.b0, SYS_CTRL_PRST sbco ®_TMP0, MASTER_REGS_CONST, SYS_CTRL, 1 ;reset SAFE_CTRL register zero ®_TMP0.b0, 1 sbco ®_TMP0.b0, MASTER_REGS_CONST, SAFE_CTRL, 1 ; Set EVENT_PRST in EVENT_H register lbco ®_TMP0, MASTER_REGS_CONST, EVENT_H, 4 set REG_TMP0.w0, REG_TMP0.w0, EVENT_PRST ;save events sbco ®_TMP0.w0, MASTER_REGS_CONST, EVENT_H, 2 qbbc update_events_no_int15, REG_TMP0.w2, EVENT_PRST ; generate interrupt ldi r31.w0, PRU0_ARM_IRQ update_events_no_int15: ; Set EVENT_S_PRST in EVENT_S register lbco ®_TMP0, MASTER_REGS_CONST, EVENT_S, 2 set REG_TMP0.b0, REG_TMP0.b0, EVENT_S_PRST ;save events sbco ®_TMP0.b0, MASTER_REGS_CONST, EVENT_S, 1 qbbc update_events_no_int22, REG_TMP0.b1, EVENT_S_PRST ; generate interrupt ldi r31.w0, PRU0_ARM_IRQ4 update_events_no_int22: ; Initialize ONLINE_STATUS_D, ONLINE_STATUS_1 and ONLINE_STATUS_2 ; In ONLINE_STATUS_D high, bit 2 is FIX0, bit 4 is FIX1 and bit 5 is FIX0 ; In ONLINE_STATUS_D low, bit 0 is FIX0 and bit 3 is FIX0 lbco ®_TMP0.w0, MASTER_REGS_CONST, ONLINE_STATUS_D_H, 2 ; clearing bits ldi REG_TMP0.w0, 0 ; setting bits with fix1 and PRST bit or REG_TMP0.w0, REG_TMP0.w0, (1< vert == acc.b0 && par == acc.b1 && pipe.nibble0 == pipe.nibble1 ;second half of palindrome is actually our ENC_ID! qbne datalink_abort2, H_FRAME.vert, H_FRAME_acc0 qbne datalink_abort2, H_FRAME.s_par, H_FRAME_acc1 and REG_TMP0.b0, H_FRAME.pipe, 0xf lsr REG_TMP0.b1, H_FRAME.pipe, 4 qbne datalink_abort2, REG_TMP0.b0, REG_TMP0.b1; ;now store the encoder ID mov REG_TMP0.w0, H_FRAME.acc mov REG_TMP0.b2, H_FRAME.pipe ;now in memory for master registers ;big endian format mov REG_TMP1.b0, REG_TMP0.b2 mov REG_TMP1.b1, REG_TMP0.b1 mov REG_TMP1.b2, REG_TMP0.b0 sbco ®_TMP1, MASTER_REGS_CONST, ENC_ID2, 3 ;Safe QM + set LINK bit, which means we have established a link ;just add 0 to QM to update QM_ADD 0 ;Synchronization with Drive Cycle is enabled here! set H_FRAME.flags, H_FRAME.flags, FLAG_DRIVE_SYNC ;-------------------------------------------------------------------------------------------------- ;State ID COMPUTE datalink_id_compute: ;decode the ENC_ID here ;num of acc bits is always +8 and NUM_ACC_BITS, REG_TMP0, 0x0f add NUM_ACC_BITS, NUM_ACC_BITS, 8 ;num pos bits is +num acc bits lsr NUM_ST_BITS, REG_TMP0, 4 and NUM_ST_BITS, NUM_ST_BITS, 0x3f add NUM_ST_BITS, NUM_ST_BITS, NUM_ACC_BITS sub NUM_ST_BITS, NUM_ST_BITS, NUM_MT_BITS ;finding the mask for position add REG_TMP0.b0, NUM_ST_BITS, NUM_MT_BITS rsb REG_TMP0.b0, REG_TMP0.b0, 40 ldi32 REG_TMP1, 0xffffffff lsr REG_TMP1, REG_TMP1, REG_TMP0.b0 sbco ®_TMP1, MASTER_REGS_CONST, MASK_POS, 4 ldi DELTA_ACC0, 0 ;qba datalink_id_req CALL1 send_stuffing ; Synchronization and loading overlaid part of firmware for TXPRU (Channel 2) is needed, ; only if channel 0 and 2 are enabled .if !$defined(CHANNEL_2) ; For channel 2, we always need to check for synchronization, so this code is not needed LBCO ®_TMP0.b0, MASTER_REGS_CONST, CHANNEL_MASK, 1 qbne datalink_wait_vsynch, REG_TMP0.b0, ((1<<0) | (1<<2)) .endif .if $defined(CHANNEL_0) ; Following part of code on channel 0 loads the part 2 of overlaid firmware for ; TXPRU (Channel 2) datalink_loadfw_start: ldi REG_FNC.w0, (0x0000 | M_PAR_IDREQ) .if $defined("HDSL_MULTICHANNEL") CALL send_header_300m .else CALL send_header .endif WAIT_TX_DONE READ_IEPCNT REG_TMP1 LDI REG_TMP2, (74*CYCLES_BIT + 25) ADD REG_TMP1, REG_TMP1, REG_TMP2 SBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 ; Set sync bit and wait for all channels SET_SYNC_BIT REG_TMP0 CALL WAIT_SYNC_SET_ALL ; Disable TXPRU1 before writing into IMEM LDI32 REG_TMP0, TXPRU1_CTRL LBBO ®_TMP1, REG_TMP0, 0, 4 clr REG_TMP1, REG_TMP1, 1 SBBO ®_TMP1, REG_TMP0, 0, 4 LBBO ®_TMP1, REG_TMP0, 0, 4 clr REG_TMP1, REG_TMP1, 1 SBBO ®_TMP1, REG_TMP0, 0, 4 ; Load the load address, run address and size of part 2 of overlaid firmware ; for TXPRU (Channel 2) ZERO ®_TMP0, 12 LBCO ®_TMP0.w0, MASTER_REGS_CONST, PART2_LOAD_START, 2 LBCO ®_TMP1.w0, MASTER_REGS_CONST, PART2_RUN_START, 2 ; Add IMEM base address to run address LDI32 REG_TMP2, TXPRU1_IMEM_BASE ADD REG_TMP1.w0, REG_TMP1.w0, REG_TMP2.w0 ADC REG_TMP1.w2, REG_TMP1.w2, REG_TMP2.w2 LBCO ®_TMP2.w0, MASTER_REGS_CONST, PART2_SIZE, 2 LDI REG_TMP2.w2, 0x0 memcpy_loop2: LBBO &SPEED.b0, REG_TMP0, REG_TMP2.w2, 32 SBBO &SPEED.b0, REG_TMP1, REG_TMP2.w2, 32 ADD REG_TMP2.w2, REG_TMP2.w2, 32 QBLE memcpy_loop2, REG_TMP2.w0, REG_TMP2.w2 ZERO &SPEED, (4*8) ; Enable TXPRU1 before writing into IMEM LDI32 REG_TMP0, TXPRU1_CTRL LBBO ®_TMP1, REG_TMP0, 0, 4 set REG_TMP1, REG_TMP1, 1 SBBO ®_TMP1, REG_TMP0, 0, 4 ; Clear Synchronization bit on RTUPRU (Channel 0). ; PRU (Channel 1) and TXPRU (Channel 2) will pend on this bit clear. CLEAR_SYNC_BIT REG_TMP1 LBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 datalink_loadfw_wait_for_rx_completion: READ_IEPCNT REG_TMP2 qble datalink_loadfw_wait_for_rx_completion, REG_TMP1, REG_TMP2 TX_EN ;send TRAILER CALL1 send_trailer CALL1 send_stuffing jmp datalink_wait_vsynch .endif .if $defined(CHANNEL_1) datalink_loadfw_start: ldi REG_FNC.w0, (0x0000 | M_PAR_IDREQ) .if $defined("HDSL_MULTICHANNEL") CALL send_header_300m .else CALL send_header .endif WAIT_TX_DONE READ_IEPCNT REG_TMP1 LDI REG_TMP2, (74*CYCLES_BIT + 25) ADD REG_TMP1, REG_TMP1, REG_TMP2 SBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 ; Set sync bit and wait for all channels SET_SYNC_BIT REG_TMP0 CALL WAIT_SYNC_SET_ALL ; Wait for RTUPRU (Channel 0) to clear sync bit and clear sync bit on PRU (Channel 1) ; which signals completion of overlay part 2 load WAIT_SYNC_CLEAR_CH0 REG_TMP0, REG_TMP1 CLEAR_SYNC_BIT REG_TMP1 LBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 datalink_loadfw_wait_for_rx_completion: READ_IEPCNT REG_TMP2 qble datalink_loadfw_wait_for_rx_completion, REG_TMP1, REG_TMP2 TX_EN ;send TRAILER CALL1 send_trailer CALL1 send_stuffing jmp datalink_wait_vsynch .endif .if $defined(CHANNEL_2) datalink_loadfw_start: ldi REG_FNC.w0, (0x0000 | M_PAR_IDREQ) .if $defined("HDSL_MULTICHANNEL") CALL send_header_300m .else CALL send_header .endif WAIT_TX_DONE READ_IEPCNT REG_TMP1 LDI REG_TMP2, (74*CYCLES_BIT + 25) ADD REG_TMP1, REG_TMP1, REG_TMP2 SBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 jmp datalink_loadfw_continue ; Jumping to .text only for channel 2 .sect ".text" datalink_loadfw_continue: ; Set sync bit and wait for all channels SET_SYNC_BIT REG_TMP0 CALL WAIT_SYNC_SET_ALL ; Wait for RTUPRU (Channel 0) to clear sync bit and clear sync bit on TXPRU (Channel 2) ; which signals completion of overlay part 2 load WAIT_SYNC_CLEAR_CH0 REG_TMP0, REG_TMP1 CLEAR_SYNC_BIT REG_TMP1 LBCO ®_TMP1, MASTER_REGS_CONST, LOADFW_TIMESTAMP, 4 datalink_loadfw_wait_for_rx_completion: READ_IEPCNT REG_TMP2 qble datalink_loadfw_wait_for_rx_completion, REG_TMP1, REG_TMP2 TX_EN ;send TRAILER CALL1 send_trailer CALL1 send_stuffing jmp datalink_wait_vsynch .endif WAIT_SYNC_SET_ALL: LBCO ®_TMP1.b1, MASTER_REGS_CONST, CHANNEL_MASK, 1 QBBC wait_for_channel1?, REG_TMP1.b1, 0 wait_for_channel0?: LDI REG_TMP0, DMEM_CH0_START LBBO ®_TMP1.b0, REG_TMP0, CHANNEL_SYNC, 1 QBNE wait_for_channel0?, REG_TMP1.b0, 1 wait_for_channel1?: QBBC wait_for_channel2?, REG_TMP1.b1, 1 LDI REG_TMP0, DMEM_CH1_START LBBO ®_TMP1.b0, REG_TMP0, CHANNEL_SYNC, 1 QBNE wait_for_channel1?, REG_TMP1.b0, 1 wait_for_channel2?: QBBC wait_sync_clear_all_end?, REG_TMP1.b1, 2 LDI REG_TMP0, DMEM_CH2_START LBBO ®_TMP1.b0, REG_TMP0, CHANNEL_SYNC, 1 QBNE wait_for_channel2?, REG_TMP1.b0, 1 wait_sync_clear_all_end?: RET