Release 4.12 drivers/firmware/qcom_scm.c
  
  
  
/*
 * Qualcomm SCM driver
 *
 * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
 * Copyright (C) 2015 Linaro Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/dma-mapping.h>
#include <linux/types.h>
#include <linux/qcom_scm.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/reset-controller.h>
#include "qcom_scm.h"
#define SCM_HAS_CORE_CLK	BIT(0)
#define SCM_HAS_IFACE_CLK	BIT(1)
#define SCM_HAS_BUS_CLK		BIT(2)
struct qcom_scm {
	
struct device *dev;
	
struct clk *core_clk;
	
struct clk *iface_clk;
	
struct clk *bus_clk;
	
struct reset_controller_dev reset;
};
static struct qcom_scm *__scm;
static int qcom_scm_clk_enable(void)
{
	int ret;
	ret = clk_prepare_enable(__scm->core_clk);
	if (ret)
		goto bail;
	ret = clk_prepare_enable(__scm->iface_clk);
	if (ret)
		goto disable_core;
	ret = clk_prepare_enable(__scm->bus_clk);
	if (ret)
		goto disable_iface;
	return 0;
disable_iface:
	clk_disable_unprepare(__scm->iface_clk);
disable_core:
	clk_disable_unprepare(__scm->core_clk);
bail:
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 85 | 100.00% | 1 | 100.00% | 
| Total | 85 | 100.00% | 1 | 100.00% | 
static void qcom_scm_clk_disable(void)
{
	clk_disable_unprepare(__scm->core_clk);
	clk_disable_unprepare(__scm->iface_clk);
	clk_disable_unprepare(__scm->bus_clk);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 29 | 100.00% | 1 | 100.00% | 
| Total | 29 | 100.00% | 1 | 100.00% | 
/**
 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
 * @entry: Entry point function for the cpus
 * @cpus: The cpumask of cpus that will use the entry point
 *
 * Set the cold boot address of the cpus. Any cpu outside the supported
 * range would be removed from the cpu present mask.
 */
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
{
	return __qcom_scm_set_cold_boot_addr(entry, cpus);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Lina Iyer | 20 | 90.91% | 1 | 50.00% | 
| Kumar Gala | 2 | 9.09% | 1 | 50.00% | 
| Total | 22 | 100.00% | 2 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
/**
 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
 * @entry: Entry point function for the cpus
 * @cpus: The cpumask of cpus that will use the entry point
 *
 * Set the Linux entry point for the SCM to transfer control to when coming
 * out of a power down. CPU power down may be executed on cpuidle or hotplug.
 */
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
{
	return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Lina Iyer | 20 | 76.92% | 1 | 33.33% | 
| Andy Gross | 4 | 15.38% | 1 | 33.33% | 
| Kumar Gala | 2 | 7.69% | 1 | 33.33% | 
| Total | 26 | 100.00% | 3 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
/**
 * qcom_scm_cpu_power_down() - Power down the cpu
 * @flags - Flags to flush cache
 *
 * This is an end point to power down cpu. If there was a pending interrupt,
 * the control would return from this function, otherwise, the cpu jumps to the
 * warm boot entry point set for this cpu upon reset.
 */
void qcom_scm_cpu_power_down(u32 flags)
{
	__qcom_scm_cpu_power_down(flags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Lina Iyer | 12 | 92.31% | 1 | 50.00% | 
| Kumar Gala | 1 | 7.69% | 1 | 50.00% | 
| Total | 13 | 100.00% | 2 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_cpu_power_down);
/**
 * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
 *
 * Return true if HDCP is supported, false if not.
 */
bool qcom_scm_hdcp_available(void)
{
	int ret = qcom_scm_clk_enable();
	if (ret)
		return ret;
	ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
						QCOM_SCM_CMD_HDCP);
	qcom_scm_clk_disable();
	return ret > 0 ? true : false;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Jilai Wang | 28 | 62.22% | 1 | 33.33% | 
| Andy Gross | 17 | 37.78% | 2 | 66.67% | 
| Total | 45 | 100.00% | 3 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_hdcp_available);
/**
 * qcom_scm_hdcp_req() - Send HDCP request.
 * @req: HDCP request array
 * @req_cnt: HDCP request array count
 * @resp: response buffer passed to SCM
 *
 * Write HDCP register(s) through SCM.
 */
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
{
	int ret = qcom_scm_clk_enable();
	if (ret)
		return ret;
	ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
	qcom_scm_clk_disable();
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Jilai Wang | 27 | 52.94% | 1 | 33.33% | 
| Andy Gross | 24 | 47.06% | 2 | 66.67% | 
| Total | 51 | 100.00% | 3 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_hdcp_req);
/**
 * qcom_scm_pas_supported() - Check if the peripheral authentication service is
 *                            available for the given peripherial
 * @peripheral: peripheral id
 *
 * Returns true if PAS is supported for this peripheral, otherwise false.
 */
bool qcom_scm_pas_supported(u32 peripheral)
{
	int ret;
	ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
					   QCOM_SCM_PAS_IS_SUPPORTED_CMD);
	if (ret <= 0)
		return false;
	return __qcom_scm_pas_supported(__scm->dev, peripheral);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 43 | 100.00% | 1 | 100.00% | 
| Total | 43 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_pas_supported);
/**
 * qcom_scm_pas_init_image() - Initialize peripheral authentication service
 *                             state machine for a given peripheral, using the
 *                             metadata
 * @peripheral: peripheral id
 * @metadata:   pointer to memory containing ELF header, program header table
 *              and optional blob of data used for authenticating the metadata
 *              and the rest of the firmware
 * @size:       size of the metadata
 *
 * Returns 0 on success.
 */
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
{
	dma_addr_t mdata_phys;
	void *mdata_buf;
	int ret;
	/*
         * During the scm call memory protection will be enabled for the meta
         * data blob, so make sure it's physically contiguous, 4K aligned and
         * non-cachable to avoid XPU violations.
         */
	mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
				       GFP_KERNEL);
	if (!mdata_buf) {
		dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
		return -ENOMEM;
	}
	memcpy(mdata_buf, metadata, size);
	ret = qcom_scm_clk_enable();
	if (ret)
		goto free_metadata;
	ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys);
	qcom_scm_clk_disable();
