diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2018-10-10 07:41:16 -0400 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2018-10-10 07:41:22 -0400 |
| commit | f7d87826fe482dbe4b0675f99c1eae2890a2d8fb (patch) | |
| tree | 2640aec2ab83e9958930a7ba9b1738ed5103355e | |
| parent | b0a2cea5eb637d540ba86fd31dfd750f26ee0161 (diff) | |
| parent | b790c8ea5593d6dc3580adfad8e117eeb56af874 (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.txt | 52 | ||||
| -rw-r--r-- | drivers/reset/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/reset/Makefile | 1 | ||||
| -rw-r--r-- | drivers/reset/core.c | 15 | ||||
| -rw-r--r-- | drivers/reset/reset-qcom-pdc.c | 124 | ||||
| -rw-r--r-- | include/dt-bindings/reset/qcom,sdm845-pdc.h | 20 | ||||
| -rw-r--r-- | include/linux/reset.h | 2 |
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 @@ | |||
| 1 | PDC Global | ||
| 2 | ====================================== | ||
| 3 | |||
| 4 | This binding describes a reset-controller found on PDC-Global (Power Domain | ||
| 5 | Controller) block for Qualcomm Technologies Inc SDM845 SoCs. | ||
| 6 | |||
| 7 | Required 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 | |||
| 25 | Example: | ||
| 26 | |||
| 27 | pdc_reset: reset-controller@b2e0000 { | ||
| 28 | compatible = "qcom,sdm845-pdc-global"; | ||
| 29 | reg = <0xb2e0000 0x20000>; | ||
| 30 | #reset-cells = <1>; | ||
| 31 | }; | ||
| 32 | |||
| 33 | PDC reset clients | ||
| 34 | ====================================== | ||
| 35 | |||
| 36 | Device nodes that need access to reset lines should | ||
| 37 | specify them as a reset phandle in their corresponding node as | ||
| 38 | specified in reset.txt. | ||
| 39 | |||
| 40 | For a list of all valid reset indices see | ||
| 41 | <dt-bindings/reset/qcom,sdm845-pdc.h> | ||
| 42 | |||
| 43 | Example: | ||
| 44 | |||
| 45 | modem-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 | ||
| 101 | config 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 | |||
| 101 | config RESET_SIMPLE | 110 | config 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 | |||
| 16 | obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o | 16 | obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o |
| 17 | obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o | 17 | obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o |
| 18 | obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o | 18 | obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o |
| 19 | obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o | ||
| 19 | obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o | 20 | obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o |
| 20 | obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o | 21 | obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o |
| 21 | obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o | 22 | obj-$(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 | ||
| 519 | out: | ||
| 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 | |||
| 16 | struct qcom_pdc_reset_map { | ||
| 17 | u8 bit; | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct qcom_pdc_reset_data { | ||
| 21 | struct reset_controller_dev rcdev; | ||
| 22 | struct regmap *regmap; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static 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 | |||
| 34 | static 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 | |||
| 47 | static 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 | |||
| 53 | static 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 | |||
| 63 | static 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 | |||
| 72 | static const struct reset_control_ops qcom_pdc_reset_ops = { | ||
| 73 | .assert = qcom_pdc_control_assert, | ||
| 74 | .deassert = qcom_pdc_control_deassert, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static 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 | |||
| 108 | static const struct of_device_id qcom_pdc_reset_of_match[] = { | ||
| 109 | { .compatible = "qcom,sdm845-pdc-global" }, | ||
| 110 | {} | ||
| 111 | }; | ||
| 112 | MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match); | ||
| 113 | |||
| 114 | static 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 | }; | ||
| 121 | module_platform_driver(qcom_pdc_reset_driver); | ||
| 122 | |||
| 123 | MODULE_DESCRIPTION("Qualcomm PDC Reset Driver"); | ||
| 124 | MODULE_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 |
