Commit c9cf27d9 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'icc-5.8-rc1' of https://git.linaro.org/people/georgi.djakov/linux into char-misc-next



Georgi writes:

interconnect changes for 5.8

These are the interconnect changes for the 5.8-rc1 merge window:

Core changes:
- Convert the framework core from tristate to bool to make handling
dependencies between other core frameworks easier
- Add of_icc_get_by_index()
- Add devm_of_icc_get() helper function
- Add icc_enable() and icc_disable() helpers

New drivers:
- Platform driver for NXP i.MX8MM SoC
- Platform driver for NXP i.MX8MN SoC
- Platform driver for NXP i.MX8MQ SoC

Signed-off-by: default avatarGeorgi Djakov <georgi.djakov@linaro.org>

* tag 'icc-5.8-rc1' of https://git.linaro.org/people/georgi.djakov/linux:
  interconnect: Remove unused module exit code from core
  interconnect: Disallow interconnect core to be built as a module
  interconnect: Add of_icc_get_by_index() helper function
  interconnect: Add helpers for enabling/disabling a path
  interconnect: imx: Fix return value check in imx_icc_node_init_qos()
  interconnect: imx: Add platform driver for imx8mn
  interconnect: imx: Add platform driver for imx8mq
  interconnect: imx: Add platform driver for imx8mm
  interconnect: Add imx core driver
  dt-bindings: interconnect: Add bindings for imx8m noc
  interconnect: Add devm_of_icc_get() as exported API for users
parents f37d13d5 b35da2e8
Loading
Loading
Loading
Loading
+101 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/fsl,imx8m-noc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Generic i.MX bus frequency device

maintainers:
  - Leonard Crestez <leonard.crestez@nxp.com>

description: |
  The i.MX SoC family has multiple buses for which clock frequency (and
  sometimes voltage) can be adjusted.

  Some of those buses expose register areas mentioned in the memory maps as GPV
  ("Global Programmers View") but not all. Access to this area might be denied
  for normal (non-secure) world.

  The buses are based on externally licensed IPs such as ARM NIC-301 and
  Arteris FlexNOC but DT bindings are specific to the integration of these bus
  interconnect IPs into imx SOCs.

properties:
  compatible:
    oneOf:
      - items:
        - enum:
          - fsl,imx8mn-nic
          - fsl,imx8mm-nic
          - fsl,imx8mq-nic
        - const: fsl,imx8m-nic
      - items:
        - enum:
          - fsl,imx8mn-noc
          - fsl,imx8mm-noc
          - fsl,imx8mq-noc
        - const: fsl,imx8m-noc
      - const: fsl,imx8m-nic

  reg:
    maxItems: 1

  clocks:
    maxItems: 1

  operating-points-v2: true
  opp-table: true

  fsl,ddrc:
    $ref: "/schemas/types.yaml#/definitions/phandle"
    description:
      Phandle to DDR Controller.

  '#interconnect-cells':
    description:
      If specified then also act as an interconnect provider. Should only be
      set once per soc on the main noc.
    const: 1

required:
  - compatible
  - clocks

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/imx8mm-clock.h>
    #include <dt-bindings/interconnect/imx8mm.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>

    noc: interconnect@32700000 {
        compatible = "fsl,imx8mm-noc", "fsl,imx8m-noc";
        reg = <0x32700000 0x100000>;
        clocks = <&clk IMX8MM_CLK_NOC>;
        #interconnect-cells = <1>;
        fsl,ddrc = <&ddrc>;

        operating-points-v2 = <&noc_opp_table>;
        noc_opp_table: opp-table {
            compatible = "operating-points-v2";

            opp-133M {
                opp-hz = /bits/ 64 <133333333>;
            };
            opp-800M {
                opp-hz = /bits/ 64 <800000000>;
            };
        };
    };

    ddrc: memory-controller@3d400000 {
        compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
        reg = <0x3d400000 0x400000>;
        clock-names = "core", "pll", "alt", "apb";
        clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
                 <&clk IMX8MM_DRAM_PLL>,
                 <&clk IMX8MM_CLK_DRAM_ALT>,
                 <&clk IMX8MM_CLK_DRAM_APB>;
    };
