/* * The PMU contains a register to reset various subsystems within the * SoC. Export this as a reset controller.
*/ #ifdef CONFIG_RESET_CONTROLLER #define rcdev_to_pmu(rcdev) container_of(rcdev, struct pmu_data, reset)
/* * This deals with the "old" Marvell sequence of bringing a power domain * down/up, which is: apply power, release reset, disable isolators. * * Later devices apparantly use a different sequence: power up, disable * isolators, assert repair signal, enable SRMA clock, enable AXI clock, * enable module clock, deassert reset. * * Note: reading the assembly, it seems that the IO accessors have an * unfortunate side-effect - they cause memory already read into registers * for the if () to be re-read for the bit-set or bit-clear operation. * The code is written to avoid this.
*/ staticint pmu_domain_power_off(struct generic_pm_domain *domain)
{ struct pmu_domain *pmu_dom = to_pmu_domain(domain); struct pmu_data *pmu = pmu_dom->pmu; unsignedlong flags; unsignedint val; void __iomem *pmu_base = pmu->pmu_base; void __iomem *pmc_base = pmu->pmc_base;
spin_lock_irqsave(&pmu->lock, flags);
/* Enable isolators */ if (pmu_dom->iso_mask) {
val = ~pmu_dom->iso_mask;
val &= readl_relaxed(pmu_base + PMU_ISO);
writel_relaxed(val, pmu_base + PMU_ISO);
}
/* Reset unit */ if (pmu_dom->rst_mask) {
val = ~pmu_dom->rst_mask;
val &= readl_relaxed(pmc_base + PMC_SW_RST);
writel_relaxed(val, pmc_base + PMC_SW_RST);
}
/* Power down */
val = readl_relaxed(pmu_base + PMU_PWR) | pmu_dom->pwr_mask;
writel_relaxed(val, pmu_base + PMU_PWR);
/* * The PMU mask register is not RW0C: it is RW. This means that * the bits take whatever value is written to them; if you write * a '1', you will set the interrupt. * * Unfortunately this means there is NO race free way to clear * these interrupts. * * So, let's structure the code so that the window is as small as * possible.
*/
guard(raw_spinlock)(&gc->lock);
done &= readl_relaxed(base + PMC_IRQ_CAUSE);
writel_relaxed(done, base + PMC_IRQ_CAUSE);
}
staticint __init dove_init_pmu_irq(struct pmu_data *pmu, int irq)
{ constchar *name = "pmu_irq"; struct irq_chip_generic *gc; struct irq_domain *domain; int ret;
/* mask and clear all interrupts */
writel(0, pmu->pmc_base + PMC_IRQ_MASK);
writel(0, pmu->pmc_base + PMC_IRQ_CAUSE);
domain = irq_domain_create_linear(of_fwnode_handle(pmu->of_node), NR_PMU_IRQS,
&irq_generic_chip_ops, NULL); if (!domain) {
pr_err("%s: unable to add irq domain\n", name); return -ENOMEM;
}
ret = irq_alloc_domain_generic_chips(domain, NR_PMU_IRQS, 1, name,
handle_level_irq,
IRQ_NOREQUEST | IRQ_NOPROBE, 0,
IRQ_GC_INIT_MASK_CACHE); if (ret) {
pr_err("%s: unable to alloc irq domain gc: %d\n", name, ret);
irq_domain_remove(domain); return ret;
}
/* * We parse the reset controller property directly here * to ensure that we can operate when the reset controller * support is not configured into the kernel.
*/
ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
0, &args); if (ret == 0) { if (args.np == pmu->of_node)
domain->rst_mask = BIT(args.args[0]);
of_node_put(args.np);
}
__pmu_domain_register(domain, np);
}
/* Loss of the interrupt controller is not a fatal error. */
parent_irq = irq_of_parse_and_map(pmu->of_node, 0); if (!parent_irq) {
pr_err("%pOFn: no interrupt specified\n", np_pmu);
} else {
ret = dove_init_pmu_irq(pmu, parent_irq); if (ret)
pr_err("dove_init_pmu_irq() failed: %d\n", ret);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.