aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
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>
Diffstat (limited to 'drivers')
-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
4 files changed, 142 insertions, 7 deletions
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");