1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2016, Linaro Ltd. 4 * Copyright (c) 2015, Sony Mobile Communications Inc. 5 */ 6 #include <linux/firmware.h> 7 #include <linux/module.h> 8 #include <linux/slab.h> 9 #include <linux/io.h> 10 #include <linux/of.h> 11 #include <linux/of_platform.h> 12 #include <linux/platform_device.h> 13 #include <linux/rpmsg.h> 14 #include <linux/soc/qcom/wcnss_ctrl.h> 15 16 #define WCNSS_REQUEST_TIMEOUT (5 * HZ) 17 #define WCNSS_CBC_TIMEOUT (10 * HZ) 18 19 #define WCNSS_ACK_DONE_BOOTING 1 20 #define WCNSS_ACK_COLD_BOOTING 2 21 22 #define NV_FRAGMENT_SIZE 3072 23 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" 24 25 /** 26 * struct wcnss_ctrl - driver context 27 * @dev: device handle 28 * @channel: SMD channel handle 29 * @ack: completion for outstanding requests 30 * @cbc: completion for cbc complete indication 31 * @ack_status: status of the outstanding request 32 * @probe_work: worker for uploading nv binary 33 */ 34 struct wcnss_ctrl { 35 struct device *dev; 36 struct rpmsg_endpoint *channel; 37 38 struct completion ack; 39 struct completion cbc; 40 int ack_status; 41 42 struct work_struct probe_work; 43 }; 44 45 /* message types */ 46 enum { 47 WCNSS_VERSION_REQ = 0x01000000, 48 WCNSS_VERSION_RESP, 49 WCNSS_DOWNLOAD_NV_REQ, 50 WCNSS_DOWNLOAD_NV_RESP, 51 WCNSS_UPLOAD_CAL_REQ, 52 WCNSS_UPLOAD_CAL_RESP, 53 WCNSS_DOWNLOAD_CAL_REQ, 54 WCNSS_DOWNLOAD_CAL_RESP, 55 WCNSS_VBAT_LEVEL_IND, 56 WCNSS_BUILD_VERSION_REQ, 57 WCNSS_BUILD_VERSION_RESP, 58 WCNSS_PM_CONFIG_REQ, 59 WCNSS_CBC_COMPLETE_IND, 60 }; 61 62 /** 63 * struct wcnss_msg_hdr - common packet header for requests and responses 64 * @type: packet message type 65 * @len: total length of the packet, including this header 66 */ 67 struct wcnss_msg_hdr { 68 u32 type; 69 u32 len; 70 } __packed; 71 72 /* 73 * struct wcnss_version_resp - version request response 74 */ 75 struct wcnss_version_resp { 76 struct wcnss_msg_hdr hdr; 77 u8 major; 78 u8 minor; 79 u8 version; 80 u8 revision; 81 } __packed; 82 83 /** 84 * struct wcnss_download_nv_req - firmware fragment request 85 * @hdr: common packet wcnss_msg_hdr header 86 * @seq: sequence number of this fragment 87 * @last: boolean indicator of this being the last fragment of the binary 88 * @frag_size: length of this fragment 89 * @fragment: fragment data 90 */ 91 struct wcnss_download_nv_req { 92 struct wcnss_msg_hdr hdr; 93 u16 seq; 94 u16 last; 95 u32 frag_size; 96 u8 fragment[]; 97 } __packed; 98 99 /** 100 * struct wcnss_download_nv_resp - firmware download response 101 * @hdr: common packet wcnss_msg_hdr header 102 * @status: boolean to indicate success of the download 103 */ 104 struct wcnss_download_nv_resp { 105 struct wcnss_msg_hdr hdr; 106 u8 status; 107 } __packed; 108 109 /** 110 * wcnss_ctrl_smd_callback() - handler from SMD responses 111 * @rpdev: remote processor message device pointer 112 * @data: pointer to the incoming data packet 113 * @count: size of the incoming data packet 114 * @priv: unused 115 * @addr: unused 116 * 117 * Handles any incoming packets from the remote WCNSS_CTRL service. 118 */ 119 static int wcnss_ctrl_smd_callback(struct rpmsg_device *rpdev, 120 void *data, 121 int count, 122 void *priv, 123 u32 addr) 124 { 125 struct wcnss_ctrl *wcnss = dev_get_drvdata(&rpdev->dev); 126 const struct wcnss_download_nv_resp *nvresp; 127 const struct wcnss_version_resp *version; 128 const struct wcnss_msg_hdr *hdr = data; 129 130 switch (hdr->type) { 131 case WCNSS_VERSION_RESP: 132 if (count != sizeof(*version)) { 133 dev_err(wcnss->dev, 134 "invalid size of version response\n"); 135 break; 136 } 137 138 version = data; 139 dev_info(wcnss->dev, "WCNSS Version %d.%d %d.%d\n", 140 version->major, version->minor, 141 version->version, version->revision); 142 143 complete(&wcnss->ack); 144 break; 145 case WCNSS_DOWNLOAD_NV_RESP: 146 if (count != sizeof(*nvresp)) { 147 dev_err(wcnss->dev, 148 "invalid size of download response\n"); 149 break; 150 } 151 152 nvresp = data; 153 wcnss->ack_status = nvresp->status; 154 complete(&wcnss->ack); 155 break; 156 case WCNSS_CBC_COMPLETE_IND: 157 dev_dbg(wcnss->dev, "cold boot complete\n"); 158 complete(&wcnss->cbc); 159 break; 160 default: 161 dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); 162 break; 163 } 164 165 return 0; 166 } 167 168 /** 169 * wcnss_request_version() - send a version request to WCNSS 170 * @wcnss: wcnss ctrl driver context 171 */ 172 static int wcnss_request_version(struct wcnss_ctrl *wcnss) 173 { 174 struct wcnss_msg_hdr msg; 175 int ret; 176 177 msg.type = WCNSS_VERSION_REQ; 178 msg.len = sizeof(msg); 179 ret = rpmsg_send(wcnss->channel, &msg, sizeof(msg)); 180 if (ret < 0) 181 return ret; 182 183 ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT); 184 if (!ret) { 185 dev_err(wcnss->dev, "timeout waiting for version response\n"); 186 return -ETIMEDOUT; 187 } 188 189 return 0; 190 } 191 192 /** 193 * wcnss_download_nv() - send nv binary to WCNSS 194 * @wcnss: wcnss_ctrl state handle 195 * @expect_cbc: indicator to caller that an cbc event is expected 196 * 197 * Returns 0 on success. Negative errno on failure. 198 */ 199 static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) 200 { 201 struct wcnss_download_nv_req *req; 202 const struct firmware *fw; 203 struct device *dev = wcnss->dev; 204 const char *nvbin = NVBIN_FILE; 205 const void *data; 206 ssize_t left; 207 int ret; 208 209 req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); 210 if (!req) 211 return -ENOMEM; 212 213 ret = of_property_read_string(dev->of_node, "firmware-name", &nvbin); 214 if (ret < 0 && ret != -EINVAL) 215 goto free_req; 216 217 ret = request_firmware(&fw, nvbin, dev); 218 if (ret < 0) { 219 dev_err(dev, "Failed to load nv file %s: %d\n", nvbin, ret); 220 goto free_req; 221 } 222 223 data = fw->data; 224 left = fw->size; 225 226 req->hdr.type = WCNSS_DOWNLOAD_NV_REQ; 227 req->hdr.len = sizeof(*req) + NV_FRAGMENT_SIZE; 228 229 req->last = 0; 230 req->frag_size = NV_FRAGMENT_SIZE; 231 232 req->seq = 0; 233 do { 234 if (left <= NV_FRAGMENT_SIZE) { 235 req->last = 1; 236 req->frag_size = left; 237 req->hdr.len = sizeof(*req) + left; 238 } 239 240 memcpy(req->fragment, data, req->frag_size); 241 242 ret = rpmsg_send(wcnss->channel, req, req->hdr.len); 243 if (ret < 0) { 244 dev_err(dev, "failed to send smd packet\n"); 245 goto release_fw; 246 } 247 248 /* Increment for next fragment */ 249 req->seq++; 250 251 data += NV_FRAGMENT_SIZE; 252 left -= NV_FRAGMENT_SIZE; 253 } while (left > 0); 254 255 ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); 256 if (!ret) { 257 dev_err(dev, "timeout waiting for nv upload ack\n"); 258 ret = -ETIMEDOUT; 259 } else { 260 *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING; 261 ret = 0; 262 } 263 264 release_fw: 265 release_firmware(fw); 266 free_req: 267 kfree(req); 268 269 return ret; 270 } 271 272 /** 273 * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS 274 * @wcnss: wcnss handle, retrieved from drvdata 275 * @name: SMD channel name 276 * @cb: callback to handle incoming data on the channel 277 * @priv: private data for use in the call-back 278 */ 279 struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rpmsg_rx_cb_t cb, void *priv) 280 { 281 struct rpmsg_channel_info chinfo; 282 struct wcnss_ctrl *_wcnss = wcnss; 283 284 strscpy(chinfo.name, name, sizeof(chinfo.name)); 285 chinfo.src = RPMSG_ADDR_ANY; 286 chinfo.dst = RPMSG_ADDR_ANY; 287 288 return rpmsg_create_ept(_wcnss->channel->rpdev, cb, priv, chinfo); 289 } 290 EXPORT_SYMBOL_GPL(qcom_wcnss_open_channel); 291 292 static void wcnss_async_probe(struct work_struct *work) 293 { 294 struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work); 295 bool expect_cbc; 296 int ret; 297 298 ret = wcnss_request_version(wcnss); 299 if (ret < 0) 300 return; 301 302 ret = wcnss_download_nv(wcnss, &expect_cbc); 303 if (ret < 0) 304 return; 305 306 /* Wait for pending cold boot completion if indicated by the nv downloader */ 307 if (expect_cbc) { 308 ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT); 309 if (!ret) 310 dev_err(wcnss->dev, "expected cold boot completion\n"); 311 } 312 313 of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); 314 } 315 316 static int wcnss_ctrl_probe(struct rpmsg_device *rpdev) 317 { 318 struct wcnss_ctrl *wcnss; 319 320 wcnss = devm_kzalloc(&rpdev->dev, sizeof(*wcnss), GFP_KERNEL); 321 if (!wcnss) 322 return -ENOMEM; 323 324 wcnss->dev = &rpdev->dev; 325 wcnss->channel = rpdev->ept; 326 327 init_completion(&wcnss->ack); 328 init_completion(&wcnss->cbc); 329 INIT_WORK(&wcnss->probe_work, wcnss_async_probe); 330 331 dev_set_drvdata(&rpdev->dev, wcnss); 332 333 schedule_work(&wcnss->probe_work); 334 335 return 0; 336 } 337 338 static void wcnss_ctrl_remove(struct rpmsg_device *rpdev) 339 { 340 struct wcnss_ctrl *wcnss = dev_get_drvdata(&rpdev->dev); 341 342 cancel_work_sync(&wcnss->probe_work); 343 of_platform_depopulate(&rpdev->dev); 344 } 345 346 static const struct of_device_id wcnss_ctrl_of_match[] = { 347 { .compatible = "qcom,wcnss", }, 348 {} 349 }; 350 MODULE_DEVICE_TABLE(of, wcnss_ctrl_of_match); 351 352 static struct rpmsg_driver wcnss_ctrl_driver = { 353 .probe = wcnss_ctrl_probe, 354 .remove = wcnss_ctrl_remove, 355 .callback = wcnss_ctrl_smd_callback, 356 .drv = { 357 .name = "qcom_wcnss_ctrl", 358 .of_match_table = wcnss_ctrl_of_match, 359 }, 360 }; 361 362 module_rpmsg_driver(wcnss_ctrl_driver); 363 364 MODULE_DESCRIPTION("Qualcomm WCNSS control driver"); 365 MODULE_LICENSE("GPL v2"); 366