Add support for Allwinner A83T CPU frequency scaling.
This commit is contained in:
parent
b3868b9f16
commit
b78c83e321
@ -47,8 +47,42 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/extres/clk/clk_mux.h>
|
||||
|
||||
#define CPU_CLK_SRC_SEL_WIDTH 2
|
||||
#define CPU_CLK_SRC_SEL_SHIFT 16
|
||||
#define A10_CPU_CLK_SRC_SEL_WIDTH 2
|
||||
#define A10_CPU_CLK_SRC_SEL_SHIFT 16
|
||||
|
||||
#define A83T_Cx_CLK_SRC_SEL_WIDTH 1
|
||||
#define A83T_C0_CLK_SRC_SEL_SHIFT 12
|
||||
#define A83T_C1_CLK_SRC_SEL_SHIFT 28
|
||||
|
||||
struct aw_cpuclk_config {
|
||||
u_int width;
|
||||
u_int shift;
|
||||
};
|
||||
|
||||
static struct aw_cpuclk_config a10_config = {
|
||||
.width = A10_CPU_CLK_SRC_SEL_WIDTH,
|
||||
.shift = A10_CPU_CLK_SRC_SEL_SHIFT,
|
||||
};
|
||||
|
||||
static struct aw_cpuclk_config a83t_c0_config = {
|
||||
.width = A83T_Cx_CLK_SRC_SEL_WIDTH,
|
||||
.shift = A83T_C0_CLK_SRC_SEL_SHIFT,
|
||||
};
|
||||
|
||||
static struct aw_cpuclk_config a83t_c1_config = {
|
||||
.width = A83T_Cx_CLK_SRC_SEL_WIDTH,
|
||||
.shift = A83T_C1_CLK_SRC_SEL_SHIFT,
|
||||
};
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{ "allwinner,sun4i-a10-cpu-clk", (uintptr_t)&a10_config },
|
||||
{ "allwinner,sun8i-a83t-c0cpu-clk", (uintptr_t)&a83t_c0_config },
|
||||
{ "allwinner,sun8i-a83t-c1cpu-clk", (uintptr_t)&a83t_c1_config },
|
||||
{ NULL, (uintptr_t)NULL }
|
||||
};
|
||||
|
||||
#define CPUCLK_CONF(d) \
|
||||
(void *)ofw_bus_search_compatible((d), compat_data)->ocd_data
|
||||
|
||||
static int
|
||||
aw_cpuclk_probe(device_t dev)
|
||||
@ -56,7 +90,7 @@ aw_cpuclk_probe(device_t dev)
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-cpu-clk"))
|
||||
if (CPUCLK_CONF(dev) == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Allwinner CPU Clock");
|
||||
@ -68,6 +102,7 @@ aw_cpuclk_attach(device_t dev)
|
||||
{
|
||||
struct clk_mux_def def;
|
||||
struct clkdom *clkdom;
|
||||
struct aw_cpuclk_config *conf;
|
||||
bus_addr_t paddr;
|
||||
bus_size_t psize;
|
||||
phandle_t node;
|
||||
@ -75,6 +110,7 @@ aw_cpuclk_attach(device_t dev)
|
||||
clk_t clk;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
conf = CPUCLK_CONF(dev);
|
||||
|
||||
if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
|
||||
device_printf(dev, "cannot parse 'reg' property\n");
|
||||
@ -105,8 +141,8 @@ aw_cpuclk_attach(device_t dev)
|
||||
}
|
||||
def.clkdef.parent_cnt = ncells;
|
||||
def.offset = paddr;
|
||||
def.shift = CPU_CLK_SRC_SEL_SHIFT;
|
||||
def.width = CPU_CLK_SRC_SEL_WIDTH;
|
||||
def.shift = conf->shift;
|
||||
def.width = conf->width;
|
||||
|
||||
error = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
|
||||
if (error != 0) {
|
||||
|
@ -157,6 +157,17 @@ __FBSDID("$FreeBSD$");
|
||||
#define A80_PLL4_FACTOR_N (0xff << 8)
|
||||
#define A80_PLL4_FACTOR_N_SHIFT 8
|
||||
|
||||
#define A83T_PLLCPUX_LOCK_TIME (0x7 << 24)
|
||||
#define A83T_PLLCPUX_LOCK_TIME_SHIFT 24
|
||||
#define A83T_PLLCPUX_CLOCK_OUTPUT_DIS (1 << 20)
|
||||
#define A83T_PLLCPUX_OUT_EXT_DIVP (1 << 16)
|
||||
#define A83T_PLLCPUX_FACTOR_N (0xff << 8)
|
||||
#define A83T_PLLCPUX_FACTOR_N_SHIFT 8
|
||||
#define A83T_PLLCPUX_FACTOR_N_MIN 12
|
||||
#define A83T_PLLCPUX_FACTOR_N_MAX 125
|
||||
#define A83T_PLLCPUX_POSTDIV_M (0x3 << 0)
|
||||
#define A83T_PLLCPUX_POSTDIV_M_SHIFT 0
|
||||
|
||||
#define CLKID_A10_PLL3_1X 0
|
||||
#define CLKID_A10_PLL3_2X 1
|
||||
|
||||
@ -202,6 +213,7 @@ enum aw_pll_type {
|
||||
AWPLL_A31_PLL6,
|
||||
AWPLL_A64_PLLHSIC,
|
||||
AWPLL_A80_PLL4,
|
||||
AWPLL_A83T_PLLCPUX,
|
||||
AWPLL_H3_PLL1,
|
||||
};
|
||||
|
||||
@ -824,6 +836,46 @@ a64_pllhsic_init(device_t dev, bus_addr_t reg, struct clknode_init_def *def)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
a83t_pllcpux_recalc(struct aw_pll_sc *sc, uint64_t *freq)
|
||||
{
|
||||
uint32_t val, n, p;
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
PLL_READ(sc, &val);
|
||||
DEVICE_UNLOCK(sc);
|
||||
|
||||
n = (val & A83T_PLLCPUX_FACTOR_N) >> A83T_PLLCPUX_FACTOR_N_SHIFT;
|
||||
p = (val & A83T_PLLCPUX_OUT_EXT_DIVP) ? 4 : 1;
|
||||
|
||||
*freq = (*freq * n) / p;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
a83t_pllcpux_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
|
||||
int flags)
|
||||
{
|
||||
uint32_t val;
|
||||
u_int n;
|
||||
|
||||
n = *fout / fin;
|
||||
|
||||
if (n < A83T_PLLCPUX_FACTOR_N_MIN || n > A83T_PLLCPUX_FACTOR_N_MAX)
|
||||
return (EINVAL);
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
PLL_READ(sc, &val);
|
||||
val &= ~A83T_PLLCPUX_FACTOR_N;
|
||||
val |= (n << A83T_PLLCPUX_FACTOR_N_SHIFT);
|
||||
val &= ~A83T_PLLCPUX_CLOCK_OUTPUT_DIS;
|
||||
PLL_WRITE(sc, val);
|
||||
DEVICE_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define PLL(_type, _recalc, _set_freq, _init) \
|
||||
[(_type)] = { \
|
||||
.recalc = (_recalc), \
|
||||
@ -842,6 +894,7 @@ static struct aw_pll_funcs aw_pll_func[] = {
|
||||
PLL(AWPLL_A31_PLL1, a31_pll1_recalc, NULL, NULL),
|
||||
PLL(AWPLL_A31_PLL6, a31_pll6_recalc, NULL, a31_pll6_init),
|
||||
PLL(AWPLL_A80_PLL4, a80_pll4_recalc, NULL, NULL),
|
||||
PLL(AWPLL_A83T_PLLCPUX, a83t_pllcpux_recalc, a83t_pllcpux_set_freq, NULL),
|
||||
PLL(AWPLL_A64_PLLHSIC, a64_pllhsic_recalc, NULL, a64_pllhsic_init),
|
||||
PLL(AWPLL_H3_PLL1, a23_pll1_recalc, h3_pll1_set_freq, NULL),
|
||||
};
|
||||
@ -856,6 +909,7 @@ static struct ofw_compat_data compat_data[] = {
|
||||
{ "allwinner,sun6i-a31-pll1-clk", AWPLL_A31_PLL1 },
|
||||
{ "allwinner,sun6i-a31-pll6-clk", AWPLL_A31_PLL6 },
|
||||
{ "allwinner,sun8i-a23-pll1-clk", AWPLL_A23_PLL1 },
|
||||
{ "allwinner,sun8i-a83t-pllcpux-clk", AWPLL_A83T_PLLCPUX },
|
||||
{ "allwinner,sun8i-h3-pll1-clk", AWPLL_H3_PLL1 },
|
||||
{ "allwinner,sun9i-a80-pll4-clk", AWPLL_A80_PLL4 },
|
||||
{ "allwinner,sun50i-a64-pllhsic-clk", AWPLL_A64_PLLHSIC },
|
||||
|
@ -27,6 +27,18 @@
|
||||
*/
|
||||
|
||||
/ {
|
||||
cpus {
|
||||
cpu@0 {
|
||||
clocks = <&c0_cpux_clk>;
|
||||
clock-latency = <2000000>;
|
||||
};
|
||||
|
||||
cpu@100 {
|
||||
clocks = <&c1_cpux_clk>;
|
||||
clock-latency = <2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
pmu {
|
||||
compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
|
||||
|
||||
@ -38,6 +50,38 @@
|
||||
};
|
||||
|
||||
clocks {
|
||||
pll_c0cpux: clk@01c20000 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a83t-pllcpux-clk";
|
||||
reg = <0x01c20000 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
clock-output-names = "pll_c0cpux";
|
||||
};
|
||||
|
||||
pll_c1cpux: clk@01c20004 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a83t-pllcpux-clk";
|
||||
reg = <0x01c20004 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
clock-output-names = "pll_c1cpux";
|
||||
};
|
||||
|
||||
c0_cpux_clk: c0clk@01c20050 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a83t-c0cpu-clk";
|
||||
reg = <0x01c20050 0x4>;
|
||||
clocks = <&osc24M>, <&pll_c0cpux>;
|
||||
clock-output-names = "c0_cpux";
|
||||
};
|
||||
|
||||
c1_cpux_clk: c1clk@01c20050 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a83t-c1cpu-clk";
|
||||
reg = <0x01c20050 0x4>;
|
||||
clocks = <&osc24M>, <&pll_c1cpux>;
|
||||
clock-output-names = "c1_cpux";
|
||||
};
|
||||
|
||||
/* cpus_clk compatible in gnu dt is incorrect */
|
||||
cpus_clk: clk@01f01400 {
|
||||
compatible = "allwinner,sun8i-a83t-cpus-clk";
|
||||
|
@ -29,6 +29,32 @@
|
||||
#include "sun8i-a83t-sinovoip-bpi-m3.dts"
|
||||
#include "a83t.dtsi"
|
||||
|
||||
/ {
|
||||
cpus {
|
||||
cpu@0 {
|
||||
cpu-supply = <®_dcdc2>;
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
1200000 840000
|
||||
1008000 840000
|
||||
648000 840000
|
||||
408000 840000
|
||||
>;
|
||||
};
|
||||
|
||||
cpu@100 {
|
||||
cpu-supply = <®_dcdc3>;
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
1200000 840000
|
||||
1008000 840000
|
||||
648000 840000
|
||||
408000 840000
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ehci0 {
|
||||
status = "okay";
|
||||
};
|
||||
@ -115,6 +141,16 @@
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <1>;
|
||||
|
||||
regulators {
|
||||
reg_dcdc2: dcdc2 {
|
||||
regulator-name = "dcdc2";
|
||||
};
|
||||
|
||||
reg_dcdc3: dcdc3 {
|
||||
regulator-name = "dcdc3";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user