Reset controller changes for v4.20
This adds a new driver for the PDC Global (Power Domain Controller) reset controller found on Qualcomm SDM845 SoCs, fixes a potential use-after-free issue in reset_controller_dev.of_xlate() callbacks from __of_reset_control_get(), and trivially fixes a documentation grammar issue. -----BEGIN PGP SIGNATURE----- iI0EABYIADUWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCW7x5rhcccC56YWJlbEBw ZW5ndXRyb25peC5kZQAKCRDVhaclGDdiwDy9AP9Z7aMOwFUB0ie3RtL3TVdKq0dg ayIYm+iKAlWjiwvr5wD/XuHhygmuY3uDyvTaQP3yoWsQe5+/ugg606Shcxe4EQE= =+kaf -----END PGP SIGNATURE----- Merge tag 'reset-for-4.20' of git://git.pengutronix.de/git/pza/linux into next/drivers Reset controller changes for v4.20 This adds a new driver for the PDC Global (Power Domain Controller) reset controller found on Qualcomm SDM845 SoCs, fixes a potential use-after-free issue in reset_controller_dev.of_xlate() callbacks from __of_reset_control_get(), and trivially fixes a documentation grammar issue. * tag 'reset-for-4.20' of git://git.pengutronix.de/git/pza/linux: reset: Fix potential use-after-free in __of_reset_control_get() reset: qcom: PDC Global (Power Domain Controller) reset controller dt-bindings: reset: Add PDC Global binding for SDM845 SoCs reset: Grammar s/more then once/more than once/ Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
f7d87826fe
|
@ -0,0 +1,52 @@
|
||||||
|
PDC Global
|
||||||
|
======================================
|
||||||
|
|
||||||
|
This binding describes a reset-controller found on PDC-Global (Power Domain
|
||||||
|
Controller) block for Qualcomm Technologies Inc SDM845 SoCs.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible:
|
||||||
|
Usage: required
|
||||||
|
Value type: <string>
|
||||||
|
Definition: must be:
|
||||||
|
"qcom,sdm845-pdc-global"
|
||||||
|
|
||||||
|
- reg:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: must specify the base address and size of the register
|
||||||
|
space.
|
||||||
|
|
||||||
|
- #reset-cells:
|
||||||
|
Usage: required
|
||||||
|
Value type: <uint>
|
||||||
|
Definition: must be 1; cell entry represents the reset index.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
pdc_reset: reset-controller@b2e0000 {
|
||||||
|
compatible = "qcom,sdm845-pdc-global";
|
||||||
|
reg = <0xb2e0000 0x20000>;
|
||||||
|
#reset-cells = <1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
PDC reset clients
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Device nodes that need access to reset lines should
|
||||||
|
specify them as a reset phandle in their corresponding node as
|
||||||
|
specified in reset.txt.
|
||||||
|
|
||||||
|
For a list of all valid reset indices see
|
||||||
|
<dt-bindings/reset/qcom,sdm845-pdc.h>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
modem-pil@4080000 {
|
||||||
|
...
|
||||||
|
|
||||||
|
resets = <&pdc_reset PDC_MODEM_SYNC_RESET>;
|
||||||
|
reset-names = "pdc_reset";
|
||||||
|
|
||||||
|
...
|
||||||
|
};
|
|
@ -98,6 +98,15 @@ config RESET_QCOM_AOSS
|
||||||
reset signals provided by AOSS for Modem, Venus, ADSP,
|
reset signals provided by AOSS for Modem, Venus, ADSP,
|
||||||
GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
|
GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
|
||||||
|
|
||||||
|
config RESET_QCOM_PDC
|
||||||
|
tristate "Qualcomm PDC Reset Driver"
|
||||||
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
|
help
|
||||||
|
This enables the PDC (Power Domain Controller) reset driver
|
||||||
|
for Qualcomm Technologies Inc SDM845 SoCs. Say Y if you want
|
||||||
|
to control reset signals provided by PDC for Modem, Compute,
|
||||||
|
Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS.
|
||||||
|
|
||||||
config RESET_SIMPLE
|
config RESET_SIMPLE
|
||||||
bool "Simple Reset Controller Driver" if COMPILE_TEST
|
bool "Simple Reset Controller Driver" if COMPILE_TEST
|
||||||
default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
|
default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
|
||||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
|
||||||
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
|
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
|
||||||
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
|
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
|
||||||
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
|
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
|
||||||
|
obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
|
||||||
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
|
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
|
||||||
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
|
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
|
||||||
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
|
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
|
||||||
|
|
|
@ -496,28 +496,29 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
of_node_put(args.np);
|
|
||||||
|
|
||||||
if (!rcdev) {
|
if (!rcdev) {
|
||||||
mutex_unlock(&reset_list_mutex);
|
rstc = ERR_PTR(-EPROBE_DEFER);
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
|
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
|
||||||
mutex_unlock(&reset_list_mutex);
|
rstc = ERR_PTR(-EINVAL);
|
||||||
return ERR_PTR(-EINVAL);
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rstc_id = rcdev->of_xlate(rcdev, &args);
|
rstc_id = rcdev->of_xlate(rcdev, &args);
|
||||||
if (rstc_id < 0) {
|
if (rstc_id < 0) {
|
||||||
mutex_unlock(&reset_list_mutex);
|
rstc = ERR_PTR(rstc_id);
|
||||||
return ERR_PTR(rstc_id);
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset_list_mutex also protects the rcdev's reset_control list */
|
/* reset_list_mutex also protects the rcdev's reset_control list */
|
||||||
rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
|
rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
|
||||||
|
|
||||||
|
out:
|
||||||
mutex_unlock(&reset_list_mutex);
|
mutex_unlock(&reset_list_mutex);
|
||||||
|
of_node_put(args.np);
|
||||||
|
|
||||||
return rstc;
|
return rstc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/reset-controller.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/reset/qcom,sdm845-pdc.h>
|
||||||
|
|
||||||
|
#define RPMH_PDC_SYNC_RESET 0x100
|
||||||
|
|
||||||
|
struct qcom_pdc_reset_map {
|
||||||
|
u8 bit;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qcom_pdc_reset_data {
|
||||||
|
struct reset_controller_dev rcdev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config sdm845_pdc_regmap_config = {
|
||||||
|
.name = "pdc-reset",
|
||||||
|
.reg_bits = 32,
|
||||||
|
.reg_stride = 4,
|
||||||
|
.val_bits = 32,
|
||||||
|
.max_register = 0x20000,
|
||||||
|
.fast_io = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = {
|
||||||
|
[PDC_APPS_SYNC_RESET] = {0},
|
||||||
|
[PDC_SP_SYNC_RESET] = {1},
|
||||||
|
[PDC_AUDIO_SYNC_RESET] = {2},
|
||||||
|
[PDC_SENSORS_SYNC_RESET] = {3},
|
||||||
|
[PDC_AOP_SYNC_RESET] = {4},
|
||||||
|
[PDC_DEBUG_SYNC_RESET] = {5},
|
||||||
|
[PDC_GPU_SYNC_RESET] = {6},
|
||||||
|
[PDC_DISPLAY_SYNC_RESET] = {7},
|
||||||
|
[PDC_COMPUTE_SYNC_RESET] = {8},
|
||||||
|
[PDC_MODEM_SYNC_RESET] = {9},
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data(
|
||||||
|
struct reset_controller_dev *rcdev)
|
||||||
|
{
|
||||||
|
return container_of(rcdev, struct qcom_pdc_reset_data, rcdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev,
|
||||||
|
unsigned long idx)
|
||||||
|
{
|
||||||
|
struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
|
||||||
|
|
||||||
|
return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
|
||||||
|
BIT(sdm845_pdc_resets[idx].bit),
|
||||||
|
BIT(sdm845_pdc_resets[idx].bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev,
|
||||||
|
unsigned long idx)
|
||||||
|
{
|
||||||
|
struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
|
||||||
|
|
||||||
|
return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
|
||||||
|
BIT(sdm845_pdc_resets[idx].bit), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct reset_control_ops qcom_pdc_reset_ops = {
|
||||||
|
.assert = qcom_pdc_control_assert,
|
||||||
|
.deassert = qcom_pdc_control_deassert,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_pdc_reset_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct qcom_pdc_reset_data *data;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
void __iomem *base;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(base))
|
||||||
|
return PTR_ERR(base);
|
||||||
|
|
||||||
|
data->regmap = devm_regmap_init_mmio(dev, base,
|
||||||
|
&sdm845_pdc_regmap_config);
|
||||||
|
if (IS_ERR(data->regmap)) {
|
||||||
|
dev_err(dev, "Unable to initialize regmap\n");
|
||||||
|
return PTR_ERR(data->regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->rcdev.owner = THIS_MODULE;
|
||||||
|
data->rcdev.ops = &qcom_pdc_reset_ops;
|
||||||
|
data->rcdev.nr_resets = ARRAY_SIZE(sdm845_pdc_resets);
|
||||||
|
data->rcdev.of_node = dev->of_node;
|
||||||
|
|
||||||
|
return devm_reset_controller_register(dev, &data->rcdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id qcom_pdc_reset_of_match[] = {
|
||||||
|
{ .compatible = "qcom,sdm845-pdc-global" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver qcom_pdc_reset_driver = {
|
||||||
|
.probe = qcom_pdc_reset_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom_pdc_reset",
|
||||||
|
.of_match_table = qcom_pdc_reset_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(qcom_pdc_reset_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm PDC Reset Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DT_BINDINGS_RESET_PDC_SDM_845_H
|
||||||
|
#define _DT_BINDINGS_RESET_PDC_SDM_845_H
|
||||||
|
|
||||||
|
#define PDC_APPS_SYNC_RESET 0
|
||||||
|
#define PDC_SP_SYNC_RESET 1
|
||||||
|
#define PDC_AUDIO_SYNC_RESET 2
|
||||||
|
#define PDC_SENSORS_SYNC_RESET 3
|
||||||
|
#define PDC_AOP_SYNC_RESET 4
|
||||||
|
#define PDC_DEBUG_SYNC_RESET 5
|
||||||
|
#define PDC_GPU_SYNC_RESET 6
|
||||||
|
#define PDC_DISPLAY_SYNC_RESET 7
|
||||||
|
#define PDC_COMPUTE_SYNC_RESET 8
|
||||||
|
#define PDC_MODEM_SYNC_RESET 9
|
||||||
|
|
||||||
|
#endif
|
|
@ -116,7 +116,7 @@ static inline int device_reset_optional(struct device *dev)
|
||||||
* @id: reset line name
|
* @id: reset line name
|
||||||
*
|
*
|
||||||
* Returns a struct reset_control or IS_ERR() condition containing errno.
|
* Returns a struct reset_control or IS_ERR() condition containing errno.
|
||||||
* If this function is called more then once for the same reset_control it will
|
* If this function is called more than once for the same reset_control it will
|
||||||
* return -EBUSY.
|
* return -EBUSY.
|
||||||
*
|
*
|
||||||
* See reset_control_get_shared for details on shared references to
|
* See reset_control_get_shared for details on shared references to
|
||||||
|
|
Loading…
Reference in New Issue