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