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
sst_platform_get_resources(struct intel_sst_drv * ctx)24 static 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 = pci_request_regions(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(ctx->ddr_base);
39 if (!ctx->pdata->lib_info) {
40 dev_err(ctx->dev, "lib_info pointer NULL\n");
41 ret = -EINVAL;
42 goto do_release_regions;
43 }
44 if (ddr_base != ctx->pdata->lib_info->mod_base) {
45 dev_err(ctx->dev,
46 "FW LSP DDR BASE does not match with IFWI\n");
47 ret = -EINVAL;
48 goto do_release_regions;
49 }
50 ctx->ddr_end = pci_resource_end(pci, 0);
51
52 ctx->ddr = pcim_iomap(pci, 0,
53 pci_resource_len(pci, 0));
54 if (!ctx->ddr) {
55 ret = -EINVAL;
56 goto do_release_regions;
57 }
58 dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
59 } else {
60 ctx->ddr = NULL;
61 }
62 /* SHIM */
63 ctx->shim_phy_add = pci_resource_start(pci, 1);
64 ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
65 if (!ctx->shim) {
66 ret = -EINVAL;
67 goto do_release_regions;
68 }
69 dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
70
71 /* Shared SRAM */
72 ctx->mailbox_add = pci_resource_start(pci, 2);
73 ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
74 if (!ctx->mailbox) {
75 ret = -EINVAL;
76 goto do_release_regions;
77 }
78 dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
79
80 /* IRAM */
81 ctx->iram_end = pci_resource_end(pci, 3);
82 ctx->iram_base = pci_resource_start(pci, 3);
83 ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
84 if (!ctx->iram) {
85 ret = -EINVAL;
86 goto do_release_regions;
87 }
88 dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
89
90 /* DRAM */
91 ctx->dram_end = pci_resource_end(pci, 4);
92 ctx->dram_base = pci_resource_start(pci, 4);
93 ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
94 if (!ctx->dram) {
95 ret = -EINVAL;
96 goto do_release_regions;
97 }
98 dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
99 do_release_regions:
100 pci_release_regions(pci);
101 return ret;
102 }
103
104 /*
105 * intel_sst_probe - PCI probe function
106 *
107 * @pci: PCI device structure
108 * @pci_id: PCI device ID structure
109 *
110 */
intel_sst_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)111 static int intel_sst_probe(struct pci_dev *pci,
112 const struct pci_device_id *pci_id)
113 {
114 int ret = 0;
115 struct intel_sst_drv *sst_drv_ctx;
116 struct sst_platform_info *sst_pdata = pci->dev.platform_data;
117
118 dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
119 ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device);
120 if (ret < 0)
121 return ret;
122
123 sst_drv_ctx->pdata = sst_pdata;
124 sst_drv_ctx->irq_num = pci->irq;
125 snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
126 "%s%04x%s", "fw_sst_",
127 sst_drv_ctx->dev_id, ".bin");
128
129 ret = sst_context_init(sst_drv_ctx);
130 if (ret < 0)
131 return ret;
132
133 /* Init the device */
134 ret = pcim_enable_device(pci);
135 if (ret) {
136 dev_err(sst_drv_ctx->dev,
137 "device can't be enabled. Returned err: %d\n", ret);
138 goto do_free_drv_ctx;
139 }
140 sst_drv_ctx->pci = pci_dev_get(pci);
141 ret = sst_platform_get_resources(sst_drv_ctx);
142 if (ret < 0)
143 goto do_free_drv_ctx;
144
145 pci_set_drvdata(pci, sst_drv_ctx);
146 sst_configure_runtime_pm(sst_drv_ctx);
147
148 return ret;
149
150 do_free_drv_ctx:
151 sst_context_cleanup(sst_drv_ctx);
152 dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
153 return ret;
154 }
155
156 /**
157 * intel_sst_remove - PCI remove function
158 *
159 * @pci: PCI device structure
160 *
161 * This function is called by OS when a device is unloaded
162 * This frees the interrupt etc
163 */
intel_sst_remove(struct pci_dev * pci)164 static void intel_sst_remove(struct pci_dev *pci)
165 {
166 struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
167
168 sst_context_cleanup(sst_drv_ctx);
169 pci_dev_put(sst_drv_ctx->pci);
170 pci_release_regions(pci);
171 pci_set_drvdata(pci, NULL);
172 }
173
174 /* PCI Routines */
175 static const struct pci_device_id intel_sst_ids[] = {
176 { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
177 { 0, }
178 };
179
180 static struct pci_driver sst_driver = {
181 .name = SST_DRV_NAME,
182 .id_table = intel_sst_ids,
183 .probe = intel_sst_probe,
184 .remove = intel_sst_remove,
185 #ifdef CONFIG_PM
186 .driver = {
187 .pm = &intel_sst_pm,
188 },
189 #endif
190 };
191
192 module_pci_driver(sst_driver);
193
194 MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
195 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
196 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
197 MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
198 MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
199 MODULE_LICENSE("GPL v2");
200 MODULE_ALIAS("sst");
201