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
52
Documentation/devicetree/bindings/reset/qcom,pdc-global.txt
Normal file
52
Documentation/devicetree/bindings/reset/qcom,pdc-global.txt
Normal file
@ -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,
|
||||
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
|
||||
bool "Simple Reset Controller Driver" if COMPILE_TEST
|
||||
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_PISTACHIO) += reset-pistachio.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_STM32MP157) += reset-stm32mp1.o
|
||||
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
|
||||
|
@ -496,28 +496,29 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
|
||||
break;
|
||||
}
|
||||
}
|
||||
of_node_put(args.np);
|
||||
|
||||
if (!rcdev) {
|
||||
mutex_unlock(&reset_list_mutex);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
rstc = ERR_PTR(-EPROBE_DEFER);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
|
||||
mutex_unlock(&reset_list_mutex);
|
||||
return ERR_PTR(-EINVAL);
|
||||
rstc = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rstc_id = rcdev->of_xlate(rcdev, &args);
|
||||
if (rstc_id < 0) {
|
||||
mutex_unlock(&reset_list_mutex);
|
||||
return ERR_PTR(rstc_id);
|
||||
rstc = ERR_PTR(rstc_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* reset_list_mutex also protects the rcdev's reset_control list */
|
||||
rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
|
||||
|
||||
out:
|
||||
mutex_unlock(&reset_list_mutex);
|
||||
of_node_put(args.np);
|
||||
|
||||
return rstc;
|
||||
}
|
||||
|
124
drivers/reset/reset-qcom-pdc.c
Normal file
124
drivers/reset/reset-qcom-pdc.c
Normal file
@ -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");
|
20
include/dt-bindings/reset/qcom,sdm845-pdc.h
Normal file
20
include/dt-bindings/reset/qcom,sdm845-pdc.h
Normal file
@ -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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* See reset_control_get_shared for details on shared references to
|
||||
|
Loading…
Reference in New Issue
Block a user