.. | .. |
---|
| 1 | +// SPDX-License-Identifier: ISC |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. |
---|
3 | | - * |
---|
4 | | - * Permission to use, copy, modify, and/or distribute this software for any |
---|
5 | | - * purpose with or without fee is hereby granted, provided that the above |
---|
6 | | - * copyright notice and this permission notice appear in all copies. |
---|
7 | | - * |
---|
8 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
9 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
10 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
---|
11 | | - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
12 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
13 | | - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
---|
14 | | - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
15 | 4 | */ |
---|
16 | 5 | |
---|
17 | 6 | #include <linux/types.h> |
---|
18 | 7 | #include <linux/bitops.h> |
---|
| 8 | +#include <linux/bitfield.h> |
---|
19 | 9 | #include "core.h" |
---|
20 | 10 | #include "hw.h" |
---|
21 | 11 | #include "hif.h" |
---|
.. | .. |
---|
165 | 155 | .num_target_ce_config_wlan = 7, |
---|
166 | 156 | .ce_desc_meta_data_mask = 0xFFFC, |
---|
167 | 157 | .ce_desc_meta_data_lsb = 2, |
---|
| 158 | + .rfkill_pin = 16, |
---|
| 159 | + .rfkill_cfg = 0, |
---|
| 160 | + .rfkill_on_level = 1, |
---|
168 | 161 | }; |
---|
169 | 162 | |
---|
170 | 163 | const struct ath10k_hw_values qca99x0_values = { |
---|
.. | .. |
---|
317 | 310 | }; |
---|
318 | 311 | |
---|
319 | 312 | const struct ath10k_hw_ce_regs wcn3990_ce_regs = { |
---|
320 | | - .sr_base_addr = 0x00000000, |
---|
| 313 | + .sr_base_addr_lo = 0x00000000, |
---|
| 314 | + .sr_base_addr_hi = 0x00000004, |
---|
321 | 315 | .sr_size_addr = 0x00000008, |
---|
322 | | - .dr_base_addr = 0x0000000c, |
---|
| 316 | + .dr_base_addr_lo = 0x0000000c, |
---|
| 317 | + .dr_base_addr_hi = 0x00000010, |
---|
323 | 318 | .dr_size_addr = 0x00000014, |
---|
324 | 319 | .misc_ie_addr = 0x00000034, |
---|
325 | 320 | .sr_wr_index_addr = 0x0000003c, |
---|
.. | .. |
---|
463 | 458 | }; |
---|
464 | 459 | |
---|
465 | 460 | const struct ath10k_hw_ce_regs qcax_ce_regs = { |
---|
466 | | - .sr_base_addr = 0x00000000, |
---|
| 461 | + .sr_base_addr_lo = 0x00000000, |
---|
467 | 462 | .sr_size_addr = 0x00000004, |
---|
468 | | - .dr_base_addr = 0x00000008, |
---|
| 463 | + .dr_base_addr_lo = 0x00000008, |
---|
469 | 464 | .dr_size_addr = 0x0000000c, |
---|
470 | 465 | .ce_cmd_addr = 0x00000018, |
---|
471 | 466 | .misc_ie_addr = 0x00000034, |
---|
.. | .. |
---|
918 | 913 | return 0; |
---|
919 | 914 | } |
---|
920 | 915 | |
---|
| 916 | +/* Program CPU_ADDR_MSB to allow different memory |
---|
| 917 | + * region access. |
---|
| 918 | + */ |
---|
| 919 | +static void ath10k_hw_map_target_mem(struct ath10k *ar, u32 msb) |
---|
| 920 | +{ |
---|
| 921 | + u32 address = SOC_CORE_BASE_ADDRESS + FW_RAM_CONFIG_ADDRESS; |
---|
| 922 | + |
---|
| 923 | + ath10k_hif_write32(ar, address, msb); |
---|
| 924 | +} |
---|
| 925 | + |
---|
| 926 | +/* 1. Write to memory region of target, such as IRAM adn DRAM. |
---|
| 927 | + * 2. Target address( 0 ~ 00100000 & 0x00400000~0x00500000) |
---|
| 928 | + * can be written directly. See ath10k_pci_targ_cpu_to_ce_addr() too. |
---|
| 929 | + * 3. In order to access the region other than the above, |
---|
| 930 | + * we need to set the value of register CPU_ADDR_MSB. |
---|
| 931 | + * 4. Target memory access space is limited to 1M size. If the size is larger |
---|
| 932 | + * than 1M, need to split it and program CPU_ADDR_MSB accordingly. |
---|
| 933 | + */ |
---|
| 934 | +static int ath10k_hw_diag_segment_msb_download(struct ath10k *ar, |
---|
| 935 | + const void *buffer, |
---|
| 936 | + u32 address, |
---|
| 937 | + u32 length) |
---|
| 938 | +{ |
---|
| 939 | + u32 addr = address & REGION_ACCESS_SIZE_MASK; |
---|
| 940 | + int ret, remain_size, size; |
---|
| 941 | + const u8 *buf; |
---|
| 942 | + |
---|
| 943 | + ath10k_hw_map_target_mem(ar, CPU_ADDR_MSB_REGION_VAL(address)); |
---|
| 944 | + |
---|
| 945 | + if (addr + length > REGION_ACCESS_SIZE_LIMIT) { |
---|
| 946 | + size = REGION_ACCESS_SIZE_LIMIT - addr; |
---|
| 947 | + remain_size = length - size; |
---|
| 948 | + |
---|
| 949 | + ret = ath10k_hif_diag_write(ar, address, buffer, size); |
---|
| 950 | + if (ret) { |
---|
| 951 | + ath10k_warn(ar, |
---|
| 952 | + "failed to download the first %d bytes segment to address:0x%x: %d\n", |
---|
| 953 | + size, address, ret); |
---|
| 954 | + goto done; |
---|
| 955 | + } |
---|
| 956 | + |
---|
| 957 | + /* Change msb to the next memory region*/ |
---|
| 958 | + ath10k_hw_map_target_mem(ar, |
---|
| 959 | + CPU_ADDR_MSB_REGION_VAL(address) + 1); |
---|
| 960 | + buf = buffer + size; |
---|
| 961 | + ret = ath10k_hif_diag_write(ar, |
---|
| 962 | + address & ~REGION_ACCESS_SIZE_MASK, |
---|
| 963 | + buf, remain_size); |
---|
| 964 | + if (ret) { |
---|
| 965 | + ath10k_warn(ar, |
---|
| 966 | + "failed to download the second %d bytes segment to address:0x%x: %d\n", |
---|
| 967 | + remain_size, |
---|
| 968 | + address & ~REGION_ACCESS_SIZE_MASK, |
---|
| 969 | + ret); |
---|
| 970 | + goto done; |
---|
| 971 | + } |
---|
| 972 | + } else { |
---|
| 973 | + ret = ath10k_hif_diag_write(ar, address, buffer, length); |
---|
| 974 | + if (ret) { |
---|
| 975 | + ath10k_warn(ar, |
---|
| 976 | + "failed to download the only %d bytes segment to address:0x%x: %d\n", |
---|
| 977 | + length, address, ret); |
---|
| 978 | + goto done; |
---|
| 979 | + } |
---|
| 980 | + } |
---|
| 981 | + |
---|
| 982 | +done: |
---|
| 983 | + /* Change msb to DRAM */ |
---|
| 984 | + ath10k_hw_map_target_mem(ar, |
---|
| 985 | + CPU_ADDR_MSB_REGION_VAL(DRAM_BASE_ADDRESS)); |
---|
| 986 | + return ret; |
---|
| 987 | +} |
---|
| 988 | + |
---|
| 989 | +static int ath10k_hw_diag_segment_download(struct ath10k *ar, |
---|
| 990 | + const void *buffer, |
---|
| 991 | + u32 address, |
---|
| 992 | + u32 length) |
---|
| 993 | +{ |
---|
| 994 | + if (address >= DRAM_BASE_ADDRESS + REGION_ACCESS_SIZE_LIMIT) |
---|
| 995 | + /* Needs to change MSB for memory write */ |
---|
| 996 | + return ath10k_hw_diag_segment_msb_download(ar, buffer, |
---|
| 997 | + address, length); |
---|
| 998 | + else |
---|
| 999 | + return ath10k_hif_diag_write(ar, address, buffer, length); |
---|
| 1000 | +} |
---|
| 1001 | + |
---|
| 1002 | +int ath10k_hw_diag_fast_download(struct ath10k *ar, |
---|
| 1003 | + u32 address, |
---|
| 1004 | + const void *buffer, |
---|
| 1005 | + u32 length) |
---|
| 1006 | +{ |
---|
| 1007 | + const u8 *buf = buffer; |
---|
| 1008 | + bool sgmt_end = false; |
---|
| 1009 | + u32 base_addr = 0; |
---|
| 1010 | + u32 base_len = 0; |
---|
| 1011 | + u32 left = 0; |
---|
| 1012 | + struct bmi_segmented_file_header *hdr; |
---|
| 1013 | + struct bmi_segmented_metadata *metadata; |
---|
| 1014 | + int ret = 0; |
---|
| 1015 | + |
---|
| 1016 | + if (length < sizeof(*hdr)) |
---|
| 1017 | + return -EINVAL; |
---|
| 1018 | + |
---|
| 1019 | + /* check firmware header. If it has no correct magic number |
---|
| 1020 | + * or it's compressed, returns error. |
---|
| 1021 | + */ |
---|
| 1022 | + hdr = (struct bmi_segmented_file_header *)buf; |
---|
| 1023 | + if (__le32_to_cpu(hdr->magic_num) != BMI_SGMTFILE_MAGIC_NUM) { |
---|
| 1024 | + ath10k_dbg(ar, ATH10K_DBG_BOOT, |
---|
| 1025 | + "Not a supported firmware, magic_num:0x%x\n", |
---|
| 1026 | + hdr->magic_num); |
---|
| 1027 | + return -EINVAL; |
---|
| 1028 | + } |
---|
| 1029 | + |
---|
| 1030 | + if (hdr->file_flags != 0) { |
---|
| 1031 | + ath10k_dbg(ar, ATH10K_DBG_BOOT, |
---|
| 1032 | + "Not a supported firmware, file_flags:0x%x\n", |
---|
| 1033 | + hdr->file_flags); |
---|
| 1034 | + return -EINVAL; |
---|
| 1035 | + } |
---|
| 1036 | + |
---|
| 1037 | + metadata = (struct bmi_segmented_metadata *)hdr->data; |
---|
| 1038 | + left = length - sizeof(*hdr); |
---|
| 1039 | + |
---|
| 1040 | + while (left > 0) { |
---|
| 1041 | + if (left < sizeof(*metadata)) { |
---|
| 1042 | + ath10k_warn(ar, "firmware segment is truncated: %d\n", |
---|
| 1043 | + left); |
---|
| 1044 | + ret = -EINVAL; |
---|
| 1045 | + break; |
---|
| 1046 | + } |
---|
| 1047 | + base_addr = __le32_to_cpu(metadata->addr); |
---|
| 1048 | + base_len = __le32_to_cpu(metadata->length); |
---|
| 1049 | + buf = metadata->data; |
---|
| 1050 | + left -= sizeof(*metadata); |
---|
| 1051 | + |
---|
| 1052 | + switch (base_len) { |
---|
| 1053 | + case BMI_SGMTFILE_BEGINADDR: |
---|
| 1054 | + /* base_addr is the start address to run */ |
---|
| 1055 | + ret = ath10k_bmi_set_start(ar, base_addr); |
---|
| 1056 | + base_len = 0; |
---|
| 1057 | + break; |
---|
| 1058 | + case BMI_SGMTFILE_DONE: |
---|
| 1059 | + /* no more segment */ |
---|
| 1060 | + base_len = 0; |
---|
| 1061 | + sgmt_end = true; |
---|
| 1062 | + ret = 0; |
---|
| 1063 | + break; |
---|
| 1064 | + case BMI_SGMTFILE_BDDATA: |
---|
| 1065 | + case BMI_SGMTFILE_EXEC: |
---|
| 1066 | + ath10k_warn(ar, |
---|
| 1067 | + "firmware has unsupported segment:%d\n", |
---|
| 1068 | + base_len); |
---|
| 1069 | + ret = -EINVAL; |
---|
| 1070 | + break; |
---|
| 1071 | + default: |
---|
| 1072 | + if (base_len > left) { |
---|
| 1073 | + /* sanity check */ |
---|
| 1074 | + ath10k_warn(ar, |
---|
| 1075 | + "firmware has invalid segment length, %d > %d\n", |
---|
| 1076 | + base_len, left); |
---|
| 1077 | + ret = -EINVAL; |
---|
| 1078 | + break; |
---|
| 1079 | + } |
---|
| 1080 | + |
---|
| 1081 | + ret = ath10k_hw_diag_segment_download(ar, |
---|
| 1082 | + buf, |
---|
| 1083 | + base_addr, |
---|
| 1084 | + base_len); |
---|
| 1085 | + |
---|
| 1086 | + if (ret) |
---|
| 1087 | + ath10k_warn(ar, |
---|
| 1088 | + "failed to download firmware via diag interface:%d\n", |
---|
| 1089 | + ret); |
---|
| 1090 | + break; |
---|
| 1091 | + } |
---|
| 1092 | + |
---|
| 1093 | + if (ret || sgmt_end) |
---|
| 1094 | + break; |
---|
| 1095 | + |
---|
| 1096 | + metadata = (struct bmi_segmented_metadata *)(buf + base_len); |
---|
| 1097 | + left -= base_len; |
---|
| 1098 | + } |
---|
| 1099 | + |
---|
| 1100 | + if (ret == 0) |
---|
| 1101 | + ath10k_dbg(ar, ATH10K_DBG_BOOT, |
---|
| 1102 | + "boot firmware fast diag download successfully.\n"); |
---|
| 1103 | + return ret; |
---|
| 1104 | +} |
---|
| 1105 | + |
---|
| 1106 | +static int ath10k_htt_tx_rssi_enable(struct htt_resp *resp) |
---|
| 1107 | +{ |
---|
| 1108 | + return (resp->data_tx_completion.flags2 & HTT_TX_CMPL_FLAG_DATA_RSSI); |
---|
| 1109 | +} |
---|
| 1110 | + |
---|
| 1111 | +static int ath10k_htt_tx_rssi_enable_wcn3990(struct htt_resp *resp) |
---|
| 1112 | +{ |
---|
| 1113 | + return (resp->data_tx_completion.flags2 & |
---|
| 1114 | + HTT_TX_DATA_RSSI_ENABLE_WCN3990); |
---|
| 1115 | +} |
---|
| 1116 | + |
---|
| 1117 | +static int ath10k_get_htt_tx_data_rssi_pad(struct htt_resp *resp) |
---|
| 1118 | +{ |
---|
| 1119 | + struct htt_data_tx_completion_ext extd; |
---|
| 1120 | + int pad_bytes = 0; |
---|
| 1121 | + |
---|
| 1122 | + if (resp->data_tx_completion.flags2 & HTT_TX_DATA_APPEND_RETRIES) |
---|
| 1123 | + pad_bytes += sizeof(extd.a_retries) / |
---|
| 1124 | + sizeof(extd.msdus_rssi[0]); |
---|
| 1125 | + |
---|
| 1126 | + if (resp->data_tx_completion.flags2 & HTT_TX_DATA_APPEND_TIMESTAMP) |
---|
| 1127 | + pad_bytes += sizeof(extd.t_stamp) / sizeof(extd.msdus_rssi[0]); |
---|
| 1128 | + |
---|
| 1129 | + return pad_bytes; |
---|
| 1130 | +} |
---|
| 1131 | + |
---|
921 | 1132 | const struct ath10k_hw_ops qca988x_ops = { |
---|
922 | 1133 | .set_coverage_class = ath10k_hw_qca988x_set_coverage_class, |
---|
| 1134 | + .is_rssi_enable = ath10k_htt_tx_rssi_enable, |
---|
923 | 1135 | }; |
---|
924 | 1136 | |
---|
925 | 1137 | static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd) |
---|
.. | .. |
---|
928 | 1140 | RX_MSDU_END_INFO1_L3_HDR_PAD); |
---|
929 | 1141 | } |
---|
930 | 1142 | |
---|
| 1143 | +static bool ath10k_qca99x0_rx_desc_msdu_limit_error(struct htt_rx_desc *rxd) |
---|
| 1144 | +{ |
---|
| 1145 | + return !!(rxd->msdu_end.common.info0 & |
---|
| 1146 | + __cpu_to_le32(RX_MSDU_END_INFO0_MSDU_LIMIT_ERR)); |
---|
| 1147 | +} |
---|
| 1148 | + |
---|
931 | 1149 | const struct ath10k_hw_ops qca99x0_ops = { |
---|
932 | 1150 | .rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes, |
---|
| 1151 | + .rx_desc_get_msdu_limit_error = ath10k_qca99x0_rx_desc_msdu_limit_error, |
---|
| 1152 | + .is_rssi_enable = ath10k_htt_tx_rssi_enable, |
---|
933 | 1153 | }; |
---|
934 | 1154 | |
---|
935 | 1155 | const struct ath10k_hw_ops qca6174_ops = { |
---|
936 | 1156 | .set_coverage_class = ath10k_hw_qca988x_set_coverage_class, |
---|
937 | 1157 | .enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock, |
---|
| 1158 | + .is_rssi_enable = ath10k_htt_tx_rssi_enable, |
---|
938 | 1159 | }; |
---|
939 | 1160 | |
---|
940 | | -const struct ath10k_hw_ops wcn3990_ops = {}; |
---|
| 1161 | +const struct ath10k_hw_ops qca6174_sdio_ops = { |
---|
| 1162 | + .enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock, |
---|
| 1163 | +}; |
---|
| 1164 | + |
---|
| 1165 | +const struct ath10k_hw_ops wcn3990_ops = { |
---|
| 1166 | + .tx_data_rssi_pad_bytes = ath10k_get_htt_tx_data_rssi_pad, |
---|
| 1167 | + .is_rssi_enable = ath10k_htt_tx_rssi_enable_wcn3990, |
---|
| 1168 | +}; |
---|