162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2018-2021 Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include <sound/soc-acpi.h>
1462306a36Sopenharmony_ci#include <sound/soc-acpi-intel-match.h>
1562306a36Sopenharmony_ci#include <sound/sof.h>
1662306a36Sopenharmony_ci#include "../ops.h"
1762306a36Sopenharmony_ci#include "atom.h"
1862306a36Sopenharmony_ci#include "../sof-pci-dev.h"
1962306a36Sopenharmony_ci#include "../sof-audio.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* platform specific devices */
2262306a36Sopenharmony_ci#include "shim.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic struct snd_soc_acpi_mach sof_tng_machines[] = {
2562306a36Sopenharmony_ci	{
2662306a36Sopenharmony_ci		.id = "INT343A",
2762306a36Sopenharmony_ci		.drv_name = "edison",
2862306a36Sopenharmony_ci		.sof_tplg_filename = "sof-byt.tplg",
2962306a36Sopenharmony_ci	},
3062306a36Sopenharmony_ci	{}
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic const struct snd_sof_debugfs_map tng_debugfs[] = {
3462306a36Sopenharmony_ci	{"dmac0", DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
3562306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
3662306a36Sopenharmony_ci	{"dmac1", DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
3762306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
3862306a36Sopenharmony_ci	{"ssp0", DSP_BAR, SSP0_OFFSET, SSP_SIZE,
3962306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
4062306a36Sopenharmony_ci	{"ssp1", DSP_BAR, SSP1_OFFSET, SSP_SIZE,
4162306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
4262306a36Sopenharmony_ci	{"ssp2", DSP_BAR, SSP2_OFFSET, SSP_SIZE,
4362306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
4462306a36Sopenharmony_ci	{"iram", DSP_BAR, IRAM_OFFSET, IRAM_SIZE,
4562306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_D0_ONLY},
4662306a36Sopenharmony_ci	{"dram", DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
4762306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_D0_ONLY},
4862306a36Sopenharmony_ci	{"shim", DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT,
4962306a36Sopenharmony_ci	 SOF_DEBUGFS_ACCESS_ALWAYS},
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int tangier_pci_probe(struct snd_sof_dev *sdev)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
5562306a36Sopenharmony_ci	const struct sof_dev_desc *desc = pdata->desc;
5662306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(sdev->dev);
5762306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
5862306a36Sopenharmony_ci	u32 base, size;
5962306a36Sopenharmony_ci	int ret;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
6262306a36Sopenharmony_ci	if (!chip) {
6362306a36Sopenharmony_ci		dev_err(sdev->dev, "error: no such device supported\n");
6462306a36Sopenharmony_ci		return -EIO;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	sdev->num_cores = chip->cores_num;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* DSP DMA can only access low 31 bits of host memory */
7062306a36Sopenharmony_ci	ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31));
7162306a36Sopenharmony_ci	if (ret < 0) {
7262306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret);
7362306a36Sopenharmony_ci		return ret;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* LPE base */
7762306a36Sopenharmony_ci	base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET;
7862306a36Sopenharmony_ci	size = PCI_BAR_SIZE;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
8162306a36Sopenharmony_ci	sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size);
8262306a36Sopenharmony_ci	if (!sdev->bar[DSP_BAR]) {
8362306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n",
8462306a36Sopenharmony_ci			base, size);
8562306a36Sopenharmony_ci		return -ENODEV;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[DSP_BAR]);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* IMR base - optional */
9062306a36Sopenharmony_ci	if (desc->resindex_imr_base == -1)
9162306a36Sopenharmony_ci		goto irq;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	base = pci_resource_start(pci, desc->resindex_imr_base);
9462306a36Sopenharmony_ci	size = pci_resource_len(pci, desc->resindex_imr_base);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* some BIOSes don't map IMR */
9762306a36Sopenharmony_ci	if (base == 0x55aa55aa || base == 0x0) {
9862306a36Sopenharmony_ci		dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n");
9962306a36Sopenharmony_ci		goto irq;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size);
10362306a36Sopenharmony_ci	sdev->bar[IMR_BAR] = devm_ioremap(sdev->dev, base, size);
10462306a36Sopenharmony_ci	if (!sdev->bar[IMR_BAR]) {
10562306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n",
10662306a36Sopenharmony_ci			base, size);
10762306a36Sopenharmony_ci		return -ENODEV;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[IMR_BAR]);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciirq:
11262306a36Sopenharmony_ci	/* register our IRQ */
11362306a36Sopenharmony_ci	sdev->ipc_irq = pci->irq;
11462306a36Sopenharmony_ci	dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
11562306a36Sopenharmony_ci	ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
11662306a36Sopenharmony_ci					atom_irq_handler, atom_irq_thread,
11762306a36Sopenharmony_ci					0, "AudioDSP", sdev);
11862306a36Sopenharmony_ci	if (ret < 0) {
11962306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to register IRQ %d\n",
12062306a36Sopenharmony_ci			sdev->ipc_irq);
12162306a36Sopenharmony_ci		return ret;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* enable BUSY and disable DONE Interrupt by default */
12562306a36Sopenharmony_ci	snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRX,
12662306a36Sopenharmony_ci				  SHIM_IMRX_BUSY | SHIM_IMRX_DONE,
12762306a36Sopenharmony_ci				  SHIM_IMRX_DONE);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* set default mailbox offset for FW ready message */
13062306a36Sopenharmony_ci	sdev->dsp_box.offset = MBOX_OFFSET;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return ret;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistruct snd_sof_dsp_ops sof_tng_ops = {
13662306a36Sopenharmony_ci	/* device init */
13762306a36Sopenharmony_ci	.probe		= tangier_pci_probe,
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* DSP core boot / reset */
14062306a36Sopenharmony_ci	.run		= atom_run,
14162306a36Sopenharmony_ci	.reset		= atom_reset,
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Register IO uses direct mmio */
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* Block IO */
14662306a36Sopenharmony_ci	.block_read	= sof_block_read,
14762306a36Sopenharmony_ci	.block_write	= sof_block_write,
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Mailbox IO */
15062306a36Sopenharmony_ci	.mailbox_read	= sof_mailbox_read,
15162306a36Sopenharmony_ci	.mailbox_write	= sof_mailbox_write,
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* doorbell */
15462306a36Sopenharmony_ci	.irq_handler	= atom_irq_handler,
15562306a36Sopenharmony_ci	.irq_thread	= atom_irq_thread,
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* ipc */
15862306a36Sopenharmony_ci	.send_msg	= atom_send_msg,
15962306a36Sopenharmony_ci	.get_mailbox_offset = atom_get_mailbox_offset,
16062306a36Sopenharmony_ci	.get_window_offset = atom_get_window_offset,
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	.ipc_msg_data	= sof_ipc_msg_data,
16362306a36Sopenharmony_ci	.set_stream_data_offset = sof_set_stream_data_offset,
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* machine driver */
16662306a36Sopenharmony_ci	.machine_select = atom_machine_select,
16762306a36Sopenharmony_ci	.machine_register = sof_machine_register,
16862306a36Sopenharmony_ci	.machine_unregister = sof_machine_unregister,
16962306a36Sopenharmony_ci	.set_mach_params = atom_set_mach_params,
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* debug */
17262306a36Sopenharmony_ci	.debug_map	= tng_debugfs,
17362306a36Sopenharmony_ci	.debug_map_count	= ARRAY_SIZE(tng_debugfs),
17462306a36Sopenharmony_ci	.dbg_dump	= atom_dump,
17562306a36Sopenharmony_ci	.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* stream callbacks */
17862306a36Sopenharmony_ci	.pcm_open	= sof_stream_pcm_open,
17962306a36Sopenharmony_ci	.pcm_close	= sof_stream_pcm_close,
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/*Firmware loading */
18262306a36Sopenharmony_ci	.load_firmware	= snd_sof_load_firmware_memcpy,
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* DAI drivers */
18562306a36Sopenharmony_ci	.drv = atom_dai,
18662306a36Sopenharmony_ci	.num_drv = 3, /* we have only 3 SSPs on byt*/
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* ALSA HW info flags */
18962306a36Sopenharmony_ci	.hw_info =	SNDRV_PCM_INFO_MMAP |
19062306a36Sopenharmony_ci			SNDRV_PCM_INFO_MMAP_VALID |
19162306a36Sopenharmony_ci			SNDRV_PCM_INFO_INTERLEAVED |
19262306a36Sopenharmony_ci			SNDRV_PCM_INFO_PAUSE |
19362306a36Sopenharmony_ci			SNDRV_PCM_INFO_BATCH,
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	.dsp_arch_ops = &sof_xtensa_arch_ops,
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciconst struct sof_intel_dsp_desc tng_chip_info = {
19962306a36Sopenharmony_ci	.cores_num = 1,
20062306a36Sopenharmony_ci	.host_managed_cores_mask = 1,
20162306a36Sopenharmony_ci	.hw_ip_version = SOF_INTEL_TANGIER,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const struct sof_dev_desc tng_desc = {
20562306a36Sopenharmony_ci	.machines		= sof_tng_machines,
20662306a36Sopenharmony_ci	.resindex_lpe_base	= 3,	/* IRAM, but subtract IRAM offset */
20762306a36Sopenharmony_ci	.resindex_pcicfg_base	= -1,
20862306a36Sopenharmony_ci	.resindex_imr_base	= 0,
20962306a36Sopenharmony_ci	.irqindex_host_ipc	= -1,
21062306a36Sopenharmony_ci	.chip_info = &tng_chip_info,
21162306a36Sopenharmony_ci	.ipc_supported_mask	= BIT(SOF_IPC),
21262306a36Sopenharmony_ci	.ipc_default		= SOF_IPC,
21362306a36Sopenharmony_ci	.default_fw_path = {
21462306a36Sopenharmony_ci		[SOF_IPC] = "intel/sof",
21562306a36Sopenharmony_ci	},
21662306a36Sopenharmony_ci	.default_tplg_path = {
21762306a36Sopenharmony_ci		[SOF_IPC] = "intel/sof-tplg",
21862306a36Sopenharmony_ci	},
21962306a36Sopenharmony_ci	.default_fw_filename = {
22062306a36Sopenharmony_ci		[SOF_IPC] = "sof-byt.ri",
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci	.nocodec_tplg_filename = "sof-byt.tplg",
22362306a36Sopenharmony_ci	.ops = &sof_tng_ops,
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/* PCI IDs */
22762306a36Sopenharmony_cistatic const struct pci_device_id sof_pci_ids[] = {
22862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) },
22962306a36Sopenharmony_ci	{ 0, }
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sof_pci_ids);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* pci_driver definition */
23462306a36Sopenharmony_cistatic struct pci_driver snd_sof_pci_intel_tng_driver = {
23562306a36Sopenharmony_ci	.name = "sof-audio-pci-intel-tng",
23662306a36Sopenharmony_ci	.id_table = sof_pci_ids,
23762306a36Sopenharmony_ci	.probe = sof_pci_probe,
23862306a36Sopenharmony_ci	.remove = sof_pci_remove,
23962306a36Sopenharmony_ci	.shutdown = sof_pci_shutdown,
24062306a36Sopenharmony_ci	.driver = {
24162306a36Sopenharmony_ci		.pm = &sof_pci_pm,
24262306a36Sopenharmony_ci	},
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_cimodule_pci_driver(snd_sof_pci_intel_tng_driver);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
24762306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
24862306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
24962306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
25062306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
251