diff options
author | Arnd Bergmann <arnd@arndb.de> | 2018-03-28 11:02:22 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-03-28 11:02:22 -0400 |
commit | 7f95de5e4a27d3cda21f7223c22f22ab6c5b3def (patch) | |
tree | 37c91c02f6516c1870daf627a3ed264259064be3 /drivers | |
parent | f8d6dc78b8b994cf6903879ab6abf3cb25b76daf (diff) | |
parent | 0089313d8595b76422b189b44c55556cb1004190 (diff) |
Merge tag 'reset-for-4.17-2' of git://git.pengutronix.de/git/pza/linux into next/drivers
Pull "Reset controller changes for v4.17, part 2" from Philipp Zabel:
This tag contains reset lookup support, similar to pwm lookups, for legacy
non-DT platforms, a few new reset controls and a Kconfig fix for uniphier
SoCs, as well as a new driver for the STM32MP1 peripheral reset controller.
The reset lookups are merged from a separate, immutable branch, that may
also be merged into the davinci tree.
* tag 'reset-for-4.17-2' of git://git.pengutronix.de/git/pza/linux:
reset: uniphier: add ethernet reset control support for PXs3
reset: stm32mp1: Enable stm32mp1 reset driver
dt-bindings: reset: add STM32MP1 resets
reset: uniphier: add Pro4/Pro5/PXs2 audio systems reset control
reset: imx7: add 'depends on HAS_IOMEM' to fix unmet dependency
reset: modify the way reset lookup works for board files
reset: add support for non-DT systems
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/reset/Kconfig | 7 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/core.c | 96 | ||||
-rw-r--r-- | drivers/reset/reset-stm32mp1.c | 115 | ||||
-rw-r--r-- | drivers/reset/reset-uniphier.c | 5 |
5 files changed, 223 insertions, 1 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 18f152d251d7..c0b292be1b72 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig | |||
@@ -49,6 +49,7 @@ config RESET_HSDK | |||
49 | 49 | ||
50 | config RESET_IMX7 | 50 | config RESET_IMX7 |
51 | bool "i.MX7 Reset Driver" if COMPILE_TEST | 51 | bool "i.MX7 Reset Driver" if COMPILE_TEST |
52 | depends on HAS_IOMEM | ||
52 | default SOC_IMX7D | 53 | default SOC_IMX7D |
53 | select MFD_SYSCON | 54 | select MFD_SYSCON |
54 | help | 55 | help |
@@ -96,6 +97,12 @@ config RESET_SIMPLE | |||
96 | - Allwinner SoCs | 97 | - Allwinner SoCs |
97 | - ZTE's zx2967 family | 98 | - ZTE's zx2967 family |
98 | 99 | ||
100 | config RESET_STM32MP157 | ||
101 | bool "STM32MP157 Reset Driver" if COMPILE_TEST | ||
102 | default MACH_STM32MP157 | ||
103 | help | ||
104 | This enables the RCC reset controller driver for STM32 MPUs. | ||
105 | |||
99 | config RESET_SUNXI | 106 | config RESET_SUNXI |
100 | bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI | 107 | bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI |
101 | default ARCH_SUNXI | 108 | default ARCH_SUNXI |
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 132c24f5ddb5..c1261dcfe9ad 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o | |||
15 | obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o | 15 | obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o |
16 | obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o | 16 | obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o |
17 | obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o | 17 | obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o |
18 | obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o | ||
18 | obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o | 19 | obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o |
19 | obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o | 20 | obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o |
20 | obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o | 21 | obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o |
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index da4292e9de97..6488292e129c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c | |||
@@ -23,6 +23,9 @@ | |||
23 | static DEFINE_MUTEX(reset_list_mutex); | 23 | static DEFINE_MUTEX(reset_list_mutex); |
24 | static LIST_HEAD(reset_controller_list); | 24 | static LIST_HEAD(reset_controller_list); |
25 | 25 | ||
26 | static DEFINE_MUTEX(reset_lookup_mutex); | ||
27 | static LIST_HEAD(reset_lookup_list); | ||
28 | |||
26 | /** | 29 | /** |
27 | * struct reset_control - a reset control | 30 | * struct reset_control - a reset control |
28 | * @rcdev: a pointer to the reset controller device | 31 | * @rcdev: a pointer to the reset controller device |
@@ -148,6 +151,33 @@ int devm_reset_controller_register(struct device *dev, | |||
148 | } | 151 | } |
149 | EXPORT_SYMBOL_GPL(devm_reset_controller_register); | 152 | EXPORT_SYMBOL_GPL(devm_reset_controller_register); |
150 | 153 | ||
154 | /** | ||
155 | * reset_controller_add_lookup - register a set of lookup entries | ||
156 | * @lookup: array of reset lookup entries | ||
157 | * @num_entries: number of entries in the lookup array | ||
158 | */ | ||
159 | void reset_controller_add_lookup(struct reset_control_lookup *lookup, | ||
160 | unsigned int num_entries) | ||
161 | { | ||
162 | struct reset_control_lookup *entry; | ||
163 | unsigned int i; | ||
164 | |||
165 | mutex_lock(&reset_lookup_mutex); | ||
166 | for (i = 0; i < num_entries; i++) { | ||
167 | entry = &lookup[i]; | ||
168 | |||
169 | if (!entry->dev_id || !entry->provider) { | ||
170 | pr_warn("%s(): reset lookup entry badly specified, skipping\n", | ||
171 | __func__); | ||
172 | continue; | ||
173 | } | ||
174 | |||
175 | list_add_tail(&entry->list, &reset_lookup_list); | ||
176 | } | ||
177 | mutex_unlock(&reset_lookup_mutex); | ||
178 | } | ||
179 | EXPORT_SYMBOL_GPL(reset_controller_add_lookup); | ||
180 | |||
151 | static inline struct reset_control_array * | 181 | static inline struct reset_control_array * |
152 | rstc_to_array(struct reset_control *rstc) { | 182 | rstc_to_array(struct reset_control *rstc) { |
153 | return container_of(rstc, struct reset_control_array, base); | 183 | return container_of(rstc, struct reset_control_array, base); |
@@ -493,6 +523,70 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
493 | } | 523 | } |
494 | EXPORT_SYMBOL_GPL(__of_reset_control_get); | 524 | EXPORT_SYMBOL_GPL(__of_reset_control_get); |
495 | 525 | ||
526 | static struct reset_controller_dev * | ||
527 | __reset_controller_by_name(const char *name) | ||
528 | { | ||
529 | struct reset_controller_dev *rcdev; | ||
530 | |||
531 | lockdep_assert_held(&reset_list_mutex); | ||
532 | |||
533 | list_for_each_entry(rcdev, &reset_controller_list, list) { | ||
534 | if (!rcdev->dev) | ||
535 | continue; | ||
536 | |||
537 | if (!strcmp(name, dev_name(rcdev->dev))) | ||
538 | return rcdev; | ||
539 | } | ||
540 | |||
541 | return NULL; | ||
542 | } | ||
543 | |||
544 | static struct reset_control * | ||
545 | __reset_control_get_from_lookup(struct device *dev, const char *con_id, | ||
546 | bool shared, bool optional) | ||
547 | { | ||
548 | const struct reset_control_lookup *lookup; | ||
549 | struct reset_controller_dev *rcdev; | ||
550 | const char *dev_id = dev_name(dev); | ||
551 | struct reset_control *rstc = NULL; | ||
552 | |||
553 | if (!dev) | ||
554 | return ERR_PTR(-EINVAL); | ||
555 | |||
556 | mutex_lock(&reset_lookup_mutex); | ||
557 | |||
558 | list_for_each_entry(lookup, &reset_lookup_list, list) { | ||
559 | if (strcmp(lookup->dev_id, dev_id)) | ||
560 | continue; | ||
561 | |||
562 | if ((!con_id && !lookup->con_id) || | ||
563 | ((con_id && lookup->con_id) && | ||
564 | !strcmp(con_id, lookup->con_id))) { | ||
565 | mutex_lock(&reset_list_mutex); | ||
566 | rcdev = __reset_controller_by_name(lookup->provider); | ||
567 | if (!rcdev) { | ||
568 | mutex_unlock(&reset_list_mutex); | ||
569 | mutex_unlock(&reset_lookup_mutex); | ||
570 | /* Reset provider may not be ready yet. */ | ||
571 | return ERR_PTR(-EPROBE_DEFER); | ||
572 | } | ||
573 | |||
574 | rstc = __reset_control_get_internal(rcdev, | ||
575 | lookup->index, | ||
576 | shared); | ||
577 | mutex_unlock(&reset_list_mutex); | ||
578 | break; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | mutex_unlock(&reset_lookup_mutex); | ||
583 | |||
584 | if (!rstc) | ||
585 | return optional ? NULL : ERR_PTR(-ENOENT); | ||
586 | |||
587 | return rstc; | ||
588 | } | ||
589 | |||
496 | struct reset_control *__reset_control_get(struct device *dev, const char *id, | 590 | struct reset_control *__reset_control_get(struct device *dev, const char *id, |
497 | int index, bool shared, bool optional) | 591 | int index, bool shared, bool optional) |
498 | { | 592 | { |
@@ -500,7 +594,7 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id, | |||
500 | return __of_reset_control_get(dev->of_node, id, index, shared, | 594 | return __of_reset_control_get(dev->of_node, id, index, shared, |
501 | optional); | 595 | optional); |
502 | 596 | ||
503 | return optional ? NULL : ERR_PTR(-EINVAL); | 597 | return __reset_control_get_from_lookup(dev, id, shared, optional); |
504 | } | 598 | } |
505 | EXPORT_SYMBOL_GPL(__reset_control_get); | 599 | EXPORT_SYMBOL_GPL(__reset_control_get); |
506 | 600 | ||
diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c new file mode 100644 index 000000000000..b221a28041fa --- /dev/null +++ b/drivers/reset/reset-stm32mp1.c | |||
@@ -0,0 +1,115 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) STMicroelectronics 2018 - All Rights Reserved | ||
4 | * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics. | ||
5 | */ | ||
6 | |||
7 | #include <linux/device.h> | ||
8 | #include <linux/err.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/of.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/reset-controller.h> | ||
13 | |||
14 | #define CLR_OFFSET 0x4 | ||
15 | |||
16 | struct stm32_reset_data { | ||
17 | struct reset_controller_dev rcdev; | ||
18 | void __iomem *membase; | ||
19 | }; | ||
20 | |||
21 | static inline struct stm32_reset_data * | ||
22 | to_stm32_reset_data(struct reset_controller_dev *rcdev) | ||
23 | { | ||
24 | return container_of(rcdev, struct stm32_reset_data, rcdev); | ||
25 | } | ||
26 | |||
27 | static int stm32_reset_update(struct reset_controller_dev *rcdev, | ||
28 | unsigned long id, bool assert) | ||
29 | { | ||
30 | struct stm32_reset_data *data = to_stm32_reset_data(rcdev); | ||
31 | int reg_width = sizeof(u32); | ||
32 | int bank = id / (reg_width * BITS_PER_BYTE); | ||
33 | int offset = id % (reg_width * BITS_PER_BYTE); | ||
34 | void __iomem *addr; | ||
35 | |||
36 | addr = data->membase + (bank * reg_width); | ||
37 | if (!assert) | ||
38 | addr += CLR_OFFSET; | ||
39 | |||
40 | writel(BIT(offset), addr); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static int stm32_reset_assert(struct reset_controller_dev *rcdev, | ||
46 | unsigned long id) | ||
47 | { | ||
48 | return stm32_reset_update(rcdev, id, true); | ||
49 | } | ||
50 | |||
51 | static int stm32_reset_deassert(struct reset_controller_dev *rcdev, | ||
52 | unsigned long id) | ||
53 | { | ||
54 | return stm32_reset_update(rcdev, id, false); | ||
55 | } | ||
56 | |||
57 | static int stm32_reset_status(struct reset_controller_dev *rcdev, | ||
58 | unsigned long id) | ||
59 | { | ||
60 | struct stm32_reset_data *data = to_stm32_reset_data(rcdev); | ||
61 | int reg_width = sizeof(u32); | ||
62 | int bank = id / (reg_width * BITS_PER_BYTE); | ||
63 | int offset = id % (reg_width * BITS_PER_BYTE); | ||
64 | u32 reg; | ||
65 | |||
66 | reg = readl(data->membase + (bank * reg_width)); | ||
67 | |||
68 | return !!(reg & BIT(offset)); | ||
69 | } | ||
70 | |||
71 | static const struct reset_control_ops stm32_reset_ops = { | ||
72 | .assert = stm32_reset_assert, | ||
73 | .deassert = stm32_reset_deassert, | ||
74 | .status = stm32_reset_status, | ||
75 | }; | ||
76 | |||
77 | static const struct of_device_id stm32_reset_dt_ids[] = { | ||
78 | { .compatible = "st,stm32mp1-rcc"}, | ||
79 | { /* sentinel */ }, | ||
80 | }; | ||
81 | |||
82 | static int stm32_reset_probe(struct platform_device *pdev) | ||
83 | { | ||
84 | struct device *dev = &pdev->dev; | ||
85 | struct stm32_reset_data *data; | ||
86 | void __iomem *membase; | ||
87 | struct resource *res; | ||
88 | |||
89 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
90 | if (!data) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
94 | membase = devm_ioremap_resource(dev, res); | ||
95 | if (IS_ERR(membase)) | ||
96 | return PTR_ERR(membase); | ||
97 | |||
98 | data->membase = membase; | ||
99 | data->rcdev.owner = THIS_MODULE; | ||
100 | data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; | ||
101 | data->rcdev.ops = &stm32_reset_ops; | ||
102 | data->rcdev.of_node = dev->of_node; | ||
103 | |||
104 | return devm_reset_controller_register(dev, &data->rcdev); | ||
105 | } | ||
106 | |||
107 | static struct platform_driver stm32_reset_driver = { | ||
108 | .probe = stm32_reset_probe, | ||
109 | .driver = { | ||
110 | .name = "stm32mp1-reset", | ||
111 | .of_match_table = stm32_reset_dt_ids, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | builtin_platform_driver(stm32_reset_driver); | ||
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index e8bb023ff15e..360e06b20c53 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c | |||
@@ -63,6 +63,7 @@ static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { | |||
63 | UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */ | 63 | UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */ |
64 | UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ | 64 | UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ |
65 | UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ | 65 | UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ |
66 | UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ | ||
66 | UNIPHIER_RESET_END, | 67 | UNIPHIER_RESET_END, |
67 | }; | 68 | }; |
68 | 69 | ||
@@ -72,6 +73,7 @@ static const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { | |||
72 | UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (PCIe, USB3) */ | 73 | UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (PCIe, USB3) */ |
73 | UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ | 74 | UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ |
74 | UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ | 75 | UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ |
76 | UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ | ||
75 | UNIPHIER_RESET_END, | 77 | UNIPHIER_RESET_END, |
76 | }; | 78 | }; |
77 | 79 | ||
@@ -88,6 +90,7 @@ static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { | |||
88 | UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */ | 90 | UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */ |
89 | UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */ | 91 | UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */ |
90 | UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */ | 92 | UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */ |
93 | UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ | ||
91 | UNIPHIER_RESET_END, | 94 | UNIPHIER_RESET_END, |
92 | }; | 95 | }; |
93 | 96 | ||
@@ -121,6 +124,8 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { | |||
121 | static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = { | 124 | static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = { |
122 | UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ | 125 | UNIPHIER_RESETX(2, 0x200c, 0), /* NAND */ |
123 | UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ | 126 | UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ |
127 | UNIPHIER_RESETX(6, 0x200c, 9), /* Ether0 */ | ||
128 | UNIPHIER_RESETX(7, 0x200c, 10), /* Ether1 */ | ||
124 | UNIPHIER_RESETX(8, 0x200c, 12), /* STDMAC */ | 129 | UNIPHIER_RESETX(8, 0x200c, 12), /* STDMAC */ |
125 | UNIPHIER_RESETX(12, 0x200c, 4), /* USB30 link (GIO0) */ | 130 | UNIPHIER_RESETX(12, 0x200c, 4), /* USB30 link (GIO0) */ |
126 | UNIPHIER_RESETX(13, 0x200c, 5), /* USB31 link (GIO1) */ | 131 | UNIPHIER_RESETX(13, 0x200c, 5), /* USB31 link (GIO1) */ |