mirror of https://gitee.com/openkylin/linux.git
240 lines
5.8 KiB
C
240 lines
5.8 KiB
C
/*
|
|
* 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 <asm/netlogic/haldefs.h>
|
|
#include <asm/netlogic/xlr/iomap.h>
|
|
#include <asm/netlogic/xlr/pic.h>
|
|
#include <asm/netlogic/xlr/xlr.h>
|
|
|
|
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;
|
|
}
|
|
|
|
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_CLKS_PER_SEC, \
|
|
.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 platform_device xls_usb_ehci_device =
|
|
USB_PLATFORM_DEV("ehci-xls", 0, PIC_USB_IRQ);
|
|
static struct platform_device xls_usb_ohci_device_0 =
|
|
USB_PLATFORM_DEV("ohci-xls-0", 1, PIC_USB_IRQ);
|
|
static struct platform_device xls_usb_ohci_device_1 =
|
|
USB_PLATFORM_DEV("ohci-xls-1", 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;
|
|
|
|
memres += 0x400;
|
|
xls_usb_ohci_device_0.resource[0].start = memres;
|
|
xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1;
|
|
|
|
memres += 0x400;
|
|
xls_usb_ohci_device_1.resource[0].start = memres;
|
|
xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1;
|
|
|
|
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
|