/* * This routine is called about once per second directly by the master * processor and via an interprocessor interrupt for other processors. * It determines the CC frequency of each processor relative to the * master clock and the time this determination is made. These values * are used by microtime() to interpolate the microseconds between * timer interrupts. Note that we assume the kernel variables have * been zeroed early in life. */ void cc_microset(struct cpu_info *ci) { struct timeval t; int64_t delta, denom; /* Note: Clock interrupts are already blocked. */ denom = ci->ci_cc_cc; t = cc_microset_time; /* XXXSMP: not atomic */ ci->ci_cc_cc = cpu_counter32(); if (ci->ci_cc_denom == 0) { /* * This is our first time here on this CPU. Just * start with reasonable initial values. */ ci->ci_cc_time = t; ci->ci_cc_ms_delta = 1000000; ci->ci_cc_denom = cpu_frequency(ci); return; } denom = ci->ci_cc_cc - denom; if (denom < 0) denom += 0x100000000L; delta = (t.tv_sec - ci->ci_cc_time.tv_sec) * 1000000 + (t.tv_usec - ci->ci_cc_time.tv_usec); ci->ci_cc_time = t; /* * Make sure it's within .5 to 1.5 seconds -- otherwise, * the time is probably be frobbed with by the timekeeper * or the human. */ if (delta > 500000 && delta < 1500000) { ci->ci_cc_ms_delta = delta; ci->ci_cc_denom = denom; #if 0 printf("cc_microset: delta %" PRId64 ", denom %" PRId64 "\n", delta, denom); #endif } else { #if 0 printf("cc_microset: delta %" PRId64 ", resetting state\n", delta); #endif ci->ci_cc_ms_delta = 1000000; ci->ci_cc_denom = cpu_frequency(ci); } }
static uint64_t get_tsc_offset_ns(void) { uint32_t tsc_delta; struct cpu_info *ci = curcpu(); tsc_delta = cpu_counter32() - shadow_tsc_stamp; return tsc_delta * 1000000000 / cpu_frequency(ci); }
ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p) { output_data = (uch *) output_start; free_mem_ptr = free_mem_ptr_p; free_mem_ptr_end = free_mem_ptr_end_p; disable_watchdog(); arch_decomp_setup(); /* initialize clock */ HAL_CLOCK_INITIALIZE(RTC_PERIOD); printf("MicroRedBoot v1.4, (c) 2009 DD-WRT.COM (%s REVISION %s)\n", __DATE__,SVN_REVISION); printf("keep the reset button pushed to enter redboot!\n"); printf("CPU Type: Atheros AR%s\n",get_system_type()); printf("CPU Clock: %dMhz\n", cpu_frequency() / 1000000); nvram_init(); char *ddboard = nvram_get("DD_BOARD"); if (ddboard) printf("Board: %s\n", ddboard); char *resetbutton = nvram_get("resetbutton_enable"); if (resetbutton && !strcmp(resetbutton, "0")) puts("reset button manual override detected! (nvram var resetbutton_enable=0)\n"); if (resetTouched() || (resetbutton && !strcmp(resetbutton, "0"))) { puts("Reset Button triggered\nBooting Recovery RedBoot\n"); int count = 5; while (count--) { if (!resetTouched()) // check if reset button is unpressed again break; udelay(1000000); } if (count <= 0) { puts("reset button 5 seconds pushed, erasing nvram\n"); if (!flashdetect()) flash_erase_nvram(flashsize, NVRAM_SPACE); } bootoffset = 0x800004bc; resettrigger = 0; puts("loading"); lzma_unzip(); puts("\n\n\n"); return output_ptr; } else { flashdetect(); linuxaddr = getLinux(); puts("Booting Linux\n"); resettrigger = 1; /* important, enable ethernet bus, if the following lines are not initialized linux will not be able to use the ethernet mac, taken from redboot source */ enable_ethernet(); puts("loading"); lzma_unzip(); set_cmdline(); } }
/* * Wait for IPI operation to complete. * Return 0 on success. */ int sparc64_ipi_wait(sparc64_cpuset_t volatile *cpus_watchset, sparc64_cpuset_t cpus_mask) { uint64_t limit = gettick() + cpu_frequency(curcpu()); while (gettick() < limit) { membar_Sync(); if (CPUSET_EQUAL(*cpus_watchset, cpus_mask)) return 0; } return 1; }
/* * pick up tick count scaled to reference tick count */ u_int cc_get_timecount(struct timecounter *tc) { struct cpu_info *ci; int64_t rcc, cc, ncsw; u_int gen; retry: ncsw = curlwp->l_ncsw; __insn_barrier(); ci = curcpu(); if (ci->ci_cc.cc_denom == 0) { /* * This is our first time here on this CPU. Just * start with reasonable initial values. */ ci->ci_cc.cc_cc = cpu_counter32(); ci->ci_cc.cc_val = 0; if (ci->ci_cc.cc_gen == 0) ci->ci_cc.cc_gen++; ci->ci_cc.cc_denom = cpu_frequency(ci); if (ci->ci_cc.cc_denom == 0) ci->ci_cc.cc_denom = cc_timecounter.tc_frequency; ci->ci_cc.cc_delta = ci->ci_cc.cc_denom; } /* * read counter and re-read when the re-calibration * strikes inbetween */ do { /* pick up current generation number */ gen = ci->ci_cc.cc_gen; /* determine local delta ticks */ cc = cpu_counter32() - ci->ci_cc.cc_cc; if (cc < 0) cc += 0x100000000LL; /* scale to primary */ rcc = (cc * ci->ci_cc.cc_delta) / ci->ci_cc.cc_denom + ci->ci_cc.cc_val; } while (gen == 0 || gen != ci->ci_cc.cc_gen); __insn_barrier(); if (ncsw != curlwp->l_ncsw) { /* Was preempted */ goto retry; } return rcc; }
/* * This routine is called about once per second directly by the master * processor and via an interprocessor interrupt for other processors. * It determines the CC frequency of each processor relative to the * master clock and the time this determination is made. These values * are used by cc_get_timecount() to interpolate the ticks between * timer interrupts. Note that we assume the kernel variables have * been zeroed early in life. */ void cc_calibrate_cpu(struct cpu_info *ci) { u_int gen; int64_t val; int64_t delta, denom; int s; #ifdef TIMECOUNTER_DEBUG int64_t factor, old_factor; #endif val = cc_cal_val; s = splhigh(); /* create next generation number */ gen = ci->ci_cc.cc_gen; gen++; if (gen == 0) gen++; /* update in progress */ ci->ci_cc.cc_gen = 0; denom = ci->ci_cc.cc_cc; ci->ci_cc.cc_cc = cpu_counter32(); if (ci->ci_cc.cc_denom == 0) { /* * This is our first time here on this CPU. Just * start with reasonable initial values. */ ci->ci_cc.cc_val = val; ci->ci_cc.cc_denom = cpu_frequency(ci); if (ci->ci_cc.cc_denom == 0) ci->ci_cc.cc_denom = cc_timecounter.tc_frequency; ci->ci_cc.cc_delta = ci->ci_cc.cc_denom; ci->ci_cc.cc_gen = gen; splx(s); return; } #ifdef TIMECOUNTER_DEBUG old_factor = (ci->ci_cc.cc_delta * 1000 ) / ci->ci_cc.cc_denom; #endif /* local ticks per period */ denom = ci->ci_cc.cc_cc - denom; if (denom < 0) denom += 0x100000000LL; ci->ci_cc.cc_denom = denom; /* reference ticks per period */ delta = val - ci->ci_cc.cc_val; if (delta < 0) delta += 0x100000000LL; ci->ci_cc.cc_val = val; ci->ci_cc.cc_delta = delta; /* publish new generation number */ ci->ci_cc.cc_gen = gen; splx(s); #ifdef TIMECOUNTER_DEBUG factor = (delta * 1000) / denom - old_factor; if (factor < 0) factor = -factor; if (factor > old_factor / 10) printf("cc_calibrate_cpu[%u]: 10%% exceeded - delta %" PRId64 ", denom %" PRId64 ", factor %" PRId64 ", old factor %" PRId64"\n", ci->ci_index, delta, denom, (delta * 1000) / denom, old_factor); #endif /* TIMECOUNTER_DEBUG */ }
void lcd_init (void) { // Reset the SDRAM. meminit (cpu_frequency (1)); puts ("LCD setup:"); static const unsigned pins[] = { // Setup the PLL0AUDIO to give 74.75MHz off 50MHz ethernet clock. // ndec=122, mdec=13107, pdec=66 // selr=0, seli=48, selp=24 // pllfract = 47.839996,0x17eb85 // pre-divider=16, feedback div=47, post-div=2 // fcco=299MHz, fout=74.749994MHz. WORD_WRITE32n(PLL0AUDIO->ctrl, 4, 0x03001811, // CTRL 13107, // MDIV 66 + (122 << 12), // NP_DIV 0x17eb85), // FRAC BIT_RESET(PLL0AUDIO->ctrl, 0), // Wait for lock. BIT_WAIT_ZERO(PLL0AUDIO->stat, 0), // The lcd clock is outclk11. PLL0AUDIO is clock source 8. WORD_WRITE32(*BASE_LCD_CLK, 0x08000800), // Reset the lcd. WORD_WRITE32(RESET_CTRL[0], 1<<16), BIT_WAIT_SET(RESET_ACTIVE_STATUS[0], 16), // 1024x1024 59.90 Hz (CVT) hsync: 63.13 kHz; pclk: 74.75 MHz // Modeline "1024x1024R" 74.75 1024 1072 1104 1184 1024 1027 1037 1054 // +hsync -vsync // horizontal 1024 48 32 80 // vertical 1024 3 10 17 WORD_WRITE32n(LCD->timh, 7, (79 << 24) + (47 << 8) + (31 << 16) + 0xfc, // TIMH (16 << 24) + (2 << 16) + (9 << 10) + 1023, // TIMV // PCD_LO = 0, Clock divisor = 0. // CLK_SEL = 1, LCDCLKIN. // ACB = 0, N/A. // IVS=0, IHS=1, positive vsync, negative hsync (!?) // IPC=1, falling clock edge. // IOE=0, out enable positive. // CPL=1023. // BCD=1, no clock divider. // PCD_HI=0. 0x07ff3020, // POL 0, // LE (unsigned) FRAME_BUFFER, // UPBASE (unsigned) FRAME_BUFFER, // LPBASE LCD_CONTROL), // PIN_OUT_FAST(4,1,2), // A1 LCD_VD0 // PIN_OUT_FAST(4,3,2), // C2 LCD_VD2 // PIN_OUT_FAST(4,4,2), // B1 LCD_VD1 // PIN_OUT_FAST(4,8,2), // E2 LCD_VD9 // PIN_OUT_FAST(7,2,3), // A16 LCD_VD18 // PIN_OUT_FAST(7,3,3), // C13 LCD_VD17 // PIN_OUT_FAST(7,4,3), // C8 LCD_VD16 // PIN_OUT_FAST(7,5,3), // A7 LCD_VD8 //PIN_OUT_FAST(,,), // B16 LCD_LE //PIN_OUT_FAST(,,), // B6 LCD_PWR PIN_OUT_FAST(3,4,7) // A15 LCD_VD13 + PIN_EXTRA(1), // C12 LCD_VD12 PIN_OUT_FAST(4,2,2), // D3 LCD_VD3 PIN_OUT_FAST(4,5,2) // D2 LCD_FP + PIN_EXTRA(1), // C1 LCD_ENAB/LCDM PIN_OUT_FAST(4,9,2) // L2 LCD_VD11 + PIN_EXTRA(1), // M3 LCD_VD10 PIN_OUT_FAST(7,1,4), // C14 LCD_VD7 PIN_OUT_FAST(7,6,3), // C7 LCD_LP PIN_OUT_FAST(8,5,3) // J1 LCD_VD6 + PIN_EXTRA(2), // K3 LCD_VD5, K1 LCD_VD4 PIN_OUT_FAST(11,0,2) // B15 LCD_VD23 + PIN_EXTRA(6), // ... A13 VD20, B11 VD15, A12 VD14, A6 VD19 PIN_OUT_FAST(12,0,4), // D4 LCD_DCLK // Enable the lcd. BIT_SET(LCD->ctrl, 0), // TFT, 16bpp, 565, watermark=8. // Enable the frame interrupt. WORD_WRITE(LCD->intmsk, 4), }; configure(pins, sizeof pins / sizeof pins[0]); NVIC_ISER[0] = 1 << m4_lcd; puts (" done\n"); }