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