Selaa lähdekoodia

Merge branch 'topic/4.19/am65x' of git://git.ti.com/rpmsg/remoteproc into rpmsg-ti-linux-4.19.y

Pull in the dedicated AM65x remoteproc topic branch that adds the
preliminary support for representing PRUSS clocks as clocks nodes
in DT. The support is added _only_ for the ICSSG instances on K3
AM65x SoCs at the moment, and will be enhanced in the future to
scale for all applicable SoCs that have a PRUSS.

* 'topic/4.19/am65x' of git://git.ti.com/rpmsg/remoteproc:
  arm64: dts: ti: k3-am65-main: Add input clock to IEP nodes
  dt-bindings: soc: ti: pruss: Update IEP node bindings
  TEMP: soc: ti: pruss: support CORECLK_MUX and IEPCLK_MUX
  TEMP: arm64: dts: ti: k3-am65-main: Add IEP and CORE clock muxes
  TEMP: dt-bindings: soc: ti: pruss: Add IEP and CORE clock mux

Signed-off-by: Suman Anna <s-anna@ti.com>
Suman Anna 6 vuotta sitten
vanhempi
commit
3e6a82a2c9

+ 29 - 0
Documentation/devicetree/bindings/soc/ti/ti,pruss.txt

@@ -138,6 +138,35 @@ are applicable only for K3 SoCs. They are represented as follows:
 See Documentation/devicetree/bindings/mfd/syscon.txt for generic syscon
 See Documentation/devicetree/bindings/mfd/syscon.txt for generic syscon
 binding details.
 binding details.
 
 
+Required Properties:
+--------------------
+The following are required properties for IEP nodes
+- clocks        : phandle to IEP core clock.
+
+
+IEPCLK MUX Clock node
+=====================
+The IEP module can get its clock from 2 sources i.e. IEP_CLK input to
+the PRU-ICSS module or the Bus clock (ICLK). This node models this clock
+mux and should have the name "iepclk_mux".
+
+Required Properties:
+--------------------
+-#clock-cells   : should be 0
+-clocks         : phandles to the 2 input clocks to the IEPCLK MUX.
+
+CORECLK MUX Clock node
+======================
+This is applicable only for ICSSG (K3 SoCs). The ICSSG modules core clock
+can be set to one of the 2 sources i.e. CORE_CLK input to the ICSSG module
+or VBUS clock. This node models this clock mux and should have the name
+"coreclk_mux".
+
+Required Properties:
+--------------------
+-#clock-cells   : should be 0
+-clocks         : phandles to the 2 input clocks to the CORECLK MUX.
+
 
 
 PRUSS INTC Node
 PRUSS INTC Node
 ================
 ================

+ 54 - 0
arch/arm64/boot/dts/ti/k3-am65-main.dtsi

@@ -505,14 +505,32 @@
 				reg = <0xb026000 0x200>;
 				reg = <0xb026000 0x200>;
 			};
 			};
 
 
+			icssg0_coreclk_mux: coreclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 62 19>, /* icssg0_core_clk */
+					 <&k3_clks 62 3>;  /* icssg0_iclk */
+				assigned-clocks = <&icssg0_coreclk_mux>;
+				assigned-clock-parents = <&k3_clks 62 3>;
+			};
+
+			icssg0_iepclk_mux: iepclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 62 10>,	/* icssg0_iep_clk */
+					 <&icssg0_coreclk_mux>;	/* core_clk */
+				assigned-clocks = <&icssg0_iepclk_mux>;
+				assigned-clock-parents = <&icssg0_coreclk_mux>;
+			};
+
 			icssg0_iep0: iep@b02e000 {
 			icssg0_iep0: iep@b02e000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb02e000 0x1000>;
 				reg = <0xb02e000 0x1000>;
+				clocks = <&icssg0_iepclk_mux>;
 			};
 			};
 
 
 			icssg0_iep1: iep@b02f000 {
 			icssg0_iep1: iep@b02f000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb02f000 0x1000>;
 				reg = <0xb02f000 0x1000>;
+				clocks = <&icssg0_iepclk_mux>;
 			};
 			};
 
 
 			icssg0_mii_rt: mii-rt@b032000 {
 			icssg0_mii_rt: mii-rt@b032000 {
@@ -634,14 +652,32 @@
 				reg = <0xb126000 0x200>;
 				reg = <0xb126000 0x200>;
 			};
 			};
 
 