free_metadata:
	dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 118 | 100.00% | 1 | 100.00% | 
| Total | 118 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_pas_init_image);
/**
 * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
 *                            for firmware loading
 * @peripheral: peripheral id
 * @addr:       start address of memory area to prepare
 * @size:       size of the memory area to prepare
 *
 * Returns 0 on success.
 */
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
{
	int ret;
	ret = qcom_scm_clk_enable();
	if (ret)
		return ret;
	ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size);
	qcom_scm_clk_disable();
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 50 | 100.00% | 1 | 100.00% | 
| Total | 50 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
/**
 * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
 *                                 and reset the remote processor
 * @peripheral: peripheral id
 *
 * Return 0 on success.
 */
int qcom_scm_pas_auth_and_reset(u32 peripheral)
{
	int ret;
	ret = qcom_scm_clk_enable();
	if (ret)
		return ret;
	ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral);
	qcom_scm_clk_disable();
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 40 | 100.00% | 1 | 100.00% | 
| Total | 40 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
/**
 * qcom_scm_pas_shutdown() - Shut down the remote processor
 * @peripheral: peripheral id
 *
 * Returns 0 on success.
 */
int qcom_scm_pas_shutdown(u32 peripheral)
{
	int ret;
	ret = qcom_scm_clk_enable();
	if (ret)
		return ret;
	ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral);
	qcom_scm_clk_disable();
	return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 40 | 100.00% | 1 | 100.00% | 
