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