1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 *  NEC VR4100 series SIU platform device.
4 *
5 *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
6 */
7#include <linux/errno.h>
8#include <linux/init.h>
9#include <linux/ioport.h>
10#include <linux/platform_device.h>
11#include <linux/serial_core.h>
12#include <linux/irq.h>
13
14#include <asm/cpu.h>
15#include <asm/vr41xx/siu.h>
16
17static unsigned int siu_type1_ports[SIU_PORTS_MAX] __initdata = {
18	PORT_VR41XX_SIU,
19	PORT_UNKNOWN,
20};
21
22static struct resource siu_type1_resource[] __initdata = {
23	{
24		.start	= 0x0c000000,
25		.end	= 0x0c00000a,
26		.flags	= IORESOURCE_MEM,
27	},
28	{
29		.start	= SIU_IRQ,
30		.end	= SIU_IRQ,
31		.flags	= IORESOURCE_IRQ,
32	},
33};
34
35static unsigned int siu_type2_ports[SIU_PORTS_MAX] __initdata = {
36	PORT_VR41XX_SIU,
37	PORT_VR41XX_DSIU,
38};
39
40static struct resource siu_type2_resource[] __initdata = {
41	{
42		.start	= 0x0f000800,
43		.end	= 0x0f00080a,
44		.flags	= IORESOURCE_MEM,
45	},
46	{
47		.start	= 0x0f000820,
48		.end	= 0x0f000829,
49		.flags	= IORESOURCE_MEM,
50	},
51	{
52		.start	= SIU_IRQ,
53		.end	= SIU_IRQ,
54		.flags	= IORESOURCE_IRQ,
55	},
56	{
57		.start	= DSIU_IRQ,
58		.end	= DSIU_IRQ,
59		.flags	= IORESOURCE_IRQ,
60	},
61};
62
63static int __init vr41xx_siu_add(void)
64{
65	struct platform_device *pdev;
66	struct resource *res;
67	unsigned int num;
68	int retval;
69
70	pdev = platform_device_alloc("SIU", -1);
71	if (!pdev)
72		return -ENOMEM;
73
74	switch (current_cpu_type()) {
75	case CPU_VR4111:
76	case CPU_VR4121:
77		pdev->dev.platform_data = siu_type1_ports;
78		res = siu_type1_resource;
79		num = ARRAY_SIZE(siu_type1_resource);
80		break;
81	case CPU_VR4122:
82	case CPU_VR4131:
83	case CPU_VR4133:
84		pdev->dev.platform_data = siu_type2_ports;
85		res = siu_type2_resource;
86		num = ARRAY_SIZE(siu_type2_resource);
87		break;
88	default:
89		retval = -ENODEV;
90		goto err_free_device;
91	}
92
93	retval = platform_device_add_resources(pdev, res, num);
94	if (retval)
95		goto err_free_device;
96
97	retval = platform_device_add(pdev);
98	if (retval)
99		goto err_free_device;
100
101	return 0;
102
103err_free_device:
104	platform_device_put(pdev);
105
106	return retval;
107}
108device_initcall(vr41xx_siu_add);
109
110void __init vr41xx_siu_setup(void)
111{
112	struct uart_port port;
113	struct resource *res;
114	unsigned int *type;
115	int i;
116
117	switch (current_cpu_type()) {
118	case CPU_VR4111:
119	case CPU_VR4121:
120		type = siu_type1_ports;
121		res = siu_type1_resource;
122		break;
123	case CPU_VR4122:
124	case CPU_VR4131:
125	case CPU_VR4133:
126		type = siu_type2_ports;
127		res = siu_type2_resource;
128		break;
129	default:
130		return;
131	}
132
133	for (i = 0; i < SIU_PORTS_MAX; i++) {
134		port.line = i;
135		port.type = type[i];
136		if (port.type == PORT_UNKNOWN)
137			break;
138		port.mapbase = res[i].start;
139		port.membase = (unsigned char __iomem *)KSEG1ADDR(res[i].start);
140		vr41xx_siu_early_setup(&port);
141	}
142}
143