ASoC: intel: skl: Fix display power regression
[sfrench/cifs-2.6.git] / sound / soc / intel / skylake / skl.c
index 29225623b4b40d1c8fea6822b85b007e57aba690..4ed5b7e17d44aad3e09e6d6a8726ae3742bc92a1 100644 (file)
 #include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
 #include "../../../soc/codecs/hdac_hda.h"
+#endif
+static int skl_pci_binding;
+module_param_named(pci_binding, skl_pci_binding, int, 0444);
+MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
 
 /*
  * initialize the PCI registers
@@ -309,7 +314,7 @@ static int skl_suspend(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_bus *bus = pci_get_drvdata(pci);
        struct skl *skl  = bus_to_skl(bus);
-       int ret = 0;
+       int ret;
 
        /*
         * Do not suspend if streams which are marked ignore suspend are
@@ -331,14 +336,7 @@ static int skl_suspend(struct device *dev)
                skl->skl_sst->fw_loaded = false;
        }
 
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               ret = snd_hdac_display_power(bus, false);
-               if (ret < 0)
-                       dev_err(bus->dev,
-                               "Cannot turn OFF display power on i915\n");
-       }
-
-       return ret;
+       return 0;
 }
 
 static int skl_resume(struct device *dev)
@@ -349,16 +347,6 @@ static int skl_resume(struct device *dev)
        struct hdac_ext_link *hlink = NULL;
        int ret;
 
-       /* Turned OFF in HDMI codec driver after codec reconfiguration */
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               ret = snd_hdac_display_power(bus, true);
-               if (ret < 0) {
-                       dev_err(bus->dev,
-                               "Cannot turn on display power on i915\n");
-                       return ret;
-               }
-       }
-
        /*
         * resume only when we are not in suspend active, otherwise need to
         * restore the device
@@ -451,8 +439,10 @@ static int skl_free(struct hdac_bus *bus)
        snd_hdac_ext_bus_exit(bus);
 
        cancel_work_sync(&skl->probe_work);
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
                snd_hdac_i915_exit(bus);
+       }
 
        return 0;
 }
@@ -515,7 +505,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
 
        if (pdata) {
                skl->use_tplg_pcm = pdata->use_tplg_pcm;
-               pdata->dmic_num = skl_get_dmic_geo(skl);
+               mach->mach_params.dmic_num = skl_get_dmic_geo(skl);
        }
 
        return 0;
@@ -525,7 +515,6 @@ static int skl_machine_device_register(struct skl *skl)
 {
        struct snd_soc_acpi_mach *mach = skl->mach;
        struct hdac_bus *bus = skl_to_bus(skl);
-       struct skl_machine_pdata *pdata;
        struct platform_device *pdev;
        int ret;
 
@@ -535,6 +524,16 @@ static int skl_machine_device_register(struct skl *skl)
                return -EIO;
        }
 
+       mach->mach_params.platform = dev_name(bus->dev);
+       mach->mach_params.codec_mask = bus->codec_mask;
+
+       ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
+       if (ret) {
+               dev_err(bus->dev, "failed to add machine device platform data\n");
+               platform_device_put(pdev);
+               return ret;
+       }
+
        ret = platform_device_add(pdev);
        if (ret) {
                dev_err(bus->dev, "failed to add machine device\n");
@@ -542,12 +541,6 @@ static int skl_machine_device_register(struct skl *skl)
                return -EIO;
        }
 
-       if (mach->pdata) {
-               pdata = (struct skl_machine_pdata *)mach->pdata;
-               pdata->platform = dev_name(bus->dev);
-               pdata->codec_mask = bus->codec_mask;
-               dev_set_drvdata(&pdev->dev, mach->pdata);
-       }
 
        skl->i2s_dev = pdev;
 
@@ -658,6 +651,8 @@ static void skl_clock_device_unregister(struct skl *skl)
                platform_device_unregister(skl->clk_dev);
 }
 
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
+
 #define IDISP_INTEL_VENDOR_ID  0x80860000
 
 /*
@@ -676,6 +671,8 @@ static void load_codec_module(struct hda_codec *codec)
 #endif
 }
 
+#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
+
 /*
  * Probe the given codec address
  */
