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; }
/* 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 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; }
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)); }
/* * 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; }
/* * 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 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 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; }
/** * 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; }
static void wait_for_legacy_dev(void *unused) { uint32_t legacy_delay, us_since_boot; struct stopwatch sw; /* Open main hwinfo block. */ if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS) return; /* Get legacy delay parameter from hwinfo. */ if (hwilib_get_field(LegacyDelay, (uint8_t *) &legacy_delay, sizeof(legacy_delay)) != sizeof(legacy_delay)) return; us_since_boot = get_us_since_boot(); /* No need to wait if the time since boot is already long enough.*/ if (us_since_boot > legacy_delay) return; stopwatch_init_msecs_expire(&sw, (legacy_delay - us_since_boot) / 1000); printk(BIOS_NOTICE, "Wait remaining %d of %d us for legacy devices...", legacy_delay - us_since_boot, legacy_delay); stopwatch_wait_until_expired(&sw); printk(BIOS_NOTICE, "done!\n"); }
/* * 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; }
static int cr50_i2c_tis_send(struct tpm_chip *chip, uint8_t *buf, size_t len) { int status; size_t burstcnt, limit, sent = 0; uint8_t tpm_go[4] = { TPM_STS_GO }; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_LONG_MS); /* Wait until TPM is ready for a command */ while (!(cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "%s: Command ready timeout\n", __func__); return -1; } cr50_i2c_tis_ready(chip); } while (len > 0) { uint8_t mask = TPM_STS_VALID; /* Wait for data if this is not the first chunk */ if (sent > 0) mask |= TPM_STS_DATA_EXPECT; /* Read burst count and check status */ if (cr50_i2c_wait_burststs(chip, mask, &burstcnt, &status) < 0) goto out_err; /* Use burstcnt - 1 to account for the address byte * that is inserted by cr50_i2c_write() */ limit = min(burstcnt - 1, len); if (cr50_i2c_write(chip, TPM_DATA_FIFO(chip->vendor.locality), &buf[sent], limit) != 0) { printk(BIOS_ERR, "%s: Write failed\n", __func__); goto out_err; } sent += limit; len -= limit; } /* Ensure TPM is not expecting more data */ if (cr50_i2c_wait_burststs(chip, TPM_STS_VALID, &burstcnt, &status) < 0) goto out_err; if (status & TPM_STS_DATA_EXPECT) { printk(BIOS_ERR, "%s: Data still expected\n", __func__); goto out_err; } /* Start the TPM command */ if (cr50_i2c_write(chip, TPM_STS(chip->vendor.locality), tpm_go, sizeof(tpm_go)) < 0) { printk(BIOS_ERR, "%s: Start command failed\n", __func__); goto out_err; } return sent; out_err: /* Abort current transaction if still pending */ if (cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) cr50_i2c_tis_ready(chip); return -1; }
static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg, enum i2c_modes read) { uint32_t ret_code = I2C_OK; uint16_t status; uint32_t time_out_val = 0; uint8_t addr; uint32_t write_len = 0; uint32_t read_len = 0; uint8_t *write_buffer = NULL; uint8_t *read_buffer = NULL; struct mt8173_i2c_regs *regs; struct mt8173_i2c_dma_regs *dma_regs; struct stopwatch sw; regs = i2c[bus].i2c_regs; dma_regs = i2c[bus].i2c_dma_regs; addr = seg[0].slave; switch (read) { case I2C_WRITE_MODE: assert(seg[0].len > 0 && seg[0].len <= 255); write_len = seg[0].len; write_buffer = seg[0].buf; break; case I2C_READ_MODE: assert(seg[0].len > 0 && seg[0].len <= 255); read_len = seg[0].len; read_buffer = seg[0].buf; break; /* Must use special write-then-read mode for repeated starts. */ case I2C_WRITE_READ_MODE: assert(seg[0].len > 0 && seg[0].len <= 255); assert(seg[1].len > 0 && seg[1].len <= 255); write_len = seg[0].len; read_len = seg[1].len; write_buffer = seg[0].buf; read_buffer = seg[1].buf; break; } /* Clear interrupt status */ write32(®s->intr_stat, I2C_TRANSAC_COMP | I2C_ACKERR | I2C_HS_NACKERR); write32(®s->fifo_addr_clr, 0x1); /* Enable interrupt */ write32(®s->intr_mask, I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP); switch (read) { case I2C_WRITE_MODE: memcpy(_dma_coherent, write_buffer, write_len); /* control registers */ write32(®s->control, ACK_ERR_DET_EN | DMA_EN | CLK_EXT | REPEATED_START_FLAG); /* Set transfer and transaction len */ write32(®s->transac_len, 1); write32(®s->transfer_len, write_len); /* set i2c write slave address*/ write32(®s->slave_addr, addr << 1); /* Prepare buffer data to start transfer */ write32(&dma_regs->dma_con, I2C_DMA_CON_TX); write32(&dma_regs->dma_tx_mem_addr, (uintptr_t)_dma_coherent); write32(&dma_regs->dma_tx_len, write_len); break; case I2C_READ_MODE: /* control registers */ write32(®s->control, ACK_ERR_DET_EN | DMA_EN | CLK_EXT | REPEATED_START_FLAG); /* Set transfer and transaction len */ write32(®s->transac_len, 1); write32(®s->transfer_len, read_len); /* set i2c read slave address*/ write32(®s->slave_addr, (addr << 1 | 0x1)); /* Prepare buffer data to start transfer */ write32(&dma_regs->dma_con, I2C_DMA_CON_RX); write32(&dma_regs->dma_rx_mem_addr, (uintptr_t)_dma_coherent); write32(&dma_regs->dma_rx_len, read_len); break; case I2C_WRITE_READ_MODE: memcpy(_dma_coherent, write_buffer, write_len); /* control registers */ write32(®s->control, DIR_CHG | ACK_ERR_DET_EN | DMA_EN | CLK_EXT | REPEATED_START_FLAG); /* Set transfer and transaction len */ write32(®s->transfer_len, write_len); write32(®s->transfer_aux_len, read_len); write32(®s->transac_len, 2); /* set i2c write slave address*/ write32(®s->slave_addr, addr << 1); /* Prepare buffer data to start transfer */ write32(&dma_regs->dma_con, I2C_DMA_CLR_FLAG); write32(&dma_regs->dma_tx_mem_addr, (uintptr_t)_dma_coherent); write32(&dma_regs->dma_tx_len, write_len); write32(&dma_regs->dma_rx_mem_addr, (uintptr_t)_dma_coherent); write32(&dma_regs->dma_rx_len, read_len); break; } write32(&dma_regs->dma_int_flag, I2C_DMA_CLR_FLAG); write32(&dma_regs->dma_en, I2C_DMA_START_EN); /* start transfer transaction */ write32(®s->start, 0x1); stopwatch_init_msecs_expire(&sw, 100); /* polling mode : see if transaction complete */ while (1) { status = read32(®s->intr_stat); if (status & I2C_HS_NACKERR) { ret_code = I2C_TRANSFER_FAIL_HS_NACKERR; I2CERR("[i2c%d transfer] transaction NACK error\n", bus); mtk_i2c_dump_info(bus); break; } else if (status & I2C_ACKERR) { ret_code = I2C_TRANSFER_FAIL_ACKERR; I2CERR("[i2c%d transfer] transaction ACK error\n", bus); mtk_i2c_dump_info(bus); break; } else if (status & I2C_TRANSAC_COMP) { ret_code = I2C_OK; memcpy(read_buffer, _dma_coherent, read_len); break; } if (stopwatch_expired(&sw)) { ret_code = I2C_TRANSFER_FAIL_TIMEOUT; I2CERR("[i2c%d transfer] transaction timeout:%d\n", bus, time_out_val); mtk_i2c_dump_info(bus); break; } } write32(®s->intr_stat, I2C_TRANSAC_COMP | I2C_ACKERR | I2C_HS_NACKERR); /* clear bit mask */ write32(®s->intr_mask, I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP); /* reset the i2c controller for next i2c transfer. */ write32(®s->softreset, 0x1); i2c_dma_reset(dma_regs); return ret_code; }
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); } }
/* * Each TPM2 SPI transaction starts the same: CS is asserted, the 4 byte * header is sent to the TPM, the master waits til TPM is ready to continue. * * Returns 1 on success, 0 on failure (TPM SPI flow control timeout.) */ static int start_transaction(int read_write, size_t bytes, unsigned addr) { spi_frame_header header; uint8_t byte; int i; struct stopwatch sw; static int tpm_sync_needed CAR_GLOBAL; static struct stopwatch wake_up_sw CAR_GLOBAL; struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); /* * First Cr50 access in each coreboot stage where TPM is used will be * prepended by a wake up pulse on the CS line. */ int wakeup_needed = 1; /* Wait for TPM to finish previous transaction if needed */ if (car_get_var(tpm_sync_needed)) { tpm_sync(); /* * During the first invocation of this function on each stage * this if () clause code does not run (as tpm_sync_needed * value is zero), during all following invocations the * stopwatch below is guaranteed to be started. */ if (!stopwatch_expired(car_get_var_ptr(&wake_up_sw))) wakeup_needed = 0; } else { car_set_var(tpm_sync_needed, 1); } if (wakeup_needed) { /* Just in case Cr50 is asleep. */ spi_claim_bus(spi_slave); udelay(1); spi_release_bus(spi_slave); udelay(100); } /* * The Cr50 on H1 does not go to sleep for 1 second after any * SPI slave activity, let's be conservative and limit the * window to 900 ms. */ stopwatch_init_msecs_expire(car_get_var_ptr(&wake_up_sw), 900); /* * The first byte of the frame header encodes the transaction type * (read or write) and transfer size (set to lentgh - 1), limited to * 64 bytes. */ header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1); /* The rest of the frame header is the TPM register address. */ for (i = 0; i < 3; i++) header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff; /* CS assert wakes up the slave. */ spi_claim_bus(spi_slave); /* * The TCG TPM over SPI specification introduces the notion of SPI * flow control (Section "6.4.5 Flow Control"). * * Again, the slave (TPM device) expects each transaction to start * with a 4 byte header trasmitted by master. The header indicates if * the master needs to read or write a register, and the register * address. * * If the slave needs to stall the transaction (for instance it is not * ready to send the register value to the master), it sets the MOSI * line to 0 during the last clock of the 4 byte header. In this case * the master is supposed to start polling the SPI bus, one byte at * time, until the last bit in the received byte (transferred during * the last clock of the byte) is set to 1. * * Due to some SPI controllers' shortcomings (Rockchip comes to * mind...) we trasmit the 4 byte header without checking the byte * transmitted by the TPM during the transaction's last byte. * * We know that cr50 is guaranteed to set the flow control bit to 0 * during the header transfer, but real TPM2 might be fast enough not * to require to stall the master, this would present an issue. * crosbug.com/p/52132 has been opened to track this. */ spi_xfer(spi_slave, header.body, sizeof(header.body), NULL, 0); /* * Now poll the bus until TPM removes the stall bit. Give it up to 100 * ms to sort it out - it could be saving stuff in nvram at some * point. */ stopwatch_init_msecs_expire(&sw, 100); do { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "TPM flow control failure\n"); spi_release_bus(spi_slave); return 0; } spi_xfer(spi_slave, NULL, 0, &byte, 1); } while (!(byte & 1)); return 1; }