/* */ #include #include #include #include #include #include #include #include #include #include #define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) #define ASSERT(a) #define SB2MIPS_T6(sb) (2 * (sb)) void dump(unsigned *data) { int i; for (i = 0; i < 64; i++) { if (i % 8 == 0) printf("\n%04x: ", i * sizeof(*data)); printf(" %08x\n", data[i]); } puts("\n"); } static INLINE uint32 factor6(uint32 x) { switch (x) { case CC_F6_2: return 2; case CC_F6_3: return 3; case CC_F6_4: return 4; case CC_F6_5: return 5; case CC_F6_6: return 6; case CC_F6_7: return 7; default: return 0; } } /* calculate the speed the SB would run at given a set of clockcontrol values */ uint32 sb_clock_rate(uint32 pll_type, uint32 n, uint32 m) { uint32 n1, n2, clock, m1, m2, m3, mc; n1 = n & CN_N1_MASK; n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; if (pll_type == PLL_TYPE6) { if (m & CC_T6_MMASK) return CC_T6_M1; else return CC_T6_M0; } else if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3) || (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE7)) { n1 = factor6(n1); n2 += CC_F5_BIAS; } else if (pll_type == PLL_TYPE2) { n1 += CC_T2_BIAS; n2 += CC_T2_BIAS; ASSERT((n1 >= 2) && (n1 <= 7)); ASSERT((n2 >= 5) && (n2 <= 23)); } else if (pll_type == PLL_TYPE5) { return (100000000); } else ASSERT(0); /* PLL types 3 and 7 use BASE2 (25Mhz) */ if ((pll_type == PLL_TYPE3) || (pll_type == PLL_TYPE7)) { clock = CC_CLOCK_BASE2 * n1 * n2; } else clock = CC_CLOCK_BASE1 * n1 * n2; if (clock == 0) return 0; m1 = m & CC_M1_MASK; m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3) || (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE7)) { m1 = factor6(m1); if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) m2 += CC_F5_BIAS; else m2 = factor6(m2); m3 = factor6(m3); switch (mc) { case CC_MC_BYPASS: return (clock); case CC_MC_M1: return (clock / m1); case CC_MC_M1M2: return (clock / (m1 * m2)); case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); case CC_MC_M1M3: return (clock / (m1 * m3)); default: return (0); } } else { ASSERT(pll_type == PLL_TYPE2); m1 += CC_T2_BIAS; m2 += CC_T2M2_BIAS; m3 += CC_T2_BIAS; ASSERT((m1 >= 2) && (m1 <= 7)); ASSERT((m2 >= 3) && (m2 <= 10)); ASSERT((m3 >= 2) && (m3 <= 7)); if ((mc & CC_T2MC_M1BYP) == 0) clock /= m1; if ((mc & CC_T2MC_M2BYP) == 0) clock /= m2; if ((mc & CC_T2MC_M3BYP) == 0) clock /= m3; return(clock); } } uint32 sb_mips_clock(chipcregs_t *cc) { extifregs_t *eir; uint32 n, m; uint idx; uint32 pll_type, rate = 0; pll_type = cc->capabilities & CAP_PLL_MASK; n = cc->clockcontrol_n; if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE6) || (pll_type == PLL_TYPE7)) m = cc->clockcontrol_mips; else if (pll_type == PLL_TYPE5) { rate = 200000000; goto out; } else if (pll_type == PLL_TYPE3) { m = cc->clockcontrol_m2; /* 5350 uses m2 to control mips */ } else m = cc->clockcontrol_sb; /* calculate rate */ rate = sb_clock_rate(pll_type, n, m); if (pll_type == PLL_TYPE6) rate = SB2MIPS_T6(rate); out: return rate; } uint32 sb_mips_clock2(chipcregs_t *cc, uint32 clockcontrol) { uint32 n, m; uint32 pll_type, rate = 0; pll_type = cc->capabilities & CAP_PLL_MASK; n = cc->clockcontrol_n; m = clockcontrol; /* calculate rate */ rate = sb_clock_rate(pll_type, n, m); return rate; } int main(int argc, char *argv[]) { unsigned mapping = SB_ENUM_BASE; chipcregs_t *cc; sbconfig_t *sb; int fd = open("/dev/mem", O_RDWR); if (fd < 0) { perror("/dev/mem"); return 1; } /* srom is at offset 0x1000, map size is page size */ cc = (chipcregs_t *)mmap(NULL, SB_CORE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mapping); sb = REGS2SB(cc); if (cc == NULL) { perror("mmap"); return 1; } printf("Device memory mapped ok\n"); #define DUMP(a) printf(#a ": %08x\n", cc->a) #define WAIT(a) printf(#a ": %08x %d/%d/%d/%d\n", cc->a, \ ((cc->a >> 24) & 255) * 10, ((cc->a >> 16) & 255) * 10, \ ((cc->a >> 8) & 255) * 10,((cc->a >> 0) & 255) * 10) #define CONFIG(a) printf(#a ": %08x %sabled %s %s %s %s bit ByteSwap: %s Div: %d\n", cc->a, \ (cc->a & CC_CFG_EN) ? "En" : "Dis", \ (cc->a & CC_CFG_EM_ASYNC) ? "Async flash" : "", \ (cc->a & CC_CFG_EM_SYNC) ? "Sync" : "", \ (cc->a & CC_CFG_EM_PCMCIA) ? "PCMCIA" : "", \ (cc->a & CF_DS) ? "16" : "8", \ (cc->a & CF_BS) ? "yes" : "no", \ ((cc->a & CF_CD_MASK) >> CF_CD_SHIFT) + 2) #define CLOCK(a) printf(#a ": %08x %dHz\n", cc->a, sb_mips_clock2(cc, cc->a)) //printf("chipid: 0x%08x", cc->chipid); DUMP(chipid); printf("chip: %04x, rev: %d, pkg: %d, corerev: %d, ", cc->chipid & CID_ID_MASK, (cc->chipid & CID_REV_MASK) >> CID_REV_SHIFT, (cc->chipid & CID_PKG_MASK) >> CID_PKG_SHIFT, SBCOREREV(sb->sbidhigh)); switch (cc->capabilities & CAP_PLL_MASK) { case PLL_NONE: printf("PLL_NONE\n"); break; case PLL_TYPE1: printf("PLL_TYPE1 /* 48Mhz base, 3 dividers */\n"); break; case PLL_TYPE2: printf("PLL_TYPE2 /* 48Mhz, 4 dividers */\n"); break; case PLL_TYPE3: printf("PLL_TYPE3 /* 25Mhz, 2 dividers */\n"); break; case PLL_TYPE4: printf("PLL_TYPE4 /* 48Mhz, 4 dividers */\n"); break; case PLL_TYPE5: printf("PLL_TYPE5 /* 25Mhz, 4 dividers */\n"); break; case PLL_TYPE6: printf("PLL_TYPE6 /* 100/200 or 120/240 only */\n"); break; case PLL_TYPE7: printf("PLL_TYPE7 /* 25Mhz, 4 dividers */\n"); break; } printf("%d Hz, %d UART(s)\n", sb_mips_clock(cc), cc->capabilities & CAP_UARTS_MASK); DUMP(flashcontrol); /* 0x40 */ DUMP(flashaddress); DUMP(flashdata); DUMP(clockcontrol_n); /* 0x90 */ CLOCK(clockcontrol_sb); /* aka m0 */ CLOCK(clockcontrol_pci); /* aka m1 */ CLOCK(clockcontrol_m2); /* mii/uart/mipsref */ CLOCK(clockcontrol_mips); /* aka m3 */ DUMP(clkdiv); /* corerev >= 3 */ CONFIG(pcmcia_config); /* 0x100 */ WAIT(pcmcia_memwait); WAIT(pcmcia_attrwait); WAIT(pcmcia_iowait); CONFIG(ide_config); WAIT(ide_memwait); WAIT(ide_attrwait); WAIT(ide_iowait); CONFIG(prog_config); WAIT(prog_waitcount); CONFIG(flash_config); WAIT(flash_waitcount); if (argc > 2 && strcmp(argv[1], "w") == 0) { cc->flash_waitcount = atoi(argv[2]); WAIT(flash_waitcount); } close(fd); }