1 /*
2  * Copyright (c) 2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_ffa_drv.h"
9 #include <assert.h>
10 
11 #define FFA_ERROR_MASKS (FFA_STATUS_FIR_OV_MASK | FFA_STATUS_FFT_OV_MASK | FFA_STATUS_WR_ERR_MASK | FFA_STATUS_RD_NXT_ERR_MASK | FFA_STATUS_RD_ERR_MASK)
12 
13 static bool is_point_num_valid(uint16_t num_point);
14 static uint32_t get_fft_misc_reg_fft_len(uint16_t num_point);
15 static hpm_stat_t get_fft_error_kind(uint32_t ffa_status);
16 
is_point_num_valid(uint16_t num_point)17 static bool is_point_num_valid(uint16_t num_point)
18 {
19     return ((num_point & (num_point - 1U)) == 0U) && (num_point >= 8U);
20 }
21 
get_fft_misc_reg_fft_len(uint16_t num_point)22 static uint32_t get_fft_misc_reg_fft_len(uint16_t num_point)
23 {
24     uint32_t count = 0U;
25     num_point /= 8;
26     while (num_point > 0) {
27         count++;
28         num_point >>= 1U;
29     }
30 
31     return (count - 1U);
32 }
33 
ffa_start_fft(FFA_Type * ptr,fft_xfer_t * fft_xfer)34 void ffa_start_fft(FFA_Type *ptr, fft_xfer_t *fft_xfer)
35 {
36 
37     assert((ptr != NULL) && (fft_xfer != NULL) && is_point_num_valid(fft_xfer->num_points));
38 
39     ffa_disable(ptr);
40 
41     ffa_enable_interrupt(ptr, fft_xfer->interrupt_mask);
42 
43     ptr->OP_CTRL = FFA_OP_CTRL_EN_MASK;
44 
45     uint32_t op_cmd = FFA_OP_CMD_CMD_SET(FFA_OPCMD_FFT) | FFA_OP_CMD_IND_TYPE_SET(fft_xfer->src_data_type) |
46         FFA_OP_CMD_OUTD_TYPE_SET(fft_xfer->dst_data_type);
47     ptr->OP_CMD = op_cmd;
48 
49     uint32_t fft_len = get_fft_misc_reg_fft_len(fft_xfer->num_points);
50     uint32_t fft_misc =
51         FFA_OP_FFT_MISC_FFT_LEN_SET(fft_len) | FFA_OP_FFT_MISC_TMP_BLK_SET(1) | FFA_OP_FFT_MISC_IND_BLK_SET(0);
52     if (fft_xfer->is_ifft) {
53         fft_misc |= FFA_OP_FFT_MISC_IFFT_MASK;
54     }
55     ptr->OP_REG0 = fft_misc;
56 
57     ptr->OP_REG1 = 0;
58     ptr->OP_REG2 = (uint32_t) fft_xfer->src;
59     ptr->OP_REG4 = (uint32_t) fft_xfer->dst;
60 
61     ffa_enable(ptr);
62 }
63 
ffa_start_fir(FFA_Type * ptr,fir_xfer_t * fir_xfer)64 void ffa_start_fir(FFA_Type *ptr, fir_xfer_t *fir_xfer)
65 {
66     assert((ptr != NULL) && (fir_xfer != NULL));
67 
68     ffa_disable(ptr);
69 
70     ffa_enable_interrupt(ptr, fir_xfer->interrupt_mask);
71 
72     ptr->OP_CTRL = FFA_OP_CTRL_EN_MASK;
73 
74     uint32_t op_cmd = FFA_OP_CMD_CMD_SET(FFA_OPCMD_FIR) | FFA_OP_CMD_IND_TYPE_SET(fir_xfer->data_type) |
75         FFA_OP_CMD_OUTD_TYPE_SET(fir_xfer->data_type) | FFA_OP_CMD_COEF_TYPE_SET(fir_xfer->data_type);
76     ptr->OP_CMD = op_cmd;
77 
78     uint32_t fir_misc = FFA_OP_FIR_MISC_FIR_COEF_TAPS_SET(fir_xfer->coef_taps);
79     ptr->OP_REG0 = fir_misc;
80 #if defined(HPM_IP_FEATURE_FFA_FP32) && HPM_IP_FEATURE_FFA_FP32
81     uint32_t fir_misc1 = FFA_OP_FIR_MISC1_OUTD_MEM_BLK_SET(0) | FFA_OP_FIR_MISC1_COEF_MEM_BLK_SET(0) |
82         FFA_OP_FIR_MISC1_IND_MEM_BLK_SET(1) | FFA_OP_FIR_MISC1_FIR_DATA_TAPS_SET(fir_xfer->input_taps);
83 #else
84     uint32_t fir_misc1 = FFA_OP_FIR_MISC1_OUTD_MEM_BLK_SET(0) | FFA_OP_FIR_MISC1_COEF_MEM_BLK_SET(1) |
85         FFA_OP_FIR_MISC1_IND_MEM_BLK_SET(2) | FFA_OP_FIR_MISC1_FIR_DATA_TAPS_SET(fir_xfer->input_taps);
86 #endif
87 
88     ptr->OP_REG1 = fir_misc1;
89     ptr->OP_REG2 = 0xFFFFFFFFUL;
90     ptr->OP_REG3 = (uint32_t) fir_xfer->src;
91     ptr->OP_REG4 = (uint32_t) fir_xfer->coeff;
92     ptr->OP_REG5 = (uint32_t) fir_xfer->dst;
93 
94     ffa_enable(ptr);
95 }
96 
get_fft_error_kind(uint32_t ffa_status)97 static hpm_stat_t get_fft_error_kind(uint32_t ffa_status)
98 {
99     hpm_stat_t status;
100     if (IS_HPM_BITMASK_SET(ffa_status, FFA_ERROR_MASKS)) {
101         if (IS_HPM_BITMASK_SET(ffa_status, FFA_STATUS_FIR_OV_MASK)) {
102             status = status_ffa_fir_overflow;
103         } else if (IS_HPM_BITMASK_SET(ffa_status, FFA_STATUS_FFT_OV_MASK)) {
104             status = status_ffa_fft_overflow;
105         } else if (IS_HPM_BITMASK_SET(ffa_status, FFA_STATUS_WR_ERR_MASK)) {
106             status = status_ffa_write_error;
107         } else if (IS_HPM_BITMASK_SET(ffa_status, FFA_STATUS_RD_NXT_ERR_MASK)) {
108             status = status_ffa_read_next_error;
109         } else {
110             status = status_ffa_read_error;
111         }
112     } else {
113         status = status_success;
114     }
115     return status;
116 }
117 
ffa_calculate_fft_blocking(FFA_Type * ptr,fft_xfer_t * fft_xfer)118 hpm_stat_t ffa_calculate_fft_blocking(FFA_Type *ptr, fft_xfer_t *fft_xfer)
119 {
120     hpm_stat_t status = status_invalid_argument;
121     do {
122         HPM_BREAK_IF((ptr == NULL) || (fft_xfer == NULL) || !is_point_num_valid(fft_xfer->num_points));
123 
124         fft_xfer->interrupt_mask = 0;
125 
126         ffa_start_fft(ptr, fft_xfer);
127 
128         while (!IS_HPM_BITMASK_SET(ptr->STATUS, FFA_STATUS_OP_CMD_DONE_MASK)) {
129         }
130 
131         uint32_t ffa_status = ptr->STATUS;
132         status = get_fft_error_kind(ffa_status);
133     } while (false);
134 
135     return status;
136 }
137 
ffa_calculate_fir_blocking(FFA_Type * ptr,fir_xfer_t * fir_xfer)138 hpm_stat_t ffa_calculate_fir_blocking(FFA_Type *ptr, fir_xfer_t *fir_xfer)
139 {
140     hpm_stat_t status = status_invalid_argument;
141     do {
142         HPM_BREAK_IF((ptr == NULL) || (fir_xfer == NULL));
143 
144         fir_xfer->interrupt_mask = 0;
145 
146         ffa_start_fir(ptr, fir_xfer);
147 
148         while (!IS_HPM_BITMASK_SET(ptr->STATUS, FFA_STATUS_OP_CMD_DONE_MASK)) {
149         }
150 
151         uint32_t ffa_status = ptr->STATUS;
152         status = get_fft_error_kind(ffa_status);
153     } while (false);
154 
155     return status;
156 }
157