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