new file mode 100644
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "power_table.h"
+#include "chip.h"
+#include "e2p.h"
+#include "debug.h"
+#include "band.h"
+
+/*
+ * How to fill power table:
+ * Set 81 values in the range of 100 - 180 according to the Excel file.
+ * 100 corresponds to power of -10dBm (Pout Ant).
+ * 180 corresponds to power of +30dBm (Pout Ant).
+ * All values between 0 - 99 should be same as the value of 100.
+ * All values between 181 - 255 should be same as the value of 180.
+ */
+
+static const u8 power_to_powerword_conv_table_id_0[NUM_POWER_WORDS] = {
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 0 - 7 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 8 - 15 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 16 - 23 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 24 - 31 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 32 - 39 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 40 - 47 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 48 - 55 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 56 - 63 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 64 - 71 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 72 - 79 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 80 - 87 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 88 - 95 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x10, 0x11, /* 96 - 103 */
+ 0x12, 0x13, 0x14, 0x40, 0x41, 0x42, 0x43, 0x44, /* 104 - 111 */
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, /* 112 - 119 */
+ 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, /* 120 - 127 */
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, /* 128 - 135 */
+ 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, /* 136 - 143 */
+ 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, /* 144 - 151 */
+ 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, /* 152 - 159 */
+ 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, /* 160 - 167 */
+ 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xF9, 0xFA, 0xFB, /* 168 - 175 */
+ 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 176 - 183 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 184 - 191 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 192 - 199 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 200 - 207 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 208 - 215 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 216 - 223 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 224 - 231 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 232 - 239 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 240 - 247 */
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD /* 248 - 255 */
+};
+
+static const u8 power_to_powerword_conv_table_id_1[NUM_POWER_WORDS] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 0 - 7 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 8 - 15 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 16 - 23 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 24 - 31 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 32 - 39 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 40 - 47 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 48 - 55 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 56 - 63 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 64 - 71 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 72 - 79 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 80 - 87 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 88 - 95 */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x06, /* 96 - 103 */
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, /* 104 - 111 */
+ 0x0F, 0x10, 0x11, 0x12, 0x40, 0x41, 0x42, 0x43, /* 112 - 119 */
+ 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, /* 120 - 127 */
+ 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, /* 128 - 135 */
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, /* 136 - 143 */
+ 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, /* 144 - 151 */
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, /* 152 - 159 */
+ 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, /* 160 - 167 */
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, /* 168 - 175 */
+ 0x7D, 0xB9, 0xBA, 0xBB, 0xBC, 0xBC, 0xBC, 0xBC, /* 176 - 183 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 184 - 191 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 192 - 199 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 200 - 207 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 208 - 215 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 216 - 223 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 224 - 231 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 232 - 239 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 240 - 247 */
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC /* 248 - 255 */
+};
+
+static const u8 power_to_powerword_conv_table_id_2[NUM_POWER_WORDS] = {
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 0 - 7 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 8 - 15 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 16 - 23 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 24 - 31 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 32 - 39 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 40 - 47 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 48 - 55 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 56 - 63 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 64 - 71 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 72 - 79 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 80 - 87 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 88 - 95 */
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x10, 0x11, /* 96 - 103 */
+ 0x12, 0x13, 0x14, 0x40, 0x41, 0x42, 0x43, 0x44, /* 104 - 111 */
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, /* 112 - 119 */
+ 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, /* 120 - 127 */
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, /* 128 - 135 */
+ 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, /* 136 - 143 */
+ 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, /* 144 - 151 */
+ 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, /* 152 - 159 */
+ 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, /* 160 - 167 */
+ 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBD, 0xBD, 0xBD, /* 168 - 175 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 176 - 183 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 184 - 191 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 192 - 199 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 200 - 207 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 208 - 215 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 216 - 223 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 224 - 231 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 232 - 239 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 240 - 247 */
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD /* 248 - 255 */
+};
+
+static u8 cl_power_table_read(struct cl_hw *cl_hw)
+{
+ u8 pwr_table_id = 0;
+
+ if (cl_e2p_read(cl_hw->chip, &pwr_table_id, 1, ADDR_GEN_PWR_TABLE_ID + cl_hw->tcv_idx))
+ return U8_MAX;
+
+ return pwr_table_id;
+}
+
+static int cl_power_table_fill(struct cl_hw *cl_hw)
+{
+ u8 pwr_table_id = cl_power_table_read(cl_hw);
+
+ switch (pwr_table_id) {
+ case 0:
+ if (cl_band_is_5g(cl_hw)) {
+ memcpy(cl_hw->power_table_info.data->conv_table,
+ power_to_powerword_conv_table_id_0, NUM_POWER_WORDS);
+ cl_hw->tx_power_version = 5;
+ } else {
+ CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 5g only\n",
+ pwr_table_id);
+
+ if (!cl_hw->chip->conf->ce_production_mode)
+ return -1;
+ }
+ break;
+ case 1:
+ if (cl_band_is_24g(cl_hw)) {
+ memcpy(cl_hw->power_table_info.data->conv_table,
+ power_to_powerword_conv_table_id_1, NUM_POWER_WORDS);
+ cl_hw->tx_power_version = 25;
+ } else {
+ CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 2.4g only\n",
+ pwr_table_id);
+
+ if (!cl_hw->chip->conf->ce_production_mode)
+ return -1;
+ }
+ break;
+ case 2:
+ if (cl_band_is_6g(cl_hw)) {
+ memcpy(cl_hw->power_table_info.data->conv_table,
+ power_to_powerword_conv_table_id_2, NUM_POWER_WORDS);
+ cl_hw->tx_power_version = 1;
+ } else {
+ CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 6g only\n",
+ pwr_table_id);
+
+ if (!cl_hw->chip->conf->ce_production_mode)
+ return -1;
+ }
+ break;
+ default:
+ CL_DBG_ERROR(cl_hw, "Power table ID is not configured in EEPROM\n");
+
+ if (!cl_hw->chip->conf->ce_production_mode)
+ return -1;
+ }
+
+ cl_dbg_verbose(cl_hw, "Power table ID %u (V%u)\n", pwr_table_id, cl_hw->tx_power_version);
+
+ return 0;
+}
+
+int cl_power_table_alloc(struct cl_hw *cl_hw)
+{
+ struct cl_power_table_data *buf = NULL;
+ u32 len = sizeof(struct cl_power_table_data);
+ dma_addr_t phys_dma_addr;
+
+ buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+
+ if (!buf)
+ return -1;
+
+ cl_hw->power_table_info.data = buf;
+ cl_hw->power_table_info.dma_addr = cpu_to_le32(phys_dma_addr);
+
+ return cl_power_table_fill(cl_hw);
+}
+
+void cl_power_table_free(struct cl_hw *cl_hw)
+{
+ struct cl_power_table_info *power_table_info = &cl_hw->power_table_info;
+ u32 len = sizeof(struct cl_power_table_data);
+ dma_addr_t phys_dma_addr = le32_to_cpu(power_table_info->dma_addr);
+
+ if (!power_table_info->data)
+ return;
+
+ dma_free_coherent(cl_hw->chip->dev, len, (void *)power_table_info->data, phys_dma_addr);
+ power_table_info->data = NULL;
+}