aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2017-08-08 09:48:42 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-08-28 14:51:22 -0400
commitd3a9184773c5cde483e249096ae7c7f98f310e20 (patch)
tree4e93c505f6457f63cfb498f2ce29bfaa54e45152
parent39be40ce066da4d5d59bf53f72b914018bc84029 (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.c22
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 */
77static unsigned int uniphier_serial_in(struct uart_port *p, int offset) 78static 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)
101static void uniphier_serial_out(struct uart_port *p, int offset, int value) 107static 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