cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tb0219.c (7285B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Driver for TANBAC TB0219 base board.
      4 *
      5 *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org>
      6 */
      7#include <linux/platform_device.h>
      8#include <linux/fs.h>
      9#include <linux/init.h>
     10#include <linux/module.h>
     11#include <linux/uaccess.h>
     12
     13#include <asm/io.h>
     14#include <asm/reboot.h>
     15#include <asm/vr41xx/giu.h>
     16#include <asm/vr41xx/tb0219.h>
     17
     18MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
     19MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
     20MODULE_LICENSE("GPL");
     21
     22static int major;	/* default is dynamic major device number */
     23module_param(major, int, 0);
     24MODULE_PARM_DESC(major, "Major device number");
     25
     26static void (*old_machine_restart)(char *command);
     27static void __iomem *tb0219_base;
     28static DEFINE_SPINLOCK(tb0219_lock);
     29
     30#define tb0219_read(offset)		readw(tb0219_base + (offset))
     31#define tb0219_write(offset, value)	writew((value), tb0219_base + (offset))
     32
     33#define TB0219_START	0x0a000000UL
     34#define TB0219_SIZE	0x20UL
     35
     36#define TB0219_LED			0x00
     37#define TB0219_GPIO_INPUT		0x02
     38#define TB0219_GPIO_OUTPUT		0x04
     39#define TB0219_DIP_SWITCH		0x06
     40#define TB0219_MISC			0x08
     41#define TB0219_RESET			0x0e
     42#define TB0219_PCI_SLOT1_IRQ_STATUS	0x10
     43#define TB0219_PCI_SLOT2_IRQ_STATUS	0x12
     44#define TB0219_PCI_SLOT3_IRQ_STATUS	0x14
     45
     46typedef enum {
     47	TYPE_LED,
     48	TYPE_GPIO_OUTPUT,
     49} tb0219_type_t;
     50
     51/*
     52 * Minor device number
     53 *	 0 = 7 segment LED
     54 *
     55 *	16 = GPIO IN 0
     56 *	17 = GPIO IN 1
     57 *	18 = GPIO IN 2
     58 *	19 = GPIO IN 3
     59 *	20 = GPIO IN 4
     60 *	21 = GPIO IN 5
     61 *	22 = GPIO IN 6
     62 *	23 = GPIO IN 7
     63 *
     64 *	32 = GPIO OUT 0
     65 *	33 = GPIO OUT 1
     66 *	34 = GPIO OUT 2
     67 *	35 = GPIO OUT 3
     68 *	36 = GPIO OUT 4
     69 *	37 = GPIO OUT 5
     70 *	38 = GPIO OUT 6
     71 *	39 = GPIO OUT 7
     72 *
     73 *	48 = DIP switch 1
     74 *	49 = DIP switch 2
     75 *	50 = DIP switch 3
     76 *	51 = DIP switch 4
     77 *	52 = DIP switch 5
     78 *	53 = DIP switch 6
     79 *	54 = DIP switch 7
     80 *	55 = DIP switch 8
     81 */
     82
     83static inline char get_led(void)
     84{
     85	return (char)tb0219_read(TB0219_LED);
     86}
     87
     88static inline char get_gpio_input_pin(unsigned int pin)
     89{
     90	uint16_t values;
     91
     92	values = tb0219_read(TB0219_GPIO_INPUT);
     93	if (values & (1 << pin))
     94		return '1';
     95
     96	return '0';
     97}
     98
     99static inline char get_gpio_output_pin(unsigned int pin)
    100{
    101	uint16_t values;
    102
    103	values = tb0219_read(TB0219_GPIO_OUTPUT);
    104	if (values & (1 << pin))
    105		return '1';
    106
    107	return '0';
    108}
    109
    110static inline char get_dip_switch(unsigned int pin)
    111{
    112	uint16_t values;
    113
    114	values = tb0219_read(TB0219_DIP_SWITCH);
    115	if (values & (1 << pin))
    116		return '1';
    117
    118	return '0';
    119}
    120
    121static inline int set_led(char command)
    122{
    123	tb0219_write(TB0219_LED, command);
    124
    125	return 0;
    126}
    127
    128static inline int set_gpio_output_pin(unsigned int pin, char command)
    129{
    130	unsigned long flags;
    131	uint16_t value;
    132
    133	if (command != '0' && command != '1')
    134		return -EINVAL;
    135
    136	spin_lock_irqsave(&tb0219_lock, flags);
    137	value = tb0219_read(TB0219_GPIO_OUTPUT);
    138	if (command == '0')
    139		value &= ~(1 << pin);
    140	else
    141		value |= 1 << pin;
    142	tb0219_write(TB0219_GPIO_OUTPUT, value);
    143	spin_unlock_irqrestore(&tb0219_lock, flags);
    144
    145	return 0;
    146
    147}
    148
    149static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len,
    150                                  loff_t *ppos)
    151{
    152	unsigned int minor;
    153	char value;
    154
    155	minor = iminor(file_inode(file));
    156	switch (minor) {
    157	case 0:
    158		value = get_led();
    159		break;
    160	case 16 ... 23:
    161		value = get_gpio_input_pin(minor - 16);
    162		break;
    163	case 32 ... 39:
    164		value = get_gpio_output_pin(minor - 32);
    165		break;
    166	case 48 ... 55:
    167		value = get_dip_switch(minor - 48);
    168		break;
    169	default:
    170		return -EBADF;
    171	}
    172
    173	if (len <= 0)
    174		return -EFAULT;
    175
    176	if (put_user(value, buf))
    177		return -EFAULT;
    178
    179	return 1;
    180}
    181
    182static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
    183                                   size_t len, loff_t *ppos)
    184{
    185	unsigned int minor;
    186	tb0219_type_t type;
    187	size_t i;
    188	int retval = 0;
    189	char c;
    190
    191	minor = iminor(file_inode(file));
    192	switch (minor) {
    193	case 0:
    194		type = TYPE_LED;
    195		break;
    196	case 32 ... 39:
    197		type = TYPE_GPIO_OUTPUT;
    198		break;
    199	default:
    200		return -EBADF;
    201	}
    202
    203	for (i = 0; i < len; i++) {
    204		if (get_user(c, data + i))
    205			return -EFAULT;
    206
    207		switch (type) {
    208		case TYPE_LED:
    209			retval = set_led(c);
    210			break;
    211		case TYPE_GPIO_OUTPUT:
    212			retval = set_gpio_output_pin(minor - 32, c);
    213			break;
    214		}
    215
    216		if (retval < 0)
    217			break;
    218	}
    219
    220	return i;
    221}
    222
    223static int tanbac_tb0219_open(struct inode *inode, struct file *file)
    224{
    225	unsigned int minor;
    226
    227	minor = iminor(inode);
    228	switch (minor) {
    229	case 0:
    230	case 16 ... 23:
    231	case 32 ... 39:
    232	case 48 ... 55:
    233		return stream_open(inode, file);
    234	default:
    235		break;
    236	}
    237
    238	return -EBADF;
    239}
    240
    241static int tanbac_tb0219_release(struct inode *inode, struct file *file)
    242{
    243	return 0;
    244}
    245
    246static const struct file_operations tb0219_fops = {
    247	.owner		= THIS_MODULE,
    248	.read		= tanbac_tb0219_read,
    249	.write		= tanbac_tb0219_write,
    250	.open		= tanbac_tb0219_open,
    251	.release	= tanbac_tb0219_release,
    252	.llseek		= no_llseek,
    253};
    254
    255static void tb0219_restart(char *command)
    256{
    257	tb0219_write(TB0219_RESET, 0);
    258}
    259
    260static void tb0219_pci_irq_init(void)
    261{
    262	/* PCI Slot 1 */
    263	vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
    264	vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW);
    265
    266	/* PCI Slot 2 */
    267	vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
    268	vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW);
    269
    270	/* PCI Slot 3 */
    271	vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
    272	vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
    273}
    274
    275static int tb0219_probe(struct platform_device *dev)
    276{
    277	int retval;
    278
    279	if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL)
    280		return -EBUSY;
    281
    282	tb0219_base = ioremap(TB0219_START, TB0219_SIZE);
    283	if (tb0219_base == NULL) {
    284		release_mem_region(TB0219_START, TB0219_SIZE);
    285		return -ENOMEM;
    286	}
    287
    288	retval = register_chrdev(major, "TB0219", &tb0219_fops);
    289	if (retval < 0) {
    290		iounmap(tb0219_base);
    291		tb0219_base = NULL;
    292		release_mem_region(TB0219_START, TB0219_SIZE);
    293		return retval;
    294	}
    295
    296	old_machine_restart = _machine_restart;
    297	_machine_restart = tb0219_restart;
    298
    299	tb0219_pci_irq_init();
    300
    301	if (major == 0) {
    302		major = retval;
    303		printk(KERN_INFO "TB0219: major number %d\n", major);
    304	}
    305
    306	return 0;
    307}
    308
    309static int tb0219_remove(struct platform_device *dev)
    310{
    311	_machine_restart = old_machine_restart;
    312
    313	iounmap(tb0219_base);
    314	tb0219_base = NULL;
    315
    316	release_mem_region(TB0219_START, TB0219_SIZE);
    317
    318	return 0;
    319}
    320
    321static struct platform_device *tb0219_platform_device;
    322
    323static struct platform_driver tb0219_device_driver = {
    324	.probe		= tb0219_probe,
    325	.remove		= tb0219_remove,
    326	.driver		= {
    327		.name	= "TB0219",
    328	},
    329};
    330
    331static int __init tanbac_tb0219_init(void)
    332{
    333	int retval;
    334
    335	tb0219_platform_device = platform_device_alloc("TB0219", -1);
    336	if (!tb0219_platform_device)
    337		return -ENOMEM;
    338
    339	retval = platform_device_add(tb0219_platform_device);
    340	if (retval < 0) {
    341		platform_device_put(tb0219_platform_device);
    342		return retval;
    343	}
    344
    345	retval = platform_driver_register(&tb0219_device_driver);
    346	if (retval < 0)
    347		platform_device_unregister(tb0219_platform_device);
    348
    349	return retval;
    350}
    351
    352static void __exit tanbac_tb0219_exit(void)
    353{
    354	platform_driver_unregister(&tb0219_device_driver);
    355	platform_device_unregister(tb0219_platform_device);
    356}
    357
    358module_init(tanbac_tb0219_init);
    359module_exit(tanbac_tb0219_exit);