1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OLPC serio driver for multiplexed input from Marvell MMP security processor
5 * Copyright (C) 2011-2013 One Laptop Per Child
8 #include <linux/module.h>
9 #include <linux/interrupt.h>
10 #include <linux/serio.h>
11 #include <linux/err.h>
12 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/delay.h>
19 * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller.
20 * Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an
21 * otherwise-unused slow processor which is included in the Marvell MMP2/MMP3
22 * SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module"
23 * (WTM). This firmware then reports its results via the WTM registers,
24 * which we read from the Application Processor (AP, i.e. main CPU) in this
27 * On the hardware side we have a PS/2 mouse and an AT keyboard, the data
28 * is multiplexed through this system. We create a serio port for each one,
29 * and demultiplex the data accordingly.
32 /* WTM register offsets */
33 #define SECURE_PROCESSOR_COMMAND 0x40
34 #define COMMAND_RETURN_STATUS 0x80
35 #define COMMAND_FIFO_STATUS 0xc4
36 #define PJ_RST_INTERRUPT 0xc8
37 #define PJ_INTERRUPT_MASK 0xcc
40 * The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is
41 * used to identify which port (device) is being talked to. The lower byte
42 * is the data being sent/received.
44 #define PORT_MASK 0xff00
45 #define DATA_MASK 0x00ff
47 #define KEYBOARD_PORT 0
48 #define TOUCHPAD_PORT 1
50 /* COMMAND_FIFO_STATUS */
51 #define CMD_CNTR_MASK 0x7 /* Number of pending/unprocessed commands */
52 #define MAX_PENDING_CMDS 4 /* from device specs */
54 /* PJ_RST_INTERRUPT */
55 #define SP_COMMAND_COMPLETE_RESET 0x1
57 /* PJ_INTERRUPT_MASK */
58 #define INT_0 (1 << 0)
60 /* COMMAND_FIFO_STATUS */
61 #define CMD_STS_MASK 0x100
72 static int olpc_apsp_write(struct serio
*port
, unsigned char val
)
74 struct olpc_apsp
*priv
= port
->port_data
;
78 if (port
== priv
->padio
)
79 which
= TOUCHPAD_PORT
<< PORT_SHIFT
;
81 which
= KEYBOARD_PORT
<< PORT_SHIFT
;
83 dev_dbg(priv
->dev
, "olpc_apsp_write which=%x val=%x\n", which
, val
);
84 for (i
= 0; i
< 50; i
++) {
85 u32 sts
= readl(priv
->base
+ COMMAND_FIFO_STATUS
);
86 if ((sts
& CMD_CNTR_MASK
) < MAX_PENDING_CMDS
) {
88 priv
->base
+ SECURE_PROCESSOR_COMMAND
);
91 /* SP busy. This has not been seen in practice. */
95 dev_dbg(priv
->dev
, "olpc_apsp_write timeout, status=%x\n",
96 readl(priv
->base
+ COMMAND_FIFO_STATUS
));
101 static irqreturn_t
olpc_apsp_rx(int irq
, void *dev_id
)
103 struct olpc_apsp
*priv
= dev_id
;
108 * Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt
109 * Write 0xff00 to SECURE_PROCESSOR_COMMAND.
111 tmp
= readl(priv
->base
+ PJ_RST_INTERRUPT
);
112 if (!(tmp
& SP_COMMAND_COMPLETE_RESET
)) {
113 dev_warn(priv
->dev
, "spurious interrupt?\n");
117 w
= readl(priv
->base
+ COMMAND_RETURN_STATUS
);
118 dev_dbg(priv
->dev
, "olpc_apsp_rx %x\n", w
);
120 if (w
>> PORT_SHIFT
== KEYBOARD_PORT
)
125 serio_interrupt(serio
, w
& DATA_MASK
, 0);
127 /* Ack and clear interrupt */
128 writel(tmp
| SP_COMMAND_COMPLETE_RESET
, priv
->base
+ PJ_RST_INTERRUPT
);
129 writel(PORT_MASK
, priv
->base
+ SECURE_PROCESSOR_COMMAND
);
131 pm_wakeup_event(priv
->dev
, 1000);
135 static int olpc_apsp_open(struct serio
*port
)
137 struct olpc_apsp
*priv
= port
->port_data
;
141 if (priv
->open_count
++ == 0) {
142 l
= readl(priv
->base
+ COMMAND_FIFO_STATUS
);
143 if (!(l
& CMD_STS_MASK
)) {
144 dev_err(priv
->dev
, "SP cannot accept commands.\n");
148 /* Enable interrupt 0 by clearing its bit */
149 tmp
= readl(priv
->base
+ PJ_INTERRUPT_MASK
);
150 writel(tmp
& ~INT_0
, priv
->base
+ PJ_INTERRUPT_MASK
);
156 static void olpc_apsp_close(struct serio
*port
)
158 struct olpc_apsp
*priv
= port
->port_data
;
161 if (--priv
->open_count
== 0) {
162 /* Disable interrupt 0 */
163 tmp
= readl(priv
->base
+ PJ_INTERRUPT_MASK
);
164 writel(tmp
| INT_0
, priv
->base
+ PJ_INTERRUPT_MASK
);
168 static int olpc_apsp_probe(struct platform_device
*pdev
)
170 struct serio
*kb_serio
, *pad_serio
;
171 struct olpc_apsp
*priv
;
172 struct resource
*res
;
175 priv
= devm_kzalloc(&pdev
->dev
, sizeof(struct olpc_apsp
), GFP_KERNEL
);
179 priv
->dev
= &pdev
->dev
;
181 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
182 priv
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
183 if (IS_ERR(priv
->base
)) {
184 dev_err(&pdev
->dev
, "Failed to map WTM registers\n");
185 return PTR_ERR(priv
->base
);
188 priv
->irq
= platform_get_irq(pdev
, 0);
193 kb_serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
196 kb_serio
->id
.type
= SERIO_8042_XL
;
197 kb_serio
->write
= olpc_apsp_write
;
198 kb_serio
->open
= olpc_apsp_open
;
199 kb_serio
->close
= olpc_apsp_close
;
200 kb_serio
->port_data
= priv
;
201 kb_serio
->dev
.parent
= &pdev
->dev
;
202 strlcpy(kb_serio
->name
, "sp keyboard", sizeof(kb_serio
->name
));
203 strlcpy(kb_serio
->phys
, "sp/serio0", sizeof(kb_serio
->phys
));
204 priv
->kbio
= kb_serio
;
205 serio_register_port(kb_serio
);
208 pad_serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
213 pad_serio
->id
.type
= SERIO_8042
;
214 pad_serio
->write
= olpc_apsp_write
;
215 pad_serio
->open
= olpc_apsp_open
;
216 pad_serio
->close
= olpc_apsp_close
;
217 pad_serio
->port_data
= priv
;
218 pad_serio
->dev
.parent
= &pdev
->dev
;
219 strlcpy(pad_serio
->name
, "sp touchpad", sizeof(pad_serio
->name
));
220 strlcpy(pad_serio
->phys
, "sp/serio1", sizeof(pad_serio
->phys
));
221 priv
->padio
= pad_serio
;
222 serio_register_port(pad_serio
);
224 error
= request_irq(priv
->irq
, olpc_apsp_rx
, 0, "olpc-apsp", priv
);
226 dev_err(&pdev
->dev
, "Failed to request IRQ\n");
230 device_init_wakeup(priv
->dev
, 1);
231 platform_set_drvdata(pdev
, priv
);
233 dev_dbg(&pdev
->dev
, "probed successfully.\n");
237 serio_unregister_port(pad_serio
);
239 serio_unregister_port(kb_serio
);
243 static int olpc_apsp_remove(struct platform_device
*pdev
)
245 struct olpc_apsp
*priv
= platform_get_drvdata(pdev
);
247 free_irq(priv
->irq
, priv
);
249 serio_unregister_port(priv
->kbio
);
250 serio_unregister_port(priv
->padio
);
255 static const struct of_device_id olpc_apsp_dt_ids
[] = {
256 { .compatible
= "olpc,ap-sp", },
259 MODULE_DEVICE_TABLE(of
, olpc_apsp_dt_ids
);
261 static struct platform_driver olpc_apsp_driver
= {
262 .probe
= olpc_apsp_probe
,
263 .remove
= olpc_apsp_remove
,
266 .of_match_table
= olpc_apsp_dt_ids
,
270 MODULE_DESCRIPTION("OLPC AP-SP serio driver");
271 MODULE_LICENSE("GPL");
272 module_platform_driver(olpc_apsp_driver
);