xref: /linux/drivers/platform/x86/amd/hsmp/plat.c (revision e47c018a0ee6962fe3dd895407e2c49538cc066d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AMD HSMP Platform Driver
4  * Copyright (c) 2024, AMD.
5  * All Rights Reserved.
6  *
7  * This file provides platform device implementations.
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 
12 #include <asm/amd_nb.h>
13 
14 #include <linux/device.h>
15 #include <linux/pci.h>
16 #include <linux/sysfs.h>
17 
18 #include "hsmp.h"
19 
20 /*
21  * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox
22  * register into the SMN_INDEX register, and reads/writes the SMN_DATA reg.
23  * Below are required SMN address for HSMP Mailbox register offsets in SMU address space
24  */
25 #define SMN_HSMP_BASE		0x3B00000
26 #define SMN_HSMP_MSG_ID		0x0010534
27 #define SMN_HSMP_MSG_ID_F1A_M0H	0x0010934
28 #define SMN_HSMP_MSG_RESP	0x0010980
29 #define SMN_HSMP_MSG_DATA	0x00109E0
30 
31 #define HSMP_INDEX_REG		0xc4
32 #define HSMP_DATA_REG		0xc8
33 
34 static int amd_hsmp_pci_rdwr(struct hsmp_socket *sock, u32 offset,
35 			     u32 *value, bool write)
36 {
37 	int ret;
38 
39 	if (!sock->root)
40 		return -ENODEV;
41 
42 	ret = pci_write_config_dword(sock->root, HSMP_INDEX_REG,
43 				     sock->mbinfo.base_addr + offset);
44 	if (ret)
45 		return ret;
46 
47 	ret = (write ? pci_write_config_dword(sock->root, HSMP_DATA_REG, *value)
48 		     : pci_read_config_dword(sock->root, HSMP_DATA_REG, value));
49 
50 	return ret;
51 }
52 
53 int hsmp_create_non_acpi_sysfs_if(struct device *dev)
54 {
55 	const struct attribute_group **hsmp_attr_grps;
56 	struct attribute_group *attr_grp;
57 	u16 i;
58 
59 	hsmp_attr_grps = devm_kcalloc(dev, plat_dev.num_sockets + 1,
60 				      sizeof(*hsmp_attr_grps),
61 				      GFP_KERNEL);
62 	if (!hsmp_attr_grps)
63 		return -ENOMEM;
64 
65 	/* Create a sysfs directory for each socket */
66 	for (i = 0; i < plat_dev.num_sockets; i++) {
67 		attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group),
68 					GFP_KERNEL);
69 		if (!attr_grp)
70 			return -ENOMEM;
71 
72 		snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i);
73 		attr_grp->name			= plat_dev.sock[i].name;
74 		attr_grp->is_bin_visible	= hsmp_is_sock_attr_visible;
75 		hsmp_attr_grps[i]		= attr_grp;
76 
77 		hsmp_create_attr_list(attr_grp, dev, i);
78 	}
79 
80 	return device_add_groups(dev, hsmp_attr_grps);
81 }
82 
83 static inline bool is_f1a_m0h(void)
84 {
85 	if (boot_cpu_data.x86 == 0x1A && boot_cpu_data.x86_model <= 0x0F)
86 		return true;
87 
88 	return false;
89 }
90 
91 int init_platform_device(struct device *dev)
92 {
93 	struct hsmp_socket *sock;
94 	int ret, i;
95 
96 	for (i = 0; i < plat_dev.num_sockets; i++) {
97 		if (!node_to_amd_nb(i))
98 			return -ENODEV;
99 		sock = &plat_dev.sock[i];
100 		sock->root			= node_to_amd_nb(i)->root;
101 		sock->sock_ind			= i;
102 		sock->dev			= dev;
103 		sock->mbinfo.base_addr		= SMN_HSMP_BASE;
104 		sock->amd_hsmp_rdwr		= amd_hsmp_pci_rdwr;
105 
106 		/*
107 		 * This is a transitional change from non-ACPI to ACPI, only
108 		 * family 0x1A, model 0x00 platform is supported for both ACPI and non-ACPI.
109 		 */
110 		if (is_f1a_m0h())
111 			sock->mbinfo.msg_id_off	= SMN_HSMP_MSG_ID_F1A_M0H;
112 		else
113 			sock->mbinfo.msg_id_off	= SMN_HSMP_MSG_ID;
114 
115 		sock->mbinfo.msg_resp_off	= SMN_HSMP_MSG_RESP;
116 		sock->mbinfo.msg_arg_off	= SMN_HSMP_MSG_DATA;
117 		sema_init(&sock->hsmp_sem, 1);
118 
119 		/* Test the hsmp interface on each socket */
120 		ret = hsmp_test(i, 0xDEADBEEF);
121 		if (ret) {
122 			dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n",
123 				boot_cpu_data.x86, boot_cpu_data.x86_model);
124 			dev_err(dev, "Is HSMP disabled in BIOS ?\n");
125 			return ret;
126 		}
127 
128 		ret = hsmp_cache_proto_ver(i);
129 		if (ret) {
130 			dev_err(dev, "Failed to read HSMP protocol version\n");
131 			return ret;
132 		}
133 	}
134 
135 	return 0;
136 }
137