+			icssg1_coreclk_mux: coreclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 63 19>, /* icssg1_core_clk */
+					 <&k3_clks 63 3>;  /* icssg1_iclk */
+				assigned-clocks = <&icssg1_coreclk_mux>;
+				assigned-clock-parents = <&k3_clks 63 3>;
+			};
+
+			icssg1_iepclk_mux: iepclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 63 10>,	/* icssg1_iep_clk */
+					 <&icssg1_coreclk_mux>;	/* core_clk */
+				assigned-clocks = <&icssg1_iepclk_mux>;
+				assigned-clock-parents = <&icssg1_coreclk_mux>;
+			};
+
 			icssg1_iep0: iep@b12e000 {
 			icssg1_iep0: iep@b12e000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb12e000 0x1000>;
 				reg = <0xb12e000 0x1000>;
+				clocks = <&icssg1_iepclk_mux>;
 			};
 			};
 
 
 			icssg1_iep1: iep@b12f000 {
 			icssg1_iep1: iep@b12f000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb12f000 0x1000>;
 				reg = <0xb12f000 0x1000>;
+				clocks = <&icssg1_iepclk_mux>;
 			};
 			};
 
 
 			icssg1_mii_rt: mii-rt@b132000 {
 			icssg1_mii_rt: mii-rt@b132000 {
@@ -763,14 +799,32 @@
 				reg = <0xb226000 0x200>;
 				reg = <0xb226000 0x200>;
 			};
 			};
 
 
