++ /* Chip specific initialization */
++ switch (sb_chip(sbh)) {
++ case BCM4710_DEVICE_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(&eir->corecontrol, CC_UE);
++ /* Give USB its own interrupt */
++ sb_setirq(sbh, 1, SB_USB, 0);
++ } else {
++ /* Disable internal UART */
++ W_REG(&eir->corecontrol, 0);
++ /* Give Ethernet its own interrupt */
++ sb_setirq(sbh, 1, SB_ENET, 0);
++ sb_setirq(sbh, 0, SB_USB, 0);
++ }
++ break;
++ case BCM4310_DEVICE_ID:
++ MTC0(C0_BROADCOM, 0, MFC0(C0_BROADCOM, 0) & ~(1 << 22));
++ break;
++ }
++}
++
++uint32
++sb_mips_clock(void *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(&eir->clockcontrol_n);
++ m = R_REG(&eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(&cc->clockcontrol_n);
++ if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4))
++ m = R_REG(&cc->clockcontrol_mips);
++ else if (pll_type == PLL_TYPE3) {
++ rate = 200000000;
++ goto out;
++ } else
++ m = R_REG(&cc->clockcontrol_sb);
++ } else
++ goto out;
++
++ /* calculate rate */
++ rate = sb_clock_rate(pll_type, n, m);
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return rate;
++}
++
++static void
++icache_probe(int *size, int *lsize)
++{
++ uint32 config1;
++ uint sets, ways;
++
++ config1 = MFC0(C0_CONFIG, 1);
++
++ /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((*lsize = ((config1 >> 19) & 7)))
++ *lsize = 2 << *lsize;
++ sets = 64 << ((config1 >> 22) & 7);
++ ways = 1 + ((config1 >> 16) & 7);
++ *size = *lsize * sets * ways;
++}
++
++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
++
++static void
++handler(void)
++{
++ /* Step 11 */
++ __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"
++ "and $15, $15, -31746\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
++afterhandler(void)
++{
++}
++
++/*
++ * Set the MIPS, backplane and PCI clocks as closely as possible.
++ */
++bool
++sb_mips_setclock(void *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;
++ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, new_ratio;
++ uint32 pll_type, sync_mode;
++ uint idx, i;
++ struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 pci25;
++ } type1_table[] = {
++ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
++ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
++ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
++ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
++ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
++ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
++ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
++ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
++ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
++ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
++ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
++ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
++ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
++ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
++ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
++ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
++ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
++ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
++ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
++ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
++ };
++ typedef struct {
++ uint32 mipsclock;
++ uint32 sbclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 m2;
++ uint32 m3;
++ uint32 ratio;
++ uint32 ratio_parm;
++ } n4m_table_t;
++
++ n4m_table_t type2_table[] = {
++ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0303, 0x01000000, 0x01000600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 }
++ };
++
++ n4m_table_t type4_table[] = {
++ { 192000000, 96000000, 0x0702, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
++ { 216000000, 108000000, 0x0211, 0x11020005, 0x11030303, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
++ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x11030305, 0x04000005, 0x94, 0x012a00a9 },
++ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
++ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 0x21, 0x0aaa0555 },
++ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
++ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 0x52, 0x02520129 }
++ };
++ uint icache_size, ic_lsize;
++ ulong start, end, dst;
++ bool ret = FALSE;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++
++ /* 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;
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ clockcontrol_n = &cc->clockcontrol_n;
++ clockcontrol_sb = &cc->clockcontrol_sb;
++ clockcontrol_pci = &cc->clockcontrol_pci;
++ } else
++ goto done;
++
++ /* Store the current clock register values */
++ orig_n = R_REG(clockcontrol_n);
++ orig_sb = R_REG(clockcontrol_sb);
++ orig_pci = R_REG(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(clockcontrol_n), R_REG(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(clockcontrol_n, type1_table[i].n);
++ W_REG(clockcontrol_sb, type1_table[i].sb);
++ if (pciclock == 25000000)
++ W_REG(clockcontrol_pci, type1_table[i].pci25);
++ else
++ W_REG(clockcontrol_pci, type1_table[i].pci33);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++ while (1);
++ } else if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4)) {
++ n4m_table_t *table = (pll_type == PLL_TYPE2) ? type2_table : type4_table;
++ uint tabsz = (pll_type == PLL_TYPE2) ? ARRAYSIZE(type2_table) : ARRAYSIZE(type4_table);
++
++ ASSERT(cc);
++
++ /* Store the current clock register values */
++ orig_m2 = R_REG(&cc->clockcontrol_m2);
++ orig_mips = R_REG(&cc->clockcontrol_mips);
++ orig_ratio_parm = 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;
++ 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 {
++ ret = TRUE;
++ }
++
++ /* No PLL change */
++ 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))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, table[i].n);
++ W_REG(clockcontrol_sb, table[i].sb);
++ W_REG(clockcontrol_pci, table[i].pci33);
++ W_REG(&cc->clockcontrol_m2, table[i].m2);
++ W_REG(&cc->clockcontrol_mips, table[i].m3);
++
++ /* No ratio change */
++ if (orig_ratio_parm == table[i].ratio_parm)
++ goto end_fill;
++
++ new_ratio = table[i].ratio_parm;
++
++ icache_probe(&icache_size, &ic_lsize);
++
++ /* Preload the code into the cache */
++ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
++ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
++ while (start < end) {
++ cache_unroll(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 handler into the cache one line at a time */
++ for (i = 0; i < (end - start); i += 4)
++ cache_unroll(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));
++
++ /* Enable MIPS timer interrupt */
++ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(mipsr);
++ W_REG(&mipsr->intmask, 1);
++
++ start_fill:
++ /* step 1, set clock ratios */
++ MTC0(C0_BROADCOM, 3, new_ratio);
++ MTC0(C0_BROADCOM, 1, 8);
++
++ /* step 2: program timer intr */
++ W_REG(&mipsr->timer, 100);
++ (void) R_REG(&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, 0x9);
++
++
++ /* 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) | 4);
++
++ end_fill:
++ /* step 9 set watchdog timer */
++ sb_watchdog(sbh, 20);
++ (void) R_REG(&cc->chipid);
++
++ /* step 11 */
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++ while (1);
++ }
++
++done:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
++
++/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
++uint32
++sb_memc_get_ncdl(void *sbh)
++{
++ sbmemcregs_t *memc;
++ uint32 ret = 0;
++ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
++ uint idx, rev;
++
++ 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(&memc->config);
++ wr = R_REG(&memc->wrncdlcor);
++ rd = R_REG(&memc->rdncdlcor);
++ misc = R_REG(&memc->miscdlyctl);
++ dqsg = R_REG(&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;
++}
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c 2005-11-07 01:12:51.819809500 +0100
+@@ -0,0 +1,530 @@
++/*
++ * Low-Level PCI and SB support for BCM47xx
++ *
++ * Copyright 2001-2003, 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: sbpci.c,v 1.2 2005/02/28 13:34:25 jolt Exp $
++ */
++
++#include <typedefs.h>
++#include <pcicfg.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <sbpci.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++#include <hndmips.h>
++
++/* Can free sbpci_init() memory after boot */
++#ifndef linux
++#define __init
++#endif
++
++/* Emulated configuration space */
++static pci_config_regs sb_config_regs[SB_MAXCORES];
++
++/* Banned cores */
++static uint16 pci_ban[32] = { 0 };
++static uint pci_banned = 0;
++
++/* CardBus mode */
++static bool cardbus = FALSE;
++
++/*
++ * Functions for accessing external PCI configuration space
++ */
++
++/* Assume one-hot slot wiring */
++#define PCI_SLOT_MAX 16
++
++static uint32
++config_cmd(void *sbh, uint bus, uint dev, uint func, uint off)
++{
++ uint coreidx;
++ sbpciregs_t *regs;
++ uint32 addr = 0;
++
++ /* CardBusMode supports only one device */
++ if (cardbus && dev > 1)
++ return 0;
++
++ coreidx = sb_coreidx(sbh);
++ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
++
++ /* Type 0 transaction */
++ if (bus == 1) {
++ /* Skip unwired slots */
++ if (dev < PCI_SLOT_MAX) {
++ /* Slide the PCI window to the appropriate slot */
++ W_REG(®s->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
++ addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
++ (func << 8) | (off & ~3);
++ }
++ }
++
++ /* Type 1 transaction */
++ else {
++ W_REG(®s->sbtopci1, SBTOPCI_CFG1);
++ addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++
++ return addr;
++}
++
++static int
++extpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ val = 0xffffffff;
++
++ val >>= 8 * (off & 3);
++ if (len == 4)
++ *((uint32 *) buf) = val;
++ else if (len == 2)
++ *((uint16 *) buf) = (uint16) val;
++ else if (len == 1)
++ *((uint8 *) buf) = (uint8) val;
++ else
++ ret = -1;
++
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++static int
++extpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ goto done;
++
++ if (len == 4)
++ val = *((uint32 *) buf);
++ else if (len == 2) {
++ val &= ~(0xffff << (8 * (off & 3)));
++ val |= *((uint16 *) buf) << (8 * (off & 3));
++ } else if (len == 1) {
++ val &= ~(0xff << (8 * (off & 3)));
++ val |= *((uint8 *) buf) << (8 * (off & 3));
++ } else
++ ret = -1;
++
++ W_REG(reg, val);
++
++ done:
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++/*
++ * Functions for accessing translated SB configuration space
++ */
++
++static int
++sb_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED(buf, len));
++
++ if (len == 4)
++ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
++ else if (len == 2)
++ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
++ else if (len == 1)
++ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
++ else
++ return -1;
++
++ return 0;
++}
++
++static int
++sb_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint coreidx, n;
++ void *regs;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED(buf, len));
++
++ /* Emulate BAR sizing */
++ if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
++ len == 4 && *((uint32 *) buf) == ~0) {
++ coreidx = sb_coreidx(sbh);
++ if ((regs = sb_setcoreidx(sbh, dev))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* Highest numbered address match register */
++ n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
++ if (off == OFFSETOF(pci_config_regs, base[0]))
++ cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
++ /*else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
++ cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
++ cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
++ cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);*/
++ }
++ sb_setcoreidx(sbh, coreidx);
++ return 0;
++ }
++
++ if (len == 4)
++ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
++ else if (len == 2)
++ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
++ else if (len == 1)
++ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
++ else
++ return -1;
++
++ return 0;
++}
++
++int
++sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_read_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
++}
++
++int
++sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_write_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
++}
++
++void
++sbpci_ban(uint16 core)
++{
++ if (pci_banned < ARRAYSIZE(pci_ban))
++ pci_ban[pci_banned++] = core;
++}
++
++int __init
++sbpci_init(void *sbh)
++{
++ uint chip, chiprev, chippkg, coreidx, host, i;
++ sbpciregs_t *pci;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++ void *regs;
++ char varname[8];
++ uint wlidx = 0;
++ uint16 vendor, core;
++ uint8 class, subclass, progif;
++ uint32 val;
++ uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
++ uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
++
++ chip = sb_chip(sbh);
++ chiprev = sb_chiprev(sbh);
++ chippkg = sb_chippkg(sbh);
++ coreidx = sb_coreidx(sbh);
++
++ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0)))
++ return -1;
++ sb_core_reset(sbh, 0);
++
++ if (((chip == BCM4310_DEVICE_ID) && (chiprev == 0)) ||
++ ((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)))
++ host = 0;
++ else
++ host = !BUSPROBE(val, &pci->control);
++
++ if (!host) {
++ /* Disable PCI interrupts in client mode */
++ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
++ W_REG(&sb->sbintvec, 0);
++
++ /* Disable the PCI bridge in client mode */
++ sbpci_ban(SB_PCI);
++ printf("PCI: Disabled\n");
++ } else {
++ /* Reset the external PCI bus and enable the clock */
++ W_REG(&pci->control, 0x5); /* enable the tristate drivers */
++ W_REG(&pci->control, 0xd); /* enable the PCI clock */
++ OSL_DELAY(100); /* delay 100 us */
++ W_REG(&pci->control, 0xf); /* deassert PCI reset */
++ W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
++ OSL_DELAY(1); /* delay 1 us */
++
++ /* Enable CardBusMode */
++ cardbus = nvram_match("cardbus", "1");
++ if (cardbus) {
++ printf("PCI: Enabling CardBus\n");
++ /* GPIO 1 resets the CardBus device on bcm94710ap */
++ sb_gpioout(sbh, 1, 1);
++ sb_gpioouten(sbh, 1, 1);
++ W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
++ }
++
++ /* 64 MB I/O access window */
++ W_REG(&pci->sbtopci0, SBTOPCI_IO);
++ /* 64 MB configuration access window */
++ W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
++ /* 1 GB memory access window */
++ W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
++
++ /* Enable PCI bridge BAR0 prefetch and burst */
++ val = 6;
++ sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
++
++ /* Enable PCI interrupts */
++ W_REG(&pci->intmask, PCI_INTA);
++ }
++
++ /* Scan the SB bus */
++ bzero(sb_config_regs, sizeof(sb_config_regs));
++ for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
++ cfg->vendor = 0xffff;
++ if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
++ continue;
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* Read ID register and parse vendor and core */
++ val = R_REG(&sb->sbidhigh);
++ vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
++ core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
++ progif = 0;
++
++ /* Check if this core is banned */
++ for (i = 0; i < pci_banned; i++)
++ if (core == pci_ban[i])
++ break;
++ if (i < pci_banned)
++ continue;
++
++ /* Known vendor translations */
++ switch (vendor) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;