summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2018-06-07 11:26:46 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2018-06-07 11:26:46 +1000
commit2db7a8dadc060547f24a991e1fe2c500d3cc7c14 (patch)
tree4a9f62de8c6174352cd221544f883515099ca430
parent39c7aeb82ed5d850cd55065eaedfb8c0cccef46f (diff)
downloadcf-fsi-2db7a8dadc060547f24a991e1fe2c500d3cc7c14.tar.gz
cf-fsi-2db7a8dadc060547f24a991e1fe2c500d3cc7c14.zip
Fix problems with GPIO usage
The "value" register doesn't return the last data written when read but returns the value sampled on the line, which may or may not be the value written for an output GPIO. For example it can be delayed by the synchronizers. So whenever the CF reads the value to adjust its caches it needs to use the "data read" register intead, otherwise it can clobber values set by Linux when doing handshaking. Also don't use %d0 for DTRA, use %d1 to avoid interrupts clobber and do read/modify/write cycles on it as it's not a permanent cached value, just a temporary. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--cf-code/cf-fsi-fw.S47
-rw-r--r--cf-code/cf-fsi-romulus.h9
-rw-r--r--cf-code/cf-fsi-witherspoon.h9
3 files changed, 42 insertions, 23 deletions
diff --git a/cf-code/cf-fsi-fw.S b/cf-code/cf-fsi-fw.S
index 6a96fb5..0ac7375 100644
--- a/cf-code/cf-fsi-fw.S
+++ b/cf-code/cf-fsi-fw.S
@@ -39,17 +39,19 @@
* potential overlaps
*/
#define DCLK d7
-#if CLOCK_GPIO_REG == DATA_GPIO_REG
+
+#if CLOCK_GPIO_VREG == DATA_GPIO_VEG
#define DDAT d7
#else
#define DDAT d6
#endif
-#if TRANS_GPIO_REG == CLOCK_GPIO_REG
+
+#if TRANS_GPIO_VREG == CLOCK_GPIO_VREG
#define DTRA d7
-#elif TRANS_GPIO_REG == DATA_GPIO_REG
+#elif TRANS_GPIO_VREG == DATA_GPIO_VREG
#define DTRA d6
#else
-#define DTRA d0
+#define DTRA d1 /* Temp, not a cache */
#endif
/* Tracing macro */
@@ -90,7 +92,7 @@
* value along with the low clock edge. Thus we don't need to
* set it here, thus saving a PCLK
*/
-#if DATA_GPIO_REG != CLOCK_GPIO_REG
+#if DATA_GPIO_VREG != CLOCK_GPIO_VREG
move.l %DDAT,%a4@(0)
#endif
clock_toggle
@@ -101,7 +103,7 @@
trace #TR_CLKZ
trace \reg
bset.l #DATA_GPIO_BIT,%DDAT
-#if DATA_GPIO_REG != CLOCK_GPIO_REG
+#if DATA_GPIO_VREG != CLOCK_GPIO_VREG
move.l %DDAT,%a4@(0)
#endif
99: clock_toggle
@@ -163,23 +165,32 @@ _start:
movea.l #SRAM_BASE_BE,%a1
movea.l #GPIO_BASE,%a4
movea.l %a4,%a5
- add.l #CLOCK_GPIO_REG,%a5
- add.l #DATA_GPIO_REG,%a4
+ add.l #CLOCK_GPIO_VREG,%a5
+ add.l #DATA_GPIO_VREG,%a4
movea.l #CVIC_BASE,%a2
/* Store clock bit number */
moveq.l #CLOCK_GPIO_BIT,%d5
- /* Load GPIO values into caches and set initial values */
- move.l %a5@(0),%DCLK
- move.l %a4@(0),%DDAT
- move.l %a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG),%DTRA
+ /*
+ * Load GPIO values into caches and set initial values
+ *
+ * Note: We load from the "Data Read" register which
+ * contains the value of the write latch, and not
+ * the "Value" register which, when read, returns
+ * the value sampled on the line. The reason is that
+ * the value can be missing recent changes due to
+ * being behind synchronizers.
+ */
+ move.l %a5@(CLOCK_GPIO_DREG-CLOCK_GPIO_VREG),%DCLK
+ move.l %a4@(DATA_GPIO_DREG-DATA_GPIO_VREG),%DDAT
+ move.l %a5@(TRANS_GPIO_DREG-CLOCK_GPIO_VREG),%DTRA
bset.l #CLOCK_GPIO_BIT,%DCLK
bset.l #DATA_GPIO_BIT,%DDAT
bset.l #TRANS_GPIO_BIT,%DTRA
move.l %DCLK,%a5@(0)
move.l %DDAT,%a4@(0)
- move.l %DTRA,%a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG)
+ move.l %DTRA,%a5@(TRANS_GPIO_VREG-CLOCK_GPIO_VREG)
/* Configure all GPIOs as output */
move.l %a5@(4),%d0
@@ -188,9 +199,9 @@ _start:
move.l %a4@(4),%d0
bset.l #DATA_GPIO_BIT,%d0
move.l %d0,%a4@(4)
- move.l %DTRA,%a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG+4)
+ move.l %a5@(TRANS_GPIO_VREG-CLOCK_GPIO_VREG+4),%d0
bset.l #TRANS_GPIO_BIT,%d0
- move.l %DTRA,%a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG+4)
+ move.l %d0,%a5@(TRANS_GPIO_VREG-CLOCK_GPIO_VREG+4)
/* Initialize A6 to point to command area */
lea %a1@(CMD_DATA),%a6
@@ -483,14 +494,16 @@ config_gpio_out:
move.l %d0,%a4@(4)
/* Set transceivers to output */
+ move.l %a5@(TRANS_GPIO_DREG-CLOCK_GPIO_VREG),%DTRA
bset.l #TRANS_GPIO_BIT,%DTRA
- move.l %DTRA,%a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG)
+ move.l %DTRA,%a5@(TRANS_GPIO_VREG-CLOCK_GPIO_VREG)
rts
config_gpio_in:
/* Set transceiver to input */
+ move.l %a5@(TRANS_GPIO_DREG-CLOCK_GPIO_VREG),%DTRA
bclr.l #TRANS_GPIO_BIT,%DTRA
- move.l %DTRA,%a5@(TRANS_GPIO_REG-CLOCK_GPIO_REG)
+ move.l %DTRA,%a5@(TRANS_GPIO_VREG-CLOCK_GPIO_VREG)
/* Configure data GPIO as input */
move.l %a4@(4),%d0
diff --git a/cf-code/cf-fsi-romulus.h b/cf-code/cf-fsi-romulus.h
index 5e8be70..4cb3f10 100644
--- a/cf-code/cf-fsi-romulus.h
+++ b/cf-code/cf-fsi-romulus.h
@@ -1,8 +1,11 @@
-#define CLOCK_GPIO_REG 0x1e0
+#define CLOCK_GPIO_VREG 0x1e0
+#define CLOCK_GPIO_DREG 0x0d8
#define CLOCK_GPIO_BIT 16
-#define DATA_GPIO_REG 0x1e0
+#define DATA_GPIO_VREG 0x1e0
+#define DATA_GPIO_DREG 0x0d8
#define DATA_GPIO_BIT 18
-#define TRANS_GPIO_REG 0x080
+#define TRANS_GPIO_VREG 0x080
+#define TRANS_GPIO_DREG 0x0d0
#define TRANS_GPIO_BIT 10
#define SYS_SIG SYS_SIG_ROMULUS
diff --git a/cf-code/cf-fsi-witherspoon.h b/cf-code/cf-fsi-witherspoon.h
index 85b7f19..528101b 100644
--- a/cf-code/cf-fsi-witherspoon.h
+++ b/cf-code/cf-fsi-witherspoon.h
@@ -1,8 +1,11 @@
-#define CLOCK_GPIO_REG 0x1e0
+#define CLOCK_GPIO_VREG 0x1e0
+#define CLOCK_GPIO_DREG 0x0d8
#define CLOCK_GPIO_BIT 16
-#define DATA_GPIO_REG 0x020
+#define DATA_GPIO_VREG 0x020
+#define DATA_GPIO_DREG 0x0c4
#define DATA_GPIO_BIT 0
-#define TRANS_GPIO_REG 0x080
+#define TRANS_GPIO_VREG 0x080
+#define TRANS_GPIO_DREG 0x0d0
#define TRANS_GPIO_BIT 10
#define SYS_SIG SYS_SIG_WITHERSPOON
OpenPOWER on IntegriCloud