561 lines
15 KiB
C
561 lines
15 KiB
C
|
/* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
|
|||
|
*
|
|||
|
* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
|
|||
|
*the the People's Republic of China and other countries.
|
|||
|
* All Allwinner Technology Co.,Ltd. trademarks are used with permission.
|
|||
|
*
|
|||
|
* DISCLAIMER
|
|||
|
* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
|
|||
|
* IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
|
|||
|
* IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
|
|||
|
* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
|
|||
|
* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
|
|||
|
* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
|
|||
|
* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
|
|||
|
*
|
|||
|
*
|
|||
|
* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
|
|||
|
* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
|
|||
|
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
|
|||
|
* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
|
|||
|
* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|||
|
* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
|
|||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
*/
|
|||
|
|
|||
|
#include "sunxi_hal_common.h"
|
|||
|
#include "clk_periph.h"
|
|||
|
|
|||
|
#define NEW_RATE_CALCULATE 1
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_get_parent(clk_periph_pt clk, u8 *parent_index)
|
|||
|
{
|
|||
|
u32 reg = 0;
|
|||
|
struct sunxi_clk_periph *periph = clk->config;
|
|||
|
|
|||
|
CCMU_TRACE();
|
|||
|
if (!periph->mux.reg)
|
|||
|
{
|
|||
|
*parent_index = 0;
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
reg = readl(periph->mux.reg);
|
|||
|
*parent_index = GET_BITS(periph->mux.shift, periph->mux.width, reg);
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
|
|||
|
CCMU_DBG("parent index %d \n", (*parent_index));
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_set_parent(clk_periph_pt clk, u8 index)
|
|||
|
{
|
|||
|
unsigned long reg, flags = 0;
|
|||
|
struct sunxi_clk_periph *periph = clk->config;
|
|||
|
|
|||
|
//if (periph->flags & CLK_READONLY)
|
|||
|
// return 0;
|
|||
|
|
|||
|
if (!periph->mux.reg)
|
|||
|
{
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
reg = readl(periph->mux.reg);
|
|||
|
reg = SET_BITS(periph->mux.shift, periph->mux.width, reg, index);
|
|||
|
writel(reg, periph->mux.reg);
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t __sunxi_clk_periph_enable_shared(struct sunxi_clk_periph *periph)
|
|||
|
{
|
|||
|
unsigned long reg;
|
|||
|
struct sunxi_clk_periph_gate *gate = &periph->gate;
|
|||
|
|
|||
|
if (!periph->com_gate->val)
|
|||
|
{
|
|||
|
/* de-assert module */
|
|||
|
if (gate->reset && IS_SHARE_RST_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->reset);
|
|||
|
reg = SET_BITS(gate->rst_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->reset);
|
|||
|
}
|
|||
|
/* enable bus gating */
|
|||
|
if (gate->bus && IS_SHARE_BUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->bus);
|
|||
|
reg = SET_BITS(gate->bus_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->bus);
|
|||
|
}
|
|||
|
|
|||
|
/* enable module gating */
|
|||
|
if (gate->enable && IS_SHARE_MOD_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->enable);
|
|||
|
reg = SET_BITS(gate->enb_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->enable);
|
|||
|
}
|
|||
|
|
|||
|
/* enable dram gating */
|
|||
|
if (gate->dram && IS_SHARE_MBUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->dram);
|
|||
|
reg = SET_BITS(gate->ddr_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->dram);
|
|||
|
}
|
|||
|
}
|
|||
|
periph->com_gate->val |= 1 << periph->com_gate_off;
|
|||
|
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t __sunxi_clk_periph_enable(struct sunxi_clk_periph *periph)
|
|||
|
{
|
|||
|
u32 reg;
|
|||
|
struct sunxi_clk_periph_gate *gate = &periph->gate;
|
|||
|
|
|||
|
/* de-assert module */
|
|||
|
if (gate->reset && !IS_SHARE_RST_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->reset);
|
|||
|
reg = SET_BITS(gate->rst_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->reset);
|
|||
|
}
|
|||
|
|
|||
|
/* enable bus gating */
|
|||
|
if (gate->bus && !IS_SHARE_BUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->bus);
|
|||
|
reg = SET_BITS(gate->bus_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->bus);
|
|||
|
}
|
|||
|
|
|||
|
/* enable module gating */
|
|||
|
if (gate->enable && !IS_SHARE_MOD_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->enable);
|
|||
|
//if (periph->flags & CLK_REVERT_ENABLE)
|
|||
|
// reg = SET_BITS(gate->enb_shift, 1, reg, 0);
|
|||
|
//else
|
|||
|
reg = SET_BITS(gate->enb_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->enable);
|
|||
|
}
|
|||
|
|
|||
|
/* enable dram gating */
|
|||
|
if (gate->dram && !IS_SHARE_MBUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->dram);
|
|||
|
reg = SET_BITS(gate->ddr_shift, 1, reg, 1);
|
|||
|
writel(reg, gate->dram);
|
|||
|
}
|
|||
|
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_enable(clk_periph_pt clk)
|
|||
|
{
|
|||
|
//unsigned long flags = 0;
|
|||
|
hal_clk_status_t ret = 0;
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
|
|||
|
//if (periph->flags & CLK_READONLY)
|
|||
|
// return 0;
|
|||
|
periph = clk->config;
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
/* if common gate exist, enable it first */
|
|||
|
if (periph->com_gate)
|
|||
|
{
|
|||
|
ret = __sunxi_clk_periph_enable_shared(periph);
|
|||
|
}
|
|||
|
if (!ret)
|
|||
|
{
|
|||
|
ret = __sunxi_clk_periph_enable(periph);
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
|
|||
|
return ret == HAL_CLK_STATUS_OK ? \
|
|||
|
HAL_CLK_STATUS_ENABLED : HAL_CLK_STATUS_ERROR_CLK_ENABLED_FAILED;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_is_enabled(clk_periph_pt clk)
|
|||
|
{
|
|||
|
u32 state = 0, reg = 0;
|
|||
|
//unsigned long flags = 0;
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
struct sunxi_clk_periph_gate *gate = NULL;
|
|||
|
|
|||
|
periph = clk->config;
|
|||
|
gate = &periph->gate;
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
/* enable bus gating */
|
|||
|
if (gate->bus)
|
|||
|
{
|
|||
|
reg = readl(gate->bus);
|
|||
|
state &= GET_BITS(gate->bus_shift, 1, reg);
|
|||
|
}
|
|||
|
|
|||
|
/* enable module gating */
|
|||
|
if (gate->enable)
|
|||
|
{
|
|||
|
reg = readl(gate->enable);
|
|||
|
state &= GET_BITS(gate->enb_shift, 1, reg);
|
|||
|
}
|
|||
|
|
|||
|
/* de-assert module */
|
|||
|
if (gate->reset)
|
|||
|
{
|
|||
|
reg = readl(gate->reset);
|
|||
|
state &= GET_BITS(gate->rst_shift, 1, reg);
|
|||
|
}
|
|||
|
|
|||
|
/* enable dram gating */
|
|||
|
if (gate->dram)
|
|||
|
{
|
|||
|
reg = readl(gate->dram);
|
|||
|
state &= GET_BITS(gate->ddr_shift, 1, reg);
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
|
|||
|
return state ? HAL_CLK_STATUS_ENABLED : HAL_CLK_STATUS_DISABLED;
|
|||
|
}
|
|||
|
|
|||
|
static void __sunxi_clk_periph_disable_shared(struct sunxi_clk_periph *periph)
|
|||
|
{
|
|||
|
unsigned long reg;
|
|||
|
struct sunxi_clk_periph_gate *gate = &periph->gate;
|
|||
|
|
|||
|
if (!periph->com_gate->val)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
periph->com_gate->val &= ~(1 << periph->com_gate_off);
|
|||
|
|
|||
|
if (!periph->com_gate->val)
|
|||
|
{
|
|||
|
/* disable dram gating */
|
|||
|
if (gate->dram && IS_SHARE_MBUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->dram);
|
|||
|
reg = SET_BITS(gate->ddr_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->dram);
|
|||
|
}
|
|||
|
|
|||
|
/* disable module gating */
|
|||
|
if (gate->enable && IS_SHARE_MOD_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->enable);
|
|||
|
reg = SET_BITS(gate->enb_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->enable);
|
|||
|
}
|
|||
|
|
|||
|
/* disable bus gating */
|
|||
|
if (gate->bus && IS_SHARE_BUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->bus);
|
|||
|
reg = SET_BITS(gate->bus_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->bus);
|
|||
|
}
|
|||
|
|
|||
|
/* assert module */
|
|||
|
if (gate->reset && IS_SHARE_RST_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->reset);
|
|||
|
reg = SET_BITS(gate->rst_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->reset);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
static void __sunxi_clk_periph_disable(struct sunxi_clk_periph *periph)
|
|||
|
{
|
|||
|
u32 reg;
|
|||
|
struct sunxi_clk_periph_gate *gate = &periph->gate;
|
|||
|
|
|||
|
/* disable dram gating */
|
|||
|
if (gate->dram && !IS_SHARE_MBUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->dram);
|
|||
|
reg = SET_BITS(gate->ddr_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->dram);
|
|||
|
}
|
|||
|
|
|||
|
/* disable module gating */
|
|||
|
if (gate->enable && !IS_SHARE_MOD_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->enable);
|
|||
|
//if (periph->flags & CLK_REVERT_ENABLE)
|
|||
|
// reg = SET_BITS(gate->enb_shift, 1, reg, 1);
|
|||
|
//else
|
|||
|
reg = SET_BITS(gate->enb_shift, 1, reg, 0);
|
|||
|
|
|||
|
writel(reg, gate->enable);
|
|||
|
}
|
|||
|
|
|||
|
/* disable bus gating */
|
|||
|
if (gate->bus && !IS_SHARE_BUS_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->bus);
|
|||
|
reg = SET_BITS(gate->bus_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->bus);
|
|||
|
}
|
|||
|
|
|||
|
/* assert module */
|
|||
|
if (gate->reset && !IS_SHARE_RST_GATE(periph))
|
|||
|
{
|
|||
|
reg = readl(gate->reset);
|
|||
|
reg = SET_BITS(gate->rst_shift, 1, reg, 0);
|
|||
|
writel(reg, gate->reset);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_disable(clk_periph_pt clk)
|
|||
|
{
|
|||
|
//unsigned long flags = 0;
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
|
|||
|
//if (periph->flags & CLK_READONLY)
|
|||
|
// return 0;
|
|||
|
periph = clk->config;
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
__sunxi_clk_periph_disable(periph);
|
|||
|
|
|||
|
/* if common gate exist, disable it */
|
|||
|
if (periph->com_gate)
|
|||
|
{
|
|||
|
__sunxi_clk_periph_disable_shared(periph);
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
return HAL_CLK_STATUS_DISABLED;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_recalc_rate(clk_periph_pt clk, u32 *rate)
|
|||
|
{
|
|||
|
u32 reg = 0, parent_rate = 0;
|
|||
|
u64 div, div_m = 0, div_n = 0, clk_rate = 0;
|
|||
|
hal_clk_status_t ret = HAL_CLK_STATUS_OK;
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
struct sunxi_clk_periph_div *divider = NULL;
|
|||
|
|
|||
|
periph = clk->config;
|
|||
|
divider = &periph->divider;
|
|||
|
parent_rate = clk->clk_core.parent_rate;
|
|||
|
clk_rate = (u64)parent_rate;
|
|||
|
if (!divider->reg)
|
|||
|
{
|
|||
|
*rate = parent_rate;
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_lock_irqsave(periph->lock, flags);
|
|||
|
|
|||
|
reg = readl(divider->reg);
|
|||
|
if (divider->mwidth)
|
|||
|
{
|
|||
|
div_m = GET_BITS(divider->mshift, divider->mwidth, reg);
|
|||
|
}
|
|||
|
if (divider->nwidth)
|
|||
|
{
|
|||
|
div_n = GET_BITS(divider->nshift, divider->nwidth, reg);
|
|||
|
}
|
|||
|
div = (div_m + 1) * (1 << div_n);
|
|||
|
do_div(clk_rate, div);
|
|||
|
|
|||
|
//if (periph->lock)
|
|||
|
// spin_unlock_irqrestore(periph->lock, flags);
|
|||
|
*rate = (u32)clk_rate;
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
u32 sunxi_clk_periph_round_rate(clk_periph_pt clk, u32 rate, u32 prate)
|
|||
|
{
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
struct sunxi_clk_periph_div *divider = NULL;
|
|||
|
|
|||
|
u32 i = 0, round_rate = 0;
|
|||
|
u64 div, div_m = 0, div_n = 0;
|
|||
|
u64 factor_m = 0, factor_n = 0, found = 0;
|
|||
|
|
|||
|
CCMU_TRACE();
|
|||
|
periph = clk->config;
|
|||
|
divider = &periph->divider;
|
|||
|
|
|||
|
round_rate = (prate + rate / 2 - 1);
|
|||
|
if (!rate)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
do_div(round_rate, rate);
|
|||
|
div = round_rate;
|
|||
|
if (!div)
|
|||
|
{
|
|||
|
return prate;
|
|||
|
}
|
|||
|
|
|||
|
round_rate = prate;
|
|||
|
div_m = 1 << divider->mwidth;
|
|||
|
if (divider->nwidth)
|
|||
|
{
|
|||
|
div_n = 1 << divider->nwidth;
|
|||
|
div_n = 1 << (div_n - 1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
div_n = 1;
|
|||
|
}
|
|||
|
|
|||
|
/* NEW_RATE_CALCULATE */
|
|||
|
while (i < (1 << divider->nwidth))
|
|||
|
{
|
|||
|
if (div <= div_m)
|
|||
|
{
|
|||
|
factor_m = div - 1;
|
|||
|
factor_n = i;
|
|||
|
do_div(round_rate, (factor_m + 1) * (1 << factor_n));
|
|||
|
found = 1;
|
|||
|
break;
|
|||
|
}
|
|||
|
div = div >> 1;
|
|||
|
i++;
|
|||
|
|
|||
|
if (!div)
|
|||
|
{
|
|||
|
factor_m = 0;
|
|||
|
factor_n = i;
|
|||
|
do_div(round_rate, (factor_m + 1) * (1 << factor_n));
|
|||
|
found = 1;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!found)
|
|||
|
{
|
|||
|
factor_m = (div > div_m ? div_m : div) - 1;
|
|||
|
factor_n = (1 << divider->nwidth) - 1;
|
|||
|
do_div(round_rate, (factor_m + 1) * (1 << factor_n));
|
|||
|
}
|
|||
|
|
|||
|
CCMU_DBG("parent rate %dHZ, target rate %dHZ, round rate %dHZ\n", prate, rate, round_rate);
|
|||
|
CCMU_TRACE();
|
|||
|
return round_rate;
|
|||
|
}
|
|||
|
|
|||
|
hal_clk_status_t sunxi_clk_periph_set_rate(clk_periph_pt clk, u32 rate)
|
|||
|
{
|
|||
|
u32 i = 0, factor_m = 0, factor_n = 0, found = 0, parent_rate = 0;
|
|||
|
u32 reg = 0;
|
|||
|
struct sunxi_clk_periph *periph = NULL;
|
|||
|
struct sunxi_clk_periph_div *divider = NULL;
|
|||
|
u32 div, div_m = 0, div_n = 0;
|
|||
|
|
|||
|
CCMU_TRACE();
|
|||
|
periph = clk->config;
|
|||
|
divider = &periph->divider;
|
|||
|
parent_rate = clk->clk_core.parent_rate;
|
|||
|
|
|||
|
CCMU_DBG("parent rate %dHZ, set rate %dHZ\n", parent_rate, rate);
|
|||
|
u64 tmp_rate = parent_rate;
|
|||
|
do_div(tmp_rate, rate);
|
|||
|
div = tmp_rate;
|
|||
|
|
|||
|
if (!div)
|
|||
|
{
|
|||
|
div_m = div_n = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
div_m = 1 << divider->mwidth;
|
|||
|
div_n = (1 << divider->nwidth) - 1;
|
|||
|
|
|||
|
if (div > (div_m << div_n))
|
|||
|
{
|
|||
|
//WARN(1, "clk %s rate is too large : %lu\n", hw->init->name, rate);
|
|||
|
div = div_m << div_n;
|
|||
|
}
|
|||
|
found = 0;
|
|||
|
while (i < (1 << divider->nwidth))
|
|||
|
{
|
|||
|
if (div <= div_m)
|
|||
|
{
|
|||
|
factor_m = div - 1;
|
|||
|
factor_n = i;
|
|||
|
found = 1;
|
|||
|
break;
|
|||
|
}
|
|||
|
div = div >> 1;
|
|||
|
i++;
|
|||
|
if (!div)
|
|||
|
{
|
|||
|
factor_m = 0;
|
|||
|
factor_n = i;
|
|||
|
found = 1;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!found)
|
|||
|
{
|
|||
|
factor_m = (div > div_m ? div_m : div) - 1;
|
|||
|
factor_n = (1 << divider->nwidth) - 1;
|
|||
|
}
|
|||
|
div_m = factor_m;
|
|||
|
div_n = factor_n;
|
|||
|
}
|
|||
|
|
|||
|
CCMU_DBG("divider->reg %d divider->mwidth %d divider->nshift %d \n", divider->reg, divider->mwidth, divider->nshift);
|
|||
|
if (!divider->reg)
|
|||
|
{
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|
|||
|
reg = readl(divider->reg);
|
|||
|
if (divider->mwidth)
|
|||
|
{
|
|||
|
reg = SET_BITS(divider->mshift, divider->mwidth, reg, div_m);
|
|||
|
}
|
|||
|
if (divider->nwidth)
|
|||
|
{
|
|||
|
reg = SET_BITS(divider->nshift, divider->nwidth, reg, div_n);
|
|||
|
}
|
|||
|
writel(reg, divider->reg);
|
|||
|
|
|||
|
CCMU_TRACE();
|
|||
|
return HAL_CLK_STATUS_OK;
|
|||
|
}
|