Commit 4bd1adb8 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown

ASoC: SOF: introduce new DEBUG_NOCODEC mode

The existing NOCODEC mode enforces a build-time mutual exclusion with
the HDaudio link support, mostly to avoid any dependency on the
snd_hdac library and references to HDAudio codec/i915 stuff.

This is very useful to track dependencies and test a minimal
configuration, but very painful for developers and CI: a recompilation
and reinstall of the kernel modules is required.

This patch suggests an alternate middle ground where the selection of
the machine driver and all codec-related actions are bypassed at
run-time, contingent on a kernel module parameter being set.

For example setting BIT(10) with
'options snd_sof sof_debug=0x401'
is enough to switch from an HDaudio card to a nocodec one.

This new DEBUG_NOCODEC mode is not suitable for distributions and
end-users. It's not even recommended on all platforms, i.e. the
NOCODEC mode is known not to work on specific devices where the BIOS
did not configure support for I2S/DMIC interfaces. The usual
development devices such as Chromebooks, Up boards and Intel RVP are
the only recommended platforms where this mode can be supported.

Note that the dynamic switch between HDaudio and nocodec may not
always possible depending on hardware layout, pin-mux options, and
BIOS settings. The audio subsustems on Intel platforms has to support
4 types of interfaces and pin-mux can be complicated.

Reviewers might ask: why didn't we do this earlier? The main reason is
that all the codec-related configurations were not cleanly separated
out in the sof/intel directory. With all the cleanups done recently,
adding this opt-in behavior is relatively straightforward.

