Merge branch 'ralf-3.7' of git://git.linux-mips.org/pub/scm/sjhill/linux-sjhill into mips-for-linux-next
This commit is contained in:
commit
cb418b34ca
|
@ -16,6 +16,7 @@ platforms += lasat
|
|||
platforms += loongson
|
||||
platforms += loongson1
|
||||
platforms += mti-malta
|
||||
platforms += mti-sead3
|
||||
platforms += netlogic
|
||||
platforms += pmc-sierra
|
||||
platforms += pnx833x
|
||||
|
|
|
@ -322,6 +322,36 @@ config MIPS_MALTA
|
|||
This enables support for the MIPS Technologies Malta evaluation
|
||||
board.
|
||||
|
||||
config MIPS_SEAD3
|
||||
bool "MIPS SEAD3 board"
|
||||
select BOOT_ELF32
|
||||
select BOOT_RAW
|
||||
select CEVT_R4K
|
||||
select CSRC_R4K
|
||||
select CPU_MIPSR2_IRQ_VI
|
||||
select CPU_MIPSR2_IRQ_EI
|
||||
select DMA_NONCOHERENT
|
||||
select IRQ_CPU
|
||||
select IRQ_GIC
|
||||
select MIPS_BOARDS_GEN
|
||||
select MIPS_CPU_SCACHE
|
||||
select MIPS_MSC
|
||||
select SYS_HAS_CPU_MIPS32_R1
|
||||
select SYS_HAS_CPU_MIPS32_R2
|
||||
select SYS_HAS_CPU_MIPS64_R1
|
||||
select SYS_HAS_EARLY_PRINTK
|
||||
select SYS_SUPPORTS_32BIT_KERNEL
|
||||
select SYS_SUPPORTS_64BIT_KERNEL
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
select SYS_SUPPORTS_LITTLE_ENDIAN
|
||||
select SYS_SUPPORTS_SMARTMIPS
|
||||
select USB_ARCH_HAS_EHCI
|
||||
select USB_EHCI_BIG_ENDIAN_DESC
|
||||
select USB_EHCI_BIG_ENDIAN_MMIO
|
||||
help
|
||||
This enables support for the MIPS Technologies SEAD3 evaluation
|
||||
board.
|
||||
|
||||
config NEC_MARKEINS
|
||||
bool "NEC EMMA2RH Mark-eins board"
|
||||
select SOC_EMMA2RH
|
||||
|
@ -1732,7 +1762,6 @@ config HARDWARE_WATCHPOINTS
|
|||
menu "Kernel type"
|
||||
|
||||
choice
|
||||
|
||||
prompt "Kernel code model"
|
||||
help
|
||||
You should only select this option if you have a workload that
|
||||
|
@ -1938,7 +1967,6 @@ config SCHED_SMT
|
|||
config SYS_SUPPORTS_SCHED_SMT
|
||||
bool
|
||||
|
||||
|
||||
config SYS_SUPPORTS_MULTITHREADING
|
||||
bool
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
CONFIG_MIPS_SEAD3=y
|
||||
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||
CONFIG_CPU_MIPS32_R2=y
|
||||
CONFIG_HZ_100=y
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_LOG_BUF_SHIFT=15
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_SLAB=y
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_PNP=y
|
||||
CONFIG_IP_PNP_DHCP=y
|
||||
CONFIG_IP_PNP_BOOTP=y
|
||||
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
|
||||
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
|
||||
# CONFIG_INET_XFRM_MODE_BEET is not set
|
||||
# CONFIG_INET_LRO is not set
|
||||
# CONFIG_INET_DIAG is not set
|
||||
# CONFIG_IPV6 is not set
|
||||
# CONFIG_WIRELESS is not set
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_CHAR=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_CFI=y
|
||||
CONFIG_MTD_CFI_INTELEXT=y
|
||||
CONFIG_MTD_PHYSMAP=y
|
||||
CONFIG_MTD_UBI=y
|
||||
CONFIG_MTD_UBI_GLUEBI=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_CRYPTOLOOP=m
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_CHR_DEV_SG=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_SMSC911X=y
|
||||
# CONFIG_NET_VENDOR_WIZNET is not set
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_DAVICOM_PHY=y
|
||||
CONFIG_QSEMI_PHY=y
|
||||
CONFIG_LXT_PHY=y
|
||||
CONFIG_CICADA_PHY=y
|
||||
CONFIG_VITESSE_PHY=y
|
||||
CONFIG_SMSC_PHY=y
|
||||
CONFIG_BROADCOM_PHY=y
|
||||
CONFIG_ICPLUS_PHY=y
|
||||
# CONFIG_WLAN is not set
|
||||
# CONFIG_INPUT_MOUSEDEV is not set
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_CONSOLE_TRANSLATIONS is not set
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_LEGACY_PTY_COUNT=32
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=2
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_COMPAT is not set
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
# CONFIG_I2C_HELPER_AUTO is not set
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SENSORS_ADT7475=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_LCD_CLASS_DEVICE=y
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_ROOT_HUB_TT=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_DEBUG=y
|
||||
CONFIG_MMC_SPI=y
|
||||
CONFIG_NEW_LEDS=y
|
||||
CONFIG_LEDS_CLASS=y
|
||||
CONFIG_LEDS_TRIGGERS=y
|
||||
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_M41T80=y
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_XFS_FS=y
|
||||
CONFIG_XFS_QUOTA=y
|
||||
CONFIG_XFS_POSIX_ACL=y
|
||||
CONFIG_QUOTA=y
|
||||
# CONFIG_PRINT_QUOTA_WARNING is not set
|
||||
CONFIG_MSDOS_FS=m
|
||||
CONFIG_VFAT_FS=m
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_JFFS2_FS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_ISO8859_15=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
# CONFIG_FTRACE is not set
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_AES=y
|
||||
CONFIG_CRYPTO_ARC4=y
|
||||
# CONFIG_CRYPTO_ANSI_CPRNG is not set
|
||||
# CONFIG_CRYPTO_HW is not set
|
|
@ -94,6 +94,7 @@
|
|||
#define PRID_IMP_24KE 0x9600
|
||||
#define PRID_IMP_74K 0x9700
|
||||
#define PRID_IMP_1004K 0x9900
|
||||
#define PRID_IMP_1074K 0x9a00
|
||||
#define PRID_IMP_M14KC 0x9c00
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,13 +33,13 @@
|
|||
REG32(_gic_base + segment##_##SECTION_OFS + offset)
|
||||
|
||||
#define GIC_ABS_REG(segment, offset) \
|
||||
(_gic_base + segment##_##SECTION_OFS + offset##_##OFS)
|
||||
(_gic_base + segment##_##SECTION_OFS + offset##_##OFS)
|
||||
#define GIC_REG_ABS_ADDR(segment, offset) \
|
||||
(_gic_base + segment##_##SECTION_OFS + offset)
|
||||
(_gic_base + segment##_##SECTION_OFS + offset)
|
||||
|
||||
#ifdef GICISBYTELITTLEENDIAN
|
||||
#define GICREAD(reg, data) (data) = (reg), (data) = le32_to_cpu(data)
|
||||
#define GICWRITE(reg, data) (reg) = cpu_to_le32(data)
|
||||
#define GICREAD(reg, data) ((data) = (reg), (data) = le32_to_cpu(data))
|
||||
#define GICWRITE(reg, data) ((reg) = cpu_to_le32(data))
|
||||
#define GICBIS(reg, bits) \
|
||||
({unsigned int data; \
|
||||
GICREAD(reg, data); \
|
||||
|
@ -48,9 +48,9 @@
|
|||
})
|
||||
|
||||
#else
|
||||
#define GICREAD(reg, data) (data) = (reg)
|
||||
#define GICWRITE(reg, data) (reg) = (data)
|
||||
#define GICBIS(reg, bits) (reg) |= (bits)
|
||||
#define GICREAD(reg, data) ((data) = (reg))
|
||||
#define GICWRITE(reg, data) ((reg) = (data))
|
||||
#define GICBIS(reg, bits) ((reg) |= (bits))
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -304,15 +304,15 @@
|
|||
GIC_SH_MAP_TO_VPE_REG_BIT(vpe))
|
||||
|
||||
struct gic_pcpu_mask {
|
||||
DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
|
||||
DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
|
||||
};
|
||||
|
||||
struct gic_pending_regs {
|
||||
DECLARE_BITMAP(pending, GIC_NUM_INTRS);
|
||||
DECLARE_BITMAP(pending, GIC_NUM_INTRS);
|
||||
};
|
||||
|
||||
struct gic_intrmask_regs {
|
||||
DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
|
||||
DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -341,15 +341,44 @@ struct gic_shared_intr_map {
|
|||
unsigned int local_intr_mask;
|
||||
};
|
||||
|
||||
/* GIC nomenclature for Core Interrupt Pins. */
|
||||
#define GIC_CPU_INT0 0 /* Core Interrupt 2 */
|
||||
#define GIC_CPU_INT1 1 /* . */
|
||||
#define GIC_CPU_INT2 2 /* . */
|
||||
#define GIC_CPU_INT3 3 /* . */
|
||||
#define GIC_CPU_INT4 4 /* . */
|
||||
#define GIC_CPU_INT5 5 /* Core Interrupt 5 */
|
||||
|
||||
/* Local GIC interrupts. */
|
||||
#define GIC_INT_TMR (GIC_CPU_INT5)
|
||||
#define GIC_INT_PERFCTR (GIC_CPU_INT5)
|
||||
|
||||
/* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */
|
||||
#define GIC_CPU_TO_VEC_OFFSET (2)
|
||||
|
||||
/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
|
||||
#define GIC_PIN_TO_VEC_OFFSET (1)
|
||||
|
||||
extern unsigned long _gic_base;
|
||||
extern unsigned int gic_irq_base;
|
||||
extern unsigned int gic_irq_flags[];
|
||||
extern struct gic_shared_intr_map gic_shared_intr_map[];
|
||||
|
||||
extern void gic_init(unsigned long gic_base_addr,
|
||||
unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
|
||||
unsigned int intrmap_size, unsigned int irqbase);
|
||||
|
||||
extern void gic_clocksource_init(unsigned int);
|
||||
extern unsigned int gic_get_int(void);
|
||||
extern void gic_send_ipi(unsigned int intr);
|
||||
extern unsigned int plat_ipi_call_int_xlate(unsigned int);
|
||||
extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
|
||||
extern void gic_bind_eic_interrupt(int irq, int set);
|
||||
extern unsigned int gic_get_timer_pending(void);
|
||||
extern void gic_enable_interrupt(int irq_vec);
|
||||
extern void gic_disable_interrupt(int irq_vec);
|
||||
extern void gic_irq_ack(struct irq_data *d);
|
||||
extern void gic_finish_irq(struct irq_data *d);
|
||||
extern void gic_platform_init(int irqs, struct irq_chip *irq_controller);
|
||||
|
||||
#endif /* _ASM_GICREGS_H */
|
||||
|
|
|
@ -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 */
|
|
@ -1,31 +1,16 @@
|
|||
/*
|
||||
* Carsten Langgaard, carstenl@mips.com
|
||||
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify it
|
||||
* under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* ########################################################################
|
||||
*
|
||||
* Defines for the Malta interrupt controller.
|
||||
* 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.
|
||||
* Carsten Langgaard <carstenl@mips.com>
|
||||
* Steven J. Hill <sjhill@mips.com>
|
||||
*/
|
||||
#ifndef _MIPS_MALTAINT_H
|
||||
#define _MIPS_MALTAINT_H
|
||||
|
||||
#include <irq.h>
|
||||
#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
|
||||
|
||||
/*
|
||||
* Interrupts 0..15 are used for Malta ISA compatible interrupts
|
||||
|
@ -78,26 +63,6 @@
|
|||
#define MSC01E_INT_PERFCTR 10
|
||||
#define MSC01E_INT_CPUCTR 11
|
||||
|
||||
/* GIC's Nomenclature for Core Interrupt Pins on the Malta */
|
||||
#define GIC_CPU_INT0 0 /* Core Interrupt 2 */
|
||||
#define GIC_CPU_INT1 1 /* . */
|
||||
#define GIC_CPU_INT2 2 /* . */
|
||||
#define GIC_CPU_INT3 3 /* . */
|
||||
#define GIC_CPU_INT4 4 /* . */
|
||||
#define GIC_CPU_INT5 5 /* Core Interrupt 5 */
|
||||
|
||||
/* MALTA GIC local interrupts */
|
||||
#define GIC_INT_TMR (GIC_CPU_INT5)
|
||||
#define GIC_INT_PERFCTR (GIC_CPU_INT5)
|
||||
|
||||
/* GIC constants */
|
||||
/* Add 2 to convert non-eic hw int # to eic vector # */
|
||||
#define GIC_CPU_TO_VEC_OFFSET (2)
|
||||
/* If we map an intr to pin X, GIC will actually generate vector X+1 */
|
||||
#define GIC_PIN_TO_VEC_OFFSET (1)
|
||||
|
||||
#define GIC_EXT_INTR(x) x
|
||||
|
||||
/* External Interrupts used for IPI */
|
||||
#define GIC_IPI_EXT_INTR_RESCHED_VPE0 16
|
||||
#define GIC_IPI_EXT_INTR_CALLFNC_VPE0 17
|
||||
|
@ -108,10 +73,4 @@
|
|||
#define GIC_IPI_EXT_INTR_RESCHED_VPE3 22
|
||||
#define GIC_IPI_EXT_INTR_CALLFNC_VPE3 23
|
||||
|
||||
#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern void maltaint_init(void);
|
||||
#endif
|
||||
|
||||
#endif /* !(_MIPS_MALTAINT_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) */
|
|
@ -597,6 +597,8 @@
|
|||
#define MIPS_CONF4_MMUEXTDEF (_ULCAST_(3) << 14)
|
||||
#define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14)
|
||||
|
||||
#define MIPS_CONF6_SYND (_ULCAST_(1) << 13)
|
||||
|
||||
#define MIPS_CONF7_WII (_ULCAST_(1) << 31)
|
||||
|
||||
#define MIPS_CONF7_RPS (_ULCAST_(1) << 2)
|
||||
|
|
|
@ -90,6 +90,8 @@ Ip_u2u1u3(_dsrl);
|
|||
Ip_u2u1u3(_dsrl32);
|
||||
Ip_u3u1u2(_dsubu);
|
||||
Ip_0(_eret);
|
||||
Ip_u2u1msbu3(_ext);
|
||||
Ip_u2u1msbu3(_ins);
|
||||
Ip_u1(_j);
|
||||
Ip_u1(_jal);
|
||||
Ip_u1(_jr);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <asm/smtc_ipi.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/cevt-r4k.h>
|
||||
#include <asm/gic.h>
|
||||
|
||||
/*
|
||||
* The SMTC Kernel for the 34K, 1004K, et. al. replaces several
|
||||
|
@ -98,6 +99,10 @@ void mips_event_handler(struct clock_event_device *dev)
|
|||
*/
|
||||
static int c0_compare_int_pending(void)
|
||||
{
|
||||
#ifdef CONFIG_IRQ_GIC
|
||||
if (cpu_has_veic)
|
||||
return gic_get_timer_pending();
|
||||
#endif
|
||||
return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
|
||||
}
|
||||
|
||||
|
|
|
@ -861,6 +861,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
|
|||
c->cputype = CPU_1004K;
|
||||
__cpu_name[cpu] = "MIPS 1004Kc";
|
||||
break;
|
||||
case PRID_IMP_1074K:
|
||||
c->cputype = CPU_74K;
|
||||
__cpu_name[cpu] = "MIPS 1074Kc";
|
||||
break;
|
||||
}
|
||||
|
||||
spram_config();
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#undef DEBUG
|
||||
|
||||
/*
|
||||
* 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) 2008 Ralf Baechle (ralf@linux-mips.org)
|
||||
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
|
@ -7,33 +13,80 @@
|
|||
|
||||
#include <asm/io.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/gcmpregs.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <asm-generic/bitops/find.h>
|
||||
|
||||
unsigned long _gic_base;
|
||||
unsigned int gic_irq_base;
|
||||
unsigned int gic_irq_flags[GIC_NUM_INTRS];
|
||||
|
||||
static unsigned long _gic_base;
|
||||
static unsigned int _irqbase;
|
||||
static unsigned int gic_irq_flags[GIC_NUM_INTRS];
|
||||
#define GIC_IRQ_FLAG_EDGE 0x0001
|
||||
/* The index into this array is the vector # of the interrupt. */
|
||||
struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
|
||||
|
||||
struct gic_pcpu_mask pcpu_masks[NR_CPUS];
|
||||
static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
|
||||
static struct gic_pending_regs pending_regs[NR_CPUS];
|
||||
static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
|
||||
|
||||
unsigned int gic_get_timer_pending(void)
|
||||
{
|
||||
unsigned int vpe_pending;
|
||||
|
||||
GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
|
||||
GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
|
||||
return (vpe_pending & GIC_VPE_PEND_TIMER_MSK);
|
||||
}
|
||||
|
||||
void gic_bind_eic_interrupt(int irq, int set)
|
||||
{
|
||||
/* Convert irq vector # to hw int # */
|
||||
irq -= GIC_PIN_TO_VEC_OFFSET;
|
||||
|
||||
/* Set irq to use shadow set */
|
||||
GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set);
|
||||
}
|
||||
|
||||
void gic_send_ipi(unsigned int intr)
|
||||
{
|
||||
pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
|
||||
read_c0_status());
|
||||
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
|
||||
}
|
||||
|
||||
/* This is Malta specific and needs to be exported */
|
||||
static void gic_eic_irq_dispatch(void)
|
||||
{
|
||||
unsigned int cause = read_c0_cause();
|
||||
int irq;
|
||||
|
||||
irq = (cause & ST0_IM) >> STATUSB_IP2;
|
||||
if (irq == 0)
|
||||
irq = -1;
|
||||
|
||||
if (irq >= 0)
|
||||
do_IRQ(gic_irq_base + irq);
|
||||
else
|
||||
spurious_interrupt();
|
||||
}
|
||||
|
||||
static void __init vpe_local_setup(unsigned int numvpes)
|
||||
{
|
||||
int i;
|
||||
unsigned long timer_interrupt = 5, perf_interrupt = 5;
|
||||
unsigned long timer_intr = GIC_INT_TMR;
|
||||
unsigned long perf_intr = GIC_INT_PERFCTR;
|
||||
unsigned int vpe_ctl;
|
||||
int i;
|
||||
|
||||
if (cpu_has_veic) {
|
||||
/*
|
||||
* GIC timer interrupt -> CPU HW Int X (vector X+2) ->
|
||||
* map to pin X+2-1 (since GIC adds 1)
|
||||
*/
|
||||
timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
|
||||
/*
|
||||
* GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
|
||||
* map to pin X+2-1 (since GIC adds 1)
|
||||
*/
|
||||
perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the default performance counter timer interrupts
|
||||
|
@ -46,11 +99,20 @@ static void __init vpe_local_setup(unsigned int numvpes)
|
|||
GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
|
||||
if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
|
||||
GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
|
||||
GIC_MAP_TO_PIN_MSK | timer_interrupt);
|
||||
GIC_MAP_TO_PIN_MSK | timer_intr);
|
||||
if (cpu_has_veic) {
|
||||
set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
|
||||
gic_eic_irq_dispatch);
|
||||
gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
|
||||
}
|
||||
|
||||
if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
|
||||
GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
|
||||
GIC_MAP_TO_PIN_MSK | perf_interrupt);
|
||||
GIC_MAP_TO_PIN_MSK | perf_intr);
|
||||
if (cpu_has_veic) {
|
||||
set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
|
||||
gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,51 +142,30 @@ unsigned int gic_get_int(void)
|
|||
bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
|
||||
bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
|
||||
|
||||
i = find_first_bit(pending, GIC_NUM_INTRS);
|
||||
|
||||
pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void gic_irq_ack(struct irq_data *d)
|
||||
{
|
||||
unsigned int irq = d->irq - _irqbase;
|
||||
|
||||
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||
GIC_CLR_INTR_MASK(irq);
|
||||
|
||||
if (gic_irq_flags[irq] & GIC_IRQ_FLAG_EDGE)
|
||||
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
|
||||
return find_first_bit(pending, GIC_NUM_INTRS);
|
||||
}
|
||||
|
||||
static void gic_mask_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int irq = d->irq - _irqbase;
|
||||
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||
GIC_CLR_INTR_MASK(irq);
|
||||
GIC_CLR_INTR_MASK(d->irq - gic_irq_base);
|
||||
}
|
||||
|
||||
static void gic_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int irq = d->irq - _irqbase;
|
||||
pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
|
||||
GIC_SET_INTR_MASK(irq);
|
||||
GIC_SET_INTR_MASK(d->irq - gic_irq_base);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
static DEFINE_SPINLOCK(gic_lock);
|
||||
|
||||
static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
|
||||
bool force)
|
||||
{
|
||||
unsigned int irq = d->irq - _irqbase;
|
||||
unsigned int irq = (d->irq - gic_irq_base);
|
||||
cpumask_t tmp = CPU_MASK_NONE;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
pr_debug("%s(%d) called\n", __func__, irq);
|
||||
cpumask_and(&tmp, cpumask, cpu_online_mask);
|
||||
if (cpus_empty(tmp))
|
||||
return -1;
|
||||
|
@ -154,7 +195,7 @@ static struct irq_chip gic_irq_controller = {
|
|||
.irq_mask = gic_mask_irq,
|
||||
.irq_mask_ack = gic_mask_irq,
|
||||
.irq_unmask = gic_unmask_irq,
|
||||
.irq_eoi = gic_unmask_irq,
|
||||
.irq_eoi = gic_finish_irq,
|
||||
#ifdef CONFIG_SMP
|
||||
.irq_set_affinity = gic_set_affinity,
|
||||
#endif
|
||||
|
@ -164,6 +205,8 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
|
|||
unsigned int pin, unsigned int polarity, unsigned int trigtype,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct gic_shared_intr_map *map_ptr;
|
||||
|
||||
/* Setup Intr to Pin mapping */
|
||||
if (pin & GIC_MAP_TO_NMI_MSK) {
|
||||
GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
|
||||
|
@ -178,6 +221,14 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
|
|||
GIC_MAP_TO_PIN_MSK | pin);
|
||||
/* Setup Intr to CPU mapping */
|
||||
GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
|
||||
if (cpu_has_veic) {
|
||||
set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
|
||||
gic_eic_irq_dispatch);
|
||||
map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
|
||||
if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
|
||||
BUG();
|
||||
map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup Intr Polarity */
|
||||
|
@ -191,26 +242,39 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
|
|||
/* Initialise per-cpu Interrupt software masks */
|
||||
if (flags & GIC_FLAG_IPI)
|
||||
set_bit(intr, pcpu_masks[cpu].pcpu_mask);
|
||||
if (flags & GIC_FLAG_TRANSPARENT)
|
||||
if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
|
||||
GIC_SET_INTR_MASK(intr);
|
||||
if (trigtype == GIC_TRIG_EDGE)
|
||||
gic_irq_flags[intr] |= GIC_IRQ_FLAG_EDGE;
|
||||
gic_irq_flags[intr] |= GIC_TRIG_EDGE;
|
||||
}
|
||||
|
||||
static void __init gic_basic_init(int numintrs, int numvpes,
|
||||
struct gic_intr_map *intrmap, int mapsize)
|
||||
{
|
||||
unsigned int i, cpu;
|
||||
unsigned int pin_offset = 0;
|
||||
|
||||
board_bind_eic_interrupt = &gic_bind_eic_interrupt;
|
||||
|
||||
/* Setup defaults */
|
||||
for (i = 0; i < numintrs; i++) {
|
||||
GIC_SET_POLARITY(i, GIC_POL_POS);
|
||||
GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
|
||||
GIC_CLR_INTR_MASK(i);
|
||||
if (i < GIC_NUM_INTRS)
|
||||
if (i < GIC_NUM_INTRS) {
|
||||
gic_irq_flags[i] = 0;
|
||||
gic_shared_intr_map[i].num_shared_intr = 0;
|
||||
gic_shared_intr_map[i].local_intr_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
|
||||
* one because the GIC will add one (since 0=no intr).
|
||||
*/
|
||||
if (cpu_has_veic)
|
||||
pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
|
||||
|
||||
/* Setup specifics */
|
||||
for (i = 0; i < mapsize; i++) {
|
||||
cpu = intrmap[i].cpunum;
|
||||
|
@ -220,16 +284,13 @@ static void __init gic_basic_init(int numintrs, int numvpes,
|
|||
continue;
|
||||
gic_setup_intr(i,
|
||||
intrmap[i].cpunum,
|
||||
intrmap[i].pin,
|
||||
intrmap[i].pin + pin_offset,
|
||||
intrmap[i].polarity,
|
||||
intrmap[i].trigtype,
|
||||
intrmap[i].flags);
|
||||
}
|
||||
|
||||
vpe_local_setup(numvpes);
|
||||
|
||||
for (i = _irqbase; i < (_irqbase + numintrs); i++)
|
||||
irq_set_chip(i, &gic_irq_controller);
|
||||
}
|
||||
|
||||
void __init gic_init(unsigned long gic_base_addr,
|
||||
|
@ -242,7 +303,7 @@ void __init gic_init(unsigned long gic_base_addr,
|
|||
|
||||
_gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
|
||||
gic_addrspace_size);
|
||||
_irqbase = irqbase;
|
||||
gic_irq_base = irqbase;
|
||||
|
||||
GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
|
||||
numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
|
||||
|
@ -251,8 +312,9 @@ void __init gic_init(unsigned long gic_base_addr,
|
|||
|
||||
numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
|
||||
GIC_SH_CONFIG_NUMVPES_SHF;
|
||||
|
||||
pr_debug("%s called\n", __func__);
|
||||
numvpes = numvpes + 1;
|
||||
|
||||
gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
|
||||
|
||||
gic_platform_init(numintrs, &gic_irq_controller);
|
||||
}
|
||||
|
|
|
@ -786,6 +786,25 @@ static inline void rm7k_erratum31(void)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void alias_74k_erratum(struct cpuinfo_mips *c)
|
||||
{
|
||||
/*
|
||||
* Early versions of the 74K do not update the cache tags on a
|
||||
* vtag miss/ptag hit which can occur in the case of KSEG0/KUSEG
|
||||
* aliases. In this case it is better to treat the cache as always
|
||||
* having aliases.
|
||||
*/
|
||||
if ((c->processor_id & 0xff) <= PRID_REV_ENCODE_332(2, 4, 0))
|
||||
c->dcache.flags |= MIPS_CACHE_VTAG;
|
||||
if ((c->processor_id & 0xff) == PRID_REV_ENCODE_332(2, 4, 0))
|
||||
write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
|
||||
if (((c->processor_id & 0xff00) == PRID_IMP_1074K) &&
|
||||
((c->processor_id & 0xff) <= PRID_REV_ENCODE_332(1, 1, 0))) {
|
||||
c->dcache.flags |= MIPS_CACHE_VTAG;
|
||||
write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
|
||||
}
|
||||
}
|
||||
|
||||
static char *way_string[] __cpuinitdata = { NULL, "direct mapped", "2-way",
|
||||
"3-way", "4-way", "5-way", "6-way", "7-way", "8-way"
|
||||
};
|
||||
|
@ -1056,6 +1075,8 @@ static void __cpuinit probe_pcache(void)
|
|||
case CPU_34K:
|
||||
case CPU_74K:
|
||||
case CPU_1004K:
|
||||
if (c->cputype == CPU_74K)
|
||||
alias_74k_erratum(c);
|
||||
if ((read_c0_config7() & (1 << 16))) {
|
||||
/* effectively physically indexed dcache,
|
||||
thus no virtual aliases. */
|
||||
|
|
|
@ -449,8 +449,20 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
|
|||
}
|
||||
|
||||
if (cpu_has_mips_r2) {
|
||||
if (cpu_has_mips_r2_exec_hazard)
|
||||
/*
|
||||
* The architecture spec says an ehb is required here,
|
||||
* but a number of cores do not have the hazard and
|
||||
* using an ehb causes an expensive pipeline stall.
|
||||
*/
|
||||
switch (current_cpu_type()) {
|
||||
case CPU_M14KC:
|
||||
case CPU_74K:
|
||||
break;
|
||||
|
||||
default:
|
||||
uasm_i_ehb(p);
|
||||
break;
|
||||
}
|
||||
tlbw(p);
|
||||
return;
|
||||
}
|
||||
|
@ -921,6 +933,13 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
|
|||
#endif
|
||||
uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
|
||||
uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
|
||||
|
||||
if (cpu_has_mips_r2) {
|
||||
uasm_i_ext(p, tmp, tmp, PGDIR_SHIFT, (32 - PGDIR_SHIFT));
|
||||
uasm_i_ins(p, ptr, tmp, PGD_T_LOG2, (32 - PGDIR_SHIFT));
|
||||
return;
|
||||
}
|
||||
|
||||
uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
|
||||
uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
|
||||
uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
|
||||
|
@ -956,6 +975,15 @@ static void __cpuinit build_adjust_context(u32 **p, unsigned int ctx)
|
|||
|
||||
static void __cpuinit build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
|
||||
{
|
||||
if (cpu_has_mips_r2) {
|
||||
/* PTE ptr offset is obtained from BadVAddr */
|
||||
UASM_i_MFC0(p, tmp, C0_BADVADDR);
|
||||
UASM_i_LW(p, ptr, 0, ptr);
|
||||
uasm_i_ext(p, tmp, tmp, PAGE_SHIFT+1, PGDIR_SHIFT-PAGE_SHIFT-1);
|
||||
uasm_i_ins(p, ptr, tmp, PTE_T_LOG2+1, PGDIR_SHIFT-PAGE_SHIFT-1);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bug workaround for the Nevada. It seems as if under certain
|
||||
* circumstances the move from cp0_context might produce a
|
||||
|
|
|
@ -63,11 +63,12 @@ enum opcode {
|
|||
insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
|
||||
insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
|
||||
insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
|
||||
insn_j, insn_jal, insn_jr, insn_ld, insn_ldx, insn_ll, insn_lld,
|
||||
insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, insn_or, insn_ori,
|
||||
insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll,
|
||||
insn_sra, insn_srl, insn_subu, insn_sw, insn_syscall, insn_tlbp,
|
||||
insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
|
||||
insn_ext, insn_ins, insn_j, insn_jal, insn_jr, insn_ld, insn_ldx,
|
||||
insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0,
|
||||
insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd,
|
||||
insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
|
||||
insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor,
|
||||
insn_xori,
|
||||
};
|
||||
|
||||
struct insn {
|
||||
|
@ -115,6 +116,9 @@ static struct insn insn_table[] __uasminitdata = {
|
|||
{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
|
||||
{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
|
||||
{ insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
|
||||
{ insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
|
||||
{ insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
|
||||
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
|
||||
{ insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
|
||||
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
|
||||
{ insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
|
||||
|
@ -341,6 +345,13 @@ Ip_u2u1msbu3(op) \
|
|||
} \
|
||||
UASM_EXPORT_SYMBOL(uasm_i##op);
|
||||
|
||||
#define I_u2u1msbdu3(op) \
|
||||
Ip_u2u1msbu3(op) \
|
||||
{ \
|
||||
build_insn(buf, insn##op, b, a, d-1, c); \
|
||||
} \
|
||||
UASM_EXPORT_SYMBOL(uasm_i##op);
|
||||
|
||||
#define I_u1u2(op) \
|
||||
Ip_u1u2(op) \
|
||||
{ \
|
||||
|
@ -394,6 +405,8 @@ I_u2u1u3(_drotr)
|
|||
I_u2u1u3(_drotr32)
|
||||
I_u3u1u2(_dsubu)
|
||||
I_0(_eret)
|
||||
I_u2u1msbdu3(_ext)
|
||||
I_u2u1msbu3(_ins)
|
||||
I_u1(_j)
|
||||
I_u1(_jal)
|
||||
I_u1(_jr)
|
||||
|
|
|
@ -750,3 +750,37 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
|
|||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void gic_enable_interrupt(int irq_vec)
|
||||
{
|
||||
GIC_SET_INTR_MASK(irq_vec);
|
||||
}
|
||||
|
||||
void gic_disable_interrupt(int irq_vec)
|
||||
{
|
||||
GIC_CLR_INTR_MASK(irq_vec);
|
||||
}
|
||||
|
||||
void gic_irq_ack(struct irq_data *d)
|
||||
{
|
||||
int irq = (d->irq - gic_irq_base);
|
||||
|
||||
GIC_CLR_INTR_MASK(irq);
|
||||
|
||||
if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
|
||||
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
|
||||
}
|
||||
|
||||
void gic_finish_irq(struct irq_data *d)
|
||||
{
|
||||
/* Enable interrupts. */
|
||||
GIC_SET_INTR_MASK(d->irq - gic_irq_base);
|
||||
}
|
||||
|
||||
void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = gic_irq_base; i < (gic_irq_base + irqs); i++)
|
||||
irq_set_chip(i, irq_controller);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue