status_t platform_set_periodic_timer( platform_timer_callback callback, void *arg, time_t interval) { #ifdef PLATFORM_MSM7X30 unsigned val = 0; unsigned mask = (0x1 << 28); //Check for the hardware revision val = readl(HW_REVISION_NUMBER); if(val & mask) writel(1, DGT_CLK_CTL); #endif enter_critical_section(); timer_callback = callback; timer_arg = arg; timer_interval = interval; writel(timer_interval * (DGT_HZ / 1000), DGT_MATCH_VAL); writel(0, DGT_CLEAR); writel(DGT_ENABLE_EN | DGT_ENABLE_CLR_ON_MATCH_EN, DGT_ENABLE); register_int_handler(INT_DEBUG_TIMER_EXP, timer_irq, 0); unmask_interrupt(INT_DEBUG_TIMER_EXP); exit_critical_section(); return 0; }
status_t ethernet_init(void) { /* check to see if the ethernet feature is turned on */ if ((*REG(SYSINFO_FEATURES) & SYSINFO_FEATURE_NETWORK) == 0) return ERR_NOT_FOUND; struct netif *netif = calloc(sizeof(struct netif), 1); struct ip_addr *ipaddr = calloc(sizeof(struct ip_addr), 1); struct ip_addr *netmask = calloc(sizeof(struct ip_addr), 1); struct ip_addr *gw = calloc(sizeof(struct ip_addr), 1); struct netif *netifret = netif_add(netif, ipaddr, netmask, gw, NULL, ðernetif_init, &ip_input); if (netifret == NULL) { free(netif); free(ipaddr); free(netmask); free(gw); return ERR_NOT_FOUND; } /* register for interrupt handlers */ register_int_handler(INT_NET, ethernet_int, netif); netif_set_default(netif); unmask_interrupt(INT_NET, NULL); return NO_ERROR; }
void arm_generic_timer_init(int irq, uint32_t freq_override) { uint32_t cntfrq; if (freq_override == 0) { cntfrq = read_cntfrq(); if (!cntfrq) { TRACEF("Failed to initialize timer, frequency is 0\n"); return; } } else { cntfrq = freq_override; } #if LOCAL_TRACE LTRACEF("Test min cntfrq\n"); arm_generic_timer_init_conversion_factors(1); test_time_conversions(1); LTRACEF("Test max cntfrq\n"); arm_generic_timer_init_conversion_factors(~0); test_time_conversions(~0); LTRACEF("Set actual cntfrq\n"); #endif arm_generic_timer_init_conversion_factors(cntfrq); test_time_conversions(cntfrq); LTRACEF("register irq %d on cpu %d\n", irq, arch_curr_cpu_num()); register_int_handler(irq, &platform_tick, NULL); unmask_interrupt(irq); timer_irq = irq; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { LTRACEF("callback %p, arg %p, interval %lu\n", callback, arg, interval); enter_critical_section(); t_callback = callback; /* disable the timer */ ARM64_WRITE_SYSREG(CNTP_CTL_EL0, 0); /* set the countdown register to max */ ARM64_WRITE_SYSREG(CNTP_TVAL_EL0, INT32_MAX); /* calculate the compare delta and set the comparison register */ interval_delta = (uint64_t)timer_freq * interval / 1000U; last_compare = read_counter() + interval_delta; ARM64_WRITE_SYSREG(CNTP_CVAL_EL0, last_compare); ARM64_WRITE_SYSREG(CNTP_CTL_EL0, 1); unmask_interrupt(INT_PPI_NSPHYS_TIMER); exit_critical_section(); return NO_ERROR; }
/* Enable BAM and pipe level interrupts */ void bam_enable_interrupts(struct bam_instance *bam, uint8_t pipe_num) { uint32_t int_mask = P_ERR_EN_MASK | P_OUT_OF_DESC_EN_MASK | P_PRCSD_DESC_EN_MASK | P_TRNSFR_END_EN_MASK; uint32_t val; /* Enable BAM error interrupts */ writel(BAM_ERROR_EN_MASK, BAM_IRQ_EN_REG(bam->base)); /* Enable the interrupts for the pipe by enabling the relevant bits * in the BAM_PIPE_INTERRUPT_ENABLE register. */ writel(int_mask, BAM_P_IRQ_ENn(bam->pipe[pipe_num].pipe_num, bam->base)); /* Enable pipe interrups */ /* Do read-modify-write */ val = readl(BAM_IRQ_SRCS_MSK(bam->base)); writel((1 << bam->pipe[pipe_num].pipe_num) | val, BAM_IRQ_SRCS_MSK(bam->base)); /* Unmask the QGIC interrupts only in the case of * interrupt based transfer. * Use polling othwerwise. */ if (bam->pipe[pipe_num].int_mode) { /* Register interrupt handler */ register_int_handler(bam->pipe[pipe_num].spi_num, bam_interrupt_handler, 0); /* Unmask the interrupt */ unmask_interrupt(bam->pipe[pipe_num].spi_num); } }
int smd_init(smd_channel_info_t *ch, uint32_t ch_type) { unsigned ret = 0; smd_channel_alloc_entry = (smd_channel_alloc_entry_t*)memalign(CACHE_LINE, SMD_CHANNEL_ALLOC_MAX); ASSERT(smd_channel_alloc_entry); ret = smem_read_alloc_entry(SMEM_CHANNEL_ALLOC_TBL, (void*)smd_channel_alloc_entry, SMD_CHANNEL_ALLOC_MAX); if(ret) { dprintf(CRITICAL,"ERROR reading smem channel alloc tbl\n"); return -1; } smd_get_channel_info(ch, ch_type); register_int_handler(SMD_IRQ, smd_irq_handler, ch); unmask_interrupt(SMD_IRQ); smd_set_state(ch, SMD_SS_OPENING, 1); smd_notify_rpm(); return 0; }
void platform_init_timer(void) { #if 0 OS_TIMER_CTRL_REG = 0; // stop the timer if it's already running register_int_handler(IRQ_OS_TIMER, &os_timer_tick, NULL); unmask_interrupt(IRQ_OS_TIMER, NULL); #endif }
void __attribute__((noreturn)) thread_n_main(void) { boot_init_thread(); unmask_interrupt(1); // Enable timer interrupt // Idle task for (;;) reschedule(); }
void uart_init(void) { /* finish uart init to get rx going */ cbuf_initialize(&uart_rx_buf, 16); register_int_handler(0x24, uart_irq_handler, NULL); unmask_interrupt(0x24); outp(uart_io_port + 1, 0x1); // enable receive data available interrupt }
static void arm_cortex_a9_timer_init_percpu(uint level) { /* disable timer */ TIMREG(TIMER_CONTROL) = 0; /* kill the watchdog */ TIMREG(WDOG_CONTROL) = 0; /* ack any irqs that may be pending */ TIMREG(TIMER_ISR) = 1; /* register the platform tick on each cpu */ register_int_handler(CPU_PRIV_TIMER_INT, &platform_tick, NULL); unmask_interrupt(CPU_PRIV_TIMER_INT); }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { enter_critical_section(); t_callback = callback; periodic_interval = interval; TIMREG(LOADVAL) = periodic_interval * 1000; /* timer is running at 1Mhz */ TIMREG(CONTROL) |= (1<<7); // enable unmask_interrupt(TIMER01_INT); exit_critical_section(); return NO_ERROR; }
/* * Function: sdhci msm init * Arg : MSM specific config data for sdhci * Return : None * Flow: : Enable sdhci mode & do msm specific init */ void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config) { /* Disable HC mode */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0); /* Core power reset */ RMWREG32((config->pwrctl_base + SDCC_MCI_POWER), CORE_SW_RST_START, CORE_SW_RST_WIDTH, 1); /* Wait for the core power reset to complete*/ mdelay(1); /* Enable sdhc mode */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, SDHCI_HC_MODE_EN); /* Set the FF_CLK_SW_RST_DIS to 1 */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1); /* * Reset the controller */ sdhci_reset(host, SDHCI_SOFT_RESET); /* * CORE_SW_RST may trigger power irq if previous status of PWRCTL * was either BUS_ON or IO_HIGH. So before we enable the power irq * interrupt in GIC (by registering the interrupt handler), we need to * ensure that any pending power irq interrupt status is acknowledged * otherwise power irq interrupt handler would be fired prematurely. */ sdhci_clear_power_ctrl_irq(config); /* * Register the interrupt handler for pwr irq */ register_int_handler(config->pwr_irq, sdhci_int_handler, (void *)config); unmask_interrupt(config->pwr_irq); /* Enable pwr control interrupt */ writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG)); config->tuning_done = false; config->calibration_done = false; host->tuning_in_progress = false; }
static void imx_uart_init(const void* driver_data, uint32_t length) { uint32_t regVal; // create circular buffer to hold received data cbuf_initialize(&uart_rx_buf, RXBUF_SIZE); // register uart irq register_int_handler(uart_irq, &uart_irq_handler, NULL); // set rx fifo threshold to 1 character regVal = UARTREG(MX8_UFCR); regVal &= ~UFCR_RXTL(UFCR_MASK); regVal &= ~UFCR_TXTL(UFCR_MASK); regVal |= UFCR_RXTL(1); regVal |= UFCR_TXTL(0x2); UARTREG(MX8_UFCR) = regVal; // enable rx interrupt regVal = UARTREG(MX8_UCR1); regVal |= UCR1_RRDYEN; if (dlog_bypass() == false) { // enable tx interrupt regVal |= UCR1_TRDYEN; } UARTREG(MX8_UCR1) = regVal; // enable rx and tx transmisster regVal = UARTREG(MX8_UCR2); regVal |= UCR2_RXEN | UCR2_TXEN; UARTREG(MX8_UCR2) = regVal; if (dlog_bypass() == true) { uart_tx_irq_enabled = false; } else { /* start up tx driven output */ printf("UART: started IRQ driven TX\n"); uart_tx_irq_enabled = true; } initialized = true; // enable interrupts unmask_interrupt(uart_irq); }
int smd_init(smd_channel_info_t *ch, uint32_t ch_type) { unsigned ret = 0; int chnl_found = 0; uint64_t timeout = SMD_CHANNEL_ACCESS_RETRY; smd_channel_alloc_entry = (smd_channel_alloc_entry_t*)memalign(CACHE_LINE, SMD_CHANNEL_ALLOC_MAX); ASSERT(smd_channel_alloc_entry); dprintf(INFO, "Waiting for the RPM to populate smd channel table\n"); do { ret = smem_read_alloc_entry(SMEM_CHANNEL_ALLOC_TBL, (void*)smd_channel_alloc_entry, SMD_CHANNEL_ALLOC_MAX); if(ret) { dprintf(CRITICAL,"ERROR reading smem channel alloc tbl\n"); return -1; } chnl_found = smd_get_channel_info(ch, ch_type); timeout--; udelay(10); } while(timeout && chnl_found); if (!timeout) { dprintf(CRITICAL, "Apps timed out waiting for RPM-->APPS channel entry\n"); ASSERT(0); } register_int_handler(SMD_IRQ, smd_irq_handler, ch); smd_set_state(ch, SMD_SS_OPENING, 1); smd_notify_rpm(); unmask_interrupt(SMD_IRQ); return 0; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { enter_critical_section(); t_callback = callback; callback_arg = arg; tick_interval = interval; uint32_t ticks_per_interval = (uint64_t)interval * TIMER_TICK_RATE / 1000; // interval is in ms TIMER_REG(TCLR) = 0; // stop the timer TIMER_REG(TLDR) = -ticks_per_interval; TIMER_REG(TTGR) = 1; TIMER_REG(TIER) = 0x2; TIMER_REG(TCLR) = 0x3; // autoreload, start unmask_interrupt(GPT2_IRQ); exit_critical_section(); return NO_ERROR; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { uint32_t tick_count = interval * platform_tick_rate() / 1000; enter_critical_section(); timer_callback = callback; timer_arg = arg; timer_interval = interval; writel(tick_count, DGT_MATCH_VAL); writel(0, DGT_CLEAR); writel(DGT_ENABLE_EN | DGT_ENABLE_CLR_ON_MATCH_EN, DGT_ENABLE); register_int_handler(INT_DEBUG_TIMER_EXP, timer_irq, 0); unmask_interrupt(INT_DEBUG_TIMER_EXP); exit_critical_section(); return 0; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { spin_lock_saved_state_t statep; arch_interrupt_save(&statep, SPIN_LOCK_FLAG_IRQ); t_callback = callback; callback_arg = arg; tick_interval = interval; uint32_t ticks_per_interval = (uint64_t)interval * TIMER_TICK_RATE / 1000; // interval is in ms TIMER_REG(TCLR) = 0; // stop the timer TIMER_REG(TLDR) = -ticks_per_interval; TIMER_REG(TTGR) = 1; TIMER_REG(TIER) = 0x2; TIMER_REG(TCLR) = 0x3; // autoreload, start unmask_interrupt(GPT2_IRQ); arch_interrupt_restore(statep, SPIN_LOCK_FLAG_IRQ); return NO_ERROR; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { enter_critical_section(); LTRACEF("callback %p, arg %p, interval %lu\n", callback, arg, interval); t_callback = callback; periodic_interval = interval; uint32_t ticks = periodic_interval * 1000; /* timer is running close to 1Mhz */ ASSERT(ticks <= 0xffff); TIMREG(IEN(0)) = (1<<0); // interval interrupt TIMREG(INTERVAL_VAL(0)) = ticks; TIMREG(CNT_CTRL(0)) = (1<<5) | (1<<4) | (1<<1); // no wave, reset, interval mode unmask_interrupt(TTC0_A_INT); exit_critical_section(); return NO_ERROR; }
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { uint32_t tick_count = interval * ticks_per_sec / 1000; spin_lock_saved_state_t state; spin_lock_irqsave(&lock, state); timer_callback = callback; timer_arg = arg; timer_interval = interval; writel(tick_count, DGT_MATCH_VAL); writel(0, DGT_CLEAR); writel(DGT_ENABLE_EN | DGT_ENABLE_CLR_ON_MATCH_EN, DGT_ENABLE); register_int_handler(INT_DEBUG_TIMER_EXP, timer_irq, 0); unmask_interrupt(INT_DEBUG_TIMER_EXP); spin_unlock_irqrestore(&lock, state); return 0; }
status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) { LTRACEF("callback %p, arg %p, interval %lu\n", callback, arg, interval); enter_critical_section(); t_callback = callback; /* disable the timer */ ARM64_WRITE_SYSREG(CNTP_CTL_EL0, 0); /* set the countdown register to max */ ARM64_WRITE_SYSREG(CNTP_TVAL_EL0, INT32_MAX); /* calculate the interval */ uint64_t ticks = (uint64_t)timer_freq * interval / 1000U; /* set the comparison register */ uint64_t counter = read_counter(); counter += ticks; LTRACEF("new counter 0x%llx ticks %llu\n", counter, ticks); ARM64_WRITE_SYSREG(CNTP_CVAL_EL0, counter); /* disable periodic mode */ interval_delta = 0; /* start the timer, unmask irq */ ARM64_WRITE_SYSREG(CNTP_CTL_EL0, 1); unmask_interrupt(INT_PPI_NSPHYS_TIMER); exit_critical_section(); return NO_ERROR; }
void arm_cortex_a9_timer_init(addr_t _scu_control_base, uint32_t freq) { scu_control_base = _scu_control_base; /* disable timer */ TIMREG(TIMER_CONTROL) = 0; /* kill the watchdog */ TIMREG(WDOG_CONTROL) = 0; /* ack any irqs that may be pending */ TIMREG(TIMER_ISR) = 1; /* save the timer frequency for later calculations */ timer_freq = freq; /* precompute the conversion factor for global time to real time */ fp_32_64_div_32_32(&timer_freq_msec_conversion, timer_freq, 1000); fp_32_64_div_32_32(&timer_freq_usec_conversion_inverse, 1000000, timer_freq); fp_32_64_div_32_32(&timer_freq_msec_conversion_inverse, 1000, timer_freq); register_int_handler(CPU_PRIV_TIMER_INT, &platform_tick, NULL); unmask_interrupt(CPU_PRIV_TIMER_INT); }
void register_interrupt_handler(int interrupt, interrupt_handler_t handler) { // XXX lock handlers[interrupt] = handler; unmask_interrupt(interrupt); }
static void arm_generic_timer_init_secondary_cpu(uint level) { LTRACEF("register irq %d on cpu %d\n", timer_irq, arch_curr_cpu_num()); register_int_handler(timer_irq, &platform_tick, NULL); unmask_interrupt(timer_irq); }
static void pc_init_timer(uint level) { const struct x86_model_info* cpu_model = x86_get_model(); constant_tsc = false; if (x86_vendor == X86_VENDOR_INTEL) { /* This condition taken from Intel 3B 17.15 (Time-Stamp Counter). This * is the negation of the non-Constant TSC section, since the Constant * TSC section is incomplete (the behavior is architectural going * forward, and modern CPUs are not on the list). */ constant_tsc = !((cpu_model->family == 0x6 && cpu_model->model == 0x9) || (cpu_model->family == 0x6 && cpu_model->model == 0xd) || (cpu_model->family == 0xf && cpu_model->model < 0x3)); } invariant_tsc = x86_feature_test(X86_FEATURE_INVAR_TSC); bool has_pvclock = pvclock_is_present(); if (has_pvclock) { zx_status_t status = pvclock_init(); if (status == ZX_OK) { invariant_tsc = pvclock_is_stable(); } else { has_pvclock = false; } } bool has_hpet = hpet_is_present(); if (has_hpet) { calibration_clock = CLOCK_HPET; const uint64_t hpet_ms_rate = hpet_ticks_per_ms(); ASSERT(hpet_ms_rate <= UINT32_MAX); printf("HPET frequency: %" PRIu64 " ticks/ms\n", hpet_ms_rate); fp_32_64_div_32_32(&ns_per_hpet, 1000 * 1000, static_cast<uint32_t>(hpet_ms_rate)); // Add 1ns to conservatively deal with rounding ns_per_hpet_rounded_up = u32_mul_u64_fp32_64(1, ns_per_hpet) + 1; } else { calibration_clock = CLOCK_PIT; } const char* force_wallclock = cmdline_get("kernel.wallclock"); bool use_invariant_tsc = invariant_tsc && (!force_wallclock || !strcmp(force_wallclock, "tsc")); use_tsc_deadline = use_invariant_tsc && x86_feature_test(X86_FEATURE_TSC_DEADLINE); if (!use_tsc_deadline) { calibrate_apic_timer(); } if (use_invariant_tsc) { calibrate_tsc(has_pvclock); // Program PIT in the software strobe configuration, but do not load // the count. This will pause the PIT. outp(I8253_CONTROL_REG, 0x38); wall_clock = CLOCK_TSC; } else { if (constant_tsc || invariant_tsc) { // Calibrate the TSC even though it's not as good as we want, so we // can still let folks still use it for cheap timing. calibrate_tsc(has_pvclock); } if (has_hpet && (!force_wallclock || !strcmp(force_wallclock, "hpet"))) { wall_clock = CLOCK_HPET; hpet_set_value(0); hpet_enable(); } else { if (force_wallclock && strcmp(force_wallclock, "pit")) { panic("Could not satisfy kernel.wallclock choice\n"); } wall_clock = CLOCK_PIT; set_pit_frequency(1000); // ~1ms granularity uint32_t irq = apic_io_isa_to_global(ISA_IRQ_PIT); zx_status_t status = register_int_handler(irq, &pit_timer_tick, NULL); DEBUG_ASSERT(status == ZX_OK); unmask_interrupt(irq); } } printf("timer features: constant_tsc %d invariant_tsc %d tsc_deadline %d\n", constant_tsc, invariant_tsc, use_tsc_deadline); printf("Using %s as wallclock\n", clock_name[wall_clock]); }
int msm_i2c_xfer(struct i2c_msg msgs[], int num) { int ret, ret_wait; clk_enable(dev.pdata->clk_nr); unmask_interrupt(dev.pdata->irq_nr); ret = msm_i2c_poll_notbusy(1); if (ret) { ret = msm_i2c_recover_bus_busy(); if (ret) goto err; } enter_critical_section(); if (dev.flush_cnt) { I2C_DBG(DEBUGLEVEL, "%d unrequested bytes read\n", dev.flush_cnt); } dev.msg = msgs; dev.rem = num; dev.pos = -1; dev.ret = num; dev.need_flush = false; dev.flush_cnt = 0; dev.cnt = msgs->len; msm_i2c_interrupt_locked(); exit_critical_section(); /* * Now that we've setup the xfer, the ISR will transfer the data * and wake us up with dev.err set if there was an error */ ret_wait = msm_i2c_poll_notbusy(0); /* Read may not have stopped in time */ enter_critical_section(); if (dev.flush_cnt) { I2C_DBG(DEBUGLEVEL, "%d unrequested bytes read\n", dev.flush_cnt); } ret = dev.ret; dev.msg = NULL; dev.rem = 0; dev.pos = 0; dev.ret = 0; dev.flush_cnt = 0; dev.cnt = 0; exit_critical_section(); if (ret_wait) { I2C_DBG(DEBUGLEVEL, "Still busy after xfer completion\n"); ret_wait = msm_i2c_recover_bus_busy(); if (ret_wait) goto err; } if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = ERR_TIMED_OUT; } if (ret < 0) { I2C_ERR("Error during data xfer (%d)\n", ret); msm_i2c_recover_bus_busy(); } /* if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = 2; msm_i2c_recover_bus_busy(); } if (timeout == ERR_TIMED_OUT) { I2C_DBG(DEBUGLEVEL, "Transaction timed out\n"); ret = ERR_TIMED_OUT; } if (ret < 0) { I2C_ERR("Error during data xfer (%d)\n", ret); msm_i2c_recover_bus_busy(); } */ err: mask_interrupt(dev.pdata->irq_nr); clk_disable(dev.pdata->clk_nr); return ret; }
/* * Function: sdhci msm init * Arg : MSM specific config data for sdhci * Return : None * Flow: : Enable sdhci mode & do msm specific init */ void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config) { uint32_t io_switch; uint32_t caps = 0; uint32_t version; /* Disable HC mode */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0); /* Core power reset */ RMWREG32((config->pwrctl_base + SDCC_MCI_POWER), CORE_SW_RST_START, CORE_SW_RST_WIDTH, 1); /* Wait for the core power reset to complete*/ mdelay(1); /* Enable sdhc mode */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, SDHCI_HC_MODE_EN); /* Set the FF_CLK_SW_RST_DIS to 1 */ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1); /* * Reset the controller */ sdhci_reset(host, SDHCI_SOFT_RESET); /* * Some platforms have same SDC instance shared between emmc & sd card. * For such platforms the emmc IO voltage has to be switched from 3.3 to * 1.8 for the contoller to work with emmc. */ if(config->use_io_switch) { io_switch = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC); io_switch |= HC_IO_PAD_PWR_SWITCH | HC_IO_PAD_PWR_SWITCH_EN; REG_WRITE32(host, io_switch, SDCC_VENDOR_SPECIFIC_FUNC); } /* * CORE_SW_RST may trigger power irq if previous status of PWRCTL * was either BUS_ON or IO_HIGH. So before we enable the power irq * interrupt in GIC (by registering the interrupt handler), we need to * ensure that any pending power irq interrupt status is acknowledged * otherwise power irq interrupt handler would be fired prematurely. */ sdhci_clear_power_ctrl_irq(config); /* * Register the interrupt handler for pwr irq */ register_int_handler(config->pwr_irq, (int_handler)sdhci_int_handler, (void *)config); unmask_interrupt(config->pwr_irq); /* Enable pwr control interrupt */ writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG)); version = readl(host->msm_host->pwrctl_base + MCI_VERSION); host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT; host->minor = (version & CORE_VERSION_MINOR_MASK); /* * For SDCC5 the capabilities registers does not have voltage advertised * Override the values using SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0 */ if (host->major >= 1 && host->minor != 0x11 && host->minor != 0x12) { caps = REG_READ32(host, SDHCI_CAPS_REG1); if (config->slot == 0x1) REG_WRITE32(host, (caps | SDHCI_1_8_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0); else REG_WRITE32(host, (caps | SDHCI_3_0_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0); } config->tuning_done = false; config->calibration_done = false; host->tuning_in_progress = false; }
int virtio_mmio_detect(void *ptr, uint count, const uint irqs[]) { LTRACEF("ptr %p, count %u\n", ptr, count); DEBUG_ASSERT(ptr); DEBUG_ASSERT(irqs); DEBUG_ASSERT(!devices); /* allocate an array big enough to hold a list of devices */ devices = calloc(count, sizeof(struct virtio_device)); if (!devices) return ERR_NO_MEMORY; int found = 0; for (uint i = 0; i < count; i++) { volatile struct virtio_mmio_config *mmio = (struct virtio_mmio_config *)((uint8_t *)ptr + i * 0x200); struct virtio_device *dev = &devices[i]; dev->index = i; dev->irq = irqs[i]; mask_interrupt(irqs[i]); register_int_handler(irqs[i], &virtio_mmio_irq, (void *)dev); LTRACEF("looking at magic 0x%x version 0x%x did 0x%x vid 0x%x\n", mmio->magic, mmio->version, mmio->device_id, mmio->vendor_id); if (mmio->magic != VIRTIO_MMIO_MAGIC) { continue; } #if LOCAL_TRACE if (mmio->device_id != 0) { dump_mmio_config(mmio); } #endif #if WITH_DEV_VIRTIO_BLOCK if (mmio->device_id == 2) { // block device LTRACEF("found block device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_block_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); // XXX quick test code, remove #if 0 uint8_t buf[512]; memset(buf, 0x99, sizeof(buf)); virtio_block_read_write(dev, buf, 0, sizeof(buf), false); hexdump8_ex(buf, sizeof(buf), 0); buf[0]++; virtio_block_read_write(dev, buf, 0, sizeof(buf), true); virtio_block_read_write(dev, buf, 0, sizeof(buf), false); hexdump8_ex(buf, sizeof(buf), 0); #endif } } #endif // WITH_DEV_VIRTIO_BLOCK #if WITH_DEV_VIRTIO_NET if (mmio->device_id == 1) { // network device LTRACEF("found net device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_net_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); } } #endif // WITH_DEV_VIRTIO_NET #if WITH_DEV_VIRTIO_GPU if (mmio->device_id == 0x10) { // virtio-gpu LTRACEF("found gpu device\n"); dev->mmio_config = mmio; dev->config_ptr = (void *)mmio->config; status_t err = virtio_gpu_init(dev, mmio->host_features); if (err >= 0) { // good device dev->valid = true; if (dev->irq_driver_callback) unmask_interrupt(dev->irq); virtio_gpu_start(dev); } } #endif // WITH_DEV_VIRTIO_GPU if (dev->valid) found++; } return found; }