/* Perform any register operations required to enable the clock. */ void local_clk_enable_reg(unsigned id) { struct clk_local *clk = &soc_clk_local_tbl[id]; void *reg = clk->cc_reg; uint32_t reg_val; WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq), "Attempting to enable clock %d before setting its rate. " "Set the rate first!\n", id); /* Program the NS register, if applicable. NS registers are not * set in the set_rate path because power can be saved by deferring * the selection of a clocked source until the clock is enabled. */ if (clk->ns_mask) { reg_val = readl(clk->ns_reg); reg_val &= ~(clk->ns_mask); reg_val |= (clk->current_freq->ns_val & clk->ns_mask); writel(reg_val, clk->ns_reg); } /* Enable MN counter, if applicable. */ reg_val = readl(reg); if (clk->type == MND) { reg_val |= clk->current_freq->mnd_en_mask; writel(reg_val, reg); } /* Enable root. */ if (clk->root_en_mask) { reg_val |= clk->root_en_mask; writel(reg_val, reg); } /* Enable branch. */ if (clk->br_en_mask) { reg_val |= clk->br_en_mask; writel(reg_val, reg); } /* Wait for clock to enable before returning. */ if (clk->halt_check == DELAY) udelay(HALT_CHECK_DELAY_US); else if (clk->halt_check == ENABLE || clk->halt_check == HALT || clk->halt_check == ENABLE_VOTED || clk->halt_check == HALT_VOTED) { int count; /* Use a memory barrier since some halt status registers are * not within the same 1K segment as the branch/root enable * registers. */ mb(); /* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */ for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id) && count > 0; count--) udelay(1); if (count == 0) pr_warning("%s: clock %d status stuck at 'off' (bit %d " "of 0x%p).\n", __func__, id, clk->halt_bit, clk->halt_reg); } }
/* Perform any register operations required to enable the clock. */ void local_clk_disable_reg(unsigned id) { struct clk_local *clk = &soc_clk_local_tbl[id]; void *reg = clk->cc_reg; uint32_t reg_val; /* Disable branch. */ reg_val = readl(reg); if (clk->br_en_mask) { reg_val &= ~(clk->br_en_mask); writel(reg_val, reg); } /* Wait for clock to disable before continuing. */ if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED || clk->halt_check == HALT_VOTED) udelay(HALT_CHECK_DELAY_US); else if (clk->halt_check == ENABLE || clk->halt_check == HALT) { int count; /* Use a memory barrier since some halt status registers are * not within the same 1K segment as the branch/root enable * registers. */ mb(); /* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */ for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id) && count > 0; count--) udelay(1); if (count == 0) pr_warning("%s: clock %d status stuck at 'on' (bit %d " "of 0x%p).\n", __func__, id, clk->halt_bit, clk->halt_reg); } /* Disable root. */ if (clk->root_en_mask) { reg_val &= ~(clk->root_en_mask); writel(reg_val, reg); } /* Disable MN counter, if applicable. */ if (clk->type == MND) { reg_val &= ~(clk->current_freq->mnd_en_mask); writel(reg_val, reg); } /* Program NS register to low-power value with an un-clocked or * slowly-clocked source selected. */ if (clk->ns_mask) { reg_val = readl(clk->ns_reg); reg_val &= ~(clk->ns_mask); reg_val |= (clk->freq_tbl->ns_val & clk->ns_mask); writel(reg_val, clk->ns_reg); } }
/* Perform any register operations required to enable the clock. */ void local_clk_enable_reg(unsigned id) { struct clk_local *clk = &soc_clk_local_tbl[id]; void *reg = clk->cc_reg; uint32_t reg_val; WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq), "Attempting to enable clock %d before setting its rate. " "Set the rate first!\n", id); /* Enable MN counter, if applicable. */ reg_val = readl_relaxed(reg); if (clk->type == MND) { reg_val |= clk->current_freq->mnd_en_mask; writel_relaxed(reg_val, reg); } /* Enable root. */ if (clk->root_en_mask) { reg_val |= clk->root_en_mask; writel_relaxed(reg_val, reg); } /* Enable branch. */ if (clk->br_en_mask) { reg_val |= clk->br_en_mask; writel_relaxed(reg_val, reg); } /* * Use a memory barrier since some halt status registers are * not within the same 1K segment as the branch/root enable * registers. It's also needed in the udelay() case to ensure * the delay starts after the branch enable. */ mb(); /* Wait for clock to enable before returning. */ if (clk->halt_check == DELAY) udelay(HALT_CHECK_DELAY_US); else if (clk->halt_check == ENABLE || clk->halt_check == HALT || clk->halt_check == ENABLE_VOTED || clk->halt_check == HALT_VOTED) { int count; /* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */ for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id) && count > 0; count--) udelay(1); if (count == 0) pr_warning("%s: clock %d status bit stuck off\n", __func__, id); } }
/* Perform any register operations required to enable the clock. */ void local_clk_disable_reg(unsigned id) { struct clk_local *clk = &soc_clk_local_tbl[id]; void *reg = clk->cc_reg; uint32_t reg_val; /* Disable branch. */ reg_val = readl_relaxed(reg); if (clk->br_en_mask) { reg_val &= ~(clk->br_en_mask); writel_relaxed(reg_val, reg); } /* * Use a memory barrier since some halt status registers are * not within the same K segment as the branch/root enable * registers. It's also needed in the udelay() case to ensure * the delay starts after the branch disable. */ mb(); /* Wait for clock to disable before continuing. */ if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED || clk->halt_check == HALT_VOTED) udelay(HALT_CHECK_DELAY_US); else if (clk->halt_check == ENABLE || clk->halt_check == HALT) { int count; /* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */ for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id) && count > 0; count--) udelay(1); if (count == 0) pr_warning("%s: clock %d status bit stuck on\n", __func__, id); } /* Disable root. */ if (clk->root_en_mask) { reg_val &= ~(clk->root_en_mask); writel_relaxed(reg_val, reg); } /* Disable MN counter, if applicable. */ if (clk->type == MND) { reg_val &= ~(clk->current_freq->mnd_en_mask); writel_relaxed(reg_val, reg); } }