+2 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
menuconfig INTERCONNECT
	tristate "On-Chip Interconnect management support"
	bool "On-Chip Interconnect management support"
	help
	  Support for management of the on-chip interconnects.

@@ -11,6 +11,7 @@ menuconfig INTERCONNECT

if INTERCONNECT

source "drivers/interconnect/imx/Kconfig"
source "drivers/interconnect/qcom/Kconfig"

endif
+1 −0
Original line number Diff line number Diff line
@@ -4,4 +4,5 @@ CFLAGS_core.o := -I$(src)
icc-core-objs				:= core.o

obj-$(CONFIG_INTERCONNECT)		+= icc-core.o
obj-$(CONFIG_INTERCONNECT_IMX)		+= imx/
obj-$(CONFIG_INTERCONNECT_QCOM)		+= qcom/
+118 −25
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ static struct icc_path *path_init(struct device *dev, struct icc_node *dst,
		hlist_add_head(&path->reqs[i].req_node, &node->req_list);
		path->reqs[i].node = node;
		path->reqs[i].dev = dev;
		path->reqs[i].enabled = true;
		/* reference to previous node was saved during path traversal */
		node = node->reverse;
	}
@@ -249,9 +250,12 @@ static int aggregate_requests(struct icc_node *node)
	if (p->pre_aggregate)
		p->pre_aggregate(node);

	hlist_for_each_entry(r, &node->req_list, req_node)
	hlist_for_each_entry(r, &node->req_list, req_node) {
		if (!r->enabled)
			continue;
		p->aggregate(node, r->tag, r->avg_bw, r->peak_bw,
			     &node->avg_bw, &node->peak_bw);
	}

	return 0;
}
@@ -350,10 +354,35 @@ static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
	return node;
}

static void devm_icc_release(struct device *dev, void *res)
{
	icc_put(*(struct icc_path **)res);
}

struct icc_path *devm_of_icc_get(struct device *dev, const char *name)
{
	struct icc_path **ptr, *path;

	ptr = devres_alloc(devm_icc_release, sizeof(**ptr), GFP_KERNEL);
	if (!ptr)
		return ERR_PTR(-ENOMEM);

	path = of_icc_get(dev, name);
	if (!IS_ERR(path)) {
		*ptr = path;
		devres_add(dev, ptr);
	} else {
		devres_free(ptr);
	}

	return path;
}
EXPORT_SYMBOL_GPL(devm_of_icc_get);

/**
 * of_icc_get() - get a path handle from a DT node based on name
 * of_icc_get_by_index() - get a path handle from a DT node based on index
 * @dev: device pointer for the consumer device
 * @name: interconnect path name
 * @idx: interconnect path index
 *
 * This function will search for a path between two endpoints and return an
 * icc_path handle on success. Use icc_put() to release constraints when they
@@ -365,13 +394,12 @@ static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
 * Return: icc_path pointer on success or ERR_PTR() on error. NULL is returned
 * when the API is disabled or the "interconnects" DT property is missing.
 */
struct icc_path *of_icc_get(struct device *dev, const char *name)
struct icc_path *of_icc_get_by_index(struct device *dev, int idx)
{
	struct icc_path *path = ERR_PTR(-EPROBE_DEFER);
	struct icc_path *path;
	struct icc_node *src_node, *dst_node;
	struct device_node *np = NULL;
	struct device_node *np;
	struct of_phandle_args src_args, dst_args;
	int idx = 0;
	int ret;

	if (!dev || !dev->of_node)
@@ -391,12 +419,6 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
	 * lets support only global ids and extend this in the future if needed
	 * without breaking DT compatibility.
	 */
	if (name) {
		idx = of_property_match_string(np, "interconnect-names", name);
		if (idx < 0)
			return ERR_PTR(idx);
	}

