1 /* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. 2 * Copyright (C) 2015 Linaro Ltd. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 #include <linux/platform_device.h> 15 #include <linux/module.h> 16 #include <linux/cpumask.h> 17 #include <linux/export.h> 18 #include <linux/dma-mapping.h> 19 #include <linux/types.h> 20 #include <linux/qcom_scm.h> 21 #include <linux/of.h> 22 #include <linux/of_platform.h> 23 #include <linux/clk.h> 24 #include <linux/reset-controller.h> 25 26 #include "qcom_scm.h" 27 28 struct qcom_scm { 29 struct device *dev; 30 struct clk *core_clk; 31 struct clk *iface_clk; 32 struct clk *bus_clk; 33 struct reset_controller_dev reset; 34 }; 35 36 static struct qcom_scm *__scm; 37 38 static int qcom_scm_clk_enable(void) 39 { 40 int ret; 41 42 ret = clk_prepare_enable(__scm->core_clk); 43 if (ret) 44 goto bail; 45 46 ret = clk_prepare_enable(__scm->iface_clk); 47 if (ret) 48 goto disable_core; 49 50 ret = clk_prepare_enable(__scm->bus_clk); 51 if (ret) 52 goto disable_iface; 53 54 return 0; 55 56 disable_iface: 57 clk_disable_unprepare(__scm->iface_clk); 58 disable_core: 59 clk_disable_unprepare(__scm->core_clk); 60 bail: 61 return ret; 62 } 63 64 static void qcom_scm_clk_disable(void) 65 { 66 clk_disable_unprepare(__scm->core_clk); 67 clk_disable_unprepare(__scm->iface_clk); 68 clk_disable_unprepare(__scm->bus_clk); 69 } 70 71 /** 72 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus 73 * @entry: Entry point function for the cpus 74 * @cpus: The cpumask of cpus that will use the entry point 75 * 76 * Set the cold boot address of the cpus. Any cpu outside the supported 77 * range would be removed from the cpu present mask. 78 */ 79 int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) 80 { 81 return __qcom_scm_set_cold_boot_addr(entry, cpus); 82 } 83 EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); 84 85 /** 86 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus 87 * @entry: Entry point function for the cpus 88 * @cpus: The cpumask of cpus that will use the entry point 89 * 90 * Set the Linux entry point for the SCM to transfer control to when coming 91 * out of a power down. CPU power down may be executed on cpuidle or hotplug. 92 */ 93 int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) 94 { 95 return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus); 96 } 97 EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); 98 99 /** 100 * qcom_scm_cpu_power_down() - Power down the cpu 101 * @flags - Flags to flush cache 102 * 103 * This is an end point to power down cpu. If there was a pending interrupt, 104 * the control would return from this function, otherwise, the cpu jumps to the 105 * warm boot entry point set for this cpu upon reset. 106 */ 107 void qcom_scm_cpu_power_down(u32 flags) 108 { 109 __qcom_scm_cpu_power_down(flags); 110 } 111 EXPORT_SYMBOL(qcom_scm_cpu_power_down); 112 113 /** 114 * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. 115 * 116 * Return true if HDCP is supported, false if not. 117 */ 118 bool qcom_scm_hdcp_available(void) 119 { 120 int ret = qcom_scm_clk_enable(); 121 122 if (ret) 123 return ret; 124 125 ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP, 126 QCOM_SCM_CMD_HDCP); 127 128 qcom_scm_clk_disable(); 129 130 return ret > 0 ? true : false; 131 } 132 EXPORT_SYMBOL(qcom_scm_hdcp_available); 133 134 /** 135 * qcom_scm_hdcp_req() - Send HDCP request. 136 * @req: HDCP request array 137 * @req_cnt: HDCP request array count 138 * @resp: response buffer passed to SCM 139 * 140 * Write HDCP register(s) through SCM. 141 */ 142 int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) 143 { 144 int ret = qcom_scm_clk_enable(); 145 146 if (ret) 147 return ret; 148 149 ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp); 150 qcom_scm_clk_disable(); 151 return ret; 152 } 153 EXPORT_SYMBOL(qcom_scm_hdcp_req); 154 155 /** 156 * qcom_scm_pas_supported() - Check if the peripheral authentication service is 157 * available for the given peripherial 158 * @peripheral: peripheral id 159 * 160 * Returns true if PAS is supported for this peripheral, otherwise false. 161 */ 162 bool qcom_scm_pas_supported(u32 peripheral) 163 { 164 int ret; 165 166 ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, 167 QCOM_SCM_PAS_IS_SUPPORTED_CMD); 168 if (ret <= 0) 169 return false; 170 171 return __qcom_scm_pas_supported(__scm->dev, peripheral); 172 } 173 EXPORT_SYMBOL(qcom_scm_pas_supported); 174 175 /** 176 * qcom_scm_pas_init_image() - Initialize peripheral authentication service 177 * state machine for a given peripheral, using the 178 * metadata 179 * @peripheral: peripheral id 180 * @metadata: pointer to memory containing ELF header, program header table 181 * and optional blob of data used for authenticating the metadata 182 * and the rest of the firmware 183 * @size: size of the metadata 184 * 185 * Returns 0 on success. 186 */ 187 int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) 188 { 189 dma_addr_t mdata_phys; 190 void *mdata_buf; 191 int ret; 192 193 /* 194 * During the scm call memory protection will be enabled for the meta 195 * data blob, so make sure it's physically contiguous, 4K aligned and 196 * non-cachable to avoid XPU violations. 197 */ 198 mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, 199 GFP_KERNEL); 200 if (!mdata_buf) { 201 dev_err(__scm->dev, "Allocation of metadata buffer failed.\n"); 202 return -ENOMEM; 203 } 204 memcpy(mdata_buf, metadata, size); 205 206 ret = qcom_scm_clk_enable(); 207 if (ret) 208 goto free_metadata; 209 210 ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys); 211 212 qcom_scm_clk_disable(); 213 214 free_metadata: 215 dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); 216 217 return ret; 218 } 219 EXPORT_SYMBOL(qcom_scm_pas_init_image); 220 221 /** 222 * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral 223 * for firmware loading 224 * @peripheral: peripheral id 225 * @addr: start address of memory area to prepare 226 * @size: size of the memory area to prepare 227 * 228 * Returns 0 on success. 229 */ 230 int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) 231 { 232 int ret; 233 234 ret = qcom_scm_clk_enable(); 235 if (ret) 236 return ret; 237 238 ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size); 239 qcom_scm_clk_disable(); 240 241 return ret; 242 } 243 EXPORT_SYMBOL(qcom_scm_pas_mem_setup); 244 245 /** 246 * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware 247 * and reset the remote processor 248 * @peripheral: peripheral id 249 * 250 * Return 0 on success. 251 */ 252 int qcom_scm_pas_auth_and_reset(u32 peripheral) 253 { 254 int ret; 255 256 ret = qcom_scm_clk_enable(); 257 if (ret) 258 return ret; 259 260 ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral); 261 qcom_scm_clk_disable(); 262 263 return ret; 264 } 265 EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); 266 267 /** 268 * qcom_scm_pas_shutdown() - Shut down the remote processor 269 * @peripheral: peripheral id 270 * 271 * Returns 0 on success. 272 */ 273 int qcom_scm_pas_shutdown(u32 peripheral) 274 { 275 int ret; 276 277 ret = qcom_scm_clk_enable(); 278 if (ret) 279 return ret; 280 281 ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral); 282 qcom_scm_clk_disable(); 283 284 return ret; 285 } 286 EXPORT_SYMBOL(qcom_scm_pas_shutdown); 287 288 static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev, 289 unsigned long idx) 290 { 291 if (idx != 0) 292 return -EINVAL; 293 294 return __qcom_scm_pas_mss_reset(__scm->dev, 1); 295 } 296 297 static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev, 298 unsigned long idx) 299 { 300 if (idx != 0) 301 return -EINVAL; 302 303 return __qcom_scm_pas_mss_reset(__scm->dev, 0); 304 } 305 306 static const struct reset_control_ops qcom_scm_pas_reset_ops = { 307 .assert = qcom_scm_pas_reset_assert, 308 .deassert = qcom_scm_pas_reset_deassert, 309 }; 310 311 /** 312 * qcom_scm_is_available() - Checks if SCM is available 313 */ 314 bool qcom_scm_is_available(void) 315 { 316 return !!__scm; 317 } 318 EXPORT_SYMBOL(qcom_scm_is_available); 319 320 static int qcom_scm_probe(struct platform_device *pdev) 321 { 322 struct qcom_scm *scm; 323 int ret; 324 325 scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); 326 if (!scm) 327 return -ENOMEM; 328 329 scm->core_clk = devm_clk_get(&pdev->dev, "core"); 330 if (IS_ERR(scm->core_clk)) { 331 if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) 332 return PTR_ERR(scm->core_clk); 333 334 scm->core_clk = NULL; 335 } 336 337 if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) { 338 scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); 339 if (IS_ERR(scm->iface_clk)) { 340 if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) 341 dev_err(&pdev->dev, "failed to acquire iface clk\n"); 342 return PTR_ERR(scm->iface_clk); 343 } 344 345 scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); 346 if (IS_ERR(scm->bus_clk)) { 347 if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) 348 dev_err(&pdev->dev, "failed to acquire bus clk\n"); 349 return PTR_ERR(scm->bus_clk); 350 } 351 } 352 353 scm->reset.ops = &qcom_scm_pas_reset_ops; 354 scm->reset.nr_resets = 1; 355 scm->reset.of_node = pdev->dev.of_node; 356 reset_controller_register(&scm->reset); 357 358 /* vote for max clk rate for highest performance */ 359 ret = clk_set_rate(scm->core_clk, INT_MAX); 360 if (ret) 361 return ret; 362 363 __scm = scm; 364 __scm->dev = &pdev->dev; 365 366 __qcom_scm_init(); 367 368 return 0; 369 } 370 371 static const struct of_device_id qcom_scm_dt_match[] = { 372 { .compatible = "qcom,scm-apq8064",}, 373 { .compatible = "qcom,scm-msm8660",}, 374 { .compatible = "qcom,scm-msm8960",}, 375 { .compatible = "qcom,scm",}, 376 {} 377 }; 378 379 MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); 380 381 static struct platform_driver qcom_scm_driver = { 382 .driver = { 383 .name = "qcom_scm", 384 .of_match_table = qcom_scm_dt_match, 385 }, 386 .probe = qcom_scm_probe, 387 }; 388 389 static int __init qcom_scm_init(void) 390 { 391 struct device_node *np, *fw_np; 392 int ret; 393 394 fw_np = of_find_node_by_name(NULL, "firmware"); 395 396 if (!fw_np) 397 return -ENODEV; 398 399 np = of_find_matching_node(fw_np, qcom_scm_dt_match); 400 401 if (!np) { 402 of_node_put(fw_np); 403 return -ENODEV; 404 } 405 406 of_node_put(np); 407 408 ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL); 409 410 of_node_put(fw_np); 411 412 if (ret) 413 return ret; 414 415 return platform_driver_register(&qcom_scm_driver); 416 } 417 418 subsys_initcall(qcom_scm_init); 419 420 static void __exit qcom_scm_exit(void) 421 { 422 platform_driver_unregister(&qcom_scm_driver); 423 } 424 module_exit(qcom_scm_exit); 425 426 MODULE_DESCRIPTION("Qualcomm SCM driver"); 427 MODULE_LICENSE("GPL v2"); 428