linux/sound/soc/amd/renoir/rn-pci-acp3x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3// AMD Renoir ACP PCI Driver
   4//
   5//Copyright 2020 Advanced Micro Devices, Inc.
   6
   7#include <linux/pci.h>
   8#include <linux/acpi.h>
   9#include <linux/module.h>
  10#include <linux/io.h>
  11#include <linux/delay.h>
  12#include <linux/platform_device.h>
  13#include <linux/interrupt.h>
  14#include <linux/pm_runtime.h>
  15
  16#include "rn_acp3x.h"
  17
  18static int acp_power_gating;
  19module_param(acp_power_gating, int, 0644);
  20MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
  21
  22/**
  23 * dmic_acpi_check = -1 - Checks ACPI method to know DMIC hardware status runtime
  24 *                 = 0 - Skips the DMIC device creation and returns probe failure
  25 *                 = 1 - Assumes that platform has DMIC support and skips ACPI
  26 *                       method check
  27 */
  28static int dmic_acpi_check = ACP_DMIC_AUTO;
  29module_param(dmic_acpi_check, bint, 0644);
  30MODULE_PARM_DESC(dmic_acpi_check, "checks Dmic hardware runtime");
  31
  32struct acp_dev_data {
  33        void __iomem *acp_base;
  34        struct resource *res;
  35        struct platform_device *pdev[ACP_DEVS];
  36};
  37
  38static int rn_acp_power_on(void __iomem *acp_base)
  39{
  40        u32 val;
  41        int timeout;
  42
  43        val = rn_readl(acp_base + ACP_PGFSM_STATUS);
  44
  45        if (val == 0)
  46                return val;
  47
  48        if ((val & ACP_PGFSM_STATUS_MASK) !=
  49                                ACP_POWER_ON_IN_PROGRESS)
  50                rn_writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
  51                          acp_base + ACP_PGFSM_CONTROL);
  52        timeout = 0;
  53        while (++timeout < 500) {
  54                val = rn_readl(acp_base + ACP_PGFSM_STATUS);
  55                if (!val)
  56                        return 0;
  57                udelay(1);
  58        }
  59        return -ETIMEDOUT;
  60}
  61
  62static int rn_acp_power_off(void __iomem *acp_base)
  63{
  64        u32 val;
  65        int timeout;
  66
  67        rn_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
  68                  acp_base + ACP_PGFSM_CONTROL);
  69        timeout = 0;
  70        while (++timeout < 500) {
  71                val = rn_readl(acp_base + ACP_PGFSM_STATUS);
  72                if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
  73                        return 0;
  74                udelay(1);
  75        }
  76        return -ETIMEDOUT;
  77}
  78
  79static int rn_acp_reset(void __iomem *acp_base)
  80{
  81        u32 val;
  82        int timeout;
  83
  84        rn_writel(1, acp_base + ACP_SOFT_RESET);
  85        timeout = 0;
  86        while (++timeout < 500) {
  87                val = rn_readl(acp_base + ACP_SOFT_RESET);
  88                if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
  89                        break;
  90                cpu_relax();
  91        }
  92        rn_writel(0, acp_base + ACP_SOFT_RESET);
  93        timeout = 0;
  94        while (++timeout < 500) {
  95                val = rn_readl(acp_base + ACP_SOFT_RESET);
  96                if (!val)
  97                        return 0;
  98                cpu_relax();
  99        }
 100        return -ETIMEDOUT;
 101}
 102
 103static void rn_acp_enable_interrupts(void __iomem *acp_base)
 104{
 105        u32 ext_intr_ctrl;
 106
 107        rn_writel(0x01, acp_base + ACP_EXTERNAL_INTR_ENB);
 108        ext_intr_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
 109        ext_intr_ctrl |= ACP_ERROR_MASK;
 110        rn_writel(ext_intr_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
 111}
 112
 113static void rn_acp_disable_interrupts(void __iomem *acp_base)
 114{
 115        rn_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
 116                  ACP_EXTERNAL_INTR_STAT);
 117        rn_writel(0x00, acp_base + ACP_EXTERNAL_INTR_ENB);
 118}
 119
 120static int rn_acp_init(void __iomem *acp_base)
 121{
 122        int ret;
 123
 124        /* power on */
 125        ret = rn_acp_power_on(acp_base);
 126        if (ret) {
 127                pr_err("ACP power on failed\n");
 128                return ret;
 129        }
 130        rn_writel(0x01, acp_base + ACP_CONTROL);
 131        /* Reset */
 132        ret = rn_acp_reset(acp_base);
 133        if (ret) {
 134                pr_err("ACP reset failed\n");
 135                return ret;
 136        }
 137        rn_writel(0x03, acp_base + ACP_CLKMUX_SEL);
 138        rn_acp_enable_interrupts(acp_base);
 139        return 0;
 140}
 141
 142static int rn_acp_deinit(void __iomem *acp_base)
 143{
 144        int ret;
 145
 146        rn_acp_disable_interrupts(acp_base);
 147        /* Reset */
 148        ret = rn_acp_reset(acp_base);
 149        if (ret) {
 150                pr_err("ACP reset failed\n");
 151                return ret;
 152        }
 153        rn_writel(0x00, acp_base + ACP_CLKMUX_SEL);
 154        rn_writel(0x00, acp_base + ACP_CONTROL);
 155        /* power off */
 156        if (acp_power_gating) {
 157                ret = rn_acp_power_off(acp_base);
 158                if (ret) {
 159                        pr_err("ACP power off failed\n");
 160                        return ret;
 161                }
 162        }
 163        return 0;
 164}
 165
 166static int snd_rn_acp_probe(struct pci_dev *pci,
 167                            const struct pci_device_id *pci_id)
 168{
 169        struct acp_dev_data *adata;
 170        struct platform_device_info pdevinfo[ACP_DEVS];
 171#if defined(CONFIG_ACPI)
 172        acpi_handle handle;
 173        acpi_integer dmic_status;
 174#endif
 175        unsigned int irqflags;
 176        int ret, index;
 177        u32 addr;
 178
 179        if (pci_enable_device(pci)) {
 180                dev_err(&pci->dev, "pci_enable_device failed\n");
 181                return -ENODEV;
 182        }
 183
 184        ret = pci_request_regions(pci, "AMD ACP3x audio");
 185        if (ret < 0) {
 186                dev_err(&pci->dev, "pci_request_regions failed\n");
 187                goto disable_pci;
 188        }
 189
 190        adata = devm_kzalloc(&pci->dev, sizeof(struct acp_dev_data),
 191                             GFP_KERNEL);
 192        if (!adata) {
 193                ret = -ENOMEM;
 194                goto release_regions;
 195        }
 196
 197        /* check for msi interrupt support */
 198        ret = pci_enable_msi(pci);
 199        if (ret)
 200                /* msi is not enabled */
 201                irqflags = IRQF_SHARED;
 202        else
 203                /* msi is enabled */
 204                irqflags = 0;
 205
 206        addr = pci_resource_start(pci, 0);
 207        adata->acp_base = devm_ioremap(&pci->dev, addr,
 208                                       pci_resource_len(pci, 0));
 209        if (!adata->acp_base) {
 210                ret = -ENOMEM;
 211                goto disable_msi;
 212        }
 213        pci_set_master(pci);
 214        pci_set_drvdata(pci, adata);
 215        ret = rn_acp_init(adata->acp_base);
 216        if (ret)
 217                goto disable_msi;
 218
 219        if (!dmic_acpi_check) {
 220                ret = -ENODEV;
 221                goto de_init;
 222        } else if (dmic_acpi_check == ACP_DMIC_AUTO) {
 223#if defined(CONFIG_ACPI)
 224                handle = ACPI_HANDLE(&pci->dev);
 225                ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
 226                if (ACPI_FAILURE(ret)) {
 227                        ret = -EINVAL;
 228                        goto de_init;
 229                }
 230                if (!dmic_status) {
 231                        ret = -ENODEV;
 232                        goto de_init;
 233                }
 234#endif
 235        }
 236
 237        adata->res = devm_kzalloc(&pci->dev,
 238                                  sizeof(struct resource) * 2,
 239                                  GFP_KERNEL);
 240        if (!adata->res) {
 241                ret = -ENOMEM;
 242                goto de_init;
 243        }
 244
 245        adata->res[0].name = "acp_pdm_iomem";
 246        adata->res[0].flags = IORESOURCE_MEM;
 247        adata->res[0].start = addr;
 248        adata->res[0].end = addr + (ACP_REG_END - ACP_REG_START);
 249        adata->res[1].name = "acp_pdm_irq";
 250        adata->res[1].flags = IORESOURCE_IRQ;
 251        adata->res[1].start = pci->irq;
 252        adata->res[1].end = pci->irq;
 253
 254        memset(&pdevinfo, 0, sizeof(pdevinfo));
 255        pdevinfo[0].name = "acp_rn_pdm_dma";
 256        pdevinfo[0].id = 0;
 257        pdevinfo[0].parent = &pci->dev;
 258        pdevinfo[0].num_res = 2;
 259        pdevinfo[0].res = adata->res;
 260        pdevinfo[0].data = &irqflags;
 261        pdevinfo[0].size_data = sizeof(irqflags);
 262
 263        pdevinfo[1].name = "dmic-codec";
 264        pdevinfo[1].id = 0;
 265        pdevinfo[1].parent = &pci->dev;
 266        pdevinfo[2].name = "acp_pdm_mach";
 267        pdevinfo[2].id = 0;
 268        pdevinfo[2].parent = &pci->dev;
 269        for (index = 0; index < ACP_DEVS; index++) {
 270                adata->pdev[index] =
 271                                platform_device_register_full(&pdevinfo[index]);
 272                if (IS_ERR(adata->pdev[index])) {
 273                        dev_err(&pci->dev, "cannot register %s device\n",
 274                                pdevinfo[index].name);
 275                        ret = PTR_ERR(adata->pdev[index]);
 276                        goto unregister_devs;
 277                }
 278        }
 279        pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
 280        pm_runtime_use_autosuspend(&pci->dev);
 281        pm_runtime_put_noidle(&pci->dev);
 282        pm_runtime_allow(&pci->dev);
 283        return 0;
 284
 285unregister_devs:
 286        for (index = 0; index < ACP_DEVS; index++)
 287                platform_device_unregister(adata->pdev[index]);
 288de_init:
 289        if (rn_acp_deinit(adata->acp_base))
 290                dev_err(&pci->dev, "ACP de-init failed\n");
 291disable_msi:
 292        pci_disable_msi(pci);
 293release_regions:
 294        pci_release_regions(pci);
 295disable_pci:
 296        pci_disable_device(pci);
 297
 298        return ret;
 299}
 300
 301static int snd_rn_acp_suspend(struct device *dev)
 302{
 303        int ret;
 304        struct acp_dev_data *adata;
 305
 306        adata = dev_get_drvdata(dev);
 307        ret = rn_acp_deinit(adata->acp_base);
 308        if (ret)
 309                dev_err(dev, "ACP de-init failed\n");
 310        else
 311                dev_dbg(dev, "ACP de-initialized\n");
 312
 313        return ret;
 314}
 315
 316static int snd_rn_acp_resume(struct device *dev)
 317{
 318        int ret;
 319        struct acp_dev_data *adata;
 320
 321        adata = dev_get_drvdata(dev);
 322        ret = rn_acp_init(adata->acp_base);
 323        if (ret) {
 324                dev_err(dev, "ACP init failed\n");
 325                return ret;
 326        }
 327        return 0;
 328}
 329
 330static const struct dev_pm_ops rn_acp_pm = {
 331        .runtime_suspend = snd_rn_acp_suspend,
 332        .runtime_resume =  snd_rn_acp_resume,
 333        .suspend = snd_rn_acp_suspend,
 334        .resume =       snd_rn_acp_resume,
 335};
 336
 337static void snd_rn_acp_remove(struct pci_dev *pci)
 338{
 339        struct acp_dev_data *adata;
 340        int ret, index;
 341
 342        adata = pci_get_drvdata(pci);
 343        for (index = 0; index < ACP_DEVS; index++)
 344                platform_device_unregister(adata->pdev[index]);
 345        ret = rn_acp_deinit(adata->acp_base);
 346        if (ret)
 347                dev_err(&pci->dev, "ACP de-init failed\n");
 348        pm_runtime_forbid(&pci->dev);
 349        pm_runtime_get_noresume(&pci->dev);
 350        pci_disable_msi(pci);
 351        pci_release_regions(pci);
 352        pci_disable_device(pci);
 353}
 354
 355static const struct pci_device_id snd_rn_acp_ids[] = {
 356        { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
 357        .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
 358        .class_mask = 0xffffff },
 359        { 0, },
 360};
 361MODULE_DEVICE_TABLE(pci, snd_rn_acp_ids);
 362
 363static struct pci_driver rn_acp_driver  = {
 364        .name = KBUILD_MODNAME,
 365        .id_table = snd_rn_acp_ids,
 366        .probe = snd_rn_acp_probe,
 367        .remove = snd_rn_acp_remove,
 368        .driver = {
 369                .pm = &rn_acp_pm,
 370        }
 371};
 372
 373module_pci_driver(rn_acp_driver);
 374
 375MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 376MODULE_DESCRIPTION("AMD ACP Renoir PCI driver");
 377MODULE_LICENSE("GPL v2");
 378