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