| Total | 40 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_pas_shutdown);
static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
				     unsigned long idx)
{
	if (idx != 0)
		return -EINVAL;
	return __qcom_scm_pas_mss_reset(__scm->dev, 1);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 35 | 100.00% | 1 | 100.00% | 
| Total | 35 | 100.00% | 1 | 100.00% | 
static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
				       unsigned long idx)
{
	if (idx != 0)
		return -EINVAL;
	return __qcom_scm_pas_mss_reset(__scm->dev, 0);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Björn Andersson | 35 | 100.00% | 1 | 100.00% | 
| Total | 35 | 100.00% | 1 | 100.00% | 
static const struct reset_control_ops qcom_scm_pas_reset_ops = {
	.assert = qcom_scm_pas_reset_assert,
	.deassert = qcom_scm_pas_reset_deassert,
};
int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
{
	return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Rob Clark | 23 | 100.00% | 1 | 100.00% | 
| Total | 23 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
{
	return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Stanimir Varbanov | 24 | 100.00% | 1 | 100.00% | 
| Total | 24 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
{
	return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Stanimir Varbanov | 28 | 100.00% | 1 | 100.00% | 
| Total | 28 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
/**
 * qcom_scm_is_available() - Checks if SCM is available
 */
bool qcom_scm_is_available(void)
{
	return !!__scm;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 12 | 100.00% | 1 | 100.00% | 
| Total | 12 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_is_available);
int qcom_scm_set_remote_state(u32 state, u32 id)
{
	return __qcom_scm_set_remote_state(__scm->dev, state, id);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 23 | 100.00% | 1 | 100.00% | 
| Total | 23 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL(qcom_scm_set_remote_state);
static int qcom_scm_probe(struct platform_device *pdev)
{
	struct qcom_scm *scm;
	unsigned long clks;
	int ret;
	scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
	if (!scm)
		return -ENOMEM;
	clks = (unsigned long)of_device_get_match_data(&pdev->dev);
	if (clks & SCM_HAS_CORE_CLK) {
		scm->core_clk = devm_clk_get(&pdev->dev, "core");
		if (IS_ERR(scm->core_clk)) {
			if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER)
				dev_err(&pdev->dev,
					"failed to acquire core clk\n");
			return PTR_ERR(scm->core_clk);
		}
	}
	if (clks & SCM_HAS_IFACE_CLK) {
		scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
		if (IS_ERR(scm->iface_clk)) {
			if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
				dev_err(&pdev->dev,
					"failed to acquire iface clk\n");
			return PTR_ERR(scm->iface_clk);
		}
	}
	if (clks & SCM_HAS_BUS_CLK) {
		scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
		if (IS_ERR(scm->bus_clk)) {
			if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
				dev_err(&pdev->dev,
					"failed to acquire bus clk\n");
			return PTR_ERR(scm->bus_clk);
		}
	}
	scm->reset.ops = &qcom_scm_pas_reset_ops;
	scm->reset.nr_resets = 1;
	scm->reset.of_node = pdev->dev.of_node;
	ret = devm_reset_controller_register(&pdev->dev, &scm->reset);
	if (ret)
		return ret;
	/* vote for max clk rate for highest performance */
	ret = clk_set_rate(scm->core_clk, INT_MAX);
	if (ret)
		return ret;
	__scm = scm;
	__scm->dev = &pdev->dev;
	__qcom_scm_init();
	return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 240 | 70.18% | 1 | 16.67% | 
| Sarangdhar Joshi | 48 | 14.04% | 2 | 33.33% | 
| Björn Andersson | 36 | 10.53% | 1 | 16.67% | 
| Wei Yongjun | 15 | 4.39% | 1 | 16.67% | 
| Kumar Gala | 3 | 0.88% | 1 | 16.67% | 
| Total | 342 | 100.00% | 6 | 100.00% | 
static const struct of_device_id qcom_scm_dt_match[] = {
	{ .compatible = "qcom,scm-apq8064",
	  /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
	},
	{ .compatible = "qcom,scm-msm8660",
	  .data = (void *) SCM_HAS_CORE_CLK,
        },
	{ .compatible = "qcom,scm-msm8960",
	  .data = (void *) SCM_HAS_CORE_CLK,
        },
	{ .compatible = "qcom,scm-msm8996",
	  .data = NULL, /* no clocks */
	},
	{ .compatible = "qcom,scm",
	  .data = (void *)(SCM_HAS_CORE_CLK
			   | SCM_HAS_IFACE_CLK
			   | SCM_HAS_BUS_CLK),
        },
	{}
};
static struct platform_driver qcom_scm_driver = {
	.driver = {
		.name	= "qcom_scm",
		.of_match_table = qcom_scm_dt_match,
        },
	.probe = qcom_scm_probe,
};
static int __init qcom_scm_init(void)
{
	struct device_node *np, *fw_np;
	int ret;
	fw_np = of_find_node_by_name(NULL, "firmware");
	if (!fw_np)
		return -ENODEV;
	np = of_find_matching_node(fw_np, qcom_scm_dt_match);
	if (!np) {
		of_node_put(fw_np);
		return -ENODEV;
	}
	of_node_put(np);
	ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL);
	of_node_put(fw_np);
	if (ret)
		return ret;
	return platform_driver_register(&qcom_scm_driver);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 100 | 100.00% | 1 | 100.00% | 
| Total | 100 | 100.00% | 1 | 100.00% | 
subsys_initcall(qcom_scm_init);
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp | 
| Andy Gross | 659 | 44.17% | 6 | 27.27% | 
| Björn Andersson | 455 | 30.50% | 2 | 9.09% | 
| Sarangdhar Joshi | 111 | 7.44% | 2 | 9.09% | 
| Jilai Wang | 67 | 4.49% | 1 | 4.55% | 
| Lina Iyer | 66 | 4.42% | 3 | 13.64% | 
| Stanimir Varbanov | 62 | 4.16% | 1 | 4.55% | 
| Rob Clark | 28 | 1.88% | 1 | 4.55% | 
| Kumar Gala | 19 | 1.27% | 3 | 13.64% | 
| Wei Yongjun | 15 | 1.01% | 1 | 4.55% | 
| Stephen Boyd | 8 | 0.54% | 1 | 4.55% | 
| Paul Gortmaker | 2 | 0.13% | 1 | 4.55% | 
| Total | 1492 | 100.00% | 22 | 100.00% | 
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.