int tegra_powergate_remove_clamping(int id) { u32 mask; if (id < 0 || id >= tegra_num_powerdomains) return -EINVAL; /* * The Tegra124 GPU has a separate register (with different semantics) * to remove clamps. */ if (tegra_chip_id == TEGRA124) { if (id == TEGRA_POWERGATE_3D) { pmc_write(0, GPU_RG_CNTRL); return 0; } } /* * Tegra 2 has a bug where PCIE and VDE clamping masks are * swapped relatively to the partition ids */ if (id == TEGRA_POWERGATE_VDEC) mask = (1 << TEGRA_POWERGATE_PCIE); else if (id == TEGRA_POWERGATE_PCIE) mask = (1 << TEGRA_POWERGATE_VDEC); else mask = (1 << id); pmc_write(mask, REMOVE_CLAMPING); return 0; }
int tegra_powergate_set(int id, bool new_state) { #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM bool status; unsigned long flags; spinlock_t *lock = tegra_get_powergate_lock(); /* 10us timeout for toggle operation if it takes affect*/ int toggle_timeout = 10; /* 100 * 10 = 1000us timeout for toggle command to take affect in case of contention with h/w initiated CPU power gating */ int contention_timeout = 100; spin_lock_irqsave(lock, flags); status = !!(pmc_read(PWRGATE_STATUS) & (1 << id)); if (status == new_state) { spin_unlock_irqrestore(lock, flags); return 0; } if (TEGRA_IS_CPU_POWERGATE_ID(id)) { /* CPU ungated in s/w only during boot/resume with outer waiting loop and no contention from other CPUs */ pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); spin_unlock_irqrestore(lock, flags); return 0; } pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); do { do { udelay(1); status = !!(pmc_read(PWRGATE_STATUS) & (1 << id)); toggle_timeout--; } while ((status != new_state) && (toggle_timeout > 0)); contention_timeout--; } while ((status != new_state) && (contention_timeout > 0)); spin_unlock_irqrestore(lock, flags); if (status != new_state) { WARN(1, "Could not set powergate %d to %d", id, new_state); return -EBUSY; } trace_power_domain_target(tegra_powergate_get_name(id), new_state, smp_processor_id()); #endif return 0; }
static void clk_audio_pll_disable(struct clk_hw *hw) { struct clk_audio_frac *fck = to_clk_audio_frac(hw); struct at91_pmc *pmc = fck->pmc; u32 tmp; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_PLLEN; pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); /* do it in 2 separated writes */ pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp & ~AT91_PMC_AUDIO_PLL_RESETN); pmc_unlock(pmc); }
static void clk_system_unprepare(struct clk_hw *hw) { struct clk_system *sys = to_clk_system(hw); struct at91_pmc *pmc = sys->pmc; pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id); }
static void pmc_irq_suspend(struct irq_data *d) { struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); pmc->imr = pmc_read(pmc, AT91_PMC_IMR); pmc_write(pmc, AT91_PMC_IDR, pmc->imr); }
int tegra_io_rail_power_off(int id) { unsigned long request, status, value; unsigned int bit, mask; int err; err = tegra_io_rail_prepare(id, &request, &status, &bit); if (err < 0) return err; mask = 1 << bit; value = pmc_read(request); value |= mask; value &= ~IO_DPD_REQ_CODE_MASK; value |= IO_DPD_REQ_CODE_ON; pmc_write(value, request); err = tegra_io_rail_poll(status, mask, mask, 250); if (err < 0) return err; tegra_io_rail_unprepare(); return 0; }
static void clk_utmi_unprepare(struct clk_hw *hw) { struct clk_utmi *utmi = to_clk_utmi(hw); struct at91_pmc *pmc = utmi->pmc; u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN; pmc_write(pmc, AT91_CKGR_UCKR, tmp); }
static void clk_audio_pll_pmc_disable(struct clk_hw *hw) { struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); struct at91_pmc *pmc = apmc_ck->pmc; u32 tmp; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_PMCEN; pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); pmc_unlock(pmc); }
static void clk_main_rc_osc_unprepare(struct clk_hw *hw) { struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); struct at91_pmc *pmc = osc->pmc; u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); if (!(tmp & AT91_PMC_MOSCRCEN)) return; tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN); pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); }
/* make sure that pll is in reset state beforehand */ static int clk_audio_pll_prepare(struct clk_hw *hw) { struct clk_audio_frac *fck = to_clk_audio_frac(hw); struct at91_pmc *pmc = fck->pmc; u32 tmp; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_RESETN; pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); pmc_unlock(pmc); return 0; }
static int tegra_io_rail_prepare(int id, unsigned long *request, unsigned long *status, unsigned int *bit) { unsigned long rate, value; struct clk *clk; *bit = id % 32; /* * There are two sets of 30 bits to select IO rails, but bits 30 and * 31 are control bits rather than IO rail selection bits. */ if (id > 63 || *bit == 30 || *bit == 31) return -EINVAL; if (id < 32) { *status = IO_DPD_STATUS; *request = IO_DPD_REQ; } else { *status = IO_DPD2_STATUS; *request = IO_DPD2_REQ; } clk = clk_get_sys(NULL, "pclk"); if (IS_ERR(clk)) return PTR_ERR(clk); rate = clk_get_rate(clk); clk_put(clk); pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE); /* must be at least 200 ns, in APB (PCLK) clock cycles */ value = DIV_ROUND_UP(1000000000, rate); value = DIV_ROUND_UP(200, value); pmc_write(value, SEL_DPD_TIM); return 0; }
static int clk_audio_pll_pmc_enable(struct clk_hw *hw) { struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); struct at91_pmc *pmc = apmc_ck->pmc; u32 tmp; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_QDPMC_MASK; tmp |= AT91_PMC_AUDIO_PLL_PMCEN | AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc); pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); pmc_unlock(pmc); return 0; }
static struct clk * __init at91_clk_register_main_osc(struct at91_pmc *pmc, unsigned int irq, const char *name, const char *parent_name, bool bypass) { int ret; struct clk_main_osc *osc; struct clk *clk = NULL; struct clk_init_data init; if (!pmc || !irq || !name || !parent_name) return ERR_PTR(-EINVAL); osc = kzalloc(sizeof(*osc), GFP_KERNEL); if (!osc) return ERR_PTR(-ENOMEM); init.name = name; init.ops = &main_osc_ops; init.parent_names = &parent_name; init.num_parents = 1; init.flags = CLK_IGNORE_UNUSED; osc->hw.init = &init; osc->pmc = pmc; osc->irq = irq; init_waitqueue_head(&osc->wait); irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); ret = request_irq(osc->irq, clk_main_osc_irq_handler, IRQF_TRIGGER_HIGH, name, osc); if (ret) return ERR_PTR(ret); if (bypass) pmc_write(pmc, AT91_CKGR_MOR, (pmc_read(pmc, AT91_CKGR_MOR) & ~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) | AT91_PMC_OSCBYPASS | AT91_PMC_KEY); clk = clk_register(NULL, &osc->hw); if (IS_ERR(clk)) { free_irq(irq, osc); kfree(osc); } return clk; }
static int clk_audio_pll_enable(struct clk_hw *hw) { struct clk_audio_frac *fck = to_clk_audio_frac(hw); struct at91_pmc *pmc = fck->pmc; u32 tmp, tmp2; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0); pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp | AT91_PMC_AUDIO_PLL_RESETN); tmp2 = pmc_read(pmc, AT91_PMC_AUDIO_PLL1) & ~AT91_PMC_AUDIO_PLL_FRACR_MASK; pmc_write(pmc, AT91_PMC_AUDIO_PLL1, tmp2 | fck->fracr); /* * reset and enabled have to be done in 2 separated writes * for AT91_PMC_AUDIO_PLL0 */ tmp &= ~AT91_PMC_AUDIO_PLL_ND_MASK; pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp | AT91_PMC_AUDIO_PLL_RESETN | AT91_PMC_AUDIO_PLL_PLLEN | AT91_PMC_AUDIO_PLL_ND(fck->nd)); pmc_unlock(pmc); return 0; }
static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index) { struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); struct at91_pmc *pmc = clkmain->pmc; u32 tmp; if (index > 1) return -EINVAL; tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; if (index && !(tmp & AT91_PMC_MOSCSEL)) pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL); else if (!index && (tmp & AT91_PMC_MOSCSEL)) pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) { enable_irq(clkmain->irq); wait_event(clkmain->wait, pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); } return 0; }
static int clk_utmi_prepare(struct clk_hw *hw) { struct clk_utmi *utmi = to_clk_utmi(hw); struct at91_pmc *pmc = utmi->pmc; u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN; pmc_write(pmc, AT91_CKGR_UCKR, tmp); while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) { enable_irq(utmi->irq); wait_event(utmi->wait, pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); } return 0; }
static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); struct at91_pmc *pmc = h32mxclk->pmc; u32 tmp; if (parent_rate != rate && (parent_rate / 2) != rate) return -EINVAL; pmc_lock(pmc); tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV; if ((parent_rate / 2) == rate) tmp |= AT91_PMC_H32MXDIV; pmc_write(pmc, AT91_PMC_MCKR, tmp); pmc_unlock(pmc); return 0; }
static int clk_programmable_prepare(struct clk_hw *hw) { u32 tmp; struct clk_programmable *prog = to_clk_programmable(hw); struct at91_pmc *pmc = prog->pmc; const struct clk_programmable_layout *layout = prog->layout; u8 id = prog->id; u32 mask = PROG_STATUS_MASK(id); tmp = prog->css | (prog->pres << layout->pres_shift); if (layout->have_slck_mck && prog->slckmck) tmp |= AT91_PMC_CSSMCK_MCK; pmc_write(pmc, AT91_PMC_PCKR(id), tmp); while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) wait_event(prog->wait, pmc_read(pmc, AT91_PMC_SR) & mask); return 0; }
static int tegra_powergate_set(int id, bool new_state) { bool status; unsigned long flags; spin_lock_irqsave(&tegra_powergate_lock, flags); status = pmc_read(PWRGATE_STATUS) & (1 << id); if (status == new_state) { spin_unlock_irqrestore(&tegra_powergate_lock, flags); return 0; } pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); spin_unlock_irqrestore(&tegra_powergate_lock, flags); return 0; }
static int clk_main_rc_osc_prepare(struct clk_hw *hw) { struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); struct at91_pmc *pmc = osc->pmc; u32 tmp; tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; if (!(tmp & AT91_PMC_MOSCRCEN)) { tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY; pmc_write(pmc, AT91_CKGR_MOR, tmp); } while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) { enable_irq(osc->irq); wait_event(osc->wait, pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS); } return 0; }
static int clk_system_prepare(struct clk_hw *hw) { struct clk_system *sys = to_clk_system(hw); struct at91_pmc *pmc = sys->pmc; u32 mask = 1 << sys->id; pmc_write(pmc, AT91_PMC_SCER, mask); if (!is_pck(sys->id)) return 0; while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { if (sys->irq) { enable_irq(sys->irq); wait_event(sys->wait, pmc_read(pmc, AT91_PMC_SR) & mask); } else cpu_relax(); } return 0; }
int tegra_powergate_remove_clamping(int id) { u32 mask; if (id < 0 || id >= tegra_num_powerdomains) return -EINVAL; /* * Tegra 2 has a bug where PCIE and VDE clamping masks are * swapped relatively to the partition ids */ if (id == TEGRA_POWERGATE_VDEC) mask = (1 << TEGRA_POWERGATE_PCIE); else if (id == TEGRA_POWERGATE_PCIE) mask = (1 << TEGRA_POWERGATE_VDEC); else mask = (1 << id); pmc_write(mask, REMOVE_CLAMPING); return 0; }
static struct at91_pmc *__init at91_pmc_init(struct device_node *np, void __iomem *regbase, int virq, const struct at91_pmc_caps *caps) { struct at91_pmc *pmc; if (!regbase || !virq || !caps) return NULL; at91_pmc_base = regbase; pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); if (!pmc) return NULL; spin_lock_init(&pmc->lock); pmc->regbase = regbase; pmc->virq = virq; pmc->caps = caps; pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc); if (!pmc->irqdomain) goto out_free_pmc; pmc_write(pmc, AT91_PMC_IDR, 0xffffffff); if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc)) goto out_remove_irqdomain; return pmc; out_remove_irqdomain: irq_domain_remove(pmc->irqdomain); out_free_pmc: kfree(pmc); return NULL; }
int tegra_powergate_remove_clamping(int id) { u32 mask; int contention_timeout = 100; if (!pg_ops) { pr_info("This SOC doesn't support powergating\n"); return -EINVAL; } if (id < 0 || id >= pg_ops->num_powerdomains) return -EINVAL; /* * PCIE and VDE clamping masks are swapped with respect to their * partition ids */ if (id == TEGRA_POWERGATE_VDEC) mask = (1 << TEGRA_POWERGATE_PCIE); else if (id == TEGRA_POWERGATE_PCIE) mask = (1 << TEGRA_POWERGATE_VDEC); else mask = (1 << id); pmc_write(mask, REMOVE_CLAMPING); /* Wait until clamp is removed */ do { udelay(1); contention_timeout--; } while ((contention_timeout > 0) && (pmc_read(REMOVE_CLAMPING) & mask)); WARN(contention_timeout <= 0, "Couldn't remove clamping"); return 0; }
static void pmc_irq_unmask(struct irq_data *d) { struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq); }
static void pmc_irq_resume(struct irq_data *d) { struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); pmc_write(pmc, AT91_PMC_IER, pmc->imr); }
static void tegra_io_rail_unprepare(void) { pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE); }