Mise en place du PRU sur Beagle Bone Black avec un Kernel 3.14 de TI

Aujourd’hui j’ai réussit à mettre en fonction le PRU sur une image debian utilisant un  kernel v3.14 de TI à partir du dépot de Robert C Nelson sur github

git clone https://github.com/RobertCNelson/ti-linux-kernel-dev.git
cd ti-linux-kernel-dev/
git checkout origin/ti-linux-3.14.y -b tmp

Le fichier de patch est ici

Ce qu’il contient:

diff --git arch/arm/boot/dts/am335x-boneblack.dts arch/arm/boot/dts/am335x-boneblack.dts
index 7dd5b5b..243ff3a 100644
--- arch/arm/boot/dts/am335x-boneblack.dts
+++ arch/arm/boot/dts/am335x-boneblack.dts
@@ -142,3 +143,66 @@
 
 /* http://elinux.org/CircuitCo:Basic_Proto_Cape */
 /* #include "am335x-bone-basic-proto-cape.dtsi" */
+
+/* PRUSS */
+&pruss {
+	status = "okay";
+};

diff --git arch/arm/boot/dts/am33xx.dtsi arch/arm/boot/dts/am33xx.dtsi
index 0018daa..d027b61 100644
--- arch/arm/boot/dts/am33xx.dtsi
+++ arch/arm/boot/dts/am33xx.dtsi
@@ -432,6 +432,17 @@
 			ti,timer-pwm;
 		};
 
+		pruss: pruss@4a300000 {
+			compatible = "ti,pruss-v2";
+			ti,hwmods = "pruss";
+			ti,deassert-hard-reset = "pruss", "pruss";
+			reg = <0x4a300000 0x080000>;
+			ti,pintc-offset = <0x20000>;
+			interrupt-parent = <&intc>;
+			status = "disabled";
+			interrupts = <20 21 22 23 24 25 26 27>;
+		};
+
 		rtc@44e3e000 {
 			compatible = "ti,am3352-rtc";
 			reg = <0x44e3e000 0x1000>;
@@ -758,39 +769,6 @@
 			mboxes = <&mailbox &mbox_wkupm3>;
 		};
 
-		pruss: pruss@4a300000 {
-			compatible = "ti,am335x-pruss";
-			ti,hwmods = "pruss";
-			reg = <0x4a300000 0x2000>,
-			      <0x4a302000 0x2000>,
-			      <0x4a310000 0x3000>,
-			      <0x4a320000 0x2000>,
-			      <0x4a326000 0x2000>;
-			reg-names = "dram0", "dram1", "shrdram2", "intc", "cfg";
-			interrupts = <20 21 22 23 24 25 26 27>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges;
-
-			pru0: pru@4a334000 {
-				compatible = "ti,pru-rproc";
-				reg = <0x4a334000 0x2000>,
-				      <0x4a322000 0x400>,
-				      <0x4a322400 0x100>;
-				reg-names = "iram", "control", "debug";
-				mboxes = <&mailbox &mbox_pru0>;
-			};
-
-			pru1: pru@4a338000 {
-				compatible = "ti,pru-rproc";
-				reg = <0x4a338000 0x2000>,
-				      <0x4a324000 0x400>,
-				      <0x4a324400 0x100>;
-				reg-names = "iram", "control", "debug";
-				mboxes = <&mailbox &mbox_pru1>;
-			};
-		};
-
 		elm: elm@48080000 {
 			compatible = "ti,am3352-elm";
 			reg = <0x48080000 0x2000>;
diff --git arch/arm/mach-omap2/omap_device.c arch/arm/mach-omap2/omap_device.c
index fcd2c9e..ce7a859 100644
--- arch/arm/mach-omap2/omap_device.c
+++ arch/arm/mach-omap2/omap_device.c
@@ -128,8 +128,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 	struct omap_device *od;
 	struct omap_hwmod *oh;
 	struct device_node *node = pdev->dev.of_node;
-	const char *oh_name;
-	int oh_cnt, i, ret = 0;
+	const char *oh_name, *rst_name;
+	int oh_cnt, dstr_cnt, i, ret = 0;
 	bool device_active = false;
 
 	oh_cnt = of_property_count_strings(node, "ti,hwmods");
@@ -181,6 +181,27 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 		pm_runtime_set_active(&pdev->dev);
 	}
 
