aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-11-02 11:36:23 -0400
committerArnd Bergmann <arnd@arndb.de>2017-11-02 11:36:23 -0400
commite54a7867f3c6a631ccfdc6db86f33a2fac4e103e (patch)
tree765fb101f37e591978952d9bffda791f3c7af485
parent51d3290c3ad6ba691bd66df8ead6e7c19dc995f1 (diff)
parent8fca9e95243128961357577ba394ec1d4bd8c92c (diff)
Merge tag 'amlogic-drivers-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic into next/drivers
Pull "Amlogic drivers for v4.15, round 2" from Kevin Hilman: - add PM domain driver for GX VPU * tag 'amlogic-drivers-2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic: dt-bindings: power: add amlogic meson power domain bindings soc: amlogic: add Meson GX VPU Domains driver
-rw-r--r--Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt61
-rw-r--r--drivers/soc/amlogic/Kconfig10
-rw-r--r--drivers/soc/amlogic/Makefile1
-rw-r--r--drivers/soc/amlogic/meson-gx-pwrc-vpu.c234
4 files changed, 306 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt
new file mode 100644
index 000000000000..1cd050b4054c
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt
@@ -0,0 +1,61 @@
1Amlogic Meson Power Controller
2==============================
3
4The Amlogic Meson SoCs embeds an internal Power domain controller.
5
6VPU Power Domain
7----------------
8
9The Video Processing Unit power domain is controlled by this power controller,
10but the domain requires some external resources to meet the correct power
11sequences.
12The bindings must respect the power domain bindings as described in the file
13power_domain.txt
14
15Device Tree Bindings:
16---------------------
17
18Required properties:
19- compatible: should be "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs
20- #power-domain-cells: should be 0
21- amlogic,hhi-sysctrl: phandle to the HHI sysctrl node
22- resets: phandles to the reset lines needed for this power demain sequence
23 as described in ../reset/reset.txt
24- clocks: from common clock binding: handle to VPU and VAPB clocks
25- clock-names: from common clock binding: must contain "vpu", "vapb"
26 corresponding to entry in the clocks property.
27
28Parent node should have the following properties :
29- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"
30- reg: base address and size of the AO system control register space.
31
32Example:
33-------
34
35ao_sysctrl: sys-ctrl@0 {
36 compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd";
37 reg = <0x0 0x0 0x0 0x100>;
38
39 pwrc_vpu: power-controller-vpu {
40 compatible = "amlogic,meson-gx-pwrc-vpu";
41 #power-domain-cells = <0>;
42 amlogic,hhi-sysctrl = <&sysctrl>;
43 resets = <&reset RESET_VIU>,
44 <&reset RESET_VENC>,
45 <&reset RESET_VCBUS>,
46 <&reset RESET_BT656>,
47 <&reset RESET_DVIN_RESET>,
48 <&reset RESET_RDMA>,
49 <&reset RESET_VENCI>,
50 <&reset RESET_VENCP>,
51 <&reset RESET_VDAC>,
52 <&reset RESET_VDI6>,
53 <&reset RESET_VENCL>,
54 <&reset RESET_VID_LOCK>;
55 clocks = <&clkc CLKID_VPU>,
56 <&clkc CLKID_VAPB>;
57 clock-names = "vpu", "vapb";
58 };
59};
60
61
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
index ef0b8f6c53e0..1621bb25a1ea 100644
--- a/drivers/soc/amlogic/Kconfig
+++ b/drivers/soc/amlogic/Kconfig
@@ -9,6 +9,16 @@ config MESON_GX_SOCINFO
9 Say yes to support decoding of Amlogic Meson GX SoC family 9 Say yes to support decoding of Amlogic Meson GX SoC family
10 information about the type, package and version. 10 information about the type, package and version.
11 11
12config MESON_GX_PM_DOMAINS
13 bool "Amlogic Meson GX Power Domains driver"
14 depends on ARCH_MESON || COMPILE_TEST
15 default ARCH_MESON
16 select PM_GENERIC_DOMAINS
17 select PM_GENERIC_DOMAINS_OF
18 help
19 Say yes to expose Amlogic Meson GX Power Domains as
20 Generic Power Domains.
21
12config MESON_MX_SOCINFO 22config MESON_MX_SOCINFO
13 bool "Amlogic Meson MX SoC Information driver" 23 bool "Amlogic Meson MX SoC Information driver"
14 depends on ARCH_MESON || COMPILE_TEST 24 depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
index 1f5df50ebd73..8fa321893928 100644
--- a/drivers/soc/amlogic/Makefile
+++ b/drivers/soc/amlogic/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o 1obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
2obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
2obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o 3obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
new file mode 100644
index 000000000000..bf5190b65ad9
--- /dev/null
+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
@@ -0,0 +1,234 @@
1/*
2 * Copyright (c) 2017 BayLibre, SAS
3 * Author: Neil Armstrong <narmstrong@baylibre.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <linux/of_address.h>
9#include <linux/platform_device.h>
10#include <linux/pm_domain.h>
11#include <linux/bitfield.h>
12#include <linux/regmap.h>
13#include <linux/mfd/syscon.h>
14#include <linux/reset.h>
15#include <linux/clk.h>
16
17/* AO Offsets */
18
19#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
20
21#define GEN_PWR_VPU_HDMI BIT(8)
22#define GEN_PWR_VPU_HDMI_ISO BIT(9)
23
24/* HHI Offsets */
25
26#define HHI_MEM_PD_REG0 (0x40 << 2)
27#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
28#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
29
30struct meson_gx_pwrc_vpu {
31 struct generic_pm_domain genpd;
32 struct regmap *regmap_ao;
33 struct regmap *regmap_hhi;
34 struct reset_control *rstc;
35 struct clk *vpu_clk;
36 struct clk *vapb_clk;
37 bool powered;
38};
39
40static inline
41struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d)
42{
43 return container_of(d, struct meson_gx_pwrc_vpu, genpd);
44}
45
46static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
47{
48 struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
49 int i;
50
51 regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
52 GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
53 udelay(20);
54
55 /* Power Down Memories */
56 for (i = 0; i < 32; i += 2) {
57 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
58 0x2 << i, 0x3 << i);
59 udelay(5);
60 }
61 for (i = 0; i < 32; i += 2) {
62 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
63 0x2 << i, 0x3 << i);
64 udelay(5);
65 }
66 for (i = 8; i < 16; i++) {
67 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
68 BIT(i), BIT(i));
69 udelay(5);
70 }
71 udelay(20);
72
73 regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
74 GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
75
76 msleep(20);
77
78 clk_disable_unprepare(pd->vpu_clk);
79 clk_disable_unprepare(pd->vapb_clk);
80
81 pd->powered = false;
82
83 return 0;
84}
85
86static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
87{
88 int ret;
89
90 ret = clk_prepare_enable(pd->vpu_clk);
91 if (ret)
92 return ret;
93
94 return clk_prepare_enable(pd->vapb_clk);
95}
96
97static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
98{
99 struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
100 int ret;
101 int i;
102
103 regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
104 GEN_PWR_VPU_HDMI, 0);
105 udelay(20);
106
107 /* Power Up Memories */
108 for (i = 0; i < 32; i += 2) {
109 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
110 0x2 << i, 0);
111 udelay(5);
112 }
113
114 for (i = 0; i < 32; i += 2) {
115 regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
116 0x2 << i, 0);
117 udelay(5);
118 }
119
120 for (i = 8; i < 16; i++) {
121 regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
122 BIT(i), 0);
123 udelay(5);
124 }
125 udelay(20);
126
127 ret = reset_control_assert(pd->rstc);
128 if (ret)
129 return ret;
130
131 regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
132 GEN_PWR_VPU_HDMI_ISO, 0);
133
134 ret = reset_control_deassert(pd->rstc);
135 if (ret)
136 return ret;
137
138 ret = meson_gx_pwrc_vpu_setup_clk(pd);
139 if (ret)
140 return ret;
141
142 pd->powered = true;
143
144 return 0;
145}
146
147static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd)
148{
149 u32 reg;
150
151 regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, &reg);
152
153 return (reg & GEN_PWR_VPU_HDMI);
154}
155
156static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
157 .genpd = {
158 .name = "vpu_hdmi",
159 .power_off = meson_gx_pwrc_vpu_power_off,
160 .power_on = meson_gx_pwrc_vpu_power_on,
161 },
162};
163
164static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
165{
166 struct regmap *regmap_ao, *regmap_hhi;
167 struct reset_control *rstc;
168 struct clk *vpu_clk;
169 struct clk *vapb_clk;
170
171 regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
172 if (IS_ERR(regmap_ao)) {
173 dev_err(&pdev->dev, "failed to get regmap\n");
174 return PTR_ERR(regmap_ao);
175 }
176
177 regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
178 "amlogic,hhi-sysctrl");
179 if (IS_ERR(regmap_hhi)) {
180 dev_err(&pdev->dev, "failed to get HHI regmap\n");
181 return PTR_ERR(regmap_hhi);
182 }
183
184 rstc = devm_reset_control_array_get(&pdev->dev, false, false);
185 if (IS_ERR(rstc)) {
186 dev_err(&pdev->dev, "failed to get reset lines\n");
187 return PTR_ERR(rstc);
188 }
189
190 vpu_clk = devm_clk_get(&pdev->dev, "vpu");
191 if (IS_ERR(vpu_clk)) {
192 dev_err(&pdev->dev, "vpu clock request failed\n");
193 return PTR_ERR(vpu_clk);
194 }
195
196 vapb_clk = devm_clk_get(&pdev->dev, "vapb");
197 if (IS_ERR(vapb_clk)) {
198 dev_err(&pdev->dev, "vapb clock request failed\n");
199 return PTR_ERR(vapb_clk);
200 }
201
202 vpu_hdmi_pd.regmap_ao = regmap_ao;
203 vpu_hdmi_pd.regmap_hhi = regmap_hhi;
204 vpu_hdmi_pd.rstc = rstc;
205 vpu_hdmi_pd.vpu_clk = vpu_clk;
206 vpu_hdmi_pd.vapb_clk = vapb_clk;
207
208 pm_genpd_init(&vpu_hdmi_pd.genpd, &simple_qos_governor,
209 meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd));
210
211 return of_genpd_add_provider_simple(pdev->dev.of_node,
212 &vpu_hdmi_pd.genpd);
213}
214
215static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
216{
217 if (vpu_hdmi_pd.powered)
218 meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
219}
220
221static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
222 { .compatible = "amlogic,meson-gx-pwrc-vpu" },
223 { /* sentinel */ }
224};
225
226static struct platform_driver meson_gx_pwrc_vpu_driver = {
227 .probe = meson_gx_pwrc_vpu_probe,
228 .shutdown = meson_gx_pwrc_vpu_shutdown,
229 .driver = {
230 .name = "meson_gx_pwrc_vpu",
231 .of_match_table = meson_gx_pwrc_vpu_match_table,
232 },
233};
234builtin_platform_driver(meson_gx_pwrc_vpu_driver);