Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/tegra: sor: Parse more data from HDA format

The HDA format data passed to the SOR from the HDA codec contains more
information than just the rate and number of channels. Parse all the
fields and store them in an internal structure for subsequent use.

While at it, also fix an off-by-one error in the number of channels.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+53 -16
+53 -16
drivers/gpu/drm/tegra/sor.c
··· 393 393 int (*remove)(struct tegra_sor *sor); 394 394 }; 395 395 396 + struct tegra_sor_audio { 397 + unsigned int sample_rate; 398 + unsigned int channels; 399 + unsigned int bits; 400 + bool pcm; 401 + }; 402 + 396 403 struct tegra_sor { 397 404 struct host1x_client client; 398 405 struct tegra_output output; ··· 436 429 struct delayed_work scdc; 437 430 bool scdc_enabled; 438 431 439 - struct { 440 - unsigned int sample_rate; 441 - unsigned int channels; 442 - } audio; 432 + struct tegra_sor_audio audio; 443 433 }; 444 434 445 435 struct tegra_sor_state { ··· 3199 3195 return 0; 3200 3196 } 3201 3197 3202 - static void tegra_hda_parse_format(unsigned int format, unsigned int *rate, 3203 - unsigned int *channels) 3198 + static void tegra_hda_parse_format(unsigned int format, 3199 + struct tegra_sor_audio *audio) 3204 3200 { 3205 - unsigned int mul, div; 3201 + unsigned int mul, div, bits, channels; 3202 + 3203 + if (format & AC_FMT_TYPE_NON_PCM) 3204 + audio->pcm = false; 3205 + else 3206 + audio->pcm = true; 3206 3207 3207 3208 if (format & AC_FMT_BASE_44K) 3208 - *rate = 44100; 3209 + audio->sample_rate = 44100; 3209 3210 else 3210 - *rate = 48000; 3211 + audio->sample_rate = 48000; 3211 3212 3212 3213 mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT; 3213 3214 div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT; 3214 3215 3215 - *rate = *rate * (mul + 1) / (div + 1); 3216 + audio->sample_rate = audio->sample_rate * (mul + 1) / (div + 1); 3216 3217 3217 - *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT; 3218 + switch (format & AC_FMT_BITS_MASK) { 3219 + case AC_FMT_BITS_8: 3220 + audio->bits = 8; 3221 + break; 3222 + 3223 + case AC_FMT_BITS_16: 3224 + audio->bits = 16; 3225 + break; 3226 + 3227 + case AC_FMT_BITS_20: 3228 + audio->bits = 20; 3229 + break; 3230 + 3231 + case AC_FMT_BITS_24: 3232 + audio->bits = 24; 3233 + break; 3234 + 3235 + case AC_FMT_BITS_32: 3236 + audio->bits = 32; 3237 + break; 3238 + 3239 + default: 3240 + bits = (format & AC_FMT_BITS_MASK) >> AC_FMT_BITS_SHIFT; 3241 + WARN(1, "invalid number of bits: %#x\n", bits); 3242 + audio->bits = 8; 3243 + break; 3244 + } 3245 + 3246 + channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT; 3247 + 3248 + /* channels are encoded as n - 1 */ 3249 + audio->channels = channels + 1; 3218 3250 } 3219 3251 3220 3252 static irqreturn_t tegra_sor_irq(int irq, void *data) ··· 3265 3225 value = tegra_sor_readl(sor, SOR_AUDIO_HDA_CODEC_SCRATCH0); 3266 3226 3267 3227 if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) { 3268 - unsigned int format, sample_rate, channels; 3228 + unsigned int format; 3269 3229 3270 3230 format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK; 3271 3231 3272 - tegra_hda_parse_format(format, &sample_rate, &channels); 3273 - 3274 - sor->audio.sample_rate = sample_rate; 3275 - sor->audio.channels = channels; 3232 + tegra_hda_parse_format(format, &sor->audio); 3276 3233 3277 3234 tegra_sor_hdmi_audio_enable(sor); 3278 3235 } else {