diff options
Diffstat (limited to 'arch/mips/mti-sead3')
23 files changed, 2226 insertions, 0 deletions
diff --git a/arch/mips/mti-sead3/Makefile b/arch/mips/mti-sead3/Makefile new file mode 100644 index 00000000000..071786fa234 --- /dev/null +++ b/arch/mips/mti-sead3/Makefile @@ -0,0 +1,27 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# Copyright (C) 2008 Wind River Systems, Inc. +# written by Ralf Baechle <ralf@linux-mips.org> +# +# Copyright (C) 2012 MIPS Technoligies, Inc. All rights reserved. +# Steven J. Hill <sjhill@mips.com> +# +obj-y := sead3-lcd.o sead3-display.o sead3-init.o \ + sead3-int.o sead3-mtd.o sead3-net.o \ + sead3-platform.o sead3-reset.o \ + sead3-setup.o sead3-time.o + +obj-y += sead3-i2c-dev.o sead3-i2c.o \ + sead3-pic32-i2c-drv.o sead3-pic32-bus.o \ + leds-sead3.o sead3-leds.o + +obj-$(CONFIG_EARLY_PRINTK) += sead3-console.o +obj-$(CONFIG_USB_EHCI_HCD) += sead3-ehci.o +obj-$(CONFIG_OF) += sead3.dtb.o + +CFLAGS_sead3-setup.o = -I$(src)/../../../scripts/dtc/libfdt + +$(obj)/%.dtb: $(obj)/%.dts + $(call if_changed,dtc) diff --git a/arch/mips/mti-sead3/Platform b/arch/mips/mti-sead3/Platform new file mode 100644 index 00000000000..38709242714 --- /dev/null +++ b/arch/mips/mti-sead3/Platform @@ -0,0 +1,7 @@ +# +# MIPS SEAD-3 board +# +platform-$(CONFIG_MIPS_SEAD3) += mti-sead3/ +cflags-$(CONFIG_MIPS_SEAD3) += -I$(srctree)/arch/mips/include/asm/mach-sead3 +load-$(CONFIG_MIPS_SEAD3) += 0xffffffff80100000 +all-$(CONFIG_MIPS_SEAD3) := $(COMPRESSION_FNAME).srec diff --git a/arch/mips/mti-sead3/leds-sead3.c b/arch/mips/mti-sead3/leds-sead3.c new file mode 100644 index 00000000000..0a168c948b0 --- /dev/null +++ b/arch/mips/mti-sead3/leds-sead3.c @@ -0,0 +1,107 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/err.h> +#include <linux/io.h> + +#define DRVNAME "sead3-led" + +static struct platform_device *pdev; + +static void sead3_pled_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + pr_debug("sead3_pled_set\n"); + writel(value, (void __iomem *)0xBF000210); /* FIXME */ +} + +static void sead3_fled_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + pr_debug("sead3_fled_set\n"); + writel(value, (void __iomem *)0xBF000218); /* FIXME */ +} + +static struct led_classdev sead3_pled = { + .name = "sead3::pled", + .brightness_set = sead3_pled_set, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static struct led_classdev sead3_fled = { + .name = "sead3::fled", + .brightness_set = sead3_fled_set, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static int sead3_led_probe(struct platform_device *pdev) +{ + int ret; + + ret = led_classdev_register(&pdev->dev, &sead3_pled); + if (ret < 0) + return ret; + + ret = led_classdev_register(&pdev->dev, &sead3_fled); + if (ret < 0) + led_classdev_unregister(&sead3_pled); + + return ret; +} + +static int sead3_led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&sead3_pled); + led_classdev_unregister(&sead3_fled); + return 0; +} + +static struct platform_driver sead3_led_driver = { + .probe = sead3_led_probe, + .remove = sead3_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init sead3_led_init(void) +{ + int ret; + + ret = platform_driver_register(&sead3_led_driver); + if (ret < 0) + goto out; + + pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + platform_driver_unregister(&sead3_led_driver); + goto out; + } + +out: + return ret; +} + +static void __exit sead3_led_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&sead3_led_driver); +} + +module_init(sead3_led_init); +module_exit(sead3_led_exit); + +MODULE_AUTHOR("Kristian Kielhofner <kris@krisk.org>"); +MODULE_DESCRIPTION("SEAD3 LED driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/mti-sead3/sead3-console.c b/arch/mips/mti-sead3/sead3-console.c new file mode 100644 index 00000000000..031f47d6977 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-console.c @@ -0,0 +1,46 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/console.h> +#include <linux/serial_reg.h> +#include <linux/io.h> + +#define SEAD_UART1_REGS_BASE 0xbf000800 /* ttyS1 = DB9 port */ +#define SEAD_UART0_REGS_BASE 0xbf000900 /* ttyS0 = USB port */ +#define PORT(base_addr, offset) ((unsigned int __iomem *)(base_addr+(offset)*4)) + +static char console_port = 1; + +static inline unsigned int serial_in(int offset, unsigned int base_addr) +{ + return __raw_readl(PORT(base_addr, offset)) & 0xff; +} + +static inline void serial_out(int offset, int value, unsigned int base_addr) +{ + __raw_writel(value, PORT(base_addr, offset)); +} + +void __init fw_init_early_console(char port) +{ + console_port = port; +} + +int prom_putchar(char c) +{ + unsigned int base_addr; + + base_addr = console_port ? SEAD_UART1_REGS_BASE : SEAD_UART0_REGS_BASE; + + while ((serial_in(UART_LSR, base_addr) & UART_LSR_THRE) == 0) + ; + + serial_out(UART_TX, c, base_addr); + + return 1; +} diff --git a/arch/mips/mti-sead3/sead3-display.c b/arch/mips/mti-sead3/sead3-display.c new file mode 100644 index 00000000000..94875991907 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-display.c @@ -0,0 +1,77 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/timer.h> +#include <linux/io.h> +#include <asm/mips-boards/generic.h> + +static unsigned int display_count; +static unsigned int max_display_count; + +#define LCD_DISPLAY_POS_BASE 0x1f000400 +#define DISPLAY_LCDINSTRUCTION (0*2) +#define DISPLAY_LCDDATA (1*2) +#define DISPLAY_CPLDSTATUS (2*2) +#define DISPLAY_CPLDDATA (3*2) +#define LCD_SETDDRAM 0x80 +#define LCD_IR_BF 0x80 + +const char display_string[] = " LINUX ON SEAD3 "; + +static void scroll_display_message(unsigned long data); +static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); + +static void lcd_wait(unsigned int __iomem *display) +{ + /* Wait for CPLD state machine to become idle. */ + do { } while (__raw_readl(display + DISPLAY_CPLDSTATUS) & 1); + + do { + __raw_readl(display + DISPLAY_LCDINSTRUCTION); + + /* Wait for CPLD state machine to become idle. */ + do { } while (__raw_readl(display + DISPLAY_CPLDSTATUS) & 1); + } while (__raw_readl(display + DISPLAY_CPLDDATA) & LCD_IR_BF); +} + +void mips_display_message(const char *str) +{ + static unsigned int __iomem *display; + char ch; + int i; + + if (unlikely(display == NULL)) + display = ioremap_nocache(LCD_DISPLAY_POS_BASE, + (8 * sizeof(int))); + + for (i = 0; i < 16; i++) { + if (*str) + ch = *str++; + else + ch = ' '; + lcd_wait(display); + __raw_writel((LCD_SETDDRAM | i), + (display + DISPLAY_LCDINSTRUCTION)); + lcd_wait(display); + __raw_writel(ch, display + DISPLAY_LCDDATA); + } +} + +static void scroll_display_message(unsigned long data) +{ + mips_display_message(&display_string[display_count++]); + if (display_count == max_display_count) + display_count = 0; + mod_timer(&mips_scroll_timer, jiffies + HZ); +} + +void mips_scroll_message(void) +{ + del_timer_sync(&mips_scroll_timer); + max_display_count = strlen(display_string) + 1 - 16; + mod_timer(&mips_scroll_timer, jiffies + 1); +} diff --git a/arch/mips/mti-sead3/sead3-ehci.c b/arch/mips/mti-sead3/sead3-ehci.c new file mode 100644 index 00000000000..772fc056a92 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-ehci.c @@ -0,0 +1,47 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +struct resource ehci_resources[] = { + { + .start = 0x1b200000, + .end = 0x1b200fff, + .flags = IORESOURCE_MEM + }, + { + .start = MIPS_CPU_IRQ_BASE + 2, + .flags = IORESOURCE_IRQ + } +}; + +u64 sead3_usbdev_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device ehci_device = { + .name = "sead3-ehci", + .id = 0, + .dev = { + .dma_mask = &sead3_usbdev_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32) + }, + .num_resources = ARRAY_SIZE(ehci_resources), + .resource = ehci_resources +}; + +static int __init ehci_init(void) +{ + return platform_device_register(&ehci_device); +} + +module_init(ehci_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EHCI probe driver for SEAD3"); diff --git a/arch/mips/mti-sead3/sead3-i2c-dev.c b/arch/mips/mti-sead3/sead3-i2c-dev.c new file mode 100644 index 00000000000..eca0b53a71d --- /dev/null +++ b/arch/mips/mti-sead3/sead3-i2c-dev.c @@ -0,0 +1,33 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/i2c.h> + +static struct i2c_board_info __initdata sead3_i2c_devices[] = { + { + I2C_BOARD_INFO("adt7476", 0x2c), + .irq = 0, + }, + { + I2C_BOARD_INFO("m41t80", 0x68), + .irq = 0, + }, +}; + +static int __init sead3_i2c_init(void) +{ + int err; + + err = i2c_register_board_info(0, sead3_i2c_devices, + ARRAY_SIZE(sead3_i2c_devices)); + if (err < 0) + pr_err("sead3-i2c-dev: cannot register board I2C devices\n"); + return err; +} + +arch_initcall(sead3_i2c_init); diff --git a/arch/mips/mti-sead3/sead3-i2c-drv.c b/arch/mips/mti-sead3/sead3-i2c-drv.c new file mode 100644 index 00000000000..1f787a6a787 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-i2c-drv.c @@ -0,0 +1,405 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> + +#define PIC32_I2CxCON 0x0000 +#define PIC32_I2CCON_ON (1<<15) +#define PIC32_I2CCON_ACKDT (1<<5) +#define PIC32_I2CCON_ACKEN (1<<4) +#define PIC32_I2CCON_RCEN (1<<3) +#define PIC32_I2CCON_PEN (1<<2) +#define PIC32_I2CCON_RSEN (1<<1) +#define PIC32_I2CCON_SEN (1<<0) +#define PIC32_I2CxCONCLR 0x0004 +#define PIC32_I2CxCONSET 0x0008 +#define PIC32_I2CxSTAT 0x0010 +#define PIC32_I2CxSTATCLR 0x0014 +#define PIC32_I2CSTAT_ACKSTAT (1<<15) +#define PIC32_I2CSTAT_TRSTAT (1<<14) +#define PIC32_I2CSTAT_BCL (1<<10) +#define PIC32_I2CSTAT_IWCOL (1<<7) +#define PIC32_I2CSTAT_I2COV (1<<6) +#define PIC32_I2CxBRG 0x0040 +#define PIC32_I2CxTRN 0x0050 +#define PIC32_I2CxRCV 0x0060 + +static DEFINE_SPINLOCK(pic32_bus_lock); + +static void __iomem *bus_xfer = (void __iomem *)0xbf000600; +static void __iomem *bus_status = (void __iomem *)0xbf000060; + +#define DELAY() udelay(100) + +static inline unsigned int ioready(void) +{ + return readl(bus_status) & 1; +} + +static inline void wait_ioready(void) +{ + do { } while (!ioready()); +} + +static inline void wait_ioclear(void) +{ + do { } while (ioready()); +} + +static inline void check_ioclear(void) +{ + if (ioready()) { + do { + (void) readl(bus_xfer); + DELAY(); + } while (ioready()); + } +} + +static u32 pic32_bus_readl(u32 reg) +{ + unsigned long flags; + u32 status, val; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + writel((0x01 << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + DELAY(); + val = readl(bus_xfer); + wait_ioclear(); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); + + return val; +} + +static void pic32_bus_writel(u32 val, u32 reg) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + writel((0x10 << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + writel(val, bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + wait_ioclear(); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); +} + +struct pic32_i2c_platform_data { + u32 base; + struct i2c_adapter adap; + u32 xfer_timeout; + u32 ack_timeout; + u32 ctl_timeout; +}; + +static inline void pic32_i2c_start(struct pic32_i2c_platform_data *adap) +{ + pic32_bus_writel(PIC32_I2CCON_SEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void pic32_i2c_stop(struct pic32_i2c_platform_data *adap) +{ + pic32_bus_writel(PIC32_I2CCON_PEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void pic32_i2c_ack(struct pic32_i2c_platform_data *adap) +{ + pic32_bus_writel(PIC32_I2CCON_ACKDT, adap->base + PIC32_I2CxCONCLR); + pic32_bus_writel(PIC32_I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void pic32_i2c_nack(struct pic32_i2c_platform_data *adap) +{ + pic32_bus_writel(PIC32_I2CCON_ACKDT, adap->base + PIC32_I2CxCONSET); + pic32_bus_writel(PIC32_I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); +} + +static inline int pic32_i2c_idle(struct pic32_i2c_platform_data *adap) +{ + int i; + + for (i = 0; i < adap->ctl_timeout; i++) { + if (((pic32_bus_readl(adap->base + PIC32_I2CxCON) & + (PIC32_I2CCON_ACKEN | PIC32_I2CCON_RCEN | + PIC32_I2CCON_PEN | PIC32_I2CCON_RSEN | + PIC32_I2CCON_SEN)) == 0) && + ((pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + (PIC32_I2CSTAT_TRSTAT)) == 0)) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static inline u32 pic32_i2c_master_write(struct pic32_i2c_platform_data *adap, + u32 byte) +{ + pic32_bus_writel(byte, adap->base + PIC32_I2CxTRN); + return pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + PIC32_I2CSTAT_IWCOL; +} + +static inline u32 pic32_i2c_master_read(struct pic32_i2c_platform_data *adap) +{ + pic32_bus_writel(PIC32_I2CCON_RCEN, adap->base + PIC32_I2CxCONSET); + while (pic32_bus_readl(adap->base + PIC32_I2CxCON) & PIC32_I2CCON_RCEN) + ; + pic32_bus_writel(PIC32_I2CSTAT_I2COV, adap->base + PIC32_I2CxSTATCLR); + return pic32_bus_readl(adap->base + PIC32_I2CxRCV); +} + +static int pic32_i2c_address(struct pic32_i2c_platform_data *adap, + unsigned int addr, int rd) +{ + pic32_i2c_idle(adap); + pic32_i2c_start(adap); + pic32_i2c_idle(adap); + + addr <<= 1; + if (rd) + addr |= 1; + + if (pic32_i2c_master_write(adap, addr)) + return -EIO; + pic32_i2c_idle(adap); + if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + PIC32_I2CSTAT_ACKSTAT) + return -EIO; + return 0; +} + +static int sead3_i2c_read(struct pic32_i2c_platform_data *adap, + unsigned char *buf, unsigned int len) +{ + u32 data; + int i; + + i = 0; + while (i < len) { + data = pic32_i2c_master_read(adap); + buf[i++] = data; + if (i < len) + pic32_i2c_ack(adap); + else + pic32_i2c_nack(adap); + } + + pic32_i2c_stop(adap); + pic32_i2c_idle(adap); + return 0; +} + +static int sead3_i2c_write(struct pic32_i2c_platform_data *adap, + unsigned char *buf, unsigned int len) +{ + int i; + u32 data; + + i = 0; + while (i < len) { + data = buf[i]; + if (pic32_i2c_master_write(adap, data)) + return -EIO; + pic32_i2c_idle(adap); + if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + PIC32_I2CSTAT_ACKSTAT) + return -EIO; + i++; + } + + pic32_i2c_stop(adap); + pic32_i2c_idle(adap); + return 0; +} + +static int sead3_pic32_platform_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct pic32_i2c_platform_data *adap = i2c_adap->algo_data; + struct i2c_msg *p; + int i, err = 0; + + for (i = 0; i < num; i++) { +#define __BUFSIZE 80 + int ii; + static char buf[__BUFSIZE]; + char *b = buf; + + p = &msgs[i]; + b += sprintf(buf, " [%d bytes]", p->len); + if ((p->flags & I2C_M_RD) == 0) { + for (ii = 0; ii < p->len; ii++) { + if (b < &buf[__BUFSIZE-4]) { + b += sprintf(b, " %02x", p->buf[ii]); + } else { + strcat(b, "..."); + break; + } + } + } + } + + for (i = 0; !err && i < num; i++) { + p = &msgs[i]; + err = pic32_i2c_address(adap, p->addr, p->flags & I2C_M_RD); + if (err || !p->len) + continue; + if (p->flags & I2C_M_RD) + err = sead3_i2c_read(adap, p->buf, p->len); + else + err = sead3_i2c_write(adap, p->buf, p->len); + } + + /* Return the number of messages processed, or the error code. */ + if (err == 0) + err = num; + + return err; +} + +static u32 sead3_pic32_platform_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm sead3_platform_algo = { + .master_xfer = sead3_pic32_platform_xfer, + .functionality = sead3_pic32_platform_func, +}; + +static void sead3_i2c_platform_setup(struct pic32_i2c_platform_data *priv) +{ + pic32_bus_writel(500, priv->base + PIC32_I2CxBRG); + pic32_bus_writel(PIC32_I2CCON_ON, priv->base + PIC32_I2CxCONCLR); + pic32_bus_writel(PIC32_I2CCON_ON, priv->base + PIC32_I2CxCONSET); + pic32_bus_writel(PIC32_I2CSTAT_BCL | PIC32_I2CSTAT_IWCOL, + priv->base + PIC32_I2CxSTATCLR); +} + +static int sead3_i2c_platform_probe(struct platform_device *pdev) +{ + struct pic32_i2c_platform_data *priv; + struct resource *r; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out; + } + + priv = kzalloc(sizeof(struct pic32_i2c_platform_data), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + + priv->base = r->start; + if (!priv->base) { + ret = -EBUSY; + goto out_mem; + } + + priv->xfer_timeout = 200; + priv->ack_timeout = 200; + priv->ctl_timeout = 200; + + priv->adap.nr = pdev->id; + priv->adap.algo = &sead3_platform_algo; + priv->adap.algo_data = priv; + priv->adap.dev.parent = &pdev->dev; + strlcpy(priv->adap.name, "SEAD3 PIC32", sizeof(priv->adap.name)); + + sead3_i2c_platform_setup(priv); + + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret == 0) { + platform_set_drvdata(pdev, priv); + return 0; + } + +out_mem: + kfree(priv); +out: + return ret; +} + +static int sead3_i2c_platform_remove(struct platform_device *pdev) +{ + struct pic32_i2c_platform_data *priv = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&priv->adap); + kfree(priv); + return 0; +} + +#ifdef CONFIG_PM +static int sead3_i2c_platform_suspend(struct platform_device *pdev, + pm_message_t state) +{ + dev_dbg(&pdev->dev, "i2c_platform_disable\n"); + return 0; +} + +static int sead3_i2c_platform_resume(struct platform_device *pdev) +{ + struct pic32_i2c_platform_data *priv = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "sead3_i2c_platform_setup\n"); + sead3_i2c_platform_setup(priv); + + return 0; +} +#else +#define sead3_i2c_platform_suspend NULL +#define sead3_i2c_platform_resume NULL +#endif + +static struct platform_driver sead3_i2c_platform_driver = { + .driver = { + .name = "sead3-i2c", + .owner = THIS_MODULE, + }, + .probe = sead3_i2c_platform_probe, + .remove = sead3_i2c_platform_remove, + .suspend = sead3_i2c_platform_suspend, + .resume = sead3_i2c_platform_resume, +}; + +static int __init sead3_i2c_platform_init(void) +{ + return platform_driver_register(&sead3_i2c_platform_driver); +} +module_init(sead3_i2c_platform_init); + +static void __exit sead3_i2c_platform_exit(void) +{ + platform_driver_unregister(&sead3_i2c_platform_driver); +} +module_exit(sead3_i2c_platform_exit); + +MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC."); +MODULE_DESCRIPTION("SEAD3 PIC32 I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/mti-sead3/sead3-i2c.c b/arch/mips/mti-sead3/sead3-i2c.c new file mode 100644 index 00000000000..f70d5fc58ef --- /dev/null +++ b/arch/mips/mti-sead3/sead3-i2c.c @@ -0,0 +1,37 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <irq.h> + +struct resource sead3_i2c_resources[] = { + { + .start = 0x805200, + .end = 0x8053ff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sead3_i2c_device = { + .name = "sead3-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(sead3_i2c_resources), + .resource = sead3_i2c_resources, +}; + +static int __init sead3_i2c_init(void) +{ + return platform_device_register(&sead3_i2c_device); +} + +module_init(sead3_i2c_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2C probe driver for SEAD3"); diff --git a/arch/mips/mti-sead3/sead3-init.c b/arch/mips/mti-sead3/sead3-init.c new file mode 100644 index 00000000000..bfbd17b120a --- /dev/null +++ b/arch/mips/mti-sead3/sead3-init.c @@ -0,0 +1,152 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/bootinfo.h> +#include <asm/cacheflush.h> +#include <asm/traps.h> +#include <asm/mips-boards/generic.h> +#include <asm/fw/fw.h> + +extern char except_vec_nmi; +extern char except_vec_ejtag_debug; + +#ifdef CONFIG_SERIAL_8250_CONSOLE +static void __init console_config(void) +{ + char console_string[40]; + int baud = 0; + char parity = '\0', bits = '\0', flow = '\0'; + char *s; + + if ((strstr(fw_getcmdline(), "console=")) == NULL) { + s = fw_getenv("modetty0"); + if (s) { + while (*s >= '0' && *s <= '9') + baud = baud*10 + *s++ - '0'; + if (*s == ',') + s++; + if (*s) + parity = *s++; + if (*s == ',') + s++; + if (*s) + bits = *s++; + if (*s == ',') + s++; + if (*s == 'h') + flow = 'r'; + } + if (baud == 0) + baud = 38400; + if (parity != 'n' && parity != 'o' && parity != 'e') + parity = 'n'; + if (bits != '7' && bits != '8') + bits = '8'; + if (flow == '\0') + flow = 'r'; + sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, + parity, bits, flow); + strcat(fw_getcmdline(), console_string); + } +} +#endif + +static void __init mips_nmi_setup(void) +{ + void *base; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa80) : + (void *)(CAC_BASE + 0x380); +#ifdef CONFIG_CPU_MICROMIPS + /* + * Decrement the exception vector address by one for microMIPS. + */ + memcpy(base, (&except_vec_nmi - 1), 0x80); + + /* + * This is a hack. We do not know if the boot loader was built with + * microMIPS instructions or not. If it was not, the NMI exception + * code at 0x80000a80 will be taken in MIPS32 mode. The hand coded + * assembly below forces us into microMIPS mode if we are a pure + * microMIPS kernel. The assembly instructions are: + * + * 3C1A8000 lui k0,0x8000 + * 375A0381 ori k0,k0,0x381 + * 03400008 jr k0 + * 00000000 nop + * + * The mode switch occurs by jumping to the unaligned exception + * vector address at 0x80000381 which would have been 0x80000380 + * in MIPS32 mode. The jump to the unaligned address transitions + * us into microMIPS mode. + */ + if (!cpu_has_veic) { + void *base2 = (void *)(CAC_BASE + 0xa80); + *((unsigned int *)base2) = 0x3c1a8000; + *((unsigned int *)base2 + 1) = 0x375a0381; + *((unsigned int *)base2 + 2) = 0x03400008; + *((unsigned int *)base2 + 3) = 0x00000000; + flush_icache_range((unsigned long)base2, + (unsigned long)base2 + 0x10); + } +#else + memcpy(base, &except_vec_nmi, 0x80); +#endif + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + +static void __init mips_ejtag_setup(void) +{ + void *base; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa00) : + (void *)(CAC_BASE + 0x300); +#ifdef CONFIG_CPU_MICROMIPS + /* Deja vu... */ + memcpy(base, (&except_vec_ejtag_debug - 1), 0x80); + if (!cpu_has_veic) { + void *base2 = (void *)(CAC_BASE + 0xa00); + *((unsigned int *)base2) = 0x3c1a8000; + *((unsigned int *)base2 + 1) = 0x375a0301; + *((unsigned int *)base2 + 2) = 0x03400008; + *((unsigned int *)base2 + 3) = 0x00000000; + flush_icache_range((unsigned long)base2, + (unsigned long)base2 + 0x10); + } +#else + memcpy(base, &except_vec_ejtag_debug, 0x80); +#endif + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + +void __init prom_init(void) +{ + board_nmi_handler_setup = mips_nmi_setup; + board_ejtag_handler_setup = mips_ejtag_setup; + + fw_init_cmdline(); +#ifdef CONFIG_EARLY_PRINTK + if ((strstr(fw_getcmdline(), "console=ttyS0")) != NULL) + fw_init_early_console(0); + else if ((strstr(fw_getcmdline(), "console=ttyS1")) != NULL) + fw_init_early_console(1); +#endif +#ifdef CONFIG_SERIAL_8250_CONSOLE + if ((strstr(fw_getcmdline(), "console=")) == NULL) + strcat(fw_getcmdline(), " console=ttyS0,38400n8r"); + console_config(); +#endif +} + +void prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c new file mode 100644 index 00000000000..6a560ac03de --- /dev/null +++ b/arch/mips/mti-sead3/sead3-int.c @@ -0,0 +1,157 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <asm/gic.h> +#include <asm/irq_cpu.h> +#include <asm/setup.h> + +#include <asm/mips-boards/sead3int.h> + +#define SEAD_CONFIG_GIC_PRESENT_SHF 1 +#define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF) +#define SEAD_CONFIG_BASE 0x1b100110 +#define SEAD_CONFIG_SIZE 4 + +static unsigned long sead3_config_reg; + +/* + * This table defines the setup for each external GIC interrupt. It is + * indexed by interrupt number. + */ +#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK +static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = { + { 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, + { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, +}; + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; + int irq; + + irq = (fls(pending) - CAUSEB_IP - 1); + if (irq >= 0) + do_IRQ(MIPS_CPU_IRQ_BASE + irq); + else + spurious_interrupt(); +} + +void __init arch_init_irq(void) +{ + int i; + + if (!cpu_has_veic) { + mips_cpu_irq_init(); + + if (cpu_has_vint) { + /* install generic handler */ + for (i = 0; i < 8; i++) + set_vi_handler(i, plat_irq_dispatch); + } + } + + sead3_config_reg = (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE, + SEAD_CONFIG_SIZE); + gic_present = (REG32(sead3_config_reg) & SEAD_CONFIG_GIC_PRESENT_MSK) >> + SEAD_CONFIG_GIC_PRESENT_SHF; + pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); + pr_info("EIC: %s\n", + (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); + + if (gic_present) + gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, + ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); +} + +void gic_enable_interrupt(int irq_vec) +{ + unsigned int i, irq_source; + + /* enable all the interrupts associated with this vector */ + for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) { + irq_source = gic_shared_intr_map[irq_vec].intr_list[i]; + GIC_SET_INTR_MASK(irq_source); + } + /* enable all local interrupts associated with this vector */ + if (gic_shared_intr_map[irq_vec].local_intr_mask) { + GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); + GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), + gic_shared_intr_map[irq_vec].local_intr_mask); + } +} + +void gic_disable_interrupt(int irq_vec) +{ + unsigned int i, irq_source; + + /* disable all the interrupts associated with this vector */ + for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) { + irq_source = gic_shared_intr_map[irq_vec].intr_list[i]; + GIC_CLR_INTR_MASK(irq_source); + } + /* disable all local interrupts associated with this vector */ + if (gic_shared_intr_map[irq_vec].local_intr_mask) { + GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); + GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), + gic_shared_intr_map[irq_vec].local_intr_mask); + } +} + +void gic_irq_ack(struct irq_data *d) +{ + GIC_CLR_INTR_MASK(d->irq - gic_irq_base); +} + +void gic_finish_irq(struct irq_data *d) +{ + unsigned int irq = (d->irq - gic_irq_base); + unsigned int i, irq_source; + + /* Clear edge detectors. */ + for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) { + irq_source = gic_shared_intr_map[irq].intr_list[i]; + if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE) + GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq_source); + } + + /* Enable interrupts. */ + GIC_SET_INTR_MASK(irq); +} + +void __init gic_platform_init(int irqs, struct irq_chip *irq_controller) +{ + int i; + + /* + * For non-EIC mode, we want to setup the GIC in pass-through + * mode, as if the GIC didn't exist. Do not map any interrupts + * for an external interrupt controller. + */ + if (!cpu_has_veic) + return; + + for (i = gic_irq_base; i < (gic_irq_base + irqs); i++) + irq_set_chip_and_handler(i, irq_controller, handle_percpu_irq); +} diff --git a/arch/mips/mti-sead3/sead3-lcd.c b/arch/mips/mti-sead3/sead3-lcd.c new file mode 100644 index 00000000000..10b10ed21f7 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-lcd.c @@ -0,0 +1,43 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/platform_device.h> + +static struct resource __initdata sead3_lcd_resource = { + .start = 0x1f000400, + .end = 0x1f00041f, + .flags = IORESOURCE_MEM, +}; + +static __init int sead3_lcd_add(void) +{ + struct platform_device *pdev; + int retval; + + /* SEAD-3 and Cobalt platforms use same display type. */ + pdev = platform_device_alloc("cobalt-lcd", -1); + if (!pdev) + return -ENOMEM; + + retval = platform_device_add_resources(pdev, &sead3_lcd_resource, 1); + if (retval) + goto err_free_device; + + retval = platform_device_add(pdev); + if (retval) + goto err_free_device; + + return 0; + +err_free_device: + platform_device_put(pdev); + + return retval; +} + +device_initcall(sead3_lcd_add); diff --git a/arch/mips/mti-sead3/sead3-leds.c b/arch/mips/mti-sead3/sead3-leds.c new file mode 100644 index 00000000000..20102a6d414 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-leds.c @@ -0,0 +1,83 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/leds.h> +#include <linux/platform_device.h> + +#define LEDFLAGS(bits, shift) \ + ((bits << 8) | (shift << 8)) + +#define LEDBITS(id, shift, bits) \ + .name = id #shift, \ + .flags = LEDFLAGS(bits, shift) + +struct led_info led_data_info[] = { + { LEDBITS("bit", 0, 1) }, + { LEDBITS("bit", 1, 1) }, + { LEDBITS("bit", 2, 1) }, + { LEDBITS("bit", 3, 1) }, + { LEDBITS("bit", 4, 1) }, + { LEDBITS("bit", 5, 1) }, + { LEDBITS("bit", 6, 1) }, + { LEDBITS("bit", 7, 1) }, + { LEDBITS("all", 0, 8) }, +}; + +static struct led_platform_data led_data = { + .num_leds = ARRAY_SIZE(led_data_info), + .leds = led_data_info +}; + +static struct resource pled_resources[] = { + { + .start = 0x1f000210, + .end = 0x1f000217, + .flags = IORESOURCE_MEM + } +}; + +static struct platform_device pled_device = { + .name = "sead3::pled", + .id = 0, + .dev = { + .platform_data = &led_data, + }, + .num_resources = ARRAY_SIZE(pled_resources), + .resource = pled_resources +}; + + +static struct resource fled_resources[] = { + { + .start = 0x1f000218, + .end = 0x1f00021f, + .flags = IORESOURCE_MEM + } +}; + +static struct platform_device fled_device = { + .name = "sead3::fled", + .id = 0, + .dev = { + .platform_data = &led_data, + }, + .num_resources = ARRAY_SIZE(fled_resources), + .resource = fled_resources +}; + +static int __init led_init(void) +{ + platform_device_register(&pled_device); + return platform_device_register(&fled_device); +} + +module_init(led_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LED probe driver for SEAD-3"); diff --git a/arch/mips/mti-sead3/sead3-mtd.c b/arch/mips/mti-sead3/sead3-mtd.c new file mode 100644 index 00000000000..f9c890d7267 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-mtd.c @@ -0,0 +1,53 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> + +static struct mtd_partition sead3_mtd_partitions[] = { + { + .name = "User FS", + .offset = 0x00000000, + .size = 0x01fc0000, + }, { + .name = "Board Config", + .offset = 0x01fc0000, + .size = 0x00040000, + .mask_flags = MTD_WRITEABLE + }, +}; + +static struct physmap_flash_data sead3_flash_data = { + .width = 4, + .nr_parts = ARRAY_SIZE(sead3_mtd_partitions), + .parts = sead3_mtd_partitions +}; + +static struct resource sead3_flash_resource = { + .start = 0x1c000000, + .end = 0x1dffffff, + .flags = IORESOURCE_MEM +}; + +static struct platform_device sead3_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &sead3_flash_data, + }, + .num_resources = 1, + .resource = &sead3_flash_resource, +}; + +static int __init sead3_mtd_init(void) +{ + platform_device_register(&sead3_flash); + + return 0; +} +device_initcall(sead3_mtd_init); diff --git a/arch/mips/mti-sead3/sead3-net.c b/arch/mips/mti-sead3/sead3-net.c new file mode 100644 index 00000000000..dd11e7eb771 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-net.c @@ -0,0 +1,51 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> + +static struct smsc911x_platform_config sead3_smsc911x_data = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +struct resource sead3_net_resourcess[] = { + { + .start = 0x1f010000, + .end = 0x1f01ffff, + .flags = IORESOURCE_MEM + }, + { + .start = MIPS_CPU_IRQ_BASE + 6, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device sead3_net_device = { + .name = "smsc911x", + .id = 0, + .dev = { + .platform_data = &sead3_smsc911x_data, + }, + .num_resources = ARRAY_SIZE(sead3_net_resourcess), + .resource = sead3_net_resourcess +}; + +static int __init sead3_net_init(void) +{ + return platform_device_register(&sead3_net_device); +} + +module_init(sead3_net_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Network probe driver for SEAD-3"); diff --git a/arch/mips/mti-sead3/sead3-pic32-bus.c b/arch/mips/mti-sead3/sead3-pic32-bus.c new file mode 100644 index 00000000000..3b12aa5a7c8 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-pic32-bus.c @@ -0,0 +1,102 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/errno.h> + +#define PIC32_NULL 0x00 +#define PIC32_RD 0x01 +#define PIC32_SYSRD 0x02 +#define PIC32_WR 0x10 +#define PIC32_SYSWR 0x20 +#define PIC32_IRQ_CLR 0x40 +#define PIC32_STATUS 0x80 + +#define DELAY() udelay(100) /* FIXME: needed? */ + +/* spinlock to ensure atomic access to PIC32 */ +static DEFINE_SPINLOCK(pic32_bus_lock); + +/* FIXME: io_remap these */ +static void __iomem *bus_xfer = (void __iomem *)0xbf000600; +static void __iomem *bus_status = (void __iomem *)0xbf000060; + +static inline unsigned int ioready(void) +{ + return readl(bus_status) & 1; +} + +static inline void wait_ioready(void) +{ + do { } while (!ioready()); +} + +static inline void wait_ioclear(void) +{ + do { } while (ioready()); +} + +static inline void check_ioclear(void) +{ + if (ioready()) { + pr_debug("ioclear: initially busy\n"); + do { + (void) readl(bus_xfer); + DELAY(); + } while (ioready()); + pr_debug("ioclear: cleared busy\n"); + } +} + +u32 pic32_bus_readl(u32 reg) +{ + unsigned long flags; + u32 status, val; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + + writel((PIC32_RD << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + DELAY(); + val = readl(bus_xfer); + wait_ioclear(); + + pr_debug("pic32_bus_readl: *%x -> %x (status=%x)\n", reg, val, status); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); + + return val; +} + +void pic32_bus_writel(u32 val, u32 reg) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + + writel((PIC32_WR << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + writel(val, bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + wait_ioclear(); + + pr_debug("pic32_bus_writel: *%x <- %x (status=%x)\n", reg, val, status); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); +} diff --git a/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c b/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c new file mode 100644 index 00000000000..80fe194cfa5 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-pic32-i2c-drv.c @@ -0,0 +1,423 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/slab.h> + +#define PIC32_I2CxCON 0x0000 +#define PIC32_I2CxCONCLR 0x0004 +#define PIC32_I2CxCONSET 0x0008 +#define PIC32_I2CxCONINV 0x000C +#define I2CCON_ON (1<<15) +#define I2CCON_FRZ (1<<14) +#define I2CCON_SIDL (1<<13) +#define I2CCON_SCLREL (1<<12) +#define I2CCON_STRICT (1<<11) +#define I2CCON_A10M (1<<10) +#define I2CCON_DISSLW (1<<9) +#define I2CCON_SMEN (1<<8) +#define I2CCON_GCEN (1<<7) +#define I2CCON_STREN (1<<6) +#define I2CCON_ACKDT (1<<5) +#define I2CCON_ACKEN (1<<4) +#define I2CCON_RCEN (1<<3) +#define I2CCON_PEN (1<<2) +#define I2CCON_RSEN (1<<1) +#define I2CCON_SEN (1<<0) + +#define PIC32_I2CxSTAT 0x0010 +#define PIC32_I2CxSTATCLR 0x0014 +#define PIC32_I2CxSTATSET 0x0018 +#define PIC32_I2CxSTATINV 0x001C +#define I2CSTAT_ACKSTAT (1<<15) +#define I2CSTAT_TRSTAT (1<<14) +#define I2CSTAT_BCL (1<<10) +#define I2CSTAT_GCSTAT (1<<9) +#define I2CSTAT_ADD10 (1<<8) +#define I2CSTAT_IWCOL (1<<7) +#define I2CSTAT_I2COV (1<<6) +#define I2CSTAT_DA (1<<5) +#define I2CSTAT_P (1<<4) +#define I2CSTAT_S (1<<3) +#define I2CSTAT_RW (1<<2) +#define I2CSTAT_RBF (1<<1) +#define I2CSTAT_TBF (1<<0) + +#define PIC32_I2CxADD 0x0020 +#define PIC32_I2CxADDCLR 0x0024 +#define PIC32_I2CxADDSET 0x0028 +#define PIC32_I2CxADDINV 0x002C +#define PIC32_I2CxMSK 0x0030 +#define PIC32_I2CxMSKCLR 0x0034 +#define PIC32_I2CxMSKSET 0x0038 +#define PIC32_I2CxMSKINV 0x003C +#define PIC32_I2CxBRG 0x0040 +#define PIC32_I2CxBRGCLR 0x0044 +#define PIC32_I2CxBRGSET 0x0048 +#define PIC32_I2CxBRGINV 0x004C +#define PIC32_I2CxTRN 0x0050 +#define PIC32_I2CxTRNCLR 0x0054 +#define PIC32_I2CxTRNSET 0x0058 +#define PIC32_I2CxTRNINV 0x005C +#define PIC32_I2CxRCV 0x0060 + +struct i2c_platform_data { + u32 base; + struct i2c_adapter adap; + u32 xfer_timeout; + u32 ack_timeout; + u32 ctl_timeout; +}; + +extern u32 pic32_bus_readl(u32 reg); +extern void pic32_bus_writel(u32 val, u32 reg); + +static inline void +StartI2C(struct i2c_platform_data *adap) +{ + pr_debug("StartI2C\n"); + pic32_bus_writel(I2CCON_SEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void +StopI2C(struct i2c_platform_data *adap) +{ + pr_debug("StopI2C\n"); + pic32_bus_writel(I2CCON_PEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void +AckI2C(struct i2c_platform_data *adap) +{ + pr_debug("AckI2C\n"); + pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONCLR); + pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); +} + +static inline void +NotAckI2C(struct i2c_platform_data *adap) +{ + pr_debug("NakI2C\n"); + pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONSET); + pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); +} + +static inline int +IdleI2C(struct i2c_platform_data *adap) +{ + int i; + + pr_debug("IdleI2C\n"); + for (i = 0; i < adap->ctl_timeout; i++) { + if (((pic32_bus_readl(adap->base + PIC32_I2CxCON) & + (I2CCON_ACKEN | I2CCON_RCEN | I2CCON_PEN | I2CCON_RSEN | + I2CCON_SEN)) == 0) && + ((pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + (I2CSTAT_TRSTAT)) == 0)) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static inline u32 +MasterWriteI2C(struct i2c_platform_data *adap, u32 byte) +{ + pr_debug("MasterWriteI2C\n"); + + pic32_bus_writel(byte, adap->base + PIC32_I2CxTRN); + + return pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_IWCOL; +} + +static inline u32 +MasterReadI2C(struct i2c_platform_data *adap) +{ + pr_debug("MasterReadI2C\n"); + + pic32_bus_writel(I2CCON_RCEN, adap->base + PIC32_I2CxCONSET); + + while (pic32_bus_readl(adap->base + PIC32_I2CxCON) & I2CCON_RCEN) + ; + + pic32_bus_writel(I2CSTAT_I2COV, adap->base + PIC32_I2CxSTATCLR); + + return pic32_bus_readl(adap->base + PIC32_I2CxRCV); +} + +static int +do_address(struct i2c_platform_data *adap, unsigned int addr, int rd) +{ + pr_debug("doaddress\n"); + + IdleI2C(adap); + StartI2C(adap); + IdleI2C(adap); + + addr <<= 1; + if (rd) + addr |= 1; + + if (MasterWriteI2C(adap, addr)) + return -EIO; + IdleI2C(adap); + if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_ACKSTAT) + return -EIO; + return 0; +} + +static int +i2c_read(struct i2c_platform_data *adap, unsigned char *buf, + unsigned int len) +{ + int i; + u32 data; + + pr_debug("i2c_read\n"); + + i = 0; + while (i < len) { + data = MasterReadI2C(adap); + buf[i++] = data; + if (i < len) + AckI2C(adap); + else + NotAckI2C(adap); + } + + StopI2C(adap); + IdleI2C(adap); + return 0; +} + +static int +i2c_write(struct i2c_platform_data *adap, unsigned char *buf, + unsigned int len) +{ + int i; + u32 data; + + pr_debug("i2c_write\n"); + + i = 0; + while (i < len) { + data = buf[i]; + if (MasterWriteI2C(adap, data)) + return -EIO; + IdleI2C(adap); + if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & + I2CSTAT_ACKSTAT) + return -EIO; + i++; + } + + StopI2C(adap); + IdleI2C(adap); + return 0; +} + +static int +platform_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct i2c_platform_data *adap = i2c_adap->algo_data; + struct i2c_msg *p; + int i, err = 0; + + pr_debug("platform_xfer\n"); + for (i = 0; i < num; i++) { +#define __BUFSIZE 80 + int ii; + static char buf[__BUFSIZE]; + char *b = buf; + + p = &msgs[i]; + b += sprintf(buf, " [%d bytes]", p->len); + if ((p->flags & I2C_M_RD) == 0) { + for (ii = 0; ii < p->len; ii++) { + if (b < &buf[__BUFSIZE-4]) { + b += sprintf(b, " %02x", p->buf[ii]); + } else { + strcat(b, "..."); + break; + } + } + } + pr_debug("xfer%d: DevAddr: %04x Op:%s Data:%s\n", i, p->addr, + (p->flags & I2C_M_RD) ? "Rd" : "Wr", buf); + } + + + for (i = 0; !err && i < num; i++) { + p = &msgs[i]; + err = do_address(adap, p->addr, p->flags & I2C_M_RD); + if (err || !p->len) + continue; + if (p->flags & I2C_M_RD) + err = i2c_read(adap, p->buf, p->len); + else + err = i2c_write(adap, p->buf, p->len); + } + + /* Return the number of messages processed, or the error code. */ + if (err == 0) + err = num; + + return err; +} + +static u32 +platform_func(struct i2c_adapter *adap) +{ + pr_debug("platform_algo\n"); + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm platform_algo = { + .master_xfer = platform_xfer, + .functionality = platform_func, +}; + +static void i2c_platform_setup(struct i2c_platform_data *priv) +{ + pr_debug("i2c_platform_setup\n"); + + pic32_bus_writel(500, priv->base + PIC32_I2CxBRG); + pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONCLR); + pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONSET); + pic32_bus_writel((I2CSTAT_BCL | I2CSTAT_IWCOL), + (priv->base + PIC32_I2CxSTATCLR)); +} + +static void i2c_platform_disable(struct i2c_platform_data *priv) +{ + pr_debug("i2c_platform_disable\n"); +} + +static int i2c_platform_probe(struct platform_device *pdev) +{ + struct i2c_platform_data *priv; + struct resource *r; + int ret; + + pr_debug("i2c_platform_probe\n"); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_platform_data), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* FIXME: need to allocate resource in PIC32 space */ +#if 0 + priv->base = bus_request_region(r->start, resource_size(r), + pdev->name); +#else + priv->base = r->start; +#endif + if (!priv->base) + return -EBUSY; + + priv->xfer_timeout = 200; + priv->ack_timeout = 200; + priv->ctl_timeout = 200; + + priv->adap.nr = pdev->id; + priv->adap.algo = &platform_algo; + priv->adap.algo_data = priv; + priv->adap.dev.parent = &pdev->dev; + strlcpy(priv->adap.name, "PIC32 I2C", sizeof(priv->adap.name)); + + i2c_platform_setup(priv); + + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret) { + i2c_platform_disable(priv); + return ret; + } + + platform_set_drvdata(pdev, priv); + return 0; +} + +static int i2c_platform_remove(struct platform_device *pdev) +{ + struct i2c_platform_data *priv = platform_get_drvdata(pdev); + + pr_debug("i2c_platform_remove\n"); + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&priv->adap); + i2c_platform_disable(priv); + return 0; +} + +#ifdef CONFIG_PM +static int +i2c_platform_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct i2c_platform_data *priv = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "i2c_platform_disable\n"); + i2c_platform_disable(priv); + + return 0; +} + +static int +i2c_platform_resume(struct platform_device *pdev) +{ + struct i2c_platform_data *priv = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "i2c_platform_setup\n"); + i2c_platform_setup(priv); + + return 0; +} +#else +#define i2c_platform_suspend NULL +#define i2c_platform_resume NULL +#endif + +static struct platform_driver i2c_platform_driver = { + .driver = { + .name = "i2c_pic32", + .owner = THIS_MODULE, + }, + .probe = i2c_platform_probe, + .remove = i2c_platform_remove, + .suspend = i2c_platform_suspend, + .resume = i2c_platform_resume, +}; + +static int __init +i2c_platform_init(void) +{ + pr_debug("i2c_platform_init\n"); + return platform_driver_register(&i2c_platform_driver); +} + +static void __exit +i2c_platform_exit(void) +{ + pr_debug("i2c_platform_exit\n"); + platform_driver_unregister(&i2c_platform_driver); +} + +MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC."); +MODULE_DESCRIPTION("PIC32 I2C driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_platform_init); +module_exit(i2c_platform_exit); diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c new file mode 100644 index 00000000000..6c3b33dbed1 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -0,0 +1,45 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/serial_8250.h> + +#define UART(base, int) \ +{ \ + .mapbase = base, \ + .irq = int, \ + .uartclk = 14745600, \ + .iotype = UPIO_MEM32, \ + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \ + .regshift = 2, \ +} + +static struct plat_serial8250_port uart8250_data[] = { + UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4), /* ttyS0 = USB */ + UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4), /* ttyS1 = RS232 */ + { }, +}; + +static struct platform_device uart8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM2, + .dev = { + .platform_data = uart8250_data, + }, +}; + +static int __init uart8250_init(void) +{ + return platform_device_register(&uart8250_device); +} + +module_init(uart8250_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("8250 UART probe driver for SEAD3"); diff --git a/arch/mips/mti-sead3/sead3-reset.c b/arch/mips/mti-sead3/sead3-reset.c new file mode 100644 index 00000000000..e6fb24414a7 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-reset.c @@ -0,0 +1,40 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/io.h> +#include <linux/pm.h> + +#include <asm/reboot.h> + +#define SOFTRES_REG 0x1f000050 +#define GORESET 0x4d + +static void mips_machine_restart(char *command) +{ + unsigned int __iomem *softres_reg = + ioremap(SOFTRES_REG, sizeof(unsigned int)); + + __raw_writel(GORESET, softres_reg); +} + +static void mips_machine_halt(void) +{ + unsigned int __iomem *softres_reg = + ioremap(SOFTRES_REG, sizeof(unsigned int)); + + __raw_writel(GORESET, softres_reg); +} + +static int __init mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; + pm_power_off = mips_machine_halt; + + return 0; +} +arch_initcall(mips_reboot_setup); diff --git a/arch/mips/mti-sead3/sead3-serial.c b/arch/mips/mti-sead3/sead3-serial.c new file mode 100644 index 00000000000..bc52705bbee --- /dev/null +++ b/arch/mips/mti-sead3/sead3-serial.c @@ -0,0 +1,45 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/serial_8250.h> + +#define UART(base, int) \ +{ \ + .mapbase = base, \ + .irq = int, \ + .uartclk = 14745600, \ + .iotype = UPIO_MEM32, \ + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \ + .regshift = 2, \ +} + +static struct plat_serial8250_port uart8250_data[] = { + UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4), /* ttyS0 = USB */ + UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4), /* ttyS1 = RS232 */ + { }, +}; + +static struct platform_device uart8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = uart8250_data, + }, +}; + +static int __init uart8250_init(void) +{ + return platform_device_register(&uart8250_device); +} + +module_init(uart8250_init); + +MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("8250 UART probe driver for the SEAD-3 platform"); diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c new file mode 100644 index 00000000000..e43f4801a24 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -0,0 +1,111 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + */ +#include <linux/init.h> +#include <linux/libfdt.h> +#include <linux/of_platform.h> +#include <linux/of_fdt.h> + +#include <asm/prom.h> +#include <asm/fw/fw.h> + +#include <asm/mips-boards/generic.h> + +const char *get_system_type(void) +{ + return "MIPS SEAD3"; +} + +static uint32_t get_memsize_from_cmdline(void) +{ + int memsize = 0; + char *p = arcs_cmdline; + char *s = "memsize="; + + p = strstr(p, s); + if (p) { + p += strlen(s); + memsize = memparse(p, NULL); + } + + return memsize; +} + +static uint32_t get_memsize_from_env(void) +{ + int memsize = 0; + char *p; + + p = fw_getenv("memsize"); + if (p) + memsize = memparse(p, NULL); + + return memsize; +} + +static uint32_t get_memsize(void) +{ + uint32_t memsize; + + memsize = get_memsize_from_cmdline(); + if (memsize) + return memsize; + + return get_memsize_from_env(); +} + +static void __init parse_memsize_param(void) +{ + int offset; + const uint64_t *prop_value; + int prop_len; + uint32_t memsize = get_memsize(); + + if (!memsize) + return; + + offset = fdt_path_offset(__dtb_start, "/memory"); + if (offset > 0) { + uint64_t new_value; + /* + * reg contains 2 32-bits BE values, offset and size. We just + * want to replace the size value without affecting the offset + */ + prop_value = fdt_getprop(__dtb_start, offset, "reg", &prop_len); + new_value = be64_to_cpu(*prop_value); + new_value = (new_value & ~0xffffffffllu) | memsize; + fdt_setprop_inplace_u64(__dtb_start, offset, "reg", new_value); + } +} + +void __init plat_mem_setup(void) +{ + /* allow command line/bootloader env to override memory size in DT */ + parse_memsize_param(); + + /* + * Load the builtin devicetree. This causes the chosen node to be + * parsed resulting in our memory appearing + */ + __dt_setup_arch(__dtb_start); +} + +void __init device_tree_init(void) +{ + if (!initial_boot_params) + return; + + unflatten_and_copy_device_tree(); +} + +static int __init customize_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; +} +arch_initcall(customize_machine); diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c new file mode 100644 index 00000000000..678d03d53c6 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-time.c @@ -0,0 +1,113 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> + +#include <asm/cpu.h> +#include <asm/setup.h> +#include <asm/time.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> + +static int mips_cpu_timer_irq; +static int mips_cpu_perf_irq; + +static void mips_timer_dispatch(void) +{ + do_IRQ(mips_cpu_timer_irq); +} + +static void mips_perf_dispatch(void) +{ + do_IRQ(mips_cpu_perf_irq); +} + +static void __iomem *status_reg = (void __iomem *)0xbf000410; + +/* + * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect. + */ +static unsigned int __init estimate_cpu_frequency(void) +{ + unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); + unsigned int tick = 0; + unsigned int freq; + unsigned int orig; + unsigned long flags; + + local_irq_save(flags); + + orig = readl(status_reg) & 0x2; /* get original sample */ + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + + write_c0_count(0); + + /* wait 1 second (the sampling clock transitions every 10ms) */ + while (tick < 100) { + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + tick++; + } + + freq = read_c0_count(); + + local_irq_restore(flags); + + mips_hpt_frequency = freq; + + /* Adjust for processor */ + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + + freq += 5000; /* rounding */ + freq -= freq%10000; + + return freq ; +} + +void read_persistent_clock(struct timespec *ts) +{ + ts->tv_sec = 0; + ts->tv_nsec = 0; +} + +static void __init plat_perf_setup(void) +{ + if (cp0_perfcount_irq >= 0) { + if (cpu_has_vint) + set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + } +} + +unsigned int get_c0_compare_int(void) +{ + if (cpu_has_vint) + set_vi_handler(cp0_compare_irq, mips_timer_dispatch); + mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; + return mips_cpu_timer_irq; +} + +void __init plat_time_init(void) +{ + unsigned int est_freq; + + est_freq = estimate_cpu_frequency(); + + pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), + (est_freq % 1000000) * 100 / 1000000); + + mips_scroll_message(); + + plat_perf_setup(); +} diff --git a/arch/mips/mti-sead3/sead3.dts b/arch/mips/mti-sead3/sead3.dts new file mode 100644 index 00000000000..e4b317d414f --- /dev/null +++ b/arch/mips/mti-sead3/sead3.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/memreserve/ 0x00000000 0x00001000; // reserved +/memreserve/ 0x00001000 0x000ef000; // ROM data +/memreserve/ 0x000f0000 0x004cc000; // reserved + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mti,sead-3"; + + cpus { + cpu@0 { + compatible = "mti,mips14KEc", "mti,mips14Kc"; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; +}; |
