linux/sound/soc/intel/atom/sst/sst_acpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration.
   4 *
   5 * Copyright (c) 2013, Intel Corporation.
   6 *
   7 *  Authors:    Ramesh Babu K V <Ramesh.Babu@intel.com>
   8 *  Authors:    Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/fs.h>
  13#include <linux/interrupt.h>
  14#include <linux/slab.h>
  15#include <linux/io.h>
  16#include <linux/platform_device.h>
  17#include <linux/firmware.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/pm_qos.h>
  20#include <linux/dmi.h>
  21#include <linux/acpi.h>
  22#include <asm/platform_sst_audio.h>
  23#include <sound/core.h>
  24#include <sound/intel-dsp-config.h>
  25#include <sound/soc.h>
  26#include <sound/compress_driver.h>
  27#include <acpi/acbuffer.h>
  28#include <acpi/platform/acenv.h>
  29#include <acpi/platform/aclinux.h>
  30#include <acpi/actypes.h>
  31#include <acpi/acpi_bus.h>
  32#include <sound/soc-acpi.h>
  33#include <sound/soc-acpi-intel-match.h>
  34#include "../sst-mfld-platform.h"
  35#include "../../common/soc-intel-quirks.h"
  36#include "sst.h"
  37
  38/* LPE viewpoint addresses */
  39#define SST_BYT_IRAM_PHY_START  0xff2c0000
  40#define SST_BYT_IRAM_PHY_END    0xff2d4000
  41#define SST_BYT_DRAM_PHY_START  0xff300000
  42#define SST_BYT_DRAM_PHY_END    0xff320000
  43#define SST_BYT_IMR_VIRT_START  0xc0000000 /* virtual addr in LPE */
  44#define SST_BYT_IMR_VIRT_END    0xc01fffff
  45#define SST_BYT_SHIM_PHY_ADDR   0xff340000
  46#define SST_BYT_MBOX_PHY_ADDR   0xff344000
  47#define SST_BYT_DMA0_PHY_ADDR   0xff298000
  48#define SST_BYT_DMA1_PHY_ADDR   0xff29c000
  49#define SST_BYT_SSP0_PHY_ADDR   0xff2a0000
  50#define SST_BYT_SSP2_PHY_ADDR   0xff2a2000
  51
  52#define BYT_FW_MOD_TABLE_OFFSET 0x80000
  53#define BYT_FW_MOD_TABLE_SIZE   0x100
  54#define BYT_FW_MOD_OFFSET       (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE)
  55
  56static const struct sst_info byt_fwparse_info = {
  57        .use_elf        = false,
  58        .max_streams    = 25,
  59        .iram_start     = SST_BYT_IRAM_PHY_START,
  60        .iram_end       = SST_BYT_IRAM_PHY_END,
  61        .iram_use       = true,
  62        .dram_start     = SST_BYT_DRAM_PHY_START,
  63        .dram_end       = SST_BYT_DRAM_PHY_END,
  64        .dram_use       = true,
  65        .imr_start      = SST_BYT_IMR_VIRT_START,
  66        .imr_end        = SST_BYT_IMR_VIRT_END,
  67        .imr_use        = true,
  68        .mailbox_start  = SST_BYT_MBOX_PHY_ADDR,
  69        .num_probes     = 0,
  70        .lpe_viewpt_rqd  = true,
  71};
  72
  73static const struct sst_ipc_info byt_ipc_info = {
  74        .ipc_offset = 0,
  75        .mbox_recv_off = 0x400,
  76};
  77
  78static const struct sst_lib_dnld_info  byt_lib_dnld_info = {
  79        .mod_base           = SST_BYT_IMR_VIRT_START,
  80        .mod_end            = SST_BYT_IMR_VIRT_END,
  81        .mod_table_offset   = BYT_FW_MOD_TABLE_OFFSET,
  82        .mod_table_size     = BYT_FW_MOD_TABLE_SIZE,
  83        .mod_ddr_dnld       = false,
  84};
  85
  86static const struct sst_res_info byt_rvp_res_info = {
  87        .shim_offset = 0x140000,
  88        .shim_size = 0x000100,
  89        .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
  90        .ssp0_offset = 0xa0000,
  91        .ssp0_size = 0x1000,
  92        .dma0_offset = 0x98000,
  93        .dma0_size = 0x4000,
  94        .dma1_offset = 0x9c000,
  95        .dma1_size = 0x4000,
  96        .iram_offset = 0x0c0000,
  97        .iram_size = 0x14000,
  98        .dram_offset = 0x100000,
  99        .dram_size = 0x28000,
 100        .mbox_offset = 0x144000,
 101        .mbox_size = 0x1000,
 102        .acpi_lpe_res_index = 0,
 103        .acpi_ddr_index = 2,
 104        .acpi_ipc_irq_index = 5,
 105};
 106
 107/* BYTCR has different BIOS from BYT */
 108static const struct sst_res_info bytcr_res_info = {
 109        .shim_offset = 0x140000,
 110        .shim_size = 0x000100,
 111        .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
 112        .ssp0_offset = 0xa0000,
 113        .ssp0_size = 0x1000,
 114        .dma0_offset = 0x98000,
 115        .dma0_size = 0x4000,
 116        .dma1_offset = 0x9c000,
 117        .dma1_size = 0x4000,
 118        .iram_offset = 0x0c0000,
 119        .iram_size = 0x14000,
 120        .dram_offset = 0x100000,
 121        .dram_size = 0x28000,
 122        .mbox_offset = 0x144000,
 123        .mbox_size = 0x1000,
 124        .acpi_lpe_res_index = 0,
 125        .acpi_ddr_index = 2,
 126        .acpi_ipc_irq_index = 0
 127};
 128
 129static struct sst_platform_info byt_rvp_platform_data = {
 130        .probe_data = &byt_fwparse_info,
 131        .ipc_info = &byt_ipc_info,
 132        .lib_info = &byt_lib_dnld_info,
 133        .res_info = &byt_rvp_res_info,
 134        .platform = "sst-mfld-platform",
 135        .streams_lost_on_suspend = true,
 136};
 137
 138/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail,
 139 * so pdata is same as Baytrail, minus the streams_lost_on_suspend quirk.
 140 */
 141static struct sst_platform_info chv_platform_data = {
 142        .probe_data = &byt_fwparse_info,
 143        .ipc_info = &byt_ipc_info,
 144        .lib_info = &byt_lib_dnld_info,
 145        .res_info = &byt_rvp_res_info,
 146        .platform = "sst-mfld-platform",
 147};
 148
 149static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 150{
 151        struct resource *rsrc;
 152        struct platform_device *pdev = to_platform_device(ctx->dev);
 153
 154        /* All ACPI resource request here */
 155        /* Get Shim addr */
 156        rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
 157                                        ctx->pdata->res_info->acpi_lpe_res_index);
 158        if (!rsrc) {
 159                dev_err(ctx->dev, "Invalid SHIM base from IFWI\n");
 160                return -EIO;
 161        }
 162        dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
 163                                        (unsigned int)resource_size(rsrc));
 164
 165        ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset;
 166        ctx->iram_end =  ctx->iram_base + ctx->pdata->res_info->iram_size - 1;
 167        dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base);
 168        ctx->iram = devm_ioremap(ctx->dev, ctx->iram_base,
 169                                         ctx->pdata->res_info->iram_size);
 170        if (!ctx->iram) {
 171                dev_err(ctx->dev, "unable to map IRAM\n");
 172                return -EIO;
 173        }
 174
 175        ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset;
 176        ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1;
 177        dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base);
 178        ctx->dram = devm_ioremap(ctx->dev, ctx->dram_base,
 179                                         ctx->pdata->res_info->dram_size);
 180        if (!ctx->dram) {
 181                dev_err(ctx->dev, "unable to map DRAM\n");
 182                return -EIO;
 183        }
 184
 185        ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset;
 186        dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add);
 187        ctx->shim = devm_ioremap(ctx->dev, ctx->shim_phy_add,
 188                                        ctx->pdata->res_info->shim_size);
 189        if (!ctx->shim) {
 190                dev_err(ctx->dev, "unable to map SHIM\n");
 191                return -EIO;
 192        }
 193
 194        /* reassign physical address to LPE viewpoint address */
 195        ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr;
 196
 197        /* Get mailbox addr */
 198        ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset;
 199        dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add);
 200        ctx->mailbox = devm_ioremap(ctx->dev, ctx->mailbox_add,
 201                                            ctx->pdata->res_info->mbox_size);
 202        if (!ctx->mailbox) {
 203                dev_err(ctx->dev, "unable to map mailbox\n");
 204                return -EIO;
 205        }
 206
 207        /* reassign physical address to LPE viewpoint address */
 208        ctx->mailbox_add = ctx->info.mailbox_start;
 209
 210        rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
 211                                        ctx->pdata->res_info->acpi_ddr_index);
 212        if (!rsrc) {
 213                dev_err(ctx->dev, "Invalid DDR base from IFWI\n");
 214                return -EIO;
 215        }
 216        ctx->ddr_base = rsrc->start;
 217        ctx->ddr_end = rsrc->end;
 218        dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base);
 219        ctx->ddr = devm_ioremap(ctx->dev, ctx->ddr_base,
 220                                        resource_size(rsrc));
 221        if (!ctx->ddr) {
 222                dev_err(ctx->dev, "unable to map DDR\n");
 223                return -EIO;
 224        }
 225
 226        /* Find the IRQ */
 227        ctx->irq_num = platform_get_irq(pdev,
 228                                ctx->pdata->res_info->acpi_ipc_irq_index);
 229        if (ctx->irq_num <= 0)
 230                return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
 231
 232        return 0;
 233}
 234
 235static int sst_acpi_probe(struct platform_device *pdev)
 236{
 237        struct device *dev = &pdev->dev;
 238        int ret = 0;
 239        struct intel_sst_drv *ctx;
 240        const struct acpi_device_id *id;
 241        struct snd_soc_acpi_mach *mach;
 242        struct platform_device *mdev;
 243        struct platform_device *plat_dev;
 244        struct sst_platform_info *pdata;
 245        unsigned int dev_id;
 246
 247        id = acpi_match_device(dev->driver->acpi_match_table, dev);
 248        if (!id)
 249                return -ENODEV;
 250
 251        ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
 252        if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
 253                dev_dbg(dev, "SST ACPI driver not selected, aborting probe\n");
 254                return -ENODEV;
 255        }
 256
 257        dev_dbg(dev, "for %s\n", id->id);
 258
 259        mach = (struct snd_soc_acpi_mach *)id->driver_data;
 260        mach = snd_soc_acpi_find_machine(mach);
 261        if (mach == NULL) {
 262                dev_err(dev, "No matching machine driver found\n");
 263                return -ENODEV;
 264        }
 265
 266        if (soc_intel_is_byt())
 267                mach->pdata = &byt_rvp_platform_data;
 268        else
 269                mach->pdata = &chv_platform_data;
 270        pdata = mach->pdata;
 271
 272        ret = kstrtouint(id->id, 16, &dev_id);
 273        if (ret < 0) {
 274                dev_err(dev, "Unique device id conversion error: %d\n", ret);
 275                return ret;
 276        }
 277
 278        dev_dbg(dev, "ACPI device id: %x\n", dev_id);
 279
 280        ret = sst_alloc_drv_context(&ctx, dev, dev_id);
 281        if (ret < 0)
 282                return ret;
 283
 284        if (soc_intel_is_byt_cr(pdev)) {
 285                /* override resource info */
 286                byt_rvp_platform_data.res_info = &bytcr_res_info;
 287        }
 288
 289        /* update machine parameters */
 290        mach->mach_params.acpi_ipc_irq_index =
 291                pdata->res_info->acpi_ipc_irq_index;
 292
 293        plat_dev = platform_device_register_data(dev, pdata->platform, -1,
 294                                                NULL, 0);
 295        if (IS_ERR(plat_dev)) {
 296                dev_err(dev, "Failed to create machine device: %s\n",
 297                        pdata->platform);
 298                return PTR_ERR(plat_dev);
 299        }
 300
 301        /*
 302         * Create platform device for sst machine driver,
 303         * pass machine info as pdata
 304         */
 305        mdev = platform_device_register_data(dev, mach->drv_name, -1,
 306                                        (const void *)mach, sizeof(*mach));
 307        if (IS_ERR(mdev)) {
 308                dev_err(dev, "Failed to create machine device: %s\n",
 309                        mach->drv_name);
 310                return PTR_ERR(mdev);
 311        }
 312
 313        /* Fill sst platform data */
 314        ctx->pdata = pdata;
 315        strcpy(ctx->firmware_name, mach->fw_filename);
 316
 317        ret = sst_platform_get_resources(ctx);
 318        if (ret)
 319                return ret;
 320
 321        ret = sst_context_init(ctx);
 322        if (ret < 0)
 323                return ret;
 324
 325        sst_configure_runtime_pm(ctx);
 326        platform_set_drvdata(pdev, ctx);
 327        return ret;
 328}
 329
 330/**
 331* sst_acpi_remove - remove function
 332*
 333* @pdev:        platform device structure
 334*
 335* This function is called by OS when a device is unloaded
 336* This frees the interrupt etc
 337*/
 338static int sst_acpi_remove(struct platform_device *pdev)
 339{
 340        struct intel_sst_drv *ctx;
 341
 342        ctx = platform_get_drvdata(pdev);
 343        sst_context_cleanup(ctx);
 344        platform_set_drvdata(pdev, NULL);
 345        return 0;
 346}
 347
 348static const struct acpi_device_id sst_acpi_ids[] = {
 349        { "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
 350        { "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines},
 351        { },
 352};
 353
 354MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
 355
 356static struct platform_driver sst_acpi_driver = {
 357        .driver = {
 358                .name                   = "intel_sst_acpi",
 359                .acpi_match_table       = ACPI_PTR(sst_acpi_ids),
 360                .pm                     = &intel_sst_pm,
 361        },
 362        .probe  = sst_acpi_probe,
 363        .remove = sst_acpi_remove,
 364};
 365
 366module_platform_driver(sst_acpi_driver);
 367
 368MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver");
 369MODULE_AUTHOR("Ramesh Babu K V");
 370MODULE_AUTHOR("Omair Mohammed Abdullah");
 371MODULE_LICENSE("GPL v2");
 372MODULE_ALIAS("sst");
 373