Merge branch 'clk-bcm' into clk-next

- Make defines for bcm63xx-gate clks to use in DT
 - Support gate clks on BCM6318 SoCs
 - Add HDMI clks for BCM2711 SoCs
 - Support BCM2711 SoC firmware clks

* clk-bcm: (42 commits)
  clk: bcm: dvp: Add missing module informations
  clk: bcm: rpi: Remove the quirks for the CPU clock
  clk: bcm2835: Don't cache the PLLB rate
  clk: bcm2835: Allow custom CCF flags for the PLLs
  Revert "clk: bcm2835: remove pllb"
  clk: bcm: rpi: Give firmware clocks a name
  clk: bcm: rpi: Discover the firmware clocks
  clk: bcm: rpi: Add an enum for the firmware clocks
  clk: bcm: rpi: Add DT provider for the clocks
  clk: bcm: rpi: Make the PLLB registration function return a clk_hw
  clk: bcm: rpi: Split pllb clock hooks
  clk: bcm: rpi: Rename is_prepared function
  clk: bcm: rpi: Pass the clocks data to the firmware function
  clk: bcm: rpi: Add clock id to data
  clk: bcm: rpi: Create a data structure for the clocks
  clk: bcm: rpi: Use CCF boundaries instead of rolling our own
  clk: bcm: rpi: Make sure the clkdev lookup is removed
  clk: bcm: rpi: Switch to clk_hw_register_clkdev
  clk: bcm: rpi: Remove pllb_arm_lookup global pointer
  clk: bcm: rpi: Make sure pllb_arm is removed
  ...
This commit is contained in:
Stephen Boyd 2020-06-26 11:58:51 -07:00
commit 12ef3933b4
23 changed files with 1139 additions and 259 deletions

View File

@ -1,14 +0,0 @@
Raspberry Pi VideoCore firmware driver
Required properties:
- compatible: Should be "raspberrypi,bcm2835-firmware"
- mboxes: Phandle to the firmware device's Mailbox.
(See: ../mailbox/mailbox.txt for more information)
Example:
firmware {
compatible = "raspberrypi,bcm2835-firmware";
mboxes = <&mailbox>;
};

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/arm/bcm/raspberrypi,bcm2835-firmware.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Raspberry Pi VideoCore firmware driver
maintainers:
- Eric Anholt <eric@anholt.net>
- Stefan Wahren <wahrenst@gmx.net>
properties:
compatible:
items:
- const: raspberrypi,bcm2835-firmware
- const: simple-bus
mboxes:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: |
Phandle to the firmware device's Mailbox.
(See: ../mailbox/mailbox.txt for more information)
clocks:
type: object
properties:
compatible:
const: raspberrypi,firmware-clocks
"#clock-cells":
const: 1
description: >
The argument is the ID of the clocks contained by the
firmware messages.
required:
- compatible
- "#clock-cells"
additionalProperties: false
required:
- compatible
- mboxes
examples:
- |
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
mboxes = <&mailbox>;
firmware_clocks: clocks {
compatible = "raspberrypi,firmware-clocks";
#clock-cells = <1>;
};
};
...

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/brcm,bcm2711-dvp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BCM2711 HDMI DVP Device Tree Bindings
maintainers:
- Maxime Ripard <mripard@kernel.org>
properties:
"#clock-cells":
const: 1
"#reset-cells":
const: 1
compatible:
const: brcm,brcm2711-dvp
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- "#clock-cells"
- "#reset-cells"
- compatible
- reg
- clocks
additionalProperties: false
examples:
- |
dvp: clock@7ef00000 {
compatible = "brcm,brcm2711-dvp";
reg = <0x7ef00000 0x10>;
clocks = <&clk_108MHz>;
#clock-cells = <1>;
#reset-cells = <1>;
};
...

View File

@ -3,6 +3,8 @@ Gated Clock Controller Bindings for MIPS based BCM63XX SoCs
Required properties: Required properties:
- compatible: must be one of: - compatible: must be one of:
"brcm,bcm3368-clocks" "brcm,bcm3368-clocks"
"brcm,bcm6318-clocks"
"brcm,bcm6318-ubus-clocks"
"brcm,bcm6328-clocks" "brcm,bcm6328-clocks"
"brcm,bcm6358-clocks" "brcm,bcm6358-clocks"
"brcm,bcm6362-clocks" "brcm,bcm6362-clocks"

