mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Qualcomm ARM Based Driver Updates for v4.20
* Refactor of SCM compatibles and clock requirements * SMEM cleanup * Add LLCC EDAC driver * Fixes for GENI clocks and macros * Fix includes for llcc-slice and smem * String overflow fixes for APR and wcnss_ctrl * Fixup for COMPILE_TEST of qcom driver Kconfigs * Cleanup of Kconfig depends of rpmh, smd_rpm, smsm, and smp2p * Add SCM dependencies to SPM and rmtfs-mem -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJbsQupAAoJEFKiBbHx2RXVQBYQAKWr3RsQlWJ09M0vm8qGeCCA 8FXxX9wqcU34KvYR16IIXzQ/25L4h1uLjvjBfQurn7zOFIrCoqn2PGOchGOyJEA0 hPw+RomT17BV1hRSJkl8lIXMqGCAvoc44VrAQyipCTpEJO82emh6qJ1ki5XpIvfI EOad6S2IGNXU39F0B6rtl4+LL/Vfh+MOJcz0E23SVujtDT0pvxuP5aVGM+Faqif/ rQ4dKcYZokRHmuTlfg2azo4OmkLyrwsMjirna3NN3MX14wK5Ox53ESplGZXndt3V Gy48IbXdTTjbmHT07aqPVSkFgulkaE9Z3MTw+vyn/r10ww6R55XtoSJIbS/v4+Y0 mzjTYTSHmxzpGHR4Rs+E1q9/7y8tbxO0uzFMHlmD8fNNbkK3FlXymGfVJFjSJGSN hTN97zEYUKco4M6RXAly8XUrOetSglZwul1+gQnHYYCx7Y8BhgpyZtyjVeKzg1Mw wqgAi+1+cOLG2JjI+h0Xo0xqvuWwl3e2jrmBZNs9BWoXaaWA2L7oqPL3bxq2TeWs kF56I7YH5eD5sUGvShjrJ9WfKeN4hWpYSif/qg58kqz/zbCSjmmfiqQ7HmjJUetm JnAZaik38YhsDvR8K1gECQiN2myjojjdyg3ONBk2y0Yho+ClVSMPo/qCceRy21/q LVTRThQ0tZExH8zEJrJt =rx3Z -----END PGP SIGNATURE----- Merge tag 'qcom-drivers-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/drivers Qualcomm ARM Based Driver Updates for v4.20 * Refactor of SCM compatibles and clock requirements * SMEM cleanup * Add LLCC EDAC driver * Fixes for GENI clocks and macros * Fix includes for llcc-slice and smem * String overflow fixes for APR and wcnss_ctrl * Fixup for COMPILE_TEST of qcom driver Kconfigs * Cleanup of Kconfig depends of rpmh, smd_rpm, smsm, and smp2p * Add SCM dependencies to SPM and rmtfs-mem * tag 'qcom-drivers-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux: (38 commits) soc: qcom: geni: geni_se_clk_freq_match() should always accept multiples soc: qcom: geni: Don't ignore clk_round_rate() errors in geni_se_clk_tbl_get() soc: qcom: geni: Make version macros simpler dt-bindings: firmware: scm: Add MSM8998 and SDM845 firmware: qcom: scm: Refactor clock handling dt-bindings: firmware: scm: Refactor compatibles and clocks soc: qcom: smem: a few last cleanups soc: qcom: smem: verify partition host ids match soc: qcom: smem: small change in global entry loop soc: qcom: smem: verify partition offset_free_uncached soc: qcom: smem: verify partition header size soc: qcom: smem: introduce qcom_smem_partition_header() soc: qcom: smem: require order of host ids to match soc: qcom: smem: verify both host ids in partition header soc: qcom: smem: small refactor in qcom_smem_enumerate_partitions() soc: qcom: smem: always ignore partitions with 0 offset or size soc: qcom: smem: initialize region struct only when successful soc: qcom: smem: rename variable in qcom_smem_get_global() drivers: qcom: rpmh-rsc: clear wait_for_compl after use soc: qcom: rmtfs-mem: Validate that scm is available ... Signed-off-by: Arnd Bergmann <[email protected]>
This commit is contained in:
commit
64d20b774f
18 changed files with 732 additions and 202 deletions
|
|
@ -33,7 +33,7 @@ config QCOM_GLINK_SSR
|
|||
|
||||
config QCOM_GSBI
|
||||
tristate "QCOM General Serial Bus Interface"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Say y here to enable GSBI support. The GSBI provides control
|
||||
|
|
@ -42,7 +42,7 @@ config QCOM_GSBI
|
|||
|
||||
config QCOM_LLCC
|
||||
tristate "Qualcomm Technologies, Inc. LLCC driver"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
help
|
||||
Qualcomm Technologies, Inc. platform specific
|
||||
Last Level Cache Controller(LLCC) driver. This provides interfaces
|
||||
|
|
@ -73,7 +73,8 @@ config QCOM_PM
|
|||
|
||||
config QCOM_QMI_HELPERS
|
||||
tristate
|
||||
depends on ARCH_QCOM && NET
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on NET
|
||||
help
|
||||
Helper library for handling QMI encoded messages. QMI encoded
|
||||
messages are used in communication between the majority of QRTR
|
||||
|
|
@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM
|
|||
|
||||
config QCOM_RPMH
|
||||
bool "Qualcomm RPM-Hardened (RPMH) Communication"
|
||||
depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
|
||||
depends on ARCH_QCOM && ARM64 || COMPILE_TEST
|
||||
help
|
||||
Support for communication with the hardened-RPM blocks in
|
||||
Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
|
||||
|
|
@ -104,7 +105,7 @@ config QCOM_RPMH
|
|||
|
||||
config QCOM_SMEM
|
||||
tristate "Qualcomm Shared Memory Manager (SMEM)"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on HWSPINLOCK
|
||||
help
|
||||
Say y here to enable support for the Qualcomm Shared Memory Manager.
|
||||
|
|
@ -113,8 +114,8 @@ config QCOM_SMEM
|
|||
|
||||
config QCOM_SMD_RPM
|
||||
tristate "Qualcomm Resource Power Manager (RPM) over SMD"
|
||||
depends on ARCH_QCOM
|
||||
depends on RPMSG && OF
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on RPMSG
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Resource Power Manager system found in the Qualcomm 8974 based
|
||||
|
|
@ -134,6 +135,7 @@ config QCOM_SMP2P
|
|||
depends on MAILBOX
|
||||
depends on QCOM_SMEM
|
||||
select QCOM_SMEM_STATE
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to support the Qualcomm Shared Memory Point to Point
|
||||
protocol.
|
||||
|
|
@ -142,13 +144,14 @@ config QCOM_SMSM
|
|||
tristate "Qualcomm Shared Memory State Machine"
|
||||
depends on QCOM_SMEM
|
||||
select QCOM_SMEM_STATE
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to support the Qualcomm Shared Memory State Machine.
|
||||
The state machine is represented by bits in shared memory.
|
||||
|
||||
config QCOM_WCNSS_CTRL
|
||||
tristate "Qualcomm WCNSS control driver"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on RPMSG
|
||||
help
|
||||
Client driver for the WCNSS_CTRL SMD channel, used to download nv
|
||||
|
|
@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL
|
|||
|
||||
config QCOM_APR
|
||||
tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on RPMSG
|
||||
help
|
||||
Enable APR IPC protocol support between
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
|
|||
}
|
||||
|
||||
if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) {
|
||||
dev_err(apr->dev, "APR: Wrong paket size\n");
|
||||
dev_err(apr->dev, "APR: Wrong packet size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np,
|
|||
adev->domain_id = id->domain_id;
|
||||
adev->version = id->svc_version;
|
||||
if (np)
|
||||
strncpy(adev->name, np->name, APR_NAME_SIZE);
|
||||
strscpy(adev->name, np->name, APR_NAME_SIZE);
|
||||
else
|
||||
strncpy(adev->name, id->name, APR_NAME_SIZE);
|
||||
strscpy(adev->name, id->name, APR_NAME_SIZE);
|
||||
|
||||
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
|
||||
id->domain_id, id->svc_id);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/llcc-qcom.h>
|
||||
|
||||
|
|
@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid,
|
|||
u32 slice_status;
|
||||
int ret;
|
||||
|
||||
act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid);
|
||||
status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid);
|
||||
act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
|
||||
status_reg = LLCC_TRP_STATUSn(sid);
|
||||
|
||||
/* Set the ACTIVE trigger */
|
||||
act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
|
||||
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
|
||||
ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
|
||||
act_ctrl_reg_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Clear the ACTIVE trigger */
|
||||
act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
|
||||
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
|
||||
ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
|
||||
act_ctrl_reg_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(drv_data->regmap, status_reg,
|
||||
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
|
||||
slice_status, !(slice_status & status),
|
||||
0, LLCC_STATUS_READ_DELAY);
|
||||
return ret;
|
||||
|
|
@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
|
|||
u32 attr0_val;
|
||||
u32 max_cap_cacheline;
|
||||
u32 sz;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
const struct llcc_slice_config *llcc_table;
|
||||
struct llcc_slice_desc desc;
|
||||
u32 bcast_off = drv_data->bcast_off;
|
||||
|
||||
sz = drv_data->cfg_size;
|
||||
llcc_table = drv_data->cfg;
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
attr1_cfg = bcast_off +
|
||||
LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
|
||||
attr0_cfg = bcast_off +
|
||||
LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
|
||||
attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
|
||||
attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
|
||||
|
||||
attr1_val = llcc_table[i].cache_mode;
|
||||
attr1_val |= llcc_table[i].probe_target_ways <<
|
||||
|
|
@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
|
|||
attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
|
||||
attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
|
||||
|
||||
ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val);
|
||||
ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
|
||||
attr1_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val);
|
||||
ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
|
||||
attr0_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (llcc_table[i].activate_on_init) {
|
||||
|
|
@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev,
|
|||
{
|
||||
u32 num_banks;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct resource *llcc_banks_res, *llcc_bcast_res;
|
||||
void __iomem *llcc_banks_base, *llcc_bcast_base;
|
||||
int ret, i;
|
||||
struct platform_device *llcc_edac;
|
||||
|
||||
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"llcc_base");
|
||||
llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
|
||||
if (IS_ERR(llcc_banks_base))
|
||||
return PTR_ERR(llcc_banks_base);
|
||||
|
||||
drv_data->regmap = devm_regmap_init_mmio(dev, base,
|
||||
&llcc_regmap_config);
|
||||
drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
|
||||
&llcc_regmap_config);
|
||||
if (IS_ERR(drv_data->regmap))
|
||||
return PTR_ERR(drv_data->regmap);
|
||||
|
||||
llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"llcc_broadcast_base");
|
||||
llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res);
|
||||
if (IS_ERR(llcc_bcast_base))
|
||||
return PTR_ERR(llcc_bcast_base);
|
||||
|
||||
drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base,
|
||||
&llcc_regmap_config);
|
||||
if (IS_ERR(drv_data->bcast_regmap))
|
||||
return PTR_ERR(drv_data->bcast_regmap);
|
||||
|
||||
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
|
||||
&num_banks);
|
||||
if (ret)
|
||||
|
|
@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev,
|
|||
for (i = 0; i < num_banks; i++)
|
||||
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
|
||||
|
||||
drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
|
||||
|
||||
drv_data->bitmap = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev,
|
|||
mutex_init(&drv_data->lock);
|
||||
platform_set_drvdata(pdev, drv_data);
|
||||
|
||||
return qcom_llcc_cfg_program(pdev);
|
||||
ret = qcom_llcc_cfg_program(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data->ecc_irq = platform_get_irq(pdev, 0);
|
||||
if (drv_data->ecc_irq >= 0) {
|
||||
llcc_edac = platform_device_register_data(&pdev->dev,
|
||||
"qcom_llcc_edac", -1, drv_data,
|
||||
sizeof(*drv_data));
|
||||
if (IS_ERR(llcc_edac))
|
||||
dev_err(dev, "Failed to register llcc edac driver\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_llcc_probe);
|
||||
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on);
|
|||
*/
|
||||
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
|
||||
{
|
||||
unsigned long freq = 0;
|
||||
long freq = 0;
|
||||
int i;
|
||||
|
||||
if (se->clk_perf_tbl) {
|
||||
|
|
@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
|
|||
|
||||
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
|
||||
freq = clk_round_rate(se->clk, freq + 1);
|
||||
if (!freq || freq == se->clk_perf_tbl[i - 1])
|
||||
if (freq <= 0 || freq == se->clk_perf_tbl[i - 1])
|
||||
break;
|
||||
se->clk_perf_tbl[i] = freq;
|
||||
}
|
||||
|
|
@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get);
|
|||
* @se: Pointer to the concerned serial engine.
|
||||
* @req_freq: Requested clock frequency.
|
||||
* @index: Index of the resultant frequency in the table.
|
||||
* @res_freq: Resultant frequency which matches or is closer to the
|
||||
* requested frequency.
|
||||
* @res_freq: Resultant frequency of the source clock.
|
||||
* @exact: Flag to indicate exact multiple requirement of the requested
|
||||
* frequency.
|
||||
*
|
||||
* This function is called by the protocol drivers to determine the matching
|
||||
* or exact multiple of the requested frequency, as provided by the serial
|
||||
* engine clock in order to meet the performance requirements. If there is
|
||||
* no matching or exact multiple of the requested frequency found, then it
|
||||
* selects the closest floor frequency, if exact flag is not set.
|
||||
* This function is called by the protocol drivers to determine the best match
|
||||
* of the requested frequency as provided by the serial engine clock in order
|
||||
* to meet the performance requirements.
|
||||
*
|
||||
* If we return success:
|
||||
* - if @exact is true then @res_freq / <an_integer> == @req_freq
|
||||
* - if @exact is false then @res_freq / <an_integer> <= @req_freq
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure.
|
||||
*/
|
||||
|
|
@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
|
|||
unsigned long *tbl;
|
||||
int num_clk_levels;
|
||||
int i;
|
||||
unsigned long best_delta;
|
||||
unsigned long new_delta;
|
||||
unsigned int divider;
|
||||
|
||||
num_clk_levels = geni_se_clk_tbl_get(se, &tbl);
|
||||
if (num_clk_levels < 0)
|
||||
|
|
@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
|
|||
if (num_clk_levels == 0)
|
||||
return -EINVAL;
|
||||
|
||||
*res_freq = 0;
|
||||
best_delta = ULONG_MAX;
|
||||
for (i = 0; i < num_clk_levels; i++) {
|
||||
if (!(tbl[i] % req_freq)) {
|
||||
divider = DIV_ROUND_UP(tbl[i], req_freq);
|
||||
new_delta = req_freq - tbl[i] / divider;
|
||||
if (new_delta < best_delta) {
|
||||
/* We have a new best! */
|
||||
*index = i;
|
||||
*res_freq = tbl[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(*res_freq) || ((tbl[i] > *res_freq) &&
|
||||
(tbl[i] < req_freq))) {
|
||||
*index = i;
|
||||
*res_freq = tbl[i];
|
||||
/* If the new best is exact then we're done */
|
||||
if (new_delta == 0)
|
||||
return 0;
|
||||
|
||||
/* Record how close we got */
|
||||
best_delta = new_delta;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
|
||||
goto remove_cdev;
|
||||
} else if (!ret) {
|
||||
if (!qcom_scm_is_available()) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto remove_cdev;
|
||||
}
|
||||
|
||||
perms[0].vmid = QCOM_SCM_VMID_HLOS;
|
||||
perms[0].perm = QCOM_SCM_PERM_RW;
|
||||
perms[1].vmid = vmid;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
|
|||
return -EAGAIN;
|
||||
}
|
||||
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
|
||||
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
|
||||
}
|
||||
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
|
||||
spin_unlock(&tcs->lock);
|
||||
|
|
@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
|
|||
skip:
|
||||
/* Reclaim the TCS */
|
||||
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
|
||||
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
|
||||
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
|
||||
spin_lock(&drv->lock);
|
||||
clear_bit(i, drv->tcs_in_use);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
|
||||
|
|
@ -277,7 +278,7 @@ struct qcom_smem {
|
|||
u32 item_count;
|
||||
|
||||
unsigned num_regions;
|
||||
struct smem_region regions[0];
|
||||
struct smem_region regions[];
|
||||
};
|
||||
|
||||
static void *
|
||||
|
|
@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
|
|||
size_t *size)
|
||||
{
|
||||
struct smem_header *header;
|
||||
struct smem_region *area;
|
||||
struct smem_region *region;
|
||||
struct smem_global_entry *entry;
|
||||
u32 aux_base;
|
||||
unsigned i;
|
||||
|
|
@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
|
|||
aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
|
||||
|
||||
for (i = 0; i < smem->num_regions; i++) {
|
||||
area = &smem->regions[i];
|
||||
region = &smem->regions[i];
|
||||
|
||||
if (area->aux_base == aux_base || !aux_base) {
|
||||
if (region->aux_base == aux_base || !aux_base) {
|
||||
if (size != NULL)
|
||||
*size = le32_to_cpu(entry->size);
|
||||
return area->virt_base + le32_to_cpu(entry->offset);
|
||||
return region->virt_base + le32_to_cpu(entry->offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
|
|||
return le16_to_cpu(info->num_items);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the partition header for a partition whose partition
|
||||
* table entry is supplied. Returns a pointer to its header if
|
||||
* valid, or a null pointer otherwise.
|
||||
*/
|
||||
static struct smem_partition_header *
|
||||
qcom_smem_partition_header(struct qcom_smem *smem,
|
||||
struct smem_ptable_entry *entry, u16 host0, u16 host1)
|
||||
{
|
||||
struct smem_partition_header *header;
|
||||
u32 size;
|
||||
|
||||
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
|
||||
|
||||
if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
|
||||
dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
|
||||
header->magic[0], header->magic[1],
|
||||
header->magic[2], header->magic[3]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (host0 != le16_to_cpu(header->host0)) {
|
||||
dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
|
||||
host0, le16_to_cpu(header->host0));
|
||||
return NULL;
|
||||
}
|
||||
if (host1 != le16_to_cpu(header->host1)) {
|
||||
dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
|
||||
host1, le16_to_cpu(header->host1));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = le32_to_cpu(header->size);
|
||||
if (size != le32_to_cpu(entry->size)) {
|
||||
dev_err(smem->dev, "bad partition size (%u != %u)\n",
|
||||
size, le32_to_cpu(entry->size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header->offset_free_uncached) > size) {
|
||||
dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
|
||||
le32_to_cpu(header->offset_free_uncached), size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
||||
{
|
||||
struct smem_partition_header *header;
|
||||
struct smem_ptable_entry *entry;
|
||||
struct smem_ptable *ptable;
|
||||
u32 host0, host1, size;
|
||||
bool found = false;
|
||||
int i;
|
||||
|
||||
|
|
@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
|||
|
||||
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
|
||||
entry = &ptable->entry[i];
|
||||
host0 = le16_to_cpu(entry->host0);
|
||||
host1 = le16_to_cpu(entry->host1);
|
||||
if (!le32_to_cpu(entry->offset))
|
||||
continue;
|
||||
if (!le32_to_cpu(entry->size))
|
||||
continue;
|
||||
|
||||
if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
|
||||
if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
|
||||
continue;
|
||||
|
||||
if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) {
|
||||
dev_err(smem->dev, "Invalid entry for global partition\n");
|
||||
header = qcom_smem_partition_header(smem, entry,
|
||||
SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
|
||||
if (!header)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
|
||||
host0 = le16_to_cpu(header->host0);
|
||||
host1 = le16_to_cpu(header->host1);
|
||||
|
||||
if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
|
||||
dev_err(smem->dev, "Global partition has invalid magic\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) {
|
||||
dev_err(smem->dev, "Global partition hosts are invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
|
||||
dev_err(smem->dev, "Global partition has invalid size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = le32_to_cpu(header->offset_free_uncached);
|
||||
if (size > le32_to_cpu(header->size)) {
|
||||
dev_err(smem->dev,
|
||||
"Global partition has invalid free pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smem->global_partition = header;
|
||||
smem->global_cacheline = le32_to_cpu(entry->cacheline);
|
||||
|
|
@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
|
||||
unsigned int local_host)
|
||||
static int
|
||||
qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
|
||||
{
|
||||
struct smem_partition_header *header;
|
||||
struct smem_ptable_entry *entry;
|
||||
struct smem_ptable *ptable;
|
||||
unsigned int remote_host;
|
||||
u32 host0, host1;
|
||||
u16 host0, host1;
|
||||
int i;
|
||||
|
||||
ptable = qcom_smem_get_ptable(smem);
|
||||
|
|
@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
|
|||
|
||||
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
|
||||
entry = &ptable->entry[i];
|
||||
host0 = le16_to_cpu(entry->host0);
|
||||
host1 = le16_to_cpu(entry->host1);
|
||||
|
||||
if (host0 != local_host && host1 != local_host)
|
||||
continue;
|
||||
|
||||
if (!le32_to_cpu(entry->offset))
|
||||
continue;
|
||||
|
||||
if (!le32_to_cpu(entry->size))
|
||||
continue;
|
||||
|
||||
host0 = le16_to_cpu(entry->host0);
|
||||
host1 = le16_to_cpu(entry->host1);
|
||||
if (host0 == local_host)
|
||||
remote_host = host1;
|
||||
else
|
||||
else if (host1 == local_host)
|
||||
remote_host = host0;
|
||||
else
|
||||
continue;
|
||||
|
||||
if (remote_host >= SMEM_HOST_COUNT) {
|
||||
dev_err(smem->dev,
|
||||
"Invalid remote host %d\n",
|
||||
remote_host);
|
||||
dev_err(smem->dev, "bad host %hu\n", remote_host);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (smem->partitions[remote_host]) {
|
||||
dev_err(smem->dev,
|
||||
"Already found a partition for host %d\n",
|
||||
remote_host);
|
||||
dev_err(smem->dev, "duplicate host %hu\n", remote_host);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
|
||||
host0 = le16_to_cpu(header->host0);
|
||||
host1 = le16_to_cpu(header->host1);
|
||||
|
||||
if (memcmp(header->magic, SMEM_PART_MAGIC,
|
||||
sizeof(header->magic))) {
|
||||
dev_err(smem->dev,
|
||||
"Partition %d has invalid magic\n", i);
|
||||
header = qcom_smem_partition_header(smem, entry, host0, host1);
|
||||
if (!header)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (host0 != local_host && host1 != local_host) {
|
||||
dev_err(smem->dev,
|
||||
"Partition %d hosts are invalid\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (host0 != remote_host && host1 != remote_host) {
|
||||
dev_err(smem->dev,
|
||||
"Partition %d hosts are invalid\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
|
||||
dev_err(smem->dev,
|
||||
"Partition %d has invalid size\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
|
||||
dev_err(smem->dev,
|
||||
"Partition %d has invalid free pointer\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smem->partitions[remote_host] = header;
|
||||
smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
|
||||
|
|
@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
|
|||
{
|
||||
struct device_node *np;
|
||||
struct resource r;
|
||||
resource_size_t size;
|
||||
int ret;
|
||||
|
||||
np = of_parse_phandle(dev->of_node, name, 0);
|
||||
|
|
@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
|
|||
of_node_put(np);
|
||||
if (ret)
|
||||
return ret;
|
||||
size = resource_size(&r);
|
||||
|
||||
smem->regions[i].aux_base = (u32)r.start;
|
||||
smem->regions[i].size = resource_size(&r);
|
||||
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
|
||||
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
|
||||
if (!smem->regions[i].virt_base)
|
||||
return -ENOMEM;
|
||||
smem->regions[i].aux_base = (u32)r.start;
|
||||
smem->regions[i].size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
|
||||
ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
|
|||
cpumask_t mask;
|
||||
bool use_scm_power_down = false;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
|
||||
if (!state_node)
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
|
|||
struct rpmsg_channel_info chinfo;
|
||||
struct wcnss_ctrl *_wcnss = wcnss;
|
||||
|
||||
strncpy(chinfo.name, name, sizeof(chinfo.name));
|
||||
strscpy(chinfo.name, name, sizeof(chinfo.name));
|
||||
chinfo.src = RPMSG_ADDR_ANY;
|
||||
chinfo.dst = RPMSG_ADDR_ANY;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue