mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
strip the kernel version suffix from target directories, except for brcm-2.4 (the -2.4 will be included in the board name here). CONFIG_LINUX_<ver>_<board> becomes CONFIG_TARGET_<board>, same for profiles.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@8653 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
9
target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile
Normal file
9
target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for the Broadcom BCM963xx SoC specific parts of the kernel
|
||||
#
|
||||
# Copyright (C) 2004 Broadcom Corporation
|
||||
#
|
||||
obj-y := irq.o prom.o setup.o time.o ser_init.o int-handler.o info.o wdt.o
|
||||
|
||||
SRCBASE := $(TOPDIR)
|
||||
EXTRA_CFLAGS += -I$(SRCBASE)/include
|
||||
102
target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c
Normal file
102
target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 OpenWrt.org
|
||||
* Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
|
||||
* Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/string.h>
|
||||
#include <asm/mach-bcm963xx/bootloaders.h>
|
||||
|
||||
static char *boot_loader_names[BOOT_LOADER_LAST+1] = {
|
||||
[BOOT_LOADER_UNKNOWN] = "Unknown",
|
||||
[BOOT_LOADER_CFE] = "CFE",
|
||||
[BOOT_LOADER_REDBOOT] = "RedBoot",
|
||||
[BOOT_LOADER_CFE2] = "CFEv2"
|
||||
};
|
||||
|
||||
/* boot loaders specific definitions */
|
||||
#define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE from other bootloaders */
|
||||
|
||||
int boot_loader_type;
|
||||
/*
|
||||
* Boot loader detection routines
|
||||
*/
|
||||
static int __init detect_cfe(void)
|
||||
{
|
||||
/*
|
||||
* This method only works, when we are booted directly from the CFE.
|
||||
*/
|
||||
uint32_t cfe_handle = (uint32_t) fw_arg0;
|
||||
uint32_t cfe_a1_val = (uint32_t) fw_arg1;
|
||||
uint32_t cfe_entry = (uint32_t) fw_arg2;
|
||||
uint32_t cfe_seal = (uint32_t) fw_arg3;
|
||||
|
||||
/* Check for CFE by finding the CFE magic number */
|
||||
if (cfe_seal != CFE_EPTSEAL)
|
||||
/* We are not booted from CFE */
|
||||
return 0;
|
||||
|
||||
/* cfe_a1_val must be 0, because only one CPU present in the ADM5120 SoC */
|
||||
if (cfe_a1_val != 0)
|
||||
return 0;
|
||||
|
||||
/* The cfe_handle, and the cfe_entry must be kernel mode addresses */
|
||||
if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init detect_redboot(void)
|
||||
{
|
||||
/* On Inventel Livebox, the boot loader is passed as a command line argument, check for it */
|
||||
if (!strncmp(arcs_cmdline, "boot_loader=RedBoot", 19))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init detect_bootloader(void)
|
||||
{
|
||||
if (detect_cfe()) {
|
||||
boot_loader_type = BOOT_LOADER_CFE;
|
||||
}
|
||||
|
||||
if (detect_redboot()) {
|
||||
boot_loader_type = BOOT_LOADER_REDBOOT;
|
||||
}
|
||||
else {
|
||||
/* Some devices are using CFE, but it is not detected as is */
|
||||
boot_loader_type = BOOT_LOADER_CFE2;
|
||||
}
|
||||
printk("Boot loader is : %s\n", boot_loader_names[boot_loader_type]);
|
||||
}
|
||||
|
||||
void __init detect_board(void)
|
||||
{
|
||||
switch (boot_loader_type)
|
||||
{
|
||||
case BOOT_LOADER_CFE:
|
||||
break;
|
||||
case BOOT_LOADER_REDBOOT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(boot_loader_type);
|
||||
59
target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S
Normal file
59
target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
<:copyright-gpl
|
||||
Copyright 2002 Broadcom Corp. 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.
|
||||
:>
|
||||
*/
|
||||
/*
|
||||
* Generic interrupt handler for Broadcom MIPS boards
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
/*
|
||||
* MIPS IRQ Source
|
||||
* -------- ------
|
||||
* 0 Software (ignored)
|
||||
* 1 Software (ignored)
|
||||
* 2 Combined hardware interrupt (hw0)
|
||||
* 3 Hardware
|
||||
* 4 Hardware
|
||||
* 5 Hardware
|
||||
* 6 Hardware
|
||||
* 7 R4k timer
|
||||
*/
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.set noat
|
||||
.align 5
|
||||
NESTED(brcmIRQ, PT_SIZE, sp)
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set noreorder
|
||||
.set at
|
||||
|
||||
jal plat_irq_dispatch
|
||||
move a0, sp
|
||||
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
END(brcmIRQ)
|
||||
258
target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c
Normal file
258
target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
<:copyright-gpl
|
||||
Copyright 2002 Broadcom Corp. 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.
|
||||
:>
|
||||
*/
|
||||
/*
|
||||
* Interrupt control functions for Broadcom 963xx MIPS boards
|
||||
*/
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/signal.h>
|
||||
#include <6348_map_part.h>
|
||||
#include <6348_intr.h>
|
||||
#include <bcm_map_part.h>
|
||||
#include <bcm_intr.h>
|
||||
|
||||
static void irq_dispatch_int(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int pendingIrqs;
|
||||
static unsigned int irqBit;
|
||||
static unsigned int isrNumber = 31;
|
||||
|
||||
pendingIrqs = PERF->IrqStatus & PERF->IrqMask;
|
||||
if (!pendingIrqs) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
irqBit <<= 1;
|
||||
isrNumber++;
|
||||
if (isrNumber == 32) {
|
||||
isrNumber = 0;
|
||||
irqBit = 0x1;
|
||||
}
|
||||
if (pendingIrqs & irqBit) {
|
||||
PERF->IrqMask &= ~irqBit; // mask
|
||||
do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void irq_dispatch_ext(uint32 irq)
|
||||
{
|
||||
if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) {
|
||||
printk("**** Ext IRQ mask. Should not dispatch ****\n");
|
||||
}
|
||||
/* disable and clear interrupt in the controller */
|
||||
PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
|
||||
PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
|
||||
do_IRQ(irq);
|
||||
}
|
||||
|
||||
|
||||
extern void brcm_timer_interrupt(struct pt_regs *regs);
|
||||
|
||||
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
u32 cause;
|
||||
while((cause = (read_c0_cause()& CAUSEF_IP))) {
|
||||
if (cause & CAUSEF_IP7)
|
||||
brcm_timer_interrupt(regs);
|
||||
else if (cause & CAUSEF_IP2)
|
||||
irq_dispatch_int(regs);
|
||||
else if (cause & CAUSEF_IP3)
|
||||
irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0);
|
||||
else if (cause & CAUSEF_IP4)
|
||||
irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1);
|
||||
else if (cause & CAUSEF_IP5)
|
||||
irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2);
|
||||
else if (cause & CAUSEF_IP6)
|
||||
irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3);
|
||||
local_irq_disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void enable_brcm_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
|
||||
PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
|
||||
}
|
||||
else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
|
||||
/* enable and clear interrupt in the controller */
|
||||
PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
|
||||
PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void disable_brcm_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
|
||||
PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
|
||||
}
|
||||
else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
|
||||
/* disable interrupt in the controller */
|
||||
PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void ack_brcm_irq(unsigned int irq)
|
||||
{
|
||||
/* Already done in brcm_irq_dispatch */
|
||||
}
|
||||
|
||||
unsigned int startup_brcm_irq(unsigned int irq)
|
||||
{
|
||||
enable_brcm_irq(irq);
|
||||
|
||||
return 0; /* never anything pending */
|
||||
}
|
||||
|
||||
unsigned int startup_brcm_none(unsigned int irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void end_brcm_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
|
||||
enable_brcm_irq(irq);
|
||||
}
|
||||
|
||||
void end_brcm_none(unsigned int irq)
|
||||
{
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type brcm_irq_type = {
|
||||
.typename = "MIPS",
|
||||
.startup = startup_brcm_irq,
|
||||
.shutdown = disable_brcm_irq,
|
||||
.enable = enable_brcm_irq,
|
||||
.disable = disable_brcm_irq,
|
||||
.ack = ack_brcm_irq,
|
||||
.end = end_brcm_irq,
|
||||
.set_affinity = NULL
|
||||
};
|
||||
|
||||
static struct hw_interrupt_type brcm_irq_no_end_type = {
|
||||
.typename = "MIPS",
|
||||
.startup = startup_brcm_none,
|
||||
.shutdown = disable_brcm_irq,
|
||||
.enable = enable_brcm_irq,
|
||||
.disable = disable_brcm_irq,
|
||||
.ack = ack_brcm_irq,
|
||||
.end = end_brcm_none,
|
||||
.set_affinity = NULL
|
||||
};
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
clear_c0_status(ST0_BEV);
|
||||
change_c0_status(ST0_IM, (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4));
|
||||
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = 0;
|
||||
irq_desc[i].depth = 1;
|
||||
irq_desc[i].chip = &brcm_irq_type;
|
||||
}
|
||||
}
|
||||
|
||||
int request_external_irq(unsigned int irq,
|
||||
FN_HANDLER handler,
|
||||
unsigned long irqflags,
|
||||
const char * devname,
|
||||
void *dev_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); // Clear
|
||||
PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); // Mask
|
||||
PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT)); // Edge insesnsitive
|
||||
PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT)); // Level triggered
|
||||
PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT)); // Low level
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return( request_irq(irq, handler, irqflags, devname, dev_id) );
|
||||
}
|
||||
|
||||
/* VxWorks compatibility function(s). */
|
||||
|
||||
unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param,
|
||||
unsigned int interruptId)
|
||||
{
|
||||
int nRet = -1;
|
||||
char *devname;
|
||||
|
||||
devname = kmalloc(16, GFP_KERNEL);
|
||||
if (devname)
|
||||
sprintf( devname, "brcm_%d", interruptId );
|
||||
|
||||
/* Set the IRQ description to not automatically enable the interrupt at
|
||||
* the end of an ISR. The driver that handles the interrupt must
|
||||
* explicitly call BcmHalInterruptEnable or enable_brcm_irq. This behavior
|
||||
* is consistent with interrupt handling on VxWorks.
|
||||
*/
|
||||
irq_desc[interruptId].chip = &brcm_irq_no_end_type;
|
||||
|
||||
if( interruptId >= INTERNAL_ISR_TABLE_OFFSET )
|
||||
{
|
||||
printk("BcmHalMapInterrupt : internal IRQ\n");
|
||||
nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param );
|
||||
}
|
||||
else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3)
|
||||
{
|
||||
printk("BcmHalMapInterrupt : external IRQ\n");
|
||||
nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param );
|
||||
}
|
||||
|
||||
return( nRet );
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(enable_brcm_irq);
|
||||
EXPORT_SYMBOL(disable_brcm_irq);
|
||||
EXPORT_SYMBOL(request_external_irq);
|
||||
EXPORT_SYMBOL(BcmHalMapInterrupt);
|
||||
|
||||
73
target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c
Normal file
73
target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2004 Broadcom Corp. All Rights Reserved.
|
||||
Copyright 2007 OpenWrt,org, Florian Fainelli <florian@openwrt.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* prom.c: PROM library initialization code.
|
||||
*
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/mach-bcm963xx/bootloaders.h>
|
||||
#include <asm/mach-bcm963xx/6348_map_part.h>
|
||||
|
||||
#include "../cfe/cfe_private.h"
|
||||
|
||||
extern void __init detect_bootloader(void);
|
||||
extern void serial_init(void);
|
||||
extern int boot_loader_type;
|
||||
|
||||
#define MACH_BCM MACH_BCM96348
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return "Broadcom BCM963xx";
|
||||
}
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
serial_init();
|
||||
|
||||
printk("%s prom init\n", get_system_type() );
|
||||
|
||||
PERF->IrqMask = 0;
|
||||
|
||||
/* Detect the bootloader */
|
||||
detect_bootloader();
|
||||
|
||||
/* Do further initialisations depending on the bootloader */
|
||||
if (boot_loader_type == BOOT_LOADER_CFE || boot_loader_type == BOOT_LOADER_CFE2) {
|
||||
cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3);
|
||||
}
|
||||
/* Register 16MB RAM minus the ADSL SDRAM by default */
|
||||
add_memory_region(0, (0x01000000 - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM);
|
||||
|
||||
mips_machgroup = MACH_GROUP_BRCM;
|
||||
mips_machtype = MACH_BCM;
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
/* We do not have any memory to free */
|
||||
}
|
||||
181
target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c
Normal file
181
target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
<:copyright-gpl
|
||||
Copyright 2004 Broadcom Corp. 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.
|
||||
:>
|
||||
*/
|
||||
/*
|
||||
* Broadcom bcm63xx serial port initialization, also prepare for printk
|
||||
* by registering with console_init
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include <asm/mc146818rtc.h>
|
||||
|
||||
#include <bcm_map_part.h>
|
||||
#include <6348_map_part.h>
|
||||
#include <board.h>
|
||||
|
||||
#define SER63XX_DEFAULT_BAUD 115200
|
||||
#define BD_BCM63XX_TIMER_CLOCK_INPUT (FPERIPH)
|
||||
#define stUart ((volatile Uart * const) UART_BASE)
|
||||
|
||||
// Transmit interrupts
|
||||
#define TXINT (TXFIFOEMT | TXUNDERR | TXOVFERR)
|
||||
// Receive interrupts
|
||||
#define RXINT (RXFIFONE | RXOVFERR)
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Name: serial_init
|
||||
Purpose: Initalize the UART
|
||||
-------------------------------------------------------------------------- */
|
||||
void __init serial_init(void)
|
||||
{
|
||||
u32 tmpVal = SER63XX_DEFAULT_BAUD;
|
||||
ULONG clockFreqHz;
|
||||
|
||||
#if defined(CONFIG_BCM96345)
|
||||
// Make sure clock is ticking
|
||||
PERF->blkEnables |= UART_CLK_EN;
|
||||
#endif
|
||||
|
||||
/* Dissable channel's receiver and transmitter. */
|
||||
stUart->control &= ~(BRGEN|TXEN|RXEN);
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/* Write the table value to the clock select register. */
|
||||
/* DPullen - this is the equation to use: */
|
||||
/* value = clockFreqHz / baud / 32-1; */
|
||||
/* (snmod) Actually you should also take into account any necessary */
|
||||
/* rounding. Divide by 16, look at lsb, if 0, divide by 2 */
|
||||
/* and subtract 1. If 1, just divide by 2 */
|
||||
/*--------------------------------------------------------------------*/
|
||||
clockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT;
|
||||
tmpVal = (clockFreqHz / tmpVal) / 16;
|
||||
if( tmpVal & 0x01 )
|
||||
tmpVal /= 2; //Rounding up, so sub is already accounted for
|
||||
else
|
||||
tmpVal = (tmpVal / 2) - 1; // Rounding down so we must sub 1
|
||||
stUart->baudword = tmpVal;
|
||||
|
||||
/* Finally, re-enable the transmitter and receiver. */
|
||||
stUart->control |= (BRGEN|TXEN|RXEN);
|
||||
|
||||
stUart->config = (BITS8SYM | ONESTOP);
|
||||
// Set the FIFO interrupt depth ... stUart->fifocfg = 0xAA;
|
||||
stUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
|
||||
stUart->intMask = 0;
|
||||
stUart->intMask = RXINT | TXINT;
|
||||
}
|
||||
|
||||
|
||||
/* prom_putc()
|
||||
* Output a character to the UART
|
||||
*/
|
||||
void prom_putc(char c)
|
||||
{
|
||||
/* Wait for Tx uffer to empty */
|
||||
while (! (READ16(stUart->intStatus) & TXFIFOEMT));
|
||||
/* Send character */
|
||||
stUart->Data = c;
|
||||
}
|
||||
|
||||
/* prom_puts()
|
||||
* Write a string to the UART
|
||||
*/
|
||||
void prom_puts(const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s == '\n') {
|
||||
prom_putc('\r');
|
||||
}
|
||||
prom_putc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* prom_getc_nowait()
|
||||
* Returns a character from the UART
|
||||
* Returns -1 if no characters available or corrupted
|
||||
*/
|
||||
int prom_getc_nowait(void)
|
||||
{
|
||||
uint16 uStatus;
|
||||
int cData = -1;
|
||||
|
||||
uStatus = READ16(stUart->intStatus);
|
||||
|
||||
if (uStatus & RXFIFONE) { /* Do we have a character? */
|
||||
cData = READ16(stUart->Data) & 0xff; /* Read character */
|
||||
if (uStatus & (RXFRAMERR | RXPARERR)) { /* If we got an error, throw it away */
|
||||
cData = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return cData;
|
||||
}
|
||||
|
||||
/* prom_getc()
|
||||
* Returns a charcter from the serial port
|
||||
* Will block until it receives a valid character
|
||||
*/
|
||||
char prom_getc(void)
|
||||
{
|
||||
int cData = -1;
|
||||
|
||||
/* Loop until we get a valid character */
|
||||
while(cData == -1) {
|
||||
cData = prom_getc_nowait();
|
||||
}
|
||||
return (char) cData;
|
||||
}
|
||||
|
||||
/* prom_testc()
|
||||
* Returns 0 if no characters available
|
||||
*/
|
||||
int prom_testc(void)
|
||||
{
|
||||
uint16 uStatus;
|
||||
|
||||
uStatus = READ16(stUart->intStatus);
|
||||
|
||||
return (uStatus & RXFIFONE);
|
||||
}
|
||||
|
||||
#if defined (CONFIG_REMOTE_DEBUG)
|
||||
/* Prevent other code from writing to the serial port */
|
||||
void _putc(char c) { }
|
||||
void _puts(const char *ptr) { }
|
||||
#else
|
||||
/* Low level outputs call prom routines */
|
||||
void _putc(char c) {
|
||||
prom_putc(c);
|
||||
}
|
||||
void _puts(const char *ptr) {
|
||||
prom_puts(ptr);
|
||||
}
|
||||
#endif
|
||||
472
target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c
Normal file
472
target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c
Normal file
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
<:copyright-gpl
|
||||
Copyright 2002 Broadcom Corp. 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.
|
||||
:>
|
||||
*/
|
||||
/*
|
||||
* Generic setup routines for Broadcom 963xx MIPS boards
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bcache.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/mach-bcm963xx/bootloaders.h>
|
||||
|
||||
extern void brcm_time_init(void);
|
||||
extern int boot_loader_type;
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <bcm_map_part.h>
|
||||
#include <6348_map_part.h>
|
||||
#include <bcmpci.h>
|
||||
|
||||
static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
|
||||
|
||||
/* This function should be in a board specific directory. For now,
|
||||
* assume that all boards that include this file use a Broadcom chip
|
||||
* with a soft reset bit in the PLL control register.
|
||||
*/
|
||||
static void brcm_machine_restart(char *command)
|
||||
{
|
||||
const unsigned long ulSoftReset = 0x00000001;
|
||||
unsigned long *pulPllCtrl = (unsigned long *) 0xfffe0008;
|
||||
*pulPllCtrl |= ulSoftReset;
|
||||
}
|
||||
|
||||
static void brcm_machine_halt(void)
|
||||
{
|
||||
printk("System halted\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
static void mpi_SetLocalPciConfigReg(uint32 reg, uint32 value)
|
||||
{
|
||||
/* write index then value */
|
||||
mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
|
||||
mpi->pcicfgdata = value;
|
||||
}
|
||||
|
||||
static uint32 mpi_GetLocalPciConfigReg(uint32 reg)
|
||||
{
|
||||
/* write index then get value */
|
||||
mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
|
||||
return mpi->pcicfgdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* mpi_ResetPcCard: Set/Reset the PcCard
|
||||
*/
|
||||
static void mpi_ResetPcCard(int cardtype, BOOL bReset)
|
||||
{
|
||||
if (cardtype == MPI_CARDTYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cardtype == MPI_CARDTYPE_CARDBUS) {
|
||||
bReset = ! bReset;
|
||||
}
|
||||
|
||||
if (bReset) {
|
||||
mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
|
||||
} else {
|
||||
mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 | PCCARD_CARD_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mpi_ConfigCs: Configure an MPI/EBI chip select
|
||||
*/
|
||||
static void mpi_ConfigCs(uint32 cs, uint32 base, uint32 size, uint32 flags)
|
||||
{
|
||||
mpi->cs[cs].base = ((base & 0x1FFFFFFF) | size);
|
||||
mpi->cs[cs].config = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* mpi_InitPcmciaSpace
|
||||
*/
|
||||
static void mpi_InitPcmciaSpace(void)
|
||||
{
|
||||
// ChipSelect 4 controls PCMCIA Memory accesses
|
||||
mpi_ConfigCs(PCMCIA_COMMON_BASE, pcmciaMem, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
|
||||
// ChipSelect 5 controls PCMCIA Attribute accesses
|
||||
mpi_ConfigCs(PCMCIA_ATTRIBUTE_BASE, pcmciaAttr, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
|
||||
// ChipSelect 6 controls PCMCIA I/O accesses
|
||||
mpi_ConfigCs(PCMCIA_IO_BASE, pcmciaIo, EBI_SIZE_64K, (EBI_WORD_WIDE|EBI_ENABLE));
|
||||
|
||||
mpi->pcmcia_cntl2 = ((PCMCIA_ATTR_ACTIVE << RW_ACTIVE_CNT_BIT) |
|
||||
(PCMCIA_ATTR_INACTIVE << INACTIVE_CNT_BIT) |
|
||||
(PCMCIA_ATTR_CE_SETUP << CE_SETUP_CNT_BIT) |
|
||||
(PCMCIA_ATTR_CE_HOLD << CE_HOLD_CNT_BIT));
|
||||
|
||||
mpi->pcmcia_cntl2 |= (PCMCIA_HALFWORD_EN | PCMCIA_BYTESWAP_DIS);
|
||||
}
|
||||
|
||||
/*
|
||||
* cardtype_vcc_detect: PC Card's card detect and voltage sense connection
|
||||
*
|
||||
* CD1#/ CD2#/ VS1#/ VS2#/ Card Initial Vcc
|
||||
* CCD1# CCD2# CVS1 CVS2 Type
|
||||
*
|
||||
* GND GND open open 16-bit 5 vdc
|
||||
*
|
||||
* GND GND GND open 16-bit 3.3 vdc
|
||||
*
|
||||
* GND GND open GND 16-bit x.x vdc
|
||||
*
|
||||
* GND GND GND GND 16-bit 3.3 & x.x vdc
|
||||
*
|
||||
*====================================================================
|
||||
*
|
||||
* CVS1 GND CCD1# open CardBus 3.3 vdc
|
||||
*
|
||||
* GND CVS2 open CCD2# CardBus x.x vdc
|
||||
*
|
||||
* GND CVS1 CCD2# open CardBus y.y vdc
|
||||
*
|
||||
* GND CVS2 GND CCD2# CardBus 3.3 & x.x vdc
|
||||
*
|
||||
* CVS2 GND open CCD1# CardBus x.x & y.y vdc
|
||||
*
|
||||
* GND CVS1 CCD2# open CardBus 3.3, x.x & y.y vdc
|
||||
*
|
||||
*/
|
||||
static int cardtype_vcc_detect(void)
|
||||
{
|
||||
uint32 data32;
|
||||
int cardtype;
|
||||
|
||||
cardtype = MPI_CARDTYPE_NONE;
|
||||
mpi->pcmcia_cntl1 = 0x0000A000; // Turn on the output enables and drive
|
||||
// the CVS pins to 0.
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
switch (data32 & 0x00000003) // Test CD1# and CD2#, see if card is plugged in.
|
||||
{
|
||||
case 0x00000003: // No Card is in the slot.
|
||||
printk("mpi: No Card is in the PCMCIA slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000002: // Partial insertion, No CD2#.
|
||||
printk("mpi: Card in the PCMCIA slot partial insertion, no CD2 signal\n");
|
||||
break;
|
||||
|
||||
case 0x00000001: // Partial insertion, No CD1#.
|
||||
printk("mpi: Card in the PCMCIA slot partial insertion, no CD1 signal\n");
|
||||
break;
|
||||
|
||||
case 0x00000000:
|
||||
mpi->pcmcia_cntl1 = 0x0000A0C0; // Turn off the CVS output enables and
|
||||
// float the CVS pins.
|
||||
mdelay(1);
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
// Read the Register.
|
||||
switch (data32 & 0x0000000C) // See what is on the CVS pins.
|
||||
{
|
||||
case 0x00000000: // CVS1 and CVS2 are tied to ground, only 1 option.
|
||||
printk("mpi: Detected 3.3 & x.x 16-bit PCMCIA card\n");
|
||||
cardtype = MPI_CARDTYPE_PCMCIA;
|
||||
break;
|
||||
|
||||
case 0x00000004: // CVS1 is open or tied to CCD1/CCD2 and CVS2 is tied to ground.
|
||||
// 2 valid voltage options.
|
||||
switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
|
||||
{
|
||||
case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
|
||||
// This is not a valid combination.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
|
||||
mpi->pcmcia_cntl1 = 0x0000A080; // Drive CVS1 to a 0.
|
||||
mdelay(1);
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
if (data32 & 0x00000002) { // CCD2 is tied to CVS2, not valid.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
} else { // CCD2 is tied to CVS1.
|
||||
printk("mpi: Detected 3.3, x.x and y.y Cardbus card\n");
|
||||
cardtype = MPI_CARDTYPE_CARDBUS;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
|
||||
// This is not a valid combination.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000000: // CCD1 and CCD2 are tied to ground.
|
||||
printk("mpi: Detected x.x vdc 16-bit PCMCIA card\n");
|
||||
cardtype = MPI_CARDTYPE_PCMCIA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x00000008: // CVS2 is open or tied to CCD1/CCD2 and CVS1 is tied to ground.
|
||||
// 2 valid voltage options.
|
||||
switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
|
||||
{
|
||||
case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
|
||||
// This is not a valid combination.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
|
||||
mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
|
||||
mdelay(1);
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
if (data32 & 0x00000002) { // CCD2 is tied to CVS1, not valid.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
} else {// CCD2 is tied to CVS2.
|
||||
printk("mpi: Detected 3.3 and x.x Cardbus card\n");
|
||||
cardtype = MPI_CARDTYPE_CARDBUS;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
|
||||
// This is not a valid combination.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000000: // CCD1 and CCD2 are tied to ground.
|
||||
cardtype = MPI_CARDTYPE_PCMCIA;
|
||||
printk("mpi: Detected 3.3 vdc 16-bit PCMCIA card\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0000000C: // CVS1 and CVS2 are open or tied to CCD1/CCD2.
|
||||
// 5 valid voltage options.
|
||||
|
||||
switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
|
||||
{
|
||||
case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
|
||||
// This is not a valid combination.
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
|
||||
// CCD1 is tied to ground.
|
||||
mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
|
||||
mdelay(1);
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
if (data32 & 0x00000002) { // CCD2 is tied to CVS1.
|
||||
printk("mpi: Detected y.y vdc Cardbus card\n");
|
||||
} else { // CCD2 is tied to CVS2.
|
||||
printk("mpi: Detected x.x vdc Cardbus card\n");
|
||||
}
|
||||
cardtype = MPI_CARDTYPE_CARDBUS;
|
||||
break;
|
||||
|
||||
case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
|
||||
// CCD2 is tied to ground.
|
||||
|
||||
mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
|
||||
mdelay(1);
|
||||
data32 = mpi->pcmcia_cntl1;
|
||||
if (data32 & 0x00000001) {// CCD1 is tied to CVS1.
|
||||
printk("mpi: Detected 3.3 vdc Cardbus card\n");
|
||||
} else { // CCD1 is tied to CVS2.
|
||||
printk("mpi: Detected x.x and y.y Cardbus card\n");
|
||||
}
|
||||
cardtype = MPI_CARDTYPE_CARDBUS;
|
||||
break;
|
||||
|
||||
case 0x00000000: // CCD1 and CCD2 are tied to ground.
|
||||
cardtype = MPI_CARDTYPE_PCMCIA;
|
||||
printk("mpi: Detected 5 vdc 16-bit PCMCIA card\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("mpi: Unknown card plugged into slot\n");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return cardtype;
|
||||
}
|
||||
|
||||
/*
|
||||
* mpi_DetectPcCard: Detect the plugged in PC-Card
|
||||
* Return: < 0 => Unknown card detected
|
||||
* 0 => No card detected
|
||||
* 1 => 16-bit card detected
|
||||
* 2 => 32-bit CardBus card detected
|
||||
*/
|
||||
static int mpi_DetectPcCard(void)
|
||||
{
|
||||
int cardtype;
|
||||
|
||||
cardtype = cardtype_vcc_detect();
|
||||
switch(cardtype) {
|
||||
case MPI_CARDTYPE_PCMCIA:
|
||||
mpi->pcmcia_cntl1 &= ~0x0000e000; // disable enable bits
|
||||
//mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
|
||||
mpi->pcmcia_cntl1 |= (PCMCIA_ENABLE | PCMCIA_GPIO_ENABLE);
|
||||
mpi_InitPcmciaSpace();
|
||||
mpi_ResetPcCard(cardtype, FALSE);
|
||||
// Hold card in reset for 10ms
|
||||
mdelay(10);
|
||||
mpi_ResetPcCard(cardtype, TRUE);
|
||||
// Let card come out of reset
|
||||
mdelay(100);
|
||||
break;
|
||||
case MPI_CARDTYPE_CARDBUS:
|
||||
// 8 => CardBus Enable
|
||||
// 1 => PCI Slot Number
|
||||
// C => Float VS1 & VS2
|
||||
mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & 0xFFFF0000) |
|
||||
CARDBUS_ENABLE |
|
||||
(CARDBUS_SLOT << 8)|
|
||||
VS2_OEN |
|
||||
VS1_OEN;
|
||||
/* access to this memory window will be to/from CardBus */
|
||||
mpi->l2pmremap1 |= CARDBUS_MEM;
|
||||
|
||||
// Need to reset the Cardbus Card. There's no CardManager to do this,
|
||||
// and we need to be ready for PCI configuration.
|
||||
mpi_ResetPcCard(cardtype, FALSE);
|
||||
// Hold card in reset for 10ms
|
||||
mdelay(10);
|
||||
mpi_ResetPcCard(cardtype, TRUE);
|
||||
// Let card come out of reset
|
||||
mdelay(100);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return cardtype;
|
||||
}
|
||||
|
||||
static int mpi_init(void)
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned int chipid, chiprev, sdramsize;
|
||||
|
||||
printk("Broadcom BCM963xx MPI\n");
|
||||
chipid = (PERF->RevID & 0xFFFF0000) >> 16;
|
||||
chiprev = (PERF->RevID & 0xFF);
|
||||
|
||||
if (boot_loader_type == BOOT_LOADER_CFE)
|
||||
sdramsize = boot_mem_map.map[0].size;
|
||||
else
|
||||
sdramsize = 0x01000000;
|
||||
/*
|
||||
* Init the pci interface
|
||||
*/
|
||||
data = GPIO->GPIOMode; // GPIO mode register
|
||||
data |= GROUP2_PCI | GROUP1_MII_PCCARD; // PCI internal arbiter + Cardbus
|
||||
GPIO->GPIOMode = data; // PCI internal arbiter
|
||||
|
||||
/*
|
||||
* In the BCM6348 CardBus support is defaulted to Slot 0
|
||||
* because there is no external IDSEL for CardBus. To disable
|
||||
* the CardBus and allow a standard PCI card in Slot 0
|
||||
* set the cbus_idsel field to 0x1f.
|
||||
*/
|
||||
/*
|
||||
uData = mpi->pcmcia_cntl1;
|
||||
uData |= CARDBUS_IDSEL;
|
||||
mpi->pcmcia_cntl1 = uData;
|
||||
*/
|
||||
// Setup PCI I/O Window range. Give 64K to PCI I/O
|
||||
mpi->l2piorange = ~(BCM_PCI_IO_SIZE_64KB-1);
|
||||
// UBUS to PCI I/O base address
|
||||
mpi->l2piobase = BCM_PCI_IO_BASE & BCM_PCI_ADDR_MASK;
|
||||
// UBUS to PCI I/O Window remap
|
||||
mpi->l2pioremap = (BCM_PCI_IO_BASE | MEM_WINDOW_EN);
|
||||
|
||||
// enable PCI related GPIO pins and data swap between system and PCI bus
|
||||
mpi->locbuscntrl = (EN_PCI_GPIO | DIR_U2P_NOSWAP);
|
||||
|
||||
/* Enable 6348 BusMaster and Memory access mode */
|
||||
data = mpi_GetLocalPciConfigReg(PCI_COMMAND);
|
||||
data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
||||
mpi_SetLocalPciConfigReg(PCI_COMMAND, data);
|
||||
|
||||
/* Configure two 16 MByte PCI to System memory regions. */
|
||||
/* These memory regions are used when PCI device is a bus master */
|
||||
/* Accesses to the SDRAM from PCI bus will be "byte swapped" for this region */
|
||||
mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_3, BCM_HOST_MEM_SPACE1);
|
||||
mpi->sp0remap = 0x0;
|
||||
|
||||
/* Accesses to the SDRAM from PCI bus will not be "byte swapped" for this region */
|
||||
mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_4, BCM_HOST_MEM_SPACE2);
|
||||
mpi->sp1remap = 0x0;
|
||||
mpi->pcimodesel |= (PCI_BAR2_NOSWAP | 0x40);
|
||||
|
||||
if ((chipid == 0x6348) && (chiprev == 0xb0)) {
|
||||
mpi->sp0range = ~(sdramsize-1);
|
||||
mpi->sp1range = ~(sdramsize-1);
|
||||
}
|
||||
/*
|
||||
* Change 6348 PCI Cfg Reg. offset 0x40 to PCI memory read retry count infinity
|
||||
* by set 0 in bit 8~15. This resolve read Bcm4306 srom return 0xffff in
|
||||
* first read.
|
||||
*/
|
||||
data = mpi_GetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER);
|
||||
data &= ~BRCM_PCI_CONFIG_TIMER_RETRY_MASK;
|
||||
data |= 0x00000080;
|
||||
mpi_SetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER, data);
|
||||
|
||||
/* enable pci interrupt */
|
||||
mpi->locintstat |= (EXT_PCI_INT << 16);
|
||||
|
||||
mpi_DetectPcCard();
|
||||
|
||||
ioport_resource.start = BCM_PCI_IO_BASE;
|
||||
ioport_resource.end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB;
|
||||
|
||||
#if defined(CONFIG_USB)
|
||||
PERF->blkEnables |= USBH_CLK_EN;
|
||||
mdelay(100);
|
||||
*USBH_NON_OHCI = NON_OHCI_BYTE_SWAP;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
_machine_restart = brcm_machine_restart;
|
||||
_machine_halt = brcm_machine_halt;
|
||||
pm_power_off = brcm_machine_halt;
|
||||
|
||||
board_time_init = brcm_time_init;
|
||||
|
||||
/* mpi initialization */
|
||||
mpi_init();
|
||||
}
|
||||
116
target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c
Normal file
116
target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
<:copyright-gpl
|
||||
Copyright 2004 Broadcom Corp. 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.
|
||||
:>
|
||||
*/
|
||||
/*
|
||||
* Setup time for Broadcom 963xx MIPS boards
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/div64.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
#include <6348_map_part.h>
|
||||
#include <6348_intr.h>
|
||||
#include <bcm_map_part.h>
|
||||
#include <bcm_intr.h>
|
||||
|
||||
static unsigned long r4k_offset; /* Amount to increment compare reg each time */
|
||||
static unsigned long r4k_cur; /* What counter should be at next timer irq */
|
||||
|
||||
/* *********************************************************************
|
||||
* calculateCpuSpeed()
|
||||
* Calculate the BCM6348 CPU speed by reading the PLL strap register
|
||||
* and applying the following formula:
|
||||
* cpu_clk = (.25 * 64MHz freq) * (N1 + 1) * (N2 + 2) / (M1_CPU + 1)
|
||||
* Input parameters:
|
||||
* none
|
||||
* Return value:
|
||||
* none
|
||||
********************************************************************* */
|
||||
|
||||
static inline unsigned long __init calculateCpuSpeed(void)
|
||||
{
|
||||
u32 pllStrap = PERF->PllStrap;
|
||||
int n1 = (pllStrap & PLL_N1_MASK) >> PLL_N1_SHFT;
|
||||
int n2 = (pllStrap & PLL_N2_MASK) >> PLL_N2_SHFT;
|
||||
int m1cpu = (pllStrap & PLL_M1_CPU_MASK) >> PLL_M1_CPU_SHFT;
|
||||
|
||||
return (16 * (n1 + 1) * (n2 + 2) / (m1cpu + 1)) * 1000000;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned long __init cal_r4koff(void)
|
||||
{
|
||||
mips_hpt_frequency = calculateCpuSpeed() / 2;
|
||||
return (mips_hpt_frequency / HZ);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* There are a lot of conceptually broken versions of the MIPS timer interrupt
|
||||
* handler floating around. This one is rather different, but the algorithm
|
||||
* is provably more robust.
|
||||
*/
|
||||
irqreturn_t brcm_timer_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
int irq = MIPS_TIMER_INT;
|
||||
|
||||
irq_enter();
|
||||
kstat_this_cpu.irqs[irq]++;
|
||||
|
||||
timer_interrupt(irq, regs);
|
||||
irq_exit();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
void __init brcm_time_init(void)
|
||||
{
|
||||
unsigned int est_freq, flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
printk("calculating r4koff... ");
|
||||
r4k_offset = cal_r4koff();
|
||||
printk("%08lx(%d)\n", r4k_offset, (int)r4k_offset);
|
||||
|
||||
est_freq = 2 * r4k_offset * HZ;
|
||||
est_freq += 5000; /* round */
|
||||
est_freq -= est_freq % 10000;
|
||||
printk("CPU frequency %d.%02d MHz\n", est_freq / 1000000,
|
||||
(est_freq % 1000000) * 100 / 1000000);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
void __init plat_timer_setup(struct irqaction *irq)
|
||||
{
|
||||
r4k_cur = (read_c0_count() + r4k_offset);
|
||||
write_c0_compare(r4k_cur);
|
||||
set_c0_status(IE_IRQ5);
|
||||
}
|
||||
246
target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c
Normal file
246
target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Watchdog driver for the BCM963xx devices
|
||||
*
|
||||
* Copyright (C) 2007 OpenWrt.org
|
||||
* Florian Fainelli <florian@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
typedef struct bcm963xx_timer {
|
||||
unsigned short unused0;
|
||||
unsigned char timer_mask;
|
||||
#define TIMER0EN 0x01
|
||||
#define TIMER1EN 0x02
|
||||
#define TIMER2EN 0x04
|
||||
unsigned char timer_ints;
|
||||
#define TIMER0 0x01
|
||||
#define TIMER1 0x02
|
||||
#define TIMER2 0x04
|
||||
#define WATCHDOG 0x08
|
||||
unsigned long timer_ctl0;
|
||||
unsigned long timer_ctl1;
|
||||
unsigned long timer_ctl2;
|
||||
#define TIMERENABLE 0x80000000
|
||||
#define RSTCNTCLR 0x40000000
|
||||
unsigned long timer_cnt0;
|
||||
unsigned long timer_cnt1;
|
||||
unsigned long timer_cnt2;
|
||||
unsigned long wdt_def_count;
|
||||
|
||||
/* Write 0xff00 0x00ff to Start timer
|
||||
* Write 0xee00 0x00ee to Stop and re-load default count
|
||||
* Read from this register returns current watch dog count
|
||||
*/
|
||||
unsigned long wdt_ctl;
|
||||
|
||||
/* Number of 40-MHz ticks for WD Reset pulse to last */
|
||||
unsigned long wdt_rst_count;
|
||||
} bcm963xx_timer;
|
||||
|
||||
static struct bcm963xx_wdt_device {
|
||||
struct completion stop;
|
||||
volatile int running;
|
||||
struct timer_list timer;
|
||||
volatile int queue;
|
||||
int default_ticks;
|
||||
unsigned long inuse;
|
||||
} bcm963xx_wdt_device;
|
||||
|
||||
static int ticks = 1000;
|
||||
|
||||
#define WDT_BASE 0xfffe0200
|
||||
#define WDT ((volatile bcm963xx_timer * const) WDT_BASE)
|
||||
|
||||
#define BCM963XX_INTERVAL (HZ/10+1)
|
||||
|
||||
static void bcm963xx_wdt_trigger(unsigned long unused)
|
||||
{
|
||||
if (bcm963xx_wdt_device.running)
|
||||
ticks--;
|
||||
|
||||
/* Load the default ticking value into the reset counter register */
|
||||
WDT->wdt_rst_count = bcm963xx_wdt_device.default_ticks;
|
||||
|
||||
if (bcm963xx_wdt_device.queue && ticks) {
|
||||
bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL;
|
||||
add_timer(&bcm963xx_wdt_device.timer);
|
||||
}
|
||||
else {
|
||||
complete(&bcm963xx_wdt_device.stop);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm963xx_wdt_reset(void)
|
||||
{
|
||||
ticks = bcm963xx_wdt_device.default_ticks;
|
||||
/* Also reload default count */
|
||||
WDT->wdt_def_count = ticks;
|
||||
WDT->wdt_ctl = 0xee00;
|
||||
WDT->wdt_ctl = 0x00ee;
|
||||
}
|
||||
|
||||
static void bcm963xx_wdt_start(void)
|
||||
{
|
||||
if (!bcm963xx_wdt_device.queue) {
|
||||
bcm963xx_wdt_device.queue;
|
||||
/* Enable the watchdog by writing 0xff00 ,then 0x00ff to the control register */
|
||||
WDT->wdt_ctl = 0xff00;
|
||||
WDT->wdt_ctl = 0x00ff;
|
||||
bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL;
|
||||
add_timer(&bcm963xx_wdt_device.timer);
|
||||
}
|
||||
bcm963xx_wdt_device.running++;
|
||||
}
|
||||
|
||||
static int bcm963xx_wdt_stop(void)
|
||||
{
|
||||
if (bcm963xx_wdt_device.running)
|
||||
bcm963xx_wdt_device.running = 0;
|
||||
|
||||
ticks = bcm963xx_wdt_device.default_ticks;
|
||||
|
||||
/* Stop the watchdog by writing 0xee00 then 0x00ee to the control register */
|
||||
WDT->wdt_ctl = 0xee00;
|
||||
WDT->wdt_ctl = 0x00ee;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bcm963xx_wdt_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (test_and_set_bit(0, &bcm963xx_wdt_device.inuse))
|
||||
return -EBUSY;
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
||||
static int bcm963xx_wdt_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
clear_bit(0, &bcm963xx_wdt_device.inuse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm963xx_wdt_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
unsigned int value;
|
||||
|
||||
static struct watchdog_info ident = {
|
||||
.options = WDIOF_CARDRESET,
|
||||
.identity = "BCM963xx WDT",
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
case WDIOC_KEEPALIVE:
|
||||
bcm963xx_wdt_reset();
|
||||
break;
|
||||
case WDIOC_GETSTATUS:
|
||||
/* Reading from the control register will return the current value */
|
||||
value = WDT->wdt_ctl;
|
||||
if ( copy_to_user(argp, &value, sizeof(int)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
case WDIOC_GETSUPPORT:
|
||||
if ( copy_to_user(argp, &ident, sizeof(ident)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
case WDIOC_SETOPTIONS:
|
||||
if ( copy_from_user(&value, argp, sizeof(int)) )
|
||||
return -EFAULT;
|
||||
switch(value) {
|
||||
case WDIOS_ENABLECARD:
|
||||
bcm963xx_wdt_start();
|
||||
break;
|
||||
case WDIOS_DISABLECARD:
|
||||
bcm963xx_wdt_stop();
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm963xx_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
if (!count)
|
||||
return -EIO;
|
||||
bcm963xx_wdt_reset();
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations bcm963xx_wdt_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.write = bcm963xx_wdt_write,
|
||||
.ioctl = bcm963xx_wdt_ioctl,
|
||||
.open = bcm963xx_wdt_open,
|
||||
.release = bcm963xx_wdt_release,
|
||||
};
|
||||
|
||||
static struct miscdevice bcm963xx_wdt_miscdev = {
|
||||
.minor = WATCHDOG_MINOR,
|
||||
.name = "watchdog",
|
||||
.fops = &bcm963xx_wdt_fops,
|
||||
};
|
||||
|
||||
static void __exit bcm963xx_wdt_exit(void)
|
||||
{
|
||||
if (bcm963xx_wdt_device.queue ){
|
||||
bcm963xx_wdt_device.queue = 0;
|
||||
wait_for_completion(&bcm963xx_wdt_device.stop);
|
||||
}
|
||||
misc_deregister(&bcm963xx_wdt_miscdev);
|
||||
}
|
||||
|
||||
static int __init bcm963xx_wdt_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
printk("Broadcom BCM963xx Watchdog timer\n");
|
||||
|
||||
ret = misc_register(&bcm963xx_wdt_miscdev);
|
||||
if (ret) {
|
||||
printk(KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret);
|
||||
return ret;
|
||||
}
|
||||
init_completion(&bcm963xx_wdt_device.stop);
|
||||
bcm963xx_wdt_device.queue = 0;
|
||||
|
||||
clear_bit(0, &bcm963xx_wdt_device.inuse);
|
||||
|
||||
init_timer(&bcm963xx_wdt_device.timer);
|
||||
bcm963xx_wdt_device.timer.function = bcm963xx_wdt_trigger;
|
||||
bcm963xx_wdt_device.timer.data = 0;
|
||||
|
||||
bcm963xx_wdt_device.default_ticks = ticks;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
module_init(bcm963xx_wdt_init);
|
||||
module_exit(bcm963xx_wdt_exit);
|
||||
|
||||
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
||||
MODULE_DESCRIPTION("Broadcom BCM963xx Watchdog driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user