+	dstr_cnt =
+		of_property_count_strings(node, "ti,deassert-hard-reset");
+	if (dstr_cnt > 0) {
+		for (i = 0; i < dstr_cnt; i += 2) {
+			of_property_read_string_index(
+				node, "ti,deassert-hard-reset", i,
+				&oh_name);
+			of_property_read_string_index(
+				node, "ti,deassert-hard-reset", i+1,
+				&rst_name);
+			oh = omap_hwmod_lookup(oh_name);
+			if (!oh) {
+				dev_warn(&pdev->dev,
+				"Cannot parse deassert property for '%s'\n",
+				oh_name);
+				break;
+			}
+			omap_hwmod_deassert_hardreset(oh, rst_name);
+		}
+	}
+
 odbfd_exit1:
 	kfree(hwmods);
 odbfd_exit:
diff --git drivers/uio/Kconfig drivers/uio/Kconfig
index 5a90914..6c5abe9 100644
--- drivers/uio/Kconfig
+++ drivers/uio/Kconfig
@@ -106,10 +106,10 @@ config UIO_NETX
 
 config UIO_PRUSS
 	tristate "Texas Instruments PRUSS driver"
-	depends on ARCH_DAVINCI_DA850
+	depends on ARCH_DAVINCI_DA850 || SOC_AM33XX
 	select GENERIC_ALLOCATOR
 	help
-	  PRUSS driver for OMAPL138/DA850/AM18XX devices
+	  PRUSS driver for OMAPL138/DA850/AM18XX and AM33XX devices
 	  PRUSS driver requires user space components, examples and user space
 	  driver is available from below SVN repo - you may use anonymous login
 
diff --git drivers/uio/uio_pruss.c drivers/uio/uio_pruss.c
index 96c4a19..c8c83e5 100644
--- drivers/uio/uio_pruss.c
+++ drivers/uio/uio_pruss.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
+#include <linux/of_gpio.h>
 #include <linux/uio_driver.h>
 #include <linux/platform_data/uio_pruss.h>
 #include <linux/io.h>
@@ -26,6 +27,11 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/genalloc.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #define DRV_NAME "pruss_uio"
 #define DRV_VERSION "1.0"
@@ -106,10 +112,12 @@ static void pruss_cleanup(struct platform_device *dev,
 		dma_free_coherent(&dev->dev, extram_pool_sz, gdev->ddr_vaddr,
 			gdev->ddr_paddr);
 	}
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 	if (gdev->sram_vaddr)
 		gen_pool_free(gdev->sram_pool,
 			      gdev->sram_vaddr,
 			      sram_pool_sz);
+#endif
 	kfree(gdev->info);
 	clk_put(gdev->pruss_clk);
 	kfree(gdev);
@@ -120,9 +128,15 @@ static int pruss_probe(struct platform_device *dev)
 	struct uio_info *p;
 	struct uio_pruss_dev *gdev;
 	struct resource *regs_prussio;
+	struct resource res;
 	int ret = -ENODEV, cnt = 0, len;
 	struct uio_pruss_pdata *pdata = dev_get_platdata(&dev->dev);
+    struct pinctrl *pinctrl;
 
+	int count;
+	struct device_node *child;
+	const char *pin_name;
+    
 	gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
 	if (!gdev)
 		return -ENOMEM;
@@ -132,6 +146,7 @@ static int pruss_probe(struct platform_device *dev)
 		kfree(gdev);
 		return -ENOMEM;
 	}
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 	/* Power on PRU in case its not done as part of boot-loader */
 	gdev->pruss_clk = clk_get(&dev->dev, "pruss");
 	if (IS_ERR(gdev->pruss_clk)) {
@@ -143,6 +158,63 @@ static int pruss_probe(struct platform_device *dev)
 	} else {
 		clk_enable(gdev->pruss_clk);
 	}
