int __cpuinit twd_clockchip_init(virtual_addr_t base, virtual_addr_t ref_counter_addr, u32 ref_counter_freq, u32 ppi_hirq) { int rc; u32 cpu = vmm_smp_processor_id(); struct twd_clockchip *cc = &this_cpu(twd_cc); memset(cc, 0, sizeof(struct twd_clockchip)); twd_caliberate_freq(base, ref_counter_addr, ref_counter_freq); vmm_sprintf(cc->name, "twd/%d", cpu); cc->base = base; cc->clkchip.name = cc->name; cc->clkchip.hirq = ppi_hirq; cc->clkchip.rating = 350; cc->clkchip.cpumask = vmm_cpumask_of(cpu); cc->clkchip.features = VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT; cc->clkchip.shift = 20; cc->clkchip.mult = vmm_clockchip_hz2mult(twd_freq_hz, cc->clkchip.shift); cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip); cc->clkchip.max_delta_ns = vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip); cc->clkchip.set_mode = &twd_clockchip_set_mode; cc->clkchip.set_next_event = &twd_clockchip_set_next_event; cc->clkchip.expire = &twd_clockchip_expire; cc->clkchip.priv = cc; if (!cpu) { /* Register interrupt handler */ if ((rc = vmm_host_irq_register(ppi_hirq, "twd", &twd_clockchip_irq_handler, cc))) { return rc; } /* Mark interrupt as per-cpu */ if ((rc = vmm_host_irq_mark_per_cpu(ppi_hirq))) { return rc; } } /* Explicitly enable local timer PPI in GIC * Note: Local timer requires PPI support hence requires GIC */ gic_enable_ppi(ppi_hirq); return vmm_clockchip_register(&cc->clkchip); }
static int __cpuinit twd_clockchip_init(struct vmm_devtree_node *node) { int rc; u32 ref_cnt_freq; virtual_addr_t ref_cnt_addr; u32 cpu = vmm_smp_processor_id(); struct twd_clockchip *cc = &this_cpu(twd_cc); if (!twd_base) { rc = vmm_devtree_regmap(node, &twd_base, 0); if (rc) { goto fail; } } if (!twd_ppi_irq) { rc = vmm_devtree_irq_get(node, &twd_ppi_irq, 0); if (rc) { goto fail_regunmap; } } if (!twd_freq_hz) { /* First try to find TWD clock */ if (!twd_clk) { twd_clk = of_clk_get(node, 0); } if (!twd_clk) { twd_clk = clk_get_sys("smp_twd", NULL); } if (twd_clk) { /* Use TWD clock to find frequency */ rc = clk_prepare_enable(twd_clk); if (rc) { clk_put(twd_clk); goto fail_regunmap; } twd_freq_hz = clk_get_rate(twd_clk); } else { /* No TWD clock found hence caliberate */ rc = vmm_devtree_regmap(node, &ref_cnt_addr, 1); if (rc) { vmm_devtree_regunmap(node, ref_cnt_addr, 1); goto fail_regunmap; } if (vmm_devtree_read_u32(node, "ref-counter-freq", &ref_cnt_freq)) { vmm_devtree_regunmap(node, ref_cnt_addr, 1); goto fail_regunmap; } twd_caliberate_freq(twd_base, ref_cnt_addr, ref_cnt_freq); vmm_devtree_regunmap(node, ref_cnt_addr, 1); } } memset(cc, 0, sizeof(struct twd_clockchip)); vmm_sprintf(cc->name, "twd/%d", cpu); cc->clkchip.name = cc->name; cc->clkchip.hirq = twd_ppi_irq; cc->clkchip.rating = 350; cc->clkchip.cpumask = vmm_cpumask_of(cpu); cc->clkchip.features = VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT; vmm_clocks_calc_mult_shift(&cc->clkchip.mult, &cc->clkchip.shift, VMM_NSEC_PER_SEC, twd_freq_hz, 10); cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip); cc->clkchip.max_delta_ns = vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip); cc->clkchip.set_mode = &twd_clockchip_set_mode; cc->clkchip.set_next_event = &twd_clockchip_set_next_event; cc->clkchip.priv = cc; if (vmm_smp_is_bootcpu()) { /* Register interrupt handler */ if ((rc = vmm_host_irq_register(twd_ppi_irq, "twd", &twd_clockchip_irq_handler, cc))) { goto fail_regunmap; } /* Mark interrupt as per-cpu */ if ((rc = vmm_host_irq_mark_per_cpu(twd_ppi_irq))) { goto fail_unreg_irq; } } /* Explicitly enable local timer PPI in GIC * Note: Local timer requires PPI support hence requires GIC */ gic_enable_ppi(twd_ppi_irq); rc = vmm_clockchip_register(&cc->clkchip); if (rc) { goto fail_unreg_irq; } return VMM_OK; fail_unreg_irq: if (vmm_smp_is_bootcpu()) { vmm_host_irq_unregister(twd_ppi_irq, cc); } fail_regunmap: vmm_devtree_regunmap(node, twd_base, 0); fail: return rc; }
int __cpuinit twd_clockchip_init(virtual_addr_t ref_counter_addr, u32 ref_counter_freq) { int rc; u32 cpu = vmm_smp_processor_id(); struct vmm_devtree_node *node; struct twd_clockchip *cc = &this_cpu(twd_cc); node = vmm_devtree_find_matching(NULL, twd_match); if (!node) { return VMM_ENODEV; } if (!twd_base) { rc = vmm_devtree_regmap(node, &twd_base, 0); if (rc) { return rc; } } if (!twd_ppi_irq) { rc = vmm_devtree_irq_get(node, &twd_ppi_irq, 0); if (rc) { return rc; } } twd_caliberate_freq(twd_base, ref_counter_addr, ref_counter_freq); memset(cc, 0, sizeof(struct twd_clockchip)); vmm_sprintf(cc->name, "twd/%d", cpu); cc->clkchip.name = cc->name; cc->clkchip.hirq = twd_ppi_irq; cc->clkchip.rating = 350; cc->clkchip.cpumask = vmm_cpumask_of(cpu); cc->clkchip.features = VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT; vmm_clocks_calc_mult_shift(&cc->clkchip.mult, &cc->clkchip.shift, VMM_NSEC_PER_SEC, twd_freq_hz, 10); cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip); cc->clkchip.max_delta_ns = vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip); cc->clkchip.set_mode = &twd_clockchip_set_mode; cc->clkchip.set_next_event = &twd_clockchip_set_next_event; cc->clkchip.priv = cc; if (!cpu) { /* Register interrupt handler */ if ((rc = vmm_host_irq_register(twd_ppi_irq, "twd", &twd_clockchip_irq_handler, cc))) { return rc; } /* Mark interrupt as per-cpu */ if ((rc = vmm_host_irq_mark_per_cpu(twd_ppi_irq))) { return rc; } } /* Explicitly enable local timer PPI in GIC * Note: Local timer requires PPI support hence requires GIC */ gic_enable_ppi(twd_ppi_irq); return vmm_clockchip_register(&cc->clkchip); }