Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 900d96e4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-ethernet-ti-netcp-update-and-enable-cpts-support'

Grygorii Strashko says:

====================
net: ethernet: ti: netcp: update and enable cpts support

The Keystone 2 66AK2HK/E/L 1G Ethernet Switch Subsystems contains The
Common Platform Time Sync (CPTS) module which is in general compatible with
CPTS module found on TI AM3/4/5 SoCs. So, the basic support for
Keystone 2 CPTS is available by default, but not documented and has never been
enabled inconfig files.

The Keystone 2 CPTS module supports also some additional features like time
sync reference (RFTCLK) clock selection through CPTS_RFTCLK_SEL register
(offset: x08) in CPTS module, which can modelled as multiplexer clock
(this was discussed some time ago [1]).

This series adds missed binding documentation for Keystone 2 66AK2HK/E/L
CPTS module and enables CPTS for TI Keystone 2 66AK2HK/E/L SoCs with possiblity
to select CPTS reference clock.

Patch 1: adds the CPTS binding documentation. CPTS bindings are defined in the
way that allows CPTS properties to be grouped under "cpts" sub-node.
It also defines "cpts-refclk-mux" clock for CPTS RFTCLK selection.
Patches 2-3: implement CPTS properties grouping under "cpts" sub-node with
backward compatibility support.
Patch 4: adds support for time sync reference (RFTCLK) clock selection from DT
by adding support for "cpts-refclk-mux" multiplexer clock.
Patches 5-9: DT CPTS nodes update for TI Keystone 2 66AK2HK/E/L SoCs.
Patch 10: enables CPTS for TI Keystone 2 66AK2HK/E/L SoCs.

I grouped all patches in one series for better illustration of the changes,
but in general Pateches 1-4 are netdev matarieal (first) and other patches
are platform specific.

Series can be found at:
 git@git.ti.com:~gragst/ti-linux-kernel/gragsts-ti-linux-kernel.git
branch:
 net-next-k2e-cpts-refclk

Changes in v2:
 - do reverse christmas tree in cpts_of_mux_clk_setup()
 - add ack from Richard Cochran

v1: https://lkml.org/lkml/2019/6/1/77

[1] https://www.spinics.net/lists/netdev/msg408931.html


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8d94a873 a3047a81
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -104,6 +104,23 @@ Required properties:
			- 10Gb mac<->mac forced mode : 11
----phy-handle:	phandle to PHY device

- cpts:		sub-node time synchronization (CPTS) submodule configuration
-- clocks:	CPTS reference clock. Should point on cpts-refclk-mux clock.
-- clock-names: should be "cpts"
-- cpts-refclk-mux: multiplexer clock definition sub-node for CPTS reference (RFTCLK) clock
--- #clock-cells: should be 0
--- clocks:	list of CPTS reference (RFTCLK) clock's parents as defined in Data manual
--- ti,mux-tbl: array of multiplexer indexes as defined in Data manual
--- assigned-clocks: should point on cpts-refclk-mux clock
--- assigned-clock-parents: should point on required RFTCLK clock parent to be selected
-- cpts_clock_mult: (optional) Numerator to convert input clock ticks
		into nanoseconds
-- cpts_clock_shift: (optional) Denominator to convert input clock ticks into
		nanoseconds.
		Mult and shift will be calculated basing on CPTS
		rftclk frequency if both cpts_clock_shift and
		cpts_clock_mult properties are not provided.

Optional properties:
- enable-ale:	NetCP driver keeps the address learning feature in the ethernet
		switch module disabled. This attribute is to enable the address
@@ -168,6 +185,23 @@ netcp: netcp@2000000 {
			tx-queue = <648>;
			tx-channel = <8>;

			cpts {
				clocks = <&cpts_refclk_mux>;
				clock-names = "cpts";

				cpts_refclk_mux: cpts-refclk-mux {
					#clock-cells = <0>;
					clocks = <&chipclk12>, <&chipclk13>,
						 <&timi0>, <&timi1>,
						 <&tsipclka>, <&tsrefclk>,
						 <&tsipclkb>;
					ti,mux-tbl = <0x0>, <0x1>, <0x2>,
						<0x3>, <0x4>, <0x8>, <0xC>;
					assigned-clocks = <&cpts_refclk_mux>;
					assigned-clock-parents = <&chipclk12>;
				};
			};

			interfaces {
				gbe0: interface-0 {
					slave-port = <0>;
@@ -219,3 +253,13 @@ netcp: netcp@2000000 {
		};
	};
};

CPTS board configuration - select external CPTS RFTCLK:

&tsrefclk{
	clock-frequency = <500000000>;
};

&cpts_refclk_mux {
	assigned-clock-parents = <&tsrefclk>;
};
+85 −3
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
 *
 */
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/if.h>
#include <linux/hrtimer.h>
@@ -532,6 +533,82 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
		 freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
}

