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