aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch
blob: 66b934ffb375686ca5fed19c034eb67f4dd263af (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
From 82033037ad413326a3a1425f05d89b0c7abf8f73 Mon Sep 17 00:00:00 2001
From: Derek Lai <Derek.Lai@amd.com>
Date: Wed, 22 May 2019 14:49:23 +0800
Subject: [PATCH 2071/2940] drm/amd/display: add i2c_hw_Status check to make
 sure as HW I2c in use

1. Add i2c_hw_Status check to make sure when HW i2c is in use.
2. Don't reset HW engine in is_hw_busy() and instead do this in
process_transaction() because SW i2c does not check if hw i2c is in use

Signed-off-by: Derek Lai <Derek.Lai@amd.com>
Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
---
 .../gpu/drm/amd/display/dc/dce/dce_i2c_hw.c   | 65 +++++++++++--------
 .../gpu/drm/amd/display/dc/dce/dce_i2c_hw.h   |  5 ++
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
index 526aab438374..7f2460caa2a6 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
@@ -149,6 +149,36 @@ static void process_channel_reply(
 	}
 }
 
+static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw)
+{
+	unsigned int arbitrate;
+	unsigned int i2c_hw_status;
+
+	REG_GET(HW_STATUS, DC_I2C_DDC1_HW_STATUS, &i2c_hw_status);
+	if (i2c_hw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW)
+		return false;
+
+	REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
+	if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY)
+		return false;
+
+	return true;
+}
+
+static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
+{
+	uint32_t i2c_sw_status = 0;
+
+	REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
+	if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
+		return false;
+
+	if (is_engine_available(dce_i2c_hw))
+		return false;
+
+	return true;
+}
+
 static bool process_transaction(
 	struct dce_i2c_hw *dce_i2c_hw,
 	struct i2c_request_transaction_data *request)
@@ -159,6 +189,11 @@ static bool process_transaction(
 	bool last_transaction = false;
 	uint32_t value = 0;
 
+	if (is_hw_busy(dce_i2c_hw)) {
+		request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
+		return false;
+	}
+
 	last_transaction = ((dce_i2c_hw->transaction_count == 3) ||
 			(request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) ||
 			(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ));
@@ -294,27 +329,12 @@ static bool setup_engine(
 	 * Enable restart of SW I2C that was interrupted by HW
 	 * disable queuing of software while I2C is in use by HW
 	 */
-	REG_UPDATE_2(DC_I2C_ARBITRATION,
-		     DC_I2C_NO_QUEUED_SW_GO, 0,
-		     DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
+	REG_UPDATE(DC_I2C_ARBITRATION,
+			DC_I2C_NO_QUEUED_SW_GO, 0);
 
 	return true;
 }
 
-static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
-{
-	uint32_t i2c_sw_status = 0;
-
-	REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
-	if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
-		return false;
-
-	reset_hw_engine(dce_i2c_hw);
-
-	REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
-	return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
-}
-
 static void release_engine(
 	struct dce_i2c_hw *dce_i2c_hw)
 {
@@ -349,16 +369,6 @@ static void release_engine(
 
 }
 
-static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw)
-{
-	unsigned int arbitrate;
-
-	REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
-	if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY)
-		return false;
-	return true;
-}
-
 struct dce_i2c_hw *acquire_i2c_hw_engine(
 	struct resource_pool *pool,
 	struct ddc *ddc)
@@ -456,6 +466,7 @@ static void submit_channel_request_hw(
 		request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
 		return;
 	}
+	reset_hw_engine(dce_i2c_hw);
 
 	execute_transaction(dce_i2c_hw);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
index f718e3d396f2..a633632f625b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
@@ -84,6 +84,7 @@ enum {
 #define I2C_HW_ENGINE_COMMON_REG_LIST(id)\
 	SRI(SETUP, DC_I2C_DDC, id),\
 	SRI(SPEED, DC_I2C_DDC, id),\
+	SRI(HW_STATUS, DC_I2C_DDC, id),\
 	SR(DC_I2C_ARBITRATION),\
 	SR(DC_I2C_CONTROL),\
 	SR(DC_I2C_SW_STATUS),\
@@ -105,6 +106,7 @@ enum {
 	I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL, mask_sh),\
 	I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY, mask_sh),\
 	I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY, mask_sh),\
+	I2C_SF(DC_I2C_DDC1_HW_STATUS, DC_I2C_DDC1_HW_STATUS, mask_sh),\
 	I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, mask_sh),\
 	I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, mask_sh),\
 	I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\
@@ -146,6 +148,7 @@ struct dce_i2c_shift {
 	uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL;
 	uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
 	uint8_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
+	uint8_t DC_I2C_DDC1_HW_STATUS;
 	uint8_t DC_I2C_SW_DONE_USING_I2C_REG;
 	uint8_t DC_I2C_SW_USE_I2C_REG_REQ;
 	uint8_t DC_I2C_NO_QUEUED_SW_GO;
@@ -185,6 +188,7 @@ struct dce_i2c_mask {
 	uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL;
 	uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
 	uint32_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
+	uint32_t DC_I2C_DDC1_HW_STATUS;
 	uint32_t DC_I2C_SW_DONE_USING_I2C_REG;
 	uint32_t DC_I2C_SW_USE_I2C_REG_REQ;
 	uint32_t DC_I2C_NO_QUEUED_SW_GO;
@@ -219,6 +223,7 @@ struct dce_i2c_mask {
 struct dce_i2c_registers {
 	uint32_t SETUP;
 	uint32_t SPEED;
+	uint32_t HW_STATUS;
 	uint32_t DC_I2C_ARBITRATION;
 	uint32_t DC_I2C_CONTROL;
 	uint32_t DC_I2C_SW_STATUS;
-- 
2.17.1