static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
{
	struct device_node *refclk_np;
	const char **parent_names;
	unsigned int num_parents;
	struct clk_hw *clk_hw;
	int ret = -EINVAL;
	u32 *mux_table;

	refclk_np = of_get_child_by_name(node, "cpts-refclk-mux");
	if (!refclk_np)
		/* refclk selection supported not for all SoCs */
		return 0;

	num_parents = of_clk_get_parent_count(refclk_np);
	if (num_parents < 1) {
		dev_err(cpts->dev, "mux-clock %s must have parents\n",
			refclk_np->name);
		goto mux_fail;
	}

	parent_names = devm_kzalloc(cpts->dev, (sizeof(char *) * num_parents),
				    GFP_KERNEL);

	mux_table = devm_kzalloc(cpts->dev, sizeof(*mux_table) * num_parents,
				 GFP_KERNEL);
	if (!mux_table || !parent_names) {
		ret = -ENOMEM;
		goto mux_fail;
	}

	of_clk_parent_fill(refclk_np, parent_names, num_parents);

	ret = of_property_read_variable_u32_array(refclk_np, "ti,mux-tbl",
						  mux_table,
						  num_parents, num_parents);
	if (ret < 0)
		goto mux_fail;

	clk_hw = clk_hw_register_mux_table(cpts->dev, refclk_np->name,
					   parent_names, num_parents,
					   0,
					   &cpts->reg->rftclk_sel, 0, 0x1F,
					   0, mux_table, NULL);
	if (IS_ERR(clk_hw)) {
		ret = PTR_ERR(clk_hw);
		goto mux_fail;
	}

	ret = devm_add_action_or_reset(cpts->dev,
				       (void(*)(void *))clk_hw_unregister_mux,
				       clk_hw);
	if (ret) {
		dev_err(cpts->dev, "add clkmux unreg action %d", ret);
		goto mux_fail;
	}

	ret = of_clk_add_hw_provider(refclk_np, of_clk_hw_simple_get, clk_hw);
	if (ret)
		goto mux_fail;

	ret = devm_add_action_or_reset(cpts->dev,
				       (void(*)(void *))of_clk_del_provider,
				       refclk_np);
	if (ret) {
		dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
		goto mux_fail;
	}

	return ret;

mux_fail:
	of_node_put(refclk_np);
	return ret;
}

static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
{
	int ret = -EINVAL;
@@ -547,7 +624,7 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
	    (!cpts->cc.mult && cpts->cc.shift))
		goto of_error;

	return 0;
	return cpts_of_mux_clk_setup(cpts, node);

of_error:
	dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
@@ -572,9 +649,14 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
	if (ret)
		return ERR_PTR(ret);

	cpts->refclk = devm_get_clk_from_child(dev, node, "cpts");
	if (IS_ERR(cpts->refclk))
		/* try get clk from dev node for compatibility */
		cpts->refclk = devm_clk_get(dev, "cpts");

	if (IS_ERR(cpts->refclk)) {
		dev_err(dev, "Failed to get cpts refclk\n");
		dev_err(dev, "Failed to get cpts refclk %ld\n",
			PTR_ERR(cpts->refclk));
		return ERR_CAST(cpts->refclk);
	}

+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@
struct cpsw_cpts {
	u32 idver;                /* Identification and version */
	u32 control;              /* Time sync control */
	u32 res1;
	u32 rftclk_sel;		  /* Reference Clock Select Register */
	u32 ts_push;              /* Time stamp event push */
	u32 ts_load_val;          /* Time stamp load value */
	u32 ts_load_en;           /* Time stamp load enable */
+7 −2
Original line number Diff line number Diff line
@@ -3554,7 +3554,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
		     struct device_node *node, void **inst_priv)
{
	struct device_node *interfaces, *interface;
	struct device_node *interfaces, *interface, *cpts_node;
	struct device_node *secondary_ports;
	struct cpsw_ale_params ale_params;
	struct gbe_priv *gbe_dev;
@@ -3713,7 +3713,12 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
		dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
	}

	gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, node);
	cpts_node = of_get_child_by_name(node, "cpts");
	if (!cpts_node)
		cpts_node = of_node_get(node);

	gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, cpts_node);
	of_node_put(cpts_node);
	if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) {
		ret = PTR_ERR(gbe_dev->cpts);
		goto free_sec_ports;