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 = 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);
99do_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 */
111static 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
150do_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 */
164static 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 */
175static const struct pci_device_id intel_sst_ids[] = {
176	{ PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
177	{ 0, }
178};
179
180static 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
192module_pci_driver(sst_driver);
193
194MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
195MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
196MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
197MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
198MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
199MODULE_LICENSE("GPL v2");
200MODULE_ALIAS("sst");
201