brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · dc9e093 Raw
275 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 11#define MEN_UART_ID_Z025 0x1912#define MEN_UART_ID_Z057 0x3913#define MEN_UART_ID_Z125 0x7d14 15/*16 * IP Cores Z025 and Z057 can have up to 4 UART17 * The UARTs available are stored in a global18 * register saved in physical address + 0x4019 * Is saved as follows:20 *21 * 7                                                              022 * +------+-------+-------+-------+-------+-------+-------+-------+23 * |UART4 | UART3 | UART2 | UART1 | U4irq | U3irq | U2irq | U1irq |24 * +------+-------+-------+-------+-------+-------+-------+-------+25 */26#define MEN_UART1_MASK	0x0127#define MEN_UART2_MASK	0x0228#define MEN_UART3_MASK	0x0429#define MEN_UART4_MASK	0x0830 31#define MEN_Z125_UARTS_AVAILABLE	0x0132 33#define MEN_Z025_MAX_UARTS		434#define MEN_UART_MEM_SIZE		0x1035#define MEM_UART_REGISTER_SIZE		0x0136#define MEN_Z025_REGISTER_OFFSET	0x4037 38#define MEN_UART1_OFFSET	039#define MEN_UART2_OFFSET	(MEN_UART1_OFFSET + MEN_UART_MEM_SIZE)40#define MEN_UART3_OFFSET	(MEN_UART2_OFFSET + MEN_UART_MEM_SIZE)41#define MEN_UART4_OFFSET	(MEN_UART3_OFFSET + MEN_UART_MEM_SIZE)42 43#define MEN_READ_REGISTER(addr)	readb(addr)44 45#define MAX_PORTS	446 47struct serial_8250_men_mcb_data {48	int num_ports;49	int line[MAX_PORTS];50	unsigned int offset[MAX_PORTS];51};52 53/*54 * The Z125 16550-compatible UART has no fixed base clock assigned55 * So, depending on the board we're on, we need to adjust the56 * parameter in order to really set the correct baudrate, and57 * do so if possible without user interaction58 */59static u32 men_lookup_uartclk(struct mcb_device *mdev)60{61	/* use default value if board is not available below */62	u32 clkval = 1041666;63 64	dev_info(&mdev->dev, "%s on board %s\n",65		dev_name(&mdev->dev),66		mdev->bus->name);67	if  (strncmp(mdev->bus->name, "F075", 4) == 0)68		clkval = 1041666;69	else if (strncmp(mdev->bus->name, "F216", 4) == 0)70		clkval = 1843200;71	else if (strncmp(mdev->bus->name, "F210", 4) == 0)72		clkval = 115200;73	else if (strstr(mdev->bus->name, "215"))74		clkval = 1843200;75	else76		dev_info(&mdev->dev,77			 "board not detected, using default uartclk\n");78 79	clkval = clkval  << 4;80 81	return clkval;82}83 84static int read_uarts_available_from_register(struct resource *mem_res,85					      u8 *uarts_available)86{87	void __iomem *mem;88	int reg_value;89 90	if (!request_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET,91				MEM_UART_REGISTER_SIZE,  KBUILD_MODNAME)) {92		return -EBUSY;93	}94 95	mem = ioremap(mem_res->start + MEN_Z025_REGISTER_OFFSET,96		      MEM_UART_REGISTER_SIZE);97	if (!mem) {98		release_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET,99				   MEM_UART_REGISTER_SIZE);100		return -ENOMEM;101	}102 103	reg_value = MEN_READ_REGISTER(mem);104 105	iounmap(mem);106 107	release_mem_region(mem_res->start + MEN_Z025_REGISTER_OFFSET,108			   MEM_UART_REGISTER_SIZE);109 110	*uarts_available = reg_value >> 4;111 112	return 0;113}114 115static int read_serial_data(struct mcb_device *mdev,116			    struct resource *mem_res,117			    struct serial_8250_men_mcb_data *serial_data)118{119	u8 uarts_available;120	int count = 0;121	int mask;122	int res;123	int i;124 125	res = read_uarts_available_from_register(mem_res, &uarts_available);126	if (res < 0)127		return res;128 129	for (i = 0; i < MAX_PORTS; i++) {130		mask = 0x1 << i;131		switch (uarts_available & mask) {132		case MEN_UART1_MASK:133			serial_data->offset[count] = MEN_UART1_OFFSET;134			count++;135			break;136		case MEN_UART2_MASK:137			serial_data->offset[count] = MEN_UART2_OFFSET;138			count++;139			break;140		case MEN_UART3_MASK:141			serial_data->offset[count] = MEN_UART3_OFFSET;142			count++;143			break;144		case MEN_UART4_MASK:145			serial_data->offset[count] = MEN_UART4_OFFSET;146			count++;147			break;148		default:149			return -EINVAL;150		}151	}152 153	if (count <= 0 || count > MAX_PORTS) {154		dev_err(&mdev->dev, "unexpected number of ports: %u\n",155			count);156		return -ENODEV;157	}158 159	serial_data->num_ports = count;160 161	return 0;162}163 164static int init_serial_data(struct mcb_device *mdev,165			    struct resource *mem_res,166			    struct serial_8250_men_mcb_data *serial_data)167{168	switch (mdev->id) {169	case MEN_UART_ID_Z125:170		serial_data->num_ports = 1;171		serial_data->offset[0] = 0;172		return 0;173	case MEN_UART_ID_Z025:174	case MEN_UART_ID_Z057:175		return read_serial_data(mdev, mem_res, serial_data);176	default:177		dev_err(&mdev->dev, "no supported device!\n");178		return -ENODEV;179	}180}181 182static int serial_8250_men_mcb_probe(struct mcb_device *mdev,183				     const struct mcb_device_id *id)184{185	struct uart_8250_port uart;186	struct serial_8250_men_mcb_data *data;187	struct resource *mem;188	int i;189	int res;190 191	mem = mcb_get_resource(mdev, IORESOURCE_MEM);192	if (mem == NULL)193		return -ENXIO;194 195	data = devm_kzalloc(&mdev->dev,196			    sizeof(struct serial_8250_men_mcb_data),197			    GFP_KERNEL);198	if (!data)199		return -ENOMEM;200 201	res = init_serial_data(mdev, mem, data);202	if (res < 0)203		return res;204 205	dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",206		mdev->id, data->num_ports);207 208	mcb_set_drvdata(mdev, data);209 210	for (i = 0; i < data->num_ports; i++) {211		memset(&uart, 0, sizeof(struct uart_8250_port));212		spin_lock_init(&uart.port.lock);213 214		uart.port.flags = UPF_SKIP_TEST |215				  UPF_SHARE_IRQ |216				  UPF_BOOT_AUTOCONF |217				  UPF_IOREMAP;218		uart.port.iotype = UPIO_MEM;219		uart.port.uartclk = men_lookup_uartclk(mdev);220		uart.port.irq = mcb_get_irq(mdev);221		uart.port.mapbase = (unsigned long) mem->start222					    + data->offset[i];223 224		/* ok, register the port */225		res = serial8250_register_8250_port(&uart);226		if (res < 0) {227			dev_err(&mdev->dev, "unable to register UART port\n");228			return res;229		}230 231		data->line[i] = res;232		dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->line[i]);233	}234 235	return 0;236}237 238static void serial_8250_men_mcb_remove(struct mcb_device *mdev)239{240	int i;241	struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);242 243	if (!data)244		return;245 246	for (i = 0; i < data->num_ports; i++)247		serial8250_unregister_port(data->line[i]);248}249 250static const struct mcb_device_id serial_8250_men_mcb_ids[] = {251	{ .device = MEN_UART_ID_Z025 },252	{ .device = MEN_UART_ID_Z057 },253	{ .device = MEN_UART_ID_Z125 },254	{ }255};256MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);257 258static struct mcb_driver mcb_driver = {259	.driver = {260		.name = "8250_men_mcb",261	},262	.probe = serial_8250_men_mcb_probe,263	.remove = serial_8250_men_mcb_remove,264	.id_table = serial_8250_men_mcb_ids,265};266module_mcb_driver(mcb_driver);267 268MODULE_LICENSE("GPL v2");269MODULE_DESCRIPTION("MEN 8250 UART driver");270MODULE_AUTHOR("Michael Moese <michael.moese@men.de");271MODULE_ALIAS("mcb:16z125");272MODULE_ALIAS("mcb:16z025");273MODULE_ALIAS("mcb:16z057");274MODULE_IMPORT_NS(MCB);275