Add support for Allwinner A83T CPU frequency scaling.

This commit is contained in:
Jared McNeill 2016-09-07 01:10:16 +00:00
parent b3868b9f16
commit b78c83e321
4 changed files with 175 additions and 5 deletions

View File

@ -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) {

View File

@ -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 },

View File

@ -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";

View File

@ -29,6 +29,32 @@
#include "sun8i-a83t-sinovoip-bpi-m3.dts"
#include "a83t.dtsi"
/ {
cpus {
cpu@0 {
cpu-supply = <&reg_dcdc2>;
operating-points = <
/* kHz uV */
1200000 840000
1008000 840000
648000 840000
408000 840000
>;
};
cpu@100 {
cpu-supply = <&reg_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";
};
};
};
};