| /* | |
| * Copyright 2011, Netlogic Microsystems. | |
| * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | |
| * | |
| * This file is licensed under the terms of the GNU General Public | |
| * License version 2. This program is licensed "as is" without any | |
| * warranty of any kind, whether express or implied. | |
| */ | |
| #include <linux/device.h> | |
| #include <linux/platform_device.h> | |
| #include <linux/kernel.h> | |
| #include <linux/init.h> | |
| #include <linux/resource.h> | |
| #include <linux/serial_8250.h> | |
| #include <linux/serial_reg.h> | |
| #include <linux/i2c.h> | |
| #include <linux/usb/ehci_pdriver.h> | |
| #include <linux/usb/ohci_pdriver.h> | |
| #include <asm/netlogic/haldefs.h> | |
| #include <asm/netlogic/xlr/iomap.h> | |
| #include <asm/netlogic/xlr/pic.h> | |
| #include <asm/netlogic/xlr/xlr.h> | |
| static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) | |
| { | |
| uint64_t uartbase; | |
| unsigned int value; | |
| /* sign extend to 64 bits, if needed */ | |
| uartbase = (uint64_t)(long)p->membase; | |
| value = nlm_read_reg(uartbase, offset); | |
| /* See XLR/XLS errata */ | |
| if (offset == UART_MSR) | |
| value ^= 0xF0; | |
| else if (offset == UART_MCR) | |
| value ^= 0x3; | |
| return value; | |
| } | |
| static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) | |
| { | |
| uint64_t uartbase; | |
| /* sign extend to 64 bits, if needed */ | |
| uartbase = (uint64_t)(long)p->membase; | |
| /* See XLR/XLS errata */ | |
| if (offset == UART_MSR) | |
| value ^= 0xF0; | |
| else if (offset == UART_MCR) | |
| value ^= 0x3; | |
| nlm_write_reg(uartbase, offset, value); | |
| } | |
| #define PORT(_irq) \ | |
| { \ | |
| .irq = _irq, \ | |
| .regshift = 2, \ | |
| .iotype = UPIO_MEM32, \ | |
| .flags = (UPF_SKIP_TEST | \ | |
| UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ | |
| .uartclk = PIC_CLK_HZ, \ | |
| .type = PORT_16550A, \ | |
| .serial_in = nlm_xlr_uart_in, \ | |
| .serial_out = nlm_xlr_uart_out, \ | |
| } | |
| static struct plat_serial8250_port xlr_uart_data[] = { | |
| PORT(PIC_UART_0_IRQ), | |
| PORT(PIC_UART_1_IRQ), | |
| {}, | |
| }; | |
| static struct platform_device uart_device = { | |
| .name = "serial8250", | |
| .id = PLAT8250_DEV_PLATFORM, | |
| .dev = { | |
| .platform_data = xlr_uart_data, | |
| }, | |
| }; | |
| static int __init nlm_uart_init(void) | |
| { | |
| unsigned long uartbase; | |
| uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); | |
| xlr_uart_data[0].membase = (void __iomem *)uartbase; | |
| xlr_uart_data[0].mapbase = CPHYSADDR(uartbase); | |
| uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET); | |
| xlr_uart_data[1].membase = (void __iomem *)uartbase; | |
| xlr_uart_data[1].mapbase = CPHYSADDR(uartbase); | |
| return platform_device_register(&uart_device); | |
| } | |
| arch_initcall(nlm_uart_init); | |
| #ifdef CONFIG_USB | |
| /* Platform USB devices, only on XLS chips */ | |
| static u64 xls_usb_dmamask = ~(u32)0; | |
| #define USB_PLATFORM_DEV(n, i, irq) \ | |
| { \ | |
| .name = n, \ | |
| .id = i, \ | |
| .num_resources = 2, \ | |
| .dev = { \ | |
| .dma_mask = &xls_usb_dmamask, \ | |
| .coherent_dma_mask = 0xffffffff, \ | |
| }, \ | |
| .resource = (struct resource[]) { \ | |
| { \ | |
| .flags = IORESOURCE_MEM, \ | |
| }, \ | |
| { \ | |
| .start = irq, \ | |
| .end = irq, \ | |
| .flags = IORESOURCE_IRQ, \ | |
| }, \ | |
| }, \ | |
| } | |
| static struct usb_ehci_pdata xls_usb_ehci_pdata = { | |
| .caps_offset = 0, | |
| }; | |
| static struct usb_ohci_pdata xls_usb_ohci_pdata; | |
| static struct platform_device xls_usb_ehci_device = | |
| USB_PLATFORM_DEV("ehci-platform", 0, PIC_USB_IRQ); | |
| static struct platform_device xls_usb_ohci_device_0 = | |
| USB_PLATFORM_DEV("ohci-platform", 1, PIC_USB_IRQ); | |
| static struct platform_device xls_usb_ohci_device_1 = | |
| USB_PLATFORM_DEV("ohci-platform", 2, PIC_USB_IRQ); | |
| static struct platform_device *xls_platform_devices[] = { | |
| &xls_usb_ehci_device, | |
| &xls_usb_ohci_device_0, | |
| &xls_usb_ohci_device_1, | |
| }; | |
| int xls_platform_usb_init(void) | |
| { | |
| uint64_t usb_mmio, gpio_mmio; | |
| unsigned long memres; | |
| uint32_t val; | |
| if (!nlm_chip_is_xls()) | |
| return 0; | |
| gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); | |
| usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET); | |
| /* Clear Rogue Phy INTs */ | |
| nlm_write_reg(usb_mmio, 49, 0x10000000); | |
| /* Enable all interrupts */ | |
| nlm_write_reg(usb_mmio, 50, 0x1f000000); | |
| /* Enable ports */ | |
| nlm_write_reg(usb_mmio, 1, 0x07000500); | |
| val = nlm_read_reg(gpio_mmio, 21); | |
| if (((val >> 22) & 0x01) == 0) { | |
| pr_info("Detected USB Device mode - Not supported!\n"); | |
| nlm_write_reg(usb_mmio, 0, 0x01000000); | |
| return 0; | |
| } | |
| pr_info("Detected USB Host mode - Adding XLS USB devices.\n"); | |
| /* Clear reset, host mode */ | |
| nlm_write_reg(usb_mmio, 0, 0x02000000); | |
| /* Memory resource for various XLS usb ports */ | |
| usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET); | |
| memres = CPHYSADDR((unsigned long)usb_mmio); | |
| xls_usb_ehci_device.resource[0].start = memres; | |
| xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1; | |
| xls_usb_ehci_device.dev.platform_data = &xls_usb_ehci_pdata; | |
| memres += 0x400; | |
| xls_usb_ohci_device_0.resource[0].start = memres; | |
| xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1; | |
| xls_usb_ohci_device_0.dev.platform_data = &xls_usb_ohci_pdata; | |
| memres += 0x400; | |
| xls_usb_ohci_device_1.resource[0].start = memres; | |
| xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1; | |
| xls_usb_ohci_device_1.dev.platform_data = &xls_usb_ohci_pdata; | |
| return platform_add_devices(xls_platform_devices, | |
| ARRAY_SIZE(xls_platform_devices)); | |
| } | |
| arch_initcall(xls_platform_usb_init); | |
| #endif | |
| #ifdef CONFIG_I2C | |
| static struct i2c_board_info nlm_i2c_board_info1[] __initdata = { | |
| /* All XLR boards have this RTC and Max6657 Temp Chip */ | |
| [0] = { | |
| .type = "ds1374", | |
| .addr = 0x68 | |
| }, | |
| [1] = { | |
| .type = "lm90", | |
| .addr = 0x4c | |
| }, | |
| }; | |
| static struct resource i2c_resources[] = { | |
| [0] = { | |
| .start = 0, /* filled at init */ | |
| .end = 0, | |
| .flags = IORESOURCE_MEM, | |
| }, | |
| }; | |
| static struct platform_device nlm_xlr_i2c_1 = { | |
| .name = "xlr-i2cbus", | |
| .id = 1, | |
| .num_resources = 1, | |
| .resource = i2c_resources, | |
| }; | |
| static int __init nlm_i2c_init(void) | |
| { | |
| int err = 0; | |
| unsigned int offset; | |
| /* I2C bus 0 does not have any useful devices, configure only bus 1 */ | |
| offset = NETLOGIC_IO_I2C_1_OFFSET; | |
| nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset)); | |
| nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff; | |
| platform_device_register(&nlm_xlr_i2c_1); | |
| err = i2c_register_board_info(1, nlm_i2c_board_info1, | |
| ARRAY_SIZE(nlm_i2c_board_info1)); | |
| if (err < 0) | |
| pr_err("nlm-i2c: cannot register board I2C devices\n"); | |
| return err; | |
| } | |
| arch_initcall(nlm_i2c_init); | |
| #endif |