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

8250_men_mcb.c (4584B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/device.h>
      3#include <linux/kernel.h>
      4#include <linux/module.h>
      5#include <linux/io.h>
      6#include <linux/mcb.h>
      7#include <linux/serial.h>
      8#include <linux/serial_core.h>
      9#include <linux/serial_8250.h>
     10#include <uapi/linux/serial_core.h>
     11
     12#define MEN_UART_ID_Z025 0x19
     13#define MEN_UART_ID_Z057 0x39
     14#define MEN_UART_ID_Z125 0x7d
     15
     16#define MEN_UART_MEM_SIZE 0x10
     17
     18struct serial_8250_men_mcb_data {
     19	struct uart_8250_port uart;
     20	int line;
     21};
     22
     23/*
     24 * The Z125 16550-compatible UART has no fixed base clock assigned
     25 * So, depending on the board we're on, we need to adjust the
     26 * parameter in order to really set the correct baudrate, and
     27 * do so if possible without user interaction
     28 */
     29static u32 men_lookup_uartclk(struct mcb_device *mdev)
     30{
     31	/* use default value if board is not available below */
     32	u32 clkval = 1041666;
     33
     34	dev_info(&mdev->dev, "%s on board %s\n",
     35		dev_name(&mdev->dev),
     36		mdev->bus->name);
     37	if  (strncmp(mdev->bus->name, "F075", 4) == 0)
     38		clkval = 1041666;
     39	else if (strncmp(mdev->bus->name, "F216", 4) == 0)
     40		clkval = 1843200;
     41	else if (strncmp(mdev->bus->name, "G215", 4) == 0)
     42		clkval = 1843200;
     43	else if (strncmp(mdev->bus->name, "F210", 4) == 0)
     44		clkval = 115200;
     45	else
     46		dev_info(&mdev->dev,
     47			 "board not detected, using default uartclk\n");
     48
     49	clkval = clkval  << 4;
     50
     51	return clkval;
     52}
     53
     54static int get_num_ports(struct mcb_device *mdev,
     55				  void __iomem *membase)
     56{
     57	switch (mdev->id) {
     58	case MEN_UART_ID_Z125:
     59		return 1U;
     60	case MEN_UART_ID_Z025:
     61		return readb(membase) >> 4;
     62	case MEN_UART_ID_Z057:
     63		return 4U;
     64	default:
     65		dev_err(&mdev->dev, "no supported device!\n");
     66		return -ENODEV;
     67	}
     68}
     69
     70static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
     71				     const struct mcb_device_id *id)
     72{
     73	struct serial_8250_men_mcb_data *data;
     74	struct resource *mem;
     75	int num_ports;
     76	int i;
     77	void __iomem *membase;
     78
     79	mem = mcb_get_resource(mdev, IORESOURCE_MEM);
     80	if (mem == NULL)
     81		return -ENXIO;
     82	membase = devm_ioremap_resource(&mdev->dev, mem);
     83	if (IS_ERR(membase))
     84		return PTR_ERR_OR_ZERO(membase);
     85
     86	num_ports = get_num_ports(mdev, membase);
     87
     88	dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",
     89		mdev->id, num_ports);
     90
     91	if (num_ports <= 0 || num_ports > 4) {
     92		dev_err(&mdev->dev, "unexpected number of ports: %u\n",
     93			num_ports);
     94		return -ENODEV;
     95	}
     96
     97	data = devm_kcalloc(&mdev->dev, num_ports,
     98			    sizeof(struct serial_8250_men_mcb_data),
     99			    GFP_KERNEL);
    100	if (!data)
    101		return -ENOMEM;
    102
    103	mcb_set_drvdata(mdev, data);
    104
    105	for (i = 0; i < num_ports; i++) {
    106		data[i].uart.port.dev = mdev->dma_dev;
    107		spin_lock_init(&data[i].uart.port.lock);
    108
    109		data[i].uart.port.type = PORT_16550;
    110		data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
    111					  | UPF_FIXED_TYPE;
    112		data[i].uart.port.iotype = UPIO_MEM;
    113		data[i].uart.port.uartclk = men_lookup_uartclk(mdev);
    114		data[i].uart.port.regshift = 0;
    115		data[i].uart.port.irq = mcb_get_irq(mdev);
    116		data[i].uart.port.membase = membase;
    117		data[i].uart.port.fifosize = 60;
    118		data[i].uart.port.mapbase = (unsigned long) mem->start
    119					    + i * MEN_UART_MEM_SIZE;
    120		data[i].uart.port.iobase = data[i].uart.port.mapbase;
    121
    122		/* ok, register the port */
    123		data[i].line = serial8250_register_8250_port(&data[i].uart);
    124		if (data[i].line < 0) {
    125			dev_err(&mdev->dev, "unable to register UART port\n");
    126			return data[i].line;
    127		}
    128		dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line);
    129	}
    130
    131	return 0;
    132}
    133
    134static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
    135{
    136	int num_ports, i;
    137	struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);
    138
    139	if (!data)
    140		return;
    141
    142	num_ports = get_num_ports(mdev, data[0].uart.port.membase);
    143	if (num_ports <= 0 || num_ports > 4) {
    144		dev_err(&mdev->dev, "error retrieving number of ports!\n");
    145		return;
    146	}
    147
    148	for (i = 0; i < num_ports; i++)
    149		serial8250_unregister_port(data[i].line);
    150}
    151
    152static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
    153	{ .device = MEN_UART_ID_Z025 },
    154	{ .device = MEN_UART_ID_Z057 },
    155	{ .device = MEN_UART_ID_Z125 },
    156	{ }
    157};
    158MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);
    159
    160static struct mcb_driver mcb_driver = {
    161	.driver = {
    162		.name = "8250_men_mcb",
    163		.owner = THIS_MODULE,
    164	},
    165	.probe = serial_8250_men_mcb_probe,
    166	.remove = serial_8250_men_mcb_remove,
    167	.id_table = serial_8250_men_mcb_ids,
    168};
    169module_mcb_driver(mcb_driver);
    170
    171MODULE_LICENSE("GPL v2");
    172MODULE_DESCRIPTION("MEN 8250 UART driver");
    173MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
    174MODULE_ALIAS("mcb:16z125");
    175MODULE_ALIAS("mcb:16z025");
    176MODULE_ALIAS("mcb:16z057");
    177MODULE_IMPORT_NS(MCB);