@@ -685,9 +682,11 @@ static int probe_codec(struct hdac_bus *bus, int addr)
                (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
        unsigned int res = -1;
        struct skl *skl = bus_to_skl(bus);
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
        struct hdac_hda_priv *hda_codec;
-       struct hdac_device *hdev;
        int err;
+#endif
+       struct hdac_device *hdev;
 
        mutex_lock(&bus->cmd_mutex);
        snd_hdac_bus_send_cmd(bus, cmd);
@@ -697,6 +696,7 @@ static int probe_codec(struct hdac_bus *bus, int addr)
                return -EIO;
        dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res);
 
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
        hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec),
                                 GFP_KERNEL);
        if (!hda_codec)
@@ -715,6 +715,13 @@ static int probe_codec(struct hdac_bus *bus, int addr)
                load_codec_module(&hda_codec->codec);
        }
        return 0;
+#else
+       hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL);
+       if (!hdev)
+               return -ENOMEM;
+
+       return snd_hdac_ext_bus_device_init(bus, addr, hdev);
+#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
 }
 
 /* Codec initialization */
@@ -767,11 +774,9 @@ static int skl_i915_init(struct hdac_bus *bus)
        if (err < 0)
                return err;
 
-       err = snd_hdac_display_power(bus, true);
-       if (err < 0)
-               dev_err(bus->dev, "Cannot turn on display power on i915\n");
+       snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
 
-       return err;
+       return 0;
 }
 
 static void skl_probe_work(struct work_struct *work)
@@ -804,24 +809,13 @@ static void skl_probe_work(struct work_struct *work)
        err = skl_platform_register(bus->dev);
        if (err < 0) {
                dev_err(bus->dev, "platform register failed: %d\n", err);
-               return;
-       }
-
-       if (bus->ppcap) {
-               err = skl_machine_device_register(skl);
-               if (err < 0) {
-                       dev_err(bus->dev, "machine register failed: %d\n", err);
-                       goto out_err;
-               }
+               goto out_err;
        }
 
-       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
-               err = snd_hdac_display_power(bus, false);
-               if (err < 0) {
-                       dev_err(bus->dev, "Cannot turn off display power on i915\n");
-                       skl_machine_device_unregister(skl);
-                       return;
-               }
+       err = skl_machine_device_register(skl);
+       if (err < 0) {
+               dev_err(bus->dev, "machine register failed: %d\n", err);
+               goto out_err;
        }
 
        /*
@@ -830,6 +824,9 @@ static void skl_probe_work(struct work_struct *work)
        list_for_each_entry(hlink, &bus->hlink_list, list)
                snd_hdac_ext_bus_link_put(bus, hlink);
 
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+
        /* configure PM */
        pm_runtime_put_noidle(bus->dev);
        pm_runtime_allow(bus->dev);
@@ -839,7 +836,7 @@ static void skl_probe_work(struct work_struct *work)
 
 out_err:
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
-               err = snd_hdac_display_power(bus, false);
+               snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
 }
 
 /*
@@ -870,7 +867,7 @@ static int skl_create(struct pci_dev *pci,
        hbus = skl_to_hbus(skl);
        bus = skl_to_bus(skl);
 
-#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
        ext_ops = snd_soc_hdac_hda_get_ops();
 #endif
        snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops);
@@ -912,6 +909,12 @@ static int skl_first_init(struct hdac_bus *bus)
 
        snd_hdac_bus_parse_capabilities(bus);
 
+       /* check if PPCAP exists */
+       if (!bus->ppcap) {
+               dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n");
+               return -ENODEV;
+       }
+
        if (skl_acquire_irq(bus, 0) < 0)
                return -EBUSY;
 
@@ -921,23 +924,25 @@ static int skl_first_init(struct hdac_bus *bus)
        gcap = snd_hdac_chip_readw(bus, GCAP);
        dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
 
-       /* allow 64bit DMA address if supported by H/W */
-       if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
-       } else {
-               dma_set_mask(bus->dev, DMA_BIT_MASK(32));
-               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
-       }
-
        /* read number of streams from GCAP register */
        cp_streams = (gcap >> 8) & 0x0f;
        pb_streams = (gcap >> 12) & 0x0f;
 
-       if (!pb_streams && !cp_streams)
+       if (!pb_streams && !cp_streams) {
+               dev_err(bus->dev, "no streams found in GCAP definitions?\n");
                return -EIO;
+       }
 
        bus->num_streams = cp_streams + pb_streams;
 
