diff options
author | Masahiro Yamada <yamada.masahiro@socionext.com> | 2017-08-08 09:48:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-08-28 14:51:22 -0400 |
commit | d3a9184773c5cde483e249096ae7c7f98f310e20 (patch) | |
tree | 4e93c505f6457f63cfb498f2ce29bfaa54e45152 | |
parent | 39be40ce066da4d5d59bf53f72b914018bc84029 (diff) |
serial: 8250_uniphier: use CHAR register for canary to detect power-off
The 8250 core uses the SCR as a canary to discover if the console has
been powered-off.
This hardware does not have SCR at offset 7, but an unused register
CHAR at a different offset. As long as the character interrupt is
disabled, the register access has no impact, so it is useful as an
alternative scratch register.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/serial/8250/8250_uniphier.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 633ac378b7f2..97a45b798fcd 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c | |||
@@ -29,12 +29,13 @@ | |||
29 | * - MMIO32 (regshift = 2) | 29 | * - MMIO32 (regshift = 2) |
30 | * - FCR is not at 2, but 3 | 30 | * - FCR is not at 2, but 3 |
31 | * - LCR and MCR are not at 3 and 4, they share 4 | 31 | * - LCR and MCR are not at 3 and 4, they share 4 |
32 | * - No SCR (Instead, CHAR can be used as a scratch register) | ||
32 | * - Divisor latch at 9, no divisor latch access bit | 33 | * - Divisor latch at 9, no divisor latch access bit |
33 | */ | 34 | */ |
34 | 35 | ||
35 | #define UNIPHIER_UART_REGSHIFT 2 | 36 | #define UNIPHIER_UART_REGSHIFT 2 |
36 | 37 | ||
37 | /* bit[15:8] = CHAR (not used), bit[7:0] = FCR */ | 38 | /* bit[15:8] = CHAR, bit[7:0] = FCR */ |
38 | #define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) | 39 | #define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) |
39 | /* bit[15:8] = LCR, bit[7:0] = MCR */ | 40 | /* bit[15:8] = LCR, bit[7:0] = MCR */ |
40 | #define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) | 41 | #define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) |
@@ -72,13 +73,18 @@ OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart", | |||
72 | 73 | ||
73 | /* | 74 | /* |
74 | * The register map is slightly different from that of 8250. | 75 | * The register map is slightly different from that of 8250. |
75 | * IO callbacks must be overridden for correct access to FCR, LCR, and MCR. | 76 | * IO callbacks must be overridden for correct access to FCR, LCR, MCR and SCR. |
76 | */ | 77 | */ |
77 | static unsigned int uniphier_serial_in(struct uart_port *p, int offset) | 78 | static unsigned int uniphier_serial_in(struct uart_port *p, int offset) |
78 | { | 79 | { |
79 | unsigned int valshift = 0; | 80 | unsigned int valshift = 0; |
80 | 81 | ||
81 | switch (offset) { | 82 | switch (offset) { |
83 | case UART_SCR: | ||
84 | /* No SCR for this hardware. Use CHAR as a scratch register */ | ||
85 | valshift = 8; | ||
86 | offset = UNIPHIER_UART_CHAR_FCR; | ||
87 | break; | ||
82 | case UART_LCR: | 88 | case UART_LCR: |
83 | valshift = 8; | 89 | valshift = 8; |
84 | /* fall through */ | 90 | /* fall through */ |
@@ -91,8 +97,8 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) | |||
91 | } | 97 | } |
92 | 98 | ||
93 | /* | 99 | /* |
94 | * The return value must be masked with 0xff because LCR and MCR reside | 100 | * The return value must be masked with 0xff because some registers |
95 | * in the same register that must be accessed by 32-bit write/read. | 101 | * share the same offset that must be accessed by 32-bit write/read. |
96 | * 8 or 16 bit access to this hardware result in unexpected behavior. | 102 | * 8 or 16 bit access to this hardware result in unexpected behavior. |
97 | */ | 103 | */ |
98 | return (readl(p->membase + offset) >> valshift) & 0xff; | 104 | return (readl(p->membase + offset) >> valshift) & 0xff; |
@@ -101,9 +107,13 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) | |||
101 | static void uniphier_serial_out(struct uart_port *p, int offset, int value) | 107 | static void uniphier_serial_out(struct uart_port *p, int offset, int value) |
102 | { | 108 | { |
103 | unsigned int valshift = 0; | 109 | unsigned int valshift = 0; |
104 | bool normal = true; | 110 | bool normal = false; |
105 | 111 | ||
106 | switch (offset) { | 112 | switch (offset) { |
113 | case UART_SCR: | ||
114 | /* No SCR for this hardware. Use CHAR as a scratch register */ | ||
115 | valshift = 8; | ||
116 | /* fall through */ | ||
107 | case UART_FCR: | 117 | case UART_FCR: |
108 | offset = UNIPHIER_UART_CHAR_FCR; | 118 | offset = UNIPHIER_UART_CHAR_FCR; |
109 | break; | 119 | break; |
@@ -114,10 +124,10 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) | |||
114 | /* fall through */ | 124 | /* fall through */ |
115 | case UART_MCR: | 125 | case UART_MCR: |
116 | offset = UNIPHIER_UART_LCR_MCR; | 126 | offset = UNIPHIER_UART_LCR_MCR; |
117 | normal = false; | ||
118 | break; | 127 | break; |
119 | default: | 128 | default: |
120 | offset <<= UNIPHIER_UART_REGSHIFT; | 129 | offset <<= UNIPHIER_UART_REGSHIFT; |
130 | normal = true; | ||
121 | break; | 131 | break; |
122 | } | 132 | } |
123 | 133 | ||