aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-10-10 07:41:16 -0400
committerArnd Bergmann <arnd@arndb.de>2018-10-10 07:41:22 -0400
commitf7d87826fe482dbe4b0675f99c1eae2890a2d8fb (patch)
tree2640aec2ab83e9958930a7ba9b1738ed5103355e
parentb0a2cea5eb637d540ba86fd31dfd750f26ee0161 (diff)
parentb790c8ea5593d6dc3580adfad8e117eeb56af874 (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/reset/qcom,pdc-global.txt52
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c15
-rw-r--r--drivers/reset/reset-qcom-pdc.c124
-rw-r--r--include/dt-bindings/reset/qcom,sdm845-pdc.h20
-rw-r--r--include/linux/reset.h2
7 files changed, 215 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/reset/qcom,pdc-global.txt b/Documentation/devicetree/bindings/reset/qcom,pdc-global.txt
new file mode 100644
index 000000000000..a62a492843e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/qcom,pdc-global.txt
@@ -0,0 +1,52 @@
1PDC Global
2======================================
3
4This binding describes a reset-controller found on PDC-Global (Power Domain
5Controller) block for Qualcomm Technologies Inc SDM845 SoCs.
6
7Required properties:
8- compatible:
9 Usage: required
10 Value type: <string>
11 Definition: must be:
12 "qcom,sdm845-pdc-global"
13
14- reg:
15 Usage: required
16 Value type: <prop-encoded-array>
17 Definition: must specify the base address and size of the register
18 space.
19
20- #reset-cells:
21 Usage: required
22 Value type: <uint>
23 Definition: must be 1; cell entry represents the reset index.
24
25Example:
26
27pdc_reset: reset-controller@b2e0000 {
28 compatible = "qcom,sdm845-pdc-global";
29 reg = <0xb2e0000 0x20000>;
30 #reset-cells = <1>;
31};
32
33PDC reset clients
34======================================
35
36Device nodes that need access to reset lines should
37specify them as a reset phandle in their corresponding node as
38specified in reset.txt.
39
40For a list of all valid reset indices see
41<dt-bindings/reset/qcom,sdm845-pdc.h>
42
43Example:
44
45modem-pil@4080000 {
46 ...
47
48 resets = <&pdc_reset PDC_MODEM_SYNC_RESET>;
49 reset-names = "pdc_reset";
50
51 ...
52};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 13d28fdbdbb5..c21da9fe51ec 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -98,6 +98,15 @@ config RESET_QCOM_AOSS
98 reset signals provided by AOSS for Modem, Venus, ADSP, 98 reset signals provided by AOSS for Modem, Venus, ADSP,
99 GPU, Camera, Wireless, Display subsystem. Otherwise, say N. 99 GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
100 100
101config RESET_QCOM_PDC
102 tristate "Qualcomm PDC Reset Driver"
103 depends on ARCH_QCOM || COMPILE_TEST
104 help
105 This enables the PDC (Power Domain Controller) reset driver
106 for Qualcomm Technologies Inc SDM845 SoCs. Say Y if you want
107 to control reset signals provided by PDC for Modem, Compute,
108 Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS.
109
101config RESET_SIMPLE 110config RESET_SIMPLE
102 bool "Simple Reset Controller Driver" if COMPILE_TEST 111 bool "Simple Reset Controller Driver" if COMPILE_TEST
103 default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED 112 default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 4243c38228e2..d08e8b90046a 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
16obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o 16obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
17obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o 17obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
18obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o 18obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
19obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
19obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o 20obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
20obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o 21obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
21obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o 22obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 225e34c56b94..d1887c0ed5d3 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -496,28 +496,29 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
496 break; 496 break;
497 } 497 }
498 } 498 }
499 of_node_put(args.np);
500 499
501 if (!rcdev) { 500 if (!rcdev) {
502 mutex_unlock(&reset_list_mutex); 501 rstc = ERR_PTR(-EPROBE_DEFER);
503 return ERR_PTR(-EPROBE_DEFER); 502 goto out;
504 } 503 }
505 504
506 if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { 505 if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
507 mutex_unlock(&reset_list_mutex); 506 rstc = ERR_PTR(-EINVAL);
508 return ERR_PTR(-EINVAL); 507 goto out;
509 } 508 }
510 509
511 rstc_id = rcdev->of_xlate(rcdev, &args); 510 rstc_id = rcdev->of_xlate(rcdev, &args);
512 if (rstc_id < 0) { 511 if (rstc_id < 0) {
513 mutex_unlock(&reset_list_mutex); 512 rstc = ERR_PTR(rstc_id);
514 return ERR_PTR(rstc_id); 513 goto out;
515 } 514 }
516 515
517 /* reset_list_mutex also protects the rcdev's reset_control list */ 516 /* reset_list_mutex also protects the rcdev's reset_control list */
518 rstc = __reset_control_get_internal(rcdev, rstc_id, shared); 517 rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
519 518
519out:
520 mutex_unlock(&reset_list_mutex); 520 mutex_unlock(&reset_list_mutex);
521 of_node_put(args.np);
521 522
522 return rstc; 523 return rstc;
523} 524}
diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c
new file mode 100644
index 000000000000..ab74bccd4a5b
--- /dev/null
+++ b/drivers/reset/reset-qcom-pdc.c
@@ -0,0 +1,124 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/module.h>
7#include <linux/of_device.h>
8#include <linux/platform_device.h>
9#include <linux/regmap.h>
10#include <linux/reset-controller.h>
11
12#include <dt-bindings/reset/qcom,sdm845-pdc.h>
13
14#define RPMH_PDC_SYNC_RESET 0x100
15
16struct qcom_pdc_reset_map {
17 u8 bit;
18};
19
20struct qcom_pdc_reset_data {
21 struct reset_controller_dev rcdev;
22 struct regmap *regmap;
23};
24
25static const struct regmap_config sdm845_pdc_regmap_config = {
26 .name = "pdc-reset",
27 .reg_bits = 32,
28 .reg_stride = 4,
29 .val_bits = 32,
30 .max_register = 0x20000,
31 .fast_io = true,
32};
33
34static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = {
35 [PDC_APPS_SYNC_RESET] = {0},
36 [PDC_SP_SYNC_RESET] = {1},
37 [PDC_AUDIO_SYNC_RESET] = {2},
38 [PDC_SENSORS_SYNC_RESET] = {3},
39 [PDC_AOP_SYNC_RESET] = {4},
40 [PDC_DEBUG_SYNC_RESET] = {5},
41 [PDC_GPU_SYNC_RESET] = {6},
42 [PDC_DISPLAY_SYNC_RESET] = {7},
43 [PDC_COMPUTE_SYNC_RESET] = {8},
44 [PDC_MODEM_SYNC_RESET] = {9},
45};
46
47static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data(
48 struct reset_controller_dev *rcdev)
49{
50 return container_of(rcdev, struct qcom_pdc_reset_data, rcdev);
51}
52
53static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev,
54 unsigned long idx)
55{
56 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
57
58 return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
59 BIT(sdm845_pdc_resets[idx].bit),
60 BIT(sdm845_pdc_resets[idx].bit));
61}
62
63static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev,
64 unsigned long idx)
65{
66 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
67
68 return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
69 BIT(sdm845_pdc_resets[idx].bit), 0);
70}
71
72static const struct reset_control_ops qcom_pdc_reset_ops = {
73 .assert = qcom_pdc_control_assert,
74 .deassert = qcom_pdc_control_deassert,
75};
76
77static int qcom_pdc_reset_probe(struct platform_device *pdev)
78{
79 struct qcom_pdc_reset_data *data;
80 struct device *dev = &pdev->dev;
81 void __iomem *base;
82 struct resource *res;
83
84 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
85 if (!data)
86 return -ENOMEM;
87
88 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
89 base = devm_ioremap_resource(dev, res);
90 if (IS_ERR(base))
91 return PTR_ERR(base);
92
93 data->regmap = devm_regmap_init_mmio(dev, base,
94 &sdm845_pdc_regmap_config);
95 if (IS_ERR(data->regmap)) {
96 dev_err(dev, "Unable to initialize regmap\n");
97 return PTR_ERR(data->regmap);
98 }
99
100 data->rcdev.owner = THIS_MODULE;
101 data->rcdev.ops = &qcom_pdc_reset_ops;
102 data->rcdev.nr_resets = ARRAY_SIZE(sdm845_pdc_resets);
103 data->rcdev.of_node = dev->of_node;
104
105 return devm_reset_controller_register(dev, &data->rcdev);
106}
107
108static const struct of_device_id qcom_pdc_reset_of_match[] = {
109 { .compatible = "qcom,sdm845-pdc-global" },
110 {}
111};
112MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match);
113
114static struct platform_driver qcom_pdc_reset_driver = {
115 .probe = qcom_pdc_reset_probe,
116 .driver = {
117 .name = "qcom_pdc_reset",
118 .of_match_table = qcom_pdc_reset_of_match,
119 },
120};
121module_platform_driver(qcom_pdc_reset_driver);
122
123MODULE_DESCRIPTION("Qualcomm PDC Reset Driver");
124MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/reset/qcom,sdm845-pdc.h b/include/dt-bindings/reset/qcom,sdm845-pdc.h
new file mode 100644
index 000000000000..53c37f9c319a
--- /dev/null
+++ b/include/dt-bindings/reset/qcom,sdm845-pdc.h
@@ -0,0 +1,20 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2018 The Linux Foundation. All rights reserved.
4 */
5
6#ifndef _DT_BINDINGS_RESET_PDC_SDM_845_H
7#define _DT_BINDINGS_RESET_PDC_SDM_845_H
8
9#define PDC_APPS_SYNC_RESET 0
10#define PDC_SP_SYNC_RESET 1
11#define PDC_AUDIO_SYNC_RESET 2
12#define PDC_SENSORS_SYNC_RESET 3
13#define PDC_AOP_SYNC_RESET 4
14#define PDC_DEBUG_SYNC_RESET 5
15#define PDC_GPU_SYNC_RESET 6
16#define PDC_DISPLAY_SYNC_RESET 7
17#define PDC_COMPUTE_SYNC_RESET 8
18#define PDC_MODEM_SYNC_RESET 9
19
20#endif
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 09732c36f351..29af6d6b2f4b 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -116,7 +116,7 @@ static inline int device_reset_optional(struct device *dev)
116 * @id: reset line name 116 * @id: reset line name
117 * 117 *
118 * Returns a struct reset_control or IS_ERR() condition containing errno. 118 * Returns a struct reset_control or IS_ERR() condition containing errno.
119 * If this function is called more then once for the same reset_control it will 119 * If this function is called more than once for the same reset_control it will
120 * return -EBUSY. 120 * return -EBUSY.
121 * 121 *
122 * See reset_control_get_shared for details on shared references to 122 * See reset_control_get_shared for details on shared references to