linux/sound/soc/sof/intel/hda-ctrl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2//
   3// This file is provided under a dual BSD/GPLv2 license.  When using or
   4// redistributing this file, you may do so under either license.
   5//
   6// Copyright(c) 2018 Intel Corporation. All rights reserved.
   7//
   8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
   9//          Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  10//          Rander Wang <rander.wang@intel.com>
  11//          Keyon Jie <yang.jie@linux.intel.com>
  12//
  13
  14/*
  15 * Hardware interface for generic Intel audio DSP HDA IP
  16 */
  17
  18#include <linux/module.h>
  19#include <sound/hdaudio_ext.h>
  20#include <sound/hda_register.h>
  21#include <sound/hda_component.h>
  22#include "../ops.h"
  23#include "hda.h"
  24
  25#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
  26static int hda_codec_mask = -1;
  27module_param_named(codec_mask, hda_codec_mask, int, 0444);
  28MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
  29#endif
  30
  31/*
  32 * HDA Operations.
  33 */
  34
  35int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset)
  36{
  37        unsigned long timeout;
  38        u32 gctl = 0;
  39        u32 val;
  40
  41        /* 0 to enter reset and 1 to exit reset */
  42        val = reset ? 0 : SOF_HDA_GCTL_RESET;
  43
  44        /* enter/exit HDA controller reset */
  45        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
  46                                SOF_HDA_GCTL_RESET, val);
  47
  48        /* wait to enter/exit reset */
  49        timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
  50        while (time_before(jiffies, timeout)) {
  51                gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
  52                if ((gctl & SOF_HDA_GCTL_RESET) == val)
  53                        return 0;
  54                usleep_range(500, 1000);
  55        }
  56
  57        /* enter/exit reset failed */
  58        dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n",
  59                reset ? "reset" : "ready", gctl);
  60        return -EIO;
  61}
  62
  63int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
  64{
  65        struct hdac_bus *bus = sof_to_bus(sdev);
  66        u32 cap, offset, feature;
  67        int count = 0;
  68        int ret;
  69
  70        /*
  71         * On some devices, one reset cycle is necessary before reading
  72         * capabilities
  73         */
  74        ret = hda_dsp_ctrl_link_reset(sdev, true);
  75        if (ret < 0)
  76                return ret;
  77        ret = hda_dsp_ctrl_link_reset(sdev, false);
  78        if (ret < 0)
  79                return ret;
  80
  81        offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH);
  82
  83        do {
  84                dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n",
  85                        offset & SOF_HDA_CAP_NEXT_MASK);
  86
  87                cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset);
  88
  89                if (cap == -1) {
  90                        dev_dbg(bus->dev, "Invalid capability reg read\n");
  91                        break;
  92                }
  93
  94                feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF;
  95
  96                switch (feature) {
  97                case SOF_HDA_PP_CAP_ID:
  98                        dev_dbg(sdev->dev, "found DSP capability at 0x%x\n",
  99                                offset);
 100                        bus->ppcap = bus->remap_addr + offset;
 101                        sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap;
 102                        break;
 103                case SOF_HDA_SPIB_CAP_ID:
 104                        dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n",
 105                                offset);
 106                        bus->spbcap = bus->remap_addr + offset;
 107                        sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap;
 108                        break;
 109                case SOF_HDA_DRSM_CAP_ID:
 110                        dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n",
 111                                offset);
 112                        bus->drsmcap = bus->remap_addr + offset;
 113                        sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap;
 114                        break;
 115                case SOF_HDA_GTS_CAP_ID:
 116                        dev_dbg(sdev->dev, "found GTS capability at 0x%x\n",
 117                                offset);
 118                        bus->gtscap = bus->remap_addr + offset;
 119                        break;
 120                case SOF_HDA_ML_CAP_ID:
 121                        dev_dbg(sdev->dev, "found ML capability at 0x%x\n",
 122                                offset);
 123                        bus->mlcap = bus->remap_addr + offset;
 124                        break;
 125                default:
 126                        dev_dbg(sdev->dev, "found capability %d at 0x%x\n",
 127                                feature, offset);
 128                        break;
 129                }
 130
 131                offset = cap & SOF_HDA_CAP_NEXT_MASK;
 132        } while (count++ <= SOF_HDA_MAX_CAPS && offset);
 133
 134        return 0;
 135}
 136
 137void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
 138{
 139        u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0;
 140
 141        snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
 142                                SOF_HDA_PPCTL_GPROCEN, val);
 143}
 144
 145void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
 146{
 147        u32 val = enable ? SOF_HDA_PPCTL_PIE : 0;
 148
 149        snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
 150                                SOF_HDA_PPCTL_PIE, val);
 151}
 152
 153void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
 154{
 155        u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0;
 156
 157        snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val);
 158}
 159
 160/*
 161 * enable/disable audio dsp clock gating and power gating bits.
 162 * This allows the HW to opportunistically power and clock gate
 163 * the audio dsp when it is idle
 164 */
 165int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
 166{
 167        u32 val;
 168
 169        /* enable/disable audio dsp clock gating */
 170        val = enable ? PCI_CGCTL_ADSPDCGE : 0;
 171        snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
 172
 173        /* enable/disable DMI Link L1 support */
 174        val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0;
 175        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
 176                                HDA_VS_INTEL_EM2_L1SEN, val);
 177
 178        /* enable/disable audio dsp power gating */
 179        val = enable ? 0 : PCI_PGCTL_ADSPPGD;
 180        snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val);
 181
 182        return 0;
 183}
 184
 185int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
 186{
 187        struct hdac_bus *bus = sof_to_bus(sdev);
 188#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 189        struct hdac_ext_link *hlink;
 190#endif
 191        struct hdac_stream *stream;
 192        int sd_offset, ret = 0;
 193
 194        if (bus->chip_init)
 195                return 0;
 196
 197#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 198        snd_hdac_set_codec_wakeup(bus, true);
 199#endif
 200        hda_dsp_ctrl_misc_clock_gating(sdev, false);
 201
 202        if (full_reset) {
 203                /* reset HDA controller */
 204                ret = hda_dsp_ctrl_link_reset(sdev, true);
 205                if (ret < 0) {
 206                        dev_err(sdev->dev, "error: failed to reset HDA controller\n");
 207                        goto err;
 208                }
 209
 210                usleep_range(500, 1000);
 211
 212                /* exit HDA controller reset */
 213                ret = hda_dsp_ctrl_link_reset(sdev, false);
 214                if (ret < 0) {
 215                        dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
 216                        goto err;
 217                }
 218
 219                usleep_range(1000, 1200);
 220        }
 221
 222#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 223        /* check to see if controller is ready */
 224        if (!snd_hdac_chip_readb(bus, GCTL)) {
 225                dev_dbg(bus->dev, "controller not ready!\n");
 226                ret = -EBUSY;
 227                goto err;
 228        }
 229
 230        /* Accept unsolicited responses */
 231        snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
 232
 233        /* detect codecs */
 234        if (!bus->codec_mask) {
 235                bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
 236                dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
 237        }
 238
 239        if (hda_codec_mask != -1) {
 240                bus->codec_mask &= hda_codec_mask;
 241                dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
 242                        bus->codec_mask);
 243        }
 244#endif
 245
 246        /* clear stream status */
 247        list_for_each_entry(stream, &bus->stream_list, list) {
 248                sd_offset = SOF_STREAM_SD_OFFSET(stream);
 249                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
 250                                  sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
 251                                  SOF_HDA_CL_DMA_SD_INT_MASK);
 252        }
 253
 254        /* clear WAKESTS */
 255        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
 256                          SOF_HDA_WAKESTS_INT_MASK);
 257
 258#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 259        /* clear rirb status */
 260        snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
 261#endif
 262
 263        /* clear interrupt status register */
 264        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
 265                          SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
 266
 267#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 268        /* initialize the codec command I/O */
 269        snd_hdac_bus_init_cmd_io(bus);
 270#endif
 271
 272        /* enable CIE and GIE interrupts */
 273        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
 274                                SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
 275                                SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
 276
 277        /* program the position buffer */
 278        if (bus->use_posbuf && bus->posbuf.addr) {
 279                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE,
 280                                  (u32)bus->posbuf.addr);
 281                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE,
 282                                  upper_32_bits(bus->posbuf.addr));
 283        }
 284
 285#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 286        /* Reset stream-to-link mapping */
 287        list_for_each_entry(hlink, &bus->hlink_list, list)
 288                writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
 289#endif
 290
 291        bus->chip_init = true;
 292
 293err:
 294        hda_dsp_ctrl_misc_clock_gating(sdev, true);
 295#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 296        snd_hdac_set_codec_wakeup(bus, false);
 297#endif
 298
 299        return ret;
 300}
 301
 302void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
 303{
 304        struct hdac_bus *bus = sof_to_bus(sdev);
 305        struct hdac_stream *stream;
 306        int sd_offset;
 307
 308        if (!bus->chip_init)
 309                return;
 310
 311        /* disable interrupts in stream descriptor */
 312        list_for_each_entry(stream, &bus->stream_list, list) {
 313                sd_offset = SOF_STREAM_SD_OFFSET(stream);
 314                snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
 315                                        sd_offset +
 316                                        SOF_HDA_ADSP_REG_CL_SD_CTL,
 317                                        SOF_HDA_CL_DMA_SD_INT_MASK,
 318                                        0);
 319        }
 320
 321        /* disable SIE for all streams */
 322        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
 323                                SOF_HDA_INT_ALL_STREAM, 0);
 324
 325        /* disable controller CIE and GIE */
 326        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
 327                                SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
 328                                0);
 329
 330        /* clear stream status */
 331        list_for_each_entry(stream, &bus->stream_list, list) {
 332                sd_offset = SOF_STREAM_SD_OFFSET(stream);
 333                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
 334                                  sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
 335                                  SOF_HDA_CL_DMA_SD_INT_MASK);
 336        }
 337
 338        /* clear WAKESTS */
 339        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
 340                          SOF_HDA_WAKESTS_INT_MASK);
 341
 342#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 343        /* clear rirb status */
 344        snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
 345#endif
 346
 347        /* clear interrupt status register */
 348        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
 349                          SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
 350
 351#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 352        /* disable CORB/RIRB */
 353        snd_hdac_bus_stop_cmd_io(bus);
 354#endif
 355        /* disable position buffer */
 356        if (bus->posbuf.addr) {
 357                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
 358                                  SOF_HDA_ADSP_DPLBASE, 0);
 359                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
 360                                  SOF_HDA_ADSP_DPUBASE, 0);
 361        }
 362
 363        bus->chip_init = false;
 364}
 365