+#endif
+
+	if (dev->dev.of_node) {
+		pm_runtime_enable(&dev->dev);
+		ret = pm_runtime_get_sync(&dev->dev);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(&dev->dev, "pm_runtime_get_sync() failed\n");
+			return ret;
+		}
+
+		ret = of_address_to_resource(dev->dev.of_node, 0, &res);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(&dev->dev, "failed to parse DT reg\n");
+			return ret;
+		}
+		regs_prussio = &res;
+	}
+
+	pinctrl = devm_pinctrl_get_select_default(&dev->dev);
+	if (IS_ERR(pinctrl))
+		dev_warn(&dev->dev,
+			"pins are not configured from the driver\n");
+	else{
+		count = of_get_child_count(dev->dev.of_node);
+		if (!count){
+			dev_info(&dev->dev, "No children\n");
+			return -ENODEV;
+		}
+		// Run through all children. They have lables for easy reference.
+		for_each_child_of_node(dev->dev.of_node, child){
+			enum of_gpio_flags flags;
+			unsigned gpio;
+
+			count = of_gpio_count(child);
+
+			ret = of_property_count_strings(child, "pin-names");
+			if (ret < 0) {
+				dev_err(&dev->dev, "Failed to get pin-names\n");
+				continue;
+			}
+			if(count != ret){
+				dev_err(&dev->dev, "The number of gpios (%d) does not match"\
+					" the number of pin names (%d)\n", count, ret);
+				continue;
+			}
+
+			dev_err(&dev->dev, "Child has %u gpios\n", count);
+			for(cnt=0; cnt<count; cnt++){
+				ret = of_property_read_string_index(child,
+					"pin-names", cnt, &pin_name);
+				if (ret != 0)
+					dev_err(&dev->dev, "Error on pin-name #%d\n", cnt);
+				gpio = of_get_gpio_flags(child, cnt, &flags);
+				ret = devm_gpio_request_one(&dev->dev, gpio, flags, pin_name);
+			}
+		}
+	}
 
 	regs_prussio = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!regs_prussio) {
@@ -155,7 +227,7 @@ static int pruss_probe(struct platform_device *dev)
 		goto out_free;
 	}
 
-	if (pdata->sram_pool) {
+	if (pdata && pdata->sram_pool) {
 		gdev->sram_pool = pdata->sram_pool;
 		gdev->sram_vaddr =
 			(unsigned long)gen_pool_dma_alloc(gdev->sram_pool,
@@ -180,7 +252,17 @@ static int pruss_probe(struct platform_device *dev)
 		goto out_free;
 	}
 
-	gdev->pintc_base = pdata->pintc_base;
+	if (dev->dev.of_node) {
+		ret = of_property_read_u32(dev->dev.of_node,
+					   "ti,pintc-offset",
+					   &gdev->pintc_base);
+		if (ret < 0) {
+			dev_err(&dev->dev,
+				"Can't parse ti,pintc-offset property\n");
+			goto out_free;
+		}
+	} else
+		gdev->pintc_base = pdata->pintc_base;
 	gdev->hostirq_start = platform_get_irq(dev, 0);
 
 	for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
@@ -188,6 +270,7 @@ static int pruss_probe(struct platform_device *dev)
 		p->mem[0].size = resource_size(regs_prussio);
 		p->mem[0].memtype = UIO_MEM_PHYS;
 
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 		p->mem[1].addr = gdev->sram_paddr;
 		p->mem[1].size = sram_pool_sz;
 		p->mem[1].memtype = UIO_MEM_PHYS;
@@ -195,6 +278,11 @@ static int pruss_probe(struct platform_device *dev)
 		p->mem[2].addr = gdev->ddr_paddr;
 		p->mem[2].size = extram_pool_sz;
 		p->mem[2].memtype = UIO_MEM_PHYS;
+#else
+		p->mem[1].addr = gdev->ddr_paddr;
+		p->mem[1].size = extram_pool_sz;
+		p->mem[1].memtype = UIO_MEM_PHYS;
+#endif
 
 		p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
 		p->version = DRV_VERSION;
@@ -208,7 +296,6 @@ static int pruss_probe(struct platform_device *dev)
 		if (ret < 0)
 			goto out_free;
 	}
-
 	platform_set_drvdata(dev, gdev);
 	return 0;
 
@@ -225,12 +312,20 @@ static int pruss_remove(struct platform_device *dev)
 	return 0;
 }
 
+static const struct of_device_id pruss_dt_ids[] = {
+	{ .compatible = "ti,pruss-v1", .data = NULL, },
+	{ .compatible = "ti,pruss-v2", .data = NULL, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pruss_dt_ids);
+
 static struct platform_driver pruss_driver = {
 	.probe = pruss_probe,
 	.remove = pruss_remove,
 	.driver = {
 		   .name = DRV_NAME,
 		   .owner = THIS_MODULE,
+		   .of_match_table = pruss_dt_ids,
 		   },
 };
 

Pour pouvoir utiliser des broches du BBB avec le PRU, il faut d’abord les désactiver du PINMUX en rajoutant dans le dts am335x-boneblack.dts, par exemple:

&ocp {
	P9_28_pinmux {
			/* gpio1[29] */
			status = "disabled";
		};
	P9_29_pinmux {
			/* gpio1[29] */
			status = "disabled";
		};
};

 

 

 

, , , , , , , ,

This article was written by Cédric

Menu