Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OLPC serio driver for multiplexed input from Marvell MMP security processor
0004  *
0005  * Copyright (C) 2011-2013 One Laptop Per Child
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/interrupt.h>
0010 #include <linux/serio.h>
0011 #include <linux/err.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/io.h>
0014 #include <linux/of.h>
0015 #include <linux/slab.h>
0016 #include <linux/delay.h>
0017 
0018 /*
0019  * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller.
0020  * Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an
0021  * otherwise-unused slow processor which is included in the Marvell MMP2/MMP3
0022  * SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module"
0023  * (WTM). This firmware then reports its results via the WTM registers,
0024  * which we read from the Application Processor (AP, i.e. main CPU) in this
0025  * driver.
0026  *
0027  * On the hardware side we have a PS/2 mouse and an AT keyboard, the data
0028  * is multiplexed through this system. We create a serio port for each one,
0029  * and demultiplex the data accordingly.
0030  */
0031 
0032 /* WTM register offsets */
0033 #define SECURE_PROCESSOR_COMMAND    0x40
0034 #define COMMAND_RETURN_STATUS       0x80
0035 #define COMMAND_FIFO_STATUS     0xc4
0036 #define PJ_RST_INTERRUPT        0xc8
0037 #define PJ_INTERRUPT_MASK       0xcc
0038 
0039 /*
0040  * The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is
0041  * used to identify which port (device) is being talked to. The lower byte
0042  * is the data being sent/received.
0043  */
0044 #define PORT_MASK   0xff00
0045 #define DATA_MASK   0x00ff
0046 #define PORT_SHIFT  8
0047 #define KEYBOARD_PORT   0
0048 #define TOUCHPAD_PORT   1
0049 
0050 /* COMMAND_FIFO_STATUS */
0051 #define CMD_CNTR_MASK       0x7 /* Number of pending/unprocessed commands */
0052 #define MAX_PENDING_CMDS    4   /* from device specs */
0053 
0054 /* PJ_RST_INTERRUPT */
0055 #define SP_COMMAND_COMPLETE_RESET   0x1
0056 
0057 /* PJ_INTERRUPT_MASK */
0058 #define INT_0   (1 << 0)
0059 
0060 /* COMMAND_FIFO_STATUS */
0061 #define CMD_STS_MASK    0x100
0062 
0063 struct olpc_apsp {
0064     struct device *dev;
0065     struct serio *kbio;
0066     struct serio *padio;
0067     void __iomem *base;
0068     int open_count;
0069     int irq;
0070 };
0071 
0072 static int olpc_apsp_write(struct serio *port, unsigned char val)
0073 {
0074     struct olpc_apsp *priv = port->port_data;
0075     unsigned int i;
0076     u32 which = 0;
0077 
0078     if (port == priv->padio)
0079         which = TOUCHPAD_PORT << PORT_SHIFT;
0080     else
0081         which = KEYBOARD_PORT << PORT_SHIFT;
0082 
0083     dev_dbg(priv->dev, "olpc_apsp_write which=%x val=%x\n", which, val);
0084     for (i = 0; i < 50; i++) {
0085         u32 sts = readl(priv->base + COMMAND_FIFO_STATUS);
0086         if ((sts & CMD_CNTR_MASK) < MAX_PENDING_CMDS) {
0087             writel(which | val,
0088                    priv->base + SECURE_PROCESSOR_COMMAND);
0089             return 0;
0090         }
0091         /* SP busy. This has not been seen in practice. */
0092         mdelay(1);
0093     }
0094 
0095     dev_dbg(priv->dev, "olpc_apsp_write timeout, status=%x\n",
0096         readl(priv->base + COMMAND_FIFO_STATUS));
0097 
0098     return -ETIMEDOUT;
0099 }
0100 
0101 static irqreturn_t olpc_apsp_rx(int irq, void *dev_id)
0102 {
0103     struct olpc_apsp *priv = dev_id;
0104     unsigned int w, tmp;
0105     struct serio *serio;
0106 
0107     /*
0108      * Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt
0109      * Write 0xff00 to SECURE_PROCESSOR_COMMAND.
0110      */
0111     tmp = readl(priv->base + PJ_RST_INTERRUPT);
0112     if (!(tmp & SP_COMMAND_COMPLETE_RESET)) {
0113         dev_warn(priv->dev, "spurious interrupt?\n");
0114         return IRQ_NONE;
0115     }
0116 
0117     w = readl(priv->base + COMMAND_RETURN_STATUS);
0118     dev_dbg(priv->dev, "olpc_apsp_rx %x\n", w);
0119 
0120     if (w >> PORT_SHIFT == KEYBOARD_PORT)
0121         serio = priv->kbio;
0122     else
0123         serio = priv->padio;
0124 
0125     serio_interrupt(serio, w & DATA_MASK, 0);
0126 
0127     /* Ack and clear interrupt */
0128     writel(tmp | SP_COMMAND_COMPLETE_RESET, priv->base + PJ_RST_INTERRUPT);
0129     writel(PORT_MASK, priv->base + SECURE_PROCESSOR_COMMAND);
0130 
0131     pm_wakeup_event(priv->dev, 1000);
0132     return IRQ_HANDLED;
0133 }
0134 
0135 static int olpc_apsp_open(struct serio *port)
0136 {
0137     struct olpc_apsp *priv = port->port_data;
0138     unsigned int tmp;
0139     unsigned long l;
0140 
0141     if (priv->open_count++ == 0) {
0142         l = readl(priv->base + COMMAND_FIFO_STATUS);
0143         if (!(l & CMD_STS_MASK)) {
0144             dev_err(priv->dev, "SP cannot accept commands.\n");
0145             return -EIO;
0146         }
0147 
0148         /* Enable interrupt 0 by clearing its bit */
0149         tmp = readl(priv->base + PJ_INTERRUPT_MASK);
0150         writel(tmp & ~INT_0, priv->base + PJ_INTERRUPT_MASK);
0151     }
0152 
0153     return 0;
0154 }
0155 
0156 static void olpc_apsp_close(struct serio *port)
0157 {
0158     struct olpc_apsp *priv = port->port_data;
0159     unsigned int tmp;
0160 
0161     if (--priv->open_count == 0) {
0162         /* Disable interrupt 0 */
0163         tmp = readl(priv->base + PJ_INTERRUPT_MASK);
0164         writel(tmp | INT_0, priv->base + PJ_INTERRUPT_MASK);
0165     }
0166 }
0167 
0168 static int olpc_apsp_probe(struct platform_device *pdev)
0169 {
0170     struct serio *kb_serio, *pad_serio;
0171     struct olpc_apsp *priv;
0172     struct resource *res;
0173     int error;
0174 
0175     priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL);
0176     if (!priv)
0177         return -ENOMEM;
0178 
0179     priv->dev = &pdev->dev;
0180 
0181     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0182     priv->base = devm_ioremap_resource(&pdev->dev, res);
0183     if (IS_ERR(priv->base)) {
0184         dev_err(&pdev->dev, "Failed to map WTM registers\n");
0185         return PTR_ERR(priv->base);
0186     }
0187 
0188     priv->irq = platform_get_irq(pdev, 0);
0189     if (priv->irq < 0)
0190         return priv->irq;
0191 
0192     /* KEYBOARD */
0193     kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
0194     if (!kb_serio)
0195         return -ENOMEM;
0196     kb_serio->id.type   = SERIO_8042_XL;
0197     kb_serio->write     = olpc_apsp_write;
0198     kb_serio->open      = olpc_apsp_open;
0199     kb_serio->close     = olpc_apsp_close;
0200     kb_serio->port_data = priv;
0201     kb_serio->dev.parent    = &pdev->dev;
0202     strlcpy(kb_serio->name, "sp keyboard", sizeof(kb_serio->name));
0203     strlcpy(kb_serio->phys, "sp/serio0", sizeof(kb_serio->phys));
0204     priv->kbio      = kb_serio;
0205     serio_register_port(kb_serio);
0206 
0207     /* TOUCHPAD */
0208     pad_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
0209     if (!pad_serio) {
0210         error = -ENOMEM;
0211         goto err_pad;
0212     }
0213     pad_serio->id.type  = SERIO_8042;
0214     pad_serio->write    = olpc_apsp_write;
0215     pad_serio->open     = olpc_apsp_open;
0216     pad_serio->close    = olpc_apsp_close;
0217     pad_serio->port_data    = priv;
0218     pad_serio->dev.parent   = &pdev->dev;
0219     strlcpy(pad_serio->name, "sp touchpad", sizeof(pad_serio->name));
0220     strlcpy(pad_serio->phys, "sp/serio1", sizeof(pad_serio->phys));
0221     priv->padio     = pad_serio;
0222     serio_register_port(pad_serio);
0223 
0224     error = request_irq(priv->irq, olpc_apsp_rx, 0, "olpc-apsp", priv);
0225     if (error) {
0226         dev_err(&pdev->dev, "Failed to request IRQ\n");
0227         goto err_irq;
0228     }
0229 
0230     device_init_wakeup(priv->dev, 1);
0231     platform_set_drvdata(pdev, priv);
0232 
0233     dev_dbg(&pdev->dev, "probed successfully.\n");
0234     return 0;
0235 
0236 err_irq:
0237     serio_unregister_port(pad_serio);
0238 err_pad:
0239     serio_unregister_port(kb_serio);
0240     return error;
0241 }
0242 
0243 static int olpc_apsp_remove(struct platform_device *pdev)
0244 {
0245     struct olpc_apsp *priv = platform_get_drvdata(pdev);
0246 
0247     free_irq(priv->irq, priv);
0248 
0249     serio_unregister_port(priv->kbio);
0250     serio_unregister_port(priv->padio);
0251 
0252     return 0;
0253 }
0254 
0255 static const struct of_device_id olpc_apsp_dt_ids[] = {
0256     { .compatible = "olpc,ap-sp", },
0257     {}
0258 };
0259 MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids);
0260 
0261 static struct platform_driver olpc_apsp_driver = {
0262     .probe      = olpc_apsp_probe,
0263     .remove     = olpc_apsp_remove,
0264     .driver     = {
0265         .name   = "olpc-apsp",
0266         .of_match_table = olpc_apsp_dt_ids,
0267     },
0268 };
0269 
0270 MODULE_DESCRIPTION("OLPC AP-SP serio driver");
0271 MODULE_LICENSE("GPL");
0272 module_platform_driver(olpc_apsp_driver);