0001
0002
0003
0004
0005
0006
0007 #include "bmi.h"
0008 #include "hif.h"
0009 #include "debug.h"
0010 #include "htc.h"
0011 #include "hw.h"
0012
0013 void ath10k_bmi_start(struct ath10k *ar)
0014 {
0015 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
0016
0017 ar->bmi.done_sent = false;
0018 }
0019 EXPORT_SYMBOL(ath10k_bmi_start);
0020
0021 int ath10k_bmi_done(struct ath10k *ar)
0022 {
0023 struct bmi_cmd cmd;
0024 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
0025 int ret;
0026
0027 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
0028
0029 if (ar->bmi.done_sent) {
0030 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
0031 return 0;
0032 }
0033
0034 ar->bmi.done_sent = true;
0035 cmd.id = __cpu_to_le32(BMI_DONE);
0036
0037 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
0038 if (ret) {
0039 ath10k_warn(ar, "unable to write to the device: %d\n", ret);
0040 return ret;
0041 }
0042
0043 return 0;
0044 }
0045
0046 int ath10k_bmi_get_target_info(struct ath10k *ar,
0047 struct bmi_target_info *target_info)
0048 {
0049 struct bmi_cmd cmd;
0050 union bmi_resp resp;
0051 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
0052 u32 resplen = sizeof(resp.get_target_info);
0053 int ret;
0054
0055 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
0056
0057 if (ar->bmi.done_sent) {
0058 ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
0059 return -EBUSY;
0060 }
0061
0062 cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
0063
0064 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
0065 if (ret) {
0066 ath10k_warn(ar, "unable to get target info from device\n");
0067 return ret;
0068 }
0069
0070 if (resplen < sizeof(resp.get_target_info)) {
0071 ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
0072 resplen);
0073 return -EIO;
0074 }
0075
0076 target_info->version = __le32_to_cpu(resp.get_target_info.version);
0077 target_info->type = __le32_to_cpu(resp.get_target_info.type);
0078
0079 return 0;
0080 }
0081
0082 #define TARGET_VERSION_SENTINAL 0xffffffffu
0083
0084 int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
0085 struct bmi_target_info *target_info)
0086 {
0087 struct bmi_cmd cmd;
0088 union bmi_resp resp;
0089 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
0090 u32 resplen, ver_len;
0091 __le32 tmp;
0092 int ret;
0093
0094 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
0095
0096 if (ar->bmi.done_sent) {
0097 ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
0098 return -EBUSY;
0099 }
0100
0101 cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
0102
0103
0104
0105
0106
0107 resplen = sizeof(u32);
0108 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
0109 if (ret) {
0110 ath10k_warn(ar, "unable to read from device\n");
0111 return ret;
0112 }
0113
0114
0115
0116
0117 if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
0118
0119 resplen = sizeof(u32);
0120 ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
0121 &resplen);
0122 if (ret) {
0123 ath10k_warn(ar, "unable to read from device\n");
0124 return ret;
0125 }
0126 }
0127
0128 ver_len = __le32_to_cpu(tmp);
0129
0130
0131 if (ver_len != sizeof(resp.get_target_info)) {
0132 ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
0133 ver_len, sizeof(resp.get_target_info));
0134 return -EINVAL;
0135 }
0136
0137
0138 resplen = sizeof(resp.get_target_info) - sizeof(u32);
0139 ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
0140 &resp.get_target_info.version,
0141 &resplen);
0142 if (ret) {
0143 ath10k_warn(ar, "unable to read from device\n");
0144 return ret;
0145 }
0146
0147 target_info->version = __le32_to_cpu(resp.get_target_info.version);
0148 target_info->type = __le32_to_cpu(resp.get_target_info.type);
0149
0150 return 0;
0151 }
0152
0153 int ath10k_bmi_read_memory(struct ath10k *ar,
0154 u32 address, void *buffer, u32 length)
0155 {
0156 struct bmi_cmd cmd;
0157 union bmi_resp resp;
0158 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
0159 u32 rxlen;
0160 int ret;
0161
0162 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
0163 address, length);
0164
0165 if (ar->bmi.done_sent) {
0166 ath10k_warn(ar, "command disallowed\n");
0167 return -EBUSY;
0168 }
0169
0170 while (length) {
0171 rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
0172
0173 cmd.id = __cpu_to_le32(BMI_READ_MEMORY);
0174 cmd.read_mem.addr = __cpu_to_le32(address);
0175 cmd.read_mem.len = __cpu_to_le32(rxlen);
0176
0177 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
0178 &resp, &rxlen);
0179 if (ret) {
0180 ath10k_warn(ar, "unable to read from the device (%d)\n",
0181 ret);
0182 return ret;
0183 }
0184
0185 memcpy(buffer, resp.read_mem.payload, rxlen);
0186 address += rxlen;
0187 buffer += rxlen;
0188 length -= rxlen;
0189 }
0190
0191 return 0;
0192 }
0193 EXPORT_SYMBOL(ath10k_bmi_read_memory);
0194
0195 int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
0196 {
0197 struct bmi_cmd cmd;
0198 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
0199 int ret;
0200
0201 ath10k_dbg(ar, ATH10K_DBG_BMI,
0202 "bmi write soc register 0x%08x val 0x%08x\n",
0203 address, reg_val);
0204
0205 if (ar->bmi.done_sent) {
0206 ath10k_warn(ar, "bmi write soc register command in progress\n");
0207 return -EBUSY;
0208 }
0209
0210 cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
0211 cmd.write_soc_reg.addr = __cpu_to_le32(address);
0212 cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
0213
0214 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
0215 if (ret) {
0216 ath10k_warn(ar, "Unable to write soc register to device: %d\n",
0217 ret);
0218 return ret;
0219 }
0220
0221 return 0;
0222 }
0223
0224 int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
0225 {
0226 struct bmi_cmd cmd;
0227 union bmi_resp resp;
0228 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
0229 u32 resplen = sizeof(resp.read_soc_reg);
0230 int ret;
0231
0232 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
0233 address);
0234
0235 if (ar->bmi.done_sent) {
0236 ath10k_warn(ar, "bmi read soc register command in progress\n");
0237 return -EBUSY;
0238 }
0239
0240 cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
0241 cmd.read_soc_reg.addr = __cpu_to_le32(address);
0242
0243 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
0244 if (ret) {
0245 ath10k_warn(ar, "Unable to read soc register from device: %d\n",
0246 ret);
0247 return ret;
0248 }
0249
0250 *reg_val = __le32_to_cpu(resp.read_soc_reg.value);
0251
0252 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
0253 *reg_val);
0254
0255 return 0;
0256 }
0257
0258 int ath10k_bmi_write_memory(struct ath10k *ar,
0259 u32 address, const void *buffer, u32 length)
0260 {
0261 struct bmi_cmd cmd;
0262 u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
0263 u32 txlen;
0264 int ret;
0265
0266 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
0267 address, length);
0268
0269 if (ar->bmi.done_sent) {
0270 ath10k_warn(ar, "command disallowed\n");
0271 return -EBUSY;
0272 }
0273
0274 while (length) {
0275 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
0276
0277
0278 memcpy(cmd.write_mem.payload, buffer, txlen);
0279 txlen = roundup(txlen, 4);
0280
0281 cmd.id = __cpu_to_le32(BMI_WRITE_MEMORY);
0282 cmd.write_mem.addr = __cpu_to_le32(address);
0283 cmd.write_mem.len = __cpu_to_le32(txlen);
0284
0285 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
0286 NULL, NULL);
0287 if (ret) {
0288 ath10k_warn(ar, "unable to write to the device (%d)\n",
0289 ret);
0290 return ret;
0291 }
0292
0293
0294 txlen = min(txlen, length);
0295
0296 address += txlen;
0297 buffer += txlen;
0298 length -= txlen;
0299 }
0300
0301 return 0;
0302 }
0303
0304 int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
0305 {
0306 struct bmi_cmd cmd;
0307 union bmi_resp resp;
0308 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
0309 u32 resplen = sizeof(resp.execute);
0310 int ret;
0311
0312 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
0313 address, param);
0314
0315 if (ar->bmi.done_sent) {
0316 ath10k_warn(ar, "command disallowed\n");
0317 return -EBUSY;
0318 }
0319
0320 cmd.id = __cpu_to_le32(BMI_EXECUTE);
0321 cmd.execute.addr = __cpu_to_le32(address);
0322 cmd.execute.param = __cpu_to_le32(param);
0323
0324 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
0325 if (ret) {
0326 ath10k_warn(ar, "unable to read from the device\n");
0327 return ret;
0328 }
0329
0330 if (resplen < sizeof(resp.execute)) {
0331 ath10k_warn(ar, "invalid execute response length (%d)\n",
0332 resplen);
0333 return -EIO;
0334 }
0335
0336 *result = __le32_to_cpu(resp.execute.result);
0337
0338 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
0339
0340 return 0;
0341 }
0342
0343 static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
0344 {
0345 struct bmi_cmd *cmd;
0346 u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
0347 u32 txlen;
0348 int ret;
0349 size_t buf_len;
0350
0351 ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
0352 buffer, length);
0353
0354 if (ar->bmi.done_sent) {
0355 ath10k_warn(ar, "command disallowed\n");
0356 return -EBUSY;
0357 }
0358
0359 buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
0360 cmd = kzalloc(buf_len, GFP_KERNEL);
0361 if (!cmd)
0362 return -ENOMEM;
0363
0364 while (length) {
0365 txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
0366
0367 WARN_ON_ONCE(txlen & 3);
0368
0369 cmd->id = __cpu_to_le32(BMI_LZ_DATA);
0370 cmd->lz_data.len = __cpu_to_le32(txlen);
0371 memcpy(cmd->lz_data.payload, buffer, txlen);
0372
0373 ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
0374 NULL, NULL);
0375 if (ret) {
0376 ath10k_warn(ar, "unable to write to the device\n");
0377 kfree(cmd);
0378 return ret;
0379 }
0380
0381 buffer += txlen;
0382 length -= txlen;
0383 }
0384
0385 kfree(cmd);
0386
0387 return 0;
0388 }
0389
0390 int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
0391 {
0392 struct bmi_cmd cmd;
0393 u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
0394 u32 txlen;
0395 int ret;
0396
0397 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%pK length %d\n",
0398 buffer, length);
0399
0400 if (ar->bmi.done_sent) {
0401 ath10k_warn(ar, "command disallowed\n");
0402 return -EBUSY;
0403 }
0404
0405 while (length) {
0406 txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
0407
0408 WARN_ON_ONCE(txlen & 3);
0409
0410 cmd.id = __cpu_to_le32(BMI_LZ_DATA);
0411 cmd.lz_data.len = __cpu_to_le32(txlen);
0412 memcpy(cmd.lz_data.payload, buffer, txlen);
0413
0414 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
0415 NULL, NULL);
0416 if (ret) {
0417 ath10k_warn(ar, "unable to write to the device\n");
0418 return ret;
0419 }
0420
0421 buffer += txlen;
0422 length -= txlen;
0423 }
0424
0425 return 0;
0426 }
0427
0428 int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
0429 {
0430 struct bmi_cmd cmd;
0431 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
0432 int ret;
0433
0434 ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
0435 address);
0436
0437 if (ar->bmi.done_sent) {
0438 ath10k_warn(ar, "command disallowed\n");
0439 return -EBUSY;
0440 }
0441
0442 cmd.id = __cpu_to_le32(BMI_LZ_STREAM_START);
0443 cmd.lz_start.addr = __cpu_to_le32(address);
0444
0445 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
0446 if (ret) {
0447 ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
0448 return ret;
0449 }
0450
0451 return 0;
0452 }
0453
0454 int ath10k_bmi_fast_download(struct ath10k *ar,
0455 u32 address, const void *buffer, u32 length)
0456 {
0457 u8 trailer[4] = {};
0458 u32 head_len = rounddown(length, 4);
0459 u32 trailer_len = length - head_len;
0460 int ret;
0461
0462 ath10k_dbg(ar, ATH10K_DBG_BMI,
0463 "bmi fast download address 0x%x buffer 0x%pK length %d\n",
0464 address, buffer, length);
0465
0466 ret = ath10k_bmi_lz_stream_start(ar, address);
0467 if (ret)
0468 return ret;
0469
0470
0471 if (trailer_len > 0)
0472 memcpy(trailer, buffer + head_len, trailer_len);
0473
0474 if (ar->hw_params.bmi_large_size_download)
0475 ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
0476 else
0477 ret = ath10k_bmi_lz_data(ar, buffer, head_len);
0478
0479 if (ret)
0480 return ret;
0481
0482 if (trailer_len > 0)
0483 ret = ath10k_bmi_lz_data(ar, trailer, 4);
0484
0485 if (ret != 0)
0486 return ret;
0487
0488
0489
0490
0491
0492 ret = ath10k_bmi_lz_stream_start(ar, 0x00);
0493
0494 return ret;
0495 }
0496
0497 int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
0498 {
0499 struct bmi_cmd cmd;
0500 u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
0501 int ret;
0502
0503 if (ar->bmi.done_sent) {
0504 ath10k_warn(ar, "bmi set start command disallowed\n");
0505 return -EBUSY;
0506 }
0507
0508 cmd.id = __cpu_to_le32(BMI_SET_APP_START);
0509 cmd.set_app_start.addr = __cpu_to_le32(address);
0510
0511 ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
0512 if (ret) {
0513 ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
0514 return ret;
0515 }
0516
0517 return 0;
0518 }