xref: /freebsd/sys/dev/amdsmu/amdsmu.h (revision 8aab12ca1898e3fe62a85c39aa1921950d739284)
1 /*
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 The FreeBSD Foundation
5  *
6  * This software was developed by Aymeric Wibo <obiwac@freebsd.org>
7  * under sponsorship from the FreeBSD Foundation.
8  */
9 
10 #ifndef _AMDSMU_H_
11 #define	_AMDSMU_H_
12 
13 #include <sys/param.h>
14 #include <sys/bus.h>
15 #include <sys/eventhandler.h>
16 #include <sys/kernel.h>
17 
18 #include <machine/cpu.h>
19 #include <machine/md_var.h>
20 #include <machine/cputypes.h>
21 #include <machine/specialreg.h>
22 #include <x86/cputypes.h>
23 
24 #include <dev/amdsmu/amdsmu_reg.h>
25 
26 #define SMU_RES_READ_PERIOD_US	50
27 #define SMU_RES_READ_MAX	20000
28 
29 static const char *amdsmu_ip_blocks_names[] = {
30     "DISPLAY",
31     "CPU",
32     "GFX",
33     "VDD",
34     "ACP",
35     "VCN",
36     "ISP",
37     "NBIO",
38     "DF",
39     "USB3_0",
40     "USB3_1",
41     "LAPIC",
42     "USB3_2",
43     "USB3_3",
44     "USB3_4",
45     "USB4_0",
46     "USB4_1",
47     "MPM",
48     "JPEG",
49     "IPU",
50     "UMSCH",
51     "VPE",
52 };
53 
54 static const char *amdsmu_ip_blocks_names_v2[] = {
55     "DISPLAY",
56     "CPU",
57     "GFX",
58     "VDD",
59     "VDD_CCX",
60     "ACP",
61     "VCN_0",
62     "VCN_1",
63     "ISP",
64     "NBIO",
65     "DF",
66     "USB3_0",
67     "USB3_1",
68     "LAPIC",
69     "USB3_2",
70     "USB4_RT0",
71     "USB4_RT1",
72     "USB4_0",
73     "USB4_1",
74     "MPM",
75     "JPEG_0",
76     "JPEG_1",
77     "IPU",
78     "UMSCH",
79     "VPE",
80 };
81 
82 #define IP_MAX_BLOCK_NAMES	32
83 
84 CTASSERT(nitems(amdsmu_ip_blocks_names) <= IP_MAX_BLOCK_NAMES);
85 CTASSERT(nitems(amdsmu_ip_blocks_names_v2) <= IP_MAX_BLOCK_NAMES);
86 
87 static const struct amdsmu_product {
88 	uint16_t	amdsmu_vendorid;
89 	uint16_t	amdsmu_deviceid;
90 	/* CPU model from CPUID_TO_MODEL() if specific to that model, or -1. */
91 	int		model;
92 	int16_t		idlemask_reg;
93 	size_t		ip_block_count;
94 	const char 	**ip_blocks_names;
95 	uint32_t	amdsmu_msg;
96 } amdsmu_products[] = {
97 	/*
98 	 * Lines with -1 as 'model' must come before ones having same vendor and
99 	 * device IDs but a real CPU model.
100 	 */
101 	{ CPU_VENDOR_AMD,	PCI_DEVICEID_AMD_CEZANNE_ROOT,		-1,
102 	    SMU_REG_IDLEMASK_CEZANNE,	12,	amdsmu_ip_blocks_names,
103 	    SMU_REG_MSG_CEZANNE},
104 	{ CPU_VENDOR_AMD,	PCI_DEVICEID_AMD_REMBRANDT_ROOT,	-1,
105 	    SMU_REG_IDLEMASK_PHOENIX,	12,	amdsmu_ip_blocks_names,
106 	    SMU_REG_MSG_CEZANNE},
107 	{ CPU_VENDOR_AMD,	PCI_DEVICEID_AMD_PHOENIX_ROOT,		-1,
108 	    SMU_REG_IDLEMASK_PHOENIX,	21,	amdsmu_ip_blocks_names,
109 	    SMU_REG_MSG_CEZANNE},
110 	{ CPU_VENDOR_AMD,	PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT,	-1,
111 	    SMU_REG_IDLEMASK_KRACKAN,	22,	amdsmu_ip_blocks_names,
112 	    SMU_REG_MSG_KRACKAN },
113 	{ CPU_VENDOR_AMD,	PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT,	0x70,
114 	    SMU_REG_IDLEMASK_KRACKAN,	25,	amdsmu_ip_blocks_names_v2,
115 	    SMU_REG_MSG_KRACKAN },
116 	/*
117 	 * XXX Strix Point (PCI_DEVICEID_AMD_STRIX_POINT_ROOT) doesn't support
118 	 * S0i3 and thus doesn't have an idlemask.  Since our driver doesn't
119 	 * yet understand this, don't attach to Strix Point for the time being.
120 	 */
121 };
122 
123 static const struct amdsmu_diagnostics {
124 	const char	*blocking_ip_block;
125 	bool		ignore;
126 	const char	*expected_module;
127 	const char	*extra;
128 } amdsmu_diagnostics[] = {
129 	{ "CPU", false, NULL, "this can happen due to other IP blocks or "
130 	    "because the system was on AC power" },
131 	{ "MPM", false, NULL, "this can happen due to other IP blocks or "
132 	    "because the system was on AC power" },
133 	{ "GFX", false, "amdgpu", NULL },
134 	{ "DISPLAY", false, "amdgpu", NULL },
135 	/*
136 	 * On Phoenix, these seem to report USB4, not USB3 as their names would
137 	 * suggest.
138 	 */
139 	{ "USB3_0", false, "tb", "see thunderbolt(4)" },
140 	{ "USB3_1", false, "tb", "see thunderbolt(4)" },
141 	/* On Phoenix, the SMU seems to report garbage for this IP block. */
142 	{ "USB4_0", true, NULL, NULL },
143 };
144 
145 struct amdsmu_softc {
146 	const struct amdsmu_product	*product;
147 
148 	struct sysctl_ctx_list	*sysctlctx;
149 	struct sysctl_oid	*sysctlnode;
150 
151 	struct eventhandler_entry	*eh_suspend;
152 	struct eventhandler_entry	*eh_resume;
153 	struct eventhandler_entry	*eh_resume_check;
154 
155 	struct resource		*res;
156 	bus_space_tag_t 	bus_tag;
157 
158 	bus_space_handle_t	smu_space;
159 	bus_space_handle_t	reg_space;
160 
161 	uint8_t			smu_program;
162 	uint8_t			smu_maj, smu_min, smu_rev;
163 
164 	uint32_t		active_ip_blocks;
165 	struct sysctl_oid	*ip_blocks_sysctlnode;
166 	struct sysctl_oid	*ip_block_sysctlnodes[IP_MAX_BLOCK_NAMES];
167 	bool			ip_blocks_active[IP_MAX_BLOCK_NAMES];
168 
169 	bus_space_handle_t	metrics_space;
170 	struct amdsmu_metrics	metrics;
171 	uint32_t		idlemask;
172 	uint32_t		smu_msg;
173 };
174 
175 static inline uint32_t
amdsmu_read4(const struct amdsmu_softc * sc,bus_size_t reg)176 amdsmu_read4(const struct amdsmu_softc *sc, bus_size_t reg)
177 {
178 	return (bus_space_read_4(sc->bus_tag, sc->reg_space, reg));
179 }
180 
181 static inline void
amdsmu_write4(const struct amdsmu_softc * sc,bus_size_t reg,uint32_t val)182 amdsmu_write4(const struct amdsmu_softc *sc, bus_size_t reg, uint32_t val)
183 {
184 	bus_space_write_4(sc->bus_tag, sc->reg_space, reg, val);
185 }
186 
187 #endif /* _AMDSMU_H_ */
188