/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2025 The FreeBSD Foundation * * This software was developed by Aymeric Wibo * under sponsorship from the FreeBSD Foundation. */ #ifndef _AMDSMU_H_ #define _AMDSMU_H_ #include #include #include #include #include #include #include #include #include #include #define SMU_RES_READ_PERIOD_US 50 #define SMU_RES_READ_MAX 20000 static const char *amdsmu_ip_blocks_names[] = { "DISPLAY", "CPU", "GFX", "VDD", "ACP", "VCN", "ISP", "NBIO", "DF", "USB3_0", "USB3_1", "LAPIC", "USB3_2", "USB3_3", "USB3_4", "USB4_0", "USB4_1", "MPM", "JPEG", "IPU", "UMSCH", "VPE", }; static const char *amdsmu_ip_blocks_names_v2[] = { "DISPLAY", "CPU", "GFX", "VDD", "VDD_CCX", "ACP", "VCN_0", "VCN_1", "ISP", "NBIO", "DF", "USB3_0", "USB3_1", "LAPIC", "USB3_2", "USB4_RT0", "USB4_RT1", "USB4_0", "USB4_1", "MPM", "JPEG_0", "JPEG_1", "IPU", "UMSCH", "VPE", }; #define IP_MAX_BLOCK_NAMES 32 CTASSERT(nitems(amdsmu_ip_blocks_names) <= IP_MAX_BLOCK_NAMES); CTASSERT(nitems(amdsmu_ip_blocks_names_v2) <= IP_MAX_BLOCK_NAMES); static const struct amdsmu_product { uint16_t amdsmu_vendorid; uint16_t amdsmu_deviceid; /* CPU model from CPUID_TO_MODEL() if specific to that model, or -1. */ int model; int16_t idlemask_reg; size_t ip_block_count; const char **ip_blocks_names; uint32_t amdsmu_msg; } amdsmu_products[] = { /* * Lines with -1 as 'model' must come before ones having same vendor and * device IDs but a real CPU model. */ { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_CEZANNE_ROOT, -1, SMU_REG_IDLEMASK_CEZANNE, 12, amdsmu_ip_blocks_names, SMU_REG_MSG_CEZANNE}, { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_REMBRANDT_ROOT, -1, SMU_REG_IDLEMASK_PHOENIX, 12, amdsmu_ip_blocks_names, SMU_REG_MSG_CEZANNE}, { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_PHOENIX_ROOT, -1, SMU_REG_IDLEMASK_PHOENIX, 21, amdsmu_ip_blocks_names, SMU_REG_MSG_CEZANNE}, { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT, -1, SMU_REG_IDLEMASK_KRACKAN, 22, amdsmu_ip_blocks_names, SMU_REG_MSG_KRACKAN }, { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT, 0x70, SMU_REG_IDLEMASK_KRACKAN, 25, amdsmu_ip_blocks_names_v2, SMU_REG_MSG_KRACKAN }, /* * XXX Strix Point (PCI_DEVICEID_AMD_STRIX_POINT_ROOT) doesn't support * S0i3 and thus doesn't have an idlemask. Since our driver doesn't * yet understand this, don't attach to Strix Point for the time being. */ }; static const struct amdsmu_diagnostics { const char *blocking_ip_block; bool ignore; const char *expected_module; const char *extra; } amdsmu_diagnostics[] = { { "CPU", false, NULL, "this can happen due to other IP blocks or " "because the system was on AC power" }, { "MPM", false, NULL, "this can happen due to other IP blocks or " "because the system was on AC power" }, { "GFX", false, "amdgpu", NULL }, { "DISPLAY", false, "amdgpu", NULL }, /* * On Phoenix, these seem to report USB4, not USB3 as their names would * suggest. */ { "USB3_0", false, "tb", "see thunderbolt(4)" }, { "USB3_1", false, "tb", "see thunderbolt(4)" }, /* On Phoenix, the SMU seems to report garbage for this IP block. */ { "USB4_0", true, NULL, NULL }, }; struct amdsmu_softc { const struct amdsmu_product *product; struct sysctl_ctx_list *sysctlctx; struct sysctl_oid *sysctlnode; struct eventhandler_entry *eh_suspend; struct eventhandler_entry *eh_resume; struct eventhandler_entry *eh_resume_check; struct resource *res; bus_space_tag_t bus_tag; bus_space_handle_t smu_space; bus_space_handle_t reg_space; uint8_t smu_program; uint8_t smu_maj, smu_min, smu_rev; uint32_t active_ip_blocks; struct sysctl_oid *ip_blocks_sysctlnode; struct sysctl_oid *ip_block_sysctlnodes[IP_MAX_BLOCK_NAMES]; bool ip_blocks_active[IP_MAX_BLOCK_NAMES]; bus_space_handle_t metrics_space; struct amdsmu_metrics metrics; uint32_t idlemask; uint32_t smu_msg; }; static inline uint32_t amdsmu_read4(const struct amdsmu_softc *sc, bus_size_t reg) { return (bus_space_read_4(sc->bus_tag, sc->reg_space, reg)); } static inline void amdsmu_write4(const struct amdsmu_softc *sc, bus_size_t reg, uint32_t val) { bus_space_write_4(sc->bus_tag, sc->reg_space, reg, val); } #endif /* _AMDSMU_H_ */