mirror of https://github.com/hak5/openwrt.git
473 lines
16 KiB
C
473 lines
16 KiB
C
|
/*
|
||
|
<: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();
|
||
|
}
|