View File

@ -1,4 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only # 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_SIMPLE
help
Enable common clock framework support for the Broadcom BCM2711
DVP Controller.
config CLK_BCM2835 config CLK_BCM2835
bool "Broadcom BCM2835 clock support" bool "Broadcom BCM2835 clock support"
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST

View File

@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.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_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.o
obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o
obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o

View File

@ -0,0 +1,124 @@
// 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 */ }
};
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");

View File

@ -421,6 +421,7 @@ struct bcm2835_pll_data {
u32 reference_enable_mask; u32 reference_enable_mask;
/* Bit in CM_LOCK to indicate when the PLL has locked. */ /* Bit in CM_LOCK to indicate when the PLL has locked. */
u32 lock_mask; u32 lock_mask;
u32 flags;
const struct bcm2835_pll_ana_bits *ana; const struct bcm2835_pll_ana_bits *ana;
@ -1310,7 +1311,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
init.num_parents = 1; init.num_parents = 1;
init.name = pll_data->name; init.name = pll_data->name;
init.ops = &bcm2835_pll_clk_ops; 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); pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) if (!pll)
@ -1684,10 +1685,33 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.fixed_divider = 1, .fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT), .flags = CLK_SET_RATE_PARENT),
/* /* PLLB is used for the ARM's clock. */
* PLLB is used for the ARM's clock. Controlled by firmware, see [BCM2835_PLLB] = REGISTER_PLL(
* clk-raspberrypi.c. 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. * PLLC is the core PLL, used to drive the core VPU clock.

View File

