static enum switch_state get_switch_state(void) { struct stopwatch sw; int sampled_value; uint8_t rec_sw; static enum switch_state saved_state = not_probed; if (saved_state != not_probed) return saved_state; rec_sw = get_rec_sw_gpio_pin(); sampled_value = read_gpio(rec_sw) ^ !REC_POL; if (!sampled_value) { saved_state = no_req; display_pattern(WWR_NORMAL_BOOT); return saved_state; } display_pattern(WWR_RECOVERY_PUSHED); printk(BIOS_INFO, "recovery button pressed\n"); stopwatch_init_msecs_expire(&sw, WIPEOUT_MODE_DELAY_MS); do { sampled_value = read_gpio(rec_sw) ^ !REC_POL; if (!sampled_value) break; } while (!stopwatch_expired(&sw)); if (sampled_value) { display_pattern(WWR_WIPEOUT_REQUEST); printk(BIOS_INFO, "wipeout requested, checking recovery\n"); stopwatch_init_msecs_expire(&sw, RECOVERY_MODE_EXTRA_DELAY_MS); do { sampled_value = read_gpio(rec_sw) ^ !REC_POL; if (!sampled_value) break; } while (!stopwatch_expired(&sw)); if (sampled_value) { saved_state = recovery_req; display_pattern(WWR_RECOVERY_REQUEST); printk(BIOS_INFO, "recovery requested\n"); } else { saved_state = wipeout_req; } } else { saved_state = no_req; display_pattern(WWR_NORMAL_BOOT); } return saved_state; }
static int crosec_spi_io(size_t req_size, size_t resp_size, void *context) { struct spi_slave *slave = (struct spi_slave *)context; int ret = 0; while (!stopwatch_expired(&cs_cooldown_sw)) /* Wait minimum delay between CS assertions. */; spi_claim_bus(slave); /* Allow EC to ramp up clock after being awaken. * See chrome-os-partner:32223 for more details. */ udelay(CONFIG_EC_GOOGLE_CHROMEEC_SPI_WAKEUP_DELAY_US); if (spi_xfer(slave, req_buf, req_size, NULL, 0)) { printk(BIOS_ERR, "%s: Failed to send request.\n", __func__); ret = -1; goto out; } uint8_t byte; struct stopwatch sw; // Wait 1s for a framing byte. stopwatch_init_usecs_expire(&sw, USECS_PER_SEC); while (1) { if (spi_xfer(slave, NULL, 0, &byte, sizeof(byte))) { printk(BIOS_ERR, "%s: Failed to receive byte.\n", __func__); ret = -1; goto out; } if (byte == EcFramingByte) break; if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "%s: Timeout waiting for framing byte.\n", __func__); ret = -1; goto out; } } if (spi_xfer(slave, NULL, 0, resp_buf, resp_size)) { printk(BIOS_ERR, "%s: Failed to receive response.\n", __func__); ret = -1; } out: spi_release_bus(slave); stopwatch_init_usecs_expire(&cs_cooldown_sw, cs_cooldown_us); return ret; }
void reset_prepare(void) { struct stopwatch sw; /* * If CSE state is something else than 'normal', it is probably in some * recovery state. In this case there is no point in waiting for it to * get ready so we cross fingers and reset. */ if (!heci_cse_normal()) { printk(BIOS_DEBUG, "CSE is not in normal state, resetting\n"); return; } /* Reset if CSE is ready */ if (heci_cse_done()) return; printk(BIOS_SPEW, "CSE is not yet ready, waiting\n"); stopwatch_init_msecs_expire(&sw, CSE_WAIT_MAX_MS); while (!heci_cse_done()) { if (stopwatch_expired(&sw)) { printk(BIOS_SPEW, "CSE timed out. Resetting\n"); return; } mdelay(1); } printk(BIOS_SPEW, "CSE took %lu ms\n", stopwatch_duration_msecs(&sw)); }
static int check_ip_clk_status(void) { int u3_port_num; u32 check_bits; u32 sts1, sts2; struct stopwatch sw; u3_port_num = CAP_U3_PORT_NUM(read32(&ippc_regs->ip_xhci_cap)); check_bits = STS1_SYSPLL_STABLE | STS1_REF_RST | STS1_SYS125_RST; check_bits = (u3_port_num ? STS1_U3_MAC_RST : 0); stopwatch_init_usecs_expire(&sw, 50000); do { if (stopwatch_expired(&sw)) { u3p_err("usb clocks are not stable!!!\n"); return -1; } sts1 = read32(&ippc_regs->ip_pw_sts1) & check_bits; sts2 = read32(&ippc_regs->ip_pw_sts2) & STS2_U2_MAC_RST; } while ((sts1 != check_bits) || !sts2); return 0; }
/* cr50 uses bytes 3:2 of status register for burst count and * all 4 bytes must be read */ static int cr50_i2c_wait_burststs(struct tpm_chip *chip, uint8_t mask, size_t *burst, int *status) { uint8_t buf[4]; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_LONG_MS); while (!stopwatch_expired(&sw)) { if (cr50_i2c_read(chip, TPM_STS(chip->vendor.locality), buf, sizeof(buf)) != 0) { mdelay(CR50_TIMEOUT_SHORT_MS); continue; } *status = buf[0]; *burst = read_le16(&buf[1]); /* Check if mask matches and burst is valid */ if ((*status & mask) == mask && *burst > 0 && *burst <= CR50_MAX_BUFSIZE) return 0; mdelay(CR50_TIMEOUT_SHORT_MS); } printk(BIOS_ERR, "%s: Timeout reading burst and status\n", __func__); return -1; }
static int dma_read(u32 addr, u8 *buf, u32 len, uintptr_t dma_buf, size_t dma_buf_len) { struct stopwatch sw; assert(IS_ALIGNED((uintptr_t)buf, SFLASH_DMA_ALIGN) && IS_ALIGNED(len, SFLASH_DMA_ALIGN) && len <= dma_buf_len); /* do dma reset */ write32(&mt8173_nor->fdma_ctl, SFLASH_DMA_SW_RESET); write32(&mt8173_nor->fdma_ctl, SFLASH_DMA_WDLE_EN); /* flash source address and dram dest address */ write32(&mt8173_nor->fdma_fadr, addr); write32(&mt8173_nor->fdma_dadr, dma_buf); write32(&mt8173_nor->fdma_end_dadr, (dma_buf + len)); /* start dma */ write32(&mt8173_nor->fdma_ctl, SFLASH_DMA_TRIGGER | SFLASH_DMA_WDLE_EN); stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US); while ((read32(&mt8173_nor->fdma_ctl) & SFLASH_DMA_TRIGGER) != 0) { if (stopwatch_expired(&sw)) { printk(BIOS_WARNING, "dma read timeout!\n"); return -1; } } memcpy(buf, (const void *)dma_buf, len); return 0; }
static int rk_edp_hw_link_training(struct rk_edp *edp) { u32 val; struct stopwatch sw; /* Set link rate and count as you want to establish*/ write32(&edp->regs->link_bw_set, edp->link_train.link_rate); write32(&edp->regs->lane_count_set, edp->link_train.lane_count); if (rk_edp_link_train_cr(edp)) return -1; if (rk_edp_link_train_ce(edp)) return -1; write32(&edp->regs->dp_hw_link_training, HW_LT_EN); stopwatch_init_msecs_expire(&sw, 10); do { val = read32(&edp->regs->dp_hw_link_training); if (!(val & HW_LT_EN)) break; } while (!stopwatch_expired(&sw)); if (val & HW_LT_ERR_CODE_MASK) { printk(BIOS_ERR, "edp hw link training error: %d\n", val >> HW_LT_ERR_CODE_SHIFT); return -1; }
static int tegra_spi_pio_finish(struct tegra_spi_channel *spi) { u8 *p = spi->in_buf; struct stopwatch sw; clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN | SPI_CMD1_TX_EN); /* * Allow some time in case the Rx FIFO does not yet have * all packets pushed into it. See chrome-os-partner:24215. */ stopwatch_init_usecs_expire(&sw, SPI_FIFO_XFER_TIMEOUT_US); do { if (rx_fifo_count(spi) == spi_byte_count(spi)) break; } while (!stopwatch_expired(&sw)); while (!(read32(&spi->regs->fifo_status) & SPI_FIFO_STATUS_RX_FIFO_EMPTY)) { *p = read8(&spi->regs->rx_fifo); p++; } if (fifo_error(spi)) { printk(BIOS_ERR, "%s: ERROR:\n", __func__); dump_spi_regs(spi); dump_fifo_status(spi); return -1; } return 0; }
/* * Punit Initialization code. This all isn't documented, but * this is the recipe. */ static bool punit_init(void) { uint32_t reg; uint32_t data; struct stopwatch sw; /* Thermal throttle activation offset */ configure_thermal_target(); /* * Software Core Disable Mask (P_CR_CORE_DISABLE_MASK_0_0_0_MCHBAR). * Enable all cores here. */ MCHBAR32(CORE_DISABLE_MASK) = 0x0; /* P-Unit bring up */ reg = MCHBAR32(BIOS_RESET_CPL); if (reg == 0xffffffff) { /* P-unit not found */ printk(BIOS_DEBUG, "Punit MMIO not available\n"); return false; } /* Set Punit interrupt pin IPIN offset 3D */ pci_write_config8(SA_DEV_PUNIT, PCI_INTERRUPT_PIN, 0x2); /* Set PUINT IRQ to 24 and INTPIN LOCK */ MCHBAR32(PUNIT_THERMAL_DEVICE_IRQ) = PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER | PUINT_THERMAL_DEVICE_IRQ_LOCK; if (!CONFIG(SOC_INTEL_GLK)) { data = MCHBAR32(0x7818); data &= 0xFFFFE01F; data |= 0x20 | 0x200; MCHBAR32(0x7818) = data; } /* Stage0 BIOS Reset Complete (RST_CPL) */ enable_bios_reset_cpl(); /* * Poll for bit 8 to check if PCODE has completed its action * in reponse to BIOS Reset complete. * We wait here till 1 ms for the bit to get set. */ stopwatch_init_msecs_expire(&sw, 1); while (!(MCHBAR32(BIOS_RESET_CPL) & PCODE_INIT_DONE)) { if (stopwatch_expired(&sw)) { printk(BIOS_DEBUG, "PCODE Init Done Failure\n"); return false; } udelay(100); } return true; }
/* * Wait for the bit at the shift position to be set in reg * If the bit is not set in SPI_TIMEOUT_VALUE_US return with error */ static int wait_status(u32 reg, u32 shift) { struct stopwatch sw; stopwatch_init_usecs_expire(&sw, SPI_TIMEOUT_VALUE_US); while (!(read32_x(reg) & (1 << shift))) { if (stopwatch_expired(&sw)) return -SPIM_TIMEOUT; } return SPIM_OK; }
/* * Punit Initialization code. This all isn't documented, but * this is the recipe. */ static bool punit_init(void) { uint32_t reg; uint32_t data; struct stopwatch sw; /* * Software Core Disable Mask (P_CR_CORE_DISABLE_MASK_0_0_0_MCHBAR). * Enable all cores here. */ write32((void *)(MCH_BASE_ADDR + P_CR_CORE_DISABLE_MASK_0_0_0_MCHBAR), 0x0); void *bios_rest_cpl = (void *)(MCH_BASE_ADDR + P_CR_BIOS_RESET_CPL_0_0_0_MCHBAR); /* P-Unit bring up */ reg = read32(bios_rest_cpl); if (reg == 0xffffffff) { /* P-unit not found */ printk(BIOS_DEBUG, "Punit MMIO not available \n"); return false; } else { /* Set Punit interrupt pin IPIN offset 3D */ pci_write_config8(PUNIT_DEVFN, PCI_INTERRUPT_PIN, 0x2); /* Set PUINT IRQ to 24 and INTPIN LOCK */ write32((void *)(MCH_BASE_ADDR + PUNIT_THERMAL_DEVICE_IRQ), PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER | PUINT_THERMAL_DEVICE_IRQ_LOCK); data = read32((void *)(MCH_BASE_ADDR + 0x7818)); data &= 0xFFFFE01F; data |= 0x20 | 0x200; write32((void *)(MCH_BASE_ADDR + 0x7818), data); /* Stage0 BIOS Reset Complete (RST_CPL) */ write32(bios_rest_cpl, 0x1); /* * Poll for bit 8 in same reg (RST_CPL). * We wait here till 1 ms for the bit to get set. */ stopwatch_init_msecs_expire(&sw, 1); while (!(read32(bios_rest_cpl) & 0x100)) { if (stopwatch_expired(&sw)) { printk(BIOS_DEBUG, "Failed to set RST_CPL bit\n"); return false; } udelay(100); } } return true; }
/* * Configure DP in slave mode and wait for video stream. * * param dp pointer to main s5p-dp structure * param video_info pointer to main video_info structure. * return status */ static int s5p_dp_config_video(struct s5p_dp_device *dp, struct video_info *video_info) { int timeout = 0; struct exynos5_dp *base = dp->base; struct stopwatch sw; s5p_dp_config_video_slave_mode(dp, video_info); s5p_dp_set_video_color_format(dp, video_info->color_depth, video_info->color_space, video_info->dynamic_range, video_info->ycbcr_coeff); if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { printk(BIOS_DEBUG, "PLL is not locked yet.\n"); return -ERR_PLL_NOT_UNLOCKED; } stopwatch_init_msecs_expire(&sw, STREAM_ON_TIMEOUT); do { if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) { timeout++; break; } } while (!stopwatch_expired(&sw)); if (!timeout) { printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n", stopwatch_duration_usecs(&sw)); return -ERR_VIDEO_CLOCK_BAD; } /* Set to use the register calculated M/N video */ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); clrbits_le32(&base->video_ctl_10, FORMAT_SEL); /* Disable video mute */ clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE); /* Configure video slave mode */ s5p_dp_enable_video_master(dp); /* Enable video */ setbits_le32(&base->video_ctl_1, VIDEO_EN); timeout = s5p_dp_is_video_stream_on(dp); if (timeout) { printk(BIOS_DEBUG, "Video Stream Not on\n"); return -ERR_VIDEO_STREAM_BAD; } return 0; }
/* Wait for interrupt to indicate the TPM is ready */ static int cr50_i2c_wait_tpm_ready(struct tpm_chip *chip) { struct stopwatch sw; stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_IRQ_MS); while (!tis_plat_irq_status()) if (stopwatch_expired(&sw)) return -1; return 0; }
/* * TPM may trigger a IRQ after finish processing previous transfer. * Waiting for this IRQ to sync TPM status. * * Returns 1 on success, 0 on failure (timeout). */ static int tpm_sync(void) { struct stopwatch sw; stopwatch_init_msecs_expire(&sw, 10); while (!tis_plat_irq_status()) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "Timeout wait for TPM IRQ!\n"); return 0; } } return 1; }
static int pcr_wait_for_completion(device_t dev) { struct stopwatch sw; stopwatch_init_msecs_expire(&sw, PCR_SBI_CMD_TIMEOUT); do { if ((pci_read_config16(dev, P2SB_CR_SBI_STATUS) & P2SB_CR_SBI_STATUS_BUSY) == 0) return 0; } while (!stopwatch_expired(&sw)); return -1; }
static int polling_cmd(u32 val) { struct stopwatch sw; stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US); while ((read32(&mt8173_nor->cmd) & val) != 0) { if (stopwatch_expired(&sw)) return -1; } return 0; }
static int rk_edp_aux_enable(struct rk_edp *edp) { struct stopwatch sw; setbits_le32(&edp->regs->aux_ch_ctl_2, AUX_EN); stopwatch_init_msecs_expire(&sw, 20); do { if (!(read32(&edp->regs->aux_ch_ctl_2) & AUX_EN)) return 0; } while (!stopwatch_expired(&sw)); return -1; }
static int rk_edp_is_aux_reply(struct rk_edp *edp) { struct stopwatch sw; stopwatch_init_msecs_expire(&sw, 10); while (!(read32(&edp->regs->dp_int_sta) & RPLY_RECEIV)) { if (stopwatch_expired(&sw)) return -1; } write32(&edp->regs->dp_int_sta, RPLY_RECEIV); return 0; }
static int tpm2_claim_locality(void) { uint8_t access; struct stopwatch sw; /* * Locality is released by TPM reset. * * If locality is taken at this point, this could be due to the fact * that the TPM is performing a long operation and has not processed * reset request yet. We'll wait up to CR50_TIMEOUT_INIT_MS and see if * it releases locality when reset is processed. */ stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_INIT_MS); do { access = tpm2_read_access_reg(); if (access & TPM_ACCESS_ACTIVE_LOCALITY) { /* * Don't bombard the chip with traffic, let it keep * processing the command. */ mdelay(2); continue; } /* * Ok, the locality is free, TPM must be reset, let's claim * it. */ tpm2_write_access_reg(TPM_ACCESS_REQUEST_USE); access = tpm2_read_access_reg(); if (access != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { break; } printk(BIOS_INFO, "TPM ready after %ld ms\n", stopwatch_duration_msecs(&sw)); return 1; } while (!stopwatch_expired(&sw)); printk(BIOS_ERR, "Failed to claim locality 0 after %ld ms, status: %#x\n", stopwatch_duration_msecs(&sw), access); return 0; }
static int wait_for_write_done(void) { struct stopwatch sw; u8 reg; stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US); while (sflashhw_read_flash_status(®) == 0) { if (!(reg & SFLASH_WRITE_IN_PROGRESS)) return 0; if (stopwatch_expired(&sw)) return -1; } return -1; }
static bool wilco_ec_response_timed_out(void) { uint8_t mask = EC_CMDR_PENDING | EC_CMDR_BUSY; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, EC_MAILBOX_TIMEOUT_MS); while (inb(CONFIG_EC_BASE_HOST_COMMAND) & mask) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "%s: Command timeout\n", __func__); return true; /* Timed out */ } mdelay(1); } return false; /* Did not time out */ }
/* * Cr50 processes reset requests asynchronously and consceivably could be busy * executing a long command and not reacting to the reset pulse for a while. * * This function will make sure that the AP does not proceed with boot until * TPM finished reset processing. */ static int process_reset(struct tpm_chip *chip) { struct stopwatch sw; int rv = 0; uint8_t access; /* * Locality is released by TPM reset. * * If locality is taken at this point, this could be due to the fact * that the TPM is performing a long operation and has not processed * reset request yet. We'll wait up to CR50_TIMEOUT_INIT_MS and see if * it releases locality when reset is processed. */ stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_INIT_MS); do { const uint8_t mask = TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY; rv = cr50_i2c_read(chip, TPM_ACCESS(0), &access, sizeof(access)); if (rv || ((access & mask) == mask)) { /* * Don't bombard the chip with traffic, let it keep * processing the command. */ mdelay(2); continue; } printk(BIOS_INFO, "TPM ready after %ld ms\n", stopwatch_duration_msecs(&sw)); return 0; } while (!stopwatch_expired(&sw)); if (rv) printk(BIOS_ERR, "Failed to read TPM\n"); else printk(BIOS_ERR, "TPM failed to reset after %ld ms, status: %#x\n", stopwatch_duration_msecs(&sw), access); return -1; }
void udelay(unsigned int usec) { struct stopwatch sw; /* * As the timer granularity is in microseconds pad the * requested delay by one to get at least >= requested usec delay. */ usec += 1; if (!thread_yield_microseconds(usec)) return; stopwatch_init_usecs_expire(&sw, usec); while (!stopwatch_expired(&sw)) ; }
static int wait_for_status(uint32_t status_mask, uint32_t status_expected) { uint32_t status; struct stopwatch sw; stopwatch_init_usecs_expire(&sw, MAX_STATUS_TIMEOUT * 1000 * 1000); do { udelay(1000); if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "failed to get expected status %x\n", status_expected); return false; } read_tpm_sts(&status); } while ((status & status_mask) != status_expected); return 1; }
/** * Wait for DisplayPort to be ready * * @param timeout Wait aborts after <timeout> ms. * @return 1: Success or 0: Timeout. */ int google_chromeec_wait_for_displayport(long timeout) { struct stopwatch sw; printk(BIOS_INFO, "Waiting for DisplayPort\n"); stopwatch_init_msecs_expire(&sw, timeout); while (google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT) != 1) { if (stopwatch_expired(&sw)) { printk(BIOS_WARNING, "DisplayPort not ready after %ldms. Abort.\n", timeout); return 0; } mdelay(200); } printk(BIOS_INFO, "DisplayPort ready after %lu ms\n", stopwatch_duration_msecs(&sw)); return 1; }
int ps8640_init(uint8_t bus, uint8_t chip) { u8 set_vdo_done; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, 350); do { i2c_readb(bus, chip + 2, PAGE2_GPIO_H, &set_vdo_done); if (stopwatch_expired(&sw)) { printk(BIOS_INFO, "Failed to init ps8640.\n"); return -1; } } while ((set_vdo_done & PS_GPIO9) != PS_GPIO9); i2c_writeb(bus, chip + 3, PAGE3_SET_ADD, VDO_CTL_ADD); i2c_writeb(bus, chip + 3, PAGE3_SET_VAL, VDO_DIS); i2c_writeb(bus, chip + 3, PAGE3_SET_ADD, VDO_CTL_ADD); i2c_writeb(bus, chip + 3, PAGE3_SET_VAL, VDO_EN); return 0; }
static void rk_edp_init_analog_func(struct rk_edp *edp) { struct stopwatch sw; write32(&edp->regs->dp_pd, 0x00); write32(&edp->regs->common_int_sta_1, PLL_LOCK_CHG); clrbits_le32(&edp->regs->dp_debug_ctl, F_PLL_LOCK | PLL_LOCK_CTRL); stopwatch_init_msecs_expire(&sw, PLL_LOCK_TIMEOUT); while (rk_edp_get_pll_lock_status(edp) == DP_PLL_UNLOCKED) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "%s: PLL is not locked\n", __func__); return; } } /* Enable Serdes FIFO function and Link symbol clock domain module */ clrbits_le32(&edp->regs->func_en_2, SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | AUX_FUNC_EN_N | SSC_FUNC_EN_N); }
static int ccplex_start(void) { struct stopwatch sw; const long timeout_ms = 1500; const uint32_t handshake_mask = 1; const uint32_t cxreset1_mask = 1 << 21; uint32_t reg; struct tegra_pmc_regs * const pmc = PMC_REGS; /* Set the handshake bit to be knocked down. */ write32(&pmc->scratch118, handshake_mask); /* Assert nCXRSET[1] */ reg = read32(CLK_RST_REG(rst_cpu_cmplx_set)); reg |= cxreset1_mask; write32(CLK_RST_REG(rst_cpu_cmplx_set), reg); stopwatch_init_msecs_expire(&sw, timeout_ms); while (1) { reg = read32(&pmc->scratch118); /* Wait for the bit to be knocked down. */ if ((reg & handshake_mask) != handshake_mask) break; if (stopwatch_expired(&sw)) { printk(BIOS_DEBUG, "MTS handshake timeout.\n"); return -1; } } printk(BIOS_DEBUG, "MTS handshake took %ld usecs.\n", stopwatch_duration_usecs(&sw)); return 0; }
void arch_initialize_cpus(device_t cluster, struct cpu_control_ops *cntrl_ops) { size_t max_cpus; size_t i; struct cpu_info *ci; void (*entry)(void); struct bus *bus; if (cluster->path.type != DEVICE_PATH_CPU_CLUSTER) { printk(BIOS_ERR, "CPU init failed. Device is not a CPU_CLUSTER: %s\n", dev_path(cluster)); return; } bus = cluster->link_list; /* Check if no children under this device. */ if (bus == NULL) return; /* * el3_init must be performed prior to prepare_secondary_cpu_startup. * This is important since el3_init initializes SCR values on BSP CPU * and then prepare_secondary_cpu_startup reads the initialized SCR * value and saves it for use by non-BSP CPUs. */ el3_init(); /* Mark current cpu online. */ cpu_mark_online(cpu_info()); entry = prepare_secondary_cpu_startup(); /* Initialize the cpu_info structures. */ init_cpu_info(bus); max_cpus = cntrl_ops->total_cpus(); if (max_cpus > CONFIG_MAX_CPUS) { printk(BIOS_WARNING, "max_cpus (%zu) exceeds CONFIG_MAX_CPUS (%zu).\n", max_cpus, (size_t)CONFIG_MAX_CPUS); max_cpus = CONFIG_MAX_CPUS; } for (i = 0; i < max_cpus; i++) { device_t dev; struct cpu_action action; struct stopwatch sw; ci = cpu_info_for_cpu(i); dev = ci->cpu; /* Disregard CPUs not in device tree. */ if (dev == NULL) continue; /* Skip disabled CPUs. */ if (!dev->enabled) continue; if (!cpu_online(ci)) { /* Start the CPU. */ printk(BIOS_DEBUG, "Starting CPU%x\n", ci->id); if (cntrl_ops->start_cpu(ci->id, entry)) { printk(BIOS_ERR, "Failed to start CPU%x\n", ci->id); continue; } stopwatch_init_msecs_expire(&sw, 1000); /* Wait for CPU to come online. */ while (!stopwatch_expired(&sw)) { if (!cpu_online(ci)) continue; printk(BIOS_DEBUG, "CPU%x online in %ld usecs.\n", ci->id, stopwatch_duration_usecs(&sw)); break; } } if (!cpu_online(ci)) { printk(BIOS_DEBUG, "CPU%x failed to come online in %ld usecs.\n", ci->id, stopwatch_duration_usecs(&sw)); continue; } /* Send it the init action. */ action.run = init_this_cpu; action.arg = ci; arch_run_on_cpu(ci->id, &action); } }
/* * DP H/w Link Training. Set DPCD link rate and bandwidth. * param dp pointer to main s5p-dp structure * param max_lane No of lanes * param max_rate bandwidth * return status */ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp, unsigned int max_lane, unsigned int max_rate) { int pll_is_locked = 0; u32 data; int lane; struct stopwatch sw; struct exynos5_dp *base = dp->base; /* Stop Video */ clrbits_le32(&base->video_ctl_1, VIDEO_EN); stopwatch_init_msecs_expire(&sw, PLL_LOCK_TIMEOUT); while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) { if (stopwatch_expired(&sw)) { /* Ignore this error, and try to continue */ printk(BIOS_ERR, "PLL is not locked yet.\n"); break; } } printk(BIOS_SPEW, "PLL is %slocked\n", pll_is_locked == PLL_LOCKED ? "": "not "); /* Reset Macro */ setbits_le32(&base->dp_phy_test, MACRO_RST); /* 10 us is the minimum reset time. */ udelay(10); clrbits_le32(&base->dp_phy_test, MACRO_RST); /* Set TX pre-emphasis to minimum */ for (lane = 0; lane < max_lane; lane++) if (s5p_dp_set_lane_lane_pre_emphasis(dp, PRE_EMPHASIS_LEVEL_0, lane)) { printk(BIOS_DEBUG, "Unable to set pre emphasis level\n"); return -ERR_PRE_EMPHASIS_LEVELS; } /* All DP analog module power up */ writel(0x00, &base->dp_phy_pd); /* Initialize by reading RX's DPCD */ s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__, dp->link_train.link_rate, dp->link_train.lane_count); if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n", dp->link_train.link_rate); /* Not Retrying */ return -ERR_LINK_RATE_ABNORMAL; } if (dp->link_train.lane_count == 0) { printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n", dp->link_train.lane_count); /* Not retrying */ return -ERR_MAX_LANE_COUNT_ABNORMAL; } /* Setup TX lane count & rate */ if (dp->link_train.lane_count > max_lane) dp->link_train.lane_count = max_lane; if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; /* Set link rate and count as you want to establish*/ writel(dp->link_train.lane_count, &base->lane_count_set); writel(dp->link_train.link_rate, &base->link_bw_set); /* Set sink to D0 (Sink Not Ready) mode. */ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); /* Start HW link training */ writel(HW_TRAINING_EN, &base->dp_hw_link_training); /* Wait until HW link training done */ s5p_dp_wait_hw_link_training_done(dp); /* Get hardware link training status */ data = readl(&base->dp_hw_link_training); printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data); if (data != 0) { printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data); return -ERR_LINK_TRAINING_FAILURE; } /* Get Link Bandwidth */ data = readl(&base->link_bw_set); dp->link_train.link_rate = data; data = readl(&base->lane_count_set); dp->link_train.lane_count = data; printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n", dp->link_train.link_rate, data); return 0; }