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