1e2340276SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2e2340276SBjoern A. Zeeb /* Copyright(c) 2021-2023 Realtek Corporation 3e2340276SBjoern A. Zeeb */ 4e2340276SBjoern A. Zeeb 5e2340276SBjoern A. Zeeb #include <linux/acpi.h> 6e2340276SBjoern A. Zeeb #include <linux/uuid.h> 7e2340276SBjoern A. Zeeb 8e2340276SBjoern A. Zeeb #include "acpi.h" 9e2340276SBjoern A. Zeeb #include "debug.h" 10e2340276SBjoern A. Zeeb 11e2340276SBjoern A. Zeeb #if defined(__linux__) 12e2340276SBjoern A. Zeeb static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, 13e2340276SBjoern A. Zeeb 0x82, 0xBD, 0xFE, 0x86, 14e2340276SBjoern A. Zeeb 0x07, 0x80, 0x3A, 0xA7); 15e2340276SBjoern A. Zeeb 16*6d67aabdSBjoern A. Zeeb static 17*6d67aabdSBjoern A. Zeeb int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj, 18e2340276SBjoern A. Zeeb u8 *value) 19e2340276SBjoern A. Zeeb { 20*6d67aabdSBjoern A. Zeeb if (obj->type != ACPI_TYPE_INTEGER) { 21*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, 22*6d67aabdSBjoern A. Zeeb "acpi: expect integer but type: %d\n", obj->type); 23e2340276SBjoern A. Zeeb return -EINVAL; 24e2340276SBjoern A. Zeeb } 25e2340276SBjoern A. Zeeb 26*6d67aabdSBjoern A. Zeeb *value = (u8)obj->integer.value; 27*6d67aabdSBjoern A. Zeeb return 0; 28*6d67aabdSBjoern A. Zeeb } 29*6d67aabdSBjoern A. Zeeb 30*6d67aabdSBjoern A. Zeeb static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p) 31*6d67aabdSBjoern A. Zeeb { 32*6d67aabdSBjoern A. Zeeb return p->signature[0] == 0x00 && 33*6d67aabdSBjoern A. Zeeb p->signature[1] == 0xE0 && 34*6d67aabdSBjoern A. Zeeb p->signature[2] == 0x4C; 35*6d67aabdSBjoern A. Zeeb } 36*6d67aabdSBjoern A. Zeeb 37*6d67aabdSBjoern A. Zeeb static 38*6d67aabdSBjoern A. Zeeb int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev, 39*6d67aabdSBjoern A. Zeeb union acpi_object *obj, 40*6d67aabdSBjoern A. Zeeb struct rtw89_acpi_policy_6ghz **policy_6ghz) 41*6d67aabdSBjoern A. Zeeb { 42*6d67aabdSBjoern A. Zeeb const struct rtw89_acpi_policy_6ghz *ptr; 43*6d67aabdSBjoern A. Zeeb u32 expect_len; 44*6d67aabdSBjoern A. Zeeb u32 len; 45*6d67aabdSBjoern A. Zeeb 46*6d67aabdSBjoern A. Zeeb if (obj->type != ACPI_TYPE_BUFFER) { 47*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, 48*6d67aabdSBjoern A. Zeeb "acpi: expect buffer but type: %d\n", obj->type); 49*6d67aabdSBjoern A. Zeeb return -EINVAL; 50*6d67aabdSBjoern A. Zeeb } 51*6d67aabdSBjoern A. Zeeb 52*6d67aabdSBjoern A. Zeeb len = obj->buffer.length; 53*6d67aabdSBjoern A. Zeeb if (len < sizeof(*ptr)) { 54*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", 55*6d67aabdSBjoern A. Zeeb __func__, len); 56*6d67aabdSBjoern A. Zeeb return -EINVAL; 57*6d67aabdSBjoern A. Zeeb } 58*6d67aabdSBjoern A. Zeeb 59*6d67aabdSBjoern A. Zeeb ptr = (typeof(ptr))obj->buffer.pointer; 60*6d67aabdSBjoern A. Zeeb if (!chk_acpi_policy_6ghz_sig(ptr)) { 61*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); 62*6d67aabdSBjoern A. Zeeb return -EINVAL; 63*6d67aabdSBjoern A. Zeeb } 64*6d67aabdSBjoern A. Zeeb 65*6d67aabdSBjoern A. Zeeb expect_len = struct_size(ptr, country_list, ptr->country_count); 66*6d67aabdSBjoern A. Zeeb if (len < expect_len) { 67*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n", 68*6d67aabdSBjoern A. Zeeb __func__, expect_len, len); 69*6d67aabdSBjoern A. Zeeb return -EINVAL; 70*6d67aabdSBjoern A. Zeeb } 71*6d67aabdSBjoern A. Zeeb 72*6d67aabdSBjoern A. Zeeb *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL); 73*6d67aabdSBjoern A. Zeeb if (!*policy_6ghz) 74*6d67aabdSBjoern A. Zeeb return -ENOMEM; 75*6d67aabdSBjoern A. Zeeb 76*6d67aabdSBjoern A. Zeeb rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz, 77*6d67aabdSBjoern A. Zeeb expect_len); 78*6d67aabdSBjoern A. Zeeb return 0; 79*6d67aabdSBjoern A. Zeeb } 80*6d67aabdSBjoern A. Zeeb 81*6d67aabdSBjoern A. Zeeb static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p) 82*6d67aabdSBjoern A. Zeeb { 83*6d67aabdSBjoern A. Zeeb return p->signature[0] == 0x52 && 84*6d67aabdSBjoern A. Zeeb p->signature[1] == 0x54 && 85*6d67aabdSBjoern A. Zeeb p->signature[2] == 0x4B && 86*6d67aabdSBjoern A. Zeeb p->signature[3] == 0x07; 87*6d67aabdSBjoern A. Zeeb } 88*6d67aabdSBjoern A. Zeeb 89*6d67aabdSBjoern A. Zeeb static 90*6d67aabdSBjoern A. Zeeb int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev, 91*6d67aabdSBjoern A. Zeeb union acpi_object *obj, 92*6d67aabdSBjoern A. Zeeb struct rtw89_acpi_policy_6ghz_sp **policy) 93*6d67aabdSBjoern A. Zeeb { 94*6d67aabdSBjoern A. Zeeb const struct rtw89_acpi_policy_6ghz_sp *ptr; 95*6d67aabdSBjoern A. Zeeb u32 buf_len; 96*6d67aabdSBjoern A. Zeeb 97*6d67aabdSBjoern A. Zeeb if (obj->type != ACPI_TYPE_BUFFER) { 98*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, 99*6d67aabdSBjoern A. Zeeb "acpi: expect buffer but type: %d\n", obj->type); 100*6d67aabdSBjoern A. Zeeb return -EINVAL; 101*6d67aabdSBjoern A. Zeeb } 102*6d67aabdSBjoern A. Zeeb 103*6d67aabdSBjoern A. Zeeb buf_len = obj->buffer.length; 104*6d67aabdSBjoern A. Zeeb if (buf_len < sizeof(*ptr)) { 105*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", 106*6d67aabdSBjoern A. Zeeb __func__, buf_len); 107*6d67aabdSBjoern A. Zeeb return -EINVAL; 108*6d67aabdSBjoern A. Zeeb } 109*6d67aabdSBjoern A. Zeeb 110*6d67aabdSBjoern A. Zeeb ptr = (typeof(ptr))obj->buffer.pointer; 111*6d67aabdSBjoern A. Zeeb if (!chk_acpi_policy_6ghz_sp_sig(ptr)) { 112*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); 113*6d67aabdSBjoern A. Zeeb return -EINVAL; 114*6d67aabdSBjoern A. Zeeb } 115*6d67aabdSBjoern A. Zeeb 116*6d67aabdSBjoern A. Zeeb *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); 117*6d67aabdSBjoern A. Zeeb if (!*policy) 118*6d67aabdSBjoern A. Zeeb return -ENOMEM; 119*6d67aabdSBjoern A. Zeeb 120*6d67aabdSBjoern A. Zeeb rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_sp: ", *policy, 121*6d67aabdSBjoern A. Zeeb sizeof(*ptr)); 122e2340276SBjoern A. Zeeb return 0; 123e2340276SBjoern A. Zeeb } 124e2340276SBjoern A. Zeeb 125e2340276SBjoern A. Zeeb int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, 126*6d67aabdSBjoern A. Zeeb enum rtw89_acpi_dsm_func func, 127*6d67aabdSBjoern A. Zeeb struct rtw89_acpi_dsm_result *res) 128e2340276SBjoern A. Zeeb { 129e2340276SBjoern A. Zeeb union acpi_object *obj; 130e2340276SBjoern A. Zeeb int ret; 131e2340276SBjoern A. Zeeb 132e2340276SBjoern A. Zeeb obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid, 133e2340276SBjoern A. Zeeb 0, func, NULL); 134e2340276SBjoern A. Zeeb if (!obj) { 135*6d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_ACPI, 136e2340276SBjoern A. Zeeb "acpi dsm fail to evaluate func: %d\n", func); 137e2340276SBjoern A. Zeeb return -ENOENT; 138e2340276SBjoern A. Zeeb } 139e2340276SBjoern A. Zeeb 140*6d67aabdSBjoern A. Zeeb if (func == RTW89_ACPI_DSM_FUNC_6G_BP) 141*6d67aabdSBjoern A. Zeeb ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj, 142*6d67aabdSBjoern A. Zeeb &res->u.policy_6ghz); 143*6d67aabdSBjoern A. Zeeb else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP) 144*6d67aabdSBjoern A. Zeeb ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj, 145*6d67aabdSBjoern A. Zeeb &res->u.policy_6ghz_sp); 146*6d67aabdSBjoern A. Zeeb else 147*6d67aabdSBjoern A. Zeeb ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); 148e2340276SBjoern A. Zeeb 149e2340276SBjoern A. Zeeb ACPI_FREE(obj); 150e2340276SBjoern A. Zeeb return ret; 151e2340276SBjoern A. Zeeb } 152e2340276SBjoern A. Zeeb #elif defined(__FreeBSD__) 153e2340276SBjoern A. Zeeb int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, 154*6d67aabdSBjoern A. Zeeb enum rtw89_acpi_dsm_func func, 155*6d67aabdSBjoern A. Zeeb struct rtw89_acpi_dsm_result *res) 156e2340276SBjoern A. Zeeb { 157e2340276SBjoern A. Zeeb return -ENOENT; 158e2340276SBjoern A. Zeeb } 159e2340276SBjoern A. Zeeb #endif 160