This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/PROCESSOR-SDK-AM335X: Soft UART on PRU

Part Number: PROCESSOR-SDK-AM335X

Tool/software: Linux

Hi,

I'm porting linux kernel from Sitara SDK 05.07.00 to PROCESSOR-SDK-LINUX-AM335X 04_02_00_09 for a customized printer controller board (based on AM335xx EVM).

It has the support for soft-UART implementation on the Programmable Real-Time Unit (PRU) done by somebody in the past.  Can you please tell me how to add the same on PROCESSOR-SDK-LINUX-AM335X.
I found a link for kernel 3.2 version
processors.wiki.ti.com/.../Soft-UART_Implementation_on_AM335X_PRU_-_Software_Users_Guide

The links in that website are obsolete now.
Please provide me the link for the same (soft uart on PRU) on latest SDK.

Thanks,

Jeya

  • Hello Jeya,

    TI has not touched the soft UART code since kernel 3.2 in 2012, so I cannot provide the same code on our Processor SDK 4.2 release. However, I can try to rustle up the original code if you do not have access to it, so that you can forward port it to Processor SDK 4.2.

    Please let me know if you need the original code.

    Regards,
    Nick
  • /*
     * Copyright (C) 2010, 2011 Texas Instruments Incorporated
     *
     * This program is free software; you can redistribute it and/or modify it
     * under the terms of the GNU General Public License as  published by the
     * Free Software Foundation version 2.
     *
     * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
     * whether express or implied; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * General Public License for more details.
     */
    
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/module.h>
    #include <linux/bitops.h>
    #include <linux/interrupt.h>
    #include <linux/spinlock.h>
    #include <linux/errno.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/mfd/pruss.h>
    #include <linux/mfd/core.h>
    #include <linux/io.h>
    #include <linux/slab.h>
    #include <linux/err.h>
    
    struct pruss_priv {
        struct device *dev;
        spinlock_t lock;
        struct resource *res;
        struct clk *clk;
        void __iomem *ioaddr;
    };
    
    // Static function declarations
    static s32 pruss_lcl_writel(struct pruss_priv *pruss, u32 offset, u32 pdatatowrite);
    static s32 pruss_lcl_readl(struct pruss_priv *pruss, u32 offset, u32 *pdatatoread);
    static s32 pruss_lcl_rmwl(struct pruss_priv *pruss, u32 offset, u32 mask, u32 val);
    static s32 pruss_idx_lcl_writel(struct pruss_priv *pruss, u32 offset, u32 value);
    
    s32 pruss_disable(struct device *dev, u8 pruss_num)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        struct prusscore_regs __iomem *h_pruss;
        struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
        u32 temp_reg;
    
    //    __FN_IN
    
            if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
                return -EINVAL;
    
        spin_lock(&pruss->lock);
    
        /* pruss deinit */
        iowrite32(0xFFFFFFFF, &pruss_mmap->intc.statclrint[pruss_num]);
    
        /* Disable PRU */
        h_pruss = &pruss_mmap->core[pruss_num];
        temp_reg = ioread32(&h_pruss->control);
        temp_reg = (temp_reg &
                ~PRUCORE_CONTROL_COUNTENABLE_MASK) |
            ((PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
              PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
             PRUCORE_CONTROL_COUNTENABLE_MASK);
        iowrite32(temp_reg, &h_pruss->control);
    
        temp_reg = ioread32(&h_pruss->control);
        temp_reg = (temp_reg &
                ~PRUCORE_CONTROL_ENABLE_MASK) |
            ((PRUCORE_CONTROL_ENABLE_DISABLE <<
              PRUCORE_CONTROL_ENABLE_SHIFT) &
             PRUCORE_CONTROL_ENABLE_MASK);
        iowrite32(temp_reg, &h_pruss->control);
    
        /* Reset PRU */
        iowrite32(PRUCORE_CONTROL_RESETVAL,
                &h_pruss->control);
        spin_unlock(&pruss->lock);
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_disable);
    
    s32 pruss_enable(struct device *dev, u8 pruss_num)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        struct prusscore_regs __iomem *h_pruss;
        struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
        u32 i;
    //    __FN_IN
    
        if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
            return -EINVAL;
    
        h_pruss = &pruss_mmap->core[pruss_num];
    
        /* Reset PRU  */
        spin_lock(&pruss->lock);
        iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);
        spin_unlock(&pruss->lock);
    
        /* Reset any garbage in the ram */
        if (pruss_num == PRUCORE_0)
            for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
                iowrite32(0x0, &pruss_mmap->dram0[i]);
        else if (pruss_num == PRUCORE_1)
            for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
                iowrite32(0x0, &pruss_mmap->dram1[i]);
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_enable);
    
    /* Load the specified PRU with code */
    s32 pruss_load(struct device *dev, u8 pruss_num,
            u32 *pruss_code, u32 code_size_in_words)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32 *pruss_iram;
        u32 i;
    
        if (pruss_num == PRUCORE_0) {
            pruss_iram = (u32 *) ((u32) pruss->ioaddr + PRU0_IRAM);
        } else if (pruss_num == PRUCORE_1) {
            pruss_iram = (u32 *) ((u32) pruss->ioaddr + PRU1_IRAM);
        } else
            return -EINVAL;
    
    //    printk("\npruss_code=%d\n",pruss_code[0]);
        pruss_enable(dev, pruss_num);
        spin_lock(&pruss->lock);
        /* Copy PRU code to its instruction RAM  */
        for (i = 0; i < code_size_in_words; i++) {
            pruss_iram[i]=pruss_code[i];
        }
        spin_unlock(&pruss->lock);
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_load);
    
    s32 pruss_run(struct device *dev, u8 pruss_num)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        struct prusscore_regs __iomem *h_pruss;
        struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
        u32 temp_reg = 0;
    //    __FN_IN
    
        if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
            return -EINVAL;
    //    printk("\npruss_num=%d\n",pruss_num);
        h_pruss = &pruss_mmap->core[pruss_num];
    
    //    printk(KERN_INFO "\n%s value=0x%08x,addr=0x%08x\n", __FUNCTION__, temp_reg,(u32)&h_pruss->control);
        /* Enable PRU, let it execute the code we just copied */
        spin_lock(&pruss->lock);
        temp_reg = ioread32(&h_pruss->control);
        temp_reg = (temp_reg &
                ~PRUCORE_CONTROL_COUNTENABLE_MASK) |
            ((PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
              PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
             PRUCORE_CONTROL_COUNTENABLE_MASK);
        iowrite32(temp_reg, &h_pruss->control);
    
    //    printk(KERN_INFO "\n%s value=0x%08x,addr=0x%08x\n", __FUNCTION__, temp_reg,(u32)&h_pruss->control);
    
        temp_reg = ioread32(&h_pruss->control);
        temp_reg = (temp_reg &
                ~PRUCORE_CONTROL_ENABLE_MASK) |
            ((PRUCORE_CONTROL_ENABLE_ENABLE <<
              PRUCORE_CONTROL_ENABLE_SHIFT) &
             PRUCORE_CONTROL_ENABLE_MASK);
        iowrite32(temp_reg, &h_pruss->control);
    //    printk(KERN_INFO "\n%s value=0x%08x,addr=0x%08x\n", __FUNCTION__, temp_reg,(u32)&h_pruss->control);
        spin_unlock(&pruss->lock);
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_run);
    
    s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        struct prusscore_regs __iomem *h_pruss;
        struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
        u32 temp_reg;
        u32 cnt = timeout;
    
    //    __FN_IN
        if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
            return -EINVAL;
    //    printk("\npruss_num=%d\n",pruss_num);
        h_pruss = &pruss_mmap->core[pruss_num];
    
        while (cnt--) {
            temp_reg = ioread32(&h_pruss->control);
            if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
                        PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
                    PRUCORE_CONTROL_RUNSTATE_HALT)
                break;
        }
        if (!cnt)
            return -EBUSY;
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_wait_for_halt);
    
    s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite8(pdatatowrite, paddresstowrite);
        //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_writeb);
    
    s32 pruss_writeb_multi(struct device *dev, u32 offset,
    		u8 *pdatatowrite, u16 bytestowrite)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstowrite;
        u16 i;
    
        paddresstowrite = pruss->ioaddr + offset;
    
        for (i = 0; i < bytestowrite; i++)
            iowrite8(*pdatatowrite++, paddresstowrite++);
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_writeb_multi);
    
    s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddress;
        u32 preg_data;
    
    //    __FN_IN
        paddress = pruss->ioaddr + offset;
    
        spin_lock(&pruss->lock);
        preg_data = ioread8(paddress);
        preg_data &= ~mask;
        preg_data |= val;
        iowrite8(preg_data, paddress);
        spin_unlock(&pruss->lock);
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_rmwb);
    
    s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstoread;
    
        paddresstoread = pruss->ioaddr + offset ;
        *pdatatoread = ioread8(paddresstoread);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_readb);
    
    u8 pruss_readb_ret(struct device *dev, u32 offset)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstoread;
    
        paddresstoread = pruss->ioaddr + offset ;
    //    printk (KERN_INFO "%s 0x%04x 0x%02x\n", __FUNCTION__, offset, ioread8(paddresstoread));
        return ioread8(paddresstoread);
    }
    EXPORT_SYMBOL_GPL(pruss_readb_ret);
    
    s32 pruss_readb_multi(struct device *dev, u32 offset,
            u8 *pdatatoread, u16 bytestoread)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u8 __iomem *paddresstoread;
        u16 i;
    
        paddresstoread = pruss->ioaddr + offset;
    
        for (i = 0; i < bytestoread; i++)
            *pdatatoread++ = ioread8(paddresstoread++);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_readb_multi);
    
    s32 pruss_writel(struct device *dev, u32 offset,
            u32 pdatatowrite)
    {
        //	__FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite32(pdatatowrite, paddresstowrite);
        //	__FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_writel);
    
    s32 pruss_writel_multi(struct device *dev, u32 offset,
            u32 *pdatatowrite, u16 wordstowrite)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32 __iomem *paddresstowrite;
        u16 i;
    
        paddresstowrite = pruss->ioaddr + offset;
    
        for (i = 0; i < wordstowrite; i++)
            iowrite32(*pdatatowrite++, paddresstowrite++);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_writel_multi);
    
    s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
    {
        //	__FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddress;
        u32 preg_data;
    
        paddress = pruss->ioaddr + offset;
    
        spin_lock(&pruss->lock);
        preg_data = ioread32(paddress);
        preg_data &= ~mask;
        preg_data |= val;
        iowrite32(preg_data, paddress);
        spin_unlock(&pruss->lock);
        //	__FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_rmwl);
    
    s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstoread;
    
        paddresstoread = pruss->ioaddr + offset;
        *pdatatoread = ioread32(paddresstoread);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_readl);
    
    s32 pruss_readl_multi(struct device *dev, u32 offset,
            u32 *pdatatoread, u16 wordstoread)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32 __iomem *paddresstoread;
        u16 i;
    
        paddresstoread = pruss->ioaddr + offset;
        for (i = 0; i < wordstoread; i++)
            *pdatatoread++ = ioread32(paddresstoread++);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_readl_multi);
    
    s32 pruss_writew(struct device *dev, u32 offset, u16 pdatatowrite)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite16(pdatatowrite, paddresstowrite);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_writew);
    
    s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val)
    {
        //    __FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddress;
        u32 preg_data;
    
        paddress = pruss->ioaddr + offset;
    
        spin_lock(&pruss->lock);
        preg_data = ioread16(paddress);
        preg_data &= ~mask;
        preg_data |= val;
        iowrite16(preg_data, paddress);
        spin_unlock(&pruss->lock);
        //    __FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_rmww);
    
    s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread)
    {
        //	__FN_IN
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstoread;
    
        paddresstoread = pruss->ioaddr + offset;
        *pdatatoread = ioread16(paddresstoread);
        //	__FN_OUT
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_readw);
    
    s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite32(value, paddresstowrite);
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_idx_writel);
    
    s32 pruss_enable_system_interrupt(struct device *dev, u32 sysintrnum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        if(sysintrnum < PRUSS_INTC_SYSINTR_MAX)
            pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, sysintrnum);
        else
            return -1;
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_enable_system_interrupt);
    
    s32 pruss_disable_system_interrupt(struct device *dev, u32 sysintrnum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        if(sysintrnum < PRUSS_INTC_SYSINTR_MAX)
            pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, sysintrnum);
        else
            return -1;
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_disable_system_interrupt);
    
    s32 pruss_enable_system_interrupts(struct device *dev, u32 prunum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    //    __FN_IN
    
        switch(prunum) {
            case PRUSS_NUM0:
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 16);
    
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 20);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 21);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 22);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 23);
                break;
            case PRUSS_NUM1:
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 17);
    
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 24);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 25);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 26);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXSET, 27);
                break;
            default:
                return -1;
        }
    
    //    __FN_OUT
            return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_enable_system_interrupts);
    
    s32 pruss_disable_system_interrupts(struct device *dev, u32 prunum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        switch(prunum) {
            case PRUSS_NUM0:
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 16);
    
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 20);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 21);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 22);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 23);
                break;
            case PRUSS_NUM1:
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 17);
    
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 24);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 25);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 26);
                pruss_idx_lcl_writel(pruss, PRUSS_INTC_ENIDXCLR, 27);
                break;
            default:
                return -1;
        }
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_disable_system_interrupts);
    
    s32 pruss_system_interrupt_is_set(struct device *dev, u32 sysintrnum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32                statusreg = 0;
    
        if(sysintrnum < 32) {
            pruss_lcl_readl(pruss, PRUSS_INTC_STATCLRINT0, &statusreg);
            return (statusreg & ((u32)(1 << sysintrnum)));
        }
        else if(sysintrnum < 64) {
            pruss_lcl_readl(pruss, PRUSS_INTC_STATCLRINT1, &statusreg);
            sysintrnum -= 32;
            return (statusreg & ((u32)(1 << sysintrnum)));
        }
        else
            return -1;
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_system_interrupt_is_set);
    
    s32 pruss_system_interrupt_set(struct device *dev, u32 sysintrnum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        if(sysintrnum < PRUSS_INTC_SYSINTR_MAX)
            pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXSET, sysintrnum);
        else
            return -1;
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_system_interrupt_set);
    
    s32 pruss_system_interrupt_clr(struct device *dev, u32 sysintrnum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        if(sysintrnum < PRUSS_INTC_SYSINTR_MAX)
            pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXCLR, sysintrnum);
        else
            return -1;
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_system_interrupt_clr);
    
    s32 pruss_arm_to_pru_intr_set(struct device *dev, u32 prunum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        switch(prunum) {
            case PRUSS_NUM0:
                pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXSET, 16);
                break;
            case PRUSS_NUM1:
                pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXSET, 17);
                break;
            default:
                return -1;
        }
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_arm_to_pru_intr_set);
    
    s32 pruss_arm_to_pru_intr_clr(struct device *dev, u32 prunum)
    {
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
    
        switch(prunum) {
            case PRUSS_NUM0:
                pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXCLR, 16);
                break;
            case PRUSS_NUM1:
                pruss_lcl_writel(pruss, PRUSS_INTC_STATIDXCLR, 17);
                break;
            default:
                return -1;
        }
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(pruss_arm_to_pru_intr_clr);
    
    static int pruss_mfd_add_devices(struct platform_device *pdev)
    {
        struct device *dev = &pdev->dev;
        struct mfd_cell *cell = pdev->dev.platform_data;
        s32 err, i, num_devices = 0;
    
    //    __FN_IN
        for (i = 0; cell[i].name; i++) {
            err = mfd_add_devices(dev, 0, &cell[i], 1, NULL, 0);
            if (err) {
                dev_err(dev, "cannot add mfd cell: %s\n",
                        cell[i].name);
                continue;
            }
            num_devices++;
            dev_info(dev, "mfd: added %s device\n", cell[i].name);
        }
    //    __FN_OUT
            return num_devices;
    }
    
    static s32 pruss_lcl_writel(struct pruss_priv *pruss, u32 offset, u32 pdatatowrite)
    {
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite32(pdatatowrite, paddresstowrite);
        return 0;
    }
    
    static s32 pruss_lcl_readl(struct pruss_priv *pruss, u32 offset, u32 *pdatatoread)
    {
        void __iomem *paddresstoread;
    
        paddresstoread = pruss->ioaddr + offset;
        *pdatatoread = ioread32(paddresstoread);
        return 0;
    }
    
    static s32 pruss_lcl_rmwl(struct pruss_priv *pruss, u32 offset, u32 mask, u32 val)
    {
        void __iomem *paddress;
        u32 preg_data;
    
        paddress = pruss->ioaddr + offset;
    
        spin_lock(&pruss->lock);
        preg_data = ioread32(paddress);
        preg_data &= ~mask;
        preg_data |= val;
        iowrite32(preg_data, paddress);
        spin_unlock(&pruss->lock);
        return 0;
    }
    
    static s32 pruss_idx_lcl_writel(struct pruss_priv *pruss, u32 offset, u32 value)
    {
        void __iomem *paddresstowrite;
    
        paddresstowrite = pruss->ioaddr + offset;
        iowrite32(value, paddresstowrite);
        return 0;
    }
    
    static void arm_to_pru_intr_init(struct pruss_priv *pruss)
    {
        u32 value;
        u32 int_offset;
    
    //    __FN_IN
        /* Clear all the host interrupts */
        for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
                int_offset++)
            pruss_idx_lcl_writel(pruss, PRUSS_INTC_HSTINTENIDXCLR, int_offset);
    
        /* Enable the global s32errupt */
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_GLBLEN, 0, 1);
    
        /* Enable the Host interrupts for all host channels */
        for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
                int_offset++)
            pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_HSTINTENIDXSET,
                    0, int_offset);
    
        /* Set the Host insterrupt to Channel number mapping */
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_HOSTMAP0,
                PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP0_CHAN);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_HOSTMAP1,
                PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP1_CHAN);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_HOSTMAP2,
                PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP2_CHAN);
    
        /* Set the Channel to System event mapping */
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP1,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP1_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP4,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP4_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP5,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP5_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP6,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP6_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP7,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP7_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP8,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_FULL);
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_CHANMAP13,
                PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP13_FULL);
    
        /* Clear required set of system events
         * and enable them using indexed register
         */
        for (int_offset = 0; int_offset < 16; int_offset++) {
            value = 18 + int_offset;
            pruss_idx_lcl_writel(pruss, PRUSS_INTC_STATIDXCLR, value);
        }
    
        pruss_idx_lcl_writel(pruss, PRUSS_INTC_STATIDXCLR, 54);
    
        pruss_lcl_rmwl(pruss, (u32) PRUSS_INTC_GLBLEN, 0, 1);
    
        /* Enable the Host interrupts for all host channels */
        for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
                int_offset++)
            pruss_idx_lcl_writel(pruss, PRUSS_INTC_HSTINTENIDXSET, int_offset);
    
    //    __FN_OUT
    }
    
    static int __devinit pruss_probe(struct platform_device *pdev)
    {
        struct pruss_priv *pruss = NULL;
        s32 err;
    
    //    __FN_IN
        pruss = kzalloc(sizeof(struct pruss_priv), GFP_KERNEL);
        if (!pruss)
            return -ENOMEM;
    
        pruss->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!pruss->res) {
            dev_err(&pdev->dev,
                    "unable to get pruss memory resources!\n");
            err = -ENODEV;
            goto probe_exit_kfree;
        }
        if (!request_mem_region(pruss->res->start,
                    resource_size(pruss->res), dev_name(&pdev->dev))) {
            dev_err(&pdev->dev, "pruss memory region already claimed!\n");
            err = -EBUSY;
            goto probe_exit_kfree;
        }
    
        pruss->ioaddr = ioremap(pruss->res->start,
                resource_size(pruss->res));
        if (!pruss->ioaddr) {
            dev_err(&pdev->dev, "ioremap failed\n");
            err = -ENOMEM;
            goto probe_exit_free_region;
        }
    //    printk("\nioaddr=%p\n", pruss->ioaddr);
    
        pruss->clk = clk_get(NULL, "pruss");
        if (IS_ERR(pruss->clk)) {
            dev_err(&pdev->dev, "no clock available: pruss\n");
            err = -ENODEV;
            pruss->clk = NULL;
            goto probe_exit_iounmap;
        }
        spin_lock_init(&pruss->lock);
    
        clk_enable(pruss->clk);
    
        err = pruss_mfd_add_devices(pdev);
        if (!err)
            goto probe_exit_clock;
    
        platform_set_drvdata(pdev, pruss);
        pruss->dev = &pdev->dev;
    
        arm_to_pru_intr_init(pruss);
    
    //    __FN_OUT
            return 0;
    
    probe_exit_clock:
        clk_put(pruss->clk);
        clk_disable(pruss->clk);
    probe_exit_iounmap:
        iounmap(pruss->ioaddr);
    probe_exit_free_region:
        release_mem_region(pruss->res->start,
                resource_size(pruss->res));
    probe_exit_kfree:
        kfree(pruss);
        return err;
    }
    
    static int __devexit pruss_remove(struct platform_device *pdev)
    {
        struct device *dev = &pdev->dev;
        struct pruss_priv *pruss = dev_get_drvdata(dev);
    
    //    __FN_IN
        mfd_remove_devices(dev);
        pruss_disable(dev, PRUCORE_0);
        pruss_disable(dev, PRUCORE_1);
        clk_disable(pruss->clk);
        clk_put(pruss->clk);
        iounmap(pruss->ioaddr);
        release_mem_region(pruss->res->start, resource_size(pruss->res));
        kfree(pruss);
        dev_set_drvdata(dev, NULL);
    //    __FN_OUT
            return 0;
    }
    
    static struct platform_driver pruss_driver = {
        .probe	= pruss_probe,
        .remove	= __devexit_p(pruss_remove),
        .driver	= {
            .name	= "pruss_mfd",
            .owner	= THIS_MODULE,
        }
    };
    
    static int __init pruss_init(void)
    {
        return platform_driver_register(&pruss_driver);
    }
    module_init(pruss_init);
    
    static void __exit pruss_exit(void)
    {
        platform_driver_unregister(&pruss_driver);
    }
    module_exit(pruss_exit);
    
    MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
    MODULE_AUTHOR("Subhasish Ghosh");
    MODULE_AUTHOR("http://www.smartembeddedsystems.com");
    
    Hi Nick,

    Thanks for the reply.

    Please provide the original code for soft UART.

    Also I could see the PRUSS initialization code as drivers/mfd/pruss.c. But could not find similar files in the latest SDK release. Is that code (drivers/mfd/pruss.c) required or that part is handled by some other driver code. I have attached the file (drivers/mfd/pruss.c ) in kernel 3.2 for your reference.

    Thanks,

    Jeya

  • Hello Jeya,

    I am working on getting that soft UART code back on an external repository for you; I'll keep you updated.

    PRU initialization and firmware loading is done using the RemoteProc driver in Linux SDK 4.2. Please take a look at the RemoteProc and RPMsg wiki. The relevant drivers are in drivers/remoteproc/

    Regards, 

    Nick

  • I haven't heard anything yet.

    Nick
  • Can you please upload the files soon.

    Thanks,

    Jeya

  • Hello Jeya,

    It looks like some of the soft UART code is still out there, but at a slightly different URL now that it's in a read-only mirror of the former gitorious.org. I was able to clone the SUART Firmware and the Linux Kernel and Driver Source from
    gitorious.org/.../am335x-pru-uart-fw.git
    and
    gitorious.org/.../am335x-pru-linux-drivers.git
    respectively.

    Notes:
    * I was not able to find or clone the OpenEmbedded Recipes.
    * I can't guarantee to future readers that the code will still be available at those locations at a later time
    * TI no longer supports this code. You are welcome to look at it as a reference, but I cannot answer questions about it.

    Regards,
    Nick