Tested on UpExtreme (WHL) and UpExtreme i11 (TGL).
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://lore.kernel.org/r/20221027193540.259520-22-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent e8b7479d
...@@ -97,13 +97,13 @@ config SND_SOC_SOF_NOCODEC ...@@ -97,13 +97,13 @@ config SND_SOC_SOF_NOCODEC
tristate tristate
config SND_SOC_SOF_NOCODEC_SUPPORT config SND_SOC_SOF_NOCODEC_SUPPORT
bool "SOF nocodec mode support" bool "SOF nocodec static mode support"
help help
This adds support for a dummy/nocodec machine driver fallback This adds support for a dummy/nocodec machine driver fallback
option if no known codec is detected. This is typically only option if no known codec is detected. This is typically only
enabled for developers or devices where the sound card is enabled for developers or devices where the sound card is
controlled externally. controlled externally.
This option is mutually exclusive with the Intel HDAudio support. This option is mutually exclusive at build time with the Intel HDAudio support.
Selecting it may have negative impacts and prevent e.g. microphone Selecting it may have negative impacts and prevent e.g. microphone
functionality from being enabled on Intel CoffeeLake and later functionality from being enabled on Intel CoffeeLake and later
platforms. platforms.
...@@ -136,6 +136,19 @@ config SND_SOC_SOF_DEBUG ...@@ -136,6 +136,19 @@ config SND_SOC_SOF_DEBUG
if SND_SOC_SOF_DEBUG if SND_SOC_SOF_DEBUG
config SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
bool "SOF nocodec debug mode support"
depends on !SND_SOC_SOF_NOCODEC_SUPPORT
help
This adds support for a dummy/nocodec machine driver fallback
option.
Unlike the SND_SOC_SOF_NOCODEC_SUPPORT, this option is NOT
mutually exclusive at build with the Intel HDAudio support. The
selection will be done depending on command line or modprobe.d settings
Distributions should not select this option!
Say Y if you need this nocodec debug fallback option.
If unsure select "N".
config SND_SOC_SOF_FORCE_NOCODEC_MODE config SND_SOC_SOF_FORCE_NOCODEC_MODE
bool "SOF force nocodec Mode" bool "SOF force nocodec Mode"
depends on SND_SOC_SOF_NOCODEC_SUPPORT depends on SND_SOC_SOF_NOCODEC_SUPPORT
...@@ -239,6 +252,7 @@ config SND_SOC_SOF ...@@ -239,6 +252,7 @@ config SND_SOC_SOF
tristate tristate
select SND_SOC_TOPOLOGY select SND_SOC_TOPOLOGY
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
help help
This option is not user-selectable but automagically handled by This option is not user-selectable but automagically handled by
'select' statements at a higher level. 'select' statements at a higher level.
......
...@@ -277,7 +277,7 @@ if SND_SOC_SOF_HDA_COMMON ...@@ -277,7 +277,7 @@ if SND_SOC_SOF_HDA_COMMON
config SND_SOC_SOF_HDA_LINK config SND_SOC_SOF_HDA_LINK
bool "SOF support for HDA Links(HDA/HDMI)" bool "SOF support for HDA Links(HDA/HDMI)"
depends on SND_SOC_SOF_NOCODEC=n depends on SND_SOC_SOF_NOCODEC_SUPPORT=n
select SND_SOC_SOF_PROBE_WORK_QUEUE select SND_SOC_SOF_PROBE_WORK_QUEUE
help help
This adds support for HDA links(HDA/HDMI) with Sound Open Firmware This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
......
...@@ -72,6 +72,10 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) ...@@ -72,6 +72,10 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
struct hda_codec *codec; struct hda_codec *codec;
unsigned int mask = 0; unsigned int mask = 0;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
if (enable) { if (enable) {
list_for_each_codec(codec, hbus) list_for_each_codec(codec, hbus)
if (codec->jacktbl.used) if (codec->jacktbl.used)
...@@ -88,6 +92,10 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev) ...@@ -88,6 +92,10 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
struct hda_bus *hbus = sof_to_hbus(sdev); struct hda_bus *hbus = sof_to_hbus(sdev);
struct hda_codec *codec; struct hda_codec *codec;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
list_for_each_codec(codec, hbus) list_for_each_codec(codec, hbus)
/* /*
* Wake up all jack-detecting codecs regardless whether an event * Wake up all jack-detecting codecs regardless whether an event
...@@ -207,6 +215,10 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev) ...@@ -207,6 +215,10 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev)
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
int i, ret; int i, ret;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* probe codecs in avail slots */ /* probe codecs in avail slots */
for (i = 0; i < HDA_MAX_CODECS; i++) { for (i = 0; i < HDA_MAX_CODECS; i++) {
...@@ -240,6 +252,10 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev) ...@@ -240,6 +252,10 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* Accept unsolicited responses */ /* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
...@@ -261,6 +277,10 @@ void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) ...@@ -261,6 +277,10 @@ void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* initialize the codec command I/O */ /* initialize the codec command I/O */
snd_hdac_bus_init_cmd_io(bus); snd_hdac_bus_init_cmd_io(bus);
} }
...@@ -270,6 +290,10 @@ void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) ...@@ -270,6 +290,10 @@ void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* set up CORB/RIRB buffers if was on before suspend */ /* set up CORB/RIRB buffers if was on before suspend */
if (bus->cmd_dma_state) if (bus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(bus); snd_hdac_bus_init_cmd_io(bus);
...@@ -280,6 +304,10 @@ void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) ...@@ -280,6 +304,10 @@ void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* initialize the codec command I/O */ /* initialize the codec command I/O */
snd_hdac_bus_stop_cmd_io(bus); snd_hdac_bus_stop_cmd_io(bus);
} }
...@@ -289,6 +317,10 @@ void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) ...@@ -289,6 +317,10 @@ void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* stop the CORB/RIRB DMA if it is On */ /* stop the CORB/RIRB DMA if it is On */
if (bus->cmd_dma_state) if (bus->cmd_dma_state)
snd_hdac_bus_stop_cmd_io(bus); snd_hdac_bus_stop_cmd_io(bus);
...@@ -300,6 +332,10 @@ void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) ...@@ -300,6 +332,10 @@ void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* clear rirb status */ /* clear rirb status */
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
} }
...@@ -309,6 +345,9 @@ void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) ...@@ -309,6 +345,9 @@ void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
snd_hdac_set_codec_wakeup(bus, status); snd_hdac_set_codec_wakeup(bus, status);
} }
EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC); EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC);
...@@ -319,6 +358,10 @@ bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) ...@@ -319,6 +358,10 @@ bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
bool active = false; bool active = false;
u32 rirb_status; u32 rirb_status;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return false;
rirb_status = snd_hdac_chip_readb(bus, RIRBSTS); rirb_status = snd_hdac_chip_readb(bus, RIRBSTS);
if (rirb_status & RIRB_INT_MASK) { if (rirb_status & RIRB_INT_MASK) {
/* /*
...@@ -340,6 +383,10 @@ void hda_codec_device_remove(struct snd_sof_dev *sdev) ...@@ -340,6 +383,10 @@ void hda_codec_device_remove(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
/* codec removal, invoke bus_device_remove */ /* codec removal, invoke bus_device_remove */
snd_hdac_ext_bus_device_remove(bus); snd_hdac_ext_bus_device_remove(bus);
} }
...@@ -353,6 +400,10 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) ...@@ -353,6 +400,10 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
if (HDA_IDISP_CODEC(bus->codec_mask)) { if (HDA_IDISP_CODEC(bus->codec_mask)) {
dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable); dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable);
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
...@@ -365,6 +416,10 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) ...@@ -365,6 +416,10 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
int ret; int ret;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return 0;
/* i915 exposes a HDA codec for HDMI audio */ /* i915 exposes a HDA codec for HDMI audio */
ret = snd_hdac_i915_init(bus); ret = snd_hdac_i915_init(bus);
if (ret < 0) if (ret < 0)
...@@ -381,6 +436,10 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) ...@@ -381,6 +436,10 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return 0;
if (!bus->audio_component) if (!bus->audio_component)
return 0; return 0;
......
...@@ -826,6 +826,10 @@ int sof_machine_check(struct snd_sof_dev *sdev) ...@@ -826,6 +826,10 @@ int sof_machine_check(struct snd_sof_dev *sdev)
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
const struct snd_sof_of_mach *of_mach; const struct snd_sof_of_mach *of_mach;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
goto nocodec;
/* find machine */ /* find machine */
mach = snd_sof_machine_select(sdev); mach = snd_sof_machine_select(sdev);
if (mach) { if (mach) {
...@@ -848,6 +852,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) ...@@ -848,6 +852,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
dev_warn(sdev->dev, "Force to use nocodec mode\n"); dev_warn(sdev->dev, "Force to use nocodec mode\n");
} }
nocodec:
/* select nocodec mode */ /* select nocodec mode */
dev_warn(sdev->dev, "Using nocodec machine driver\n"); dev_warn(sdev->dev, "Using nocodec machine driver\n");
mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
......
...@@ -43,6 +43,9 @@ ...@@ -43,6 +43,9 @@
#define SOF_DBG_PRINT_IPC_SUCCESS_LOGS BIT(9) /* print IPC success #define SOF_DBG_PRINT_IPC_SUCCESS_LOGS BIT(9) /* print IPC success
* in dmesg logs * in dmesg logs
*/ */
#define SOF_DBG_FORCE_NOCODEC BIT(10) /* ignore all codec-related
* configurations
*/
/* Flag definitions used for controlling the DSP dump behavior */ /* Flag definitions used for controlling the DSP dump behavior */
#define SOF_DBG_DUMP_REGS BIT(0) #define SOF_DBG_DUMP_REGS BIT(0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment