MIPS: Add core files for MIPS SEAD-3 development platform.

More information about the SEAD-3 platform can be found at
<http://www.mips.com/products/development-kits/mips-sead-3/>
on MTI's site. Currently, the M14K family of cores is what
the SEAD-3 is utilised with.

Signed-off-by: Douglas Leung <douglas@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Steven J. Hill <sjhill@mips.com>
This commit is contained in:
Steven J. Hill 2012-05-30 21:02:49 +00:00
Родитель 006a851b10
Коммит 3070033a16
29 изменённых файлов: 2445 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,72 @@
/*
* 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) 2003, 2004 Chris Dearman
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H
/*
* CPU feature overrides for MIPS boards
*/
#ifdef CONFIG_CPU_MIPS32
#define cpu_has_tlb 1
#define cpu_has_4kex 1
#define cpu_has_4k_cache 1
/* #define cpu_has_fpu ? */
/* #define cpu_has_32fpr ? */
#define cpu_has_counter 1
/* #define cpu_has_watch ? */
#define cpu_has_divec 1
#define cpu_has_vce 0
/* #define cpu_has_cache_cdex_p ? */
/* #define cpu_has_cache_cdex_s ? */
/* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */
#ifdef CONFIG_CPU_HAS_LLSC
#define cpu_has_llsc 1
#else
#define cpu_has_llsc 0
#endif
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
/* #define cpu_has_inclusive_pcaches ? */
#define cpu_icache_snoops_remote_store 1
#endif
#ifdef CONFIG_CPU_MIPS64
#define cpu_has_tlb 1
#define cpu_has_4kex 1
#define cpu_has_4k_cache 1
/* #define cpu_has_fpu ? */
/* #define cpu_has_32fpr ? */
#define cpu_has_counter 1
/* #define cpu_has_watch ? */
#define cpu_has_divec 1
#define cpu_has_vce 0
/* #define cpu_has_cache_cdex_p ? */
/* #define cpu_has_cache_cdex_s ? */
/* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */
#define cpu_has_llsc 1
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
#define cpu_has_nofpuex 0
/* #define cpu_has_64bits ? */
/* #define cpu_has_64bit_zero_reg ? */
/* #define cpu_has_inclusive_pcaches ? */
#define cpu_icache_snoops_remote_store 1
#endif
#endif /* __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H */

Просмотреть файл

@ -0,0 +1,9 @@
#ifndef __ASM_MACH_MIPS_IRQ_H
#define __ASM_MACH_MIPS_IRQ_H
#define NR_IRQS 256
#include_next <irq.h>
#endif /* __ASM_MACH_MIPS_IRQ_H */

Просмотреть файл

@ -0,0 +1,52 @@
/*
* 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.
*
* Chris Dearman (chris@mips.com)
* Copyright (C) 2007 Mips Technologies, Inc.
*/
#ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
#define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
.macro kernel_entry_setup
#ifdef CONFIG_MIPS_MT_SMTC
mfc0 t0, CP0_CONFIG
bgez t0, 9f
mfc0 t0, CP0_CONFIG, 1
bgez t0, 9f
mfc0 t0, CP0_CONFIG, 2
bgez t0, 9f
mfc0 t0, CP0_CONFIG, 3
and t0, 1<<2
bnez t0, 0f
9 :
/* Assume we came from YAMON... */
PTR_LA v0, 0x9fc00534 /* YAMON print */
lw v0, (v0)
move a0, zero
PTR_LA a1, nonmt_processor
jal v0
PTR_LA v0, 0x9fc00520 /* YAMON exit */
lw v0, (v0)
li a0, 1
jal v0
1 : b 1b
__INITDATA
nonmt_processor :
.asciz "SMTC kernel requires the MT ASE to run\n"
__FINIT
0 :
#endif
.endm
/*
* Do SMP slave processor setup necessary before we can safely execute C code.
*/
.macro smp_slave_setup
.endm
#endif /* __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H */

Просмотреть файл

@ -0,0 +1,25 @@
/*
* 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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
*/
#ifndef __ASM_MIPS_MACH_MIPS_WAR_H
#define __ASM_MIPS_MACH_MIPS_WAR_H
#define R4600_V1_INDEX_ICACHEOP_WAR 0
#define R4600_V1_HIT_CACHEOP_WAR 0
#define R4600_V2_HIT_CACHEOP_WAR 0
#define R5432_CP0_INTERRUPT_WAR 0
#define BCM1250_M3_WAR 0
#define SIBYTE_1956_WAR 0
#define MIPS4K_ICACHE_REFILL_WAR 1
#define MIPS_CACHE_SYNC_WAR 1
#define TX49XX_ICACHE_INDEX_INV_WAR 0
#define RM9000_CDEX_SMP_WAR 0
#define ICACHE_REFILLS_WORKAROUND_WAR 1
#define R10000_LLSC_WAR 0
#define MIPS34K_MISSED_ITLB_WAR 0
#endif /* __ASM_MIPS_MACH_MIPS_WAR_H */

Просмотреть файл

@ -0,0 +1,19 @@
/*
* 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) 2000,2012 MIPS Technologies, Inc. All rights reserved.
* Douglas Leung <douglas@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/
#ifndef _MIPS_SEAD3INT_H
#define _MIPS_SEAD3INT_H
/* SEAD-3 GIC address space definitions. */
#define GIC_BASE_ADDR 0x1b1c0000
#define GIC_ADDRSPACE_SZ (128 * 1024)
#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 0)
#endif /* !(_MIPS_SEAD3INT_H) */

Просмотреть файл

@ -0,0 +1,19 @@
#
# 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>
#
obj-y := sead3-lcd.o sead3-cmdline.o \
sead3-display.o sead3-init.o sead3-int.o \
sead3-mtd.o sead3-net.o \
sead3-memory.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

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,128 @@
/*
* 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,
};
static struct led_classdev sead3_fled = {
.name = "sead3::fled",
.brightness_set = sead3_fled_set,
};
#ifdef CONFIG_PM
static int sead3_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&sead3_pled);
led_classdev_suspend(&sead3_fled);
return 0;
}
static int sead3_led_resume(struct platform_device *dev)
{
led_classdev_resume(&sead3_pled);
led_classdev_resume(&sead3_fled);
return 0;
}
#else
#define sead3_led_suspend NULL
#define sead3_led_resume NULL
#endif
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,
.suspend = sead3_led_suspend,
.resume = sead3_led_resume,
.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");

Просмотреть файл

@ -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/string.h>
#include <asm/bootinfo.h>
extern int prom_argc;
extern int *_prom_argv;
/*
* YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
* This macro take care of sign extension.
*/
#define prom_argv(index) ((char *)(long)_prom_argv[(index)])
char * __init prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while (actr < prom_argc) {
strcpy(cp, prom_argv(actr));
cp += strlen(prom_argv(actr));
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) {
/* get rid of trailing space */
--cp;
*cp = '\0';
}
}

Просмотреть файл

@ -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 prom_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;
}

Просмотреть файл

@ -0,0 +1,78 @@
/*
* 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>
#include <asm/mips-boards/prom.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);
}

Просмотреть файл

@ -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");

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 __devinit 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 __devexit 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 = __devexit_p(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");

Просмотреть файл

@ -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");

Просмотреть файл

@ -0,0 +1,91 @@
/*
* 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/mips-boards/prom.h>
extern void prom_init_early_console(char port);
extern char except_vec_nmi;
extern char except_vec_ejtag_debug;
int prom_argc;
int *_prom_argv, *_prom_envp;
#define prom_envp(index) ((char *)(long)_prom_envp[(index)])
char *prom_getenv(char *envname)
{
/*
* Return a pointer to the given environment variable.
* In 64-bit mode: we're using 64-bit pointers, but all pointers
* in the PROM structures are only 32-bit, so we need some
* workarounds, if we are running in 64-bit mode.
*/
int i, index = 0;
i = strlen(envname);
while (prom_envp(index)) {
if (strncmp(envname, prom_envp(index), i) == 0)
return prom_envp(index+1);
index += 2;
}
return NULL;
}
static void __init mips_nmi_setup(void)
{
void *base;
base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa80) :
(void *)(CAC_BASE + 0x380);
memcpy(base, &except_vec_nmi, 0x80);
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);
memcpy(base, &except_vec_ejtag_debug, 0x80);
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
void __init prom_init(void)
{
prom_argc = fw_arg0;
_prom_argv = (int *) fw_arg1;
_prom_envp = (int *) fw_arg2;
board_nmi_handler_setup = mips_nmi_setup;
board_ejtag_handler_setup = mips_ejtag_setup;
prom_init_cmdline();
prom_meminit();
#ifdef CONFIG_EARLY_PRINTK
if ((strstr(prom_getcmdline(), "console=ttyS0")) != NULL)
prom_init_early_console(0);
else if ((strstr(prom_getcmdline(), "console=ttyS1")) != NULL)
prom_init_early_console(1);
#endif
#ifdef CONFIG_SERIAL_8250_CONSOLE
if ((strstr(prom_getcmdline(), "console=")) == NULL)
strcat(prom_getcmdline(), " console=ttyS0,38400n8r");
#endif
}

Просмотреть файл

@ -0,0 +1,158 @@
/*
* 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
int gic_present;
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);
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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");

Просмотреть файл

@ -0,0 +1,138 @@
/*
* 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/bootmem.h>
#include <asm/bootinfo.h>
#include <asm/sections.h>
#include <asm/mips-boards/prom.h>
enum yamon_memtypes {
yamon_dontuse,
yamon_prom,
yamon_free,
};
static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
struct prom_pmemblock * __init prom_getmdesc(void)
{
char *memsize_str, *ptr;
unsigned int memsize;
static char cmdline[COMMAND_LINE_SIZE] __initdata;
long val;
int tmp;
/* otherwise look in the environment */
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
pr_warn("memsize not set in boot prom, set to default 32Mb\n");
physical_memsize = 0x02000000;
} else {
tmp = kstrtol(memsize_str, 0, &val);
physical_memsize = (unsigned long)val;
}
#ifdef CONFIG_CPU_BIG_ENDIAN
/* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last
word of physical memory */
physical_memsize -= PAGE_SIZE;
#endif
/* Check the command line for a memsize directive that overrides
the physical/default amount */
strcpy(cmdline, arcs_cmdline);
ptr = strstr(cmdline, "memsize=");
if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
ptr = strstr(ptr, " memsize=");
if (ptr)
memsize = memparse(ptr + 8, &ptr);
else
memsize = physical_memsize;
memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = yamon_dontuse;
mdesc[0].base = 0x00000000;
mdesc[0].size = 0x00001000;
mdesc[1].type = yamon_prom;
mdesc[1].base = 0x00001000;
mdesc[1].size = 0x000ef000;
/*
* The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
* south bridge and PCI access always forwarded to the ISA Bus and
* BIOSCS# is always generated.
* This mean that this area can't be used as DMA memory for PCI
* devices.
*/
mdesc[2].type = yamon_dontuse;
mdesc[2].base = 0x000f0000;
mdesc[2].size = 0x00010000;
mdesc[3].type = yamon_dontuse;
mdesc[3].base = 0x00100000;
mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
mdesc[3].base;
mdesc[4].type = yamon_free;
mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[4].size = memsize - mdesc[4].base;
return &mdesc[0];
}
static int __init prom_memtype_classify(unsigned int type)
{
switch (type) {
case yamon_free:
return BOOT_MEM_RAM;
case yamon_prom:
return BOOT_MEM_ROM_DATA;
default:
return BOOT_MEM_RESERVED;
}
}
void __init prom_meminit(void)
{
struct prom_pmemblock *p;
p = prom_getmdesc();
while (p->size) {
long type;
unsigned long base, size;
type = prom_memtype_classify(p->type);
base = p->base;
size = p->size;
add_memory_region(base, size, type);
p++;
}
}
void __init prom_free_prom_memory(void)
{
unsigned long addr;
int i;
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
addr = boot_mem_map.map[i].addr;
free_init_pages("prom memory",
addr, addr + boot_mem_map.map[i].size);
}
}

Просмотреть файл

@ -0,0 +1,54 @@
/*
* 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;
}
module_init(sead3_mtd_init)

Просмотреть файл

@ -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");

Просмотреть файл

@ -0,0 +1,103 @@
/*
* 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/init.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);
}

Просмотреть файл

@ -0,0 +1,435 @@
/*
* 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 __devinit
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) {
ret = -ENODEV;
goto out;
}
priv = kzalloc(sizeof(struct i2c_platform_data), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out;
}
/* 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) {
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 = &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 == 0) {
platform_set_drvdata(pdev, priv);
return 0;
}
i2c_platform_disable(priv);
out_mem:
kfree(priv);
out:
return ret;
}
static int __devexit
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);
kfree(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 = __devexit_p(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);

Просмотреть файл

@ -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");

Просмотреть файл

@ -0,0 +1,39 @@
/*
* 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>
#include <asm/mips-boards/generic.h>
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);

Просмотреть файл

@ -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");

Просмотреть файл

@ -0,0 +1,20 @@
/*
* 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>
int coherentio; /* 0 => no DMA cache coherency (may be set by user) */
int hw_coherentio; /* 0 => no HW DMA cache coherency (reflects real HW) */
const char *get_system_type(void)
{
return "MIPS SEAD3";
}
void __init plat_mem_setup(void)
{
}

Просмотреть файл

@ -0,0 +1,117 @@
/*
* 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/setup.h>
#include <asm/time.h>
#include <asm/irq.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
unsigned long cpu_khz;
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() & 0xffff00;
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 __cpuinit 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);
cpu_khz = est_freq / 1000;
mips_scroll_message();
plat_perf_setup();
}