summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch
blob: 220283e24c077d11bb7c87e17210b809462c3109 (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
From db310b43e5b444a4e2854f3d69d002c2f0d0605c Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Wed, 13 Mar 2019 15:53:24 -0700
Subject: [PATCH] misc: Add clock control logic into Aspeed LPC MBOX driver

If LPC MBOX driver is registered ahead of lpc-ctrl module, LPC
MBOX 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
MBOX driver.

Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
 arch/arm/boot/dts/aspeed-g4.dtsi |  1 +
 arch/arm/boot/dts/aspeed-g5.dtsi |  1 +
 drivers/misc/aspeed-lpc-mbox.c   | 42 +++++++++++++++++++++++++++++++---------
 3 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index a5072ed1f823..729245b74c13 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -389,6 +389,7 @@
 						reg = <0x180 0x5c>;
 						interrupts = <46>;
 						#mbox-cells = <1>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 				};
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 6a2f161e7548..df9d63a94264 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -493,6 +493,7 @@
 						reg = <0x180 0x5c>;
 						interrupts = <46>;
 						#mbox-cells = <1>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 				};
diff --git a/drivers/misc/aspeed-lpc-mbox.c b/drivers/misc/aspeed-lpc-mbox.c
index 0933e0553953..f105d27786ac 100644
--- a/drivers/misc/aspeed-lpc-mbox.c
+++ b/drivers/misc/aspeed-lpc-mbox.c
@@ -7,6 +7,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/syscon.h>
 #include <linux/miscdevice.h>
@@ -37,7 +38,9 @@
 struct aspeed_mbox {
 	struct miscdevice	miscdev;
 	struct regmap		*regmap;
+	struct clk		*clk;
 	unsigned int		base;
+	int			irq;
 	wait_queue_head_t	queue;
 	struct mutex		mutex;
 };
@@ -237,16 +240,16 @@ static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox,
 		struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	int rc, irq;
+	int rc;
 
-	irq = irq_of_parse_and_map(dev->of_node, 0);
-	if (!irq)
+	mbox->irq = platform_get_irq(pdev, 0);
+	if (!mbox->irq)
 		return -ENODEV;
 
-	rc = devm_request_irq(dev, irq, aspeed_mbox_irq,
-			IRQF_SHARED, DEVICE_NAME, mbox);
+	rc = devm_request_irq(dev, mbox->irq, aspeed_mbox_irq,
+			      IRQF_SHARED, DEVICE_NAME, mbox);
 	if (rc < 0) {
-		dev_err(dev, "Unable to request IRQ %d\n", irq);
+		dev_err(dev, "Unable to request IRQ %d\n", mbox->irq);
 		return rc;
 	}
 
@@ -301,6 +304,19 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
 	mutex_init(&mbox->mutex);
 	init_waitqueue_head(&mbox->queue);
 
+	mbox->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mbox->clk)) {
+		rc = PTR_ERR(mbox->clk);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "couldn't get clock\n");
+		return rc;
+	}
+	rc = clk_prepare_enable(mbox->clk);
+	if (rc) {
+		dev_err(dev, "couldn't enable clock\n");
+		return rc;
+	}
+
 	mbox->miscdev.minor = MISC_DYNAMIC_MINOR;
 	mbox->miscdev.name = DEVICE_NAME;
 	mbox->miscdev.fops = &aspeed_mbox_fops;
@@ -308,17 +324,24 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
 	rc = misc_register(&mbox->miscdev);
 	if (rc) {
 		dev_err(dev, "Unable to register device\n");
-		return rc;
+		goto err;
 	}
 
 	rc = aspeed_mbox_config_irq(mbox, pdev);
 	if (rc) {
 		dev_err(dev, "Failed to configure IRQ\n");
 		misc_deregister(&mbox->miscdev);
-		return rc;
+		goto err;
 	}
 
+	dev_info(&pdev->dev, "LPC mbox registered, irq %d\n", mbox->irq);
+
 	return 0;
+
+err:
+	clk_disable_unprepare(mbox->clk);
+
+	return rc;
 }
 
 static int aspeed_mbox_remove(struct platform_device *pdev)
@@ -326,6 +349,7 @@ static int aspeed_mbox_remove(struct platform_device *pdev)
 	struct aspeed_mbox *mbox = dev_get_drvdata(&pdev->dev);
 
 	misc_deregister(&mbox->miscdev);
+	clk_disable_unprepare(mbox->clk);
 
 	return 0;
 }
@@ -335,6 +359,7 @@ static const struct of_device_id aspeed_mbox_match[] = {
 	{ .compatible = "aspeed,ast2500-mbox" },
 	{ },
 };
+MODULE_DEVICE_TABLE(of, aspeed_mbox_match);
 
 static struct platform_driver aspeed_mbox_driver = {
 	.driver = {
@@ -347,7 +372,6 @@ static struct platform_driver aspeed_mbox_driver = {
 
 module_platform_driver(aspeed_mbox_driver);
 
-MODULE_DEVICE_TABLE(of, aspeed_mbox_match);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
 MODULE_DESCRIPTION("Aspeed mailbox device driver");
-- 
2.7.4