+       /* allow 64bit DMA address if supported by H/W */
+       if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
+               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
+       } else {
+               dma_set_mask(bus->dev, DMA_BIT_MASK(32));
+               dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
+       }
+
        /* initialize streams */
        snd_hdac_ext_stream_init_all
                (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
@@ -962,6 +967,36 @@ static int skl_probe(struct pci_dev *pci,
        struct hdac_bus *bus = NULL;
        int err;
 
+       switch (skl_pci_binding) {
+       case SND_SKL_PCI_BIND_AUTO:
+               /*
+                * detect DSP by checking class/subclass/prog-id information
+                * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
+                * class=04 subclass 01 prog-if 00: DSP is present
+                *   (and may be required e.g. for DMIC or SSP support)
+                * class=04 subclass 03 prog-if 80: use DSP or legacy mode
+                */
+               if (pci->class == 0x040300) {
+                       dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+                       return -ENODEV;
+               }
+               if (pci->class != 0x040100 && pci->class != 0x040380) {
+                       dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
+                       return -ENODEV;
+               }
+               dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+               break;
+       case SND_SKL_PCI_BIND_LEGACY:
+               dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
+               return -ENODEV;
+       case SND_SKL_PCI_BIND_ASOC:
+               dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n");
+               break;
+       default:
+               dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
+               break;
+       }
+
        /* we use ext core ops, so provide NULL for ops here */
        err = skl_create(pci, NULL, &skl);
        if (err < 0)
@@ -970,8 +1005,10 @@ static int skl_probe(struct pci_dev *pci,
        bus = skl_to_bus(skl);
 
        err = skl_first_init(bus);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
                goto out_free;
+       }
 
        skl->pci_id = pci->device;
 
@@ -980,37 +1017,48 @@ static int skl_probe(struct pci_dev *pci,
        skl->nhlt = skl_nhlt_init(bus->dev);
 
        if (skl->nhlt == NULL) {
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
+               dev_err(bus->dev, "no nhlt info found\n");
                err = -ENODEV;
                goto out_free;
-       }
-
-       err = skl_nhlt_create_sysfs(skl);
-       if (err < 0)
-               goto out_nhlt_free;
+#else
+               dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n");
+#endif
+       } else {
 
-       skl_nhlt_update_topology_bin(skl);
+               err = skl_nhlt_create_sysfs(skl);
+               if (err < 0) {
+                       dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
+                       goto out_nhlt_free;
+               }
 
-       pci_set_drvdata(skl->pci, bus);
+               skl_nhlt_update_topology_bin(skl);
 
-       /* check if dsp is there */
-       if (bus->ppcap) {
                /* create device for dsp clk */
                err = skl_clock_device_register(skl);
-               if (err < 0)
+               if (err < 0) {
+                       dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
                        goto out_clk_free;
+               }
+       }
 
-               err = skl_find_machine(skl, (void *)pci_id->driver_data);
-               if (err < 0)
-                       goto out_nhlt_free;
+       pci_set_drvdata(skl->pci, bus);
 
-               err = skl_init_dsp(skl);
-               if (err < 0) {
-                       dev_dbg(bus->dev, "error failed to register dsp\n");
-                       goto out_nhlt_free;
-               }
-               skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
-               skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
+       err = skl_find_machine(skl, (void *)pci_id->driver_data);
+       if (err < 0) {
+               dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
+               goto out_nhlt_free;
        }
+
+       err = skl_init_dsp(skl);
+       if (err < 0) {
+               dev_dbg(bus->dev, "error failed to register dsp\n");
+               goto out_nhlt_free;
+       }
+       skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+       skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
        if (bus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(bus);
 
@@ -1018,8 +1066,10 @@ static int skl_probe(struct pci_dev *pci,
 
        /* create device for soc dmic */
        err = skl_dmic_device_register(skl);
-       if (err < 0)
+       if (err < 0) {
+               dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
                goto out_dsp_free;
+       }
 
        schedule_work(&skl->probe_work);
 
@@ -1087,21 +1137,36 @@ static void skl_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
        /* BXT-P */
        { PCI_DEVICE(0x8086, 0x5a98),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
        /* KBL */
        { PCI_DEVICE(0x8086, 0x9D71),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
        /* GLK */
        { PCI_DEVICE(0x8086, 0x3198),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
        /* CNL */
        { PCI_DEVICE(0x8086, 0x9dc8),
                .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
+       /* CFL */
+       { PCI_DEVICE(0x8086, 0xa348),
+               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);