Hi,
We replace fixed clocks as declared in the initial platform support
series [1] by read-only clocks exposed by the clock driver implemented
here. Write-ability is supported by the hardware but not implemented,
it could be added later-on if the need appears.
We expose ten PLLs that derive directly from the main crystal. Also, a
divider clock is exposed as a child clock of one of the PLLs.
The platform devicetree has many more clock nodes but those are
fixed-factors that are not hardware controllable; we therefore do not
deal with them.
This is V2. Full changelog below. Major changes are:
- Switch to a platform driver.
- Switch to declaring PLLs as fixed-factor.
- Point to the parent clk using the fw_name field in clk_parent_data.
- The above two points means we add support in fixed-factor to (1) allow
fixed accuracy rather than parent accuracy and (2) add new register
prototypes to point to the parent clk using fw_name.
[1]: https://lore.kernel.org/lkml/[email protected]/
Have a nice day,
Théo Lebrun
Signed-off-by: Théo Lebrun <[email protected]>
---
Changes in v2:
- Drop [PATCH 1/5] that was taken by Stephen for clk-next.
- Add accuracy support to fixed-factor that is enabled with a flag.
Register prototypes were added to exploit this feature.
- Add fw_name support to fixed-factor. This allows pointing to parent
clocks using the value in `clock-names` in the DT. Register
prototypes were added for that.
- Bindings were modified to be less dumb: a binding was added for OLB
and the clock-controller is a child property of it. Removed the
possibility of pointing to OLB using a phandle. $nodename is the
generic `clock-controller` and not custom `clocks`. Fix dt-bindings
examples.
- Fix commit message for the driver patch. Add details, remove useless
fluff.
- Squash both driver commits together.
- Declare a platform_driver instead of using CLK_OF_DECLARE_DRIVER. This
also means using `dev_*` for logging, removing `pr_fmt`. We add a
pointer to device in the private structure.
- Use fixed-factor instead of fixed-rate for PLLs. We don't grab a
reference to the parent clk, instead using newly added fixed-factor
register prototypes and fwname.
- NULL is not an error when registering PLLs anymore.
- Now checking the return value of of_clk_add_hw_provider for errors.
- Fix includes.
- Remove defensive conditional at start of eq5c_pll_parse_registers.
- Rename clk_hw_to_ospi_priv to clk_to_priv to avoid confusion: it is
not part of the clk_hw_* family of symbols.
- Fix negative returns in eq5c_ospi_div_set_rate. It was a typo
highlighted by Stephen Boyd.
- Declare eq5c_ospi_div_ops as static.
- In devicetree, move the OLB node prior to the UARTs, as platform
device probe scheduling is dependent on devicetree ordering. This is
required to declare the driver as a platform driver, else it
CLK_OF_DECLARE_DRIVER is required.
- In device, create a core0-timer-clk fixed clock to feed to the GIC
timer. It requires a clock earlier than platform bus type init.
- Link to v1: https://lore.kernel.org/r/[email protected]
---
Théo Lebrun (6):
clk: fixed-factor: add optional accuracy support
clk: fixed-factor: add fwname-based constructor functions
dt-bindings: soc: mobileye: add EyeQ5 OLB system controller
dt-bindings: clock: mobileye,eyeq5-clk: add bindings
clk: eyeq5: add platform driver
MIPS: mobileye: eyeq5: use OLB clocks controller
.../bindings/clock/mobileye,eyeq5-clk.yaml | 50 +++
.../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 48 +++
MAINTAINERS | 4 +
.../{eyeq5-fixed-clocks.dtsi => eyeq5-clocks.dtsi} | 54 ++--
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 23 +-
drivers/clk/Kconfig | 11 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-eyeq5.c | 348 +++++++++++++++++++++
drivers/clk/clk-fixed-factor.c | 94 +++++-
include/dt-bindings/clock/mobileye,eyeq5-clk.h | 22 ++
include/linux/clk-provider.h | 26 +-
11 files changed, 621 insertions(+), 60 deletions(-)
---
base-commit: daf471f1ce94536da77948fac81d5c85ae12dbfa
change-id: 20231023-mbly-clk-87ce5c241f08
Best regards,
--
Théo Lebrun <[email protected]>
Add documentation to describe the "Other Logic Block" syscon.
Signed-off-by: Théo Lebrun <[email protected]>
---
.../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 45 insertions(+)
diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
new file mode 100644
index 000000000000..b148a49b08f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mobileye EyeQ5 SoC system controller
+
+maintainers:
+ - Grégory Clement <[email protected]>
+ - Théo Lebrun <[email protected]>
+ - Vladimir Kondratiev <[email protected]>
+
+description:
+ OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
+ resets, pinctrl are being handled from here.
+
+properties:
+ compatible:
+ items:
+ - const: mobileye,eyeq5-olb
+ - const: syscon
+ - const: simple-mfd
+
+ reg:
+ maxItems: 1
+
+ reg-io-width:
+ const: 4
+
+required:
+ - compatible
+ - reg
+ - reg-io-width
+
+additionalProperties: false
+
+examples:
+ - |
+ olb@e00000 {
+ compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
+ reg = <0xe00000 0x400>;
+ reg-io-width = <4>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 4a7bd6b40d74..d955b1e80e53 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14553,6 +14553,7 @@ M: Théo Lebrun <[email protected]>
L: [email protected]
S: Maintained
F: Documentation/devicetree/bindings/mips/mobileye.yaml
+F: Documentation/devicetree/bindings/soc/mobileye/
F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/generic/board-eyeq5.config
F: arch/mips/generic/board-epm5.its.S
--
2.43.0
Fixed factor clock reports the parent clock accuracy. Add flags and acc fields
to `struct clk_fixed_factor` to support setting a fixed accuracy. The default
if no flag is set is not changed: use the parent clock accuracy.
Signed-off-by: Théo Lebrun <[email protected]>
---
drivers/clk/clk-fixed-factor.c | 28 +++++++++++++++++++++-------
include/linux/clk-provider.h | 12 +++++++++++-
2 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index b3e66202b942..bc2644a9bd7d 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -57,10 +57,22 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
+static unsigned long clk_factor_recalc_accuracy(struct clk_hw *hw,
+ unsigned long parent_accuracy)
+{
+ struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+
+ if (fix->flags & CLK_FIXED_FACTOR_FIXED_ACCURACY)
+ return fix->acc;
+
+ return parent_accuracy;
+}
+
const struct clk_ops clk_fixed_factor_ops = {
.round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate,
.recalc_rate = clk_factor_recalc_rate,
+ .recalc_accuracy = clk_factor_recalc_accuracy,
};
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
@@ -81,7 +93,7 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
const char *name, const char *parent_name,
const struct clk_hw *parent_hw, int index,
unsigned long flags, unsigned int mult, unsigned int div,
- bool devm)
+ unsigned long acc, unsigned int fixflags, bool devm)
{
struct clk_fixed_factor *fix;
struct clk_init_data init = { };
@@ -105,6 +117,8 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
fix->mult = mult;
fix->div = div;
fix->hw.init = &init;
+ fix->acc = acc;
+ fix->flags = fixflags;
init.name = name;
init.ops = &clk_fixed_factor_ops;
@@ -152,7 +166,7 @@ struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
unsigned int mult, unsigned int div)
{
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, index,
- flags, mult, div, true);
+ flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
@@ -174,7 +188,7 @@ struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev,
unsigned long flags, unsigned int mult, unsigned int div)
{
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw,
- -1, flags, mult, div, true);
+ -1, flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw);
@@ -184,7 +198,7 @@ struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev,
{
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL,
parent_hw, -1, flags, mult, div,
- false);
+ 0, 0, false);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw);
@@ -193,7 +207,7 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
unsigned int mult, unsigned int div)
{
return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
- flags, mult, div, false);
+ flags, mult, div, 0, 0, false);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
@@ -240,7 +254,7 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
unsigned int mult, unsigned int div)
{
return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
- flags, mult, div, true);
+ flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor);
@@ -267,7 +281,7 @@ static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, NULL, 0,
- 0, mult, div, false);
+ 0, mult, div, 0, 0, false);
if (IS_ERR(hw)) {
/*
* Clear OF_POPULATED flag so that clock registration can be
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1293c38ddb7f..7ddc952c8c67 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -1084,18 +1084,28 @@ void of_fixed_factor_clk_setup(struct device_node *node);
* @hw: handle between common and hardware-specific interfaces
* @mult: multiplier
* @div: divider
+ * @acc: fixed accuracy in ppb
+ * @flags: behavior modifying flags
*
* Clock with a fixed multiplier and divider. The output frequency is the
* parent clock rate divided by div and multiplied by mult.
- * Implements .recalc_rate, .set_rate and .round_rate
+ * Implements .recalc_rate, .set_rate, .round_rate and .recalc_accuracy
+ *
+ * Flags:
+ * * CLK_FIXED_FACTOR_FIXED_ACCURACY - Use the value in @acc instead of the
+ * parent clk accuracy.
*/
struct clk_fixed_factor {
struct clk_hw hw;
unsigned int mult;
unsigned int div;
+ unsigned long acc;
+ unsigned int flags;
};
+#define CLK_FIXED_FACTOR_FIXED_ACCURACY BIT(0)
+
#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
extern const struct clk_ops clk_fixed_factor_ops;
--
2.43.0
Add four functions to register clk_hw based on the fw_name field in
clk_parent_data, ie the value in the DT property `clock-names`.
There are variants for devm or not and passing an accuracy or not
passing one:
- clk_hw_register_fixed_factor_fwname
- clk_hw_register_fixed_factor_with_accuracy_fwname
- devm_clk_hw_register_fixed_factor_fwname
- devm_clk_hw_register_fixed_factor_with_accuracy_fwname
The `struct clk_parent_data` init is extracted from
__clk_hw_register_fixed_factor to each calling function. It is required
to allow each function to pass whatever field they want, not only index.
Signed-off-by: Théo Lebrun <[email protected]>
---
drivers/clk/clk-fixed-factor.c | 76 ++++++++++++++++++++++++++++++++++--------
include/linux/clk-provider.h | 14 ++++++++
2 files changed, 76 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index bc2644a9bd7d..5fa03ae1bbdb 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -91,13 +91,12 @@ static void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *
static struct clk_hw *
__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
const char *name, const char *parent_name,
- const struct clk_hw *parent_hw, int index,
+ const struct clk_hw *parent_hw, const struct clk_parent_data *pdata,
unsigned long flags, unsigned int mult, unsigned int div,
unsigned long acc, unsigned int fixflags, bool devm)
{
struct clk_fixed_factor *fix;
struct clk_init_data init = { };
- struct clk_parent_data pdata = { .index = index };
struct clk_hw *hw;
int ret;
@@ -128,7 +127,7 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
else if (parent_hw)
init.parent_hws = &parent_hw;
else
- init.parent_data = &pdata;
+ init.parent_data = pdata;
init.num_parents = 1;
hw = &fix->hw;
@@ -165,7 +164,8 @@ struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
const char *name, unsigned int index, unsigned long flags,
unsigned int mult, unsigned int div)
{
- return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, index,
+ const struct clk_parent_data pdata = { .index = index };
+ return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, &pdata,
flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
@@ -187,8 +187,9 @@ struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev,
const char *name, const struct clk_hw *parent_hw,
unsigned long flags, unsigned int mult, unsigned int div)
{
+ const struct clk_parent_data pdata = { .index = -1 };
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw,
- -1, flags, mult, div, 0, 0, true);
+ &pdata, flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw);
@@ -196,9 +197,9 @@ struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev,
const char *name, const struct clk_hw *parent_hw,
unsigned long flags, unsigned int mult, unsigned int div)
{
- return __clk_hw_register_fixed_factor(dev, NULL, name, NULL,
- parent_hw, -1, flags, mult, div,
- 0, 0, false);
+ const struct clk_parent_data pdata = { .index = -1 };
+ return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw,
+ &pdata, flags, mult, div, 0, 0, false);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw);
@@ -206,11 +207,34 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
- return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
- flags, mult, div, 0, 0, false);
+ const struct clk_parent_data pdata = { .index = -1 };
+ return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL,
+ &pdata, flags, mult, div, 0, 0, false);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
+struct clk_hw *clk_hw_register_fixed_factor_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div)
+{
+ const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name };
+ return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL,
+ &pdata, flags, mult, div, 0, 0, false);
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_fwname);
+
+struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div,
+ unsigned long acc)
+{
+ const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name };
+ return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL,
+ &pdata, flags, mult, div, acc,
+ CLK_FIXED_FACTOR_FIXED_ACCURACY, false);
+}
+EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname);
+
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
@@ -253,16 +277,40 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
- return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
- flags, mult, div, 0, 0, true);
+ const struct clk_parent_data pdata = { .index = -1 };
+ return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL,
+ &pdata, flags, mult, div, 0, 0, true);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor);
+struct clk_hw *devm_clk_hw_register_fixed_factor_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div)
+{
+ const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name };
+ return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL,
+ &pdata, flags, mult, div, 0, 0, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_fwname);
+
+struct clk_hw *devm_clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div,
+ unsigned long acc)
+{
+ const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name };
+ return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL,
+ &pdata, flags, mult, div, acc,
+ CLK_FIXED_FACTOR_FIXED_ACCURACY, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_with_accuracy_fwname);
+
#ifdef CONFIG_OF
static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
{
struct clk_hw *hw;
const char *clk_name = node->name;
+ const struct clk_parent_data pdata = { .index = 0 };
u32 div, mult;
int ret;
@@ -280,8 +328,8 @@ static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
- hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, NULL, 0,
- 0, mult, div, 0, 0, false);
+ hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, NULL,
+ &pdata, 0, mult, div, 0, 0, false);
if (IS_ERR(hw)) {
/*
* Clear OF_POPULATED flag so that clock registration can be
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7ddc952c8c67..4a537260f655 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -1116,10 +1116,24 @@ void clk_unregister_fixed_factor(struct clk *clk);
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
+struct clk_hw *clk_hw_register_fixed_factor_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div);
+struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div,
+ unsigned long acc);
void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
+struct clk_hw *devm_clk_hw_register_fixed_factor_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div);
+struct clk_hw *devm_clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev,
+ struct device_node *np, const char *name, const char *fw_name,
+ unsigned long flags, unsigned int mult, unsigned int div,
+ unsigned long acc);
struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
const char *name, unsigned int index, unsigned long flags,
unsigned int mult, unsigned int div);
--
2.43.0
Add DT schema bindings for the EyeQ5 clock controller driver.
Signed-off-by: Théo Lebrun <[email protected]>
---
.../bindings/clock/mobileye,eyeq5-clk.yaml | 50 ++++++++++++++++++++++
.../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 4 ++
MAINTAINERS | 2 +
include/dt-bindings/clock/mobileye,eyeq5-clk.h | 22 ++++++++++
4 files changed, 78 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml b/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml
new file mode 100644
index 000000000000..64b114a52cd9
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mobileye EyeQ5 clock controller
+
+description:
+ The EyeQ5 clock controller handles 10 read-only PLLs derived from the main
+ crystal clock. It also exposes one divider clock, a child of one of the PLLs.
+ Its registers live in a shared region called OLB.
+
+maintainers:
+ - Grégory Clement <[email protected]>
+ - Théo Lebrun <[email protected]>
+ - Vladimir Kondratiev <[email protected]>
+
+properties:
+ compatible:
+ const: mobileye,eyeq5-clk
+
+ "#clock-cells":
+ const: 1
+
+ clocks:
+ maxItems: 1
+ description:
+ Input parent clock to all PLLs. Expected to be the main crystal.
+
+ clock-names:
+ items:
+ - const: ref
+
+required:
+ - compatible
+ - "#clock-cells"
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller {
+ compatible = "mobileye,eyeq5-clk";
+ #clock-cells = <1>;
+ clocks = <&xtal>;
+ clock-names = "ref";
+ };
diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
index b148a49b08f1..b4ba6f0c9f32 100644
--- a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
+++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
@@ -28,6 +28,10 @@ properties:
reg-io-width:
const: 4
+ clock-controller:
+ $ref: /schemas/clock/mobileye,eyeq5-clk.yaml#
+ type: object
+
required:
- compatible
- reg
diff --git a/MAINTAINERS b/MAINTAINERS
index d955b1e80e53..280892bdb5de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14552,11 +14552,13 @@ M: Gregory CLEMENT <[email protected]>
M: Théo Lebrun <[email protected]>
L: [email protected]
S: Maintained
+F: Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml
F: Documentation/devicetree/bindings/mips/mobileye.yaml
F: Documentation/devicetree/bindings/soc/mobileye/
F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/generic/board-eyeq5.config
F: arch/mips/generic/board-epm5.its.S
+F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
F: include/dt-bindings/soc/mobileye,eyeq5.h
MODULE SUPPORT
diff --git a/include/dt-bindings/clock/mobileye,eyeq5-clk.h b/include/dt-bindings/clock/mobileye,eyeq5-clk.h
new file mode 100644
index 000000000000..7aa974354bb6
--- /dev/null
+++ b/include/dt-bindings/clock/mobileye,eyeq5-clk.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2023 Mobileye Vision Technologies Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ5_CLK_H
+#define _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ5_CLK_H
+
+#define EQ5C_PLL_CPU 0
+#define EQ5C_PLL_VMP 1
+#define EQ5C_PLL_PMA 2
+#define EQ5C_PLL_VDI 3
+#define EQ5C_PLL_DDR0 4
+#define EQ5C_PLL_PCI 5
+#define EQ5C_PLL_PER 6
+#define EQ5C_PLL_PMAC 7
+#define EQ5C_PLL_MPC 8
+#define EQ5C_PLL_DDR1 9
+
+#define EQ5C_DIV_OSPI 10
+
+#endif
--
2.43.0
We add the clock controller inside the OLB syscon region and removed
previous fixed devicetree nodes representing PLLs exposed by the clock
controller.
Two quirks are present:
- The OLB node is moved prior to UARTs, as platform device probe
scheduling is dependent on devicetree ordering.
- The core0-timer-clk fixed clock is created to feed the GIC timer. It
requires a clock earlier than platform bus type initialisation (and
therefore platform device init).
Signed-off-by: Théo Lebrun <[email protected]>
---
.../{eyeq5-fixed-clocks.dtsi => eyeq5-clocks.dtsi} | 54 ++++++++--------------
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 23 +++++----
2 files changed, 34 insertions(+), 43 deletions(-)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
similarity index 89%
rename from arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi
rename to arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
index 78f5533a95c6..bbdaa399e408 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
@@ -3,42 +3,26 @@
* Copyright 2023 Mobileye Vision Technologies Ltd.
*/
-/ {
- /* Fixed clock */
- pll_cpu: pll-cpu {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <1500000000>;
- };
+#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
- pll_vdi: pll-vdi {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <1280000000>;
- };
-
- pll_per: pll-per {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <2000000000>;
- };
-
- pll_ddr0: pll-ddr0 {
+/ {
+/* Fixed clock */
+ xtal: xtal {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <1857210000>;
+ clock-frequency = <30000000>;
};
- pll_ddr1: pll-ddr1 {
+ core0_timer_clk: core0-timer-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <1857210000>;
+ clock-frequency = <1500000000>;
};
/* PLL_CPU derivatives */
occ_cpu: occ-cpu {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <1>;
clock-mult = <1>;
@@ -101,7 +85,7 @@ mem_clk: mem-clk {
};
occ_isram: occ-isram {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -115,7 +99,7 @@ isram_clk: isram-clk { /* gate ClkRstGen_isram */
};
occ_dbu: occ-dbu {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <10>;
clock-mult = <1>;
@@ -130,7 +114,7 @@ si_dbu_tp_pclk: si-dbu-tp-pclk { /* gate ClkRstGen_dbu */
/* PLL_VDI derivatives */
occ_vdi: occ-vdi {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -144,7 +128,7 @@ vdi_clk: vdi-clk { /* gate ClkRstGen_vdi */
};
occ_can_ser: occ-can-ser {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <16>;
clock-mult = <1>;
@@ -158,7 +142,7 @@ can_ser_clk: can-ser-clk { /* gate ClkRstGen_can_ser */
};
i2c_ser_clk: i2c-ser-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <20>;
clock-mult = <1>;
@@ -166,7 +150,7 @@ i2c_ser_clk: i2c-ser-clk {
/* PLL_PER derivatives */
occ_periph: occ-periph {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <16>;
clock-mult = <1>;
@@ -225,7 +209,7 @@ gpio_clk: gpio-clk {
};
emmc_sys_clk: emmc-sys-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <10>;
clock-mult = <1>;
@@ -233,7 +217,7 @@ emmc_sys_clk: emmc-sys-clk {
};
ccf_ctrl_clk: ccf-ctrl-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <4>;
clock-mult = <1>;
@@ -241,7 +225,7 @@ ccf_ctrl_clk: ccf-ctrl-clk {
};
occ_mjpeg_core: occ-mjpeg-core {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -265,7 +249,7 @@ mjpeg_core_clk: mjpeg-core-clk { /* gate ClkRstGen_mjpeg_gen */
};
fcmu_a_clk: fcmu-a-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <20>;
clock-mult = <1>;
@@ -273,7 +257,7 @@ fcmu_a_clk: fcmu-a-clk {
};
occ_pci_sys: occ-pci-sys {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <8>;
clock-mult = <1>;
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index d32da8fabe5a..23c67ffbad5b 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -7,7 +7,7 @@
/memreserve/ 0x40000000 0xc0000000; /* DDR32 */
-#include "eyeq5-fixed-clocks.dtsi"
+#include "eyeq5-clocks.dtsi"
/ {
#address-cells = <2>;
@@ -42,6 +42,19 @@ soc: soc {
ranges;
compatible = "simple-bus";
+ olb: olb@e00000 {
+ compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
+ reg = <0 0xe00000 0x0 0x400>;
+ reg-io-width = <4>;
+
+ clocks: clock-controller {
+ compatible = "mobileye,eyeq5-clk";
+ #clock-cells = <1>;
+ clocks = <&xtal>;
+ clock-names = "ref";
+ };
+ };
+
uart0: serial@800000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0 0x800000 0x0 0x1000>;
@@ -72,12 +85,6 @@ uart2: serial@a00000 {
clock-names = "uartclk", "apb_pclk";
};
- olb: olb@e00000 {
- compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
- reg = <0 0xe00000 0x0 0x400>;
- reg-io-width = <4>;
- };
-
gic: interrupt-controller@140000 {
compatible = "mti,gic";
reg = <0x0 0x140000 0x0 0x20000>;
@@ -95,7 +102,7 @@ gic: interrupt-controller@140000 {
timer {
compatible = "mti,gic-timer";
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
- clocks = <&core0_clk>;
+ clocks = <&core0_timer_clk>;
};
};
};
--
2.43.0
Add the Mobileye EyeQ5 clock controller driver. It is specific to this
platform but might grow to add support of other platforms from
Mobileye.
It handles 10 read-only PLLs derived from the main crystal on board. It
exposes a table-based divider clock used for OSPI. Other platform
clocks are not configurable and therefore kept as fixed-factor
devicetree nodes.
Signed-off-by: Théo Lebrun <[email protected]>
---
MAINTAINERS | 1 +
drivers/clk/Kconfig | 11 ++
drivers/clk/Makefile | 1 +
drivers/clk/clk-eyeq5.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 361 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 280892bdb5de..de6f348e8c0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14558,6 +14558,7 @@ F: Documentation/devicetree/bindings/soc/mobileye/
F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/generic/board-eyeq5.config
F: arch/mips/generic/board-epm5.its.S
+F: drivers/clk/clk-eyeq5.c
F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
F: include/dt-bindings/soc/mobileye,eyeq5.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c30d0d396f7a..673439289d48 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -218,6 +218,17 @@ config COMMON_CLK_EN7523
This driver provides the fixed clocks and gates present on Airoha
ARM silicon.
+config COMMON_CLK_EYEQ5
+ bool "Clock driver for the Mobileye EyeQ5 platform"
+ depends on OF
+ depends on SOC_EYEQ5 || COMPILE_TEST
+ default SOC_EYEQ5
+ help
+ This driver provides the fixed clocks found on the Mobileye EyeQ5
+ SoC. Its registers live in a shared register region called OLB.
+ It provides 10 read-only PLLs derived from the main crystal clock which
+ must be constant and one divider clock based on one PLLs.
+
config COMMON_CLK_FSL_FLEXSPI
tristate "Clock driver for FlexSPI on Layerscape SoCs"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index ed71f2e0ee36..0df0dc6dbcae 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
+obj-$(CONFIG_COMMON_CLK_EYEQ5) += clk-eyeq5.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
diff --git a/drivers/clk/clk-eyeq5.c b/drivers/clk/clk-eyeq5.c
new file mode 100644
index 000000000000..4a75fc113fdf
--- /dev/null
+++ b/drivers/clk/clk-eyeq5.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PLL clock driver for the Mobileye EyeQ5 platform.
+ *
+ * This controller handles 10 read-only PLLs, all derived from the same main
+ * crystal clock. It also exposes one divider clock, a child of one of the
+ * PLLs. The parent clock is expected to be constant. This driver is custom to
+ * this platform, its registers live in a shared region called OLB.
+ *
+ * We use eq5c_ as prefix, as-in "EyeQ5 Clock", but way shorter.
+ *
+ * Copyright (C) 2023 Mobileye Vision Technologies Ltd.
+ */
+#include <linux/bits.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
+
+/*
+ * PLL control & status registers, n=0..1
+ * 0x02c..0x078
+ */
+#define OLB_PCSR_CPU(n) (0x02C + (n) * 4) /* CPU */
+#define OLB_PCSR_VMP(n) (0x034 + (n) * 4) /* VMP */
+#define OLB_PCSR_PMA(n) (0x03C + (n) * 4) /* PMA */
+#define OLB_PCSR_VDI(n) (0x044 + (n) * 4) /* VDI */
+#define OLB_PCSR_DDR0(n) (0x04C + (n) * 4) /* DDR0 */
+#define OLB_PCSR_PCI(n) (0x054 + (n) * 4) /* PCI */
+#define OLB_PCSR_PER(n) (0x05C + (n) * 4) /* PER */
+#define OLB_PCSR_PMAC(n) (0x064 + (n) * 4) /* PMAC */
+#define OLB_PCSR_MPC(n) (0x06c + (n) * 4) /* MPC */
+#define OLB_PCSR_DDR1(n) (0x074 + (n) * 4) /* DDR1 */
+
+/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */
+#define OLB_PCSR0_DAC_EN BIT(0)
+/* Fractional or integer mode */
+#define OLB_PCSR0_DSM_EN BIT(1)
+#define OLB_PCSR0_PLL_EN BIT(2)
+/* All clocks output held at 0 */
+#define OLB_PCSR0_FOUTPOSTDIV_EN BIT(3)
+#define OLB_PCSR0_POST_DIV1 GENMASK(6, 4)
+#define OLB_PCSR0_POST_DIV2 GENMASK(9, 7)
+#define OLB_PCSR0_REF_DIV GENMASK(15, 10)
+#define OLB_PCSR0_INTIN GENMASK(27, 16)
+#define OLB_PCSR0_BYPASS BIT(28)
+/* Bits 30..29 are reserved */
+#define OLB_PCSR0_PLL_LOCKED BIT(31)
+
+#define OLB_PCSR1_RESET BIT(0)
+#define OLB_PCSR1_SSGC_DIV GENMASK(4, 1)
+/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */
+#define OLB_PCSR1_SPREAD GENMASK(9, 5)
+#define OLB_PCSR1_DIS_SSCG BIT(10)
+/* Down-spread or center-spread */
+#define OLB_PCSR1_DOWN_SPREAD BIT(11)
+#define OLB_PCSR1_FRAC_IN GENMASK(31, 12)
+
+static const struct eq5c_pll {
+ const char *name;
+ u32 reg;
+} eq5c_plls[] = {
+ [EQ5C_PLL_CPU] = { .name = "pll-cpu", .reg = OLB_PCSR_CPU(0), },
+ [EQ5C_PLL_VMP] = { .name = "pll-vmp", .reg = OLB_PCSR_VMP(0), },
+ [EQ5C_PLL_PMA] = { .name = "pll-pma", .reg = OLB_PCSR_PMA(0), },
+ [EQ5C_PLL_VDI] = { .name = "pll-vdi", .reg = OLB_PCSR_VDI(0), },
+ [EQ5C_PLL_DDR0] = { .name = "pll-ddr0", .reg = OLB_PCSR_DDR0(0), },
+ [EQ5C_PLL_PCI] = { .name = "pll-pci", .reg = OLB_PCSR_PCI(0), },
+ [EQ5C_PLL_PER] = { .name = "pll-per", .reg = OLB_PCSR_PER(0), },
+ [EQ5C_PLL_PMAC] = { .name = "pll-pmac", .reg = OLB_PCSR_PMAC(0), },
+ [EQ5C_PLL_MPC] = { .name = "pll-mpc", .reg = OLB_PCSR_MPC(0), },
+ [EQ5C_PLL_DDR1] = { .name = "pll-ddr1", .reg = OLB_PCSR_DDR1(0), },
+};
+
+#define EQ5C_OSPI_DIV_CLK_NAME "div-ospi"
+
+static int eq5c_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult,
+ unsigned long *div, unsigned long *acc)
+{
+ if (r0 & OLB_PCSR0_BYPASS) {
+ *mult = 1;
+ *div = 1;
+ *acc = 0;
+ return 0;
+ }
+
+ if (!(r0 & OLB_PCSR0_PLL_LOCKED))
+ return -EINVAL;
+
+ *mult = FIELD_GET(OLB_PCSR0_INTIN, r0);
+ *div = FIELD_GET(OLB_PCSR0_REF_DIV, r0);
+ if (r0 & OLB_PCSR0_FOUTPOSTDIV_EN)
+ *div *= FIELD_GET(OLB_PCSR0_POST_DIV1, r0) *
+ FIELD_GET(OLB_PCSR0_POST_DIV2, r0);
+
+ /* Fractional mode, in 2^20 (0x100000) parts. */
+ if (r0 & OLB_PCSR0_DSM_EN) {
+ *div *= 0x100000;
+ *mult = *mult * 0x100000 + FIELD_GET(OLB_PCSR1_FRAC_IN, r1);
+ }
+
+ if (!*mult || !*div)
+ return -EINVAL;
+
+ /* Spread spectrum. */
+ if (!(r1 & (OLB_PCSR1_RESET | OLB_PCSR1_DIS_SSCG))) {
+ /*
+ * Spread is 1/1000 parts of frequency, accuracy is half of
+ * that. To get accuracy, convert to ppb (parts per billion).
+ */
+ u32 spread = FIELD_GET(OLB_PCSR1_SPREAD, r1);
+ *acc = spread * 500000;
+ if (r1 & OLB_PCSR1_DOWN_SPREAD) {
+ /*
+ * Downspreading: the central frequency is half a
+ * spread lower.
+ */
+ *mult *= 2000 - spread;
+ *div *= 2000;
+ }
+ } else {
+ *acc = 0;
+ }
+
+ return 0;
+}
+
+#define OLB_OSPI_REG 0x11C
+#define OLB_OSPI_DIV_MASK GENMASK(3, 0)
+#define OLB_OSPI_DIV_MASK_WIDTH 4
+
+static const struct clk_div_table eq5c_ospi_div_table[] = {
+ { .val = 0, .div = 2 },
+ { .val = 1, .div = 4 },
+ { .val = 2, .div = 6 },
+ { .val = 3, .div = 8 },
+ { .val = 4, .div = 10 },
+ { .val = 5, .div = 12 },
+ { .val = 6, .div = 14 },
+ { .val = 7, .div = 16 },
+ {} /* sentinel */
+};
+
+struct eq5c_ospi_div {
+ struct clk_hw hw;
+ struct device *dev;
+ struct regmap *olb;
+};
+
+static struct eq5c_ospi_div *clk_to_priv(struct clk_hw *hw)
+{
+ return container_of(hw, struct eq5c_ospi_div, hw);
+}
+
+static unsigned long eq5c_ospi_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct eq5c_ospi_div *div = clk_to_priv(hw);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(div->olb, OLB_OSPI_REG, &val);
+
+ if (ret) {
+ dev_err(div->dev, "regmap_read failed: %d\n", ret);
+ return 0;
+ }
+
+ val = FIELD_GET(OLB_OSPI_DIV_MASK, val);
+
+ return divider_recalc_rate(hw, parent_rate, val,
+ eq5c_ospi_div_table, 0,
+ OLB_OSPI_DIV_MASK_WIDTH);
+}
+
+static long eq5c_ospi_div_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *prate)
+{
+ return divider_round_rate(hw, rate, prate, eq5c_ospi_div_table,
+ OLB_OSPI_DIV_MASK_WIDTH, 0);
+}
+
+static int eq5c_ospi_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ return divider_determine_rate(hw, req, eq5c_ospi_div_table,
+ OLB_OSPI_DIV_MASK_WIDTH, 0);
+}
+
+static int eq5c_ospi_div_set_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct eq5c_ospi_div *div = clk_to_priv(hw);
+ unsigned int val;
+ int value, ret;
+
+ value = divider_get_val(rate, parent_rate, eq5c_ospi_div_table,
+ OLB_OSPI_DIV_MASK_WIDTH, 0);
+ if (value < 0)
+ return value;
+
+ ret = regmap_read(div->olb, OLB_OSPI_REG, &val);
+ if (ret) {
+ dev_err(div->dev, "regmap_read failed: %d\n", ret);
+ return ret;
+ }
+
+ val &= ~OLB_OSPI_DIV_MASK;
+ val |= FIELD_PREP(OLB_OSPI_DIV_MASK, value);
+
+ ret = regmap_write(div->olb, OLB_OSPI_REG, val);
+ if (ret) {
+ dev_err(div->dev, "regmap_write failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct clk_ops eq5c_ospi_div_ops = {
+ .recalc_rate = eq5c_ospi_div_recalc_rate,
+ .round_rate = eq5c_ospi_div_round_rate,
+ .determine_rate = eq5c_ospi_div_determine_rate,
+ .set_rate = eq5c_ospi_div_set_rate,
+};
+
+static struct clk_hw *eq5c_init_ospi_div(struct device *dev,
+ const struct clk_hw *parent,
+ struct regmap *olb)
+{
+ struct eq5c_ospi_div *div;
+ int ret;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOENT);
+
+ div->dev = dev;
+ div->olb = olb;
+ div->hw.init = CLK_HW_INIT_HW(EQ5C_OSPI_DIV_CLK_NAME, parent,
+ &eq5c_ospi_div_ops, 0);
+
+ ret = clk_hw_register(dev, &div->hw);
+ if (ret) {
+ dev_err(dev, "failed registering div_ospi: %d\n", ret);
+ kfree(div);
+ return ERR_PTR(ret);
+ }
+
+ return &div->hw;
+}
+
+static int eq5c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *parent_np = of_get_parent(np);
+ struct clk_hw_onecell_data *data;
+ struct regmap *olb;
+ size_t nb_clks;
+ int i, ret;
+
+ nb_clks = ARRAY_SIZE(eq5c_plls) + 1;
+ data = kzalloc(struct_size(data, hws, nb_clks), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->num = nb_clks;
+
+ /*
+ * TODO: currently, if OLB is not available, we log an error and early
+ * return. We might want to change this behavior and assume all clocks
+ * are in bypass mode; that is what is being done in the vendor driver.
+ *
+ * It is still unclear if there are valid situations where the OLB
+ * region would be inaccessible.
+ */
+ olb = ERR_PTR(-ENODEV);
+ if (parent_np)
+ olb = syscon_node_to_regmap(parent_np);
+ if (IS_ERR(olb)) {
+ dev_err(dev, "failed getting regmap: %ld\n", PTR_ERR(olb));
+ return PTR_ERR(olb);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(eq5c_plls); i++) {
+ const struct eq5c_pll *pll = &eq5c_plls[i];
+ unsigned long mult, div, acc;
+ u32 r0, r1;
+ int ret;
+
+ regmap_read(olb, pll->reg, &r0);
+ regmap_read(olb, pll->reg + sizeof(r0), &r1);
+
+ ret = eq5c_pll_parse_registers(r0, r1, &mult, &div, &acc);
+ if (ret) {
+ dev_warn(dev, "failed parsing state of %s\n", pll->name);
+ continue;
+ }
+
+ data->hws[i] = devm_clk_hw_register_fixed_factor_with_accuracy_fwname(
+ dev, np, pll->name, "ref", 0, mult, div, acc);
+ if (IS_ERR(data->hws[i])) {
+ dev_err(dev, "failed registering %s: %ld\n",
+ pll->name, PTR_ERR(data->hws[i]));
+ data->hws[i] = ERR_PTR(-ENOENT);
+ }
+ }
+
+ /*
+ * Register the OSPI table-based divider clock manually. This is
+ * equivalent to drivers/clk/clk-divider.c, but using regmap to access
+ * its register.
+ */
+ i = ARRAY_SIZE(eq5c_plls);
+ data->hws[i] = eq5c_init_ospi_div(dev, data->hws[EQ5C_PLL_PER], olb);
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, data);
+ if (ret < 0) {
+ pr_err("failed registering clock provider: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id eq5c_match_table[] = {
+ { .compatible = "mobileye,eyeq5-clk" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, eq5c_match_table);
+
+static struct platform_driver eq5c_driver = {
+ .probe = eq5c_probe,
+ .driver = {
+ .name = "clk-eyeq5",
+ .of_match_table = eq5c_match_table,
+ },
+};
+
+static int __init eq5c_init(void)
+{
+ return platform_driver_register(&eq5c_driver);
+}
+arch_initcall(eq5c_init);
--
2.43.0
On Wed, Dec 27, 2023 at 10:24 AM Théo Lebrun <[email protected]> wrote:
>
> Add documentation to describe the "Other Logic Block" syscon.
>
> Signed-off-by: Théo Lebrun <[email protected]>
> ---
> .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 45 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> new file mode 100644
> index 000000000000..b148a49b08f1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mobileye EyeQ5 SoC system controller
> +
> +maintainers:
> + - Grégory Clement <[email protected]>
> + - Théo Lebrun <[email protected]>
> + - Vladimir Kondratiev <[email protected]>
> +
> +description:
> + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
> + resets, pinctrl are being handled from here.
I don't see resets or pinctrl in the binding. Please make it complete
whether you have the driver or not.
As-is, you don't need clocks to be a child node.
> +
> +properties:
> + compatible:
> + items:
> + - const: mobileye,eyeq5-olb
> + - const: syscon
> + - const: simple-mfd
> +
> + reg:
> + maxItems: 1
> +
> + reg-io-width:
> + const: 4
Why do you need this? It is not a generic block and can only ever be 1 value.
> +
> +required:
> + - compatible
> + - reg
> + - reg-io-width
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + olb@e00000 {
> + compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
> + reg = <0xe00000 0x400>;
> + reg-io-width = <4>;
Make this example complete and drop the child node example.
Rob
On 27/12/2023 17:23, Théo Lebrun wrote:
> Add documentation to describe the "Other Logic Block" syscon.
>
> Signed-off-by: Théo Lebrun <[email protected]>
> ---
> .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 45 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> new file mode 100644
> index 000000000000..b148a49b08f1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> @@ -0,0 +1,44 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mobileye EyeQ5 SoC system controller
> +
> +maintainers:
> + - Grégory Clement <[email protected]>
> + - Théo Lebrun <[email protected]>
> + - Vladimir Kondratiev <[email protected]>
> +
> +description:
> + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
> + resets, pinctrl are being handled from here.
> +
> +properties:
> + compatible:
> + items:
> + - const: mobileye,eyeq5-olb
> + - const: syscon
> + - const: simple-mfd
> +
> + reg:
> + maxItems: 1
> +
> + reg-io-width:
> + const: 4
> +
> +required:
> + - compatible
> + - reg
> + - reg-io-width
It's still wrong order of the patches. Binding should be complete, so
you miss clock-controller in this patch. If you ordered them hoping
there is no dependency between patches, it will not work. You still have
dependency! Your next patch still depends on this, which should be
clearly expressed either in cover letter or next patch.
Best regards,
Krzysztof
On 27/12/2023 17:23, Théo Lebrun wrote:
> Add DT schema bindings for the EyeQ5 clock controller driver.
>
> Signed-off-by: Théo Lebrun <[email protected]>
> ---
Where is the dependency expressed, so maintainers understand it should
go via one tree?
> diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> index b148a49b08f1..b4ba6f0c9f32 100644
> --- a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> @@ -28,6 +28,10 @@ properties:
> reg-io-width:
> const: 4
>
> + clock-controller:
> + $ref: /schemas/clock/mobileye,eyeq5-clk.yaml#
> + type: object
This belongs to the MFD patch.
Best regards,
Krzysztof
On 27/12/2023 17:23, Théo Lebrun wrote:
> We add the clock controller inside the OLB syscon region and removed
> previous fixed devicetree nodes representing PLLs exposed by the clock
> controller.
>
...
> / {
> #address-cells = <2>;
> @@ -42,6 +42,19 @@ soc: soc {
> ranges;
> compatible = "simple-bus";
>
> + olb: olb@e00000 {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
Often: system-controller
> + compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
> + reg = <0 0xe00000 0x0 0x400>;
> + reg-io-width = <4>;
> +
> + clocks: clock-controller {
> + compatible = "mobileye,eyeq5-clk";
> + #clock-cells = <1>;
> + clocks = <&xtal>;
> + clock-names = "ref";
> + };
> + };
> +
Best regards,
Krzysztof
Hello,
On Wed Dec 27, 2023 at 7:27 PM CET, Rob Herring wrote:
> On Wed, Dec 27, 2023 at 10:24 AM Théo Lebrun <[email protected]> wrote:
> >
> > Add documentation to describe the "Other Logic Block" syscon.
> >
> > Signed-off-by: Théo Lebrun <[email protected]>
> > ---
> > .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
> > MAINTAINERS | 1 +
> > 2 files changed, 45 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > new file mode 100644
> > index 000000000000..b148a49b08f1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > @@ -0,0 +1,44 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Mobileye EyeQ5 SoC system controller
> > +
> > +maintainers:
> > + - Grégory Clement <[email protected]>
> > + - Théo Lebrun <[email protected]>
> > + - Vladimir Kondratiev <[email protected]>
> > +
> > +description:
> > + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
> > + resets, pinctrl are being handled from here.
>
> I don't see resets or pinctrl in the binding. Please make it complete
> whether you have the driver or not.
>
> As-is, you don't need clocks to be a child node.
Will do. Would it make sense to have the three drivers be a single
series? Else we could have the dt-bindings be part of the base platform
support series[1].
[1]: https://lore.kernel.org/lkml/[email protected]/
> > +properties:
> > + compatible:
> > + items:
> > + - const: mobileye,eyeq5-olb
> > + - const: syscon
> > + - const: simple-mfd
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + reg-io-width:
> > + const: 4
>
> Why do you need this? It is not a generic block and can only ever be 1
> value.
This block is still a syscon in the end. I wanted to explicit that
access width must be 4 bytes and nothing else.
Does you question mean you think I should be removing it?
> > +required:
> > + - compatible
> > + - reg
> > + - reg-io-width
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + olb@e00000 {
> > + compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
> > + reg = <0xe00000 0x400>;
> > + reg-io-width = <4>;
>
> Make this example complete and drop the child node example.
I hesitated inbetween the two options, I'll fix that on the next
revision. Thanks!
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Hello,
On Thu Dec 28, 2023 at 8:21 AM CET, Krzysztof Kozlowski wrote:
> On 27/12/2023 17:23, Théo Lebrun wrote:
> > Add documentation to describe the "Other Logic Block" syscon.
> >
> > Signed-off-by: Théo Lebrun <[email protected]>
> > ---
> > .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
> > MAINTAINERS | 1 +
> > 2 files changed, 45 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > new file mode 100644
> > index 000000000000..b148a49b08f1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > @@ -0,0 +1,44 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Mobileye EyeQ5 SoC system controller
> > +
> > +maintainers:
> > + - Grégory Clement <[email protected]>
> > + - Théo Lebrun <[email protected]>
> > + - Vladimir Kondratiev <[email protected]>
> > +
> > +description:
> > + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
> > + resets, pinctrl are being handled from here.
> > +
> > +properties:
> > + compatible:
> > + items:
> > + - const: mobileye,eyeq5-olb
> > + - const: syscon
> > + - const: simple-mfd
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + reg-io-width:
> > + const: 4
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - reg-io-width
>
> It's still wrong order of the patches. Binding should be complete, so
> you miss clock-controller in this patch. If you ordered them hoping
> there is no dependency between patches, it will not work. You still have
> dependency! Your next patch still depends on this, which should be
> clearly expressed either in cover letter or next patch.
Ah you read me right, I did indeed expect ordering to be enough. I'll
squash all changes to mobileye,eyeq5-olb.yaml into a single commit to
avoid any dependency.
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Thu, Dec 28, 2023 at 03:57:55PM +0100, Théo Lebrun wrote:
> Hello,
>
> On Wed Dec 27, 2023 at 7:27 PM CET, Rob Herring wrote:
> > On Wed, Dec 27, 2023 at 10:24 AM Théo Lebrun <[email protected]> wrote:
> > >
> > > Add documentation to describe the "Other Logic Block" syscon.
> > >
> > > Signed-off-by: Théo Lebrun <[email protected]>
> > > ---
> > > .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 44 ++++++++++++++++++++++
> > > MAINTAINERS | 1 +
> > > 2 files changed, 45 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > > new file mode 100644
> > > index 000000000000..b148a49b08f1
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml
> > > @@ -0,0 +1,44 @@
> > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq5-olb.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Mobileye EyeQ5 SoC system controller
> > > +
> > > +maintainers:
> > > + - Grégory Clement <[email protected]>
> > > + - Théo Lebrun <[email protected]>
> > > + - Vladimir Kondratiev <[email protected]>
> > > +
> > > +description:
> > > + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. Clocks,
> > > + resets, pinctrl are being handled from here.
> >
> > I don't see resets or pinctrl in the binding. Please make it complete
> > whether you have the driver or not.
> >
> > As-is, you don't need clocks to be a child node.
>
> Will do. Would it make sense to have the three drivers be a single
> series?
You could, but doesn't have to be. Just make the binding complete.
Whether you have the drivers done is up to you.
> Else we could have the dt-bindings be part of the base platform
> support series[1].
>
> [1]: https://lore.kernel.org/lkml/[email protected]/
>
> > > +properties:
> > > + compatible:
> > > + items:
> > > + - const: mobileye,eyeq5-olb
> > > + - const: syscon
> > > + - const: simple-mfd
> > > +
> > > + reg:
> > > + maxItems: 1
> > > +
> > > + reg-io-width:
> > > + const: 4
> >
> > Why do you need this? It is not a generic block and can only ever be 1
> > value.
>
> This block is still a syscon in the end. I wanted to explicit that
> access width must be 4 bytes and nothing else.
>
> Does you question mean you think I should be removing it?
Yes. It can be implied by compatible.
Rob