/* Normalize value to a 6M multiple */
div = req->rate / 6000000;
req->rate = 6000000 * div;
/* m is always zero for pll1 */
req->m = 0;
/* k is 1 only on these cases */ if (req->rate >= 768000000 || req->rate == 42000000 ||
req->rate == 54000000)
req->k = 1; else
req->k = 0;
/* p will be 3 for divs under 10 */ if (div < 10)
req->p = 3;
/* p will be 2 for divs between 10 - 20 and odd divs under 32 */ elseif (div < 20 || (div < 32 && (div & 1)))
req->p = 2;
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
* of divs between 40-62 */ elseif (div < 40 || (div < 64 && (div & 2)))
req->p = 1;
/* any other entries have p = 0 */ else
req->p = 0;
/* calculate a suitable n based on k and p */
div <<= req->p;
div /= (req->k + 1);
req->n = div / 4;
}
/* * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1 * PLL1 rate is calculated as follows * rate = parent_rate * (n + 1) * (k + 1) / (m + 1); * parent_rate should always be 24MHz
*/ staticvoid sun6i_a31_get_pll1_factors(struct factors_request *req)
{ /* * We can operate only on MHz, this will make our life easier * later.
*/
u32 freq_mhz = req->rate / 1000000;
u32 parent_freq_mhz = req->parent_rate / 1000000;
/* * Round down the frequency to the closest multiple of either * 6 or 16
*/
u32 round_freq_6 = rounddown(freq_mhz, 6);
u32 round_freq_16 = round_down(freq_mhz, 16);
/* If the frequency is a multiple of 32 MHz, k is always 3 */ if (!(freq_mhz % 32))
req->k = 3; /* If the frequency is a multiple of 9 MHz, k is always 2 */ elseif (!(freq_mhz % 9))
req->k = 2; /* If the frequency is a multiple of 8 MHz, k is always 1 */ elseif (!(freq_mhz % 8))
req->k = 1; /* Otherwise, we don't use the k factor */ else
req->k = 0;
/* * If the frequency is a multiple of 2 but not a multiple of * 3, m is 3. This is the first time we use 6 here, yet we * will use it on several other places. * We use this number because it's the lowest frequency we can * generate (with n = 0, k = 0, m = 3), so every other frequency * somehow relates to this frequency.
*/ if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
req->m = 2; /* * If the frequency is a multiple of 6MHz, but the factor is * odd, m will be 3
*/ elseif ((freq_mhz / 6) & 1)
req->m = 3; /* Otherwise, we end up with m = 1 */ else
req->m = 1;
/* Calculate n thanks to the above factors we already got */
req->n = freq_mhz * (req->m + 1) / ((req->k + 1) * parent_freq_mhz)
- 1;
/* * If n end up being outbound, and that we can still decrease * m, do it.
*/ if ((req->n + 1) > 31 && (req->m + 1) > 1) {
req->n = (req->n + 1) / 2 - 1;
req->m = (req->m + 1) / 2 - 1;
}
}
/* * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1 * PLL1 rate is calculated as follows * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1); * parent_rate is always 24Mhz
*/
/* Normalize value to a 6M multiple */
div = req->rate / 6000000;
req->rate = 6000000 * div;
/* m is always zero for pll1 */
req->m = 0;
/* k is 1 only on these cases */ if (req->rate >= 768000000 || req->rate == 42000000 ||
req->rate == 54000000)
req->k = 1; else
req->k = 0;
/* p will be 2 for divs under 20 and odd divs under 32 */ if (div < 20 || (div < 32 && (div & 1)))
req->p = 2;
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
* of divs between 40-62 */ elseif (div < 40 || (div < 64 && (div & 2)))
req->p = 1;
/* any other entries have p = 0 */ else
req->p = 0;
/* calculate a suitable n based on k and p */
div <<= req->p;
div /= (req->k + 1);
req->n = div / 4 - 1;
}
/* * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 * PLL5 rate is calculated as follows * rate = parent_rate * n * (k + 1) * parent_rate is always 24Mhz
*/
/* divide only */ if (req->parent_rate < req->rate)
req->rate = req->parent_rate;
/* * user manual says valid speed is 8k ~ 276M, but tests show it * can work at speeds up to 300M, just after reparenting to pll6
*/ if (req->rate < 8000)
req->rate = 8000; if (req->rate > 300000000)
req->rate = 300000000;
div = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
/* p = 0 ~ 3 */ if (div > 3)
div = 3;
req->rate = req->parent_rate >> div;
req->p = div;
}
#define SUN6I_AHB1_PARENT_PLL6 3
/* * sun6i_a31_get_ahb_factors() - calculates m, p factors for AHB * AHB rate is calculated as follows * rate = parent_rate >> p * * if parent is pll6, then * parent_rate = pll6 rate / (m + 1)
*/
/* * clock can only divide, so we will never be able to achieve * frequencies higher than the parent frequency
*/ if (req->parent_rate && req->rate > req->parent_rate)
req->rate = req->parent_rate;
/* * sun6i_ahb1_recalc() - calculates AHB clock rate from m, p factors and * parent index
*/ staticvoid sun6i_ahb1_recalc(struct factors_request *req)
{
req->rate = req->parent_rate;
/* apply pre-divider first if parent is pll6 */ if (req->parent_index == SUN6I_AHB1_PARENT_PLL6)
req->rate /= req->m + 1;
/* clk divider */
req->rate >>= req->p;
}
/* * sun4i_get_apb1_factors() - calculates m, p factors for APB1 * APB1 rate is calculated as follows * rate = (parent_rate >> p) / (m + 1);
*/
staticvoid sun4i_get_apb1_factors(struct factors_request *req)
{
u8 calcm, calcp; int div;
if (req->parent_rate < req->rate)
req->rate = req->parent_rate;
/* These clocks can only divide, so we will never be able to achieve
* frequencies higher than the parent frequency */ if (req->rate > req->parent_rate)
req->rate = req->parent_rate;
reg = of_iomap(node, 0); if (!reg) {
pr_err("Could not map registers for mux-clk: %pOF\n", node); return NULL;
}
i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS); if (of_property_read_string(node, "clock-output-names", &clk_name)) {
pr_err("%s: could not read clock-output-names from \"%pOF\"\n",
__func__, node); goto out_unmap;
}
reg = of_iomap(node, 0); if (!reg) {
pr_err("Could not map registers for mux-clk: %pOF\n", node); return;
}
clk_parent = of_clk_get_parent_name(node, 0);
if (of_property_read_string(node, "clock-output-names", &clk_name)) {
pr_err("%s: could not read clock-output-names from \"%pOF\"\n",
__func__, node); goto out_unmap;
}
struct divs_data { conststruct factors_data *factors; /* data for the factor clock */ int ndivs; /* number of outputs */ /* * List of outputs. Refer to the diagram for sunxi_divs_clk_setup(): * self or base factor clock refers to the output from the pll * itself. The remaining refer to fixed or configurable divider * outputs.
*/ struct {
u8 self; /* is it the base factor clock? (only one) */
u8 fixed; /* is it a fixed divisor? if not... */ struct clk_div_table *table; /* is it a table based divisor? */
u8 shift; /* otherwise it's a normal divisor with this shift */
u8 pow; /* is it power-of-two based? */
u8 gate; /* is it independently gateable? */ bool critical;
} div[SUNXI_DIVS_MAX_QTY];
};
/* * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks * * These clocks look something like this * ________________________ * | ___divisor 1---|----> to consumer * parent >--| pll___/___divisor 2---|----> to consumer * | \_______________|____> to consumer * |________________________|
*/
/* if number of children known, use it */ if (data->ndivs)
ndivs = data->ndivs;
/* Try to find a name for base factor clock */ for (i = 0; i < ndivs; i++) { if (data->div[i].self) {
of_property_read_string_index(node, "clock-output-names",
i, &factors.name); break;
}
} /* If we don't have a .self clk use the first output-name up to '_' */ if (factors.name == NULL) { char *endp;
/* Leaves can be fixed or configurable divisors */ if (data->div[i].fixed) {
fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL); if (!fix_factor) goto free_gate;
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.