audio: hal: enable dynamic DSP bitwidth configuration

DSP Bitwidth can be dynamically configured. ASM bitwidth
is configured via mixer ctl, while ADM and AFE are set
by HAL interface.

CRs-Fixed: 2080987
Change-Id: I6f35ac8036e3e4ddc3714c7a2c03272d9da5d584
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 67a8e26..19f08c6 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -594,6 +594,7 @@
                                   struct audio_device *adev,
                                   struct audio_usecase *usecase);
 int audio_extn_utils_get_snd_card_num();
+bool audio_extn_is_dsp_bit_width_enforce_mode_supported(audio_output_flags_t flags);
 
 #ifdef DS2_DOLBY_DAP_ENABLED
 #define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 9b0df8e..303cb63 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -385,6 +385,7 @@
     struct mixer_ctl *ctl = NULL;
     const char *mixer_ctl_name = "App Type Config";
     struct streams_io_cfg *s_info = NULL;
+    uint32_t target_bit_width = 0;
 
     if (!mixer) {
         ALOGE("%s: mixer is null",__func__);
@@ -410,6 +411,9 @@
         num_app_types += 1;
     }
 
+    /* get target bit width for ADM enforce mode */
+    target_bit_width = adev_get_dsp_bit_width_enforce_mode();
+
     list_for_each(node, streams_output_cfg_list) {
         s_info = node_to_item(node, struct streams_io_cfg, list);
         update = true;
@@ -421,6 +425,11 @@
                     app_type_cfg[i+2] = s_info->app_type_cfg.sample_rate;
                 if (app_type_cfg[i+3] < (size_t)s_info->app_type_cfg.bit_width)
                     app_type_cfg[i+3] = s_info->app_type_cfg.bit_width;
+                /* ADM bit width = max(enforce_bit_width, bit_width from s_info */
+                if (audio_extn_is_dsp_bit_width_enforce_mode_supported(s_info->flags.out_flags) &&
+                    (target_bit_width > app_type_cfg[i+3]))
+                    app_type_cfg[i+3] = target_bit_width;
+
                 update = false;
                 break;
             }
@@ -429,7 +438,12 @@
             num_app_types += 1;
             app_type_cfg[length++] = s_info->app_type_cfg.app_type;
             app_type_cfg[length++] = s_info->app_type_cfg.sample_rate;
-            app_type_cfg[length++] = s_info->app_type_cfg.bit_width;
+            app_type_cfg[length] = s_info->app_type_cfg.bit_width;
+            if (audio_extn_is_dsp_bit_width_enforce_mode_supported(s_info->flags.out_flags) &&
+                (target_bit_width > app_type_cfg[length]))
+                app_type_cfg[length] = target_bit_width;
+
+            length++;
         }
     }
     list_for_each(node, streams_input_cfg_list) {
@@ -759,6 +773,28 @@
     return native_usecase;
 }
 
+bool audio_extn_is_dsp_bit_width_enforce_mode_supported(audio_output_flags_t flags)
+{
+    /* DSP bitwidth enforce mode for ADM and AFE:
+    * includes:
+    *     deep buffer, low latency, direct pcm and offload.
+    * excludes:
+    *     ull(raw+fast), VOIP.
+    */
+    if ((flags & AUDIO_OUTPUT_FLAG_VOIP_RX) ||
+            ((flags & AUDIO_OUTPUT_FLAG_RAW) &&
+            (flags & AUDIO_OUTPUT_FLAG_FAST)))
+        return false;
+
+
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
+            (flags & AUDIO_OUTPUT_FLAG_DIRECT) ||
+            (flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) ||
+            (flags & AUDIO_OUTPUT_FLAG_PRIMARY))
+        return true;
+    else
+        return false;
+}
 
 static inline bool audio_is_vr_mode_on(struct audio_device *(__attribute__((unused)) adev))
 {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index f5129c5..f2820a7 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1439,6 +1439,84 @@
     return active;
 }
 
