forked from Minki/linux
Allwinner Clocks additions for 3.19
A few patches that should go through the clock tree, mostly fixes, cleanups, and new clocks additions to start to support the A80. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUcgvhAAoJEBx+YmzsjxAgMBQQALMexo9E+r09f/1+rtH9iFXC XBWbGZJufGHLPP0RYNhOK1m6TShpaZMMu6OTWHkQZ8sUUb0e35AhgvZxdMtdj/9T K3yQ2PX4YlcJJUOK1HiLNXtVa//evth/GjXEB7MC1D8FW6hbXU6jkvhbLiCDAxyl s3PPvbi6EXRExiHN6r5U3PD3BdLjSr/eRZLNvbHM5ImFMA03rmJsRcIK+STP01zg OYgEkwSq+n0lJ+9d7mFXb+Bb7fPUvwDGtgqdoajiMOJc99p/91bDHTu84Fq0g2X2 m/2ofaiuioVj6QiIH+tm1WiOU0qON70N23YSaeG4c9yGZI1CnRIsUvjRWA8/mWtb 94O+k+LpU1fk1xWvNL+uthIHiiBJqlg5255ry02jKIZWMeuNVlBLawynvnaQ2Lki RkOQkaMYtYTFUsKWCf0LSEwCC8UCuXa3mkRfPioC6Pk/fE5Doqb56qnDHdxhn0VX t6GH03Pzb1OLLMdxfK7VcamLwA3MeEp7byxpCZ24GSUtthhFdXvyduaeXSV7+Lo7 gg7NdFwlNy6RXAMkP1CpnYF0sZsekn7hToUl+GQzYSAP35Mt2C62sHzMD9Pxgezv n7WXThKIYJz/r7S00MnTFlp2Ge20NtUp/BEFbxn6w3FvG7R8Gk633z1LiZ1mGEJ9 4iMjTj20SnN+GOz0p7qA =Krm9 -----END PGP SIGNATURE----- Merge tag 'sunxi-clocks-for-3.19' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next Allwinner Clocks additions for 3.19 A few patches that should go through the clock tree, mostly fixes, cleanups, and new clocks additions to start to support the A80.
This commit is contained in:
commit
b082915c9d
@ -10,14 +10,17 @@ Required properties:
|
||||
"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
|
||||
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
|
||||
"allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
|
||||
"allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80
|
||||
"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
|
||||
"allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
|
||||
"allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
|
||||
"allwinner,sun9i-a80-gt-clk" - for the GT bus clock on A80
|
||||
"allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
|
||||
"allwinner,sun4i-a10-axi-clk" - for the AXI clock
|
||||
"allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
|
||||
"allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
|
||||
"allwinner,sun4i-a10-ahb-clk" - for the AHB clock
|
||||
"allwinner,sun9i-a80-ahb-clk" - for the AHB bus clocks on A80
|
||||
"allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
|
||||
"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
|
||||
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
|
||||
@ -26,24 +29,29 @@ Required properties:
|
||||
"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
|
||||
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
|
||||
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
|
||||
"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
|
||||
"allwinner,sun9i-a80-ahb1-gates-clk" - for the AHB1 gates on A80
|
||||
"allwinner,sun9i-a80-ahb2-gates-clk" - for the AHB2 gates on A80
|
||||
"allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
|
||||
"allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
|
||||
"allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23
|
||||
"allwinner,sun9i-a80-apb0-clk" - for the APB0 bus clock on A80
|
||||
"allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
|
||||
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
|
||||
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
|
||||
"allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
|
||||
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
|
||||
"allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23
|
||||
"allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80
|
||||
"allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
|
||||
"allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
|
||||
"allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80
|
||||
"allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
|
||||
"allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
|
||||
"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
|
||||
"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
|
||||
"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
|
||||
"allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23
|
||||
"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
|
||||
"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
|
||||
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
|
||||
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
|
||||
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
|
||||
@ -63,8 +71,9 @@ Required properties for all clocks:
|
||||
multiplexed clocks, the list order must match the hardware
|
||||
programming order.
|
||||
- #clock-cells : from common clock binding; shall be set to 0 except for
|
||||
"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk" and
|
||||
"allwinner,sun4i-pll6-clk" where it shall be set to 1
|
||||
the following compatibles where it shall be set to 1:
|
||||
"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
|
||||
"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
|
||||
- clock-output-names : shall be the corresponding names of the outputs.
|
||||
If the clock module only has one output, the name shall be the
|
||||
module name.
|
||||
@ -79,6 +88,12 @@ Clock consumers should specify the desired clocks they use with a
|
||||
"clocks" phandle cell. Consumers that are using a gated clock should
|
||||
provide an additional ID in their clock property. This ID is the
|
||||
offset of the bit controlling this particular gate in the register.
|
||||
For the other clocks with "#clock-cells" = 1, the additional ID shall
|
||||
refer to the index of the output.
|
||||
|
||||
For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
|
||||
is the normal PLL6 output, or "pll6". The second output is rate doubled
|
||||
PLL6, or "pll6x2".
|
||||
|
||||
For example:
|
||||
|
||||
@ -106,6 +121,14 @@ pll5: clk@01c20020 {
|
||||
clock-output-names = "pll5_ddr", "pll5_other";
|
||||
};
|
||||
|
||||
pll6: clk@01c20028 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun6i-a31-pll6-clk";
|
||||
reg = <0x01c20028 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
clock-output-names = "pll6", "pll6x2";
|
||||
};
|
||||
|
||||
cpu: cpu@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-cpu-clk";
|
||||
|
@ -174,19 +174,11 @@
|
||||
"apb0_ir1", "apb0_keypad";
|
||||
};
|
||||
|
||||
apb1_mux: apb1_mux@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1_mux";
|
||||
};
|
||||
|
||||
apb1: apb1@01c20058 {
|
||||
apb1: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb1_mux>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1";
|
||||
};
|
||||
|
||||
|
@ -162,19 +162,11 @@
|
||||
"apb0_ir", "apb0_keypad";
|
||||
};
|
||||
|
||||
apb1_mux: apb1_mux@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1_mux";
|
||||
};
|
||||
|
||||
apb1: apb1@01c20058 {
|
||||
apb1: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb1_mux>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1";
|
||||
};
|
||||
|
||||
|
@ -161,19 +161,11 @@
|
||||
clock-output-names = "apb0_codec", "apb0_pio", "apb0_ir";
|
||||
};
|
||||
|
||||
apb1_mux: apb1_mux@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1_mux";
|
||||
};
|
||||
|
||||
apb1: apb1@01c20058 {
|
||||
apb1: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb1_mux>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1";
|
||||
};
|
||||
|
||||
|
@ -217,19 +217,11 @@
|
||||
"apb1_daudio1";
|
||||
};
|
||||
|
||||
apb2_mux: apb2_mux@01c20058 {
|
||||
apb2: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
|
||||
clock-output-names = "apb2_mux";
|
||||
};
|
||||
|
||||
apb2: apb2@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun6i-a31-apb2-div-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb2_mux>;
|
||||
clock-output-names = "apb2";
|
||||
};
|
||||
|
||||
|
@ -222,19 +222,11 @@
|
||||
"apb0_iis2", "apb0_keypad";
|
||||
};
|
||||
|
||||
apb1_mux: apb1_mux@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1_mux";
|
||||
};
|
||||
|
||||
apb1: apb1@01c20058 {
|
||||
apb1: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb1_mux>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
|
||||
clock-output-names = "apb1";
|
||||
};
|
||||
|
||||
|
@ -189,19 +189,11 @@
|
||||
"apb1_daudio0", "apb1_daudio1";
|
||||
};
|
||||
|
||||
apb2_mux: apb2_mux_clk@01c20058 {
|
||||
apb2: clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
|
||||
clock-output-names = "apb2_mux";
|
||||
};
|
||||
|
||||
apb2: apb2_clk@01c20058 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun6i-a31-apb2-div-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&apb2_mux>;
|
||||
clock-output-names = "apb2";
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,7 @@ obj-y += clk-a10-hosc.o
|
||||
obj-y += clk-a20-gmac.o
|
||||
obj-y += clk-mod0.o
|
||||
obj-y += clk-sun8i-mbus.o
|
||||
obj-y += clk-sun9i-core.o
|
||||
|
||||
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
|
||||
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
|
||||
|
@ -53,6 +53,11 @@ static DEFINE_SPINLOCK(gmac_lock);
|
||||
#define SUN7I_A20_GMAC_MASK 0x3
|
||||
#define SUN7I_A20_GMAC_PARENTS 2
|
||||
|
||||
static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = {
|
||||
0x00, /* Select mii_phy_tx_clk */
|
||||
0x02, /* Select gmac_int_tx_clk */
|
||||
};
|
||||
|
||||
static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
@ -90,7 +95,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
|
||||
gate->lock = &gmac_lock;
|
||||
mux->reg = reg;
|
||||
mux->mask = SUN7I_A20_GMAC_MASK;
|
||||
mux->flags = CLK_MUX_INDEX_BIT;
|
||||
mux->table = sun7i_a20_gmac_mux_table;
|
||||
mux->lock = &gmac_lock;
|
||||
|
||||
clk = clk_register_composite(NULL, clk_name,
|
||||
|
@ -224,7 +224,7 @@ struct clk * __init sunxi_factors_register(struct device_node *node,
|
||||
/* set up gate properties */
|
||||
mux->reg = reg;
|
||||
mux->shift = data->mux;
|
||||
mux->mask = SUNXI_FACTORS_MUX_MASK;
|
||||
mux->mask = data->muxmask;
|
||||
mux->lock = factors->lock;
|
||||
mux_hw = &mux->hw;
|
||||
}
|
||||
|
@ -7,8 +7,6 @@
|
||||
|
||||
#define SUNXI_FACTORS_NOT_APPLICABLE (0)
|
||||
|
||||
#define SUNXI_FACTORS_MUX_MASK 0x3
|
||||
|
||||
struct clk_factors_config {
|
||||
u8 nshift;
|
||||
u8 nwidth;
|
||||
@ -24,6 +22,7 @@ struct clk_factors_config {
|
||||
struct factors_data {
|
||||
int enable;
|
||||
int mux;
|
||||
int muxmask;
|
||||
struct clk_factors_config *table;
|
||||
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
|
||||
const char *name;
|
||||
|
@ -70,6 +70,7 @@ static struct clk_factors_config sun4i_a10_mod0_config = {
|
||||
static const struct factors_data sun4i_a10_mod0_data __initconst = {
|
||||
.enable = 31,
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun4i_a10_mod0_config,
|
||||
.getter = sun4i_a10_get_mod0_factors,
|
||||
};
|
||||
|
@ -60,6 +60,7 @@ static struct clk_factors_config sun8i_a23_mbus_config = {
|
||||
static const struct factors_data sun8i_a23_mbus_data __initconst = {
|
||||
.enable = 31,
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun8i_a23_mbus_config,
|
||||
.getter = sun8i_a23_get_mbus_factors,
|
||||
};
|
||||
|
271
drivers/clk/sunxi/clk-sun9i-core.c
Normal file
271
drivers/clk/sunxi/clk-sun9i-core.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2014 Chen-Yu Tsai
|
||||
*
|
||||
* Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include "clk-factors.h"
|
||||
|
||||
|
||||
/**
|
||||
* sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1
|
||||
* PLL4 rate is calculated as follows
|
||||
* rate = (parent_rate * n >> p) / (m + 1);
|
||||
* parent_rate is always 24Mhz
|
||||
*
|
||||
* p and m are named div1 and div2 in Allwinner's SDK
|
||||
*/
|
||||
|
||||
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
int div;
|
||||
|
||||
/* Normalize value to a 6M multiple */
|
||||
div = DIV_ROUND_UP(*freq, 6000000);
|
||||
|
||||
/* divs above 256 cannot be odd */
|
||||
if (div > 256)
|
||||
div = round_up(div, 2);
|
||||
|
||||
/* divs above 512 must be a multiple of 4 */
|
||||
if (div > 512)
|
||||
div = round_up(div, 4);
|
||||
|
||||
*freq = 6000000 * div;
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (n == NULL)
|
||||
return;
|
||||
|
||||
/* p will be 1 for divs under 512 */
|
||||
if (div < 512)
|
||||
*p = 1;
|
||||
else
|
||||
*p = 0;
|
||||
|
||||
/* m will be 1 if div is odd */
|
||||
if (div & 1)
|
||||
*m = 1;
|
||||
else
|
||||
*m = 0;
|
||||
|
||||
/* calculate a suitable n based on m and p */
|
||||
*n = div / (*p + 1) / (*m + 1);
|
||||
}
|
||||
|
||||
static struct clk_factors_config sun9i_a80_pll4_config = {
|
||||
.mshift = 18,
|
||||
.mwidth = 1,
|
||||
.nshift = 8,
|
||||
.nwidth = 8,
|
||||
.pshift = 16,
|
||||
.pwidth = 1,
|
||||
};
|
||||
|
||||
static const struct factors_data sun9i_a80_pll4_data __initconst = {
|
||||
.enable = 31,
|
||||
.table = &sun9i_a80_pll4_config,
|
||||
.getter = sun9i_a80_get_pll4_factors,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
|
||||
|
||||
static void __init sun9i_a80_pll4_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
|
||||
|
||||
|
||||
/**
|
||||
* sun9i_a80_get_gt_factors() - calculates m factor for GT
|
||||
* GT rate is calculated as follows
|
||||
* rate = parent_rate / (m + 1);
|
||||
*/
|
||||
|
||||
static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
u32 div;
|
||||
|
||||
if (parent_rate < *freq)
|
||||
*freq = parent_rate;
|
||||
|
||||
div = DIV_ROUND_UP(parent_rate, *freq);
|
||||
|
||||
/* maximum divider is 4 */
|
||||
if (div > 4)
|
||||
div = 4;
|
||||
|
||||
*freq = parent_rate / div;
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
*m = div;
|
||||
}
|
||||
|
||||
static struct clk_factors_config sun9i_a80_gt_config = {
|
||||
.mshift = 0,
|
||||
.mwidth = 2,
|
||||
};
|
||||
|
||||
static const struct factors_data sun9i_a80_gt_data __initconst = {
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun9i_a80_gt_config,
|
||||
.getter = sun9i_a80_get_gt_factors,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
|
||||
|
||||
static void __init sun9i_a80_gt_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
|
||||
&sun9i_a80_gt_lock);
|
||||
|
||||
/* The GT bus clock needs to be always enabled */
|
||||
__clk_get(gt);
|
||||
clk_prepare_enable(gt);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
|
||||
|
||||
|
||||
/**
|
||||
* sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2
|
||||
* AHB rate is calculated as follows
|
||||
* rate = parent_rate >> p;
|
||||
*/
|
||||
|
||||
static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
u32 _p;
|
||||
|
||||
if (parent_rate < *freq)
|
||||
*freq = parent_rate;
|
||||
|
||||
_p = order_base_2(DIV_ROUND_UP(parent_rate, *freq));
|
||||
|
||||
/* maximum p is 3 */
|
||||
if (_p > 3)
|
||||
_p = 3;
|
||||
|
||||
*freq = parent_rate >> _p;
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
*p = _p;
|
||||
}
|
||||
|
||||
static struct clk_factors_config sun9i_a80_ahb_config = {
|
||||
.pshift = 0,
|
||||
.pwidth = 2,
|
||||
};
|
||||
|
||||
static const struct factors_data sun9i_a80_ahb_data __initconst = {
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun9i_a80_ahb_config,
|
||||
.getter = sun9i_a80_get_ahb_factors,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
|
||||
|
||||
static void __init sun9i_a80_ahb_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
|
||||
|
||||
|
||||
static const struct factors_data sun9i_a80_apb0_data __initconst = {
|
||||
.mux = 24,
|
||||
.muxmask = BIT(0),
|
||||
.table = &sun9i_a80_ahb_config,
|
||||
.getter = sun9i_a80_get_ahb_factors,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
|
||||
|
||||
static void __init sun9i_a80_apb0_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
|
||||
|
||||
|
||||
/**
|
||||
* sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1
|
||||
* APB1 rate is calculated as follows
|
||||
* rate = (parent_rate >> p) / (m + 1);
|
||||
*/
|
||||
|
||||
static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
u32 div;
|
||||
u8 calcm, calcp;
|
||||
|
||||
if (parent_rate < *freq)
|
||||
*freq = parent_rate;
|
||||
|
||||
div = DIV_ROUND_UP(parent_rate, *freq);
|
||||
|
||||
/* Highest possible divider is 256 (p = 3, m = 31) */
|
||||
if (div > 256)
|
||||
div = 256;
|
||||
|
||||
calcp = order_base_2(div);
|
||||
calcm = (parent_rate >> calcp) - 1;
|
||||
*freq = (parent_rate >> calcp) / (calcm + 1);
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (n == NULL)
|
||||
return;
|
||||
|
||||
*m = calcm;
|
||||
*p = calcp;
|
||||
}
|
||||
|
||||
static struct clk_factors_config sun9i_a80_apb1_config = {
|
||||
.mshift = 0,
|
||||
.mwidth = 5,
|
||||
.pshift = 16,
|
||||
.pwidth = 2,
|
||||
};
|
||||
|
||||
static const struct factors_data sun9i_a80_apb1_data __initconst = {
|
||||
.mux = 24,
|
||||
.muxmask = BIT(0),
|
||||
.table = &sun9i_a80_apb1_config,
|
||||
.getter = sun9i_a80_get_apb1_factors,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
|
||||
|
||||
static void __init sun9i_a80_apb1_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);
|
@ -245,9 +245,9 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
|
||||
}
|
||||
|
||||
/**
|
||||
* sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
|
||||
* PLL6 rate is calculated as follows
|
||||
* rate = parent_rate * n * (k + 1) / 2
|
||||
* sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6x2
|
||||
* PLL6x2 rate is calculated as follows
|
||||
* rate = parent_rate * (n + 1) * (k + 1)
|
||||
* parent_rate is always 24Mhz
|
||||
*/
|
||||
|
||||
@ -256,13 +256,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
|
||||
{
|
||||
u8 div;
|
||||
|
||||
/*
|
||||
* We always have 24MHz / 2, so we can just say that our
|
||||
* parent clock is 12MHz.
|
||||
*/
|
||||
parent_rate = parent_rate / 2;
|
||||
|
||||
/* Normalize value to a parent_rate multiple (24M / 2) */
|
||||
/* Normalize value to a parent_rate multiple (24M) */
|
||||
div = *freq / parent_rate;
|
||||
*freq = parent_rate * div;
|
||||
|
||||
@ -274,7 +268,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
|
||||
if (*k > 3)
|
||||
*k = 3;
|
||||
|
||||
*n = DIV_ROUND_UP(div, (*k+1));
|
||||
*n = DIV_ROUND_UP(div, (*k+1)) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,6 +439,7 @@ static struct clk_factors_config sun6i_a31_pll6_config = {
|
||||
.nwidth = 5,
|
||||
.kshift = 4,
|
||||
.kwidth = 2,
|
||||
.n_start = 1,
|
||||
};
|
||||
|
||||
static struct clk_factors_config sun4i_apb1_config = {
|
||||
@ -504,9 +499,12 @@ static const struct factors_data sun6i_a31_pll6_data __initconst = {
|
||||
.enable = 31,
|
||||
.table = &sun6i_a31_pll6_config,
|
||||
.getter = sun6i_a31_get_pll6_factors,
|
||||
.name = "pll6x2",
|
||||
};
|
||||
|
||||
static const struct factors_data sun4i_apb1_data __initconst = {
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun4i_apb1_config,
|
||||
.getter = sun4i_get_apb1_factors,
|
||||
};
|
||||
@ -514,6 +512,7 @@ static const struct factors_data sun4i_apb1_data __initconst = {
|
||||
static const struct factors_data sun7i_a20_out_data __initconst = {
|
||||
.enable = 31,
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
.table = &sun7i_a20_out_config,
|
||||
.getter = sun7i_a20_get_out_factors,
|
||||
};
|
||||
@ -544,10 +543,6 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
|
||||
.shift = 12,
|
||||
};
|
||||
|
||||
static const struct mux_data sun4i_apb1_mux_data __initconst = {
|
||||
.shift = 24,
|
||||
};
|
||||
|
||||
static void __init sunxi_mux_clk_setup(struct device_node *node,
|
||||
struct mux_data *data)
|
||||
{
|
||||
@ -633,12 +628,6 @@ static const struct div_data sun4i_apb0_data __initconst = {
|
||||
.table = sun4i_apb0_table,
|
||||
};
|
||||
|
||||
static const struct div_data sun6i_a31_apb2_div_data __initconst = {
|
||||
.shift = 0,
|
||||
.pow = 0,
|
||||
.width = 4,
|
||||
};
|
||||
|
||||
static void __init sunxi_divider_clk_setup(struct device_node *node,
|
||||
struct div_data *data)
|
||||
{
|
||||
@ -757,6 +746,18 @@ static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
|
||||
.mask = {0x25386742, 0x2505111},
|
||||
};
|
||||
|
||||
static const struct gates_data sun9i_a80_ahb0_gates_data __initconst = {
|
||||
.mask = {0xF5F12B},
|
||||
};
|
||||
|
||||
static const struct gates_data sun9i_a80_ahb1_gates_data __initconst = {
|
||||
.mask = {0x1E20003},
|
||||
};
|
||||
|
||||
static const struct gates_data sun9i_a80_ahb2_gates_data __initconst = {
|
||||
.mask = {0x9B7},
|
||||
};
|
||||
|
||||
static const struct gates_data sun4i_apb0_gates_data __initconst = {
|
||||
.mask = {0x4EF},
|
||||
};
|
||||
@ -773,6 +774,10 @@ static const struct gates_data sun7i_a20_apb0_gates_data __initconst = {
|
||||
.mask = { 0x4ff },
|
||||
};
|
||||
|
||||
static const struct gates_data sun9i_a80_apb0_gates_data __initconst = {
|
||||
.mask = {0xEB822},
|
||||
};
|
||||
|
||||
static const struct gates_data sun4i_apb1_gates_data __initconst = {
|
||||
.mask = {0xFF00F7},
|
||||
};
|
||||
@ -801,6 +806,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
|
||||
.mask = { 0xff80ff },
|
||||
};
|
||||
|
||||
static const struct gates_data sun9i_a80_apb1_gates_data __initconst = {
|
||||
.mask = {0x3F001F},
|
||||
};
|
||||
|
||||
static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
|
||||
.mask = {0x1F0007},
|
||||
};
|
||||
@ -893,6 +902,7 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
|
||||
|
||||
struct divs_data {
|
||||
const struct factors_data *factors; /* data for the factor clock */
|
||||
int ndivs; /* number of children */
|
||||
struct {
|
||||
u8 fixed; /* is it a fixed divisor? if not... */
|
||||
struct clk_div_table *table; /* is it a table based divisor? */
|
||||
@ -912,6 +922,7 @@ static struct clk_div_table pll6_sata_tbl[] = {
|
||||
|
||||
static const struct divs_data pll5_divs_data __initconst = {
|
||||
.factors = &sun4i_pll5_data,
|
||||
.ndivs = 2,
|
||||
.div = {
|
||||
{ .shift = 0, .pow = 0, }, /* M, DDR */
|
||||
{ .shift = 16, .pow = 1, }, /* P, other */
|
||||
@ -920,12 +931,21 @@ static const struct divs_data pll5_divs_data __initconst = {
|
||||
|
||||
static const struct divs_data pll6_divs_data __initconst = {
|
||||
.factors = &sun4i_pll6_data,
|
||||
.ndivs = 2,
|
||||
.div = {
|
||||
{ .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
|
||||
{ .fixed = 2 }, /* P, other */
|
||||
}
|
||||
};
|
||||
|
||||
static const struct divs_data sun6i_a31_pll6_divs_data __initconst = {
|
||||
.factors = &sun6i_a31_pll6_data,
|
||||
.ndivs = 1,
|
||||
.div = {
|
||||
{ .fixed = 2 }, /* normal output */
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks
|
||||
*
|
||||
@ -950,7 +970,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
|
||||
struct clk_fixed_factor *fix_factor;
|
||||
struct clk_divider *divider;
|
||||
void __iomem *reg;
|
||||
int i = 0;
|
||||
int ndivs = SUNXI_DIVS_MAX_QTY, i = 0;
|
||||
int flags, clkflags;
|
||||
|
||||
/* Set up factor clock that we will be dividing */
|
||||
@ -973,7 +993,11 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
|
||||
* our RAM clock! */
|
||||
clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT;
|
||||
|
||||
for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) {
|
||||
/* if number of children known, use it */
|
||||
if (data->ndivs)
|
||||
ndivs = data->ndivs;
|
||||
|
||||
for (i = 0; i < ndivs; i++) {
|
||||
if (of_property_read_string_index(node, "clock-output-names",
|
||||
i, &clk_name) != 0)
|
||||
break;
|
||||
@ -1062,7 +1086,6 @@ static const struct of_device_id clk_factors_match[] __initconst = {
|
||||
{.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
|
||||
{.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
|
||||
{.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
|
||||
{.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
|
||||
{}
|
||||
@ -1074,7 +1097,6 @@ static const struct of_device_id clk_div_match[] __initconst = {
|
||||
{.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1082,13 +1104,13 @@ static const struct of_device_id clk_div_match[] __initconst = {
|
||||
static const struct of_device_id clk_divs_match[] __initconst = {
|
||||
{.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_divs_data,},
|
||||
{}
|
||||
};
|
||||
|
||||
/* Matches for mux clocks */
|
||||
static const struct of_device_id clk_mux_match[] __initconst = {
|
||||
{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
|
||||
{}
|
||||
};
|
||||
@ -1102,16 +1124,21 @@ static const struct of_device_id clk_gates_match[] __initconst = {
|
||||
{.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
|
||||
{.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
|
||||
{.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
|
||||
{.compatible = "allwinner,sun9i-a80-ahb0-gates-clk", .data = &sun9i_a80_ahb0_gates_data,},
|
||||
{.compatible = "allwinner,sun9i-a80-ahb1-gates-clk", .data = &sun9i_a80_ahb1_gates_data,},
|
||||
{.compatible = "allwinner,sun9i-a80-ahb2-gates-clk", .data = &sun9i_a80_ahb2_gates_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
|
||||
{.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
|
||||
{.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
|
||||
{.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
|
||||
{.compatible = "allwinner,sun9i-a80-apb0-gates-clk", .data = &sun9i_a80_apb0_gates_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,},
|
||||
{.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
|
||||
{.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
|
||||
{.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
|
||||
@ -1200,3 +1227,9 @@ static void __init sun6i_init_clocks(struct device_node *node)
|
||||
}
|
||||
CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
|
||||
CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
|
||||
|
||||
static void __init sun9i_init_clocks(struct device_node *node)
|
||||
{
|
||||
sunxi_init_clocks(NULL, 0);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_clk_init, "allwinner,sun9i-a80", sun9i_init_clocks);
|
||||
|
Loading…
Reference in New Issue
Block a user