@ -6,6 +6,14 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_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 { struct clk_bcm63xx_table_entry {
const char * const name; const char * const name;
u8 bit; u8 bit;
@ -20,126 +28,458 @@ struct clk_bcm63xx_hw {
}; };
static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = { static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
{ .name = "mac", .bit = 3, }, {
{ .name = "tc", .bit = 5, }, .name = "mac",
{ .name = "us_top", .bit = 6, }, .bit = BCM3368_CLK_MAC,
{ .name = "ds_top", .bit = 7, }, }, {
{ .name = "acm", .bit = 8, }, .name = "tc",
{ .name = "spi", .bit = 9, }, .bit = BCM3368_CLK_TC,
{ .name = "usbs", .bit = 10, }, }, {
{ .name = "bmu", .bit = 11, }, .name = "us_top",
{ .name = "pcm", .bit = 12, }, .bit = BCM3368_CLK_US_TOP,
{ .name = "ntp", .bit = 13, }, }, {
{ .name = "acp_b", .bit = 14, }, .name = "ds_top",
{ .name = "acp_a", .bit = 15, }, .bit = BCM3368_CLK_DS_TOP,
{ .name = "emusb", .bit = 17, }, }, {
{ .name = "enet0", .bit = 18, }, .name = "acm",
{ .name = "enet1", .bit = 19, }, .bit = BCM3368_CLK_ACM,
{ .name = "usbsu", .bit = 20, }, }, {
{ .name = "ephy", .bit = 21, }, .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[] = { static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
{ .name = "phy_mips", .bit = 0, }, {
{ .name = "adsl_qproc", .bit = 1, }, .name = "phy_mips",
{ .name = "adsl_afe", .bit = 2, }, .bit = BCM6328_CLK_PHYMIPS,
{ .name = "adsl", .bit = 3, }, }, {
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, .name = "adsl_qproc",
{ .name = "sar", .bit = 5, }, .bit = BCM6328_CLK_ADSL_QPROC,
{ .name = "pcm", .bit = 6, }, }, {
{ .name = "usbd", .bit = 7, }, .name = "adsl_afe",
{ .name = "usbh", .bit = 8, }, .bit = BCM6328_CLK_ADSL_AFE,
{ .name = "hsspi", .bit = 9, }, }, {
{ .name = "pcie", .bit = 10, }, .name = "adsl",
{ .name = "robosw", .bit = 11, }, .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[] = { static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
{ .name = "enet", .bit = 4, }, {
{ .name = "adslphy", .bit = 5, }, .name = "enet",
{ .name = "pcm", .bit = 8, }, .bit = BCM6358_CLK_ENET,
{ .name = "spi", .bit = 9, }, }, {
{ .name = "usbs", .bit = 10, }, .name = "adslphy",
{ .name = "sar", .bit = 11, }, .bit = BCM6358_CLK_ADSLPHY,
{ .name = "emusb", .bit = 17, }, }, {
{ .name = "enet0", .bit = 18, }, .name = "pcm",
{ .name = "enet1", .bit = 19, }, .bit = BCM6358_CLK_PCM,
{ .name = "usbsu", .bit = 20, }, }, {
{ .name = "ephy", .bit = 21, }, .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[] = { static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
{ .name = "adsl_qproc", .bit = 1, }, {
{ .name = "adsl_afe", .bit = 2, }, .name = "adsl_qproc",
{ .name = "adsl", .bit = 3, }, .bit = BCM6362_CLK_ADSL_QPROC,
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, }, {
{ .name = "wlan_ocp", .bit = 5, }, .name = "adsl_afe",
{ .name = "swpkt_usb", .bit = 7, }, .bit = BCM6362_CLK_ADSL_AFE,
{ .name = "swpkt_sar", .bit = 8, }, }, {
{ .name = "sar", .bit = 9, }, .name = "adsl",
{ .name = "robosw", .bit = 10, }, .bit = BCM6362_CLK_ADSL,
{ .name = "pcm", .bit = 11, }, }, {
{ .name = "usbd", .bit = 12, }, .name = "mips",
{ .name = "usbh", .bit = 13, }, .bit = BCM6362_CLK_MIPS,
{ .name = "ipsec", .bit = 14, }, .flags = CLK_IS_CRITICAL,
{ .name = "spi", .bit = 15, }, }, {
{ .name = "hsspi", .bit = 16, }, .name = "wlan_ocp",
{ .name = "pcie", .bit = 17, }, .bit = BCM6362_CLK_WLAN_OCP,
{ .name = "fap", .bit = 18, }, }, {
{ .name = "phymips", .bit = 19, }, .name = "swpkt_usb",
{ .name = "nand", .bit = 20, }, .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[] = { static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
{ .name = "vdsl_qproc", .bit = 2, }, {
{ .name = "vdsl_afe", .bit = 3, }, .name = "vdsl_qproc",
{ .name = "vdsl_bonding", .bit = 4, }, .bit = BCM6368_CLK_VDSL_QPROC,
{ .name = "vdsl", .bit = 5, }, }, {
{ .name = "phymips", .bit = 6, }, .name = "vdsl_afe",
{ .name = "swpkt_usb", .bit = 7, }, .bit = BCM6368_CLK_VDSL_AFE,
{ .name = "swpkt_sar", .bit = 8, }, }, {
{ .name = "spi", .bit = 9, }, .name = "vdsl_bonding",
{ .name = "usbd", .bit = 10, }, .bit = BCM6368_CLK_VDSL_BONDING,
{ .name = "sar", .bit = 11, }, }, {
{ .name = "robosw", .bit = 12, }, .name = "vdsl",
{ .name = "utopia", .bit = 13, }, .bit = BCM6368_CLK_VDSL,
{ .name = "pcm", .bit = 14, }, }, {
{ .name = "usbh", .bit = 15, }, .name = "phymips",
{ .name = "disable_gless", .bit = 16, }, .bit = BCM6368_CLK_PHYMIPS,
{ .name = "nand", .bit = 17, }, }, {
{ .name = "ipsec", .bit = 18, }, .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[] = { static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
{ .name = "disable_gless", .bit = 0, }, {
{ .name = "vdsl_qproc", .bit = 1, }, .name = "disable_gless",
{ .name = "vdsl_afe", .bit = 2, }, .bit = BCM63268_CLK_DIS_GLESS,
{ .name = "vdsl", .bit = 3, }, }, {
{ .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, }, .name = "vdsl_qproc",
{ .name = "wlan_ocp", .bit = 5, }, .bit = BCM63268_CLK_VDSL_QPROC,
{ .name = "dect", .bit = 6, }, }, {
{ .name = "fap0", .bit = 7, }, .name = "vdsl_afe",
{ .name = "fap1", .bit = 8, }, .bit = BCM63268_CLK_VDSL_AFE,
{ .name = "sar", .bit = 9, }, }, {
{ .name = "robosw", .bit = 10, }, .name = "vdsl",
{ .name = "pcm", .bit = 11, }, .bit = BCM63268_CLK_VDSL,
{ .name = "usbd", .bit = 12, }, }, {
{ .name = "usbh", .bit = 13, }, .name = "mips",
{ .name = "ipsec", .bit = 14, }, .bit = BCM63268_CLK_MIPS,
{ .name = "spi", .bit = 15, }, .flags = CLK_IS_CRITICAL,
{ .name = "hsspi", .bit = 16, }, }, {
{ .name = "pcie", .bit = 17, }, .name = "wlan_ocp",
{ .name = "phymips", .bit = 18, }, .bit = BCM63268_CLK_WLAN_OCP,
{ .name = "gmac", .bit = 19, }, }, {
{ .name = "nand", .bit = 20, }, .name = "dect",
{ .name = "tbus", .bit = 27, }, .bit = BCM63268_CLK_DECT,
{ .name = "robosw250", .bit = 31, }, }, {
{ }, .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) static int clk_bcm63xx_probe(struct platform_device *pdev)
@ -155,6 +495,7 @@ static int clk_bcm63xx_probe(struct platform_device *pdev)
for (entry = table; entry->name; entry++) for (entry = table; entry->name; entry++)
maxbit = max_t(u8, maxbit, entry->bit); maxbit = max_t(u8, maxbit, entry->bit);
maxbit++;
hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
GFP_KERNEL); GFP_KERNEL);
@ -217,6 +558,8 @@ static int clk_bcm63xx_remove(struct platform_device *pdev)
static const struct of_device_id clk_bcm63xx_dt_ids[] = { static const struct of_device_id clk_bcm63xx_dt_ids[] = {
{ .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, }, { .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,bcm6328-clocks", .data = &bcm6328_clocks, },
{ .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, }, { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
{ .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, }, { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },

View File

@ -18,30 +18,56 @@
#include <soc/bcm2835/raspberrypi-firmware.h> #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_ENABLE_BIT BIT(0)
#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) #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 raspberrypi_clk {
struct device *dev; struct device *dev;
struct rpi_firmware *firmware; struct rpi_firmware *firmware;
struct platform_device *cpufreq; struct platform_device *cpufreq;
};
unsigned long min_rate; struct raspberrypi_clk_data {
unsigned long max_rate; struct clk_hw hw;
struct clk_hw pllb; unsigned int id;
struct clk_hw *pllb_arm;
struct clk_lookup *pllb_arm_lookup; struct raspberrypi_clk *rpi;
}; };
/* /*
@ -64,11 +90,12 @@ struct raspberrypi_firmware_prop {
__le32 disable_turbo; __le32 disable_turbo;
} __packed; } __packed;
static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag, static int raspberrypi_clock_property(struct rpi_firmware *firmware,
u32 clk, u32 *val) const struct raspberrypi_clk_data *data,
u32 tag, u32 *val)
{ {
struct raspberrypi_firmware_prop msg = { struct raspberrypi_firmware_prop msg = {
.id = cpu_to_le32(clk), .id = cpu_to_le32(data->id),
.val = cpu_to_le32(*val), .val = cpu_to_le32(*val),
.disable_turbo = cpu_to_le32(1), .disable_turbo = cpu_to_le32(1),
}; };
@ -83,16 +110,16 @@ static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
return 0; 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, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0; u32 val = 0;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_STATE, RPI_FIRMWARE_GET_CLOCK_STATE, &val);
RPI_FIRMWARE_ARM_CLK_ID, &val);
if (ret) if (ret)
return 0; return 0;
@ -100,36 +127,34 @@ static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
} }
static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0; u32 val = 0;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_CLOCK_RATE, RPI_FIRMWARE_GET_CLOCK_RATE, &val);
RPI_FIRMWARE_ARM_CLK_ID,
&val);
if (ret) if (ret)
return 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, static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, struct raspberrypi_clk_data *data =
pllb); container_of(hw, struct raspberrypi_clk_data, hw);
u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; struct raspberrypi_clk *rpi = data->rpi;
u32 _rate = rate;
int ret; int ret;
ret = raspberrypi_clock_property(rpi->firmware, ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_SET_CLOCK_RATE, RPI_FIRMWARE_SET_CLOCK_RATE, &_rate);
RPI_FIRMWARE_ARM_CLK_ID,
&new_rate);
if (ret) if (ret)
dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
clk_hw_get_name(hw), ret); clk_hw_get_name(hw), ret);
@ -137,111 +162,128 @@ static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
return ret; return ret;
} }
/* static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
* Sadly there is no firmware rate rounding interface. We borrowed it from struct clk_rate_request *req)
* clk-bcm2835.
*/
static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{ {
struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, /*
pllb); * The firmware will do the rounding but that isn't part of
u64 div, final_rate; * the interface with the firmware, so we just do our best
u32 ndiv, fdiv; * here.
*/
/* We can't use req->rate directly as it would overflow */ req->rate = clamp(req->rate, req->min_rate, req->max_rate);
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;
return 0; return 0;
} }
static const struct clk_ops raspberrypi_firmware_pll_clk_ops = { static const struct clk_ops raspberrypi_firmware_clk_ops = {
.is_prepared = raspberrypi_fw_pll_is_on, .is_prepared = raspberrypi_fw_is_prepared,
.recalc_rate = raspberrypi_fw_pll_get_rate, .recalc_rate = raspberrypi_fw_get_rate,
.set_rate = raspberrypi_fw_pll_set_rate, .determine_rate = raspberrypi_fw_dumb_determine_rate,
.determine_rate = raspberrypi_pll_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 raspberrypi_clk_data *data;
struct clk_init_data init; struct clk_init_data init = {};
u32 min_rate, max_rate;
int ret; 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.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
init.parent_names = (const char *[]){ "osc" }; "fw-clk-%s",
init.num_parents = 1; rpi_firmware_clk_names[id]);
init.name = "pllb"; init.ops = &raspberrypi_firmware_clk_ops;
init.ops = &raspberrypi_firmware_pll_clk_ops; init.flags = CLK_GET_RATE_NOCACHE;
init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
/* Get min & max rates set by the firmware */ data->hw.init = &init;
ret = raspberrypi_clock_property(rpi->firmware,
ret = raspberrypi_clock_property(rpi->firmware, data,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE, RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&min_rate); &min_rate);
if (ret) { if (ret) {
dev_err(rpi->dev, "Failed to get %s min freq: %d\n", dev_err(rpi->dev, "Failed to get clock %d min freq: %d",
init.name, ret); id, ret);
return 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_GET_MAX_CLOCK_RATE,
RPI_FIRMWARE_ARM_CLK_ID,
&max_rate); &max_rate);
if (ret) { if (ret) {
dev_err(rpi->dev, "Failed to get %s max freq: %d\n", dev_err(rpi->dev, "Failed to get clock %d max freq: %d\n",
init.name, ret); id, ret);
return ret; return ERR_PTR(ret);
} }
if (!min_rate || !max_rate) { ret = devm_clk_hw_register(rpi->dev, &data->hw);
dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n", if (ret)
min_rate, max_rate); return ERR_PTR(ret);
return -EINVAL;
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", return &data->hw;
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);
} }
static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) struct rpi_firmware_get_clocks_response {
{ u32 parent;
rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev, u32 id;
"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);
}
rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
if (!rpi->pllb_arm_lookup) { struct clk_hw_onecell_data *data)
dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); {
clk_hw_unregister_fixed_factor(rpi->pllb_arm); 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; 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:
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; return 0;
@ -249,14 +291,23 @@ static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
static int raspberrypi_clk_probe(struct platform_device *pdev) static int raspberrypi_clk_probe(struct platform_device *pdev)
{ {
struct clk_hw_onecell_data *clk_data;
struct device_node *firmware_node; struct device_node *firmware_node;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rpi_firmware *firmware; struct rpi_firmware *firmware;
struct raspberrypi_clk *rpi; struct raspberrypi_clk *rpi;
int ret; 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) { if (!firmware_node) {
dev_err(dev, "Missing firmware node\n"); dev_err(dev, "Missing firmware node\n");
return -ENOENT; return -ENOENT;
@ -275,13 +326,18 @@ static int raspberrypi_clk_probe(struct platform_device *pdev)
rpi->firmware = firmware; rpi->firmware = firmware;
platform_set_drvdata(pdev, rpi); platform_set_drvdata(pdev, rpi);
ret = raspberrypi_register_pllb(rpi); clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
if (ret) { RPI_FIRMWARE_NUM_CLK_ID),
dev_err(dev, "Failed to initialize pllb, %d\n", ret); GFP_KERNEL);
return ret; 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) if (ret)
return ret; return ret;
@ -300,9 +356,16 @@ static int raspberrypi_clk_remove(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver raspberrypi_clk_driver = {
.driver = { .driver = {
.name = "raspberrypi-clk", .name = "raspberrypi-clk",
.of_match_table = raspberrypi_clk_match,
}, },
.probe = raspberrypi_clk_probe, .probe = raspberrypi_clk_probe,
.remove = raspberrypi_clk_remove, .remove = raspberrypi_clk_remove,

View File

@ -208,6 +208,20 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
static void rpi_register_clk_driver(struct device *dev) static void rpi_register_clk_driver(struct device *dev)
{ {
struct device_node *firmware;
/*
* Earlier DTs don't have a node for the firmware clocks but
* rely on us creating a platform device by hand. If we do
* have a node for the firmware clocks, just bail out here.
*/
firmware = of_get_compatible_child(dev->of_node,
"raspberrypi,firmware-clocks");
if (firmware) {
of_node_put(firmware);
return;
}
rpi_clk = platform_device_register_data(dev, "raspberrypi-clk", rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
-1, NULL, 0); -1, NULL, 0);
} }

View File

@ -11,6 +11,7 @@
* Maxime Ripard <maxime.ripard@free-electrons.com> * Maxime Ripard <maxime.ripard@free-electrons.com>
*/ */
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
@ -18,10 +19,9 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "reset-simple.h"
static inline struct reset_simple_data * static inline struct reset_simple_data *
to_reset_simple_data(struct reset_controller_dev *rcdev) to_reset_simple_data(struct reset_controller_dev *rcdev)
{ {
@ -64,6 +64,24 @@ static int reset_simple_deassert(struct reset_controller_dev *rcdev,
return reset_simple_update(rcdev, id, false); return reset_simple_update(rcdev, id, false);
} }
static int reset_simple_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct reset_simple_data *data = to_reset_simple_data(rcdev);
int ret;
if (!data->reset_us)
return -ENOTSUPP;
ret = reset_simple_assert(rcdev, id);
if (ret)
return ret;
usleep_range(data->reset_us, data->reset_us * 2);
return reset_simple_deassert(rcdev, id);
}
static int reset_simple_status(struct reset_controller_dev *rcdev, static int reset_simple_status(struct reset_controller_dev *rcdev,
unsigned long id) unsigned long id)
{ {
@ -81,6 +99,7 @@ static int reset_simple_status(struct reset_controller_dev *rcdev,
const struct reset_control_ops reset_simple_ops = { const struct reset_control_ops reset_simple_ops = {
.assert = reset_simple_assert, .assert = reset_simple_assert,
.deassert = reset_simple_deassert, .deassert = reset_simple_deassert,
.reset = reset_simple_reset,
.status = reset_simple_status, .status = reset_simple_status,
}; };
EXPORT_SYMBOL_GPL(reset_simple_ops); EXPORT_SYMBOL_GPL(reset_simple_ops);

View File

@ -11,13 +11,12 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/socfpga.h> #include <linux/reset/socfpga.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include "reset-simple.h"
#define SOCFPGA_NR_BANKS 8 #define SOCFPGA_NR_BANKS 8
static int a10_reset_init(struct device_node *np) static int a10_reset_init(struct device_node *np)

View File

@ -14,13 +14,12 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/reset/reset-simple.h>
#include <linux/reset/sunxi.h> #include <linux/reset/sunxi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include "reset-simple.h"
static int sunxi_reset_init(struct device_node *np) static int sunxi_reset_init(struct device_node *np)
{ {
struct reset_simple_data *data; struct reset_simple_data *data;

View File

@ -9,8 +9,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/reset/reset-simple.h>
#include "reset-simple.h"
#define MAX_CLKS 2 #define MAX_CLKS 2
#define MAX_RSTS 2 #define MAX_RSTS 2

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM3368_H
#define __DT_BINDINGS_CLOCK_BCM3368_H
#define BCM3368_CLK_MAC 3
#define BCM3368_CLK_TC 5
#define BCM3368_CLK_US_TOP 6
#define BCM3368_CLK_DS_TOP 7
#define BCM3368_CLK_ACM 8
#define BCM3368_CLK_SPI 9
#define BCM3368_CLK_USBS 10
#define BCM3368_CLK_BMU 11
#define BCM3368_CLK_PCM 12
#define BCM3368_CLK_NTP 13
#define BCM3368_CLK_ACP_B 14
#define BCM3368_CLK_ACP_A 15
#define BCM3368_CLK_EMUSB 17
#define BCM3368_CLK_ENET0 18
#define BCM3368_CLK_ENET1 19
#define BCM3368_CLK_USBSU 20
#define BCM3368_CLK_EPHY 21
#endif /* __DT_BINDINGS_CLOCK_BCM3368_H */

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6318_H
#define __DT_BINDINGS_CLOCK_BCM6318_H
#define BCM6318_CLK_ADSL_ASB 0
#define BCM6318_CLK_USB_ASB 1
#define BCM6318_CLK_MIPS_ASB 2
#define BCM6318_CLK_PCIE_ASB 3
#define BCM6318_CLK_PHYMIPS_ASB 4
#define BCM6318_CLK_ROBOSW_ASB 5
#define BCM6318_CLK_SAR_ASB 6
#define BCM6318_CLK_SDR_ASB 7
#define BCM6318_CLK_SWREG_ASB 8
#define BCM6318_CLK_PERIPH_ASB 9
#define BCM6318_CLK_CPUBUS160 10
#define BCM6318_CLK_ADSL 11
#define BCM6318_CLK_SAR125 12
#define BCM6318_CLK_MIPS 13
#define BCM6318_CLK_PCIE 14
#define BCM6318_CLK_ROBOSW250 16
#define BCM6318_CLK_ROBOSW025 17
#define BCM6318_CLK_SDR 19
#define BCM6318_CLK_USBD 20
#define BCM6318_CLK_HSSPI 25
#define BCM6318_CLK_PCIE25 27
#define BCM6318_CLK_PHYMIPS 28
#define BCM6318_CLK_AFE 29
#define BCM6318_CLK_QPROC 30
#define BCM6318_UCLK_ADSL 0
#define BCM6318_UCLK_ARB 1
#define BCM6318_UCLK_MIPS 2
#define BCM6318_UCLK_PCIE 3
#define BCM6318_UCLK_PERIPH 4
#define BCM6318_UCLK_PHYMIPS 5
#define BCM6318_UCLK_ROBOSW 6
#define BCM6318_UCLK_SAR 7
#define BCM6318_UCLK_SDR 8
#define BCM6318_UCLK_USB 9
#endif /* __DT_BINDINGS_CLOCK_BCM6318_H */

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM63268_H
#define __DT_BINDINGS_CLOCK_BCM63268_H
#define BCM63268_CLK_DIS_GLESS 0
#define BCM63268_CLK_VDSL_QPROC 1
#define BCM63268_CLK_VDSL_AFE 2
#define BCM63268_CLK_VDSL 3
#define BCM63268_CLK_MIPS 4
#define BCM63268_CLK_WLAN_OCP 5
#define BCM63268_CLK_DECT 6
#define BCM63268_CLK_FAP0 7
#define BCM63268_CLK_FAP1 8
#define BCM63268_CLK_SAR 9
#define BCM63268_CLK_ROBOSW 10
#define BCM63268_CLK_PCM 11
#define BCM63268_CLK_USBD 12
#define BCM63268_CLK_USBH 13
#define BCM63268_CLK_IPSEC 14
#define BCM63268_CLK_SPI 15
#define BCM63268_CLK_HSSPI 16
#define BCM63268_CLK_PCIE 17
#define BCM63268_CLK_PHYMIPS 18
#define BCM63268_CLK_GMAC 19
#define BCM63268_CLK_NAND 20
#define BCM63268_CLK_TBUS 27
#define BCM63268_CLK_ROBOSW250 31
#endif /* __DT_BINDINGS_CLOCK_BCM63268_H */

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6328_H
#define __DT_BINDINGS_CLOCK_BCM6328_H
#define BCM6328_CLK_PHYMIPS 0
#define BCM6328_CLK_ADSL_QPROC 1
#define BCM6328_CLK_ADSL_AFE 2
#define BCM6328_CLK_ADSL 3
#define BCM6328_CLK_MIPS 4
#define BCM6328_CLK_SAR 5
#define BCM6328_CLK_PCM 6
#define BCM6328_CLK_USBD 7
#define BCM6328_CLK_USBH 8
#define BCM6328_CLK_HSSPI 9
#define BCM6328_CLK_PCIE 10
#define BCM6328_CLK_ROBOSW 11
#endif /* __DT_BINDINGS_CLOCK_BCM6328_H */

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6358_H
#define __DT_BINDINGS_CLOCK_BCM6358_H
#define BCM6358_CLK_ENET 4
#define BCM6358_CLK_ADSLPHY 5
#define BCM6358_CLK_PCM 8
#define BCM6358_CLK_SPI 9
#define BCM6358_CLK_USBS 10
#define BCM6358_CLK_SAR 11
#define BCM6358_CLK_EMUSB 17
#define BCM6358_CLK_ENET0 18
#define BCM6358_CLK_ENET1 19
#define BCM6358_CLK_USBSU 20
#define BCM6358_CLK_EPHY 21
#endif /* __DT_BINDINGS_CLOCK_BCM6358_H */

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6362_H
#define __DT_BINDINGS_CLOCK_BCM6362_H
#define BCM6362_CLK_ADSL_QPROC 1
#define BCM6362_CLK_ADSL_AFE 2
#define BCM6362_CLK_ADSL 3
#define BCM6362_CLK_MIPS 4
#define BCM6362_CLK_WLAN_OCP 5
#define BCM6362_CLK_SWPKT_USB 7
#define BCM6362_CLK_SWPKT_SAR 8
#define BCM6362_CLK_SAR 9
#define BCM6362_CLK_ROBOSW 10
#define BCM6362_CLK_PCM 11
#define BCM6362_CLK_USBD 12
#define BCM6362_CLK_USBH 13
#define BCM6362_CLK_IPSEC 14
#define BCM6362_CLK_SPI 15
#define BCM6362_CLK_HSSPI 16
#define BCM6362_CLK_PCIE 17
#define BCM6362_CLK_FAP 18
#define BCM6362_CLK_PHYMIPS 19
#define BCM6362_CLK_NAND 20
#endif /* __DT_BINDINGS_CLOCK_BCM6362_H */

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __DT_BINDINGS_CLOCK_BCM6368_H
#define __DT_BINDINGS_CLOCK_BCM6368_H
#define BCM6368_CLK_VDSL_QPROC 2
#define BCM6368_CLK_VDSL_AFE 3
#define BCM6368_CLK_VDSL_BONDING 4
#define BCM6368_CLK_VDSL 5
#define BCM6368_CLK_PHYMIPS 6
#define BCM6368_CLK_SWPKT_USB 7
#define BCM6368_CLK_SWPKT_SAR 8
#define BCM6368_CLK_SPI 9
#define BCM6368_CLK_USBD 10
#define BCM6368_CLK_SAR 11
#define BCM6368_CLK_ROBOSW 12
#define BCM6368_CLK_UTOPIA 13
#define BCM6368_CLK_PCM 14
#define BCM6368_CLK_USBH 15
#define BCM6368_CLK_DIS_GLESS 16
#define BCM6368_CLK_NAND 17
#define BCM6368_CLK_IPSEC 18
#endif /* __DT_BINDINGS_CLOCK_BCM6368_H */

View File

@ -27,6 +27,12 @@
* @status_active_low: if true, bits read back as cleared while the reset is * @status_active_low: if true, bits read back as cleared while the reset is
* asserted. Otherwise, bits read back as set while the * asserted. Otherwise, bits read back as set while the
* reset is asserted. * reset is asserted.
* @reset_us: Minimum delay in microseconds needed that needs to be
* waited for between an assert and a deassert to reset the
* device. If multiple consumers with different delay
* requirements are connected to this controller, it must
* be the largest minimum delay. 0 means that such a delay is
* unknown and the reset operation is unsupported.
*/ */
struct reset_simple_data { struct reset_simple_data {
spinlock_t lock; spinlock_t lock;
@ -34,6 +40,7 @@ struct reset_simple_data {
struct reset_controller_dev rcdev; struct reset_controller_dev rcdev;
bool active_low; bool active_low;
bool status_active_low; bool status_active_low;
unsigned int reset_us;
}; };
extern const struct reset_control_ops reset_simple_ops; extern const struct reset_control_ops reset_simple_ops;