mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
Adjust all AMD audio drivers to use AMD_NODE
Merge series from Mario Limonciello <superm1@kernel.org>: The various AMD audio drivers have self contained implementations for SMN router communication that require hardcoding the bridge ID. These implementations also don't prevent race conditions with other drivers performing SMN communication. A new centralized driver AMD_NODE is introduced and all drivers in the kernel should use this instead. Adjust all AMD audio drivers to use it.
This commit is contained in:
commit
67ebf71236
|
|
@ -142,7 +142,7 @@ static __always_inline int syscall_32_enter(struct pt_regs *regs)
|
|||
#ifdef CONFIG_IA32_EMULATION
|
||||
bool __ia32_enabled __ro_after_init = !IS_ENABLED(CONFIG_IA32_EMULATION_DEFAULT_DISABLED);
|
||||
|
||||
static int ia32_emulation_override_cmdline(char *arg)
|
||||
static int __init ia32_emulation_override_cmdline(char *arg)
|
||||
{
|
||||
return kstrtobool(arg, &__ia32_enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ struct amd_l3_cache {
|
|||
};
|
||||
|
||||
struct amd_northbridge {
|
||||
struct pci_dev *root;
|
||||
struct pci_dev *misc;
|
||||
struct pci_dev *link;
|
||||
struct amd_l3_cache l3_cache;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,31 @@ static inline u16 amd_num_nodes(void)
|
|||
return topology_amd_nodes_per_pkg() * topology_max_packages();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMD_NODE
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value);
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value);
|
||||
|
||||
/* Should only be used by the HSMP driver. */
|
||||
int __must_check amd_smn_hsmp_rdwr(u16 node, u32 address, u32 *value, bool write);
|
||||
#else
|
||||
static inline int __must_check amd_smn_read(u16 node, u32 address, u32 *value) { return -ENODEV; }
|
||||
static inline int __must_check amd_smn_write(u16 node, u32 address, u32 value) { return -ENODEV; }
|
||||
|
||||
static inline int __must_check amd_smn_hsmp_rdwr(u16 node, u32 address, u32 *value, bool write)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_AMD_NODE */
|
||||
|
||||
/* helper for use with read_poll_timeout */
|
||||
static inline int smn_read_register(u32 reg)
|
||||
{
|
||||
int data, rc;
|
||||
|
||||
rc = amd_smn_read(0, reg, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return data;
|
||||
}
|
||||
#endif /*_ASM_X86_AMD_NODE_H_*/
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ static int amd_cache_northbridges(void)
|
|||
amd_northbridges.nb = nb;
|
||||
|
||||
for (i = 0; i < amd_northbridges.num; i++) {
|
||||
node_to_amd_nb(i)->root = amd_node_get_root(i);
|
||||
node_to_amd_nb(i)->misc = amd_node_get_func(i, 3);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
/*
|
||||
|
|
@ -93,10 +94,14 @@ static struct pci_dev **amd_roots;
|
|||
|
||||
/* Protect the PCI config register pairs used for SMN. */
|
||||
static DEFINE_MUTEX(smn_mutex);
|
||||
static bool smn_exclusive;
|
||||
|
||||
#define SMN_INDEX_OFFSET 0x60
|
||||
#define SMN_DATA_OFFSET 0x64
|
||||
|
||||
#define HSMP_INDEX_OFFSET 0xc4
|
||||
#define HSMP_DATA_OFFSET 0xc8
|
||||
|
||||
/*
|
||||
* SMN accesses may fail in ways that are difficult to detect here in the called
|
||||
* functions amd_smn_read() and amd_smn_write(). Therefore, callers must do
|
||||
|
|
@ -146,6 +151,9 @@ static int __amd_smn_rw(u8 i_off, u8 d_off, u16 node, u32 address, u32 *value, b
|
|||
if (!root)
|
||||
return err;
|
||||
|
||||
if (!smn_exclusive)
|
||||
return err;
|
||||
|
||||
guard(mutex)(&smn_mutex);
|
||||
|
||||
err = pci_write_config_dword(root, i_off, address);
|
||||
|
|
@ -179,6 +187,93 @@ int __must_check amd_smn_write(u16 node, u32 address, u32 value)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_write);
|
||||
|
||||
int __must_check amd_smn_hsmp_rdwr(u16 node, u32 address, u32 *value, bool write)
|
||||
{
|
||||
return __amd_smn_rw(HSMP_INDEX_OFFSET, HSMP_DATA_OFFSET, node, address, value, write);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_hsmp_rdwr);
|
||||
|
||||
static struct dentry *debugfs_dir;
|
||||
static u16 debug_node;
|
||||
static u32 debug_address;
|
||||
|
||||
static ssize_t smn_node_write(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u16 node;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou16_from_user(userbuf, count, 0, &node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (node >= amd_num_nodes())
|
||||
return -ENODEV;
|
||||
|
||||
debug_node = node;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int smn_node_show(struct seq_file *m, void *v)
|
||||
{
|
||||
seq_printf(m, "0x%08x\n", debug_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t smn_address_write(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint_from_user(userbuf, count, 0, &debug_address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int smn_address_show(struct seq_file *m, void *v)
|
||||
{
|
||||
seq_printf(m, "0x%08x\n", debug_address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smn_value_show(struct seq_file *m, void *v)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = amd_smn_read(debug_node, debug_address, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq_printf(m, "0x%08x\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t smn_value_write(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint_from_user(userbuf, count, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
|
||||
|
||||
ret = amd_smn_write(debug_node, debug_address, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(smn_node);
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(smn_address);
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(smn_value);
|
||||
|
||||
static int amd_cache_roots(void)
|
||||
{
|
||||
u16 node, num_nodes = amd_num_nodes();
|
||||
|
|
@ -193,6 +288,48 @@ static int amd_cache_roots(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int reserve_root_config_spaces(void)
|
||||
{
|
||||
struct pci_dev *root = NULL;
|
||||
struct pci_bus *bus = NULL;
|
||||
|
||||
while ((bus = pci_find_next_bus(bus))) {
|
||||
/* Root device is Device 0 Function 0 on each Primary Bus. */
|
||||
root = pci_get_slot(bus, 0);
|
||||
if (!root)
|
||||
continue;
|
||||
|
||||
if (root->vendor != PCI_VENDOR_ID_AMD &&
|
||||
root->vendor != PCI_VENDOR_ID_HYGON)
|
||||
continue;
|
||||
|
||||
pci_dbg(root, "Reserving PCI config space\n");
|
||||
|
||||
/*
|
||||
* There are a few SMN index/data pairs and other registers
|
||||
* that shouldn't be accessed by user space.
|
||||
* So reserve the entire PCI config space for simplicity rather
|
||||
* than covering specific registers piecemeal.
|
||||
*/
|
||||
if (!pci_request_config_region_exclusive(root, 0, PCI_CFG_SPACE_SIZE, NULL)) {
|
||||
pci_err(root, "Failed to reserve config space\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
smn_exclusive = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool enable_dfs;
|
||||
|
||||
static int __init amd_smn_enable_dfs(char *str)
|
||||
{
|
||||
enable_dfs = true;
|
||||
return 1;
|
||||
}
|
||||
__setup("amd_smn_debugfs_enable", amd_smn_enable_dfs);
|
||||
|
||||
static int __init amd_smn_init(void)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -209,6 +346,18 @@ static int __init amd_smn_init(void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = reserve_root_config_spaces();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (enable_dfs) {
|
||||
debugfs_dir = debugfs_create_dir("amd_smn", arch_debugfs_dir);
|
||||
|
||||
debugfs_create_file("node", 0600, debugfs_dir, NULL, &smn_node_fops);
|
||||
debugfs_create_file("address", 0600, debugfs_dir, NULL, &smn_address_fops);
|
||||
debugfs_create_file("value", 0600, debugfs_dir, NULL, &smn_value_fops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cc_platform.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/cacheinfo.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
|
@ -646,10 +647,10 @@ static void __init print_mtrr_state(void)
|
|||
pr_info("MTRR default type: %s\n",
|
||||
mtrr_attrib_to_str(mtrr_state.def_type));
|
||||
if (mtrr_state.have_fixed) {
|
||||
pr_info("MTRR fixed ranges %sabled:\n",
|
||||
((mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) ?
|
||||
"en" : "dis");
|
||||
pr_info("MTRR fixed ranges %s:\n",
|
||||
str_enabled_disabled(
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)));
|
||||
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
|
||||
for (i = 0; i < 2; ++i)
|
||||
print_fixed(0x80000 + i * 0x20000, 0x04000,
|
||||
|
|
@ -661,8 +662,8 @@ static void __init print_mtrr_state(void)
|
|||
/* tail */
|
||||
print_fixed_last();
|
||||
}
|
||||
pr_info("MTRR variable ranges %sabled:\n",
|
||||
mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED ? "en" : "dis");
|
||||
pr_info("MTRR variable ranges %s:\n",
|
||||
str_enabled_disabled(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED));
|
||||
high_width = (boot_cpu_data.x86_phys_bits - (32 - PAGE_SHIFT) + 3) / 4;
|
||||
|
||||
for (i = 0; i < num_var_ranges; ++i) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ config AMD_HSMP
|
|||
tristate
|
||||
|
||||
menu "AMD HSMP Driver"
|
||||
depends on AMD_NB || COMPILE_TEST
|
||||
depends on AMD_NODE || COMPILE_TEST
|
||||
|
||||
config AMD_HSMP_ACPI
|
||||
tristate "AMD HSMP ACPI device driver"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -24,6 +23,8 @@
|
|||
|
||||
#include <uapi/asm-generic/errno-base.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "hsmp.h"
|
||||
|
||||
#define DRIVER_NAME "amd_hsmp"
|
||||
|
|
@ -321,8 +322,8 @@ static int hsmp_acpi_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
if (!hsmp_pdev->is_probed) {
|
||||
hsmp_pdev->num_sockets = amd_nb_num();
|
||||
if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_SOCKETS)
|
||||
hsmp_pdev->num_sockets = amd_num_nodes();
|
||||
if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_NUM_NODES)
|
||||
return -ENODEV;
|
||||
|
||||
hsmp_pdev->sock = devm_kcalloc(&pdev->dev, hsmp_pdev->num_sockets,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#define HSMP_ATTR_GRP_NAME_SIZE 10
|
||||
|
||||
#define MAX_AMD_SOCKETS 8
|
||||
|
||||
#define HSMP_CDEV_NAME "hsmp_cdev"
|
||||
#define HSMP_DEVNODE_NAME "hsmp"
|
||||
|
||||
|
|
@ -41,7 +39,6 @@ struct hsmp_socket {
|
|||
void __iomem *virt_base_addr;
|
||||
struct semaphore hsmp_sem;
|
||||
char name[HSMP_ATTR_GRP_NAME_SIZE];
|
||||
struct pci_dev *root;
|
||||
struct device *dev;
|
||||
u16 sock_ind;
|
||||
int (*amd_hsmp_rdwr)(struct hsmp_socket *sock, u32 off, u32 *val, bool rw);
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "hsmp.h"
|
||||
|
||||
#define DRIVER_NAME "amd_hsmp"
|
||||
|
|
@ -34,28 +36,12 @@
|
|||
#define SMN_HSMP_MSG_RESP 0x0010980
|
||||
#define SMN_HSMP_MSG_DATA 0x00109E0
|
||||
|
||||
#define HSMP_INDEX_REG 0xc4
|
||||
#define HSMP_DATA_REG 0xc8
|
||||
|
||||
static struct hsmp_plat_device *hsmp_pdev;
|
||||
|
||||
static int amd_hsmp_pci_rdwr(struct hsmp_socket *sock, u32 offset,
|
||||
u32 *value, bool write)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sock->root)
|
||||
return -ENODEV;
|
||||
|
||||
ret = pci_write_config_dword(sock->root, HSMP_INDEX_REG,
|
||||
sock->mbinfo.base_addr + offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = (write ? pci_write_config_dword(sock->root, HSMP_DATA_REG, *value)
|
||||
: pci_read_config_dword(sock->root, HSMP_DATA_REG, value));
|
||||
|
||||
return ret;
|
||||
return amd_smn_hsmp_rdwr(sock->sock_ind, sock->mbinfo.base_addr + offset, value, write);
|
||||
}
|
||||
|
||||
static ssize_t hsmp_metric_tbl_plat_read(struct file *filp, struct kobject *kobj,
|
||||
|
|
@ -95,7 +81,12 @@ static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
|
|||
* Static array of 8 + 1(for NULL) elements is created below
|
||||
* to create sysfs groups for sockets.
|
||||
* is_bin_visible function is used to show / hide the necessary groups.
|
||||
*
|
||||
* Validate the maximum number against MAX_AMD_NUM_NODES. If this changes,
|
||||
* then the attributes and groups below must be adjusted.
|
||||
*/
|
||||
static_assert(MAX_AMD_NUM_NODES == 8);
|
||||
|
||||
#define HSMP_BIN_ATTR(index, _list) \
|
||||
static const struct bin_attribute attr##index = { \
|
||||
.attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444}, \
|
||||
|
|
@ -159,10 +150,7 @@ static int init_platform_device(struct device *dev)
|
|||
int ret, i;
|
||||
|
||||
for (i = 0; i < hsmp_pdev->num_sockets; i++) {
|
||||
if (!node_to_amd_nb(i))
|
||||
return -ENODEV;
|
||||
sock = &hsmp_pdev->sock[i];
|
||||
sock->root = node_to_amd_nb(i)->root;
|
||||
sock->sock_ind = i;
|
||||
sock->dev = dev;
|
||||
sock->mbinfo.base_addr = SMN_HSMP_BASE;
|
||||
|
|
@ -305,11 +293,11 @@ static int __init hsmp_plt_init(void)
|
|||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* amd_nb_num() returns number of SMN/DF interfaces present in the system
|
||||
* amd_num_nodes() returns number of SMN/DF interfaces present in the system
|
||||
* if we have N SMN/DF interfaces that ideally means N sockets
|
||||
*/
|
||||
hsmp_pdev->num_sockets = amd_nb_num();
|
||||
if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_SOCKETS)
|
||||
hsmp_pdev->num_sockets = amd_num_nodes();
|
||||
if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_NUM_NODES)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&amd_hsmp_driver);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ config SND_AMD_ASOC_REMBRANDT
|
|||
select SND_SOC_AMD_ACP_I2S
|
||||
select SND_SOC_AMD_ACP_PDM
|
||||
select SND_SOC_AMD_ACP_LEGACY_COMMON
|
||||
depends on AMD_NODE
|
||||
depends on X86 && PCI
|
||||
help
|
||||
This option enables Rembrandt I2S support on AMD platform.
|
||||
|
|
@ -68,6 +69,7 @@ config SND_AMD_ASOC_ACP63
|
|||
tristate "AMD ACP ASOC ACP6.3 Support"
|
||||
depends on X86 && PCI
|
||||
depends on ACPI
|
||||
depends on AMD_NODE
|
||||
select SND_SOC_AMD_ACP_PCM
|
||||
select SND_SOC_AMD_ACP_I2S
|
||||
select SND_SOC_AMD_ACP_PDM
|
||||
|
|
@ -81,6 +83,7 @@ config SND_AMD_ASOC_ACP70
|
|||
tristate "AMD ACP ASOC Acp7.0 Support"
|
||||
depends on X86 && PCI
|
||||
depends on ACPI
|
||||
depends on AMD_NODE
|
||||
select SND_SOC_AMD_ACP_PCM
|
||||
select SND_SOC_AMD_ACP_I2S
|
||||
select SND_SOC_AMD_ACP_PDM
|
||||
|
|
|
|||
|
|
@ -345,24 +345,6 @@ int acp_deinit(struct acp_chip_info *chip)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON");
|
||||
|
||||
int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
|
||||
{
|
||||
pci_write_config_dword(dev, 0x60, smn_addr);
|
||||
pci_write_config_dword(dev, 0x64, data);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(smn_write, "SND_SOC_ACP_COMMON");
|
||||
|
||||
int smn_read(struct pci_dev *dev, u32 smn_addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
pci_write_config_dword(dev, 0x60, smn_addr);
|
||||
pci_read_config_dword(dev, 0x64, &data);
|
||||
return data;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(smn_read, "SND_SOC_ACP_COMMON");
|
||||
|
||||
static void check_acp3x_config(struct acp_chip_info *chip)
|
||||
{
|
||||
u32 val;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "amd.h"
|
||||
#include "../mach-config.h"
|
||||
#include "acp-mach.h"
|
||||
|
|
@ -31,7 +33,6 @@
|
|||
#define MP1_C2PMSG_69 0x3B10A14
|
||||
#define MP1_C2PMSG_85 0x3B10A54
|
||||
#define MP1_C2PMSG_93 0x3B10A74
|
||||
#define HOST_BRIDGE_ID 0x14B5
|
||||
|
||||
static struct acp_resource rsrc = {
|
||||
.offset = 0,
|
||||
|
|
@ -166,21 +167,20 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
|
|||
|
||||
static int acp6x_master_clock_generate(struct device *dev)
|
||||
{
|
||||
int data = 0;
|
||||
struct pci_dev *smn_dev;
|
||||
int data, rc;
|
||||
|
||||
smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL);
|
||||
if (!smn_dev) {
|
||||
dev_err(dev, "Failed to get host bridge device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
rc = amd_smn_write(0, MP1_C2PMSG_93, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, MP1_C2PMSG_85, 0xC4);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, MP1_C2PMSG_69, 0x4);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
smn_write(smn_dev, MP1_C2PMSG_93, 0);
|
||||
smn_write(smn_dev, MP1_C2PMSG_85, 0xC4);
|
||||
smn_write(smn_dev, MP1_C2PMSG_69, 0x4);
|
||||
read_poll_timeout(smn_read, data, data, DELAY_US,
|
||||
ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93);
|
||||
return 0;
|
||||
return read_poll_timeout(smn_read_register, data, data > 0, DELAY_US,
|
||||
ACP_TIMEOUT, false, MP1_C2PMSG_93);
|
||||
}
|
||||
|
||||
static int rembrandt_audio_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "amd.h"
|
||||
#include "acp-mach.h"
|
||||
#include "../mach-config.h"
|
||||
|
|
@ -160,37 +163,53 @@ static struct snd_soc_dai_driver acp63_dai[] = {
|
|||
|
||||
static int acp63_i2s_master_clock_generate(struct acp_dev_data *adata)
|
||||
{
|
||||
int rc;
|
||||
u32 data;
|
||||
union clk_pll_req_no clk_pll;
|
||||
struct pci_dev *smn_dev;
|
||||
|
||||
smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL);
|
||||
if (!smn_dev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Clk5 pll register values to get mclk as 196.6MHz*/
|
||||
clk_pll.bits.fb_mult_int = 0x31;
|
||||
clk_pll.bits.pll_spine_div = 0;
|
||||
clk_pll.bits.gb_mult_frac = 0x26E9;
|
||||
|
||||
data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
|
||||
smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
|
||||
rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
data = smn_read(smn_dev, CLK_SPLL_FIELD_2_N0);
|
||||
if (data & PLL_FRANCE_EN)
|
||||
smn_write(smn_dev, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
|
||||
rc = amd_smn_read(0, CLK_SPLL_FIELD_2_N0, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (data & PLL_FRANCE_EN) {
|
||||
rc = amd_smn_write(0, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
smn_write(smn_dev, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
|
||||
rc = amd_smn_write(0, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
|
||||
smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
|
||||
rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
data = smn_read(smn_dev, CLK_DFSBYPASS_CONTR);
|
||||
smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
|
||||
smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
|
||||
rc = amd_smn_read(0, CLK_DFSBYPASS_CONTR, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
smn_write(smn_dev, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
|
||||
return 0;
|
||||
return amd_smn_write(0, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
|
||||
}
|
||||
|
||||
static int acp63_audio_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "amd.h"
|
||||
#include "acp-mach.h"
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#define DRV_NAME "acp_asoc_acp70"
|
||||
|
||||
#define CLK7_CLK0_DFS_CNTL_N1 0X0006C1A4
|
||||
|
|
@ -137,29 +139,6 @@ static struct snd_soc_dai_driver acp70_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata)
|
||||
{
|
||||
struct pci_dev *smn_dev;
|
||||
u32 device_id;
|
||||
|
||||
if (adata->acp_rev == ACP70_PCI_ID)
|
||||
device_id = 0x1507;
|
||||
else if (adata->acp_rev == ACP71_PCI_ID)
|
||||
device_id = 0x1122;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL);
|
||||
|
||||
if (!smn_dev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/
|
||||
smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp_acp70_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -215,7 +194,8 @@ static int acp_acp70_audio_probe(struct platform_device *pdev)
|
|||
|
||||
dev_set_drvdata(dev, adata);
|
||||
|
||||
ret = acp70_i2s_master_clock_generate(adata);
|
||||
/* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/
|
||||
ret = amd_smn_write(0, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n");
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -235,9 +235,6 @@ int acp_platform_unregister(struct device *dev);
|
|||
|
||||
int acp_machine_select(struct acp_dev_data *adata);
|
||||
|
||||
int smn_read(struct pci_dev *dev, u32 smn_addr);
|
||||
int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data);
|
||||
|
||||
int acp_init(struct acp_chip_info *chip);
|
||||
int acp_deinit(struct acp_chip_info *chip);
|
||||
void acp_enable_interrupts(struct acp_dev_data *adata);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ config SND_SOC_SOF_AMD_COMMON
|
|||
select SND_SOC_SOF_ACP_PROBES
|
||||
select SND_SOC_ACPI_AMD_MATCH
|
||||
select SND_SOC_ACPI if ACPI
|
||||
depends on AMD_NODE
|
||||
help
|
||||
This option is not user-selectable but automatically handled by
|
||||
'select' statements at a higher level
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "../ops.h"
|
||||
#include "acp.h"
|
||||
#include "acp-dsp-offset.h"
|
||||
|
|
@ -42,24 +44,6 @@ const struct dmi_system_id acp_sof_quirk_table[] = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(acp_sof_quirk_table);
|
||||
|
||||
static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
|
||||
{
|
||||
pci_write_config_dword(dev, 0x60, smn_addr);
|
||||
pci_write_config_dword(dev, 0x64, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smn_read(struct pci_dev *dev, u32 smn_addr)
|
||||
{
|
||||
u32 data = 0;
|
||||
|
||||
pci_write_config_dword(dev, 0x60, smn_addr);
|
||||
pci_read_config_dword(dev, 0x64, &data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void init_dma_descriptor(struct acp_dev_data *adata)
|
||||
{
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
|
|
@ -208,11 +192,11 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
|
|||
static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
|
||||
{
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
int ret;
|
||||
u32 data;
|
||||
int ret, data;
|
||||
|
||||
ret = read_poll_timeout(smn_read_register, data, data > 0 && data & MBOX_READY_MASK,
|
||||
MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_114_REG);
|
||||
|
||||
ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US,
|
||||
ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
|
|
@ -240,8 +224,8 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
|
|||
return -EINVAL;
|
||||
|
||||
/* Get a non-zero Doorbell value from PSP */
|
||||
ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false,
|
||||
adata->smn_dev, MP0_C2PMSG_73_REG);
|
||||
ret = read_poll_timeout(smn_read_register, data, data > 0, MBOX_DELAY_US,
|
||||
ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_73_REG);
|
||||
|
||||
if (ret) {
|
||||
dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
|
||||
|
|
@ -253,10 +237,14 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
smn_write(adata->smn_dev, MP0_C2PMSG_114_REG, cmd);
|
||||
ret = amd_smn_write(0, MP0_C2PMSG_114_REG, cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Ring the Doorbell for PSP */
|
||||
smn_write(adata->smn_dev, MP0_C2PMSG_73_REG, data);
|
||||
ret = amd_smn_write(0, MP0_C2PMSG_73_REG, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check MBOX ready as PSP ack */
|
||||
ret = psp_mbox_ready(adata, 1);
|
||||
|
|
@ -770,16 +758,10 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
|
|||
adata->pci_rev = pci->revision;
|
||||
mutex_init(&adata->acp_lock);
|
||||
sdev->pdata->hw_pdata = adata;
|
||||
adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL);
|
||||
if (!adata->smn_dev) {
|
||||
dev_err(sdev->dev, "Failed to get host bridge device\n");
|
||||
ret = -ENODEV;
|
||||
goto unregister_dev;
|
||||
}
|
||||
|
||||
ret = acp_init(sdev);
|
||||
if (ret < 0)
|
||||
goto free_smn_dev;
|
||||
goto unregister_dev;
|
||||
|
||||
sdev->ipc_irq = pci->irq;
|
||||
ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread,
|
||||
|
|
@ -787,7 +769,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
|
|||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "failed to register IRQ %d\n",
|
||||
sdev->ipc_irq);
|
||||
goto free_smn_dev;
|
||||
goto unregister_dev;
|
||||
}
|
||||
|
||||
/* scan SoundWire capabilities exposed by DSDT */
|
||||
|
|
@ -800,7 +782,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
|
|||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: SoundWire probe error\n");
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
pci_dev_put(adata->smn_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -846,8 +827,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
|
|||
|
||||
free_ipc_irq:
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
free_smn_dev:
|
||||
pci_dev_put(adata->smn_dev);
|
||||
unregister_dev:
|
||||
platform_device_unregister(adata->dmic_dev);
|
||||
return ret;
|
||||
|
|
@ -858,9 +837,6 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
|
|||
{
|
||||
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
|
||||
|
||||
if (adata->smn_dev)
|
||||
pci_dev_put(adata->smn_dev);
|
||||
|
||||
if (adata->sdw)
|
||||
amd_sof_sdw_exit(sdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ struct acp_dsp_stream {
|
|||
|
||||
struct sof_amd_acp_desc {
|
||||
const char *name;
|
||||
unsigned int host_bridge_id;
|
||||
u32 pgfsm_base;
|
||||
u32 ext_intr_enb;
|
||||
u32 ext_intr_cntl;
|
||||
|
|
@ -255,7 +254,6 @@ struct acp_dev_data {
|
|||
struct dma_descriptor dscr_info[ACP_MAX_DESC];
|
||||
struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
|
||||
struct acp_dsp_stream *dtrace_stream;
|
||||
struct pci_dev *smn_dev;
|
||||
struct acp_dsp_stream *probe_stream;
|
||||
bool enable_fw_debug;
|
||||
bool is_dram_in_use;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#define ACP6x_REG_END 0x125C000
|
||||
|
||||
static const struct sof_amd_acp_desc acp63_chip_info = {
|
||||
.host_bridge_id = HOST_BRIDGE_ACP63,
|
||||
.pgfsm_base = ACP6X_PGFSM_BASE,
|
||||
.ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
|
||||
.ext_intr_cntl = ACP6X_EXTERNAL_INTR_CNTL,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#define ACP70_REG_END 0x125C000
|
||||
|
||||
static const struct sof_amd_acp_desc acp70_chip_info = {
|
||||
.host_bridge_id = HOST_BRIDGE_ACP70,
|
||||
.pgfsm_base = ACP70_PGFSM_BASE,
|
||||
.ext_intr_enb = ACP70_EXTERNAL_INTR_ENB,
|
||||
.ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#define ACP6X_FUTURE_REG_ACLK_0 0x1854
|
||||
|
||||
static const struct sof_amd_acp_desc rembrandt_chip_info = {
|
||||
.host_bridge_id = HOST_BRIDGE_RMB,
|
||||
.pgfsm_base = ACP6X_PGFSM_BASE,
|
||||
.ext_intr_stat = ACP6X_EXT_INTR_STAT,
|
||||
.dsp_intr_base = ACP6X_DSP_SW_INTR_BASE,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#define ACP3X_FUTURE_REG_ACLK_0 0x1860
|
||||
|
||||
static const struct sof_amd_acp_desc renoir_chip_info = {
|
||||
.host_bridge_id = HOST_BRIDGE_CZN,
|
||||
.pgfsm_base = ACP3X_PGFSM_BASE,
|
||||
.ext_intr_stat = ACP3X_EXT_INTR_STAT,
|
||||
.dsp_intr_base = ACP3X_DSP_SW_INTR_BASE,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
static const struct sof_amd_acp_desc vangogh_chip_info = {
|
||||
.name = "vangogh",
|
||||
.host_bridge_id = HOST_BRIDGE_VGH,
|
||||
.pgfsm_base = ACP5X_PGFSM_BASE,
|
||||
.ext_intr_stat = ACP5X_EXT_INTR_STAT,
|
||||
.dsp_intr_base = ACP5X_DSP_SW_INTR_BASE,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user