mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-14 03:26:15 +02:00
7ed9009bbd
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7092 3c298f89-4303-0410-b956-a3cf2f4a3e73
1133 lines
33 KiB
C
1133 lines
33 KiB
C
/*
|
|
* BCM47XX Sonics SiliconBackplane MIPS core routines
|
|
*
|
|
* Copyright 2006, Broadcom Corporation
|
|
* All Rights Reserved.
|
|
*
|
|
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
|
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
|
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
|
*
|
|
* $Id: hndmips.c,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
|
|
*/
|
|
|
|
#include <typedefs.h>
|
|
#include <bcmdefs.h>
|
|
#include <osl.h>
|
|
#include <bcmutils.h>
|
|
#include <sbutils.h>
|
|
#include <bcmdevs.h>
|
|
#include <bcmnvram.h>
|
|
#include <sbconfig.h>
|
|
#include <sbextif.h>
|
|
#include <sbchipc.h>
|
|
#include <sbmemc.h>
|
|
#include <mipsinc.h>
|
|
#include <sbhndmips.h>
|
|
#include <hndcpu.h>
|
|
|
|
/* sbipsflag register format, indexed by irq. */
|
|
static const uint32 sbips_int_mask[] = {
|
|
0, /* placeholder */
|
|
SBIPS_INT1_MASK,
|
|
SBIPS_INT2_MASK,
|
|
SBIPS_INT3_MASK,
|
|
SBIPS_INT4_MASK
|
|
};
|
|
|
|
static const uint32 sbips_int_shift[] = {
|
|
0, /* placeholder */
|
|
SBIPS_INT1_SHIFT,
|
|
SBIPS_INT2_SHIFT,
|
|
SBIPS_INT3_SHIFT,
|
|
SBIPS_INT4_SHIFT
|
|
};
|
|
|
|
/*
|
|
* Map SB cores sharing the MIPS hardware IRQ0 to virtual dedicated OS IRQs.
|
|
* Per-port BSP code is required to provide necessary translations between
|
|
* the shared MIPS IRQ and the virtual OS IRQs based on SB core flag.
|
|
*
|
|
* See sb_irq() for the mapping.
|
|
*/
|
|
static uint shirq_map_base = 0;
|
|
|
|
/* Returns the SB interrupt flag of the current core. */
|
|
static uint32
|
|
sb_getflag(sb_t *sbh)
|
|
{
|
|
osl_t *osh;
|
|
void *regs;
|
|
sbconfig_t *sb;
|
|
|
|
osh = sb_osh(sbh);
|
|
regs = sb_coreregs(sbh);
|
|
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
|
|
|
|
return (R_REG(osh, &sb->sbtpsflag) & SBTPS_NUM0_MASK);
|
|
}
|
|
|
|
/*
|
|
* Returns the MIPS IRQ assignment of the current core. If unassigned,
|
|
* 0 is returned.
|
|
*/
|
|
uint
|
|
sb_irq(sb_t *sbh)
|
|
{
|
|
osl_t *osh;
|
|
uint idx;
|
|
void *regs;
|
|
sbconfig_t *sb;
|
|
uint32 flag, sbipsflag;
|
|
uint irq = 0;
|
|
|
|
osh = sb_osh(sbh);
|
|
flag = sb_getflag(sbh);
|
|
|
|
idx = sb_coreidx(sbh);
|
|
|
|
if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
|
|
(regs = sb_setcore(sbh, SB_MIPS33, 0))) {
|
|
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
|
|
|
|
/* sbipsflag specifies which core is routed to interrupts 1 to 4 */
|
|
sbipsflag = R_REG(osh, &sb->sbipsflag);
|
|
for (irq = 1; irq <= 4; irq++) {
|
|
if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
|
|
break;
|
|
}
|
|
if (irq == 5)
|
|
irq = 0;
|
|
}
|
|
|
|
sb_setcoreidx(sbh, idx);
|
|
|
|
return irq;
|
|
}
|
|
|
|
/* Clears the specified MIPS IRQ. */
|
|
static void
|
|
BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
|
|
{
|
|
osl_t *osh;
|
|
void *regs;
|
|
sbconfig_t *sb;
|
|
|
|
osh = sb_osh(sbh);
|
|
|
|
if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
|
|
!(regs = sb_setcore(sbh, SB_MIPS33, 0)))
|
|
ASSERT(regs);
|
|
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
|
|
|
|
if (irq == 0)
|
|
W_REG(osh, &sb->sbintvec, 0);
|
|
else
|
|
OR_REG(osh, &sb->sbipsflag, sbips_int_mask[irq]);
|
|
}
|
|
|
|
/*
|
|
* Assigns the specified MIPS IRQ to the specified core. Shared MIPS
|
|
* IRQ 0 may be assigned more than once.
|
|
*
|
|
* The old assignment to the specified core is removed first.
|
|
*/
|
|
static void
|
|
BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
|
|
{
|
|
osl_t *osh;
|
|
void *regs;
|
|
sbconfig_t *sb;
|
|
uint32 flag;
|
|
uint oldirq;
|
|
|
|
osh = sb_osh(sbh);
|
|
|
|
regs = sb_setcore(sbh, coreid, coreunit);
|
|
ASSERT(regs);
|
|
flag = sb_getflag(sbh);
|
|
oldirq = sb_irq(sbh);
|
|
if (oldirq)
|
|
sb_clearirq(sbh, oldirq);
|
|
|
|
if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
|
|
!(regs = sb_setcore(sbh, SB_MIPS33, 0)))
|
|
ASSERT(regs);
|
|
sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
|
|
|
|
if (!oldirq)
|
|
AND_REG(osh, &sb->sbintvec, ~(1 << flag));
|
|
|
|
if (irq == 0)
|
|
OR_REG(osh, &sb->sbintvec, 1 << flag);
|
|
else {
|
|
flag <<= sbips_int_shift[irq];
|
|
ASSERT(!(flag & ~sbips_int_mask[irq]));
|
|
flag |= R_REG(osh, &sb->sbipsflag) & ~sbips_int_mask[irq];
|
|
W_REG(osh, &sb->sbipsflag, flag);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes clocks and interrupts. SB and NVRAM access must be
|
|
* initialized prior to calling.
|
|
*
|
|
* 'shirqmap' enables virtual dedicated OS IRQ mapping if non-zero.
|
|
*/
|
|
void
|
|
BCMINITFN(sb_mips_init)(sb_t *sbh, uint shirqmap)
|
|
{
|
|
osl_t *osh;
|
|
ulong hz, ns, tmp;
|
|
extifregs_t *eir;
|
|
chipcregs_t *cc;
|
|
char *value;
|
|
uint irq;
|
|
|
|
osh = sb_osh(sbh);
|
|
|
|
/* Figure out current SB clock speed */
|
|
if ((hz = sb_clock(sbh)) == 0)
|
|
hz = 100000000;
|
|
ns = 1000000000 / hz;
|
|
|
|
/* Setup external interface timing */
|
|
if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
|
|
/* Initialize extif so we can get to the LEDs and external UART */
|
|
W_REG(osh, &eir->prog_config, CF_EN);
|
|
|
|
/* Set timing for the flash */
|
|
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
|
|
tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
|
|
tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
|
|
W_REG(osh, &eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
|
|
|
|
/* Set programmable interface timing for external uart */
|
|
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
|
|
tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
|
|
tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
|
|
tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
|
|
W_REG(osh, &eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
|
|
} else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
|
|
/* Set timing for the flash */
|
|
tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
|
|
tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
|
|
tmp |= CEIL(120, ns); /* W0 = 120nS */
|
|
if ((sb_corerev(sbh) < 9) ||
|
|
(BCMINIT(sb_chip)(sbh) == 0x5365))
|
|
W_REG(osh, &cc->flash_waitcount, tmp);
|
|
|
|
if ((sb_corerev(sbh) < 9) ||
|
|
((sb_chip(sbh) == BCM5350_CHIP_ID) && sb_chiprev(sbh) == 0) ||
|
|
(BCMINIT(sb_chip)(sbh) == 0x5365)) {
|
|
W_REG(osh, &cc->pcmcia_memwait, tmp);
|
|
}
|
|
|
|
/* Save shared IRQ mapping base */
|
|
shirq_map_base = shirqmap;
|
|
}
|
|
|
|
/* Chip specific initialization */
|
|
switch (sb_chip(sbh)) {
|
|
case BCM4710_CHIP_ID:
|
|
/* Clear interrupt map */
|
|
for (irq = 0; irq <= 4; irq++)
|
|
sb_clearirq(sbh, irq);
|
|
sb_setirq(sbh, 0, SB_CODEC, 0);
|
|
sb_setirq(sbh, 0, SB_EXTIF, 0);
|
|
sb_setirq(sbh, 2, SB_ENET, 1);
|
|
sb_setirq(sbh, 3, SB_ILINE20, 0);
|
|
sb_setirq(sbh, 4, SB_PCI, 0);
|
|
ASSERT(eir);
|
|
value = nvram_get("et0phyaddr");
|
|
if (value && !strcmp(value, "31")) {
|
|
/* Enable internal UART */
|
|
W_REG(osh, &eir->corecontrol, CC_UE);
|
|
/* Give USB its own interrupt */
|
|
sb_setirq(sbh, 1, SB_USB, 0);
|
|
} else {
|
|
/* Disable internal UART */
|
|
W_REG(osh, &eir->corecontrol, 0);
|
|
/* Give Ethernet its own interrupt */
|
|
sb_setirq(sbh, 1, SB_ENET, 0);
|
|
sb_setirq(sbh, 0, SB_USB, 0);
|
|
}
|
|
break;
|
|
case BCM5350_CHIP_ID:
|
|
/* Clear interrupt map */
|
|
for (irq = 0; irq <= 4; irq++)
|
|
sb_clearirq(sbh, irq);
|
|
sb_setirq(sbh, 0, SB_CC, 0);
|
|
sb_setirq(sbh, 0, SB_MIPS33, 0);
|
|
sb_setirq(sbh, 1, SB_D11, 0);
|
|
sb_setirq(sbh, 2, SB_ENET, 0);
|
|
sb_setirq(sbh, 3, SB_PCI, 0);
|
|
sb_setirq(sbh, 4, SB_USB, 0);
|
|
break;
|
|
case BCM4785_CHIP_ID:
|
|
/* Reassign PCI to irq 4 */
|
|
sb_setirq(sbh, 4, SB_PCI, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32
|
|
BCMINITFN(sb_cpu_clock)(sb_t *sbh)
|
|
{
|
|
extifregs_t *eir;
|
|
chipcregs_t *cc;
|
|
uint32 n, m;
|
|
uint idx;
|
|
uint32 pll_type, rate = 0;
|
|
|
|
/* get index of the current core */
|
|
idx = sb_coreidx(sbh);
|
|
pll_type = PLL_TYPE1;
|
|
|
|
/* switch to extif or chipc core */
|
|
if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
|
|
n = R_REG(osh, &eir->clockcontrol_n);
|
|
m = R_REG(osh, &eir->clockcontrol_sb);
|
|
} else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
|
|
pll_type = R_REG(osh, &cc->capabilities) & CAP_PLL_MASK;
|
|
n = R_REG(osh, &cc->clockcontrol_n);
|
|
if ((pll_type == PLL_TYPE2) ||
|
|
(pll_type == PLL_TYPE4) ||
|
|
(pll_type == PLL_TYPE6) ||
|
|
(pll_type == PLL_TYPE7))
|
|
m = R_REG(osh, &cc->clockcontrol_m3);
|
|
else if (pll_type == PLL_TYPE5) {
|
|
rate = 200000000;
|
|
goto out;
|
|
}
|
|
else if (pll_type == PLL_TYPE3) {
|
|
if (sb_chip(sbh) == BCM5365_CHIP_ID) {
|
|
rate = 200000000;
|
|
goto out;
|
|
}
|
|
/* 5350 uses m2 to control mips */
|
|
else
|
|
m = R_REG(osh, &cc->clockcontrol_m2);
|
|
} else
|
|
m = R_REG(osh, &cc->clockcontrol_sb);
|
|
} else
|
|
goto out;
|
|
|
|
|
|
/* calculate rate */
|
|
if (BCMINIT(sb_chip)(sbh) == 0x5365)
|
|
rate = 100000000;
|
|
else
|
|
rate = sb_clock_rate(pll_type, n, m);
|
|
|
|
if (pll_type == PLL_TYPE6)
|
|
rate = SB2MIPS_T6(rate);
|
|
|
|
out:
|
|
/* switch back to previous core */
|
|
sb_setcoreidx(sbh, idx);
|
|
|
|
return rate;
|
|
}
|
|
|
|
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
|
|
|
|
static void
|
|
BCMINITFN(handler)(void)
|
|
{
|
|
__asm__(
|
|
".set\tmips32\n\t"
|
|
"ssnop\n\t"
|
|
"ssnop\n\t"
|
|
/* Disable interrupts */
|
|
/* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
|
|
"mfc0 $15, $12\n\t"
|
|
/* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
|
|
"li $14, -31746\n\t"
|
|
"and $15, $15, $14\n\t"
|
|
"mtc0 $15, $12\n\t"
|
|
"eret\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
".set\tmips0");
|
|
}
|
|
|
|
/* The following MUST come right after handler() */
|
|
static void
|
|
BCMINITFN(afterhandler)(void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Set the MIPS, backplane and PCI clocks as closely as possible.
|
|
*
|
|
* MIPS clocks synchronization function has been moved from PLL in chipcommon
|
|
* core rev. 15 to a DLL inside the MIPS core in 4785.
|
|
*/
|
|
bool
|
|
BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
|
|
{
|
|
extifregs_t *eir = NULL;
|
|
chipcregs_t *cc = NULL;
|
|
mipsregs_t *mipsr = NULL;
|
|
volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
|
|
uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
|
|
uint32 pll_type, sync_mode;
|
|
uint ic_size, ic_lsize;
|
|
uint idx, i;
|
|
|
|
/* PLL configuration: type 1 */
|
|
typedef struct {
|
|
uint32 mipsclock;
|
|
uint16 n;
|
|
uint32 sb;
|
|
uint32 pci33;
|
|
uint32 pci25;
|
|
} n3m_table_t;
|
|
static n3m_table_t BCMINITDATA(type1_table)[] = {
|
|
/* 96.000 32.000 24.000 */
|
|
{ 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 },
|
|
/* 100.000 33.333 25.000 */
|
|
{ 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 },
|
|
/* 104.000 31.200 24.960 */
|
|
{ 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 },
|
|
/* 108.000 32.400 24.923 */
|
|
{ 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 },
|
|
/* 112.000 32.000 24.889 */
|
|
{ 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 },
|
|
/* 115.200 32.000 24.000 */
|
|
{ 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 },
|
|
/* 120.000 30.000 24.000 */
|
|
{ 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 },
|
|
/* 124.800 31.200 24.960 */
|
|
{ 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 },
|
|
/* 128.000 32.000 24.000 */
|
|
{ 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 },
|
|
/* 132.000 33.000 24.750 */
|
|
{ 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 },
|
|
/* 136.000 32.640 24.727 */
|
|
{ 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 },
|
|
/* 140.000 30.000 24.706 */
|
|
{ 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 },
|
|
/* 144.000 30.857 24.686 */
|
|
{ 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 },
|
|
/* 150.857 33.000 24.000 */
|
|
{ 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 },
|
|
/* 152.000 32.571 24.000 */
|
|
{ 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 },
|
|
/* 156.000 31.200 24.960 */
|
|
{ 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 },
|
|
/* 160.000 32.000 24.000 */
|
|
{ 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 },
|
|
/* 163.200 32.640 24.727 */
|
|
{ 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 },
|
|
/* 168.000 32.000 24.889 */
|
|
{ 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 },
|
|
/* 176.000 33.000 24.000 */
|
|
{ 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 },
|
|
};
|
|
|
|
/* PLL configuration: type 3 */
|
|
typedef struct {
|
|
uint32 mipsclock;
|
|
uint16 n;
|
|
uint32 m2; /* that is the clockcontrol_m2 */
|
|
} type3_table_t;
|
|
static type3_table_t type3_table[] = {
|
|
/* for 5350, mips clock is always double sb clock */
|
|
{ 150000000, 0x311, 0x4020005 },
|
|
{ 200000000, 0x311, 0x4020003 },
|
|
};
|
|
|
|
/* PLL configuration: type 2, 4, 7 */
|
|
typedef struct {
|
|
uint32 mipsclock;
|
|
uint32 sbclock;
|
|
uint16 n;
|
|
uint32 sb;
|
|
uint32 pci33;
|
|
uint32 m2;
|
|
uint32 m3;
|
|
uint32 ratio_cfg;
|
|
uint32 ratio_parm;
|
|
uint32 d11_r1;
|
|
uint32 d11_r2;
|
|
} n4m_table_t;
|
|
static n4m_table_t BCMINITDATA(type2_table)[] = {
|
|
{ 120000000, 60000000, 0x0303, 0x01000200, 0x01000600, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 150000000, 75000000, 0x0303, 0x01000100, 0x01000600, 0x01000100, 0x05000100, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 200000000, 100000000, 0x0303, 0x02010000, 0x02040001, 0x02010000, 0x06000001, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01010100, 0x05000100, 8,
|
|
0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01010100, 0x05000100, 11,
|
|
0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 330000000, 132000000, 0x0903, 0x01000200, 0x00020200, 0x01010100, 0x05000100, 0,
|
|
0, 10 /* ratio 4/10 */, 0x02520129 },
|
|
{ 330000000, 146666666, 0x0903, 0x01010000, 0x00020200, 0x01010100, 0x05000100, 0,
|
|
0, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 330000000, 165000000, 0x0903, 0x01000100, 0x00020200, 0x01010100, 0x05000100, 0,
|
|
0, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 360000000, 120000000, 0x0a03, 0x01000300, 0x00010201, 0x01010200, 0x05000100, 0,
|
|
0, 12 /* ratio 4/12 */, 0x04920492 },
|
|
{ 360000000, 144000000, 0x0a03, 0x01000200, 0x00010201, 0x01010200, 0x05000100, 0,
|
|
0, 10 /* ratio 4/10 */, 0x02520129 },
|
|
{ 360000000, 160000000, 0x0a03, 0x01010000, 0x00010201, 0x01010200, 0x05000100, 0,
|
|
0, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 360000000, 180000000, 0x0a03, 0x01000100, 0x00010201, 0x01010200, 0x05000100, 0,
|
|
0, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
{ 390000000, 130000000, 0x0b03, 0x01010100, 0x00020101, 0x01020100, 0x05000100, 0,
|
|
0, 12 /* ratio 4/12 */, 0x04920492 },
|
|
{ 390000000, 156000000, 0x0b03, 0x01000200, 0x00020101, 0x01020100, 0x05000100, 0,
|
|
0, 10 /* ratio 4/10 */, 0x02520129 },
|
|
{ 390000000, 173000000, 0x0b03, 0x01010000, 0x00020101, 0x01020100, 0x05000100, 0,
|
|
0, 9 /* ratio 4/9 */, 0x012a00a9 },
|
|
{ 390000000, 195000000, 0x0b03, 0x01000100, 0x00020101, 0x01020100, 0x05000100, 0,
|
|
0, 8 /* ratio 4/8 */, 0x00aa0055 },
|
|
};
|
|
static n4m_table_t BCMINITDATA(type4_table)[] = {
|
|
{ 120000000, 60000000, 0x0009, 0x11020009, 0x01030203, 0x11020009, 0x04000009, 11,
|
|
0x0aaa0555 },
|
|
{ 150000000, 75000000, 0x0009, 0x11050002, 0x01030203, 0x11050002, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 192000000, 96000000, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 198000000, 99000000, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11,
|
|
0x0aaa0555 },
|
|
{ 204000000, 102000000, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 208000000, 104000000, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 210000000, 105000000, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 224000000, 112000000, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005, 8,
|
|
0x012a00a9 },
|
|
{ 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 240000000, 102857143, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003, 13,
|
|
0x254a14a9 },
|
|
{ 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 252000000, 100800000, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002, 9,
|
|
0x02520129 },
|
|
{ 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11,
|
|
0x0aaa0555 },
|
|
{ 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11,
|
|
0x0aaa0555 },
|
|
{ 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 13,
|
|
0x254a14a9 },
|
|
{ 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13,
|
|
0x254a14a9 },
|
|
{ 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13,
|
|
0x254a14a9 },
|
|
{ 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 9,
|
|
0x02520129 },
|
|
{ 300000000, 150000000, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002, 11,
|
|
0x0aaa0555 }
|
|
};
|
|
static n4m_table_t BCMINITDATA(type7_table)[] = {
|
|
{ 183333333, 91666666, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 187500000, 93750000, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 196875000, 98437500, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 200000000, 100000000, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 200000000, 100000000, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11,
|
|
0x0aaa0555 },
|
|
{ 206250000, 103125000, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 212500000, 106250000, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 215625000, 107812500, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 216666666, 108333333, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 225000000, 112500000, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 233333333, 116666666, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
|
|
0x0aaa0555 },
|
|
{ 237500000, 118750000, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11,
|
|
0x0aaa0555 },
|
|
{ 240000000, 120000000, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009, 11,
|
|
0x0aaa0555 },
|
|
{ 250000000, 125000000, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003, 11,
|
|
0x0aaa0555 }
|
|
};
|
|
|
|
ulong start, end, dst;
|
|
bool ret = FALSE;
|
|
|
|
volatile uint32 *dll_ctrl = (volatile uint32 *)0xff400008;
|
|
volatile uint32 *dll_r1 = (volatile uint32 *)0xff400010;
|
|
volatile uint32 *dll_r2 = (volatile uint32 *)0xff400018;
|
|
|
|
/* get index of the current core */
|
|
idx = sb_coreidx(sbh);
|
|
clockcontrol_m2 = NULL;
|
|
|
|
/* switch to extif or chipc core */
|
|
if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
|
|
pll_type = PLL_TYPE1;
|
|
clockcontrol_n = &eir->clockcontrol_n;
|
|
clockcontrol_sb = &eir->clockcontrol_sb;
|
|
clockcontrol_pci = &eir->clockcontrol_pci;
|
|
clockcontrol_m2 = &cc->clockcontrol_m2;
|
|
} else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
|
|
pll_type = R_REG(osh, &cc->capabilities) & CAP_PLL_MASK;
|
|
if (pll_type == PLL_TYPE6) {
|
|
clockcontrol_n = NULL;
|
|
clockcontrol_sb = NULL;
|
|
clockcontrol_pci = NULL;
|
|
} else {
|
|
clockcontrol_n = &cc->clockcontrol_n;
|
|
clockcontrol_sb = &cc->clockcontrol_sb;
|
|
clockcontrol_pci = &cc->clockcontrol_pci;
|
|
clockcontrol_m2 = &cc->clockcontrol_m2;
|
|
}
|
|
} else
|
|
goto done;
|
|
|
|
if (pll_type == PLL_TYPE6) {
|
|
/* Silence compilers */
|
|
orig_n = orig_sb = orig_pci = 0;
|
|
} else {
|
|
/* Store the current clock register values */
|
|
orig_n = R_REG(osh, clockcontrol_n);
|
|
orig_sb = R_REG(osh, clockcontrol_sb);
|
|
orig_pci = R_REG(osh, clockcontrol_pci);
|
|
}
|
|
|
|
if (pll_type == PLL_TYPE1) {
|
|
/* Keep the current PCI clock if not specified */
|
|
if (pciclock == 0) {
|
|
pciclock = sb_clock_rate(pll_type, R_REG(osh, clockcontrol_n),
|
|
R_REG(osh, clockcontrol_pci));
|
|
pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
|
|
}
|
|
|
|
/* Search for the closest MIPS clock less than or equal to a preferred value */
|
|
for (i = 0; i < ARRAYSIZE(type1_table); i++) {
|
|
ASSERT(type1_table[i].mipsclock ==
|
|
sb_clock_rate(pll_type, type1_table[i].n,
|
|
type1_table[i].sb));
|
|
if (type1_table[i].mipsclock > mipsclock)
|
|
break;
|
|
}
|
|
if (i == 0) {
|
|
ret = FALSE;
|
|
goto done;
|
|
} else {
|
|
ret = TRUE;
|
|
i--;
|
|
}
|
|
ASSERT(type1_table[i].mipsclock <= mipsclock);
|
|
|
|
/* No PLL change */
|
|
if ((orig_n == type1_table[i].n) &&
|
|
(orig_sb == type1_table[i].sb) &&
|
|
(orig_pci == type1_table[i].pci33))
|
|
goto done;
|
|
|
|
/* Set the PLL controls */
|
|
W_REG(osh, clockcontrol_n, type1_table[i].n);
|
|
W_REG(osh, clockcontrol_sb, type1_table[i].sb);
|
|
if (pciclock == 25000000)
|
|
W_REG(osh, clockcontrol_pci, type1_table[i].pci25);
|
|
else
|
|
W_REG(osh, clockcontrol_pci, type1_table[i].pci33);
|
|
|
|
/* Reset */
|
|
sb_watchdog(sbh, 1);
|
|
while (1);
|
|
} else if (pll_type == PLL_TYPE3) {
|
|
/* 5350 */
|
|
if (sb_chip(sbh) != BCM5365_CHIP_ID) {
|
|
/*
|
|
* Search for the closest MIPS clock less than or equal to
|
|
* a preferred value.
|
|
*/
|
|
for (i = 0; i < ARRAYSIZE(type3_table); i++) {
|
|
if (type3_table[i].mipsclock > mipsclock)
|
|
break;
|
|
}
|
|
if (i == 0) {
|
|
ret = FALSE;
|
|
goto done;
|
|
} else {
|
|
ret = TRUE;
|
|
i--;
|
|
}
|
|
ASSERT(type3_table[i].mipsclock <= mipsclock);
|
|
|
|
/* No PLL change */
|
|
orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
|
|
if ((orig_n == type3_table[i].n) &&
|
|
(orig_m2 == type3_table[i].m2)) {
|
|
goto done;
|
|
}
|
|
|
|
/* Set the PLL controls */
|
|
W_REG(osh, clockcontrol_n, type3_table[i].n);
|
|
W_REG(osh, clockcontrol_m2, type3_table[i].m2);
|
|
|
|
/* Reset */
|
|
sb_watchdog(sbh, 1);
|
|
while (1);
|
|
}
|
|
} else if ((pll_type == PLL_TYPE2) ||
|
|
(pll_type == PLL_TYPE4) ||
|
|
(pll_type == PLL_TYPE6) ||
|
|
(pll_type == PLL_TYPE7)) {
|
|
n4m_table_t *table = NULL, *te;
|
|
uint tabsz = 0;
|
|
|
|
ASSERT(cc);
|
|
|
|
orig_mips = R_REG(osh, &cc->clockcontrol_m3);
|
|
|
|
switch (pll_type) {
|
|
case PLL_TYPE6: {
|
|
uint32 new_mips = 0;
|
|
|
|
ret = TRUE;
|
|
if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
|
|
new_mips = CC_T6_MMASK;
|
|
|
|
if (orig_mips == new_mips)
|
|
goto done;
|
|
|
|
W_REG(osh, &cc->clockcontrol_m3, new_mips);
|
|
goto end_fill;
|
|
}
|
|
case PLL_TYPE2:
|
|
table = type2_table;
|
|
tabsz = ARRAYSIZE(type2_table);
|
|
break;
|
|
case PLL_TYPE4:
|
|
table = type4_table;
|
|
tabsz = ARRAYSIZE(type4_table);
|
|
break;
|
|
case PLL_TYPE7:
|
|
table = type7_table;
|
|
tabsz = ARRAYSIZE(type7_table);
|
|
break;
|
|
default:
|
|
ASSERT("No table for plltype" == NULL);
|
|
break;
|
|
}
|
|
|
|
/* Store the current clock register values */
|
|
orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
|
|
orig_ratio_parm = 0;
|
|
orig_ratio_cfg = 0;
|
|
|
|
/* Look up current ratio */
|
|
for (i = 0; i < tabsz; i++) {
|
|
if ((orig_n == table[i].n) &&
|
|
(orig_sb == table[i].sb) &&
|
|
(orig_pci == table[i].pci33) &&
|
|
(orig_m2 == table[i].m2) &&
|
|
(orig_mips == table[i].m3)) {
|
|
orig_ratio_parm = table[i].ratio_parm;
|
|
orig_ratio_cfg = table[i].ratio_cfg;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Search for the closest MIPS clock greater or equal to a preferred value */
|
|
for (i = 0; i < tabsz; i++) {
|
|
ASSERT(table[i].mipsclock ==
|
|
sb_clock_rate(pll_type, table[i].n, table[i].m3));
|
|
if ((mipsclock <= table[i].mipsclock) &&
|
|
((sbclock == 0) || (sbclock <= table[i].sbclock)))
|
|
break;
|
|
}
|
|
if (i == tabsz) {
|
|
ret = FALSE;
|
|
goto done;
|
|
} else {
|
|
te = &table[i];
|
|
ret = TRUE;
|
|
}
|
|
|
|
/* No PLL change */
|
|
if ((orig_n == te->n) &&
|
|
(orig_sb == te->sb) &&
|
|
(orig_pci == te->pci33) &&
|
|
(orig_m2 == te->m2) &&
|
|
(orig_mips == te->m3))
|
|
goto done;
|
|
|
|
/* Set the PLL controls */
|
|
W_REG(osh, clockcontrol_n, te->n);
|
|
W_REG(osh, clockcontrol_sb, te->sb);
|
|
W_REG(osh, clockcontrol_pci, te->pci33);
|
|
W_REG(osh, &cc->clockcontrol_m2, te->m2);
|
|
W_REG(osh, &cc->clockcontrol_m3, te->m3);
|
|
|
|
/* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
|
|
if ((pll_type == PLL_TYPE7) && (te->sb != te->m2) &&
|
|
(sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
|
|
W_REG(osh, &cc->chipcontrol,
|
|
R_REG(osh, &cc->chipcontrol) | 0x100);
|
|
|
|
/* No ratio change */
|
|
if (sb_chip(sbh) != BCM4785_CHIP_ID) {
|
|
if (orig_ratio_parm == te->ratio_parm)
|
|
goto end_fill;
|
|
}
|
|
|
|
/* Preload the code into the cache */
|
|
icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
|
|
if (sb_chip(sbh) == BCM4785_CHIP_ID) {
|
|
start = ((ulong) &&start_fill_4785) & ~(ic_lsize - 1);
|
|
end = ((ulong) &&end_fill_4785 + (ic_lsize - 1)) & ~(ic_lsize - 1);
|
|
}
|
|
else {
|
|
start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
|
|
end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
|
|
}
|
|
while (start < end) {
|
|
cache_op(start, Fill_I);
|
|
start += ic_lsize;
|
|
}
|
|
|
|
/* Copy the handler */
|
|
start = (ulong) &handler;
|
|
end = (ulong) &afterhandler;
|
|
dst = KSEG1ADDR(0x180);
|
|
for (i = 0; i < (end - start); i += 4)
|
|
*((ulong *)(dst + i)) = *((ulong *)(start + i));
|
|
|
|
/* Preload the handler into the cache one line at a time */
|
|
for (i = 0; i < (end - start); i += ic_lsize)
|
|
cache_op(dst + i, Fill_I);
|
|
|
|
/* Clear BEV bit */
|
|
MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
|
|
|
|
/* Enable interrupts */
|
|
MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
|
|
|
|
/* 4785 clock freq change procedures */
|
|
if (sb_chip(sbh) == BCM4785_CHIP_ID) {
|
|
start_fill_4785:
|
|
/* Switch to async */
|
|
MTC0(C0_BROADCOM, 4, (1 << 22));
|
|
|
|
/* Set clock ratio in MIPS */
|
|
*dll_r1 = (*dll_r1 & 0xfffffff0) | (te->d11_r1 - 1);
|
|
*dll_r2 = te->d11_r2;
|
|
|
|
/* Enable new settings in MIPS */
|
|
*dll_r1 = *dll_r1 | 0xc0000000;
|
|
|
|
/* Set active cfg */
|
|
MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) | (1 << 3) | 1);
|
|
|
|
/* Fake soft reset (clock cfg registers not reset) */
|
|
MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
|
|
|
|
/* Clear active cfg */
|
|
MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) & ~(1 << 3));
|
|
|
|
/* set watchdog timer */
|
|
W_REG(osh, &cc->watchdog, 20);
|
|
(void) R_REG(osh, &cc->chipid);
|
|
|
|
/* wait for timer interrupt */
|
|
__asm__ __volatile__(
|
|
".set\tmips3\n\t"
|
|
"sync\n\t"
|
|
"wait\n\t"
|
|
".set\tmips0");
|
|
end_fill_4785:
|
|
while (1);
|
|
}
|
|
/* Generic clock freq change procedures */
|
|
else {
|
|
/* Enable MIPS timer interrupt */
|
|
if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
|
|
!(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
|
|
ASSERT(mipsr);
|
|
W_REG(osh, &mipsr->intmask, 1);
|
|
|
|
start_fill:
|
|
/* step 1, set clock ratios */
|
|
MTC0(C0_BROADCOM, 3, te->ratio_parm);
|
|
MTC0(C0_BROADCOM, 1, te->ratio_cfg);
|
|
|
|
/* step 2: program timer intr */
|
|
W_REG(osh, &mipsr->timer, 100);
|
|
(void) R_REG(osh, &mipsr->timer);
|
|
|
|
/* step 3, switch to async */
|
|
sync_mode = MFC0(C0_BROADCOM, 4);
|
|
MTC0(C0_BROADCOM, 4, 1 << 22);
|
|
|
|
/* step 4, set cfg active */
|
|
MTC0(C0_BROADCOM, 2, (1 << 3) | 1);
|
|
|
|
/* steps 5 & 6 */
|
|
__asm__ __volatile__(
|
|
".set\tmips3\n\t"
|
|
"wait\n\t"
|
|
".set\tmips0");
|
|
|
|
/* step 7, clear cfg active */
|
|
MTC0(C0_BROADCOM, 2, 0);
|
|
|
|
/* Additional Step: set back to orig sync mode */
|
|
MTC0(C0_BROADCOM, 4, sync_mode);
|
|
|
|
/* step 8, fake soft reset */
|
|
MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
|
|
|
|
end_fill:
|
|
/* set watchdog timer */
|
|
W_REG(osh, &cc->watchdog, 20);
|
|
(void) R_REG(osh, &cc->chipid);
|
|
|
|
/* wait for timer interrupt */
|
|
__asm__ __volatile__(
|
|
".set\tmips3\n\t"
|
|
"sync\n\t"
|
|
"wait\n\t"
|
|
".set\tmips0");
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
done:
|
|
/* Enable 4785 DLL */
|
|
if (sb_chip(sbh) == BCM4785_CHIP_ID) {
|
|
uint32 tmp;
|
|
|
|
/* set mask to 1e, enable DLL (bit 0) */
|
|
*dll_ctrl |= 0x0041e021;
|
|
|
|
/* enable aggressive hardware mode */
|
|
*dll_ctrl |= 0x00000080;
|
|
|
|
/* wait for lock flag to clear */
|
|
while ((*dll_ctrl & 0x2) == 0);
|
|
|
|
/* clear sticky flags (clear on write 1) */
|
|
tmp = *dll_ctrl;
|
|
*dll_ctrl = tmp;
|
|
|
|
/* set mask to 5b'10001 */
|
|
*dll_ctrl = (*dll_ctrl & 0xfffc1fff) | 0x00022000;
|
|
|
|
/* enable sync mode */
|
|
MTC0(C0_BROADCOM, 4, MFC0(C0_BROADCOM, 4) & 0xfe3fffff);
|
|
(void)MFC0(C0_BROADCOM, 4);
|
|
}
|
|
|
|
/* switch back to previous core */
|
|
sb_setcoreidx(sbh, idx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
BCMINITFN(enable_pfc)(uint32 mode)
|
|
{
|
|
ulong start, end;
|
|
uint ic_size, ic_lsize;
|
|
|
|
/* If auto then choose the correct mode for this
|
|
* platform, currently we only ever select one mode
|
|
*/
|
|
if (mode == PFC_AUTO)
|
|
mode = PFC_INST;
|
|
|
|
icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
|
|
|
|
/* enable prefetch cache if available */
|
|
if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
|
|
start = ((ulong) &&setpfc_start) & ~(ic_lsize - 1);
|
|
end = ((ulong) &&setpfc_end + (ic_lsize - 1)) & ~(ic_lsize - 1);
|
|
|
|
/* Preload setpfc code into the cache one line at a time */
|
|
while (start < end) {
|
|
cache_op(start, Fill_I);
|
|
start += ic_lsize;
|
|
}
|
|
|
|
/* Now set the pfc */
|
|
setpfc_start:
|
|
/* write range */
|
|
*(volatile uint32 *)PFC_CR1 = 0xffff0000;
|
|
|
|
/* enable */
|
|
*(volatile uint32 *)PFC_CR0 = mode;
|
|
setpfc_end:
|
|
/* Compiler foder */
|
|
ic_size = 0;
|
|
}
|
|
}
|
|
|
|
/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
|
|
uint32
|
|
BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
|
|
{
|
|
osl_t *osh;
|
|
sbmemcregs_t *memc;
|
|
uint32 ret = 0;
|
|
uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
|
|
uint idx, rev;
|
|
|
|
osh = sb_osh(sbh);
|
|
|
|
idx = sb_coreidx(sbh);
|
|
|
|
memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
|
|
if (memc == 0)
|
|
goto out;
|
|
|
|
rev = sb_corerev(sbh);
|
|
|
|
config = R_REG(osh, &memc->config);
|
|
wr = R_REG(osh, &memc->wrncdlcor);
|
|
rd = R_REG(osh, &memc->rdncdlcor);
|
|
misc = R_REG(osh, &memc->miscdlyctl);
|
|
dqsg = R_REG(osh, &memc->dqsgatencdl);
|
|
|
|
rd &= MEMC_RDNCDLCOR_RD_MASK;
|
|
wr &= MEMC_WRNCDLCOR_WR_MASK;
|
|
dqsg &= MEMC_DQSGATENCDL_G_MASK;
|
|
|
|
if (config & MEMC_CONFIG_DDR) {
|
|
ret = (wr << 16) | (rd << 8) | dqsg;
|
|
} else {
|
|
if (rev > 0)
|
|
cd = rd;
|
|
else
|
|
cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
|
|
sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
|
|
sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
|
|
ret = (sm << 16) | (sd << 8) | cd;
|
|
}
|
|
|
|
out:
|
|
/* switch back to previous core */
|
|
sb_setcoreidx(sbh, idx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(BCMPERFSTATS)
|
|
/*
|
|
* CP0 Register 25 supports 4 semi-independent 32bit performance counters.
|
|
* $25 select 0, 1, 2, and 3 are the counters. The counters *decrement* (who thought this one up?)
|
|
* $25 select 4 and 5 each contain 2-16bit control fields, one for each of the 4 counters
|
|
* $25 select 6 is the global perf control register.
|
|
*/
|
|
/* enable and start instruction counting */
|
|
|
|
void
|
|
hndmips_perf_instrcount_enable()
|
|
{
|
|
MTC0(C0_PERFORMANCE, 6, 0x80000200); /* global enable perf counters */
|
|
MTC0(C0_PERFORMANCE, 4,
|
|
0x8044 | MFC0(C0_PERFORMANCE, 4)); /* enable instruction counting for counter 0 */
|
|
MTC0(C0_PERFORMANCE, 0, 0); /* zero counter zero */
|
|
}
|
|
|
|
/* enable and start I$ hit and I$ miss counting */
|
|
void
|
|
hndmips_perf_icachecount_enable(void)
|
|
{
|
|
MTC0(C0_PERFORMANCE, 6, 0x80000218); /* enable I$ counting */
|
|
MTC0(C0_PERFORMANCE, 4, 0x80148018); /* count I$ hits in cntr 0 and misses in cntr 1 */
|
|
MTC0(C0_PERFORMANCE, 0, 0); /* zero counter 0 - # I$ hits */
|
|
MTC0(C0_PERFORMANCE, 1, 0); /* zero counter 1 - # I$ misses */
|
|
}
|
|
|
|
/* enable and start D$ hit and I$ miss counting */
|
|
void
|
|
hndmips_perf_dcachecount_enable(void)
|
|
{
|
|
MTC0(C0_PERFORMANCE, 6, 0x80000211); /* enable D$ counting */
|
|
MTC0(C0_PERFORMANCE, 4, 0x80248028); /* count D$ hits in cntr 0 and misses in cntr 1 */
|
|
MTC0(C0_PERFORMANCE, 0, 0); /* zero counter 0 - # D$ hits */
|
|
MTC0(C0_PERFORMANCE, 1, 0); /* zero counter 1 - # D$ misses */
|
|
}
|
|
|
|
void
|
|
hndmips_perf_icache_miss_enable()
|
|
{
|
|
MTC0(C0_PERFORMANCE, 4,
|
|
0x80140000 | MFC0(C0_PERFORMANCE, 4)); /* enable cache misses counting for counter 1 */
|
|
MTC0(C0_PERFORMANCE, 1, 0); /* zero counter one */
|
|
}
|
|
|
|
|
|
void
|
|
hndmips_perf_icache_hit_enable()
|
|
{
|
|
MTC0(C0_PERFORMANCE, 5, 0x8018 | MFC0(C0_PERFORMANCE, 5));
|
|
/* enable cache hits counting for counter 2 */
|
|
MTC0(C0_PERFORMANCE, 2, 0); /* zero counter 2 */
|
|
}
|
|
|
|
uint32
|
|
hndmips_perf_read_instrcount()
|
|
{
|
|
return -(long)(MFC0(C0_PERFORMANCE, 0));
|
|
}
|
|
|
|
uint32
|
|
hndmips_perf_read_cache_miss()
|
|
{
|
|
return -(long)(MFC0(C0_PERFORMANCE, 1));
|
|
}
|
|
|
|
uint32
|
|
hndmips_perf_read_cache_hit()
|
|
{
|
|
return -(long)(MFC0(C0_PERFORMANCE, 2));
|
|
}
|
|
|
|
#endif /* BCMINTERNAL | BCMPERFSTATS */
|