root/arch/arm/mach-imx/ssi-fiq.S
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
 */

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
 * r8  = bit 0-15: tx offset, bit 16-31: tx buffer size
 * r9  = bit 0-15: rx offset, bit 16-31: rx buffer size
 */

#define SSI_STX0        0x00
#define SSI_SRX0        0x08
#define SSI_SISR        0x14
#define SSI_SIER        0x18
#define SSI_SACNT       0x38

#define SSI_SACNT_AC97EN        (1 << 0)

#define SSI_SIER_TFE0_EN        (1 << 0)
#define SSI_SISR_TFE0           (1 << 0)
#define SSI_SISR_RFF0           (1 << 2)
#define SSI_SIER_RFF0_EN        (1 << 2)

                .text
                .global imx_ssi_fiq_start
                .global imx_ssi_fiq_end
                .global imx_ssi_fiq_base
                .global imx_ssi_fiq_rx_buffer
                .global imx_ssi_fiq_tx_buffer

/*
 * imx_ssi_fiq_start is _intentionally_ not marked as a function symbol
 * using ENDPROC().  imx_ssi_fiq_start and imx_ssi_fiq_end are used to
 * mark the function body so that it can be copied to the FIQ vector in
 * the vectors page.  imx_ssi_fiq_start should only be called as the result
 * of an FIQ: calling it directly will not work.
 */
imx_ssi_fiq_start:
                ldr r12, .L_imx_ssi_fiq_base

                /* TX */
                ldr r13, .L_imx_ssi_fiq_tx_buffer

                /* shall we send? */
                ldr r11, [r12, #SSI_SIER]
                tst r11, #SSI_SIER_TFE0_EN
                beq 1f

                /* TX FIFO empty? */
                ldr r11, [r12, #SSI_SISR]
                tst r11, #SSI_SISR_TFE0
                beq 1f

                mov r10, #0x10000
                sub r10, #1
                and r10, r10, r8        /* r10: current buffer offset */

                add r13, r13, r10

                ldrh r11, [r13]
                strh r11, [r12, #SSI_STX0]

                ldrh r11, [r13, #2]
                strh r11, [r12, #SSI_STX0]

                ldrh r11, [r13, #4]
                strh r11, [r12, #SSI_STX0]

                ldrh r11, [r13, #6]
                strh r11, [r12, #SSI_STX0]

                add r10, #8
                lsr r11, r8, #16        /* r11: buffer size */
                cmp r10, r11
                lslgt r8, r11, #16
                addle r8, #8
1:
                /* RX */

                /* shall we receive? */
                ldr r11, [r12, #SSI_SIER]
                tst r11, #SSI_SIER_RFF0_EN
                beq 1f

                /* RX FIFO full? */
                ldr r11, [r12, #SSI_SISR]
                tst r11, #SSI_SISR_RFF0
                beq 1f

                ldr r13, .L_imx_ssi_fiq_rx_buffer

                mov r10, #0x10000
                sub r10, #1
                and r10, r10, r9        /* r10: current buffer offset */

                add r13, r13, r10

                ldr r11, [r12, #SSI_SACNT]
                tst r11, #SSI_SACNT_AC97EN

                ldr r11, [r12, #SSI_SRX0]
                strh r11, [r13]

                ldr r11, [r12, #SSI_SRX0]
                strh r11, [r13, #2]

                /* dummy read to skip slot 12 */
                ldrne r11, [r12, #SSI_SRX0]

                ldr r11, [r12, #SSI_SRX0]
                strh r11, [r13, #4]

                ldr r11, [r12, #SSI_SRX0]
                strh r11, [r13, #6]

                /* dummy read to skip slot 12 */
                ldrne r11, [r12, #SSI_SRX0]

                add r10, #8
                lsr r11, r9, #16        /* r11: buffer size */
                cmp r10, r11
                lslgt r9, r11, #16
                addle r9, #8

1:
                @ return from FIQ
                subs    pc, lr, #4

                .align
.L_imx_ssi_fiq_base:
imx_ssi_fiq_base:
                .word 0x0
.L_imx_ssi_fiq_rx_buffer:
imx_ssi_fiq_rx_buffer:
                .word 0x0
.L_imx_ssi_fiq_tx_buffer:
imx_ssi_fiq_tx_buffer:
                .word 0x0
.L_imx_ssi_fiq_end:
imx_ssi_fiq_end: