mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
cpufreq: enable scpi cpufreq
PD#138714: add scpi_cpufreq Change-Id: Iaf90f7573657593f21200fed48209a2758fa189a Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
This commit is contained in:
@@ -13481,3 +13481,7 @@ F: include/linux/amlogic/usb-gxbbtv.h
|
||||
F: include/linux/amlogic/usb-gxl.h
|
||||
F: include/linux/amlogic/usb-gxbb.h
|
||||
F: include/linux/amlogic/usbtype.h
|
||||
|
||||
AMLOGIC scpi cpufreq
|
||||
M: jianxin.pan <jianxin.pan@amlogic.com>
|
||||
F: drivers/amlogic/clk/clk-scpi.c
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -53,6 +55,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
CPU2:cpu@2 {
|
||||
@@ -60,6 +64,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x2>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -68,6 +74,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x3>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -174,13 +182,25 @@
|
||||
compatible = "amlogic, meson_mhu";
|
||||
reg = <0x0 0xc883c400 0x0 0x4c>, /* MHU registers */
|
||||
<0x0 0xc8013000 0x0 0x800>; /* Payload area */
|
||||
interrupts = <0 209 8>, /* low priority interrupt */
|
||||
<0 210 8>; /* high priority interrupt */
|
||||
interrupts = <0 209 1>, /* low priority interrupt */
|
||||
<0 210 1>; /* high priority interrupt */
|
||||
#mbox-cells = <1>;
|
||||
mbox-names = "cpu_to_scp_low", "cpu_to_scp_high";
|
||||
mboxes = <&mailbox 0 &mailbox 1>;
|
||||
};
|
||||
|
||||
scpi_clocks {
|
||||
compatible = "arm, scpi-clks";
|
||||
|
||||
scpi_dvfs: scpi_clocks@0 {
|
||||
compatible = "arm, scpi-clk-indexed";
|
||||
#clock-cells = <1>;
|
||||
clock-indices = <0>;
|
||||
clock-output-names = "vcpu";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
xtal: xtal-clk {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
@@ -358,7 +378,6 @@
|
||||
"jtag_clk_0",
|
||||
"jtag_tms_0";
|
||||
function = "jtag";
|
||||
bias-pull-down;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -68,6 +70,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
CPU2:cpu@2 {
|
||||
@@ -75,6 +79,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x2>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -83,6 +89,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x3>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 0>;
|
||||
clock-names = "cpu-cluster.0";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -91,6 +99,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 1>;
|
||||
clock-names = "cpu-cluster.1";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -99,6 +109,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 1>;
|
||||
clock-names = "cpu-cluster.1";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
CPU6:cpu@102 {
|
||||
@@ -106,6 +118,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x102>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 1>;
|
||||
clock-names = "cpu-cluster.1";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -114,6 +128,8 @@
|
||||
compatible = "arm,cortex-a53","arm,armv8";
|
||||
reg = <0x0 0x103>;
|
||||
enable-method = "psci";
|
||||
clocks = <&scpi_dvfs 1>;
|
||||
clock-names = "cpu-cluster.1";
|
||||
cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
|
||||
};
|
||||
|
||||
@@ -226,6 +242,17 @@
|
||||
mboxes = <&mailbox 0 &mailbox 1>;
|
||||
};
|
||||
|
||||
scpi_clocks {
|
||||
compatible = "arm, scpi-clks";
|
||||
|
||||
scpi_dvfs: scpi_clocks@0 {
|
||||
compatible = "arm, scpi-clk-indexed";
|
||||
#clock-cells = <1>;
|
||||
clock-indices = <0 1>;
|
||||
clock-output-names = "vbig", "vlittle";
|
||||
};
|
||||
|
||||
};
|
||||
xtal: xtal-clk {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
@@ -403,7 +430,6 @@
|
||||
"jtag_clk_0",
|
||||
"jtag_tms_0";
|
||||
function = "jtag";
|
||||
bias-pull-down;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ CONFIG_COMPAT=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
|
||||
CONFIG_ARM_SCPI_CPUFREQ=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_PACKET_DIAG=y
|
||||
@@ -173,6 +174,7 @@ CONFIG_AMLOGIC_REG_ACCESS=y
|
||||
CONFIG_AMLOGIC_TIMER=y
|
||||
CONFIG_AMLOGIC_BC_TIMER=y
|
||||
CONFIG_AMLOGIC_CLK=y
|
||||
CONFIG_AMLOGIC_COMMON_CLK_SCPI=y
|
||||
CONFIG_AMLOGIC_CRYPTO=y
|
||||
CONFIG_AMLOGIC_INPUT=y
|
||||
CONFIG_AMLOGIC_INPUT_KEYBOARD=y
|
||||
|
||||
@@ -13,3 +13,13 @@ config AMLOGIC_RESET
|
||||
default AMLOGIC_CLK
|
||||
help
|
||||
This enables the reset driver for Amlogic Meson SoCs.
|
||||
|
||||
config AMLOGIC_COMMON_CLK_SCPI
|
||||
tristate "Clock driver controlled via SCPI interface"
|
||||
depends on ARM_SCPI_PROTOCOL || COMPILE_TEST
|
||||
---help---
|
||||
This driver provides support for clocks that are controlled
|
||||
by firmware that implements the SCPI interface.
|
||||
|
||||
This driver uses SCPI Message Protocol to interact with the
|
||||
firmware providing all the clock controls.
|
||||
@@ -2,6 +2,7 @@
|
||||
# Makefile for Meson specific clk
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_COMMON_CLK_SCPI) += clk-scpi.o
|
||||
obj-$(CONFIG_AMLOGIC_RESET) += rstc.o
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_CLK) += clk-pll.o clk-cpu.o clk-mpll.o \
|
||||
|
||||
314
drivers/amlogic/clk/clk-scpi.c
Normal file
314
drivers/amlogic/clk/clk-scpi.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* drivers/amlogic/clk/clk-scpi.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* 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/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
|
||||
|
||||
struct scpi_clk {
|
||||
u32 id;
|
||||
const char *name;
|
||||
struct clk_hw hw;
|
||||
struct scpi_dvfs_info *opps;
|
||||
unsigned long rate_min;
|
||||
unsigned long rate_max;
|
||||
};
|
||||
|
||||
static struct platform_device *cpufreq_dev;
|
||||
#define to_scpi_clk(clk) container_of(clk, struct scpi_clk, hw)
|
||||
|
||||
static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
|
||||
return scpi_clk_get_val(clk->id);
|
||||
}
|
||||
|
||||
static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
|
||||
if (clk->rate_min && rate < clk->rate_min)
|
||||
rate = clk->rate_min;
|
||||
if (clk->rate_max && rate > clk->rate_max)
|
||||
rate = clk->rate_max;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
|
||||
return scpi_clk_set_val(clk->id, rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops scpi_clk_ops = {
|
||||
.recalc_rate = scpi_clk_recalc_rate,
|
||||
.round_rate = scpi_clk_round_rate,
|
||||
.set_rate = scpi_clk_set_rate,
|
||||
};
|
||||
|
||||
/* find closest match to given frequency in OPP table */
|
||||
static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
|
||||
{
|
||||
int idx, max_opp = clk->opps->count;
|
||||
struct scpi_opp_entry *opp = clk->opps->opp;
|
||||
u32 fmin = 0, fmax = ~0, ftmp;
|
||||
|
||||
for (idx = 0; idx < max_opp; idx++, opp++) {
|
||||
ftmp = opp->freq_hz;
|
||||
if (ftmp >= (u32)rate) {
|
||||
if (ftmp <= fmax)
|
||||
fmax = ftmp;
|
||||
} else {
|
||||
if (ftmp >= fmin)
|
||||
fmin = ftmp;
|
||||
}
|
||||
}
|
||||
if (fmax != ~0)
|
||||
return fmax;
|
||||
else
|
||||
return fmin;
|
||||
}
|
||||
|
||||
static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
int idx = scpi_dvfs_get_idx(clk->id);
|
||||
struct scpi_opp_entry *opp = clk->opps->opp;
|
||||
|
||||
if (idx < 0)
|
||||
return 0;
|
||||
else
|
||||
return opp[idx].freq_hz;
|
||||
}
|
||||
|
||||
static long scpi_dvfs_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
|
||||
return __scpi_dvfs_round_rate(clk, rate);
|
||||
}
|
||||
|
||||
static int __scpi_find_dvfs_index(struct scpi_clk *clk, unsigned long rate)
|
||||
{
|
||||
int idx, max_opp = clk->opps->count;
|
||||
struct scpi_opp_entry *opp = clk->opps->opp;
|
||||
|
||||
for (idx = 0; idx < max_opp; idx++, opp++)
|
||||
if (opp->freq_hz == (u32)rate)
|
||||
break;
|
||||
return (idx == max_opp) ? -EINVAL : idx;
|
||||
}
|
||||
|
||||
static int scpi_dvfs_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
int ret = __scpi_find_dvfs_index(clk, rate);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return scpi_dvfs_set_idx(clk->id, (u8)ret);
|
||||
}
|
||||
|
||||
static const struct clk_ops scpi_dvfs_ops = {
|
||||
.recalc_rate = scpi_dvfs_recalc_rate,
|
||||
.round_rate = scpi_dvfs_round_rate,
|
||||
.set_rate = scpi_dvfs_set_rate,
|
||||
};
|
||||
|
||||
static struct clk *
|
||||
scpi_dvfs_ops_init(struct device *dev, struct device_node *np,
|
||||
struct scpi_clk *sclk)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct scpi_dvfs_info *opps;
|
||||
|
||||
init.name = sclk->name;
|
||||
init.flags = 0;
|
||||
init.num_parents = 0;
|
||||
init.ops = &scpi_dvfs_ops;
|
||||
sclk->hw.init = &init;
|
||||
|
||||
opps = scpi_dvfs_get_opps(sclk->id);
|
||||
if (IS_ERR(opps))
|
||||
return (struct clk *)opps;
|
||||
|
||||
sclk->opps = opps;
|
||||
|
||||
return devm_clk_register(dev, &sclk->hw);
|
||||
}
|
||||
|
||||
static struct clk *
|
||||
scpi_clk_ops_init(struct device *dev, struct device_node *np,
|
||||
struct scpi_clk *sclk)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
u32 range[2];
|
||||
int ret;
|
||||
|
||||
init.name = sclk->name;
|
||||
init.flags = 0;
|
||||
init.num_parents = 0;
|
||||
init.ops = &scpi_clk_ops;
|
||||
sclk->hw.init = &init;
|
||||
|
||||
ret = of_property_read_u32_array(np, "frequency-range", range,
|
||||
ARRAY_SIZE(range));
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
sclk->rate_min = range[0];
|
||||
sclk->rate_max = range[1];
|
||||
|
||||
return devm_clk_register(dev, &sclk->hw);
|
||||
}
|
||||
|
||||
static int scpi_clk_setup(struct device *dev, struct device_node *np,
|
||||
const void *data)
|
||||
{
|
||||
struct clk * (*setup_ops)(struct device *, struct device_node *,
|
||||
struct scpi_clk *) = data;
|
||||
struct clk_onecell_data *clk_data;
|
||||
struct clk **clks;
|
||||
size_t count;
|
||||
int idx;
|
||||
|
||||
count = of_property_count_strings(np, "clock-output-names");
|
||||
if (count < 0) {
|
||||
dev_err(dev, "%s: invalid clock output count\n", np->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_data = devm_kmalloc(dev, sizeof(*clk_data), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clks = devm_kmalloc(dev, count * sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
struct scpi_clk *sclk;
|
||||
u32 val;
|
||||
|
||||
sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
|
||||
if (!sclk)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_string_index(np, "clock-output-names",
|
||||
idx, &sclk->name)) {
|
||||
dev_err(dev, "invalid clock name @ %s\n", np->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_index(np, "clock-indices",
|
||||
idx, &val)) {
|
||||
dev_err(dev, "invalid clock index @ %s\n", np->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sclk->id = val;
|
||||
|
||||
clks[idx] = setup_ops(dev, np, sclk);
|
||||
if (IS_ERR(clks[idx])) {
|
||||
dev_err(dev, "failed to register clock '%s'\n",
|
||||
sclk->name);
|
||||
return PTR_ERR(clks[idx]);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Registered clock '%s'\n", sclk->name);
|
||||
}
|
||||
|
||||
clk_data->clks = clks;
|
||||
clk_data->clk_num = count;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id clk_match[] = {
|
||||
{ .compatible = "arm, scpi-clk-indexed", .data = scpi_dvfs_ops_init, },
|
||||
{ .compatible = "arm, scpi-clk-range", .data = &scpi_clk_ops_init, },
|
||||
{}
|
||||
};
|
||||
|
||||
static int scpi_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node, *child;
|
||||
const struct of_device_id *match;
|
||||
int ret;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
match = of_match_node(clk_match, child);
|
||||
if (!match)
|
||||
continue;
|
||||
ret = scpi_clk_setup(dev, child, match->data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* Add the virtual cpufreq device */
|
||||
cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
|
||||
-1, NULL, 0);
|
||||
if (!cpufreq_dev)
|
||||
pr_warn("unable to register cpufreq device");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id scpi_clk_ids[] = {
|
||||
{ .compatible = "arm, scpi-clks", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver scpi_clk_driver = {
|
||||
.driver = {
|
||||
.name = "aml_scpi_clocks",
|
||||
.of_match_table = scpi_clk_ids,
|
||||
},
|
||||
.probe = scpi_clk_probe,
|
||||
};
|
||||
|
||||
static int __init scpi_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&scpi_clk_driver);
|
||||
}
|
||||
postcore_initcall(scpi_clk_init);
|
||||
|
||||
static void __exit scpi_clk_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&scpi_clk_driver);
|
||||
}
|
||||
module_exit(scpi_clk_exit);
|
||||
|
||||
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
|
||||
MODULE_DESCRIPTION("ARM SCPI clock driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -195,7 +195,7 @@ config ARM_SA1110_CPUFREQ
|
||||
|
||||
config ARM_SCPI_CPUFREQ
|
||||
tristate "SCPI based CPUfreq driver"
|
||||
depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
|
||||
depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && (COMMON_CLK_SCPI || AMLOGIC_COMMON_CLK_SCPI)
|
||||
help
|
||||
This adds the CPUfreq driver support for ARM big.LITTLE platforms
|
||||
using SCPI protocol for CPU power management.
|
||||
|
||||
@@ -134,7 +134,14 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
|
||||
int ret;
|
||||
bool bLs = is_bL_switching_enabled();
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI
|
||||
/* MARK: cluster0 and cluster share the same scpi lock,
|
||||
* and don't send scpi command at the same time
|
||||
*/
|
||||
mutex_lock(&cluster_lock[0]);
|
||||
#else
|
||||
mutex_lock(&cluster_lock[new_cluster]);
|
||||
#endif
|
||||
|
||||
if (bLs) {
|
||||
prev_rate = per_cpu(cpu_last_req_freq, cpu);
|
||||
@@ -172,12 +179,20 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
|
||||
per_cpu(physical_cluster, cpu) = old_cluster;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI
|
||||
mutex_unlock(&cluster_lock[0]);
|
||||
#else
|
||||
mutex_unlock(&cluster_lock[new_cluster]);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI
|
||||
mutex_unlock(&cluster_lock[0]);
|
||||
#else
|
||||
mutex_unlock(&cluster_lock[new_cluster]);
|
||||
#endif
|
||||
|
||||
/* Recalc freq for old cluster when switching clusters */
|
||||
if (old_cluster != new_cluster) {
|
||||
@@ -187,7 +202,11 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
|
||||
/* Switch cluster */
|
||||
bL_switch_request(cpu, new_cluster);
|
||||
|
||||
mutex_lock(&cluster_lock[old_cluster]);
|
||||
#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI
|
||||
mutex_lock(&cluster_lock[0]);
|
||||
#else
|
||||
mutex_lock(&cluster_lock[new_cluster]);
|
||||
#endif
|
||||
|
||||
/* Set freq of old cluster if there are cpus left on it */
|
||||
new_rate = find_cluster_maxfreq(old_cluster);
|
||||
@@ -201,7 +220,11 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
|
||||
pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n",
|
||||
__func__, ret, old_cluster);
|
||||
}
|
||||
mutex_unlock(&cluster_lock[old_cluster]);
|
||||
#ifdef CONFIG_AMLOGIC_COMMON_CLK_SCPI
|
||||
mutex_unlock(&cluster_lock[0]);
|
||||
#else
|
||||
mutex_unlock(&cluster_lock[new_cluster]);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "arm_big_little.h"
|
||||
|
||||
static struct scpi_ops *scpi_ops;
|
||||
struct scpi_dvfs_info *scpi_dvfs_get_opps(u8 domain);
|
||||
|
||||
static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
|
||||
{
|
||||
@@ -36,7 +37,12 @@ static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
|
||||
|
||||
if (domain < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return scpi_ops->dvfs_get_info(domain);
|
||||
|
||||
/* TODO: Use API from 3.14 temporary.
|
||||
* When 4.4 arm_mhu and arm_scpi is ported,
|
||||
* tihs will be replaced by: return scpi_ops->dvfs_get_info(domain);
|
||||
*/
|
||||
return scpi_dvfs_get_opps(domain);
|
||||
}
|
||||
|
||||
static int scpi_get_transition_latency(struct device *cpu_dev)
|
||||
@@ -88,9 +94,12 @@ static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
|
||||
|
||||
static int scpi_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
scpi_ops = get_scpi_ops();
|
||||
if (!scpi_ops)
|
||||
return -EIO;
|
||||
/* TODO: TODO: Use API from 3.14 temporary.
|
||||
* When 4.4 arm_mhu and arm_scpi is ported, these lines should be added:
|
||||
* scpi_ops = get_scpi_ops();
|
||||
* if (!scpi_ops)
|
||||
* return -EIO;
|
||||
*/
|
||||
|
||||
return bL_cpufreq_register(&scpi_cpufreq_ops);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user