]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/soundwire/intel.c
Merge tag 'iomap-5.5-merge-13' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux.git] / drivers / soundwire / intel.c
index 13c54eac0cc3e2b3cb609fb907c2e832bbe711ae..99dc610212113ff5d9f94eaf6dbd0a95a0c07cf5 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -479,7 +480,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
        unsigned int link_id = sdw->instance;
        int pdi_conf = 0;
 
-       pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+       /* the Bulk and PCM streams are not contiguous */
+       pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+       if (pdi->num >= 2)
+               pdi->intel_alh_id += 2;
 
        /*
         * Program stream parameters to stream SHIM register
@@ -508,7 +512,10 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
        unsigned int link_id = sdw->instance;
        unsigned int conf;
 
-       pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+       /* the Bulk and PCM streams are not contiguous */
+       pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
+       if (pdi->num >= 2)
+               pdi->intel_alh_id += 2;
 
        /* Program Stream config ALH register */
        conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
@@ -603,66 +610,6 @@ static int intel_post_bank_switch(struct sdw_bus *bus)
  * DAI routines
  */
 
-static struct sdw_cdns_port *intel_alloc_port(struct sdw_intel *sdw,
-                                             u32 ch, u32 dir, bool pcm)
-{
-       struct sdw_cdns *cdns = &sdw->cdns;
-       struct sdw_cdns_port *port = NULL;
-       int i, ret = 0;
-
-       for (i = 0; i < cdns->num_ports; i++) {
-               if (cdns->ports[i].assigned)
-                       continue;
-
-               port = &cdns->ports[i];
-               port->assigned = true;
-               port->direction = dir;
-               port->ch = ch;
-               break;
-       }
-
-       if (!port) {
-               dev_err(cdns->dev, "Unable to find a free port\n");
-               return NULL;
-       }
-
-       if (pcm) {
-               ret = sdw_cdns_alloc_stream(cdns, &cdns->pcm, port, ch, dir);
-               if (ret)
-                       goto out;
-
-               intel_pdi_shim_configure(sdw, port->pdi);
-               sdw_cdns_config_stream(cdns, port, ch, dir, port->pdi);
-
-               intel_pdi_alh_configure(sdw, port->pdi);
-
-       } else {
-               ret = sdw_cdns_alloc_stream(cdns, &cdns->pdm, port, ch, dir);
-       }
-
-out:
-       if (ret) {
-               port->assigned = false;
-               port = NULL;
-       }
-
-       return port;
-}
-
-static void intel_port_cleanup(struct sdw_cdns_dma_data *dma)
-{
-       int i;
-
-       for (i = 0; i < dma->nr_ports; i++) {
-               if (dma->port[i]) {
-                       dma->port[i]->pdi->assigned = false;
-                       dma->port[i]->pdi = NULL;
-                       dma->port[i]->assigned = false;
-                       dma->port[i] = NULL;
-               }
-       }
-}
-
 static int intel_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
@@ -670,9 +617,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
        struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
        struct sdw_intel *sdw = cdns_to_intel(cdns);
        struct sdw_cdns_dma_data *dma;
+       struct sdw_cdns_pdi *pdi;
        struct sdw_stream_config sconfig;
        struct sdw_port_config *pconfig;
-       int ret, i, ch, dir;
+       int ch, dir;
+       int ret;
        bool pcm = true;
 
        dma = snd_soc_dai_get_dma_data(dai, substream);
@@ -685,38 +634,30 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
        else
                dir = SDW_DATA_DIR_TX;
 
-       if (dma->stream_type == SDW_STREAM_PDM) {
-               /* TODO: Check whether PDM decimator is already in use */
-               dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pdm, ch, dir);
+       if (dma->stream_type == SDW_STREAM_PDM)
                pcm = false;
-       } else {
-               dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir);
-       }
 
-       if (!dma->nr_ports) {
-               dev_err(dai->dev, "ports/resources not available\n");
-               return -EINVAL;
+       if (pcm)
+               pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
+       else
+               pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);
+
+       if (!pdi) {
+               ret = -EINVAL;
+               goto error;
        }
 
-       dma->port = kcalloc(dma->nr_ports, sizeof(*dma->port), GFP_KERNEL);
-       if (!dma->port)
-               return -ENOMEM;
+       /* do run-time configurations for SHIM, ALH and PDI/PORT */
+       intel_pdi_shim_configure(sdw, pdi);
+       intel_pdi_alh_configure(sdw, pdi);
+       sdw_cdns_config_stream(cdns, ch, dir, pdi);
 
-       for (i = 0; i < dma->nr_ports; i++) {
-               dma->port[i] = intel_alloc_port(sdw, ch, dir, pcm);
-               if (!dma->port[i]) {
-                       ret = -EINVAL;
-                       goto port_error;
-               }
-       }
 
        /* Inform DSP about PDI stream number */
-       for (i = 0; i < dma->nr_ports; i++) {
-               ret = intel_config_stream(sdw, substream, dai, params,
-                                         dma->port[i]->pdi->intel_alh_id);
-               if (ret)
-                       goto port_error;
-       }
+       ret = intel_config_stream(sdw, substream, dai, params,
+                                 pdi->intel_alh_id);
+       if (ret)
+               goto error;
 
        sconfig.direction = dir;
        sconfig.ch_count = ch;
@@ -731,32 +672,22 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Port configuration */
-       pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL);
+       pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
        if (!pconfig) {
                ret =  -ENOMEM;
-               goto port_error;
+               goto error;
        }
 
