Commit f4fcba5c5baaaa9d477d753f97124efdb8e45893

Authored by Philipp Tomsich
1 parent a45f17e8b9

clk: implement clk_set_defaults()

Linux uses the properties 'assigned-clocks', 'assigned-clock-parents'
and 'assigned-clock-rates' to configure the clock subsystem for use
with various peripheral nodes.

This implements clk_set_defaults() and hooks it up with the general
device probibin in drivers/core/device.c: when a new device is probed,
clk_set_defaults() will be called for it and will process the
properties mentioned above.

Note that this functionality is designed to fail gracefully (i.e. if a
clock-driver does not implement set_parent(), we simply accept this
and ignore the error) as not to break existing board-support.

Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Tested-by: David Wu <david.wu@rock-chips.com>

Series-changes: 2
- Fixed David's email address.

Series-version: 2

Cover-letter:
clk: support assigned-clock, assigned-clock-parents, assigned-clock-rates

For various peripherals on Rockchip SoCs (e.g. for the Ethernet GMAC),
the parent-clock needs to be set via the DTS.  This adds the required
plumbing and implements the GMAC case for the RK3399.
END

Showing 3 changed files with 141 additions and 0 deletions Side-by-side Diff

drivers/clk/clk-uclass.c
... ... @@ -2,6 +2,7 @@
2 2 * Copyright (C) 2015 Google, Inc
3 3 * Written by Simon Glass <sjg@chromium.org>
4 4 * Copyright (c) 2016, NVIDIA CORPORATION.
  5 + * Copyright (c) 2018, Theobroma Systems Design und Consulting GmbH
5 6 *
6 7 * SPDX-License-Identifier: GPL-2.0+
7 8 */
... ... @@ -10,6 +11,7 @@
10 11 #include <clk.h>
11 12 #include <clk-uclass.h>
12 13 #include <dm.h>
  14 +#include <dm/read.h>
13 15 #include <dt-structs.h>
14 16 #include <errno.h>
15 17  
... ... @@ -100,6 +102,122 @@
100 102 int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
101 103 {
102 104 return clk_get_by_indexed_prop(dev, "clocks", index, clk);
  105 +}
  106 +
  107 +static int clk_set_default_parents(struct udevice *dev)
  108 +{
  109 + struct clk clk, parent_clk;
  110 + int index;
  111 + int num_parents;
  112 + int ret;
  113 +
  114 + num_parents = dev_count_phandle_with_args(dev, "assigned-clock-parents",
  115 + "#clock-cells");
  116 + if (num_parents < 0) {
  117 + debug("%s: could not read assigned-clock-parents for %p\n",
  118 + __func__, dev);
  119 + return 0;
  120 + }
  121 +
  122 + for (index = 0; index < num_parents; index++) {
  123 + ret = clk_get_by_indexed_prop(dev, "assigned-clock-parents",
  124 + index, &parent_clk);
  125 + if (ret) {
  126 + debug("%s: could not get parent clock %d for %s\n",
  127 + __func__, index, dev_read_name(dev));
  128 + return ret;
  129 + }
  130 +
  131 + ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
  132 + index, &clk);
  133 + if (ret) {
  134 + debug("%s: could not get assigned clock %d for %s\n",
  135 + __func__, index, dev_read_name(dev));
  136 + return ret;
  137 + }
  138 +
  139 + ret = clk_set_parent(&clk, &parent_clk);
  140 +
  141 + /*
  142 + * Not all drivers may support clock-reparenting (as of now).
  143 + * Ignore errors due to this.
  144 + */
  145 + if (ret == -ENOSYS)
  146 + continue;
  147 +
  148 + if (ret) {
  149 + debug("%s: failed to reparent clock %d for %s\n",
  150 + __func__, index, dev_read_name(dev));
  151 + return ret;
  152 + }
  153 + }
  154 +
  155 + return 0;
  156 +}
  157 +
  158 +static int clk_set_default_rates(struct udevice *dev)
  159 +{
  160 + struct clk clk;
  161 + int index;
  162 + int num_rates;
  163 + int size;
  164 + int ret = 0;
  165 + u32 *rates = NULL;
  166 +
  167 + size = dev_read_size(dev, "assigned-clock-rates");
  168 + if (size < 0)
  169 + return 0;
  170 +
  171 + num_rates = size / sizeof(u32);
  172 + rates = calloc(num_rates, sizeof(u32));
  173 + if (!rates)
  174 + return -ENOMEM;
  175 +
  176 + ret = dev_read_u32_array(dev, "assigned-clock-rates", rates, num_rates);
  177 + if (ret)
  178 + goto fail;
  179 +
  180 + for (index = 0; index < num_rates; index++) {
  181 + ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
  182 + index, &clk);
  183 + if (ret) {
  184 + debug("%s: could not get assigned clock %d for %s\n",
  185 + __func__, index, dev_read_name(dev));
  186 + continue;
  187 + }
  188 +
  189 + ret = clk_set_rate(&clk, rates[index]);
  190 + if (ret < 0) {
  191 + debug("%s: failed to set rate on clock %d for %s\n",
  192 + __func__, index, dev_read_name(dev));
  193 + break;
  194 + }
  195 + }
  196 +
  197 +fail:
  198 + free(rates);
  199 + return ret;
  200 +}
  201 +
  202 +int clk_set_defaults(struct udevice *dev)
  203 +{
  204 + int ret;
  205 +
  206 + /* If this is running pre-reloc state, don't take any action. */
  207 + if (!(gd->flags & GD_FLG_RELOC))
  208 + return 0;
  209 +
  210 + debug("%s(%s)\n", __func__, dev_read_name(dev));
  211 +
  212 + ret = clk_set_default_parents(dev);
  213 + if (ret)
  214 + return ret;
  215 +
  216 + ret = clk_set_default_rates(dev);
  217 + if (ret < 0)
  218 + return ret;
  219 +
  220 + return 0;
103 221 }
104 222 # endif /* OF_PLATDATA */
105 223  
drivers/core/device.c
... ... @@ -11,6 +11,7 @@
11 11  
12 12 #include <common.h>
13 13 #include <asm/io.h>
  14 +#include <clk.h>
14 15 #include <fdtdec.h>
15 16 #include <fdt_support.h>
16 17 #include <malloc.h>
... ... @@ -390,6 +391,11 @@
390 391 if (ret)
391 392 goto fail;
392 393 }
  394 +
  395 + /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
  396 + ret = clk_set_defaults(dev);
  397 + if (ret)
  398 + goto fail;
393 399  
394 400 if (drv->probe) {
395 401 ret = drv->probe(dev);
... ... @@ -133,6 +133,23 @@
133 133  
134 134 #endif
135 135  
  136 +#if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) && \
  137 + CONFIG_IS_ENABLED(CLK)
  138 +/**
  139 + * clk_set_defaults - Process 'assigned-{clocks/clock-parents/clock-rates}'
  140 + * properties to configure clocks
  141 + *
  142 + * @dev: A device to process (the ofnode associated with this device
  143 + * will be processed).
  144 + */
  145 +int clk_set_defaults(struct udevice *dev);
  146 +#else
  147 +static inline int clk_set_defaults(struct udevice *dev)
  148 +{
  149 + return 0;
  150 +}
  151 +#endif
  152 +
136 153 /**
137 154 * clk_request - Request a clock by provider-specific ID.
138 155 *