summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch
blob: 499662ac3f083c86639e4970d292a4dd526ea1ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
From 27675470115548612cee9153903aaffffb68177b Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Wed, 13 Mar 2019 15:36:34 -0700
Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS
 driver

If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS
block will be enabled without heart beating of LCLK until lpc-ctrl
enables the LCLK. This issue causes improper handling on host
interrupts when the host sends interrupt in that time frame. Then
kernel eventually forcibly disables the interrupt with dumping
stack and printing a 'nobody cared this irq' message out.

To prevent this issue, all LPC sub-nodes should enable LCLK
individually so this patch adds clock control logic into the LPC
KCS driver.

Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
 .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt    |  3 ++
 arch/arm/boot/dts/aspeed-g4.dtsi                   | 35 ++++++++++++++++++++
 arch/arm/boot/dts/aspeed-g5.dtsi                   |  6 +++-
 drivers/char/ipmi/kcs_bmc_aspeed.c                 | 37 ++++++++++++++++++----
 4 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
index d98a9bf45d6c..3453eb0bf8f2 100644
--- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
@@ -9,6 +9,8 @@ Required properties:
     "aspeed,ast2400-kcs-bmc"
     "aspeed,ast2500-kcs-bmc"
 - interrupts : interrupt generated by the controller
+- clocks: contains a phandle to the syscon node describing the clocks.
+	  There should then be one cell representing the clock to use.
 - kcs_chan : The LPC channel number in the controller
 - kcs_addr : The host CPU IO map address
 
@@ -19,6 +21,7 @@ Example:
         compatible = "aspeed,ast2500-kcs-bmc";
         reg = <0x0 0x80>;
         interrupts = <8>;
+        clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
         kcs_chan = <3>;
         kcs_addr = <0xCA2>;
         status = "okay";
diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index 1c00828da913..f04006f4cd27 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -298,6 +298,33 @@
 				lpc_bmc: lpc-bmc@0 {
 					compatible = "aspeed,ast2400-lpc-bmc";
 					reg = <0x0 0x80>;
+					reg-io-width = <4>;
+
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges = <0x0 0x0 0x80>;
+
+					kcs1: kcs1@0 {
+						compatible = "aspeed,ast2400-kcs-bmc";
+						interrupts = <8>;
+						kcs_chan = <1>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+						status = "disabled";
+					};
+					kcs2: kcs2@0 {
+						compatible = "aspeed,ast2400-kcs-bmc";
+						interrupts = <8>;
+						kcs_chan = <2>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+						status = "disabled";
+					};
+					kcs3: kcs3@0 {
+						compatible = "aspeed,ast2400-kcs-bmc";
+						interrupts = <8>;
+						kcs_chan = <3>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+						status = "disabled";
+					};
 				};
 
 				lpc_host: lpc-host@80 {
@@ -309,6 +336,14 @@
 					#size-cells = <1>;
 					ranges = <0x0 0x80 0x1e0>;
 
+					kcs4: kcs4@0 {
+						compatible = "aspeed,ast2400-kcs-bmc";
+						interrupts = <8>;
+						kcs_chan = <4>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+						status = "disabled";
+					};
+
 					lpc_ctrl: lpc-ctrl@0 {
 						compatible = "aspeed,ast2400-lpc-ctrl";
 						reg = <0x0 0x80>;
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index f2292bdfef91..d46b9ffc79de 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -135,7 +135,7 @@
 		};
 
 		vic: interrupt-controller@1e6c0080 {
-			compatible = "aspeed,ast2400-vic";
+			compatible = "aspeed,ast2500-vic";
 			interrupt-controller;
 			#interrupt-cells = <1>;
 			valid-sources = <0xfefff7ff 0x0807ffff>;
@@ -410,18 +410,21 @@
 						compatible = "aspeed,ast2500-kcs-bmc";
 						interrupts = <8>;
 						kcs_chan = <1>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 					kcs2: kcs2@0 {
 						compatible = "aspeed,ast2500-kcs-bmc";
 						interrupts = <8>;
 						kcs_chan = <2>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 					kcs3: kcs3@0 {
 						compatible = "aspeed,ast2500-kcs-bmc";
 						interrupts = <8>;
 						kcs_chan = <3>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 				};
@@ -439,6 +442,7 @@
 						compatible = "aspeed,ast2500-kcs-bmc";
 						interrupts = <8>;
 						kcs_chan = <4>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
index 3c955946e647..bd1912dc5a21 100644
--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -1,11 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2015-2018, Intel Corporation.
- */
+// Copyright (c) 2015-2019, Intel Corporation.
 
 #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
 
 #include <linux/atomic.h>
+#include <linux/clk.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -63,6 +62,7 @@
 
 struct aspeed_kcs_bmc {
 	struct regmap *map;
+	struct clk    *clk;
 };
 
 
@@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		rc = PTR_ERR(priv->clk);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "couldn't get clock\n");
+		return rc;
+	}
+	rc = clk_prepare_enable(priv->clk);
+	if (rc) {
+		dev_err(dev, "couldn't enable clock\n");
+		return rc;
+	}
+
 	kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
 	kcs_bmc->io_inputb = aspeed_kcs_inb;
 	kcs_bmc->io_outputb = aspeed_kcs_outb;
 
 	dev_set_drvdata(dev, kcs_bmc);
 
-	aspeed_kcs_set_address(kcs_bmc, addr);
-	aspeed_kcs_enable_channel(kcs_bmc, true);
 	rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
 	if (rc)
-		return rc;
+		goto err;
 
 	rc = misc_register(&kcs_bmc->miscdev);
 	if (rc) {
 		dev_err(dev, "Unable to register device\n");
-		return rc;
+		goto err;
 	}
 
+	aspeed_kcs_set_address(kcs_bmc, addr);
+	aspeed_kcs_enable_channel(kcs_bmc, true);
+
 	pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
 		chan, addr,
 		kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
 
 	return 0;
+
+err:
+	aspeed_kcs_enable_channel(kcs_bmc, false);
+	clk_disable_unprepare(priv->clk);
+
+	return rc;
 }
 
 static int aspeed_kcs_remove(struct platform_device *pdev)
 {
 	struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
+	struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
 
 	misc_deregister(&kcs_bmc->miscdev);
+	aspeed_kcs_enable_channel(kcs_bmc, false);
+	clk_disable_unprepare(priv->clk);
 
 	return 0;
 }
-- 
2.7.4