-       for (i = 0; i < dma->nr_ports; i++) {
-               pconfig[i].num = dma->port[i]->num;
-               pconfig[i].ch_mask = (1 << ch) - 1;
-       }
+       pconfig->num = pdi->num;
+       pconfig->ch_mask = (1 << ch) - 1;
 
        ret = sdw_stream_add_master(&cdns->bus, &sconfig,
-                                   pconfig, dma->nr_ports, dma->stream);
-       if (ret) {
+                                   pconfig, 1, dma->stream);
+       if (ret)
                dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
-               goto stream_error;
-       }
 
        kfree(pconfig);
-       return ret;
-
-stream_error:
-       kfree(pconfig);
-port_error:
-       intel_port_cleanup(dma);
-       kfree(dma->port);
+error:
        return ret;
 }
 
@@ -776,8 +707,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
                dev_err(dai->dev, "remove master from stream %s failed: %d\n",
                        dma->stream->name, ret);
 
-       intel_port_cleanup(dma);
-       kfree(dma->port);
        return ret;
 }
 
@@ -842,14 +771,6 @@ static int intel_create_dai(struct sdw_cdns *cdns,
                        return -ENOMEM;
 
                if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
-                       dais[i].playback.stream_name =
-                               kasprintf(GFP_KERNEL, "SDW%d Tx%d",
-                                         cdns->instance, i);
-                       if (!dais[i].playback.stream_name) {
-                               kfree(dais[i].name);
-                               return -ENOMEM;
-                       }
-
                        dais[i].playback.channels_min = 1;
                        dais[i].playback.channels_max = max_ch;
                        dais[i].playback.rates = SNDRV_PCM_RATE_48000;
@@ -857,23 +778,12 @@ static int intel_create_dai(struct sdw_cdns *cdns,
                }
 
                if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
-                       dais[i].capture.stream_name =
-                               kasprintf(GFP_KERNEL, "SDW%d Rx%d",
-                                         cdns->instance, i);
-                       if (!dais[i].capture.stream_name) {
-                               kfree(dais[i].name);
-                               kfree(dais[i].playback.stream_name);
-                               return -ENOMEM;
-                       }
-
                        dais[i].capture.channels_min = 1;
                        dais[i].capture.channels_max = max_ch;
                        dais[i].capture.rates = SNDRV_PCM_RATE_48000;
                        dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
                }
 
-               dais[i].id = SDW_DAI_ID_RANGE_START + i;
-
                if (pcm)
                        dais[i].ops = &intel_pcm_dai_ops;
                else
@@ -993,6 +903,15 @@ static struct sdw_master_ops sdw_intel_ops = {
        .post_bank_switch = intel_post_bank_switch,
 };
 
+static int intel_init(struct sdw_intel *sdw)
+{
+       /* Initialize shim and controller */
+       intel_link_power_up(sdw);
+       intel_shim_init(sdw);
+
+       return sdw_cdns_init(&sdw->cdns, false);
+}
+
 /*
  * probe and init
  */
@@ -1026,7 +945,7 @@ static int intel_probe(struct platform_device *pdev)
        ret = sdw_add_bus_master(&sdw->cdns.bus);
        if (ret) {
                dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret);
-               goto err_master_reg;
+               return ret;
        }
 
        if (sdw->cdns.bus.prop.hw_disabled) {
@@ -1035,16 +954,11 @@ static int intel_probe(struct platform_device *pdev)
                return 0;
        }
 
-       /* Initialize shim and controller */
-       intel_link_power_up(sdw);
-       intel_shim_init(sdw);
-
-       ret = sdw_cdns_init(&sdw->cdns);
+       /* Initialize shim, controller and Cadence IP */
+       ret = intel_init(sdw);
        if (ret)
                goto err_init;
 
-       ret = sdw_cdns_enable_interrupt(&sdw->cdns);
-
        /* Read the PDI config and initialize cadence PDI */
        intel_pdi_init(sdw, &config);
        ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1062,23 +976,35 @@ static int intel_probe(struct platform_device *pdev)
                goto err_init;
        }
 
+       ret = sdw_cdns_enable_interrupt(&sdw->cdns, true);
+       if (ret < 0) {
+               dev_err(sdw->cdns.dev, "cannot enable interrupts\n");
+               goto err_init;
+       }
+
+       ret = sdw_cdns_exit_reset(&sdw->cdns);
+       if (ret < 0) {
+               dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n");
+               goto err_interrupt;
+       }
+
        /* Register DAIs */
        ret = intel_register_dai(sdw);
        if (ret) {
                dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret);
                snd_soc_unregister_component(sdw->cdns.dev);
-               goto err_dai;
+               goto err_interrupt;
        }
 
        intel_debugfs_init(sdw);
 
        return 0;
 
-err_dai:
+err_interrupt:
+       sdw_cdns_enable_interrupt(&sdw->cdns, false);
        free_irq(sdw->res->irq, sdw);
 err_init:
        sdw_delete_bus_master(&sdw->cdns.bus);
-err_master_reg:
        return ret;
 }
 
@@ -1090,6 +1016,7 @@ static int intel_remove(struct platform_device *pdev)
 
        if (!sdw->cdns.bus.prop.hw_disabled) {
                intel_debugfs_exit(sdw);
+               sdw_cdns_enable_interrupt(&sdw->cdns, false);
                free_irq(sdw->res->irq, sdw);
                snd_soc_unregister_component(sdw->cdns.dev);
        }