|
19 | 19 | * struct sof_ipc4_timestamp_info - IPC4 timestamp info |
20 | 20 | * @host_copier: the host copier of the pcm stream |
21 | 21 | * @dai_copier: the dai copier of the pcm stream |
22 | | - * @stream_start_offset: reported by fw in memory window (converted to frames) |
23 | | - * @stream_end_offset: reported by fw in memory window (converted to frames) |
| 22 | + * @stream_start_offset: reported by fw in memory window (converted to |
| 23 | + * frames at dai_copier sampling rate) |
| 24 | + * @stream_end_offset: reported by fw in memory window (converted to |
| 25 | + * frames at dai_copier sampling rate) |
24 | 26 | * @llp_offset: llp offset in memory window |
25 | 27 | * @boundary: wrap boundary should be used for the LLP frame counter |
26 | 28 | * @delay: Calculated and stored in pointer callback. The stored value is |
27 | | - * returned in the delay callback. |
| 29 | + * returned in the delay callback. Expressed in frames at host copier |
| 30 | + * sampling rate. |
28 | 31 | */ |
29 | 32 | struct sof_ipc4_timestamp_info { |
30 | 33 | struct sof_ipc4_copier *host_copier; |
@@ -1113,6 +1116,53 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, |
1113 | 1116 | return 0; |
1114 | 1117 | } |
1115 | 1118 |
|
| 1119 | +static u64 sof_ipc4_time_scale(struct sof_ipc4_timestamp_info *time_info, u64 value, bool dai_to_host) |
| 1120 | +{ |
| 1121 | + u64 dai_rate, host_rate, mul, div; |
| 1122 | + |
| 1123 | + if (!time_info->dai_copier || !time_info->host_copier) |
| 1124 | + return value; |
| 1125 | + |
| 1126 | + /* |
| 1127 | + * copiers do not change sampling rate, so we can use the |
| 1128 | + * out_format independently of stream direction |
| 1129 | + */ |
| 1130 | + dai_rate = time_info->dai_copier->data.out_format.sampling_frequency; |
| 1131 | + host_rate = time_info->host_copier->data.out_format.sampling_frequency; |
| 1132 | + |
| 1133 | + if (!dai_rate || !host_rate) |
| 1134 | + return value; |
| 1135 | + |
| 1136 | + if (dai_to_host) { |
| 1137 | + mul = host_rate; |
| 1138 | + div = dai_rate; |
| 1139 | + } else { |
| 1140 | + mul = dai_rate; |
| 1141 | + div = host_rate; |
| 1142 | + } |
| 1143 | + |
| 1144 | + /* take care not to overflow u64, div/mul can be upto 768000 */ |
| 1145 | + if (value > U32_MAX) { |
| 1146 | + value = DIV64_U64_ROUND_CLOSEST(value, div); |
| 1147 | + value *= mul; |
| 1148 | + } else { |
| 1149 | + value *= mul; |
| 1150 | + value = DIV64_U64_ROUND_CLOSEST(value, div); |
| 1151 | + } |
| 1152 | + |
| 1153 | + return value; |
| 1154 | +} |
| 1155 | + |
| 1156 | +static u64 sof_ipc4_time_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 dai_time) |
| 1157 | +{ |
| 1158 | + return sof_ipc4_time_scale(time_info, dai_time, true); |
| 1159 | +} |
| 1160 | + |
| 1161 | +static u64 sof_ipc4_time_host_to_dai(struct sof_ipc4_timestamp_info *time_info, u64 host_time) |
| 1162 | +{ |
| 1163 | + return sof_ipc4_time_scale(time_info, host_time, false); |
| 1164 | +} |
| 1165 | + |
1116 | 1166 | static int sof_ipc4_pcm_pointer(struct snd_soc_component *component, |
1117 | 1167 | struct snd_pcm_substream *substream, |
1118 | 1168 | snd_pcm_uframes_t *pointer) |
@@ -1149,8 +1199,13 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component, |
1149 | 1199 |
|
1150 | 1200 | /* For delay calculation we need the host counter */ |
1151 | 1201 | host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream); |
| 1202 | + |
| 1203 | + /* Store the original value to host_ptr */ |
1152 | 1204 | host_ptr = host_cnt; |
1153 | 1205 |
|
| 1206 | + /* Scale value to DAI time in case DAI running at different rate */ |
| 1207 | + host_cnt = sof_ipc4_time_host_to_dai(time_info, host_cnt); |
| 1208 | + |
1154 | 1209 | /* convert the host_cnt to frames */ |
1155 | 1210 | host_cnt = div64_u64(host_cnt, frames_to_bytes(substream->runtime, 1)); |
1156 | 1211 |
|
@@ -1212,11 +1267,16 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component, |
1212 | 1267 | } |
1213 | 1268 |
|
1214 | 1269 | if (head_cnt < tail_cnt) { |
| 1270 | + /* TODO: is this correct in the SRC case? */ |
1215 | 1271 | time_info->delay = time_info->boundary - tail_cnt + head_cnt; |
1216 | 1272 | goto out; |
1217 | 1273 | } |
1218 | 1274 |
|
1219 | | - time_info->delay = head_cnt - tail_cnt; |
| 1275 | + /* delay in DAI time */ |
| 1276 | + time_info->delay = head_cnt - tail_cnt; |
| 1277 | + |
| 1278 | + /* convert delay to host time */ |
| 1279 | + time_info->delay = sof_ipc4_time_dai_to_host(time_info, time_info->delay); |
1220 | 1280 |
|
1221 | 1281 | out: |
1222 | 1282 | /* |
|
0 commit comments