162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2005-2014, 2020-2021 Intel Corporation 462306a36Sopenharmony_ci * Copyright (C) 2016 Intel Deutschland GmbH 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "iwl-drv.h" 1162306a36Sopenharmony_ci#include "iwl-phy-db.h" 1262306a36Sopenharmony_ci#include "iwl-debug.h" 1362306a36Sopenharmony_ci#include "iwl-op-mode.h" 1462306a36Sopenharmony_ci#include "iwl-trans.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct iwl_phy_db_entry { 1762306a36Sopenharmony_ci u16 size; 1862306a36Sopenharmony_ci u8 *data; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/** 2262306a36Sopenharmony_ci * struct iwl_phy_db - stores phy configuration and calibration data. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * @cfg: phy configuration. 2562306a36Sopenharmony_ci * @calib_nch: non channel specific calibration data. 2662306a36Sopenharmony_ci * @n_group_papd: number of entries in papd channel group. 2762306a36Sopenharmony_ci * @calib_ch_group_papd: calibration data related to papd channel group. 2862306a36Sopenharmony_ci * @n_group_txp: number of entries in tx power channel group. 2962306a36Sopenharmony_ci * @calib_ch_group_txp: calibration data related to tx power chanel group. 3062306a36Sopenharmony_ci * @trans: transport layer 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistruct iwl_phy_db { 3362306a36Sopenharmony_ci struct iwl_phy_db_entry cfg; 3462306a36Sopenharmony_ci struct iwl_phy_db_entry calib_nch; 3562306a36Sopenharmony_ci int n_group_papd; 3662306a36Sopenharmony_ci struct iwl_phy_db_entry *calib_ch_group_papd; 3762306a36Sopenharmony_ci int n_group_txp; 3862306a36Sopenharmony_ci struct iwl_phy_db_entry *calib_ch_group_txp; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci struct iwl_trans *trans; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cienum iwl_phy_db_section_type { 4462306a36Sopenharmony_ci IWL_PHY_DB_CFG = 1, 4562306a36Sopenharmony_ci IWL_PHY_DB_CALIB_NCH, 4662306a36Sopenharmony_ci IWL_PHY_DB_UNUSED, 4762306a36Sopenharmony_ci IWL_PHY_DB_CALIB_CHG_PAPD, 4862306a36Sopenharmony_ci IWL_PHY_DB_CALIB_CHG_TXP, 4962306a36Sopenharmony_ci IWL_PHY_DB_MAX 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define PHY_DB_CMD 0x6c 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* for parsing of tx power channel group data that comes from the firmware*/ 5562306a36Sopenharmony_cistruct iwl_phy_db_chg_txp { 5662306a36Sopenharmony_ci __le32 space; 5762306a36Sopenharmony_ci __le16 max_channel_idx; 5862306a36Sopenharmony_ci} __packed; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistruct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), 6362306a36Sopenharmony_ci GFP_KERNEL); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!phy_db) 6662306a36Sopenharmony_ci return phy_db; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci phy_db->trans = trans; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci phy_db->n_group_txp = -1; 7162306a36Sopenharmony_ci phy_db->n_group_papd = -1; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* TODO: add default values of the phy db. */ 7462306a36Sopenharmony_ci return phy_db; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_phy_db_init); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * get phy db section: returns a pointer to a phy db section specified by 8062306a36Sopenharmony_ci * type and channel group id. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic struct iwl_phy_db_entry * 8362306a36Sopenharmony_ciiwl_phy_db_get_section(struct iwl_phy_db *phy_db, 8462306a36Sopenharmony_ci enum iwl_phy_db_section_type type, 8562306a36Sopenharmony_ci u16 chg_id) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (!phy_db || type >= IWL_PHY_DB_MAX) 8862306a36Sopenharmony_ci return NULL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci switch (type) { 9162306a36Sopenharmony_ci case IWL_PHY_DB_CFG: 9262306a36Sopenharmony_ci return &phy_db->cfg; 9362306a36Sopenharmony_ci case IWL_PHY_DB_CALIB_NCH: 9462306a36Sopenharmony_ci return &phy_db->calib_nch; 9562306a36Sopenharmony_ci case IWL_PHY_DB_CALIB_CHG_PAPD: 9662306a36Sopenharmony_ci if (chg_id >= phy_db->n_group_papd) 9762306a36Sopenharmony_ci return NULL; 9862306a36Sopenharmony_ci return &phy_db->calib_ch_group_papd[chg_id]; 9962306a36Sopenharmony_ci case IWL_PHY_DB_CALIB_CHG_TXP: 10062306a36Sopenharmony_ci if (chg_id >= phy_db->n_group_txp) 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci return &phy_db->calib_ch_group_txp[chg_id]; 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci return NULL; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci return NULL; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, 11062306a36Sopenharmony_ci enum iwl_phy_db_section_type type, 11162306a36Sopenharmony_ci u16 chg_id) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct iwl_phy_db_entry *entry = 11462306a36Sopenharmony_ci iwl_phy_db_get_section(phy_db, type, chg_id); 11562306a36Sopenharmony_ci if (!entry) 11662306a36Sopenharmony_ci return; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci kfree(entry->data); 11962306a36Sopenharmony_ci entry->data = NULL; 12062306a36Sopenharmony_ci entry->size = 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_civoid iwl_phy_db_free(struct iwl_phy_db *phy_db) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int i; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (!phy_db) 12862306a36Sopenharmony_ci return; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); 13162306a36Sopenharmony_ci iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = 0; i < phy_db->n_group_papd; i++) 13462306a36Sopenharmony_ci iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); 13562306a36Sopenharmony_ci kfree(phy_db->calib_ch_group_papd); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (i = 0; i < phy_db->n_group_txp; i++) 13862306a36Sopenharmony_ci iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); 13962306a36Sopenharmony_ci kfree(phy_db->calib_ch_group_txp); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci kfree(phy_db); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_phy_db_free); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciint iwl_phy_db_set_section(struct iwl_phy_db *phy_db, 14662306a36Sopenharmony_ci struct iwl_rx_packet *pkt) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); 14962306a36Sopenharmony_ci struct iwl_calib_res_notif_phy_db *phy_db_notif = 15062306a36Sopenharmony_ci (struct iwl_calib_res_notif_phy_db *)pkt->data; 15162306a36Sopenharmony_ci enum iwl_phy_db_section_type type; 15262306a36Sopenharmony_ci u16 size; 15362306a36Sopenharmony_ci struct iwl_phy_db_entry *entry; 15462306a36Sopenharmony_ci u16 chg_id = 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (pkt_len < sizeof(*phy_db_notif)) 15762306a36Sopenharmony_ci return -EINVAL; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci type = le16_to_cpu(phy_db_notif->type); 16062306a36Sopenharmony_ci size = le16_to_cpu(phy_db_notif->length); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (pkt_len < sizeof(*phy_db_notif) + size) 16362306a36Sopenharmony_ci return -EINVAL; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!phy_db) 16662306a36Sopenharmony_ci return -EINVAL; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (type == IWL_PHY_DB_CALIB_CHG_PAPD) { 16962306a36Sopenharmony_ci chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 17062306a36Sopenharmony_ci if (phy_db && !phy_db->calib_ch_group_papd) { 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * Firmware sends the largest index first, so we can use 17362306a36Sopenharmony_ci * it to know how much we should allocate. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci phy_db->calib_ch_group_papd = kcalloc(chg_id + 1, 17662306a36Sopenharmony_ci sizeof(struct iwl_phy_db_entry), 17762306a36Sopenharmony_ci GFP_ATOMIC); 17862306a36Sopenharmony_ci if (!phy_db->calib_ch_group_papd) 17962306a36Sopenharmony_ci return -ENOMEM; 18062306a36Sopenharmony_ci phy_db->n_group_papd = chg_id + 1; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) { 18362306a36Sopenharmony_ci chg_id = le16_to_cpup((__le16 *)phy_db_notif->data); 18462306a36Sopenharmony_ci if (phy_db && !phy_db->calib_ch_group_txp) { 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * Firmware sends the largest index first, so we can use 18762306a36Sopenharmony_ci * it to know how much we should allocate. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci phy_db->calib_ch_group_txp = kcalloc(chg_id + 1, 19062306a36Sopenharmony_ci sizeof(struct iwl_phy_db_entry), 19162306a36Sopenharmony_ci GFP_ATOMIC); 19262306a36Sopenharmony_ci if (!phy_db->calib_ch_group_txp) 19362306a36Sopenharmony_ci return -ENOMEM; 19462306a36Sopenharmony_ci phy_db->n_group_txp = chg_id + 1; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci entry = iwl_phy_db_get_section(phy_db, type, chg_id); 19962306a36Sopenharmony_ci if (!entry) 20062306a36Sopenharmony_ci return -EINVAL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci kfree(entry->data); 20362306a36Sopenharmony_ci entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC); 20462306a36Sopenharmony_ci if (!entry->data) { 20562306a36Sopenharmony_ci entry->size = 0; 20662306a36Sopenharmony_ci return -ENOMEM; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci entry->size = size; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 21262306a36Sopenharmony_ci "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", 21362306a36Sopenharmony_ci __func__, __LINE__, type, size); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_phy_db_set_section); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int is_valid_channel(u16 ch_id) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (ch_id <= 14 || 22262306a36Sopenharmony_ci (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || 22362306a36Sopenharmony_ci (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || 22462306a36Sopenharmony_ci (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) 22562306a36Sopenharmony_ci return 1; 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic u8 ch_id_to_ch_index(u16 ch_id) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci if (WARN_ON(!is_valid_channel(ch_id))) 23262306a36Sopenharmony_ci return 0xff; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (ch_id <= 14) 23562306a36Sopenharmony_ci return ch_id - 1; 23662306a36Sopenharmony_ci if (ch_id <= 64) 23762306a36Sopenharmony_ci return (ch_id + 20) / 4; 23862306a36Sopenharmony_ci if (ch_id <= 140) 23962306a36Sopenharmony_ci return (ch_id - 12) / 4; 24062306a36Sopenharmony_ci return (ch_id - 13) / 4; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic u16 channel_id_to_papd(u16 ch_id) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci if (WARN_ON(!is_valid_channel(ch_id))) 24762306a36Sopenharmony_ci return 0xff; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (1 <= ch_id && ch_id <= 14) 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci if (36 <= ch_id && ch_id <= 64) 25262306a36Sopenharmony_ci return 1; 25362306a36Sopenharmony_ci if (100 <= ch_id && ch_id <= 140) 25462306a36Sopenharmony_ci return 2; 25562306a36Sopenharmony_ci return 3; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct iwl_phy_db_chg_txp *txp_chg; 26162306a36Sopenharmony_ci int i; 26262306a36Sopenharmony_ci u8 ch_index = ch_id_to_ch_index(ch_id); 26362306a36Sopenharmony_ci if (ch_index == 0xff) 26462306a36Sopenharmony_ci return 0xff; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci for (i = 0; i < phy_db->n_group_txp; i++) { 26762306a36Sopenharmony_ci txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; 26862306a36Sopenharmony_ci if (!txp_chg) 26962306a36Sopenharmony_ci return 0xff; 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * Looking for the first channel group that its max channel is 27262306a36Sopenharmony_ci * higher then wanted channel. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) 27562306a36Sopenharmony_ci return i; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci return 0xff; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_cistatic 28062306a36Sopenharmony_ciint iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, 28162306a36Sopenharmony_ci u32 type, u8 **data, u16 *size, u16 ch_id) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct iwl_phy_db_entry *entry; 28462306a36Sopenharmony_ci u16 ch_group_id = 0; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!phy_db) 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* find wanted channel group */ 29062306a36Sopenharmony_ci if (type == IWL_PHY_DB_CALIB_CHG_PAPD) 29162306a36Sopenharmony_ci ch_group_id = channel_id_to_papd(ch_id); 29262306a36Sopenharmony_ci else if (type == IWL_PHY_DB_CALIB_CHG_TXP) 29362306a36Sopenharmony_ci ch_group_id = channel_id_to_txp(phy_db, ch_id); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); 29662306a36Sopenharmony_ci if (!entry) 29762306a36Sopenharmony_ci return -EINVAL; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci *data = entry->data; 30062306a36Sopenharmony_ci *size = entry->size; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 30362306a36Sopenharmony_ci "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", 30462306a36Sopenharmony_ci __func__, __LINE__, type, *size); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, 31062306a36Sopenharmony_ci u16 length, void *data) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct iwl_phy_db_cmd phy_db_cmd; 31362306a36Sopenharmony_ci struct iwl_host_cmd cmd = { 31462306a36Sopenharmony_ci .id = PHY_DB_CMD, 31562306a36Sopenharmony_ci }; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 31862306a36Sopenharmony_ci "Sending PHY-DB hcmd of type %d, of length %d\n", 31962306a36Sopenharmony_ci type, length); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Set phy db cmd variables */ 32262306a36Sopenharmony_ci phy_db_cmd.type = cpu_to_le16(type); 32362306a36Sopenharmony_ci phy_db_cmd.length = cpu_to_le16(length); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* Set hcmd variables */ 32662306a36Sopenharmony_ci cmd.data[0] = &phy_db_cmd; 32762306a36Sopenharmony_ci cmd.len[0] = sizeof(struct iwl_phy_db_cmd); 32862306a36Sopenharmony_ci cmd.data[1] = data; 32962306a36Sopenharmony_ci cmd.len[1] = length; 33062306a36Sopenharmony_ci cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return iwl_trans_send_cmd(phy_db->trans, &cmd); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int iwl_phy_db_send_all_channel_groups( 33662306a36Sopenharmony_ci struct iwl_phy_db *phy_db, 33762306a36Sopenharmony_ci enum iwl_phy_db_section_type type, 33862306a36Sopenharmony_ci u8 max_ch_groups) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci u16 i; 34162306a36Sopenharmony_ci int err; 34262306a36Sopenharmony_ci struct iwl_phy_db_entry *entry; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Send all the channel specific groups to operational fw */ 34562306a36Sopenharmony_ci for (i = 0; i < max_ch_groups; i++) { 34662306a36Sopenharmony_ci entry = iwl_phy_db_get_section(phy_db, 34762306a36Sopenharmony_ci type, 34862306a36Sopenharmony_ci i); 34962306a36Sopenharmony_ci if (!entry) 35062306a36Sopenharmony_ci return -EINVAL; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (!entry->size) 35362306a36Sopenharmony_ci continue; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Send the requested PHY DB section */ 35662306a36Sopenharmony_ci err = iwl_send_phy_db_cmd(phy_db, 35762306a36Sopenharmony_ci type, 35862306a36Sopenharmony_ci entry->size, 35962306a36Sopenharmony_ci entry->data); 36062306a36Sopenharmony_ci if (err) { 36162306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 36262306a36Sopenharmony_ci "Can't SEND phy_db section %d (%d), err %d\n", 36362306a36Sopenharmony_ci type, i, err); 36462306a36Sopenharmony_ci return err; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 36862306a36Sopenharmony_ci "Sent PHY_DB HCMD, type = %d num = %d\n", 36962306a36Sopenharmony_ci type, i); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciint iwl_send_phy_db_data(struct iwl_phy_db *phy_db) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci u8 *data = NULL; 37862306a36Sopenharmony_ci u16 size = 0; 37962306a36Sopenharmony_ci int err; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 38262306a36Sopenharmony_ci "Sending phy db data and configuration to runtime image\n"); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Send PHY DB CFG section */ 38562306a36Sopenharmony_ci err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG, 38662306a36Sopenharmony_ci &data, &size, 0); 38762306a36Sopenharmony_ci if (err) { 38862306a36Sopenharmony_ci IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n"); 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data); 39362306a36Sopenharmony_ci if (err) { 39462306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 39562306a36Sopenharmony_ci "Cannot send HCMD of Phy DB cfg section\n"); 39662306a36Sopenharmony_ci return err; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH, 40062306a36Sopenharmony_ci &data, &size, 0); 40162306a36Sopenharmony_ci if (err) { 40262306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 40362306a36Sopenharmony_ci "Cannot get Phy DB non specific channel section\n"); 40462306a36Sopenharmony_ci return err; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data); 40862306a36Sopenharmony_ci if (err) { 40962306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 41062306a36Sopenharmony_ci "Cannot send HCMD of Phy DB non specific channel section\n"); 41162306a36Sopenharmony_ci return err; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Send all the TXP channel specific data */ 41562306a36Sopenharmony_ci err = iwl_phy_db_send_all_channel_groups(phy_db, 41662306a36Sopenharmony_ci IWL_PHY_DB_CALIB_CHG_PAPD, 41762306a36Sopenharmony_ci phy_db->n_group_papd); 41862306a36Sopenharmony_ci if (err) { 41962306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 42062306a36Sopenharmony_ci "Cannot send channel specific PAPD groups\n"); 42162306a36Sopenharmony_ci return err; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Send all the TXP channel specific data */ 42562306a36Sopenharmony_ci err = iwl_phy_db_send_all_channel_groups(phy_db, 42662306a36Sopenharmony_ci IWL_PHY_DB_CALIB_CHG_TXP, 42762306a36Sopenharmony_ci phy_db->n_group_txp); 42862306a36Sopenharmony_ci if (err) { 42962306a36Sopenharmony_ci IWL_ERR(phy_db->trans, 43062306a36Sopenharmony_ci "Cannot send channel specific TX power groups\n"); 43162306a36Sopenharmony_ci return err; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci IWL_DEBUG_INFO(phy_db->trans, 43562306a36Sopenharmony_ci "Finished sending phy db non channel data\n"); 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_send_phy_db_data); 439