+			icssg2_coreclk_mux: coreclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 64 19>, /* icssg1_core_clk */
+					 <&k3_clks 64 3>;  /* icssg1_iclk */
+				assigned-clocks = <&icssg2_coreclk_mux>;
+				assigned-clock-parents = <&k3_clks 64 3>;
+			};
+
+			icssg2_iepclk_mux: iepclk_mux {
+				#clock-cells = <0>;
+				clocks = <&k3_clks 64 10>,	/* icssg1_iep_clk */
+					 <&icssg2_coreclk_mux>;	/* core_clk */
+				assigned-clocks = <&icssg2_iepclk_mux>;
+				assigned-clock-parents = <&icssg2_coreclk_mux>;
+			};
+
 			icssg2_iep0: iep@b22e000 {
 			icssg2_iep0: iep@b22e000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb22e000 0x1000>;
 				reg = <0xb22e000 0x1000>;
+				clocks = <&icssg2_iepclk_mux>;
 			};
 			};
 
 
 			icssg2_iep1: iep@b22f000 {
 			icssg2_iep1: iep@b22f000 {
 				compatible = "syscon";
 				compatible = "syscon";
 				reg = <0xb22f000 0x1000>;
 				reg = <0xb22f000 0x1000>;
+				clocks = <&icssg2_iepclk_mux>;
 			};
 			};
 
 
 			icssg2_mii_rt: mii-rt@b232000 {
 			icssg2_mii_rt: mii-rt@b232000 {

+ 116 - 34
drivers/soc/ti/pruss.c

@@ -8,6 +8,7 @@
  *	Tero Kristo <t-kristo@ti.com>
  *	Tero Kristo <t-kristo@ti.com>
  */
  */
 
 
+#include <linux/clk-provider.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon.h>
@@ -229,30 +230,6 @@ int pruss_regmap_update(struct pruss *pruss, enum pruss_syscon mod,
 }
 }
 EXPORT_SYMBOL_GPL(pruss_regmap_update);
 EXPORT_SYMBOL_GPL(pruss_regmap_update);
 
 
-/* Custom configuration of couple of PRUSS clocks only on AM65x SoCs */
-static int pruss_configure_clocks(struct platform_device *pdev,
-				  struct pruss *pruss)
-{
-	int ret;
-
-	if (!of_device_is_compatible(pdev->dev.of_node, "ti,am654-icssg"))
-		return 0;
-
-	ret = pruss_regmap_update(pruss, PRUSS_SYSCON_CFG, ICSSG_CFG_CORE_SYNC,
-				  ICSSG_CORE_VBUSP_SYNC_EN,
-				  ICSSG_CORE_VBUSP_SYNC_EN);
-	if (ret)
-		return ret;
-
-	ret = pruss_regmap_update(pruss, PRUSS_SYSCON_CFG, PRUSS_CFG_IEPCLK,
-				  PRUSS_IEPCLK_IEP_OCP_CLK_EN,
-				  PRUSS_IEPCLK_IEP_OCP_CLK_EN);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
 static const
 static const
 struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
 struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
 {
 {
@@ -270,6 +247,87 @@ struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
 	return ERR_PTR(-ENODEV);
 	return ERR_PTR(-ENODEV);
 }
 }
 
 
+static const struct regmap_config syscon_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static void pruss_of_free_clk_provider(void *data)
+{
+	struct device_node *clk_mux_np = data;
+
+	of_clk_del_provider(clk_mux_np);
+	of_node_put(clk_mux_np);
+}
+
+static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
+			       char *mux_name, unsigned int reg_offset)
+{
+	unsigned int num_parents;
+	const char **parent_names;
+	void __iomem *reg;
+	int ret;
+	char *clk_mux_name = NULL;
+	struct device_node *clk_mux_np;
+
+	clk_mux_np = of_get_child_by_name(pruss->dev->of_node, mux_name);
+	if (!clk_mux_np)
+		return -EINVAL;
+
+	num_parents = of_clk_get_parent_count(clk_mux_np);
+	if (num_parents < 1) {
+		dev_err(pruss->dev, "mux-clock %pOF must have parents\n",
+			clk_mux_np);
+		return -EINVAL;
+	}
+
+	parent_names = devm_kcalloc(pruss->dev, sizeof(char *), num_parents,
+				    GFP_KERNEL);
+	if (!parent_names)
+		return -ENOMEM;
+
+	of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
+
+	clk_mux_name = devm_kasprintf(pruss->dev, GFP_KERNEL, "%s.%pOFn",
+				      dev_name(pruss->dev), clk_mux_np);
+	if (!clk_mux_name)
+		return -ENOMEM;
+
+	reg = pruss->cfg_base + reg_offset;
+	/* WARN: dev must be NULL to avoid recursive incrementing
+	 * of module refcnt
+	 */
+	clk_mux = clk_register_mux(NULL, clk_mux_name,
+				   parent_names, num_parents,
+				   0, reg, 0, 1, 0, NULL);
+	if (IS_ERR(clk_mux))
+		return PTR_ERR(clk_mux);
+
+	ret = devm_add_action_or_reset(pruss->dev,
+				       (void(*)(void *))clk_unregister_mux,
+				       clk_mux);
+	if (ret) {
+		dev_err(pruss->dev, "failed to add clkmux reset action %d",
+			ret);
+		return ret;
+	}
+
+	ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get,
+				  clk_mux);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(pruss->dev,
+				       pruss_of_free_clk_provider,
+				       clk_mux_np);
+	if (ret)
+		dev_err(pruss->dev, "failed to add clkmux reset action %d",
+			ret);
+
+	return ret;
+}
+
 static int pruss_probe(struct platform_device *pdev)
 static int pruss_probe(struct platform_device *pdev)
 {
 {
 	struct device *dev = &pdev->dev;
 	struct device *dev = &pdev->dev;
@@ -280,6 +338,7 @@ static int pruss_probe(struct platform_device *pdev)
 	int ret, i, index;
 	int ret, i, index;
 	const struct pruss_private_data *data;
 	const struct pruss_private_data *data;
 	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
 	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
+	struct regmap_config syscon_config = syscon_regmap_config;
 
 
 	if (!node) {
 	if (!node) {
 		dev_err(dev, "Non-DT platform device not supported\n");
 		dev_err(dev, "Non-DT platform device not supported\n");
@@ -311,10 +370,39 @@ static int pruss_probe(struct platform_device *pdev)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	pruss->cfg = syscon_node_to_regmap(np);
-	of_node_put(np);
-	if (IS_ERR(pruss->cfg))
-		return -ENODEV;
+	if (of_address_to_resource(np, 0, &res))
+		return -ENOMEM;
+
+	pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
+	if (!pruss->cfg_base)
+		return -ENOMEM;
+
+	if (!of_device_is_compatible(pdev->dev.of_node, "ti,am654-icssg"))
+		goto skip_mux;
+
+	ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux, "coreclk_mux",
+				  ICSSG_CFG_CORE_SYNC);
+	if (ret) {
+		dev_err(dev, "failed to setup coreclk_mux\n");
+		return ret;
+	}
+
+	ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux, "iepclk_mux",
+				  PRUSS_CFG_IEPCLK);
+	if (ret) {
+		dev_err(dev, "failed to setup iepclk_mux\n");
+		return ret;
+	}
+
+skip_mux:
+	syscon_config.name = of_node_full_name(np);
+	syscon_config.max_register = resource_size(&res) - 4;
+
+	pruss->cfg = regmap_init_mmio(NULL, pruss->cfg_base, &syscon_config);
+	if (IS_ERR(pruss->cfg)) {
+		dev_err(dev, "cfg regmap init failed\n");
+		return PTR_ERR(pruss->cfg);
+	}
 
 
 	np = of_get_child_by_name(node, "mii-rt");
 	np = of_get_child_by_name(node, "mii-rt");
 	if (!np) {
 	if (!np) {
@@ -368,12 +456,6 @@ static int pruss_probe(struct platform_device *pdev)
 
 
 	platform_set_drvdata(pdev, pruss);
 	platform_set_drvdata(pdev, pruss);
 
 
-	ret = pruss_configure_clocks(pdev, pruss);
-	if (ret) {
-		dev_err(dev, "clock frequency config failed, ret = %d\n", ret);
-		return ret;
-	}
-
 	dev_dbg(&pdev->dev, "creating PRU cores and other child platform devices\n");
 	dev_dbg(&pdev->dev, "creating PRU cores and other child platform devices\n");
 	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
 	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
 	if (ret)
 	if (ret)

+ 4 - 0
include/linux/pruss_driver.h

@@ -39,6 +39,7 @@ struct pruss_intc_config {
 /**
 /**
  * struct pruss - PRUSS parent structure
  * struct pruss - PRUSS parent structure
  * @dev: pruss device pointer
  * @dev: pruss device pointer
+ * @cfg_base: base iomap for CFG region
  * @cfg: regmap for config region
  * @cfg: regmap for config region
  * @iep: regmap for IEP sub-module
  * @iep: regmap for IEP sub-module
  * @mii_rt: regmap for MII_RT sub-module
  * @mii_rt: regmap for MII_RT sub-module
@@ -48,12 +49,15 @@ struct pruss_intc_config {
  */
  */
 struct pruss {
 struct pruss {
 	struct device *dev;
 	struct device *dev;
+	void __iomem *cfg_base;
 	struct regmap *cfg;
 	struct regmap *cfg;
 	struct regmap *iep;
 	struct regmap *iep;
 	struct regmap *mii_rt;
 	struct regmap *mii_rt;
 	struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
 	struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
 	struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX];
 	struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX];
 	struct mutex lock; /* PRU resource lock */
 	struct mutex lock; /* PRU resource lock */
+	struct clk *core_clk_mux;
+	struct clk *iep_clk_mux;
 };
 };
 
 
 int pruss_intc_configure(struct pruss *pruss,
 int pruss_intc_configure(struct pruss *pruss,