+uint32_t adev_get_dsp_bit_width_enforce_mode()
+{
+    if (adev == NULL) {
+        ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
+        return 0;
+    }
+    return adev->dsp_bit_width_enforce_mode;
+}
+
+static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
+{
+    char value[PROPERTY_VALUE_MAX];
+    int trial;
+    uint32_t dsp_bit_width_enforce_mode = 0;
+
+    if (!mixer) {
+        ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
+                __func__);
+        return 0;
+    }
+
+    if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
+                        value, NULL) > 0) {
+        trial = atoi(value);
+        switch (trial) {
+        case 16:
+            dsp_bit_width_enforce_mode = 16;
+            break;
+        case 24:
+            dsp_bit_width_enforce_mode = 24;
+            break;
+        case 32:
+            dsp_bit_width_enforce_mode = 32;
+            break;
+       default:
+            dsp_bit_width_enforce_mode = 0;
+            ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
+            break;
+        }
+    }
+
+    return dsp_bit_width_enforce_mode;
+}
+
+static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
+                                                uint32_t enforce_mode,
+                                                bool enable)
+{
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "ASM Bit Width";
+    uint32_t asm_bit_width_mode = 0;
+
+    if (enforce_mode == 0) {
+        ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
+        return;
+    }
+
+    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name);
+        return;
+    }
+
+    if (enable)
+        asm_bit_width_mode = enforce_mode;
+    else
+        asm_bit_width_mode = 0;
+
+    ALOGV("%s DSP bit width feature status is %d width=%d",
+        __func__, enable, asm_bit_width_mode);
+    if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
+        ALOGE("%s: Could not set ASM biwidth %d", __func__,
+                asm_bit_width_mode);
+
+    return;
+}
+
 /*
  * if native DSD playback active
  */
@@ -2297,6 +2375,12 @@
     /* 2. Disable the rx device */
     disable_snd_device(adev, uc_info->out_snd_device);
 
+    if (is_offload_usecase(out->usecase)) {
+        audio_enable_asm_bit_width_enforce_mode(adev->mixer,
+                                                adev->dsp_bit_width_enforce_mode,
+                                                false);
+    }
+
     list_remove(&uc_info->list);
     free(uc_info);
     out->started = 0;
@@ -2483,6 +2567,9 @@
     } else {
         platform_set_stream_channel_map(adev->platform, out->channel_mask,
                    out->pcm_device_id, &out->channel_map_param.channel_map[0]);
+        audio_enable_asm_bit_width_enforce_mode(adev->mixer,
+                                                adev->dsp_bit_width_enforce_mode,
+                                                true);
         out->pcm = NULL;
         out->compr = compress_open(adev->snd_card,
                                    out->pcm_device_id,
@@ -5591,6 +5678,7 @@
     adev->perf_lock_opts[0] = 0x101;
     adev->perf_lock_opts[1] = 0x20E;
     adev->perf_lock_opts_size = 2;
+    adev->dsp_bit_width_enforce_mode = 0;
 
     /* Loads platform specific libraries dynamically */
     adev->platform = platform_init(adev);
@@ -5703,6 +5791,8 @@
 
     audio_extn_ds2_enable(adev);
     *device = &adev->device.common;
+    adev->dsp_bit_width_enforce_mode =
+        adev_init_dsp_bit_width_enforce_mode(adev->mixer);
 
     audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
                                              &adev->streams_output_cfg_list,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 80b11b8..1aa5385 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -466,6 +466,7 @@
     bool asrc_mode_enabled;
     qahwi_device_t qahwi_dev;
     bool vr_audio_mode_enabled;
+    uint32_t dsp_bit_width_enforce_mode;
     bool bt_sco_on;
 };
 
@@ -492,6 +493,8 @@
 
 bool audio_is_dsd_native_stream_active(struct audio_device *adev);
 
+uint32_t adev_get_dsp_bit_width_enforce_mode();
+
 int pcm_ioctl(struct pcm *pcm, int request, ...);
 
 audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 3fc1ef2..257d3bc 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5748,6 +5748,10 @@
         backend_cfg.format = usecase->stream.out->format;
         backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
     }
+    /* enforce AFE bitwidth mode via backend_cfg */
+    if (audio_extn_is_dsp_bit_width_enforce_mode_supported(usecase->stream.out->flags) &&
+                (adev->dsp_bit_width_enforce_mode > backend_cfg.bit_width))
+        backend_cfg.bit_width = adev->dsp_bit_width_enforce_mode;
 
     /*this is populated by check_codec_backend_cfg hence set default value to false*/
     backend_cfg.passthrough_enabled = false;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
old mode 100755
new mode 100644
index 9c23f16..d7a36a6
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -5598,6 +5598,9 @@
         backend_cfg.format = usecase->stream.out->format;
         backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
     }
+    if (audio_extn_is_dsp_bit_width_enforce_mode_supported(usecase->stream.out->flags) &&
+                (adev->dsp_bit_width_enforce_mode > backend_cfg.bit_width))
+        backend_cfg.bit_width = adev->dsp_bit_width_enforce_mode;
 
     /*this is populated by check_codec_backend_cfg hence set default value to false*/
     backend_cfg.passthrough_enabled = false;