	ret = of_parse_phandle_with_args(np, "interconnects",
					 "#interconnect-cells", idx * 2,
					 &src_args);
@@ -439,12 +461,8 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
		return path;
	}

	if (name)
		path->name = kstrdup_const(name, GFP_KERNEL);
	else
	path->name = kasprintf(GFP_KERNEL, "%s-%s",
			       src_node->name, dst_node->name);

	if (!path->name) {
		kfree(path);
		return ERR_PTR(-ENOMEM);
@@ -452,6 +470,53 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)

	return path;
}
EXPORT_SYMBOL_GPL(of_icc_get_by_index);

/**
 * of_icc_get() - get a path handle from a DT node based on name
 * @dev: device pointer for the consumer device
 * @name: interconnect path name
 *
 * This function will search for a path between two endpoints and return an
 * icc_path handle on success. Use icc_put() to release constraints when they
 * are not needed anymore.
 * If the interconnect API is disabled, NULL is returned and the consumer
 * drivers will still build. Drivers are free to handle this specifically,
 * but they don't have to.
 *
 * Return: icc_path pointer on success or ERR_PTR() on error. NULL is returned
 * when the API is disabled or the "interconnects" DT property is missing.
 */
struct icc_path *of_icc_get(struct device *dev, const char *name)
{
	struct device_node *np;
	int idx = 0;

	if (!dev || !dev->of_node)
		return ERR_PTR(-ENODEV);

	np = dev->of_node;

	/*
	 * When the consumer DT node do not have "interconnects" property
	 * return a NULL path to skip setting constraints.
	 */
	if (!of_find_property(np, "interconnects", NULL))
		return NULL;

	/*
	 * We use a combination of phandle and specifier for endpoint. For now
	 * lets support only global ids and extend this in the future if needed
	 * without breaking DT compatibility.
	 */
	if (name) {
		idx = of_property_match_string(np, "interconnect-names", name);
		if (idx < 0)
			return ERR_PTR(idx);
	}

	return of_icc_get_by_index(dev, idx);
}
EXPORT_SYMBOL_GPL(of_icc_get);

/**
@@ -546,6 +611,39 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
}
EXPORT_SYMBOL_GPL(icc_set_bw);

static int __icc_enable(struct icc_path *path, bool enable)
{
	int i;

	if (!path)
		return 0;

	if (WARN_ON(IS_ERR(path) || !path->num_nodes))
		return -EINVAL;

	mutex_lock(&icc_lock);

	for (i = 0; i < path->num_nodes; i++)
		path->reqs[i].enabled = enable;

	mutex_unlock(&icc_lock);

	return icc_set_bw(path, path->reqs[0].avg_bw,
			  path->reqs[0].peak_bw);
}

int icc_enable(struct icc_path *path)
{
	return __icc_enable(path, true);
}
EXPORT_SYMBOL_GPL(icc_enable);

int icc_disable(struct icc_path *path)
{
	return __icc_enable(path, false);
}
EXPORT_SYMBOL_GPL(icc_disable);

/**
 * icc_get() - return a handle for path between two endpoints
 * @dev: the device requesting the path
@@ -908,12 +1006,7 @@ static int __init icc_init(void)
	return 0;
}

static void __exit icc_exit(void)
{
	debugfs_remove_recursive(icc_debugfs_dir);
}
module_init(icc_init);
module_exit(icc_exit);
device_initcall(icc_init);

MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
MODULE_DESCRIPTION("Interconnect Driver Core");
+17 −0
Original line number Diff line number Diff line
config INTERCONNECT_IMX
	tristate "i.MX interconnect drivers"
	depends on ARCH_MXC || COMPILE_TEST
	help
	  Generic interconnect drivers for i.MX SOCs

config INTERCONNECT_IMX8MM
	tristate "i.MX8MM interconnect driver"
	depends on INTERCONNECT_IMX

config INTERCONNECT_IMX8MN
	tristate "i.MX8MN interconnect driver"
	depends on INTERCONNECT_IMX

config INTERCONNECT_IMX8MQ
	tristate "i.MX8MQ interconnect driver"
	depends on INTERCONNECT_IMX
Loading