Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 8c83977..ec738f7 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -1,4 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
+
+config CLK_BCM2711_DVP
+ tristate "Broadcom BCM2711 DVP support"
+ depends on ARCH_BCM2835 ||COMPILE_TEST
+ depends on COMMON_CLK
+ default ARCH_BCM2835
+ select RESET_CONTROLLER
+ select RESET_SIMPLE
+ help
+ Enable common clock framework support for the Broadcom BCM2711
+ DVP Controller.
+
config CLK_BCM2835
bool "Broadcom BCM2835 clock support"
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 0070ddf..edb66b4 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+obj-$(CONFIG_CLK_BCM2711_DVP) += clk-bcm2711-dvp.o
obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o
obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c
new file mode 100644
index 0000000..69e2f85
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm2711-dvp.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2020 Cerno
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reset/reset-simple.h>
+
+#define DVP_HT_RPI_SW_INIT 0x04
+#define DVP_HT_RPI_MISC_CONFIG 0x08
+
+#define NR_CLOCKS 2
+#define NR_RESETS 6
+
+struct clk_dvp {
+ struct clk_hw_onecell_data *data;
+ struct reset_simple_data reset;
+};
+
+static const struct clk_parent_data clk_dvp_parent = {
+ .index = 0,
+};
+
+static int clk_dvp_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *data;
+ struct resource *res;
+ struct clk_dvp *dvp;
+ void __iomem *base;
+ int ret;
+
+ dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
+ if (!dvp)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, dvp);
+
+ dvp->data = devm_kzalloc(&pdev->dev,
+ struct_size(dvp->data, hws, NR_CLOCKS),
+ GFP_KERNEL);
+ if (!dvp->data)
+ return -ENOMEM;
+ data = dvp->data;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ dvp->reset.rcdev.owner = THIS_MODULE;
+ dvp->reset.rcdev.nr_resets = NR_RESETS;
+ dvp->reset.rcdev.ops = &reset_simple_ops;
+ dvp->reset.rcdev.of_node = pdev->dev.of_node;
+ dvp->reset.membase = base + DVP_HT_RPI_SW_INIT;
+ spin_lock_init(&dvp->reset.lock);
+
+ ret = devm_reset_controller_register(&pdev->dev, &dvp->reset.rcdev);
+ if (ret)
+ return ret;
+
+ data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev,
+ "hdmi0-108MHz",
+ &clk_dvp_parent, 0,
+ base + DVP_HT_RPI_MISC_CONFIG, 3,
+ CLK_GATE_SET_TO_DISABLE,
+ &dvp->reset.lock);
+ if (IS_ERR(data->hws[0]))
+ return PTR_ERR(data->hws[0]);
+
+ data->hws[1] = clk_hw_register_gate_parent_data(&pdev->dev,
+ "hdmi1-108MHz",
+ &clk_dvp_parent, 0,
+ base + DVP_HT_RPI_MISC_CONFIG, 4,
+ CLK_GATE_SET_TO_DISABLE,
+ &dvp->reset.lock);
+ if (IS_ERR(data->hws[1])) {
+ ret = PTR_ERR(data->hws[1]);
+ goto unregister_clk0;
+ }
+
+ data->num = NR_CLOCKS;
+ ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+ data);
+ if (ret)
+ goto unregister_clk1;
+
+ return 0;
+
+unregister_clk1:
+ clk_hw_unregister_gate(data->hws[1]);
+
+unregister_clk0:
+ clk_hw_unregister_gate(data->hws[0]);
+ return ret;
+};
+
+static int clk_dvp_remove(struct platform_device *pdev)
+{
+ struct clk_dvp *dvp = platform_get_drvdata(pdev);
+ struct clk_hw_onecell_data *data = dvp->data;
+
+ clk_hw_unregister_gate(data->hws[1]);
+ clk_hw_unregister_gate(data->hws[0]);
+
+ return 0;
+}
+
+static const struct of_device_id clk_dvp_dt_ids[] = {
+ { .compatible = "brcm,brcm2711-dvp", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids);
+
+static struct platform_driver clk_dvp_driver = {
+ .probe = clk_dvp_probe,
+ .remove = clk_dvp_remove,
+ .driver = {
+ .name = "brcm2711-dvp",
+ .of_match_table = clk_dvp_dt_ids,
+ },
+};
+module_platform_driver(clk_dvp_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_DESCRIPTION("BCM2711 DVP clock driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c
index b6d07ca..290a284 100644
--- a/drivers/clk/bcm/clk-bcm2835-aux.c
+++ b/drivers/clk/bcm/clk-bcm2835-aux.c
@@ -19,7 +19,6 @@
struct clk_hw_onecell_data *onecell;
const char *parent;
struct clk *parent_clk;
- struct resource *res;
void __iomem *reg, *gate;
parent_clk = devm_clk_get(dev, NULL);
@@ -27,8 +26,7 @@
return PTR_ERR(parent_clk);
parent = __clk_get_name(parent_clk);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- reg = devm_ioremap_resource(dev, res);
+ reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(reg))
return PTR_ERR(reg);
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index c548653..1788868 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -397,8 +397,8 @@
}
static void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
- struct debugfs_reg32 *regs, size_t nregs,
- struct dentry *dentry)
+ const struct debugfs_reg32 *regs,
+ size_t nregs, struct dentry *dentry)
{
struct debugfs_regset32 *regset;
@@ -422,6 +422,7 @@
u32 reference_enable_mask;
/* Bit in CM_LOCK to indicate when the PLL has locked. */
u32 lock_mask;
+ u32 flags;
const struct bcm2835_pll_ana_bits *ana;
@@ -932,8 +933,7 @@
static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
- unsigned long parent_rate,
- bool round_up)
+ unsigned long parent_rate)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
@@ -945,10 +945,6 @@
rem = do_div(temp, rate);
div = temp;
-
- /* Round up and mask off the unused bits */
- if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
- div += unused_frac_mask + 1;
div &= ~unused_frac_mask;
/* different clamping limits apply for a mash clock */
@@ -1079,7 +1075,7 @@
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
- u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
+ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
u32 ctl;
spin_lock(&cprman->regs_lock);
@@ -1130,7 +1126,7 @@
if (!(BIT(parent_idx) & data->set_rate_parent)) {
*prate = clk_hw_get_rate(parent);
- *div = bcm2835_clock_choose_div(hw, rate, *prate, true);
+ *div = bcm2835_clock_choose_div(hw, rate, *prate);
*avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div);
@@ -1216,7 +1212,7 @@
rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate,
&div, &prate,
&avgrate);
- if (rate > best_rate && rate <= req->rate) {
+ if (abs(req->rate - rate) < abs(req->rate - best_rate)) {
best_parent = parent;
best_prate = prate;
best_rate = rate;
@@ -1256,7 +1252,7 @@
return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
}
-static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
+static const struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
{
.name = "ctl",
.offset = 0,
@@ -1312,8 +1308,9 @@
};
static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
- const struct bcm2835_pll_data *data)
+ const void *data)
{
+ const struct bcm2835_pll_data *pll_data = data;
struct bcm2835_pll *pll;
struct clk_init_data init;
int ret;
@@ -1323,16 +1320,16 @@
/* All of the PLLs derive from the external oscillator. */
init.parent_names = &cprman->real_parent_names[0];
init.num_parents = 1;
- init.name = data->name;
+ init.name = pll_data->name;
init.ops = &bcm2835_pll_clk_ops;
- init.flags = CLK_IGNORE_UNUSED;
+ init.flags = pll_data->flags | CLK_IGNORE_UNUSED;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return NULL;
pll->cprman = cprman;
- pll->data = data;
+ pll->data = pll_data;
pll->hw.init = &init;
ret = devm_clk_hw_register(cprman->dev, &pll->hw);
@@ -1345,35 +1342,36 @@
static struct clk_hw *
bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
- const struct bcm2835_pll_divider_data *data)
+ const void *data)
{
+ const struct bcm2835_pll_divider_data *divider_data = data;
struct bcm2835_pll_divider *divider;
struct clk_init_data init;
const char *divider_name;
int ret;
- if (data->fixed_divider != 1) {
+ if (divider_data->fixed_divider != 1) {
divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL,
- "%s_prediv", data->name);
+ "%s_prediv", divider_data->name);
if (!divider_name)
return NULL;
} else {
- divider_name = data->name;
+ divider_name = divider_data->name;
}
memset(&init, 0, sizeof(init));
- init.parent_names = &data->source_pll;
+ init.parent_names = ÷r_data->source_pll;
init.num_parents = 1;
init.name = divider_name;
init.ops = &bcm2835_pll_divider_clk_ops;
- init.flags = data->flags | CLK_IGNORE_UNUSED;
+ init.flags = divider_data->flags | CLK_IGNORE_UNUSED;
divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL);
if (!divider)
return NULL;
- divider->div.reg = cprman->regs + data->a2w_reg;
+ divider->div.reg = cprman->regs + divider_data->a2w_reg;
divider->div.shift = A2W_PLL_DIV_SHIFT;
divider->div.width = A2W_PLL_DIV_BITS;
divider->div.flags = CLK_DIVIDER_MAX_AT_ZERO;
@@ -1382,7 +1380,7 @@
divider->div.table = NULL;
divider->cprman = cprman;
- divider->data = data;
+ divider->data = divider_data;
ret = devm_clk_hw_register(cprman->dev, ÷r->div.hw);
if (ret)
@@ -1392,20 +1390,22 @@
* PLLH's channels have a fixed divide by 10 afterwards, which
* is what our consumers are actually using.
*/
- if (data->fixed_divider != 1) {
- return clk_hw_register_fixed_factor(cprman->dev, data->name,
+ if (divider_data->fixed_divider != 1) {
+ return clk_hw_register_fixed_factor(cprman->dev,
+ divider_data->name,
divider_name,
CLK_SET_RATE_PARENT,
1,
- data->fixed_divider);
+ divider_data->fixed_divider);
}
return ÷r->div.hw;
}
static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
- const struct bcm2835_clock_data *data)
+ const void *data)
{
+ const struct bcm2835_clock_data *clock_data = data;
struct bcm2835_clock *clock;
struct clk_init_data init;
const char *parents[1 << CM_SRC_BITS];
@@ -1416,8 +1416,8 @@
* Replace our strings referencing parent clocks with the
* actual clock-output-name of the parent.
*/
- for (i = 0; i < data->num_mux_parents; i++) {
- parents[i] = data->parents[i];
+ for (i = 0; i < clock_data->num_mux_parents; i++) {
+ parents[i] = clock_data->parents[i];
ret = match_string(cprman_parent_names,
ARRAY_SIZE(cprman_parent_names),
@@ -1428,18 +1428,18 @@
memset(&init, 0, sizeof(init));
init.parent_names = parents;
- init.num_parents = data->num_mux_parents;
- init.name = data->name;
- init.flags = data->flags | CLK_IGNORE_UNUSED;
+ init.num_parents = clock_data->num_mux_parents;
+ init.name = clock_data->name;
+ init.flags = clock_data->flags | CLK_IGNORE_UNUSED;
/*
* Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
* rate changes on at least of the parents.
*/
- if (data->set_rate_parent)
+ if (clock_data->set_rate_parent)
init.flags |= CLK_SET_RATE_PARENT;
- if (data->is_vpu_clock) {
+ if (clock_data->is_vpu_clock) {
init.ops = &bcm2835_vpu_clock_clk_ops;
} else {
init.ops = &bcm2835_clock_clk_ops;
@@ -1448,7 +1448,7 @@
/* If the clock wasn't actually enabled at boot, it's not
* critical.
*/
- if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
+ if (!(cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE))
init.flags &= ~CLK_IS_CRITICAL;
}
@@ -1457,7 +1457,7 @@
return NULL;
clock->cprman = cprman;
- clock->data = data;
+ clock->data = clock_data;
clock->hw.init = &init;
ret = devm_clk_hw_register(cprman->dev, &clock->hw);
@@ -1467,24 +1467,26 @@
}
static struct clk_hw *bcm2835_register_gate(struct bcm2835_cprman *cprman,
- const struct bcm2835_gate_data *data)
+ const void *data)
{
- return clk_hw_register_gate(cprman->dev, data->name, data->parent,
+ const struct bcm2835_gate_data *gate_data = data;
+
+ return clk_hw_register_gate(cprman->dev, gate_data->name,
+ gate_data->parent,
CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
- cprman->regs + data->ctl_reg,
+ cprman->regs + gate_data->ctl_reg,
CM_GATE_BIT, 0, &cprman->regs_lock);
}
-typedef struct clk_hw *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
- const void *data);
struct bcm2835_clk_desc {
- bcm2835_clk_register clk_register;
+ struct clk_hw *(*clk_register)(struct bcm2835_cprman *cprman,
+ const void *data);
unsigned int supported;
const void *data;
};
/* assignment helper macros for different clock types */
-#define _REGISTER(f, s, ...) { .clk_register = (bcm2835_clk_register)f, \
+#define _REGISTER(f, s, ...) { .clk_register = f, \
.supported = s, \
.data = __VA_ARGS__ }
#define REGISTER_PLL(s, ...) _REGISTER(&bcm2835_register_pll, \
@@ -1696,10 +1698,33 @@
.fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT),
- /*
- * PLLB is used for the ARM's clock. Controlled by firmware, see
- * clk-raspberrypi.c.
- */
+ /* PLLB is used for the ARM's clock. */
+ [BCM2835_PLLB] = REGISTER_PLL(
+ SOC_ALL,
+ .name = "pllb",
+ .cm_ctrl_reg = CM_PLLB,
+ .a2w_ctrl_reg = A2W_PLLB_CTRL,
+ .frac_reg = A2W_PLLB_FRAC,
+ .ana_reg_base = A2W_PLLB_ANA0,
+ .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
+ .lock_mask = CM_LOCK_FLOCKB,
+
+ .ana = &bcm2835_ana_default,
+
+ .min_rate = 600000000u,
+ .max_rate = 3000000000u,
+ .max_fb_rate = BCM2835_MAX_FB_RATE,
+ .flags = CLK_GET_RATE_NOCACHE),
+ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
+ SOC_ALL,
+ .name = "pllb_arm",
+ .source_pll = "pllb",
+ .cm_reg = CM_PLLB,
+ .a2w_reg = A2W_PLLB_ARM,
+ .load_mask = CM_PLLB_LOADARM,
+ .hold_mask = CM_PLLB_HOLDARM,
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE),
/*
* PLLC is the core PLL, used to drive the core VPU clock.
@@ -2210,7 +2235,6 @@
struct device *dev = &pdev->dev;
struct clk_hw **hws;
struct bcm2835_cprman *cprman;
- struct resource *res;
const struct bcm2835_clk_desc *desc;
const size_t asize = ARRAY_SIZE(clk_desc_array);
const struct cprman_plat_data *pdata;
@@ -2229,8 +2253,7 @@
spin_lock_init(&cprman->regs_lock);
cprman->dev = dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- cprman->regs = devm_ioremap_resource(dev, res);
+ cprman->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(cprman->regs))
return PTR_ERR(cprman->regs);
diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c
index 911a29b..89297c5 100644
--- a/drivers/clk/bcm/clk-bcm63xx-gate.c
+++ b/drivers/clk/bcm/clk-bcm63xx-gate.c
@@ -6,6 +6,14 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <dt-bindings/clock/bcm3368-clock.h>
+#include <dt-bindings/clock/bcm6318-clock.h>
+#include <dt-bindings/clock/bcm6328-clock.h>
+#include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/clock/bcm6362-clock.h>
+#include <dt-bindings/clock/bcm6368-clock.h>
+#include <dt-bindings/clock/bcm63268-clock.h>
+
struct clk_bcm63xx_table_entry {
const char * const name;
u8 bit;
@@ -20,126 +28,458 @@
};
static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
- { .name = "mac", .bit = 3, },
- { .name = "tc", .bit = 5, },
- { .name = "us_top", .bit = 6, },
- { .name = "ds_top", .bit = 7, },
- { .name = "acm", .bit = 8, },
- { .name = "spi", .bit = 9, },
- { .name = "usbs", .bit = 10, },
- { .name = "bmu", .bit = 11, },
- { .name = "pcm", .bit = 12, },
- { .name = "ntp", .bit = 13, },
- { .name = "acp_b", .bit = 14, },
- { .name = "acp_a", .bit = 15, },
- { .name = "emusb", .bit = 17, },
- { .name = "enet0", .bit = 18, },
- { .name = "enet1", .bit = 19, },
- { .name = "usbsu", .bit = 20, },
- { .name = "ephy", .bit = 21, },
- { },
+ {
+ .name = "mac",
+ .bit = BCM3368_CLK_MAC,
+ }, {
+ .name = "tc",
+ .bit = BCM3368_CLK_TC,
+ }, {
+ .name = "us_top",
+ .bit = BCM3368_CLK_US_TOP,
+ }, {
+ .name = "ds_top",
+ .bit = BCM3368_CLK_DS_TOP,
+ }, {
+ .name = "acm",
+ .bit = BCM3368_CLK_ACM,
+ }, {
+ .name = "spi",
+ .bit = BCM3368_CLK_SPI,
+ }, {
+ .name = "usbs",
+ .bit = BCM3368_CLK_USBS,
+ }, {
+ .name = "bmu",
+ .bit = BCM3368_CLK_BMU,
+ }, {
+ .name = "pcm",
+ .bit = BCM3368_CLK_PCM,
+ }, {
+ .name = "ntp",
+ .bit = BCM3368_CLK_NTP,
+ }, {
+ .name = "acp_b",
+ .bit = BCM3368_CLK_ACP_B,
+ }, {
+ .name = "acp_a",
+ .bit = BCM3368_CLK_ACP_A,
+ }, {
+ .name = "emusb",
+ .bit = BCM3368_CLK_EMUSB,
+ }, {
+ .name = "enet0",
+ .bit = BCM3368_CLK_ENET0,
+ }, {
+ .name = "enet1",
+ .bit = BCM3368_CLK_ENET1,
+ }, {
+ .name = "usbsu",
+ .bit = BCM3368_CLK_USBSU,
+ }, {
+ .name = "ephy",
+ .bit = BCM3368_CLK_EPHY,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6318_clocks[] = {
+ {
+ .name = "adsl_asb",
+ .bit = BCM6318_CLK_ADSL_ASB,
+ }, {
+ .name = "usb_asb",
+ .bit = BCM6318_CLK_USB_ASB,
+ }, {
+ .name = "mips_asb",
+ .bit = BCM6318_CLK_MIPS_ASB,
+ }, {
+ .name = "pcie_asb",
+ .bit = BCM6318_CLK_PCIE_ASB,
+ }, {
+ .name = "phymips_asb",
+ .bit = BCM6318_CLK_PHYMIPS_ASB,
+ }, {
+ .name = "robosw_asb",
+ .bit = BCM6318_CLK_ROBOSW_ASB,
+ }, {
+ .name = "sar_asb",
+ .bit = BCM6318_CLK_SAR_ASB,
+ }, {
+ .name = "sdr_asb",
+ .bit = BCM6318_CLK_SDR_ASB,
+ }, {
+ .name = "swreg_asb",
+ .bit = BCM6318_CLK_SWREG_ASB,
+ }, {
+ .name = "periph_asb",
+ .bit = BCM6318_CLK_PERIPH_ASB,
+ }, {
+ .name = "cpubus160",
+ .bit = BCM6318_CLK_CPUBUS160,
+ }, {
+ .name = "adsl",
+ .bit = BCM6318_CLK_ADSL,
+ }, {
+ .name = "sar125",
+ .bit = BCM6318_CLK_SAR125,
+ }, {
+ .name = "mips",
+ .bit = BCM6318_CLK_MIPS,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "pcie",
+ .bit = BCM6318_CLK_PCIE,
+ }, {
+ .name = "robosw250",
+ .bit = BCM6318_CLK_ROBOSW250,
+ }, {
+ .name = "robosw025",
+ .bit = BCM6318_CLK_ROBOSW025,
+ }, {
+ .name = "sdr",
+ .bit = BCM6318_CLK_SDR,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "usbd",
+ .bit = BCM6318_CLK_USBD,
+ }, {
+ .name = "hsspi",
+ .bit = BCM6318_CLK_HSSPI,
+ }, {
+ .name = "pcie25",
+ .bit = BCM6318_CLK_PCIE25,
+ }, {
+ .name = "phymips",
+ .bit = BCM6318_CLK_PHYMIPS,
+ }, {
+ .name = "afe",
+ .bit = BCM6318_CLK_AFE,
+ }, {
+ .name = "qproc",
+ .bit = BCM6318_CLK_QPROC,
+ }, {
+ /* sentinel */
+ },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6318_ubus_clocks[] = {
+ {
+ .name = "adsl-ubus",
+ .bit = BCM6318_UCLK_ADSL,
+ }, {
+ .name = "arb-ubus",
+ .bit = BCM6318_UCLK_ARB,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "mips-ubus",
+ .bit = BCM6318_UCLK_MIPS,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "pcie-ubus",
+ .bit = BCM6318_UCLK_PCIE,
+ }, {
+ .name = "periph-ubus",
+ .bit = BCM6318_UCLK_PERIPH,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "phymips-ubus",
+ .bit = BCM6318_UCLK_PHYMIPS,
+ }, {
+ .name = "robosw-ubus",
+ .bit = BCM6318_UCLK_ROBOSW,
+ }, {
+ .name = "sar-ubus",
+ .bit = BCM6318_UCLK_SAR,
+ }, {
+ .name = "sdr-ubus",
+ .bit = BCM6318_UCLK_SDR,
+ }, {
+ .name = "usb-ubus",
+ .bit = BCM6318_UCLK_USB,
+ }, {
+ /* sentinel */
+ },
};
static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
- { .name = "phy_mips", .bit = 0, },
- { .name = "adsl_qproc", .bit = 1, },
- { .name = "adsl_afe", .bit = 2, },
- { .name = "adsl", .bit = 3, },
- { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
- { .name = "sar", .bit = 5, },
- { .name = "pcm", .bit = 6, },
- { .name = "usbd", .bit = 7, },
- { .name = "usbh", .bit = 8, },
- { .name = "hsspi", .bit = 9, },
- { .name = "pcie", .bit = 10, },
- { .name = "robosw", .bit = 11, },
- { },
+ {
+ .name = "phy_mips",
+ .bit = BCM6328_CLK_PHYMIPS,
+ }, {
+ .name = "adsl_qproc",
+ .bit = BCM6328_CLK_ADSL_QPROC,
+ }, {
+ .name = "adsl_afe",
+ .bit = BCM6328_CLK_ADSL_AFE,
+ }, {
+ .name = "adsl",
+ .bit = BCM6328_CLK_ADSL,
+ }, {
+ .name = "mips",
+ .bit = BCM6328_CLK_MIPS,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "sar",
+ .bit = BCM6328_CLK_SAR,
+ }, {
+ .name = "pcm",
+ .bit = BCM6328_CLK_PCM,
+ }, {
+ .name = "usbd",
+ .bit = BCM6328_CLK_USBD,
+ }, {
+ .name = "usbh",
+ .bit = BCM6328_CLK_USBH,
+ }, {
+ .name = "hsspi",
+ .bit = BCM6328_CLK_HSSPI,
+ }, {
+ .name = "pcie",
+ .bit = BCM6328_CLK_PCIE,
+ }, {
+ .name = "robosw",
+ .bit = BCM6328_CLK_ROBOSW,
+ }, {
+ /* sentinel */
+ },
};
static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
- { .name = "enet", .bit = 4, },
- { .name = "adslphy", .bit = 5, },
- { .name = "pcm", .bit = 8, },
- { .name = "spi", .bit = 9, },
- { .name = "usbs", .bit = 10, },
- { .name = "sar", .bit = 11, },
- { .name = "emusb", .bit = 17, },
- { .name = "enet0", .bit = 18, },
- { .name = "enet1", .bit = 19, },
- { .name = "usbsu", .bit = 20, },
- { .name = "ephy", .bit = 21, },
- { },
+ {
+ .name = "enet",
+ .bit = BCM6358_CLK_ENET,
+ }, {
+ .name = "adslphy",
+ .bit = BCM6358_CLK_ADSLPHY,
+ }, {
+ .name = "pcm",
+ .bit = BCM6358_CLK_PCM,
+ }, {
+ .name = "spi",
+ .bit = BCM6358_CLK_SPI,
+ }, {
+ .name = "usbs",
+ .bit = BCM6358_CLK_USBS,
+ }, {
+ .name = "sar",
+ .bit = BCM6358_CLK_SAR,
+ }, {
+ .name = "emusb",
+ .bit = BCM6358_CLK_EMUSB,
+ }, {
+ .name = "enet0",
+ .bit = BCM6358_CLK_ENET0,
+ }, {
+ .name = "enet1",
+ .bit = BCM6358_CLK_ENET1,
+ }, {
+ .name = "usbsu",
+ .bit = BCM6358_CLK_USBSU,
+ }, {
+ .name = "ephy",
+ .bit = BCM6358_CLK_EPHY,
+ }, {
+ /* sentinel */
+ },
};
static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
- { .name = "adsl_qproc", .bit = 1, },
- { .name = "adsl_afe", .bit = 2, },
- { .name = "adsl", .bit = 3, },
- { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
- { .name = "wlan_ocp", .bit = 5, },
- { .name = "swpkt_usb", .bit = 7, },
- { .name = "swpkt_sar", .bit = 8, },
- { .name = "sar", .bit = 9, },
- { .name = "robosw", .bit = 10, },
- { .name = "pcm", .bit = 11, },
- { .name = "usbd", .bit = 12, },
- { .name = "usbh", .bit = 13, },
- { .name = "ipsec", .bit = 14, },
- { .name = "spi", .bit = 15, },
- { .name = "hsspi", .bit = 16, },
- { .name = "pcie", .bit = 17, },
- { .name = "fap", .bit = 18, },
- { .name = "phymips", .bit = 19, },
- { .name = "nand", .bit = 20, },
- { },
+ {
+ .name = "adsl_qproc",
+ .bit = BCM6362_CLK_ADSL_QPROC,
+ }, {
+ .name = "adsl_afe",
+ .bit = BCM6362_CLK_ADSL_AFE,
+ }, {
+ .name = "adsl",
+ .bit = BCM6362_CLK_ADSL,
+ }, {
+ .name = "mips",
+ .bit = BCM6362_CLK_MIPS,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "wlan_ocp",
+ .bit = BCM6362_CLK_WLAN_OCP,
+ }, {
+ .name = "swpkt_usb",
+ .bit = BCM6362_CLK_SWPKT_USB,
+ }, {
+ .name = "swpkt_sar",
+ .bit = BCM6362_CLK_SWPKT_SAR,
+ }, {
+ .name = "sar",
+ .bit = BCM6362_CLK_SAR,
+ }, {
+ .name = "robosw",
+ .bit = BCM6362_CLK_ROBOSW,
+ }, {
+ .name = "pcm",
+ .bit = BCM6362_CLK_PCM,
+ }, {
+ .name = "usbd",
+ .bit = BCM6362_CLK_USBD,
+ }, {
+ .name = "usbh",
+ .bit = BCM6362_CLK_USBH,
+ }, {
+ .name = "ipsec",
+ .bit = BCM6362_CLK_IPSEC,
+ }, {
+ .name = "spi",
+ .bit = BCM6362_CLK_SPI,
+ }, {
+ .name = "hsspi",
+ .bit = BCM6362_CLK_HSSPI,
+ }, {
+ .name = "pcie",
+ .bit = BCM6362_CLK_PCIE,
+ }, {
+ .name = "fap",
+ .bit = BCM6362_CLK_FAP,
+ }, {
+ .name = "phymips",
+ .bit = BCM6362_CLK_PHYMIPS,
+ }, {
+ .name = "nand",
+ .bit = BCM6362_CLK_NAND,
+ }, {
+ /* sentinel */
+ },
};
static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
- { .name = "vdsl_qproc", .bit = 2, },
- { .name = "vdsl_afe", .bit = 3, },
- { .name = "vdsl_bonding", .bit = 4, },
- { .name = "vdsl", .bit = 5, },
- { .name = "phymips", .bit = 6, },
- { .name = "swpkt_usb", .bit = 7, },
- { .name = "swpkt_sar", .bit = 8, },
- { .name = "spi", .bit = 9, },
- { .name = "usbd", .bit = 10, },
- { .name = "sar", .bit = 11, },
- { .name = "robosw", .bit = 12, },
- { .name = "utopia", .bit = 13, },
- { .name = "pcm", .bit = 14, },
- { .name = "usbh", .bit = 15, },
- { .name = "disable_gless", .bit = 16, },
- { .name = "nand", .bit = 17, },
- { .name = "ipsec", .bit = 18, },
- { },
+ {
+ .name = "vdsl_qproc",
+ .bit = BCM6368_CLK_VDSL_QPROC,
+ }, {
+ .name = "vdsl_afe",
+ .bit = BCM6368_CLK_VDSL_AFE,
+ }, {
+ .name = "vdsl_bonding",
+ .bit = BCM6368_CLK_VDSL_BONDING,
+ }, {
+ .name = "vdsl",
+ .bit = BCM6368_CLK_VDSL,
+ }, {
+ .name = "phymips",
+ .bit = BCM6368_CLK_PHYMIPS,
+ }, {
+ .name = "swpkt_usb",
+ .bit = BCM6368_CLK_SWPKT_USB,
+ }, {
+ .name = "swpkt_sar",
+ .bit = BCM6368_CLK_SWPKT_SAR,
+ }, {
+ .name = "spi",
+ .bit = BCM6368_CLK_SPI,
+ }, {
+ .name = "usbd",
+ .bit = BCM6368_CLK_USBD,
+ }, {
+ .name = "sar",
+ .bit = BCM6368_CLK_SAR,
+ }, {
+ .name = "robosw",
+ .bit = BCM6368_CLK_ROBOSW,
+ }, {
+ .name = "utopia",
+ .bit = BCM6368_CLK_UTOPIA,
+ }, {
+ .name = "pcm",
+ .bit = BCM6368_CLK_PCM,
+ }, {
+ .name = "usbh",
+ .bit = BCM6368_CLK_USBH,
+ }, {
+ .name = "disable_gless",
+ .bit = BCM6368_CLK_DIS_GLESS,
+ }, {
+ .name = "nand",
+ .bit = BCM6368_CLK_NAND,
+ }, {
+ .name = "ipsec",
+ .bit = BCM6368_CLK_IPSEC,
+ }, {
+ /* sentinel */
+ },
};
static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
- { .name = "disable_gless", .bit = 0, },
- { .name = "vdsl_qproc", .bit = 1, },
- { .name = "vdsl_afe", .bit = 2, },
- { .name = "vdsl", .bit = 3, },
- { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
- { .name = "wlan_ocp", .bit = 5, },
- { .name = "dect", .bit = 6, },
- { .name = "fap0", .bit = 7, },
- { .name = "fap1", .bit = 8, },
- { .name = "sar", .bit = 9, },
- { .name = "robosw", .bit = 10, },
- { .name = "pcm", .bit = 11, },
- { .name = "usbd", .bit = 12, },
- { .name = "usbh", .bit = 13, },
- { .name = "ipsec", .bit = 14, },
- { .name = "spi", .bit = 15, },
- { .name = "hsspi", .bit = 16, },
- { .name = "pcie", .bit = 17, },
- { .name = "phymips", .bit = 18, },
- { .name = "gmac", .bit = 19, },
- { .name = "nand", .bit = 20, },
- { .name = "tbus", .bit = 27, },
- { .name = "robosw250", .bit = 31, },
- { },
+ {
+ .name = "disable_gless",
+ .bit = BCM63268_CLK_DIS_GLESS,
+ }, {
+ .name = "vdsl_qproc",
+ .bit = BCM63268_CLK_VDSL_QPROC,
+ }, {
+ .name = "vdsl_afe",
+ .bit = BCM63268_CLK_VDSL_AFE,
+ }, {
+ .name = "vdsl",
+ .bit = BCM63268_CLK_VDSL,
+ }, {
+ .name = "mips",
+ .bit = BCM63268_CLK_MIPS,
+ .flags = CLK_IS_CRITICAL,
+ }, {
+ .name = "wlan_ocp",
+ .bit = BCM63268_CLK_WLAN_OCP,
+ }, {
+ .name = "dect",
+ .bit = BCM63268_CLK_DECT,
+ }, {
+ .name = "fap0",
+ .bit = BCM63268_CLK_FAP0,
+ }, {
+ .name = "fap1",
+ .bit = BCM63268_CLK_FAP1,
+ }, {
+ .name = "sar",
+ .bit = BCM63268_CLK_SAR,
+ }, {
+ .name = "robosw",
+ .bit = BCM63268_CLK_ROBOSW,
+ }, {
+ .name = "pcm",
+ .bit = BCM63268_CLK_PCM,
+ }, {
+ .name = "usbd",
+ .bit = BCM63268_CLK_USBD,
+ }, {
+ .name = "usbh",
+ .bit = BCM63268_CLK_USBH,
+ }, {
+ .name = "ipsec",
+ .bit = BCM63268_CLK_IPSEC,
+ }, {
+ .name = "spi",
+ .bit = BCM63268_CLK_SPI,
+ }, {
+ .name = "hsspi",
+ .bit = BCM63268_CLK_HSSPI,
+ }, {
+ .name = "pcie",
+ .bit = BCM63268_CLK_PCIE,
+ }, {
+ .name = "phymips",
+ .bit = BCM63268_CLK_PHYMIPS,
+ }, {
+ .name = "gmac",
+ .bit = BCM63268_CLK_GMAC,
+ }, {
+ .name = "nand",
+ .bit = BCM63268_CLK_NAND,
+ }, {
+ .name = "tbus",
+ .bit = BCM63268_CLK_TBUS,
+ }, {
+ .name = "robosw250",
+ .bit = BCM63268_CLK_ROBOSW250,
+ }, {
+ /* sentinel */
+ },
};
static int clk_bcm63xx_probe(struct platform_device *pdev)
@@ -218,6 +558,8 @@
static const struct of_device_id clk_bcm63xx_dt_ids[] = {
{ .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
+ { .compatible = "brcm,bcm6318-clocks", .data = &bcm6318_clocks, },
+ { .compatible = "brcm,bcm6318-ubus-clocks", .data = &bcm6318_ubus_clocks, },
{ .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
{ .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
{ .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c
index 6fb8af5..e062dd4 100644
--- a/drivers/clk/bcm/clk-iproc-asiu.c
+++ b/drivers/clk/bcm/clk-iproc-asiu.c
@@ -119,7 +119,7 @@
if (rate == *parent_rate)
return *parent_rate;
- div = DIV_ROUND_UP(*parent_rate, rate);
+ div = DIV_ROUND_CLOSEST(*parent_rate, rate);
if (div < 2)
return *parent_rate;
@@ -145,7 +145,7 @@
return 0;
}
- div = DIV_ROUND_UP(parent_rate, rate);
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
if (div < 2)
return -EINVAL;
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
index 1654fd0..f89b9cf 100644
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -18,30 +18,56 @@
#include <soc/bcm2835/raspberrypi-firmware.h>
-#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
+enum rpi_firmware_clk_id {
+ RPI_FIRMWARE_EMMC_CLK_ID = 1,
+ RPI_FIRMWARE_UART_CLK_ID,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ RPI_FIRMWARE_CORE_CLK_ID,
+ RPI_FIRMWARE_V3D_CLK_ID,
+ RPI_FIRMWARE_H264_CLK_ID,
+ RPI_FIRMWARE_ISP_CLK_ID,
+ RPI_FIRMWARE_SDRAM_CLK_ID,
+ RPI_FIRMWARE_PIXEL_CLK_ID,
+ RPI_FIRMWARE_PWM_CLK_ID,
+ RPI_FIRMWARE_HEVC_CLK_ID,
+ RPI_FIRMWARE_EMMC2_CLK_ID,
+ RPI_FIRMWARE_M2MC_CLK_ID,
+ RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
+ RPI_FIRMWARE_NUM_CLK_ID,
+};
+
+static char *rpi_firmware_clk_names[] = {
+ [RPI_FIRMWARE_EMMC_CLK_ID] = "emmc",
+ [RPI_FIRMWARE_UART_CLK_ID] = "uart",
+ [RPI_FIRMWARE_ARM_CLK_ID] = "arm",
+ [RPI_FIRMWARE_CORE_CLK_ID] = "core",
+ [RPI_FIRMWARE_V3D_CLK_ID] = "v3d",
+ [RPI_FIRMWARE_H264_CLK_ID] = "h264",
+ [RPI_FIRMWARE_ISP_CLK_ID] = "isp",
+ [RPI_FIRMWARE_SDRAM_CLK_ID] = "sdram",
+ [RPI_FIRMWARE_PIXEL_CLK_ID] = "pixel",
+ [RPI_FIRMWARE_PWM_CLK_ID] = "pwm",
+ [RPI_FIRMWARE_HEVC_CLK_ID] = "hevc",
+ [RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2",
+ [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc",
+ [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb",
+};
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
-/*
- * Even though the firmware interface alters 'pllb' the frequencies are
- * provided as per 'pllb_arm'. We need to scale before passing them trough.
- */
-#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
-
-#define A2W_PLL_FRAC_BITS 20
-
struct raspberrypi_clk {
struct device *dev;
struct rpi_firmware *firmware;
struct platform_device *cpufreq;
+};
- unsigned long min_rate;
- unsigned long max_rate;
+struct raspberrypi_clk_data {
+ struct clk_hw hw;
- struct clk_hw pllb;
- struct clk_hw *pllb_arm;
- struct clk_lookup *pllb_arm_lookup;
+ unsigned int id;
+
+ struct raspberrypi_clk *rpi;
};
/*
@@ -64,11 +90,12 @@
__le32 disable_turbo;
} __packed;
-static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
- u32 clk, u32 *val)
+static int raspberrypi_clock_property(struct rpi_firmware *firmware,
+ const struct raspberrypi_clk_data *data,
+ u32 tag, u32 *val)
{
struct raspberrypi_firmware_prop msg = {
- .id = cpu_to_le32(clk),
+ .id = cpu_to_le32(data->id),
.val = cpu_to_le32(*val),
.disable_turbo = cpu_to_le32(1),
};
@@ -83,16 +110,16 @@
return 0;
}
-static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
+static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
{
- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
- pllb);
+ struct raspberrypi_clk_data *data =
+ container_of(hw, struct raspberrypi_clk_data, hw);
+ struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_GET_CLOCK_STATE,
- RPI_FIRMWARE_ARM_CLK_ID, &val);
+ ret = raspberrypi_clock_property(rpi->firmware, data,
+ RPI_FIRMWARE_GET_CLOCK_STATE, &val);
if (ret)
return 0;
@@ -100,36 +127,34 @@
}
-static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
- pllb);
+ struct raspberrypi_clk_data *data =
+ container_of(hw, struct raspberrypi_clk_data, hw);
+ struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_GET_CLOCK_RATE,
- RPI_FIRMWARE_ARM_CLK_ID,
- &val);
+ ret = raspberrypi_clock_property(rpi->firmware, data,
+ RPI_FIRMWARE_GET_CLOCK_RATE, &val);
if (ret)
return ret;
- return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+ return val;
}
-static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
- pllb);
- u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+ struct raspberrypi_clk_data *data =
+ container_of(hw, struct raspberrypi_clk_data, hw);
+ struct raspberrypi_clk *rpi = data->rpi;
+ u32 _rate = rate;
int ret;
- ret = raspberrypi_clock_property(rpi->firmware,
- RPI_FIRMWARE_SET_CLOCK_RATE,
- RPI_FIRMWARE_ARM_CLK_ID,
- &new_rate);
+ ret = raspberrypi_clock_property(rpi->firmware, data,
+ RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
if (ret)
dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
clk_hw_get_name(hw), ret);
@@ -137,111 +162,129 @@
return ret;
}
-/*
- * Sadly there is no firmware rate rounding interface. We borrowed it from
- * clk-bcm2835.
- */
-static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
+static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
- pllb);
- u64 div, final_rate;
- u32 ndiv, fdiv;
-
- /* We can't use req->rate directly as it would overflow */
- final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
-
- div = (u64)final_rate << A2W_PLL_FRAC_BITS;
- do_div(div, req->best_parent_rate);
-
- ndiv = div >> A2W_PLL_FRAC_BITS;
- fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
-
- final_rate = ((u64)req->best_parent_rate *
- ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
-
- req->rate = final_rate >> A2W_PLL_FRAC_BITS;
-
+ /*
+ * The firmware will do the rounding but that isn't part of
+ * the interface with the firmware, so we just do our best
+ * here.
+ */
+ req->rate = clamp(req->rate, req->min_rate, req->max_rate);
return 0;
}
-static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
- .is_prepared = raspberrypi_fw_pll_is_on,
- .recalc_rate = raspberrypi_fw_pll_get_rate,
- .set_rate = raspberrypi_fw_pll_set_rate,
- .determine_rate = raspberrypi_pll_determine_rate,
+static const struct clk_ops raspberrypi_firmware_clk_ops = {
+ .is_prepared = raspberrypi_fw_is_prepared,
+ .recalc_rate = raspberrypi_fw_get_rate,
+ .determine_rate = raspberrypi_fw_dumb_determine_rate,
+ .set_rate = raspberrypi_fw_set_rate,
};
-static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
+static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
+ unsigned int parent,
+ unsigned int id)
{
- u32 min_rate = 0, max_rate = 0;
- struct clk_init_data init;
+ struct raspberrypi_clk_data *data;
+ struct clk_init_data init = {};
+ u32 min_rate, max_rate;
int ret;
- memset(&init, 0, sizeof(init));
+ data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+ data->rpi = rpi;
+ data->id = id;
- /* All of the PLLs derive from the external oscillator. */
- init.parent_names = (const char *[]){ "osc" };
- init.num_parents = 1;
- init.name = "pllb";
- init.ops = &raspberrypi_firmware_pll_clk_ops;
- init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+ init.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
+ "fw-clk-%s",
+ rpi_firmware_clk_names[id]);
+ init.ops = &raspberrypi_firmware_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
- /* Get min & max rates set by the firmware */
- ret = raspberrypi_clock_property(rpi->firmware,
+ data->hw.init = &init;
+
+ ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
- RPI_FIRMWARE_ARM_CLK_ID,
&min_rate);
if (ret) {
- dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
- init.name, ret);
- return ret;
+ dev_err(rpi->dev, "Failed to get clock %d min freq: %d",
+ id, ret);
+ return ERR_PTR(ret);
}
- ret = raspberrypi_clock_property(rpi->firmware,
+ ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
- RPI_FIRMWARE_ARM_CLK_ID,
&max_rate);
if (ret) {
- dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
- init.name, ret);
- return ret;
+ dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n",
+ id, ret);
+ return ERR_PTR(ret);
}
- if (!min_rate || !max_rate) {
- dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
- min_rate, max_rate);
- return -EINVAL;
+ ret = devm_clk_hw_register(rpi->dev, &data->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ clk_hw_set_rate_range(&data->hw, min_rate, max_rate);
+
+ if (id == RPI_FIRMWARE_ARM_CLK_ID) {
+ ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw,
+ NULL, "cpu0");
+ if (ret) {
+ dev_err(rpi->dev, "Failed to initialize clkdev\n");
+ return ERR_PTR(ret);
+ }
}
- dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
- min_rate, max_rate);
-
- rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
- rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
-
- rpi->pllb.init = &init;
-
- return devm_clk_hw_register(rpi->dev, &rpi->pllb);
+ return &data->hw;
}
-static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
-{
- rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
- "pllb_arm", "pllb",
- CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
- 1, 2);
- if (IS_ERR(rpi->pllb_arm)) {
- dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
- return PTR_ERR(rpi->pllb_arm);
- }
+struct rpi_firmware_get_clocks_response {
+ u32 parent;
+ u32 id;
+};
- rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
- if (!rpi->pllb_arm_lookup) {
- dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
- clk_hw_unregister_fixed_factor(rpi->pllb_arm);
+static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
+ struct clk_hw_onecell_data *data)
+{
+ struct rpi_firmware_get_clocks_response *clks;
+ int ret;
+
+ clks = devm_kcalloc(rpi->dev,
+ sizeof(*clks), RPI_FIRMWARE_NUM_CLK_ID,
+ GFP_KERNEL);
+ if (!clks)
return -ENOMEM;
+
+ ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS,
+ clks,
+ sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID);
+ if (ret)
+ return ret;
+
+ while (clks->id) {
+ struct clk_hw *hw;
+
+ switch (clks->id) {
+ case RPI_FIRMWARE_ARM_CLK_ID:
+ case RPI_FIRMWARE_CORE_CLK_ID:
+ case RPI_FIRMWARE_M2MC_CLK_ID:
+ case RPI_FIRMWARE_V3D_CLK_ID:
+ case RPI_FIRMWARE_PIXEL_BVB_CLK_ID:
+ hw = raspberrypi_clk_register(rpi, clks->parent,
+ clks->id);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[clks->id] = hw;
+ data->num = clks->id + 1;
+ fallthrough;
+
+ default:
+ clks++;
+ break;
+ }
}
return 0;
@@ -249,14 +292,23 @@
static int raspberrypi_clk_probe(struct platform_device *pdev)
{
+ struct clk_hw_onecell_data *clk_data;
struct device_node *firmware_node;
struct device *dev = &pdev->dev;
struct rpi_firmware *firmware;
struct raspberrypi_clk *rpi;
int ret;
- firmware_node = of_find_compatible_node(NULL, NULL,
- "raspberrypi,bcm2835-firmware");
+ /*
+ * We can be probed either through the an old-fashioned
+ * platform device registration or through a DT node that is a
+ * child of the firmware node. Handle both cases.
+ */
+ if (dev->of_node)
+ firmware_node = of_get_parent(dev->of_node);
+ else
+ firmware_node = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
if (!firmware_node) {
dev_err(dev, "Missing firmware node\n");
return -ENOENT;
@@ -275,13 +327,18 @@
rpi->firmware = firmware;
platform_set_drvdata(pdev, rpi);
- ret = raspberrypi_register_pllb(rpi);
- if (ret) {
- dev_err(dev, "Failed to initialize pllb, %d\n", ret);
- return ret;
- }
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
+ RPI_FIRMWARE_NUM_CLK_ID),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
- ret = raspberrypi_register_pllb_arm(rpi);
+ ret = raspberrypi_discover_clocks(rpi, clk_data);
+ if (ret)
+ return ret;
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ clk_data);
if (ret)
return ret;
@@ -300,9 +357,16 @@
return 0;
}
+static const struct of_device_id raspberrypi_clk_match[] = {
+ { .compatible = "raspberrypi,firmware-clocks" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, raspberrypi_clk_match);
+
static struct platform_driver raspberrypi_clk_driver = {
.driver = {
.name = "raspberrypi-clk",
+ .of_match_table = raspberrypi_clk_match,
},
.probe = raspberrypi_clk_probe,
.remove = raspberrypi_clk_remove,