1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * sst_pci.c - SST (LPE) driver init file for pci enumeration.
4 *
5 * Copyright (C) 2008-14 Intel Corp
6 * Authors: Vinod Koul <vinod.koul@intel.com>
7 * Harsha Priya <priya.harsha@intel.com>
8 * Dharageswari R <dharageswari.r@intel.com>
9 * KP Jeeja <jeeja.kp@intel.com>
10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 *
12 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13 */
14#include <linux/module.h>
15#include <linux/pci.h>
16#include <linux/fs.h>
17#include <linux/firmware.h>
18#include <sound/core.h>
19#include <sound/soc.h>
20#include <asm/platform_sst_audio.h>
21#include "../sst-mfld-platform.h"
22#include "sst.h"
23
24static int sst_platform_get_resources(struct intel_sst_drv *ctx)
25{
26 int ddr_base, ret = 0;
27 struct pci_dev *pci = ctx->pci;
28
29 ret = pcim_request_all_regions(pdev: pci, SST_DRV_NAME);
30 if (ret)
31 return ret;
32
33 /* map registers */
34 /* DDR base */
35 if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) {
36 ctx->ddr_base = pci_resource_start(pci, 0);
37 /* check that the relocated IMR base matches with FW Binary */
38 ddr_base = relocate_imr_addr_mrfld(base_addr: ctx->ddr_base);
39 if (!ctx->pdata->lib_info) {
40 dev_err(ctx->dev, "lib_info pointer NULL\n");
41 return -EINVAL;
42 }
43 if (ddr_base != ctx->pdata->lib_info->mod_base) {
44 dev_err(ctx->dev,
45 "FW LSP DDR BASE does not match with IFWI\n");
46 return -EINVAL;
47 }
48 ctx->ddr_end = pci_resource_end(pci, 0);
49
50 ctx->ddr = pcim_iomap(pdev: pci, bar: 0, maxlen: 0);
51 if (!ctx->ddr)
52 return -ENOMEM;
53
54 dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
55 } else {
56 ctx->ddr = NULL;
57 }
58 /* SHIM */
59 ctx->shim_phy_add = pci_resource_start(pci, 1);
60 ctx->shim = pcim_iomap(pdev: pci, bar: 1, maxlen: 0);
61 if (!ctx->shim)
62 return -ENOMEM;
63
64 dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
65
66 /* Shared SRAM */
67 ctx->mailbox_add = pci_resource_start(pci, 2);
68 ctx->mailbox = pcim_iomap(pdev: pci, bar: 2, maxlen: 0);
69 if (!ctx->mailbox)
70 return -ENOMEM;
71
72 dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
73
74 /* IRAM */
75 ctx->iram_end = pci_resource_end(pci, 3);
76 ctx->iram_base = pci_resource_start(pci, 3);
77 ctx->iram = pcim_iomap(pdev: pci, bar: 3, maxlen: 0);
78 if (!ctx->iram)
79 return -ENOMEM;
80
81 dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
82
83 /* DRAM */
84 ctx->dram_end = pci_resource_end(pci, 4);
85 ctx->dram_base = pci_resource_start(pci, 4);
86 ctx->dram = pcim_iomap(pdev: pci, bar: 4, maxlen: 0);
87 if (!ctx->dram)
88 return -ENOMEM;
89
90 dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
91 return 0;
92}
93
94/*
95 * intel_sst_probe - PCI probe function
96 *
97 * @pci: PCI device structure
98 * @pci_id: PCI device ID structure
99 *
100 */
101static int intel_sst_probe(struct pci_dev *pci,
102 const struct pci_device_id *pci_id)
103{
104 int ret = 0;
105 struct intel_sst_drv *sst_drv_ctx;
106 struct sst_platform_info *sst_pdata = pci->dev.platform_data;
107
108 dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
109 ret = sst_alloc_drv_context(ctx: &sst_drv_ctx, dev: &pci->dev, dev_id: pci->device);
110 if (ret < 0)
111 return ret;
112
113 sst_drv_ctx->pdata = sst_pdata;
114 sst_drv_ctx->irq_num = pci->irq;
115 snprintf(buf: sst_drv_ctx->firmware_name, size: sizeof(sst_drv_ctx->firmware_name),
116 fmt: "%s%04x%s", "fw_sst_",
117 sst_drv_ctx->dev_id, ".bin");
118
119 ret = sst_context_init(ctx: sst_drv_ctx);
120 if (ret < 0)
121 return ret;
122
123 /* Init the device */
124 ret = pcim_enable_device(pdev: pci);
125 if (ret) {
126 dev_err(sst_drv_ctx->dev,
127 "device can't be enabled. Returned err: %d\n", ret);
128 goto do_free_drv_ctx;
129 }
130 sst_drv_ctx->pci = pci_dev_get(dev: pci);
131 ret = sst_platform_get_resources(ctx: sst_drv_ctx);
132 if (ret < 0)
133 goto do_free_drv_ctx;
134
135 pci_set_drvdata(pdev: pci, data: sst_drv_ctx);
136 sst_configure_runtime_pm(ctx: sst_drv_ctx);
137
138 return ret;
139
140do_free_drv_ctx:
141 sst_context_cleanup(ctx: sst_drv_ctx);
142 dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
143 return ret;
144}
145
146/**
147 * intel_sst_remove - PCI remove function
148 *
149 * @pci: PCI device structure
150 *
151 * This function is called by OS when a device is unloaded
152 * This frees the interrupt etc
153 */
154static void intel_sst_remove(struct pci_dev *pci)
155{
156 struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pdev: pci);
157
158 sst_context_cleanup(ctx: sst_drv_ctx);
159 pci_dev_put(dev: sst_drv_ctx->pci);
160 pci_set_drvdata(pdev: pci, NULL);
161}
162
163/* PCI Routines */
164static const struct pci_device_id intel_sst_ids[] = {
165 { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
166 { 0, }
167};
168
169static struct pci_driver sst_driver = {
170 .name = SST_DRV_NAME,
171 .id_table = intel_sst_ids,
172 .probe = intel_sst_probe,
173 .remove = intel_sst_remove,
174#ifdef CONFIG_PM
175 .driver = {
176 .pm = &intel_sst_pm,
177 },
178#endif
179};
180
181module_pci_driver(sst_driver);
182
183MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
184MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
185MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
186MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
187MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
188MODULE_LICENSE("GPL v2");
189MODULE_ALIAS("sst");
190

source code of linux/sound/soc/intel/atom/sst/sst_pci.c