162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Intel(R) Trace Hub pci driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014-2015 Intel Corporation.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/sysfs.h>
1462306a36Sopenharmony_ci#include <linux/pci.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "intel_th.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define DRIVER_NAME "intel_th_pci"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cienum {
2162306a36Sopenharmony_ci	TH_PCI_CONFIG_BAR	= 0,
2262306a36Sopenharmony_ci	TH_PCI_STH_SW_BAR	= 2,
2362306a36Sopenharmony_ci	TH_PCI_RTIT_BAR		= 4,
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define BAR_MASK (BIT(TH_PCI_CONFIG_BAR) | BIT(TH_PCI_STH_SW_BAR))
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define PCI_REG_NPKDSC	0x80
2962306a36Sopenharmony_ci#define NPKDSC_TSACT	BIT(5)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int intel_th_pci_activate(struct intel_th *th)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(th->dev);
3462306a36Sopenharmony_ci	u32 npkdsc;
3562306a36Sopenharmony_ci	int err;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (!INTEL_TH_CAP(th, tscu_enable))
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc);
4162306a36Sopenharmony_ci	if (!err) {
4262306a36Sopenharmony_ci		npkdsc |= NPKDSC_TSACT;
4362306a36Sopenharmony_ci		err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc);
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (err)
4762306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to read NPKDSC register\n");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return err;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void intel_th_pci_deactivate(struct intel_th *th)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(th->dev);
5562306a36Sopenharmony_ci	u32 npkdsc;
5662306a36Sopenharmony_ci	int err;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!INTEL_TH_CAP(th, tscu_enable))
5962306a36Sopenharmony_ci		return;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc);
6262306a36Sopenharmony_ci	if (!err) {
6362306a36Sopenharmony_ci		npkdsc |= NPKDSC_TSACT;
6462306a36Sopenharmony_ci		err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc);
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (err)
6862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to read NPKDSC register\n");
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int intel_th_pci_probe(struct pci_dev *pdev,
7262306a36Sopenharmony_ci			      const struct pci_device_id *id)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	const struct intel_th_drvdata *drvdata = (void *)id->driver_data;
7562306a36Sopenharmony_ci	struct resource resource[TH_MMIO_END + TH_NVEC_MAX] = {
7662306a36Sopenharmony_ci		[TH_MMIO_CONFIG]	= pdev->resource[TH_PCI_CONFIG_BAR],
7762306a36Sopenharmony_ci		[TH_MMIO_SW]		= pdev->resource[TH_PCI_STH_SW_BAR],
7862306a36Sopenharmony_ci	};
7962306a36Sopenharmony_ci	int err, r = TH_MMIO_SW + 1, i;
8062306a36Sopenharmony_ci	struct intel_th *th;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	err = pcim_enable_device(pdev);
8362306a36Sopenharmony_ci	if (err)
8462306a36Sopenharmony_ci		return err;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	err = pcim_iomap_regions_request_all(pdev, BAR_MASK, DRIVER_NAME);
8762306a36Sopenharmony_ci	if (err)
8862306a36Sopenharmony_ci		return err;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (pdev->resource[TH_PCI_RTIT_BAR].start) {
9162306a36Sopenharmony_ci		resource[TH_MMIO_RTIT] = pdev->resource[TH_PCI_RTIT_BAR];
9262306a36Sopenharmony_ci		r++;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	err = pci_alloc_irq_vectors(pdev, 1, 8, PCI_IRQ_ALL_TYPES);
9662306a36Sopenharmony_ci	if (err > 0)
9762306a36Sopenharmony_ci		for (i = 0; i < err; i++, r++) {
9862306a36Sopenharmony_ci			resource[r].flags = IORESOURCE_IRQ;
9962306a36Sopenharmony_ci			resource[r].start = pci_irq_vector(pdev, i);
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	th = intel_th_alloc(&pdev->dev, drvdata, resource, r);
10362306a36Sopenharmony_ci	if (IS_ERR(th)) {
10462306a36Sopenharmony_ci		err = PTR_ERR(th);
10562306a36Sopenharmony_ci		goto err_free_irq;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	th->activate   = intel_th_pci_activate;
10962306a36Sopenharmony_ci	th->deactivate = intel_th_pci_deactivate;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	pci_set_master(pdev);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cierr_free_irq:
11662306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
11762306a36Sopenharmony_ci	return err;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void intel_th_pci_remove(struct pci_dev *pdev)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct intel_th *th = pci_get_drvdata(pdev);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	intel_th_free(th);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic const struct intel_th_drvdata intel_th_1x_multi_is_broken = {
13062306a36Sopenharmony_ci	.multi_is_broken	= 1,
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic const struct intel_th_drvdata intel_th_2x = {
13462306a36Sopenharmony_ci	.tscu_enable	= 1,
13562306a36Sopenharmony_ci	.has_mintctl	= 1,
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic const struct pci_device_id intel_th_pci_id_table[] = {
13962306a36Sopenharmony_ci	{
14062306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d26),
14162306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
14262306a36Sopenharmony_ci	},
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa126),
14562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
14662306a36Sopenharmony_ci	},
14762306a36Sopenharmony_ci	{
14862306a36Sopenharmony_ci		/* Apollo Lake */
14962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a8e),
15062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	{
15362306a36Sopenharmony_ci		/* Broxton */
15462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
15562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
15662306a36Sopenharmony_ci	},
15762306a36Sopenharmony_ci	{
15862306a36Sopenharmony_ci		/* Broxton B-step */
15962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
16062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
16162306a36Sopenharmony_ci	},
16262306a36Sopenharmony_ci	{
16362306a36Sopenharmony_ci		/* Kaby Lake PCH-H */
16462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
16562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
16662306a36Sopenharmony_ci	},
16762306a36Sopenharmony_ci	{
16862306a36Sopenharmony_ci		/* Denverton */
16962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x19e1),
17062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
17162306a36Sopenharmony_ci	},
17262306a36Sopenharmony_ci	{
17362306a36Sopenharmony_ci		/* Lewisburg PCH */
17462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1a6),
17562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
17662306a36Sopenharmony_ci	},
17762306a36Sopenharmony_ci	{
17862306a36Sopenharmony_ci		/* Lewisburg PCH */
17962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa226),
18062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)0,
18162306a36Sopenharmony_ci	},
18262306a36Sopenharmony_ci	{
18362306a36Sopenharmony_ci		/* Gemini Lake */
18462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e),
18562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
18662306a36Sopenharmony_ci	},
18762306a36Sopenharmony_ci	{
18862306a36Sopenharmony_ci		/* Cannon Lake H */
18962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326),
19062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
19162306a36Sopenharmony_ci	},
19262306a36Sopenharmony_ci	{
19362306a36Sopenharmony_ci		/* Cannon Lake LP */
19462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6),
19562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci	{
19862306a36Sopenharmony_ci		/* Cedar Fork PCH */
19962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x18e1),
20062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
20162306a36Sopenharmony_ci	},
20262306a36Sopenharmony_ci	{
20362306a36Sopenharmony_ci		/* Ice Lake PCH */
20462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x34a6),
20562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
20662306a36Sopenharmony_ci	},
20762306a36Sopenharmony_ci	{
20862306a36Sopenharmony_ci		/* Comet Lake */
20962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a6),
21062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
21162306a36Sopenharmony_ci	},
21262306a36Sopenharmony_ci	{
21362306a36Sopenharmony_ci		/* Comet Lake PCH */
21462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x06a6),
21562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
21662306a36Sopenharmony_ci	},
21762306a36Sopenharmony_ci	{
21862306a36Sopenharmony_ci		/* Comet Lake PCH-V */
21962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa3a6),
22062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_1x_multi_is_broken,
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci	{
22362306a36Sopenharmony_ci		/* Ice Lake NNPI */
22462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
22562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
22662306a36Sopenharmony_ci	},
22762306a36Sopenharmony_ci	{
22862306a36Sopenharmony_ci		/* Ice Lake CPU */
22962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8a29),
23062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
23162306a36Sopenharmony_ci	},
23262306a36Sopenharmony_ci	{
23362306a36Sopenharmony_ci		/* Tiger Lake CPU */
23462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9a33),
23562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
23662306a36Sopenharmony_ci	},
23762306a36Sopenharmony_ci	{
23862306a36Sopenharmony_ci		/* Tiger Lake PCH */
23962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa0a6),
24062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
24162306a36Sopenharmony_ci	},
24262306a36Sopenharmony_ci	{
24362306a36Sopenharmony_ci		/* Tiger Lake PCH-H */
24462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x43a6),
24562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
24662306a36Sopenharmony_ci	},
24762306a36Sopenharmony_ci	{
24862306a36Sopenharmony_ci		/* Jasper Lake PCH */
24962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6),
25062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci	{
25362306a36Sopenharmony_ci		/* Jasper Lake CPU */
25462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4e29),
25562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	{
25862306a36Sopenharmony_ci		/* Elkhart Lake CPU */
25962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4529),
26062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci	{
26362306a36Sopenharmony_ci		/* Elkhart Lake */
26462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26),
26562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
26662306a36Sopenharmony_ci	},
26762306a36Sopenharmony_ci	{
26862306a36Sopenharmony_ci		/* Emmitsburg PCH */
26962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1bcc),
27062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
27162306a36Sopenharmony_ci	},
27262306a36Sopenharmony_ci	{
27362306a36Sopenharmony_ci		/* Alder Lake */
27462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7aa6),
27562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
27662306a36Sopenharmony_ci	},
27762306a36Sopenharmony_ci	{
27862306a36Sopenharmony_ci		/* Alder Lake-P */
27962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6),
28062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
28162306a36Sopenharmony_ci	},
28262306a36Sopenharmony_ci	{
28362306a36Sopenharmony_ci		/* Alder Lake-M */
28462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x54a6),
28562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
28662306a36Sopenharmony_ci	},
28762306a36Sopenharmony_ci	{
28862306a36Sopenharmony_ci		/* Meteor Lake-P */
28962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7e24),
29062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci	{
29362306a36Sopenharmony_ci		/* Raptor Lake-S */
29462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7a26),
29562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
29662306a36Sopenharmony_ci	},
29762306a36Sopenharmony_ci	{
29862306a36Sopenharmony_ci		/* Raptor Lake-S CPU */
29962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa76f),
30062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
30162306a36Sopenharmony_ci	},
30262306a36Sopenharmony_ci	{
30362306a36Sopenharmony_ci		/* Alder Lake CPU */
30462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f),
30562306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
30662306a36Sopenharmony_ci	},
30762306a36Sopenharmony_ci	{
30862306a36Sopenharmony_ci		/* Rocket Lake CPU */
30962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c19),
31062306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&intel_th_2x,
31162306a36Sopenharmony_ci	},
31262306a36Sopenharmony_ci	{ 0 },
31362306a36Sopenharmony_ci};
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, intel_th_pci_id_table);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic struct pci_driver intel_th_pci_driver = {
31862306a36Sopenharmony_ci	.name		= DRIVER_NAME,
31962306a36Sopenharmony_ci	.id_table	= intel_th_pci_id_table,
32062306a36Sopenharmony_ci	.probe		= intel_th_pci_probe,
32162306a36Sopenharmony_ci	.remove		= intel_th_pci_remove,
32262306a36Sopenharmony_ci};
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cimodule_pci_driver(intel_th_pci_driver);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
32762306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel(R) Trace Hub PCI controller driver");
32862306a36Sopenharmony_ciMODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");
329