162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OMAP2+ common Power & Reset Management (PRM) IP block functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 662306a36Sopenharmony_ci * Tero Kristo <t-kristo@ti.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * For historical purposes, the API used to configure the PRM 962306a36Sopenharmony_ci * interrupt handler refers to it as the "PRCM interrupt." The 1062306a36Sopenharmony_ci * underlying registers are located in the PRM on OMAP3/4. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * XXX This code should eventually be moved to a PRM driver. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/irq.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/of_address.h> 2462306a36Sopenharmony_ci#include <linux/clk-provider.h> 2562306a36Sopenharmony_ci#include <linux/clk/ti.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "soc.h" 2862306a36Sopenharmony_ci#include "prm2xxx_3xxx.h" 2962306a36Sopenharmony_ci#include "prm2xxx.h" 3062306a36Sopenharmony_ci#include "prm3xxx.h" 3162306a36Sopenharmony_ci#include "prm33xx.h" 3262306a36Sopenharmony_ci#include "prm44xx.h" 3362306a36Sopenharmony_ci#include "prm54xx.h" 3462306a36Sopenharmony_ci#include "prm7xx.h" 3562306a36Sopenharmony_ci#include "prcm43xx.h" 3662306a36Sopenharmony_ci#include "common.h" 3762306a36Sopenharmony_ci#include "clock.h" 3862306a36Sopenharmony_ci#include "cm.h" 3962306a36Sopenharmony_ci#include "control.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs 4362306a36Sopenharmony_ci * XXX this is technically not needed, since 4462306a36Sopenharmony_ci * omap_prcm_register_chain_handler() could allocate this based on the 4562306a36Sopenharmony_ci * actual amount of memory needed for the SoC 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci#define OMAP_PRCM_MAX_NR_PENDING_REG 2 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * prcm_irq_chips: an array of all of the "generic IRQ chips" in use 5162306a36Sopenharmony_ci * by the PRCM interrupt handler code. There will be one 'chip' per 5262306a36Sopenharmony_ci * PRM_{IRQSTATUS,IRQENABLE}_MPU register pair. (So OMAP3 will have 5362306a36Sopenharmony_ci * one "chip" and OMAP4 will have two.) 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic struct irq_chip_generic **prcm_irq_chips; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * prcm_irq_setup: the PRCM IRQ parameters for the hardware the code 5962306a36Sopenharmony_ci * is currently running on. Defined and passed by initialization code 6062306a36Sopenharmony_ci * that calls omap_prcm_register_chain_handler(). 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cistatic struct omap_prcm_irq_setup *prcm_irq_setup; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* prm_base: base virtual address of the PRM IP block */ 6562306a36Sopenharmony_cistruct omap_domain_base prm_base; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciu16 prm_features; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * prm_ll_data: function pointers to SoC-specific implementations of 7162306a36Sopenharmony_ci * common PRM functions 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic struct prm_ll_data null_prm_ll_data; 7462306a36Sopenharmony_cistatic struct prm_ll_data *prm_ll_data = &null_prm_ll_data; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Private functions */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * Move priority events from events to priority_events array 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic void omap_prcm_events_filter_priority(unsigned long *events, 8262306a36Sopenharmony_ci unsigned long *priority_events) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int i; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (i = 0; i < prcm_irq_setup->nr_regs; i++) { 8762306a36Sopenharmony_ci priority_events[i] = 8862306a36Sopenharmony_ci events[i] & prcm_irq_setup->priority_mask[i]; 8962306a36Sopenharmony_ci events[i] ^= priority_events[i]; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * PRCM Interrupt Handler 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * This is a common handler for the OMAP PRCM interrupts. Pending 9762306a36Sopenharmony_ci * interrupts are detected by a call to prcm_pending_events and 9862306a36Sopenharmony_ci * dispatched accordingly. Clearing of the wakeup events should be 9962306a36Sopenharmony_ci * done by the SoC specific individual handlers. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistatic void omap_prcm_irq_handler(struct irq_desc *desc) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG]; 10462306a36Sopenharmony_ci unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG]; 10562306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 10662306a36Sopenharmony_ci unsigned int virtirq; 10762306a36Sopenharmony_ci int nr_irq = prcm_irq_setup->nr_regs * 32; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * If we are suspended, mask all interrupts from PRCM level, 11162306a36Sopenharmony_ci * this does not ack them, and they will be pending until we 11262306a36Sopenharmony_ci * re-enable the interrupts, at which point the 11362306a36Sopenharmony_ci * omap_prcm_irq_handler will be executed again. The 11462306a36Sopenharmony_ci * _save_and_clear_irqen() function must ensure that the PRM 11562306a36Sopenharmony_ci * write to disable all IRQs has reached the PRM before 11662306a36Sopenharmony_ci * returning, or spurious PRCM interrupts may occur during 11762306a36Sopenharmony_ci * suspend. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci if (prcm_irq_setup->suspended) { 12062306a36Sopenharmony_ci prcm_irq_setup->save_and_clear_irqen(prcm_irq_setup->saved_mask); 12162306a36Sopenharmony_ci prcm_irq_setup->suspend_save_flag = true; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* 12562306a36Sopenharmony_ci * Loop until all pending irqs are handled, since 12662306a36Sopenharmony_ci * generic_handle_irq() can cause new irqs to come 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci while (!prcm_irq_setup->suspended) { 12962306a36Sopenharmony_ci prcm_irq_setup->read_pending_irqs(pending); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* No bit set, then all IRQs are handled */ 13262306a36Sopenharmony_ci if (find_first_bit(pending, nr_irq) >= nr_irq) 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci omap_prcm_events_filter_priority(pending, priority_pending); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Loop on all currently pending irqs so that new irqs 13962306a36Sopenharmony_ci * cannot starve previously pending irqs 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Serve priority events first */ 14362306a36Sopenharmony_ci for_each_set_bit(virtirq, priority_pending, nr_irq) 14462306a36Sopenharmony_ci generic_handle_irq(prcm_irq_setup->base_irq + virtirq); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* Serve normal events next */ 14762306a36Sopenharmony_ci for_each_set_bit(virtirq, pending, nr_irq) 14862306a36Sopenharmony_ci generic_handle_irq(prcm_irq_setup->base_irq + virtirq); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (chip->irq_ack) 15162306a36Sopenharmony_ci chip->irq_ack(&desc->irq_data); 15262306a36Sopenharmony_ci if (chip->irq_eoi) 15362306a36Sopenharmony_ci chip->irq_eoi(&desc->irq_data); 15462306a36Sopenharmony_ci chip->irq_unmask(&desc->irq_data); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci prcm_irq_setup->ocp_barrier(); /* avoid spurious IRQs */ 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* Public functions */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/** 16262306a36Sopenharmony_ci * omap_prcm_event_to_irq - given a PRCM event name, returns the 16362306a36Sopenharmony_ci * corresponding IRQ on which the handler should be registered 16462306a36Sopenharmony_ci * @name: name of the PRCM interrupt bit to look up - see struct omap_prcm_irq 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * Returns the Linux internal IRQ ID corresponding to @name upon success, 16762306a36Sopenharmony_ci * or -ENOENT upon failure. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ciint omap_prcm_event_to_irq(const char *name) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci int i; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!prcm_irq_setup || !name) 17462306a36Sopenharmony_ci return -ENOENT; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci for (i = 0; i < prcm_irq_setup->nr_irqs; i++) 17762306a36Sopenharmony_ci if (!strcmp(prcm_irq_setup->irqs[i].name, name)) 17862306a36Sopenharmony_ci return prcm_irq_setup->base_irq + 17962306a36Sopenharmony_ci prcm_irq_setup->irqs[i].offset; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return -ENOENT; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/** 18562306a36Sopenharmony_ci * omap_prcm_irq_cleanup - reverses memory allocated and other steps 18662306a36Sopenharmony_ci * done by omap_prcm_register_chain_handler() 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * No return value. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic void omap_prcm_irq_cleanup(void) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci unsigned int irq; 19362306a36Sopenharmony_ci int i; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!prcm_irq_setup) { 19662306a36Sopenharmony_ci pr_err("PRCM: IRQ handler not initialized; cannot cleanup\n"); 19762306a36Sopenharmony_ci return; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (prcm_irq_chips) { 20162306a36Sopenharmony_ci for (i = 0; i < prcm_irq_setup->nr_regs; i++) { 20262306a36Sopenharmony_ci if (prcm_irq_chips[i]) 20362306a36Sopenharmony_ci irq_remove_generic_chip(prcm_irq_chips[i], 20462306a36Sopenharmony_ci 0xffffffff, 0, 0); 20562306a36Sopenharmony_ci prcm_irq_chips[i] = NULL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci kfree(prcm_irq_chips); 20862306a36Sopenharmony_ci prcm_irq_chips = NULL; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci kfree(prcm_irq_setup->saved_mask); 21262306a36Sopenharmony_ci prcm_irq_setup->saved_mask = NULL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci kfree(prcm_irq_setup->priority_mask); 21562306a36Sopenharmony_ci prcm_irq_setup->priority_mask = NULL; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci irq = prcm_irq_setup->irq; 21862306a36Sopenharmony_ci irq_set_chained_handler(irq, NULL); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (prcm_irq_setup->base_irq > 0) 22162306a36Sopenharmony_ci irq_free_descs(prcm_irq_setup->base_irq, 22262306a36Sopenharmony_ci prcm_irq_setup->nr_regs * 32); 22362306a36Sopenharmony_ci prcm_irq_setup->base_irq = 0; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_civoid omap_prcm_irq_prepare(void) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci prcm_irq_setup->suspended = true; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_civoid omap_prcm_irq_complete(void) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci prcm_irq_setup->suspended = false; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* If we have not saved the masks, do not attempt to restore */ 23662306a36Sopenharmony_ci if (!prcm_irq_setup->suspend_save_flag) 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci prcm_irq_setup->suspend_save_flag = false; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * Re-enable all masked PRCM irq sources, this causes the PRCM 24362306a36Sopenharmony_ci * interrupt to fire immediately if the events were masked 24462306a36Sopenharmony_ci * previously in the chain handler 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/** 25062306a36Sopenharmony_ci * omap_prcm_register_chain_handler - initializes the prcm chained interrupt 25162306a36Sopenharmony_ci * handler based on provided parameters 25262306a36Sopenharmony_ci * @irq_setup: hardware data about the underlying PRM/PRCM 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Set up the PRCM chained interrupt handler on the PRCM IRQ. Sets up 25562306a36Sopenharmony_ci * one generic IRQ chip per PRM interrupt status/enable register pair. 25662306a36Sopenharmony_ci * Returns 0 upon success, -EINVAL if called twice or if invalid 25762306a36Sopenharmony_ci * arguments are passed, or -ENOMEM on any other error. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ciint omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci int nr_regs; 26262306a36Sopenharmony_ci u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG]; 26362306a36Sopenharmony_ci int offset, i, irq; 26462306a36Sopenharmony_ci struct irq_chip_generic *gc; 26562306a36Sopenharmony_ci struct irq_chip_type *ct; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (!irq_setup) 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci nr_regs = irq_setup->nr_regs; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (prcm_irq_setup) { 27362306a36Sopenharmony_ci pr_err("PRCM: already initialized; won't reinitialize\n"); 27462306a36Sopenharmony_ci return -EINVAL; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (nr_regs > OMAP_PRCM_MAX_NR_PENDING_REG) { 27862306a36Sopenharmony_ci pr_err("PRCM: nr_regs too large\n"); 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci prcm_irq_setup = irq_setup; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci prcm_irq_chips = kcalloc(nr_regs, sizeof(void *), GFP_KERNEL); 28562306a36Sopenharmony_ci prcm_irq_setup->saved_mask = kcalloc(nr_regs, sizeof(u32), 28662306a36Sopenharmony_ci GFP_KERNEL); 28762306a36Sopenharmony_ci prcm_irq_setup->priority_mask = kcalloc(nr_regs, sizeof(u32), 28862306a36Sopenharmony_ci GFP_KERNEL); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!prcm_irq_chips || !prcm_irq_setup->saved_mask || 29162306a36Sopenharmony_ci !prcm_irq_setup->priority_mask) 29262306a36Sopenharmony_ci goto err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci memset(mask, 0, sizeof(mask)); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci for (i = 0; i < irq_setup->nr_irqs; i++) { 29762306a36Sopenharmony_ci offset = irq_setup->irqs[i].offset; 29862306a36Sopenharmony_ci mask[offset >> 5] |= 1 << (offset & 0x1f); 29962306a36Sopenharmony_ci if (irq_setup->irqs[i].priority) 30062306a36Sopenharmony_ci irq_setup->priority_mask[offset >> 5] |= 30162306a36Sopenharmony_ci 1 << (offset & 0x1f); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci irq = irq_setup->irq; 30562306a36Sopenharmony_ci irq_set_chained_handler(irq, omap_prcm_irq_handler); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32, 30862306a36Sopenharmony_ci 0); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (irq_setup->base_irq < 0) { 31162306a36Sopenharmony_ci pr_err("PRCM: failed to allocate irq descs: %d\n", 31262306a36Sopenharmony_ci irq_setup->base_irq); 31362306a36Sopenharmony_ci goto err; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci for (i = 0; i < irq_setup->nr_regs; i++) { 31762306a36Sopenharmony_ci gc = irq_alloc_generic_chip("PRCM", 1, 31862306a36Sopenharmony_ci irq_setup->base_irq + i * 32, prm_base.va, 31962306a36Sopenharmony_ci handle_level_irq); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (!gc) { 32262306a36Sopenharmony_ci pr_err("PRCM: failed to allocate generic chip\n"); 32362306a36Sopenharmony_ci goto err; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci ct = gc->chip_types; 32662306a36Sopenharmony_ci ct->chip.irq_ack = irq_gc_ack_set_bit; 32762306a36Sopenharmony_ci ct->chip.irq_mask = irq_gc_mask_clr_bit; 32862306a36Sopenharmony_ci ct->chip.irq_unmask = irq_gc_mask_set_bit; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ct->regs.ack = irq_setup->ack + i * 4; 33162306a36Sopenharmony_ci ct->regs.mask = irq_setup->mask + i * 4; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci irq_setup_generic_chip(gc, mask[i], 0, IRQ_NOREQUEST, 0); 33462306a36Sopenharmony_ci prcm_irq_chips[i] = gc; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci irq = omap_prcm_event_to_irq("io"); 33862306a36Sopenharmony_ci omap_pcs_legacy_init(irq, irq_setup->reconfigure_io_chain); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cierr: 34362306a36Sopenharmony_ci omap_prcm_irq_cleanup(); 34462306a36Sopenharmony_ci return -ENOMEM; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/** 34862306a36Sopenharmony_ci * prm_was_any_context_lost_old - was device context lost? (old API) 34962306a36Sopenharmony_ci * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION) 35062306a36Sopenharmony_ci * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST) 35162306a36Sopenharmony_ci * @idx: CONTEXT register offset 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * Return 1 if any bits were set in the *_CONTEXT_* register 35462306a36Sopenharmony_ci * identified by (@part, @inst, @idx), which means that some context 35562306a36Sopenharmony_ci * was lost for that module; otherwise, return 0. XXX Deprecated; 35662306a36Sopenharmony_ci * callers need to use a less-SoC-dependent way to identify hardware 35762306a36Sopenharmony_ci * IP blocks. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_cibool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci bool ret = true; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (prm_ll_data->was_any_context_lost_old) 36462306a36Sopenharmony_ci ret = prm_ll_data->was_any_context_lost_old(part, inst, idx); 36562306a36Sopenharmony_ci else 36662306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 36762306a36Sopenharmony_ci __func__); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/** 37362306a36Sopenharmony_ci * prm_clear_context_lost_flags_old - clear context loss flags (old API) 37462306a36Sopenharmony_ci * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION) 37562306a36Sopenharmony_ci * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST) 37662306a36Sopenharmony_ci * @idx: CONTEXT register offset 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Clear hardware context loss bits for the module identified by 37962306a36Sopenharmony_ci * (@part, @inst, @idx). No return value. XXX Deprecated; callers 38062306a36Sopenharmony_ci * need to use a less-SoC-dependent way to identify hardware IP 38162306a36Sopenharmony_ci * blocks. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_civoid prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci if (prm_ll_data->clear_context_loss_flags_old) 38662306a36Sopenharmony_ci prm_ll_data->clear_context_loss_flags_old(part, inst, idx); 38762306a36Sopenharmony_ci else 38862306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 38962306a36Sopenharmony_ci __func__); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/** 39362306a36Sopenharmony_ci * omap_prm_assert_hardreset - assert hardreset for an IP block 39462306a36Sopenharmony_ci * @shift: register bit shift corresponding to the reset line 39562306a36Sopenharmony_ci * @part: PRM partition 39662306a36Sopenharmony_ci * @prm_mod: PRM submodule base or instance offset 39762306a36Sopenharmony_ci * @offset: register offset 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Asserts a hardware reset line for an IP block. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ciint omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci if (!prm_ll_data->assert_hardreset) { 40462306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 40562306a36Sopenharmony_ci __func__); 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/** 41362306a36Sopenharmony_ci * omap_prm_deassert_hardreset - deassert hardreset for an IP block 41462306a36Sopenharmony_ci * @shift: register bit shift corresponding to the reset line 41562306a36Sopenharmony_ci * @st_shift: reset status bit shift corresponding to the reset line 41662306a36Sopenharmony_ci * @part: PRM partition 41762306a36Sopenharmony_ci * @prm_mod: PRM submodule base or instance offset 41862306a36Sopenharmony_ci * @offset: register offset 41962306a36Sopenharmony_ci * @st_offset: status register offset 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * Deasserts a hardware reset line for an IP block. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ciint omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, 42462306a36Sopenharmony_ci u16 offset, u16 st_offset) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci if (!prm_ll_data->deassert_hardreset) { 42762306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 42862306a36Sopenharmony_ci __func__); 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod, 43362306a36Sopenharmony_ci offset, st_offset); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/** 43762306a36Sopenharmony_ci * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block 43862306a36Sopenharmony_ci * @shift: register bit shift corresponding to the reset line 43962306a36Sopenharmony_ci * @part: PRM partition 44062306a36Sopenharmony_ci * @prm_mod: PRM submodule base or instance offset 44162306a36Sopenharmony_ci * @offset: register offset 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Checks if a hardware reset line for an IP block is enabled or not. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ciint omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci if (!prm_ll_data->is_hardreset_asserted) { 44862306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 44962306a36Sopenharmony_ci __func__); 45062306a36Sopenharmony_ci return -EINVAL; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/** 45762306a36Sopenharmony_ci * omap_prm_reset_system - trigger global SW reset 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * Triggers SoC specific global warm reset to reboot the device. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_civoid omap_prm_reset_system(void) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci if (!prm_ll_data->reset_system) { 46462306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 46562306a36Sopenharmony_ci __func__); 46662306a36Sopenharmony_ci return; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci prm_ll_data->reset_system(); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci while (1) { 47262306a36Sopenharmony_ci cpu_relax(); 47362306a36Sopenharmony_ci wfe(); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/** 47862306a36Sopenharmony_ci * omap_prm_clear_mod_irqs - clear wake-up events from PRCM interrupt 47962306a36Sopenharmony_ci * @module: PRM module to clear wakeups from 48062306a36Sopenharmony_ci * @regs: register to clear 48162306a36Sopenharmony_ci * @wkst_mask: wkst bits to clear 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * Clears any wakeup events for the module and register set defined. 48462306a36Sopenharmony_ci * Uses SoC specific implementation to do the actual wakeup status 48562306a36Sopenharmony_ci * clearing. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ciint omap_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci if (!prm_ll_data->clear_mod_irqs) { 49062306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 49162306a36Sopenharmony_ci __func__); 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return prm_ll_data->clear_mod_irqs(module, regs, wkst_mask); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/** 49962306a36Sopenharmony_ci * omap_prm_vp_check_txdone - check voltage processor TX done status 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * Checks if voltage processor transmission has been completed. 50262306a36Sopenharmony_ci * Returns non-zero if a transmission has completed, 0 otherwise. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ciu32 omap_prm_vp_check_txdone(u8 vp_id) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci if (!prm_ll_data->vp_check_txdone) { 50762306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 50862306a36Sopenharmony_ci __func__); 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return prm_ll_data->vp_check_txdone(vp_id); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * omap_prm_vp_clear_txdone - clears voltage processor TX done status 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Clears the status bit for completed voltage processor transmission 51962306a36Sopenharmony_ci * returned by prm_vp_check_txdone. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_civoid omap_prm_vp_clear_txdone(u8 vp_id) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci if (!prm_ll_data->vp_clear_txdone) { 52462306a36Sopenharmony_ci WARN_ONCE(1, "prm: %s: no mapping function defined\n", 52562306a36Sopenharmony_ci __func__); 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci prm_ll_data->vp_clear_txdone(vp_id); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/** 53362306a36Sopenharmony_ci * prm_register - register per-SoC low-level data with the PRM 53462306a36Sopenharmony_ci * @pld: low-level per-SoC OMAP PRM data & function pointers to register 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * Register per-SoC low-level OMAP PRM data and function pointers with 53762306a36Sopenharmony_ci * the OMAP PRM common interface. The caller must keep the data 53862306a36Sopenharmony_ci * pointed to by @pld valid until it calls prm_unregister() and 53962306a36Sopenharmony_ci * it returns successfully. Returns 0 upon success, -EINVAL if @pld 54062306a36Sopenharmony_ci * is NULL, or -EEXIST if prm_register() has already been called 54162306a36Sopenharmony_ci * without an intervening prm_unregister(). 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ciint prm_register(struct prm_ll_data *pld) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (!pld) 54662306a36Sopenharmony_ci return -EINVAL; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (prm_ll_data != &null_prm_ll_data) 54962306a36Sopenharmony_ci return -EEXIST; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci prm_ll_data = pld; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return 0; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/** 55762306a36Sopenharmony_ci * prm_unregister - unregister per-SoC low-level data & function pointers 55862306a36Sopenharmony_ci * @pld: low-level per-SoC OMAP PRM data & function pointers to unregister 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * Unregister per-SoC low-level OMAP PRM data and function pointers 56162306a36Sopenharmony_ci * that were previously registered with prm_register(). The 56262306a36Sopenharmony_ci * caller may not destroy any of the data pointed to by @pld until 56362306a36Sopenharmony_ci * this function returns successfully. Returns 0 upon success, or 56462306a36Sopenharmony_ci * -EINVAL if @pld is NULL or if @pld does not match the struct 56562306a36Sopenharmony_ci * prm_ll_data * previously registered by prm_register(). 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ciint prm_unregister(struct prm_ll_data *pld) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci if (!pld || prm_ll_data != pld) 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci prm_ll_data = &null_prm_ll_data; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP2 57862306a36Sopenharmony_cistatic struct omap_prcm_init_data omap2_prm_data __initdata = { 57962306a36Sopenharmony_ci .index = TI_CLKM_PRM, 58062306a36Sopenharmony_ci .init = omap2xxx_prm_init, 58162306a36Sopenharmony_ci}; 58262306a36Sopenharmony_ci#endif 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP3 58562306a36Sopenharmony_cistatic struct omap_prcm_init_data omap3_prm_data __initdata = { 58662306a36Sopenharmony_ci .index = TI_CLKM_PRM, 58762306a36Sopenharmony_ci .init = omap3xxx_prm_init, 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* 59062306a36Sopenharmony_ci * IVA2 offset is a negative value, must offset the prm_base 59162306a36Sopenharmony_ci * address by this to get it to positive 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci .offset = -OMAP3430_IVA2_MOD, 59462306a36Sopenharmony_ci}; 59562306a36Sopenharmony_ci#endif 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_TI81XX) 59862306a36Sopenharmony_cistatic struct omap_prcm_init_data am3_prm_data __initdata = { 59962306a36Sopenharmony_ci .index = TI_CLKM_PRM, 60062306a36Sopenharmony_ci .init = am33xx_prm_init, 60162306a36Sopenharmony_ci}; 60262306a36Sopenharmony_ci#endif 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#ifdef CONFIG_SOC_TI81XX 60562306a36Sopenharmony_cistatic struct omap_prcm_init_data dm814_pllss_data __initdata = { 60662306a36Sopenharmony_ci .index = TI_CLKM_PLLSS, 60762306a36Sopenharmony_ci .init = am33xx_prm_init, 60862306a36Sopenharmony_ci}; 60962306a36Sopenharmony_ci#endif 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP4 61262306a36Sopenharmony_cistatic struct omap_prcm_init_data omap4_prm_data __initdata = { 61362306a36Sopenharmony_ci .index = TI_CLKM_PRM, 61462306a36Sopenharmony_ci .init = omap44xx_prm_init, 61562306a36Sopenharmony_ci .device_inst_offset = OMAP4430_PRM_DEVICE_INST, 61662306a36Sopenharmony_ci .flags = PRM_HAS_IO_WAKEUP | PRM_HAS_VOLTAGE, 61762306a36Sopenharmony_ci}; 61862306a36Sopenharmony_ci#endif 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci#ifdef CONFIG_SOC_OMAP5 62162306a36Sopenharmony_cistatic struct omap_prcm_init_data omap5_prm_data __initdata = { 62262306a36Sopenharmony_ci .index = TI_CLKM_PRM, 62362306a36Sopenharmony_ci .init = omap44xx_prm_init, 62462306a36Sopenharmony_ci .device_inst_offset = OMAP54XX_PRM_DEVICE_INST, 62562306a36Sopenharmony_ci .flags = PRM_HAS_IO_WAKEUP | PRM_HAS_VOLTAGE, 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci#endif 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci#ifdef CONFIG_SOC_DRA7XX 63062306a36Sopenharmony_cistatic struct omap_prcm_init_data dra7_prm_data __initdata = { 63162306a36Sopenharmony_ci .index = TI_CLKM_PRM, 63262306a36Sopenharmony_ci .init = omap44xx_prm_init, 63362306a36Sopenharmony_ci .device_inst_offset = DRA7XX_PRM_DEVICE_INST, 63462306a36Sopenharmony_ci .flags = PRM_HAS_IO_WAKEUP, 63562306a36Sopenharmony_ci}; 63662306a36Sopenharmony_ci#endif 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci#ifdef CONFIG_SOC_AM43XX 63962306a36Sopenharmony_cistatic struct omap_prcm_init_data am4_prm_data __initdata = { 64062306a36Sopenharmony_ci .index = TI_CLKM_PRM, 64162306a36Sopenharmony_ci .init = omap44xx_prm_init, 64262306a36Sopenharmony_ci .device_inst_offset = AM43XX_PRM_DEVICE_INST, 64362306a36Sopenharmony_ci .flags = PRM_HAS_IO_WAKEUP, 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci#endif 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) 64862306a36Sopenharmony_cistatic struct omap_prcm_init_data scrm_data __initdata = { 64962306a36Sopenharmony_ci .index = TI_CLKM_SCRM, 65062306a36Sopenharmony_ci}; 65162306a36Sopenharmony_ci#endif 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct of_device_id omap_prcm_dt_match_table[] __initconst = { 65462306a36Sopenharmony_ci#ifdef CONFIG_SOC_AM33XX 65562306a36Sopenharmony_ci { .compatible = "ti,am3-prcm", .data = &am3_prm_data }, 65662306a36Sopenharmony_ci#endif 65762306a36Sopenharmony_ci#ifdef CONFIG_SOC_AM43XX 65862306a36Sopenharmony_ci { .compatible = "ti,am4-prcm", .data = &am4_prm_data }, 65962306a36Sopenharmony_ci#endif 66062306a36Sopenharmony_ci#ifdef CONFIG_SOC_TI81XX 66162306a36Sopenharmony_ci { .compatible = "ti,dm814-prcm", .data = &am3_prm_data }, 66262306a36Sopenharmony_ci { .compatible = "ti,dm814-pllss", .data = &dm814_pllss_data }, 66362306a36Sopenharmony_ci { .compatible = "ti,dm816-prcm", .data = &am3_prm_data }, 66462306a36Sopenharmony_ci#endif 66562306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP2 66662306a36Sopenharmony_ci { .compatible = "ti,omap2-prcm", .data = &omap2_prm_data }, 66762306a36Sopenharmony_ci#endif 66862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP3 66962306a36Sopenharmony_ci { .compatible = "ti,omap3-prm", .data = &omap3_prm_data }, 67062306a36Sopenharmony_ci#endif 67162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP4 67262306a36Sopenharmony_ci { .compatible = "ti,omap4-prm", .data = &omap4_prm_data }, 67362306a36Sopenharmony_ci { .compatible = "ti,omap4-scrm", .data = &scrm_data }, 67462306a36Sopenharmony_ci#endif 67562306a36Sopenharmony_ci#ifdef CONFIG_SOC_OMAP5 67662306a36Sopenharmony_ci { .compatible = "ti,omap5-prm", .data = &omap5_prm_data }, 67762306a36Sopenharmony_ci { .compatible = "ti,omap5-scrm", .data = &scrm_data }, 67862306a36Sopenharmony_ci#endif 67962306a36Sopenharmony_ci#ifdef CONFIG_SOC_DRA7XX 68062306a36Sopenharmony_ci { .compatible = "ti,dra7-prm", .data = &dra7_prm_data }, 68162306a36Sopenharmony_ci#endif 68262306a36Sopenharmony_ci { } 68362306a36Sopenharmony_ci}; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/** 68662306a36Sopenharmony_ci * omap2_prm_base_init - initialize iomappings for the PRM driver 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * Detects and initializes the iomappings for the PRM driver, based 68962306a36Sopenharmony_ci * on the DT data. Returns 0 in success, negative error value 69062306a36Sopenharmony_ci * otherwise. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_cistatic int __init omap2_prm_base_init(void) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct device_node *np; 69562306a36Sopenharmony_ci const struct of_device_id *match; 69662306a36Sopenharmony_ci struct omap_prcm_init_data *data; 69762306a36Sopenharmony_ci struct resource res; 69862306a36Sopenharmony_ci int ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci for_each_matching_node_and_match(np, omap_prcm_dt_match_table, &match) { 70162306a36Sopenharmony_ci data = (struct omap_prcm_init_data *)match->data; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci ret = of_address_to_resource(np, 0, &res); 70462306a36Sopenharmony_ci if (ret) { 70562306a36Sopenharmony_ci of_node_put(np); 70662306a36Sopenharmony_ci return ret; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci data->mem = ioremap(res.start, resource_size(&res)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (data->index == TI_CLKM_PRM) { 71262306a36Sopenharmony_ci prm_base.va = data->mem + data->offset; 71362306a36Sopenharmony_ci prm_base.pa = res.start + data->offset; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci data->np = np; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (data->init) 71962306a36Sopenharmony_ci data->init(data); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ciint __init omap2_prcm_base_init(void) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci int ret; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ret = omap2_prm_base_init(); 73062306a36Sopenharmony_ci if (ret) 73162306a36Sopenharmony_ci return ret; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return omap2_cm_base_init(); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci/** 73762306a36Sopenharmony_ci * omap_prcm_init - low level init for the PRCM drivers 73862306a36Sopenharmony_ci * 73962306a36Sopenharmony_ci * Initializes the low level clock infrastructure for PRCM drivers. 74062306a36Sopenharmony_ci * Returns 0 in success, negative error value in failure. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ciint __init omap_prcm_init(void) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct device_node *np; 74562306a36Sopenharmony_ci const struct of_device_id *match; 74662306a36Sopenharmony_ci const struct omap_prcm_init_data *data; 74762306a36Sopenharmony_ci int ret; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci for_each_matching_node_and_match(np, omap_prcm_dt_match_table, &match) { 75062306a36Sopenharmony_ci data = match->data; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = omap2_clk_provider_init(np, data->index, NULL, data->mem); 75362306a36Sopenharmony_ci if (ret) { 75462306a36Sopenharmony_ci of_node_put(np); 75562306a36Sopenharmony_ci return ret; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci omap_cm_init(); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int __init prm_late_init(void) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci if (prm_ll_data->late_init) 76762306a36Sopenharmony_ci return prm_ll_data->late_init(); 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_cisubsys_initcall(prm_late_init); 771