18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2011, Netlogic Microsystems.
38c2ecf20Sopenharmony_ci * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
68c2ecf20Sopenharmony_ci * License version 2.  This program is licensed "as is" without any
78c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/resource.h>
158c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
168c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
178c2ecf20Sopenharmony_ci#include <linux/i2c.h>
188c2ecf20Sopenharmony_ci#include <linux/usb/ehci_pdriver.h>
198c2ecf20Sopenharmony_ci#include <linux/usb/ohci_pdriver.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/netlogic/haldefs.h>
228c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/iomap.h>
238c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/pic.h>
248c2ecf20Sopenharmony_ci#include <asm/netlogic/xlr/xlr.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	uint64_t uartbase;
298c2ecf20Sopenharmony_ci	unsigned int value;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	/* sign extend to 64 bits, if needed */
328c2ecf20Sopenharmony_ci	uartbase = (uint64_t)(long)p->membase;
338c2ecf20Sopenharmony_ci	value = nlm_read_reg(uartbase, offset);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* See XLR/XLS errata */
368c2ecf20Sopenharmony_ci	if (offset == UART_MSR)
378c2ecf20Sopenharmony_ci		value ^= 0xF0;
388c2ecf20Sopenharmony_ci	else if (offset == UART_MCR)
398c2ecf20Sopenharmony_ci		value ^= 0x3;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	return value;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	uint64_t uartbase;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* sign extend to 64 bits, if needed */
498c2ecf20Sopenharmony_ci	uartbase = (uint64_t)(long)p->membase;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* See XLR/XLS errata */
528c2ecf20Sopenharmony_ci	if (offset == UART_MSR)
538c2ecf20Sopenharmony_ci		value ^= 0xF0;
548c2ecf20Sopenharmony_ci	else if (offset == UART_MCR)
558c2ecf20Sopenharmony_ci		value ^= 0x3;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	nlm_write_reg(uartbase, offset, value);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define PORT(_irq)					\
618c2ecf20Sopenharmony_ci	{						\
628c2ecf20Sopenharmony_ci		.irq		= _irq,			\
638c2ecf20Sopenharmony_ci		.regshift	= 2,			\
648c2ecf20Sopenharmony_ci		.iotype		= UPIO_MEM32,		\
658c2ecf20Sopenharmony_ci		.flags		= (UPF_SKIP_TEST |	\
668c2ecf20Sopenharmony_ci			 UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\
678c2ecf20Sopenharmony_ci		.uartclk	= PIC_CLK_HZ,		\
688c2ecf20Sopenharmony_ci		.type		= PORT_16550A,		\
698c2ecf20Sopenharmony_ci		.serial_in	= nlm_xlr_uart_in,	\
708c2ecf20Sopenharmony_ci		.serial_out	= nlm_xlr_uart_out,	\
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic struct plat_serial8250_port xlr_uart_data[] = {
748c2ecf20Sopenharmony_ci	PORT(PIC_UART_0_IRQ),
758c2ecf20Sopenharmony_ci	PORT(PIC_UART_1_IRQ),
768c2ecf20Sopenharmony_ci	{},
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic struct platform_device uart_device = {
808c2ecf20Sopenharmony_ci	.name		= "serial8250",
818c2ecf20Sopenharmony_ci	.id		= PLAT8250_DEV_PLATFORM,
828c2ecf20Sopenharmony_ci	.dev = {
838c2ecf20Sopenharmony_ci		.platform_data = xlr_uart_data,
848c2ecf20Sopenharmony_ci	},
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int __init nlm_uart_init(void)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	unsigned long uartbase;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
928c2ecf20Sopenharmony_ci	xlr_uart_data[0].membase = (void __iomem *)uartbase;
938c2ecf20Sopenharmony_ci	xlr_uart_data[0].mapbase = CPHYSADDR(uartbase);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET);
968c2ecf20Sopenharmony_ci	xlr_uart_data[1].membase = (void __iomem *)uartbase;
978c2ecf20Sopenharmony_ci	xlr_uart_data[1].mapbase = CPHYSADDR(uartbase);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return platform_device_register(&uart_device);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ciarch_initcall(nlm_uart_init);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#ifdef CONFIG_USB
1058c2ecf20Sopenharmony_ci/* Platform USB devices, only on XLS chips */
1068c2ecf20Sopenharmony_cistatic u64 xls_usb_dmamask = ~(u32)0;
1078c2ecf20Sopenharmony_ci#define USB_PLATFORM_DEV(n, i, irq)					\
1088c2ecf20Sopenharmony_ci	{								\
1098c2ecf20Sopenharmony_ci		.name		= n,					\
1108c2ecf20Sopenharmony_ci		.id		= i,					\
1118c2ecf20Sopenharmony_ci		.num_resources	= 2,					\
1128c2ecf20Sopenharmony_ci		.dev		= {					\
1138c2ecf20Sopenharmony_ci			.dma_mask	= &xls_usb_dmamask,		\
1148c2ecf20Sopenharmony_ci			.coherent_dma_mask = 0xffffffff,		\
1158c2ecf20Sopenharmony_ci		},							\
1168c2ecf20Sopenharmony_ci		.resource	= (struct resource[]) {			\
1178c2ecf20Sopenharmony_ci			{						\
1188c2ecf20Sopenharmony_ci				.flags = IORESOURCE_MEM,		\
1198c2ecf20Sopenharmony_ci			},						\
1208c2ecf20Sopenharmony_ci			{						\
1218c2ecf20Sopenharmony_ci				.start	= irq,				\
1228c2ecf20Sopenharmony_ci				.end	= irq,				\
1238c2ecf20Sopenharmony_ci				.flags = IORESOURCE_IRQ,		\
1248c2ecf20Sopenharmony_ci			},						\
1258c2ecf20Sopenharmony_ci		},							\
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic struct usb_ehci_pdata xls_usb_ehci_pdata = {
1298c2ecf20Sopenharmony_ci	.caps_offset	= 0,
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic struct usb_ohci_pdata xls_usb_ohci_pdata;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct platform_device xls_usb_ehci_device =
1358c2ecf20Sopenharmony_ci			 USB_PLATFORM_DEV("ehci-platform", 0, PIC_USB_IRQ);
1368c2ecf20Sopenharmony_cistatic struct platform_device xls_usb_ohci_device_0 =
1378c2ecf20Sopenharmony_ci			 USB_PLATFORM_DEV("ohci-platform", 1, PIC_USB_IRQ);
1388c2ecf20Sopenharmony_cistatic struct platform_device xls_usb_ohci_device_1 =
1398c2ecf20Sopenharmony_ci			 USB_PLATFORM_DEV("ohci-platform", 2, PIC_USB_IRQ);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic struct platform_device *xls_platform_devices[] = {
1428c2ecf20Sopenharmony_ci	&xls_usb_ehci_device,
1438c2ecf20Sopenharmony_ci	&xls_usb_ohci_device_0,
1448c2ecf20Sopenharmony_ci	&xls_usb_ohci_device_1,
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciint xls_platform_usb_init(void)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	uint64_t usb_mmio, gpio_mmio;
1508c2ecf20Sopenharmony_ci	unsigned long memres;
1518c2ecf20Sopenharmony_ci	uint32_t val;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!nlm_chip_is_xls())
1548c2ecf20Sopenharmony_ci		return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
1578c2ecf20Sopenharmony_ci	usb_mmio  = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Clear Rogue Phy INTs */
1608c2ecf20Sopenharmony_ci	nlm_write_reg(usb_mmio, 49, 0x10000000);
1618c2ecf20Sopenharmony_ci	/* Enable all interrupts */
1628c2ecf20Sopenharmony_ci	nlm_write_reg(usb_mmio, 50, 0x1f000000);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/* Enable ports */
1658c2ecf20Sopenharmony_ci	nlm_write_reg(usb_mmio,	 1, 0x07000500);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	val = nlm_read_reg(gpio_mmio, 21);
1688c2ecf20Sopenharmony_ci	if (((val >> 22) & 0x01) == 0) {
1698c2ecf20Sopenharmony_ci		pr_info("Detected USB Device mode - Not supported!\n");
1708c2ecf20Sopenharmony_ci		nlm_write_reg(usb_mmio,	 0, 0x01000000);
1718c2ecf20Sopenharmony_ci		return 0;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	pr_info("Detected USB Host mode - Adding XLS USB devices.\n");
1758c2ecf20Sopenharmony_ci	/* Clear reset, host mode */
1768c2ecf20Sopenharmony_ci	nlm_write_reg(usb_mmio,	 0, 0x02000000);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* Memory resource for various XLS usb ports */
1798c2ecf20Sopenharmony_ci	usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET);
1808c2ecf20Sopenharmony_ci	memres = CPHYSADDR((unsigned long)usb_mmio);
1818c2ecf20Sopenharmony_ci	xls_usb_ehci_device.resource[0].start = memres;
1828c2ecf20Sopenharmony_ci	xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1;
1838c2ecf20Sopenharmony_ci	xls_usb_ehci_device.dev.platform_data = &xls_usb_ehci_pdata;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	memres += 0x400;
1868c2ecf20Sopenharmony_ci	xls_usb_ohci_device_0.resource[0].start = memres;
1878c2ecf20Sopenharmony_ci	xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1;
1888c2ecf20Sopenharmony_ci	xls_usb_ohci_device_0.dev.platform_data = &xls_usb_ohci_pdata;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	memres += 0x400;
1918c2ecf20Sopenharmony_ci	xls_usb_ohci_device_1.resource[0].start = memres;
1928c2ecf20Sopenharmony_ci	xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1;
1938c2ecf20Sopenharmony_ci	xls_usb_ohci_device_1.dev.platform_data = &xls_usb_ohci_pdata;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return platform_add_devices(xls_platform_devices,
1968c2ecf20Sopenharmony_ci				ARRAY_SIZE(xls_platform_devices));
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ciarch_initcall(xls_platform_usb_init);
2008c2ecf20Sopenharmony_ci#endif
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#ifdef CONFIG_I2C
2038c2ecf20Sopenharmony_cistatic struct i2c_board_info nlm_i2c_board_info1[] __initdata = {
2048c2ecf20Sopenharmony_ci	/* All XLR boards have this RTC and Max6657 Temp Chip */
2058c2ecf20Sopenharmony_ci	[0] = {
2068c2ecf20Sopenharmony_ci		.type	= "ds1374",
2078c2ecf20Sopenharmony_ci		.addr	= 0x68
2088c2ecf20Sopenharmony_ci	},
2098c2ecf20Sopenharmony_ci	[1] = {
2108c2ecf20Sopenharmony_ci		.type	= "lm90",
2118c2ecf20Sopenharmony_ci		.addr	= 0x4c
2128c2ecf20Sopenharmony_ci	},
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic struct resource i2c_resources[] = {
2168c2ecf20Sopenharmony_ci	[0] = {
2178c2ecf20Sopenharmony_ci		.start	= 0,	/* filled at init */
2188c2ecf20Sopenharmony_ci		.end	= 0,
2198c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
2208c2ecf20Sopenharmony_ci	},
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic struct platform_device nlm_xlr_i2c_1 = {
2248c2ecf20Sopenharmony_ci	.name		= "xlr-i2cbus",
2258c2ecf20Sopenharmony_ci	.id		= 1,
2268c2ecf20Sopenharmony_ci	.num_resources	= 1,
2278c2ecf20Sopenharmony_ci	.resource	= i2c_resources,
2288c2ecf20Sopenharmony_ci};
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int __init nlm_i2c_init(void)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	int err = 0;
2338c2ecf20Sopenharmony_ci	unsigned int offset;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* I2C bus 0 does not have any useful devices, configure only bus 1 */
2368c2ecf20Sopenharmony_ci	offset = NETLOGIC_IO_I2C_1_OFFSET;
2378c2ecf20Sopenharmony_ci	nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset));
2388c2ecf20Sopenharmony_ci	nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	platform_device_register(&nlm_xlr_i2c_1);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	err = i2c_register_board_info(1, nlm_i2c_board_info1,
2438c2ecf20Sopenharmony_ci				ARRAY_SIZE(nlm_i2c_board_info1));
2448c2ecf20Sopenharmony_ci	if (err < 0)
2458c2ecf20Sopenharmony_ci		pr_err("nlm-i2c: cannot register board I2C devices\n");
2468c2ecf20Sopenharmony_ci	return err;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ciarch_initcall(nlm_i2c_init);
2508c2ecf20Sopenharmony_ci#endif
251