pruss mfd drivers
Subsystems (8)
v2 cover pruss mfd drivers
PRUSS Functional Block Diagram
/----------------------------------------------------\
| |
| |------| |
32GPO<------->PRU CORE-0 <------>| |<------> DRAM 0 |
30GPI<------->(4KB IRAM) | S | (512 Bytes) |
| | | |
32GPO<------->PRU CORE-1 <------>| C |<------> DRAM 1 |
30GPI<------->(4KB IRAM) | | (512 Bytes) |
| | R | |
| | | |
Ints to ARM/ | Interrupt <------>| |-------------------------> Master I/F (to SCR2)
DSP INTC <------->Controller | |<------------------------- Slave I/F (from SCR2)
Events from | (INTC) |------| |
Periph + PRUs | |
\----------------------------------------------------/Programmable Realtime Unit (PRU) is basically a 32-bit RISC processor available within TI's DA8XX SOCs. It consists of local instruction and data RAM and also has access to SOC resources via a Switched Central Resource (SCR).
There are two PRU's available within DA8XX SOC's PRUSS, hence providing two execution cores. Devices/Protocols can be emulated on these utilizing either both or only one of the PRUs independently.
The rational behind the MFD driver being the fact that multiple devices can be implemented on the cores independently.
It's also possible, as in our case, to implement a single device on both the PRU's resulting in improved load sharing.
A detailed description is also available here:
http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
version 2:
==========
* added pruss TTY Soft-UART driver.
* added pruss Soft-UART board and platform changes.
* fixed previous review comments.
* reordered patch sequence.
version 1:
==========
* added pruss mfd driver.
* added pruss mfd board and platform changes.
* added pruss SocketCAN driver.
* added pruss SocketCAN board and platform changes.
* added pruss SocketCAN GPIOs.
* added previous review comments.
Subhasish Ghosh (13):
mfd: pruss mfd driver.
da850: pruss platform specific additions.
da850: pruss board specific additions.
mfd: pruss CAN private data.
da850: pruss CAN platform specific additions.
da850: pruss CAN board specific additions.
da850: pruss CAN platform specific changes for gpios.
da850: pruss CAN board specific changes for gpios.
can: pruss CAN driver.
mfd: pruss SUART private data.
da850: pruss SUART board specific additions.
da850: pruss SUART platform specific additions.
tty: pruss SUART driver
arch/arm/mach-davinci/board-da850-evm.c | 105 + arch/arm/mach-davinci/da850.c | 12 + arch/arm/mach-davinci/devices-da8xx.c | 76 + arch/arm/mach-davinci/include/mach/da8xx.h | 2 + arch/arm/mach-davinci/include/mach/mux.h | 5 + drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/da8xx_pru.c | 446 ++++ drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/da8xx_pruss/Kconfig | 73 + drivers/net/can/da8xx_pruss/Makefile | 7 + drivers/net/can/da8xx_pruss/pruss_can.c | 758 +++++++ drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 ++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.h | 290 +++ drivers/tty/serial/Kconfig | 2 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/da8xx_pruss/Kconfig | 19 + drivers/tty/serial/da8xx_pruss/Makefile | 9 + drivers/tty/serial/da8xx_pruss/pruss_suart.c | 1014 +++++++++ drivers/tty/serial/da8xx_pruss/pruss_suart_api.c | 2350 ++++++++++++++++++++ drivers/tty/serial/da8xx_pruss/pruss_suart_api.h | 345 +++ drivers/tty/serial/da8xx_pruss/pruss_suart_board.h | 58 + drivers/tty/serial/da8xx_pruss/pruss_suart_err.h | 48 + drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h | 526 +++++ drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h | 153 ++ drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c | 384 ++++ drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h | 63 + include/linux/mfd/pruss/da8xx_pru.h | 131 ++ include/linux/mfd/pruss/da8xx_prucore.h | 74 + include/linux/serial_core.h | 2 + 31 files changed, 8193 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/da8xx_pru.c create mode 100644 drivers/net/can/da8xx_pruss/Kconfig create mode 100644 drivers/net/can/da8xx_pruss/Makefile create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h create mode 100644 drivers/tty/serial/da8xx_pruss/Kconfig create mode 100644 drivers/tty/serial/da8xx_pruss/Makefile create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h create mode 100644 include/linux/mfd/pruss/da8xx_pru.h create mode 100644 include/linux/mfd/pruss/da8xx_prucore.h
Signature · 1 line
1.7.2.3
PATCH v2 1/13 mfd: pruss mfd driver.
This patch adds the pruss MFD driver and associated include files.
--- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/da8xx_pru.c | 446 +++++++++++++++++++++++++++++++ include/linux/mfd/pruss/da8xx_pru.h | 122 +++++++++ include/linux/mfd/pruss/da8xx_prucore.h | 74 +++++ 5 files changed, 653 insertions(+), 0 deletions(-) create mode 100644 drivers/mfd/da8xx_pru.c create mode 100644 include/linux/mfd/pruss/da8xx_pru.h create mode 100644 include/linux/mfd/pruss/da8xx_prucore.h
drivers/mfd/Kconfig +10 -0
@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850 + select MFD_CORE + help + This driver provides support api's for the programmable + realtime unit (PRU) present on TI's da8xx processors. It + provides basic read, write, config, enable, disable + routines to facilitate devices emulated on it. + config HTC_EGPIO bool "HTC EGPIO support" depends on GENERIC_HARDIRQS && GPIOLIB && ARM
drivers/mfd/Makefile +1 -0
@@ -13,6 +13,7 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o +obj-$(CONFIG_MFD_DA8XX_PRUSS) += da8xx_pru.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o
drivers/mfd/da8xx_pru.c new file +446 -0
446 lines not on this page · raw message
include/linux/mfd/pruss/da8xx_pru.h new file +122 -0
122 lines not on this page · raw message
include/linux/mfd/pruss/da8xx_prucore.h new file +74 -0
74 lines not on this page · raw message
Signature · 1 line
1.7.2.3
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
This patch adds the pruss MFD driver and associated include files.
A more detailed changelog would be better. What is this device, why is it an MFD and what are its potential subdevices ?
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 11 lines
drivers/mfd/Kconfig +3
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
Why are we depending on those ?
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 92
Quoted 6 lines
drivers/mfd/Kconfig +6
-0+ select MFD_CORE + help + This driver provides support api's for the programmable + realtime unit (PRU) present on TI's da8xx processors. It + provides basic read, write, config, enable, disable + routines to facilitate devices emulated on it.
Please fix your identation here.
drivers/mfd/da8xx_pru.c line 2
Quoted 5 lines
drivers/mfd/da8xx_pru.c new file +2
-0@@ -0,0 +1,446 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated
s/2010/2011/ ?
Quoted 14 lines
drivers/mfd/da8xx_pru.c new file +14
-0+* 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>
drivers/mfd/da8xx_pru.c line 27
Quoted 10 lines
drivers/mfd/da8xx_pru.c new file +10
-0+#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/mfd/pruss/da8xx_prucore.h> +#include <linux/mfd/pruss/da8xx_pru.h> +#include <linux/mfd/core.h> +#include <linux/io.h> +#include <mach/da8xx.h>
Is that include needed ?
drivers/mfd/da8xx_pru.c line 29
Quoted 1 line
drivers/mfd/da8xx_pru.c new file +1
-0+struct da8xx_pruss {
What is the "ss" suffix for ?
drivers/mfd/da8xx_pru.c line 54
Quoted 10 lines
drivers/mfd/da8xx_pru.c new file +10
-0+u32 pruss_disable (struct device *dev,u8 pruss_num) +{ +struct da8xx_pruss *pruss =dev_get_drvdata (dev->parent); +da8xx_prusscore_regs h_pruss; +u32 temp_reg; + +if (pruss_num ==DA8XX_PRUCORE_0 ) { +/* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32 ) pruss->ioaddr +0x7000 );
So it seems you're doing this in several places, and I have a few comments:
- You don't need the da8xx_prusscore_regs at all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map offset.
Then routines like this one will look a lot more readable.
Quoted 2 lines
drivers/mfd/da8xx_pru.c new file +2
-0+s16 pruss_writeb (struct device *dev,u32 u32offset, +u8 *pu8datatowrite,u16 u16bytestowrite)
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Thank you for your comments.
--------------------------------------------------
From: "Samuel Ortiz" <[email protected]>
Sent: Monday, February 21, 2011 10:00 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 7 lines
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
This patch adds the pruss MFD driver and associated include files.
A more detailed changelog would be better. What is this device, why is it an MFD and what are its potential subdevices ?
SG -- Will add a more detailed change log.
Quoted 8 lines
Quoted 8 lines
drivers/mfd/Kconfig +0
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more.
Quoted 4 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 3 lines
drivers/mfd/Kconfig +3
-0+config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.
Quoted 9 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 92
Quoted 8 lines
drivers/mfd/Kconfig +6
-0+ select MFD_CORE + help + This driver provides support api's for the programmable + realtime unit (PRU) present on TI's da8xx processors. It + provides basic read, write, config, enable, disable + routines to facilitate devices emulated on it.Please fix your identation here.
SG -- Will do.
Quoted 27 lines
drivers/mfd/da8xx_pru.c line 2
Quoted 6 lines
drivers/mfd/da8xx_pru.c new file +2
-0@@ -0,0 +1,446 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated s/2010/2011/ ?
Quoted 19 lines
drivers/mfd/da8xx_pru.c new file +1
-0+* 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.
+ */drivers/mfd/da8xx_pru.c new file +8
-0+ +#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/errno.h>
Quoted 8 lines
drivers/mfd/da8xx_pru.c line 27
Quoted 7 lines
drivers/mfd/da8xx_pru.c new file +7
-0+#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/mfd/pruss/da8xx_prucore.h> +#include <linux/mfd/pruss/da8xx_pru.h> +#include <linux/mfd/core.h> +#include <linux/io.h> +#include <mach/da8xx.h> Is that include needed ?
SG - Will remove if not needed.
Quoted 4 lines
Quoted 3 lines
+struct
da8xx_pruss{What is the "ss" suffix for ?
SG -- We call it the PRU Sub-System.
Quoted 14 lines
drivers/mfd/da8xx_pru.c line 54
Quoted 12 lines
drivers/mfd/da8xx_pru.c new file +10
-0+u32 pruss_disable (struct device *dev,u8 pruss_num) +{ +struct da8xx_pruss *pruss =dev_get_drvdata (dev->parent); +da8xx_prusscore_regs h_pruss; +u32 temp_reg; + +if (pruss_num ==DA8XX_PRUCORE_0 ) { +/* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32 ) pruss->ioaddr +0x7000 );So it seems you're doing this in several places, and I have a few comments:
Quoted 7 lines
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing. If we use #defines to plot all the
registers, then first, there are too many array type registers which will need to be duplicated.
And if the offset of one of the macro changes in between, we
will require to adjust all the rest of the macros. So I felt like a structure was a better option here.
I also named the structure elements as per the register names.
so why should it be less readable ? But, we can definitely use macros to define the PRUSS0 & 1
offsets instead of the magic numbers as above.
Quoted 5 lines
Quoted 3 lines
+s16 pruss_writeb(struct device *dev, u32 u32offset,
+ u8 *pu8datatowrite, u16 u16bytestowrite)From CodingStyle: "Encoding the type of a function into the name (so-called Hungarian notation) is brain damaged"
SG -- Will change.
Quoted 3 lines
Also, all your exported routines severely lack any sort of locking. An IO mutex or spinlock is mandatory here.
SG - As per our current implementation, we do not have two devices running simultaneously on the PRU,
so we do not have any way to test it. We have kept this as an
enhancement if request comes in for
multiple devices.
Quoted 19 lines
Quoted 19 lines
drivers/mfd/da8xx_pru.c new file +18
-0+static int pruss_mfd_add_devices (struct platform_device *pdev) +{ +struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data; +struct device *dev = &pdev->dev; +struct mfd_cell cell; +u32 err, count; + +for (count =0 ; (dev_data + count)->dev_name !=NULL ; count++) { +memset (&cell,0 ,sizeof (struct mfd_cell )); + cell.id = count; + cell.name = (dev_data + count)->dev_name; + cell.platform_data = (dev_data + count)->pdata; + cell.data_size = (dev_data + count)->pdata_size; + + err =mfd_add_devices (dev,0 , &cell,1 ,NULL ,0 ); +if (err) { +dev_err (dev,"cannot add mfd cells\n" ); +return err;
Quoted 8 lines
Quoted 4 lines
+ }
+ }
+ return err;
+}So, what are the potential subdevices for this driver ? If it's a really dynamic setup, I'm fine with passing those as platform data but then do it so that you pass a NULL terminated
da8xx_pruss_devicesarray. That will avoid most of the ugly casts you're doing here.
SG -- I did not follow your recommendations here, could you please elaborate.
I am already checking the dev_name for a NULL.
This device is basically a microcontroller within DA850, so
basically any device or protocol can be
emulated on it. Currently, we have emulated 8 UARTS using the
two PRUs and also a CAN device.
Quoted 25 lines
Quoted 25 lines
include/linux/mfd/pruss/da8xx_pru.h new file +5
-0@@ -0,0 +1,122 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Jitendra Kumar <[email protected]> +* +* 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/mfd/pruss/da8xx_pru.h new file +3
-0+ +#ifndef _PRUSS_H_ +#define _PRUSS_H_
Quoted 8 lines
include/linux/mfd/pruss/da8xx_pru.h line 23
Quoted 7 lines
include/linux/mfd/pruss/da8xx_pru.h new file +7
-0+ +#include <linux/types.h> +#include <linux/platform_device.h> +#include "da8xx_prucore.h" + +#define PRUSS_NUM0 DA8XX_PRUCORE_0 +#define PRUSS_NUM1 DA8XX_PRUCORE_1Those are unused.
SG - These are getting used by the CAN & UART drivers.
Quoted 8 lines
include/linux/mfd/pruss/da8xx_prucore.h
Quoted 6 lines
include/linux/mfd/pruss/da8xx_prucore.h new file +0
-0Please rename your mfd include directory to
include/linux/mfd/da8xx/, so that one can match it with thedrivers/mfd/da8xxdriver code.
SG - Will do.
Quoted 18 lines
Quoted 7 lines
include/linux/mfd/pruss/da8xx_prucore.h new file +5
-0+typedef struct { + u32 CONTROL; + u32 STATUS; + u32 WAKEUP; + u32 CYCLECNT;include/linux/mfd/pruss/da8xx_prucore.h line 72
Quoted 10 lines
include/linux/mfd/pruss/da8xx_prucore.h new file +10
-0+u32 STALLCNT ; +u8 RSVD0 [12 ]; +u32 CONTABBLKIDX0 ; +u32 CONTABBLKIDX1 ; +u32 CONTABPROPTR0 ; +u32 CONTABPROPTR1 ; +u8 RSVD1 [976 ]; +u32 INTGPR [32 ]; +u32 INTCTER [32 ]; +} *da8xx_prusscore_regs;Again, we don't need that structure.
SG - As mentioned above.
Quoted 8 lines
Cheers,
Samuel.Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
Thank you for your comments.
No problem.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/mfd/Kconfig +0
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more.
Quoted 7 lines
Quoted 4 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 3 lines
drivers/mfd/Kconfig +3
-0+config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.
Sure, but if there are no actual code dependencies, I'd like to get rid of those depends.
Quoted 19 lines
Quoted 19 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 96
Quoted 10 lines
drivers/mfd/Kconfig +10
-0+u32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + da8xx_prusscore_regs h_pruss; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32) pruss->ioaddr + 0x7000);So it seems you're doing this in several places, and I have a few comments:
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.
Quoted 5 lines
Quoted 1 line
Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing.
First of all, from what I read in your patch you're only using the CONTROL offset.
Quoted 3 lines
If we use #defines to plot
all the registers, then first, there are too many array type registers which will need to be duplicated.
What I'm expecting is a small set of defines for the register offsets. You have 13 fields in your da8xx_prusscore_regs, you only need to define 13 register offsets.
So, if you have a:
static u32 reg_offset(struct device *dev, u8 pru_num)
{
struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
switch (pru_num) {
case DA8XX_PRUCORE_0:
return (u32) pru->ioaddr + 0x7000;
case DA8XX_PRUCORE_1:
return (u32) pru->ioaddr + 0x7800;
default:
return 0;
}then routines like pruss_enable (which should return an int, btw) would look like:
int pruss_enable(struct device *dev, u8 pruss_num)
{
u32 offset = reg_offset(dev, pruss_num);
if (offset == 0)
return -EINVAL;
__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
offset + PRU_CORE_CONTROL);
return 0;
}Quoted 8 lines
Quoted 2 lines
Also, all your exported routines severely lack any sort of locking. An IO mutex or spinlock is mandatory here.
SG - As per our current implementation, we do not have two devices running simultaneously on the PRU,
so we do not have any way to test it. We have kept this as an
enhancement if request comes in for
multiple devices.
It's not about having multiple devices at the same time, it's about having multiple callers writing and reading to the same registers. Since you're exporting all your I/O routines you have no way to prevent 2 drivers from writing to the same register at the "same" time. You need locking here, regardless of the number of devices that you can have on a system.
Quoted 28 lines
Quoted 19 lines
Quoted 19 lines
drivers/mfd/Kconfig +19
-0+static int pruss_mfd_add_devices(struct platform_device *pdev) +{ + struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct mfd_cell cell; + u32 err, count; + + for (count = 0; (dev_data + count)->dev_name != NULL; count++) { + memset(&cell, 0, sizeof(struct mfd_cell)); + cell.id = count; + cell.name = (dev_data + count)->dev_name; + cell.platform_data = (dev_data + count)->pdata; + cell.data_size = (dev_data + count)->pdata_size; + + err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0); + if (err) { + dev_err(dev, "cannot add mfd cells\n"); + return err; + }Quoted 8 lines
Quoted 3 lines
+ }
+ return err;
+}So, what are the potential subdevices for this driver ? If it's a really dynamic setup, I'm fine with passing those as platform data but then do it so
that you pass a NULL terminatedda8xx_pruss_devicesarray. That will avoid most of the ugly casts you're doing here.
Quoted 7 lines
SG -- I did not follow your recommendations here, could you please elaborate.
I am already checking thedev_namefor a NULL. This device is basically a microcontroller within DA850,
so basically any device or protocol can be
emulated on it. Currently, we have emulated 8 UARTS using
the two PRUs and also a CAN device.
Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with you passing all your devices through platform_data. But I'd prefer this routine to look like:
[...]
for (count = 0; dev_data[count] != NULL; count++) {
memset(&cell, 0, sizeof(struct mfd_cell));
cell.id = count;
cell.name = dev_data[count]->dev_name;
cell.platform_data = dev_data[count]->pdata;
cell.data_size = dev_data[count]->pdata_size;Looks nicer to me.
Cheers,
Samuel.
Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 78 lines · Samuel Ortiz
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
Thank you for your comments.
No problem.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/mfd/Kconfig +0
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more.Quoted 7 lines
Quoted 4 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 3 lines
drivers/mfd/Kconfig +3
-0+config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.Sure, but if there are no actual code dependencies, I'd like to get rid of those depends.
Quoted 19 lines
Quoted 19 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 96
Quoted 10 lines
drivers/mfd/Kconfig +10
-0+u32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + da8xx_prusscore_regs h_pruss; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32) pruss->ioaddr + 0x7000);So it seems you're doing this in several places, and I have a few comments:
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.Quoted 5 lines
Quoted 1 line
Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing.First of all, from what I read in your patch you're only using the CONTROL offset.
Quoted 3 lines
If we use #defines to plot
all the registers, then first, there are too many array type registers which will need to be duplicated.What I'm expecting is a small set of defines for the register offsets. You have 13 fields in your
da8xx_prusscore_regs, you only need to define 13 register offsets.So, if you have a:
static u32
reg_offset(struct device *dev, u8 pru_num){ struct da8xx_pruss *pru = dev_get_drvdata(dev->parent); switch (pru_num) { case DA8XX_PRUCORE_0: return (u32) pru->ioaddr + 0x7000; case DA8XX_PRUCORE_1: return (u32) pru->ioaddr + 0x7800; default: return 0; }then routines like
pruss_enable(which should return an int, btw) would look like:int
pruss_enable(struct device *dev, u8 pruss_num)
Quoted 11 lines
{
u32 offset = reg_offset(dev, pruss_num);
if (offset == 0)
return -EINVAL;
__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
offset + PRU_CORE_CONTROL);
return 0;
}All registers are memory mapped and could nicely be described by structures (and sub-structures). Therefore we asked to considerer structs, at least for the Pruss SocketCAN drivers. That would result in much much clearer and better readable code. The code above would shrink to:
__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, &prucore[pruss_num].control);
And proper type checking would be ensured as well.
Wolfgang.
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 95 lines · Wolfgang Grandegger
Quoted 78 lines · Samuel Ortiz
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
Thank you for your comments.
No problem.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/mfd/Kconfig +0
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more.Quoted 7 lines
Quoted 4 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 3 lines
drivers/mfd/Kconfig +3
-0+config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.Sure, but if there are no actual code dependencies, I'd like to get rid of those depends.
Quoted 19 lines
Quoted 19 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 96
Quoted 10 lines
drivers/mfd/Kconfig +10
-0+u32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + da8xx_prusscore_regs h_pruss; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32) pruss->ioaddr + 0x7000);So it seems you're doing this in several places, and I have a few comments:
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.Quoted 5 lines
Quoted 1 line
Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing.First of all, from what I read in your patch you're only using the CONTROL offset.
Quoted 3 lines
If we use #defines to plot
all the registers, then first, there are too many array type registers which will need to be duplicated.What I'm expecting is a small set of defines for the register offsets. You have 13 fields in your
da8xx_prusscore_regs, you only need to define 13 register offsets.So, if you have a:
static u32
reg_offset(struct device *dev, u8 pru_num){ struct da8xx_pruss *pru = dev_get_drvdata(dev->parent); switch (pru_num) { case DA8XX_PRUCORE_0: return (u32) pru->ioaddr + 0x7000; case DA8XX_PRUCORE_1: return (u32) pru->ioaddr + 0x7800; default: return 0; }then routines like
pruss_enable(which should return an int, btw) would look like:int
pruss_enable(struct device *dev, u8 pruss_num)Quoted 11 lines
{ u32 offset = reg_offset(dev, pruss_num); if (offset == 0) return -EINVAL; __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, offset + PRU_CORE_CONTROL); return 0; }All registers are memory mapped and could nicely be described by structures (and sub-structures). Therefore we asked to considerer structs, at least for the Pruss SocketCAN drivers.
Quoted 5 lines
That would result in
much much clearer and better readable code. The code above would shrink to:__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, &prucore[pruss_num].control);
This driver seems to exclusively use the control offset, which is why I don't see an absolute need for doing this mapping.
But if both maps are contiguous then doing the mapping would prevent us from calling reg_offset() and would bring some advantage. I'd then be fine with it. For now, da8xx_prusscore_regs seems to be larger than the 0x800 interval between the 2 maps, so I have no idea if both maps are indeed contiguous.
Cheers,
Samuel.
Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
I am not sure if I understood you correctly, but the current sizeof the structure da8xx_prusscore_regs is 0x500.
Here is a link to the PRUSS memory map:
http://processors.wiki.ti.com/index.php/PRUSS_Memory_Map
The offset 0x00007000 is the PRU0 reg offset and 0x00007800 is the PRU1 reg offset.
We cannot have a register file larger than this, but lot of space is left out, possibly for future development.
--------------------------------------------------
From: "Samuel Ortiz" <[email protected]>
Sent: Tuesday, February 22, 2011 5:03 PM
To: "Wolfgang Grandegger" <[email protected]>
Cc: "Subhasish Ghosh" <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 115 lines · Wolfgang Grandegger
Quoted 96 lines · Samuel Ortiz
Quoted 82 lines
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
Thank you for your comments.
No problem.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/mfd/Kconfig +0
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more.Quoted 7 lines
Quoted 4 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 3 lines
drivers/mfd/Kconfig +3
-0+config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.Sure, but if there are no actual code dependencies, I'd like to get rid of those depends.
Quoted 20 lines
Quoted 20 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 96
Quoted 10 lines
drivers/mfd/Kconfig +10
-0+u32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + da8xx_prusscore_regs h_pruss; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32) pruss->ioaddr + 0x7000);So it seems you're doing this in several places, and I have a few comments:
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.Quoted 5 lines
Quoted 1 line
Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing.First of all, from what I read in your patch you're only using the CONTROL offset.
Quoted 3 lines
If we use #defines to plot
all the registers, then first, there are too many array type registers which will need to be duplicated.What I'm expecting is a small set of defines for the register offsets. You have 13 fields in your
da8xx_prusscore_regs, you only need to define 13 register offsets.So, if you have a:
static u32
reg_offset(struct device *dev, u8 pru_num){
structda8xx_pruss*pru =dev_get_drvdata(dev->parent);switch (
pru_num) {
caseDA8XX_PRUCORE_0:
return (u32)pru->ioaddr+0x7000;
caseDA8XX_PRUCORE_1:
return (u32)pru->ioaddr+0x7800;
default:
return 0;
}then routines like
pruss_enable(which should return an int, btw) would look like:int
pruss_enable(struct device *dev, u8 pruss_num){
u32 offset =reg_offset(dev, pruss_num);Quoted 8 lines
if (offset == 0)
return-EINVAL;__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
offset +PRU_CORE_CONTROL);return 0;
}All registers are memory mapped and could nicely be described by structures (and sub-structures). Therefore we asked to considerer structs, at least for the Pruss SocketCAN drivers.
Quoted 5 lines
That would result in
much much clearer and better readable code. The code above would shrink to:__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
&prucore[pruss_num].control);This driver seems to exclusively use the control offset, which is why I don't see an absolute need for doing this mapping.
But if both maps are contiguous then doing the mapping would prevent us from callingreg_offset()and would bring some advantage. I'd then be fine with it. For now,da8xx_prusscore_regsseems to be larger than the0x800interval between the 2 maps, so I have no idea if both maps are indeed contiguous.Cheers,
Samuel.Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 10 lines · Subhasish Ghosh
I am not sure if I understood you correctly, but the current sizeof the structure
da8xx_prusscore_regsis0x500.Here is a link to the PRUSS memory map:
http://processors.wiki.ti.com/index.php/PRUSS_Memory_MapThe offset
0x00007000is the PRU0 reg offset and0x00007800is the PRU1 reg offset.
We cannot have a register file larger than this, but lot of space is left out, possibly for future development.
What do you mean with "larger than this"? You ioremap the whole space and unsued space could be filled with padding bytes:
struct pruss_regs {
u8 ram0[0x0200];
u8 res0[0x1e00];
u8 ram1[0x0200];
u8 res1[0x1e00];
struct pruss_intc_regs intc;
struct pruss_core_regs core[2];
};Then:
pruss_dev->regs = ioremap(pruss_dev->res->start,
resource_size(pruss_dev->res));
__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
&pruss_dev->regs.core[pruss_num].control);That's simple, transparent and save without magic offset handling.
Wolfgang.
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
In reply to Samuel Ortiz--------------------------------------------------
From: "Samuel Ortiz" <[email protected]>
Sent: Tuesday, February 22, 2011 4:01 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.
Quoted 19 lines
Hi Subhasish,
Quoted 1 line · Subhasish Ghosh
Thank you for your comments.
No problem.
Quoted 13 lines
Quoted 12 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 86
Quoted 11 lines
drivers/mfd/Kconfig +3
-0@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850Why are we depending on those ?
Quoted 4 lines
Quoted 2 lines
SG -- The PRUSS core in only available within DA850 and DA830,
DA830 support is not yet implemented.Sure, but if there are no actual code dependencies, I'd like to get rid of those depends.
SG -- The PRU Clock and Power is the dependency here.
This is available in arch/arm/mach-davinci/da850.c The source is specific to the SOC clock tree.
Quoted 75 lines
Quoted 20 lines
Quoted 20 lines
drivers/mfd/Kconfig config MFD_DM355EVM_MSP · line 96
Quoted 11 lines
drivers/mfd/Kconfig +10
-0+u32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + da8xx_prusscore_regs h_pruss; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* Disable PRU0 */ + h_pruss = (da8xx_prusscore_regs) + ((u32) pruss->ioaddr + 0x7000);So it seems you're doing this in several places, and I have a few comments:
- You don't need the
da8xx_prusscore_regsat all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.Quoted 5 lines
Quoted 1 line
Then routines like this one will look a lot more readable.
SG -- There are a huge number of PRUSS registers. A lot of them are reserved and are expected to change as development on the
controller is still ongoing.First of all, from what I read in your patch you're only using the CONTROL offset.
Quoted 3 lines
If we use #defines to plot
all the registers, then first, there are too many array type registers which will need to be duplicated.What I'm expecting is a small set of defines for the register offsets. You have 13 fields in your
da8xx_prusscore_regs, you only need to define 13 register offsets.So, if you have a:
static u32
reg_offset(struct device *dev, u8 pru_num){
structda8xx_pruss*pru =dev_get_drvdata(dev->parent);switch (
pru_num) {
caseDA8XX_PRUCORE_0:
return (u32)pru->ioaddr+0x7000;
caseDA8XX_PRUCORE_1:
return (u32)pru->ioaddr+0x7800;
default:
return 0;
}then routines like
pruss_enable(which should return an int, btw) would look like:int
pruss_enable(struct device *dev, u8 pruss_num){
u32 offset =reg_offset(dev, pruss_num);if (offset == 0)
return-EINVAL;__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
offset +PRU_CORE_CONTROL);return 0;
}Quoted 8 lines
Quoted 2 lines
Also, all your exported routines severely lack any sort of locking. An IO mutex or spinlock is mandatory here.
SG - As per our current implementation, we do not have two devices running simultaneously on the PRU,
so we do not have any way to test it. We have kept this as an
enhancement if request comes in for
multiple devices.
Quoted 6 lines
It's not about having multiple devices at the same time, it's about having multiple callers writing and reading to the same registers. Since you're exporting all your I/O routines you have no way to prevent 2 drivers from writing to the same register at the "same" time. You need locking here, regardless of the number of devices that you can have on a system.
SG - Ok, will do
Quoted 48 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines
drivers/mfd/Kconfig +19
-0+static int pruss_mfd_add_devices(struct platform_device *pdev) +{ + struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct mfd_cell cell; + u32 err, count; + + for (count = 0; (dev_data + count)->dev_name != NULL; count++) { + memset(&cell, 0, sizeof(struct mfd_cell)); + cell.id = count; + cell.name = (dev_data + count)->dev_name; + cell.platform_data = (dev_data + count)->pdata; + cell.data_size = (dev_data + count)->pdata_size; + + err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0); + if (err) { + dev_err(dev, "cannot add mfd cells\n"); + return err; + }Quoted 8 lines
Quoted 3 lines
+ }
+ return err;
+}So, what are the potential subdevices for this driver ? If it's a really dynamic setup, I'm fine with passing those as platform data but then do it so
that you pass a NULL terminatedda8xx_pruss_devicesarray. That will avoid most of the ugly casts you're doing here.Quoted 7 lines
SG -- I did not follow your recommendations here, could you please elaborate.
I am already checking thedev_namefor a NULL. This device is basically a microcontroller within DA850,
so basically any device or protocol can be
emulated on it. Currently, we have emulated 8 UARTS using
the two PRUs and also a CAN device.Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with you passing all your devices through
platform_data. But I'd prefer this routine to look like:[...]
for (count = 0; dev_data[count] != NULL; count++) {memset(&cell, 0, sizeof(struct mfd_cell)); cell.id = count;
cell.name = dev_data[count]->dev_name; cell.platform_data = dev_data[count]->pdata; cell.data_size = dev_data[count]->pdata_size;
Quoted 1 line
Looks nicer to me.
SG - I have a problem here, dev_data was initialized as a structure array.
static struct da8xx_pruss_devices pruss_devices[] = {
{
.dev_name = "da8xx_pruss_can",
.pdata = &can_data,
.pdata_size = sizeof(can_data),
.setup = da850_evm_setup_pruss_can,
.num_resources = 0,
.resources = NULL,
},
{
.dev_name = "da8xx_pruss_uart",
.pdata = &suart_data,
.pdata_size = sizeof(suart_data),
.setup = da850_evm_setup_pruss_suart,
.num_resources = ARRAY_SIZE(da850_evm_suart_resource),
.resources = da850_evm_suart_resource,
},
{
.dev_name = NULL,
},
};
How can I initialize the last array element to NULL! I think, I must have some type of delimiter.
Quoted 7 lines
Cheers,
Samuel.Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/
Re: [PATCH v2 01/13] mfd: pruss mfd driver.
In reply to Samuel OrtizQuoted 14 lines · Samuel Ortiz
So, if you have a:
static u32
reg_offset(struct device *dev, u8 pru_num){ struct da8xx_pruss *pru = dev_get_drvdata(dev->parent); switch (pru_num) { case DA8XX_PRUCORE_0: return (u32) pru->ioaddr + 0x7000; case DA8XX_PRUCORE_1: return (u32) pru->ioaddr + 0x7800; default: return 0; }
No. Please don't encourage people to have 'u32' as valid cookies for readl,writel et.al. Always make the mmio cookies __iomem pointer like.
PATCH v2 2/13 da850: pruss platform specific additions.
In reply to Subhasish GhoshThis patch adds the platform device and assignes the platform resources for the PRUSS mfd driver.
--- arch/arm/mach-davinci/da850.c | 7 +++ arch/arm/mach-davinci/devices-da8xx.c | 65 ++++++++++++++++++++++++++++ arch/arm/mach-davinci/include/mach/da8xx.h | 2 + 3 files changed, 74 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/da850.c +7 -0
@@ -238,6 +238,12 @@ static struct clk tptc2_clk = { .flags = ALWAYS_ENABLED, }; +static struct clk pruss_clk = { + .name ="pruss" , + .parent = &pll0_sysclk2, + .lpsc =DA8XX_LPSC0_PRUSS , +}; +static struct clk uart0_clk = { .name ="uart0" , .parent = &pll0_sysclk2,
@@ -387,6 +393,7 @@ static struct clk_lookup da850_clks[] = {CLK (NULL ,"tpcc1" , &tpcc1_clk),CLK (NULL ,"tptc2" , &tptc2_clk),CLK (NULL ,"uart0" , &uart0_clk), +CLK (NULL ,"pruss" , &pruss_clk),CLK (NULL ,"uart1" , &uart1_clk),CLK (NULL ,"uart2" , &uart2_clk), CLK(NULL, "aintc", &aintc_clk),
arch/arm/mach-davinci/devices-da8xx.c +65 -0
77 lines not on this page · raw message
arch/arm/mach-davinci/include/mach/da8xx.h +2 -0
@@ -15,6 +15,7 @@#include <linux/platform_device.h> #include <linux/davinci_emac.h> +#include <linux/mfd/pruss/da8xx_pru.h> #include <mach/serial.h> #include <mach/edma.h>
@@ -82,6 +83,7 @@ int da8xx_register_watchdog(void);int da8xx_register_usb20 (unsigned mA,unsigned potpgt);int da8xx_register_usb11 (struct da8xx_ohci_root_hub *pdata);int da8xx_register_emac (void ); +int da8xx_register_pruss (struct da8xx_pruss_devices *);int da8xx_register_lcdc (struct da8xx_lcdc_platform_data *pdata);int da8xx_register_mmcsd0 (struct davinci_mmc_config *config);int da850_register_mmcsd1 (struct davinci_mmc_config *config);
Signature · 1 line
1.7.2.3
Re: [PATCH v2 02/13] da850: pruss platform specific additions.
Hello.
Quoted 2 lines · Subhasish Ghosh
This patch adds the platform device and assignes the platform resources for the PRUSS mfd driver.
You also add the PRUSS clock (and I would have done that as a separate patch).
Quoted 1 line
Signed-off-by Subhasish Ghosh <[email protected]>
You should have noted the patch dependency here -- this patch depends on the
one nenaming DA8XX_LPSC0_DMAX.
WBR, Sergei
Re: [PATCH v2 02/13] da850: pruss platform specific additions.
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:11 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Kevin Hilman (supporter:TI DAVINCI MACHIN...,commit_signer:16/18=89%)" <[email protected]>; "Russell King (maintainer:ARM PORT)" <[email protected]>; "Michael Williamson (commit_signer:5/18=28%)" <[email protected]>; "Cyril Chemparathy (commit_signer:3/18=17%)" <[email protected]>; "Sergei Shtylyov (commit_signer:3/18=17%)" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 02/13] da850: pruss platform specific additions.
Quoted 7 lines
Hello.
Quoted 2 lines · Subhasish Ghosh
This patch adds the platform device and assignes the platform resources for the PRUSS mfd driver.
Quoted 7 lines
You also add the PRUSS clock (and I would have done that as a separate
patch).Quoted 1 line
Signed-off-by Subhasish Ghosh <[email protected]>You should have noted the patch dependency here -- this patch depends
on the one nenamingDA8XX_LPSC0_DMAX.
SG - Will do
Quoted 2 lines
WBR, Sergei
RE: [PATCH v2 02/13] da850: pruss platform specific additions.
In reply to Subhasish GhoshHi,
Quoted 10 lines
-----Original Message-----
From: davinci-linux-open-source-bounces at linux.davincidsp.com [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf Of Subhasish Ghosh
Sent: Friday, February 11, 2011 8:21 PM
To: davinci-linux-open-source at linux.davincidsp.com
Cc: sachi at mistralsolutions.com; Russell King; Kevin Hilman; Subhasish Ghosh; open list; Watkins, Melissa; linux-arm-kernel at lists.infradead.org
Subject: [PATCH v2 02/13] da850: pruss platform specific additions.
Quoted 6 lines
This patch adds the platform device and assignes the platform resources for the PRUSS mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>---
+structplatform_deviceda8xx_pruss_dev= {
Can you please rename this to da8xx_pruss_mfddev?
Review
Quoted 1 line
(quoted diff) +1
-0+ .name = "da8xx_pruss",
Can you please rename name string as pruss_mfd? This will help to base my UIO patches on top of yours.
arch/arm/mach-davinci/devices-da8xx.c void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata) · line 561
Quoted 6 lines
arch/arm/mach-davinci/devices-da8xx.c +6
-0+ .id = -1, + .num_resources = ARRAY_SIZE(da8xx_pruss_resources), + .resource = da8xx_pruss_resources, +}; + +int __init da8xx_register_pruss (struct da8xx_pruss_devices *pruss_device)
Please rename this to da8xx_register_pruss_mfd
Thanks,
Pratheesh
Re: [PATCH v2 02/13] da850: pruss platform specific additions.
Hello,
Can we not have the PRU UIO also as a part of the MFD framework.
I know that the UIO is not really a device, but I feel its incorrect to register the same device twice. Instead we can have a single entry as the MFD framework and the UIO, as a child device, based upon the MFD driver APIs.
All that we need to do is add an entry into the da8xx_pruss_devices structure and the MFD driver will do the rest to get the UIO probe called.
--------------------------------------------------
From: "TK, Pratheesh Gangadhar" <[email protected]>
Sent: Monday, February 28, 2011 6:34 PM
To: "Subhasish Ghosh" <[email protected]>; <[email protected]>
Cc: <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; "open list" <[email protected]>; "Watkins, Melissa" <[email protected]>; <[email protected]>
Subject: RE: [PATCH v2 02/13] da850: pruss platform specific additions.
Quoted 33 lines
Hi,
Quoted 10 lines
-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Subhasish Ghosh
Sent: Friday, February 11, 2011 8:21 PM
To: [email protected]
Cc: [email protected]; Russell King; Kevin Hilman; Subhasish Ghosh; open list; Watkins, Melissa; [email protected]
Subject: [PATCH v2 02/13] da850: pruss platform specific additions.Quoted 6 lines
This patch adds the platform device and assignes the platform resources for the PRUSS mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>---
+structplatform_deviceda8xx_pruss_dev= {Can you please rename this to
da8xx_pruss_mfddev?Quoted 1 line
+ .name = "
da8xx_pruss",Can you please rename name string as
pruss_mfd? This will help to base my UIO patches on top of yours.Quoted 7 lines
+ .id = -1,
+ .num_resources =ARRAY_SIZE(da8xx_pruss_resources),
+ .resource =da8xx_pruss_resources,arch/arm/mach-davinci/da850.c +3
-0+}; + +int __init da8xx_register_pruss(struct da8xx_pruss_devices
*pruss_device)Please rename this to
da8xx_register_pruss_mfdThanks,
Pratheesh
RE: [PATCH v2 02/13] da850: pruss platform specific additions.
Hi,
Quoted 11 lines
-----Original Message-----
From: Subhasish Ghosh [mailto:subhasish at mistralsolutions.com]
Sent: Tuesday, March 01, 2011 12:29 PM
Hello,Can we not have the PRU UIO also as a part of the MFD framework. I know that the UIO is not really a device, but I feel its incorrect to register the same device twice.
Instead we can have a single entry as the MFD framework and the UIO, as a child device, based upon the MFD driver APIs.
Quoted 4 lines
All that we need to do is add an entry into the
da8xx_pruss_devicesstructure
and the MFD driver will do the rest to get the UIO probe called.
Well I see the need for MFD for in-kernel PRUSS based drivers like UART/CAN,
but UIO use cases are typically mutually exclusive to this. UIO driver
exports whole PRUSS I/O region and Interrupts to user space application and
all the tasks including PRUSS INTC setup, loading firmware and
enable/disable PRUs are handled by PRUSS user driver.
I feel it will be a nightmare to make them co-exist unless say we have
2 instances of PRUSS in a SOC. Think about kernel driver setting up PRUSS, PINTC and loading firmware and user land overriding and vice versa. Things are much simpler if we make the usage model mutually exclusive. Also I don't see any overlap in functionality and reuse UIO can gain from
MFD driver.
Since we can't register device twice - I would prefer KConfig based check
for the same.
Also can you point me where you add UART and CAN driver as children to PRUSS MFD driver - I can't seem to find this in patches.
Thanks,
Pratheesh
PATCH v2 3/13 da850: pruss board specific additions.
In reply to Subhasish GhoshThis patch adds board specific initializations and setup routines.
--- arch/arm/mach-davinci/board-da850-evm.c | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/board-da850-evm.c +25 -0
@@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)static __init int da850_evm_init_cpufreq (void ) {return 0 ; }#endif +static struct da8xx_pruss_devices pruss_devices[] = { + {.dev_name =NULL ,}, +}; + +static int __init da8xx_evm_setup_pruss (void ) +{ +u32 ret =0 ; +u32 count; + +for (count =0 ; count <ARRAY_SIZE (pruss_devices); count++) { +if (pruss_devices[count].setup !=NULL ) { + ret = pruss_devices[count].setup (); +if (ret) +return ret; + } + } + +return da8xx_register_pruss (pruss_devices); +} +static __init void da850_evm_init (void ) {int ret;
@@ -1127,6 +1147,11 @@ static __init void da850_evm_init(void)da8xx_register_mcasp (0 , &da850_evm_snd_data); + ret =da8xx_evm_setup_pruss (); +if (ret) +pr_warning ("%s: pruss initialization failed: %d\n" , + __func__, ret); + ret =davinci_cfg_reg_list (da850_lcdcntl_pins);if (ret) pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
Signature · 1 line
1.7.2.3
Re: [PATCH v2 03/13] da850: pruss board specific additions.
Quoted 3 lines · Subhasish Ghosh
This patch adds board specific initializations and setup routines.
Signed-off-by Subhasish Ghosh <[email protected]>
[...]
arch/arm/mach-davinci/board-da850-evm.c static __init int da850_evm_init_cpufreq(void) · line 1057
Quoted 10 lines
arch/arm/mach-davinci/board-da850-evm.c +2
-0@@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)static __init int da850_evm_init_cpufreq (void ) {return 0 ; }#endif +static struct da8xx_pruss_devices pruss_devices[] = { + {.dev_name =NULL ,},
No need to explicitly initialize to NULL.
WBR, Sergei
Re: [PATCH v2 03/13] da850: pruss board specific additions.
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:13 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 03/13] da850: pruss board specific additions.
Quoted 7 lines
Quoted 3 lines · Subhasish Ghosh
This patch adds board specific initializations and setup routines.
Signed-off-by Subhasish Ghosh <[email protected]>[...]
Quoted 12 lines
arch/arm/mach-davinci/board-da850-evm.c static __init int da850_evm_init_cpufreq(void) · line 1056
Quoted 9 lines
arch/arm/mach-davinci/board-da850-evm.c +1
-0@@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)static __init int da850_evm_init_cpufreq (void ) {return 0 ; }#endif +static struct da8xx_pruss_devices pruss_devices[] = { + {.dev_name =NULL ,},No need to explicitly initialize to NULL.
SG - Ok, Will remove
Quoted 2 lines
WBR, Sergei
PATCH v2 4/13 mfd: pruss CAN private data.
In reply to Subhasish GhoshThis patch adds the PRUSS CAN data.
--- include/linux/mfd/pruss/da8xx_pru.h | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
include/linux/mfd/pruss/da8xx_pru.h +4 -0
@@ -89,6 +89,10 @@ struct da8xx_pruss_devices {int (*setup)(void ); }; +struct da8xx_pruss_can_data { +u32 version; +}; +u32 pruss_get_clk_freq (struct device *dev);u32 pruss_enable (struct device *dev,u8 pruss_num);
Signature · 1 line
1.7.2.3
PATCH v2 5/13 da850: pruss CAN platform specific additions.
In reply to Subhasish GhoshThis patch adds the necessary pins for the pruss CAN.
--- arch/arm/mach-davinci/da850.c | 4 ++++ arch/arm/mach-davinci/include/mach/mux.h | 4 ++++ 2 files changed, 8 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/da850.c +4 -0
@@ -565,6 +565,10 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, EMA_CLK, 6, 0, 15, 1, false) MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, false)MUX_CFG (DA850 ,NEMA_CS_2 ,7 ,0 ,15 ,1 , false) + /* PRU functions for soft CAN */ + MUX_CFG(DA850, PRUSS_PRU0_R31_0, 7, 28, 15, 0, false) + MUX_CFG(DA850, PRUSS_PRU1_R30_15, 12, 0, 15, 4, false) +MUX_CFG (DA850 ,PRUSS_PRU1_R31_18 ,11 ,20 ,15 ,0 , false) /* GPIO function */ MUX_CFG(DA850, GPIO2_4, 6, 12, 15, 8, false)MUX_CFG (DA850 ,GPIO2_6 ,6 ,4 ,15 ,8 , false)
arch/arm/mach-davinci/include/mach/mux.h +4 -0
@@ -906,6 +906,10 @@ enum davinci_da850_index {DA850_EMA_CLK ,DA850_EMA_WAIT_1 ,DA850_NEMA_CS_2 , +/* PRU I/O */ +DA850_PRUSS_PRU0_R31_0 , +DA850_PRUSS_PRU1_R30_15 , +DA850_PRUSS_PRU1_R31_18 ,/* GPIO function */ DA850_GPIO2_4,
Signature · 1 line
1.7.2.3
PATCH v2 6/13 da850: pruss CAN board specific additions.
In reply to Subhasish GhoshThis patch adds the pruss CAN pin mux and registers the device with the pruss mfd driver.
--- arch/arm/mach-davinci/board-da850-evm.c | 37 ++++++++++++++++++++++++++++++- 1 files changed, 36 insertions(+), 1 deletions(-)
arch/arm/mach-davinci/board-da850-evm.c +36 -1
@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)static __init int da850_evm_init_cpufreq (void ) {return 0 ; }#endif +const short da850_evm_pruss_can_pins[] = { +DA850_PRUSS_PRU0_R31_0 ,DA850_PRUSS_PRU1_R30_15 , +DA850_PRUSS_PRU1_R31_18 , +-1 +}; + +static int __init da850_evm_setup_pruss_can (void ) +{ +int ret, val =0 ; +void __iomem *cfg_chip3_reg; + + ret =davinci_cfg_reg_list (da850_evm_pruss_can_pins); +if (ret) +pr_warning ("%s: da850_evm_pruss_can_pins mux setup " +"failed:%d\n" , __func__, ret); + cfg_chip3_reg =DA8XX_SYSCFG0_VIRT (DA8XX_CFGCHIP3_REG ); + val =__raw_readl (cfg_chip3_reg); + val |=BIT (3 ); +__raw_writel (val, cfg_chip3_reg); + +return ret; +} + +static struct da8xx_pruss_can_data can_data = { + .version =1 , +}; +static struct da8xx_pruss_devices pruss_devices[] = { - {.dev_name =NULL ,}, + { + .dev_name ="da8xx_pruss_can" , + .pdata = &can_data, + .pdata_size =sizeof (can_data), + .setup = da850_evm_setup_pruss_can, + }, + { + .dev_name =NULL , + }, };static int __init da8xx_evm_setup_pruss (void )
Signature · 1 line
1.7.2.3
Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
Quoted 4 lines · Subhasish Ghosh
This patch adds the pruss CAN pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>
[...]
Quoted 5 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
[...]
arch/arm/mach-davinci/board-da850-evm.c static __init int da850_evm_init_cpufreq(void) · line 1092
Quoted 11 lines
static struct
da8xx_pruss_devicespruss_devices[] = {arch/arm/mach-davinci/board-da850-evm.c +9
-1- {.dev_name = NULL,}, + { + .dev_name = "da8xx_pruss_can", + .pdata = &can_data, + .pdata_size = sizeof(can_data), + .setup = da850_evm_setup_pruss_can, + }, + { + .dev_name = NULL, + },
No need to explicitly initialize to NULL.
WBR, Sergei
Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
Quoted 27 lines
Quoted 4 lines · Subhasish Ghosh
This patch adds the pruss CAN pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>[...]
Quoted 6 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)[...]
Quoted 11 lines
static struct
da8xx_pruss_devicespruss_devices[] = {
- {.dev_name = NULL,},
+ {
+ .dev_name = "da8xx_pruss_can",
+ .pdata =&can_data,
+ .pdata_size =sizeof(can_data),
+ .setup =da850_evm_setup_pruss_can,
+ },
+ {
+ .dev_name = NULL,
+ },
Quoted 1 line
No need to explicitly initialize to NULL.
SG -- ok, Will remove
Quoted 2 lines
WBR, Sergei
Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
In reply to Sergei Shtylyov--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
Quoted 27 lines
Quoted 4 lines · Subhasish Ghosh
This patch adds the pruss CAN pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>[...]
Quoted 6 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)[...]
Quoted 11 lines
static struct
da8xx_pruss_devicespruss_devices[] = {
- {.dev_name = NULL,},
+ {
+ .dev_name = "da8xx_pruss_can",
+ .pdata =&can_data,
+ .pdata_size =sizeof(can_data),
+ .setup =da850_evm_setup_pruss_can,
+ },
+ {
+ .dev_name = NULL,
+ },
Quoted 1 line
No need to explicitly initialize to NULL.
SG -- ok, Will remove
Quoted 2 lines
WBR, Sergei
PATCH v2 7/13 da850: pruss CAN platform specific changes for gpios.
In reply to Subhasish GhoshThis patch adds the GPIOs for the pruss CAN device.
--- arch/arm/mach-davinci/da850.c | 1 + arch/arm/mach-davinci/include/mach/mux.h | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/da850.c +1 -0
@@ -570,6 +570,7 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, PRUSS_PRU1_R30_15, 12, 0, 15, 4, false)MUX_CFG (DA850 ,PRUSS_PRU1_R31_18 ,11 ,20 ,15 ,0 , false) /* GPIO function */ + MUX_CFG(DA850, GPIO2_0, 6, 28, 15, 8, false) MUX_CFG(DA850, GPIO2_4, 6, 12, 15, 8, false) MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, false)MUX_CFG (DA850 ,GPIO2_8 ,5 ,28 ,15 ,8 , false)
arch/arm/mach-davinci/include/mach/mux.h +1 -0
@@ -912,6 +912,7 @@ enum davinci_da850_index {DA850_PRUSS_PRU1_R31_18 ,/* GPIO function */ +DA850_GPIO2_0 ,DA850_GPIO2_4 ,DA850_GPIO2_6 , DA850_GPIO2_8,
Signature · 1 line
1.7.2.3
Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
Hello.
Quoted 3 lines · Subhasish Ghosh
This patch adds the GPIOs for the pruss CAN device.
Signed-off-by Subhasish Ghosh <[email protected]>
I still think this patch should be merged with patch 5, and patch 8 with
patch 6...
WBR, Sergei
Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:17 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; "Thomas Koeller" <[email protected]>; <[email protected]>; "open list" <[email protected]>; "Victor Rodriguez" <[email protected]>; "Cyril Chemparathy" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
Quoted 11 lines
Hello.
Quoted 3 lines · Subhasish Ghosh
This patch adds the GPIOs for the pruss CAN device.
Signed-off-by Subhasish Ghosh <[email protected]>I still think this patch should be merged with patch 5, and patch 8
with patch 6...
SG -- Ok, Will do.
Quoted 1 line
WBR, Sergei
PATCH v2 8/13 da850: pruss CAN board specific changes for gpios.
In reply to Subhasish GhoshThis patch adds the GPIO modifications required for the pruss CAN.
--- arch/arm/mach-davinci/board-da850-evm.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-)
arch/arm/mach-davinci/board-da850-evm.c +10 -1
@@ -45,6 +45,7 @@#define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0)#define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) +#define DA850_PRUSS_CAN_TRX_PIN GPIO_TO_PIN(2, 0)#define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6)
@@ -1055,7 +1056,7 @@ static __init int da850_evm_init_cpufreq(void) { return 0; }const short da850_evm_pruss_can_pins[] = {DA850_PRUSS_PRU0_R31_0 ,DA850_PRUSS_PRU1_R30_15 , -DA850_PRUSS_PRU1_R31_18 , +DA850_PRUSS_PRU1_R31_18 ,DA850_GPIO2_0 ,-1 };
@@ -1073,6 +1074,14 @@ static int __init da850_evm_setup_pruss_can(void) val |=BIT (3 );__raw_writel (val, cfg_chip3_reg); +/* value = 0 to enable the CAN transceiver */ + ret =gpio_request_one (DA850_PRUSS_CAN_TRX_PIN , +GPIOF_OUT_INIT_LOW ,"pruss_can_en" ); +if (ret) { +pr_warning ("Cannot setup GPIO %d\n" ,DA850_PRUSS_CAN_TRX_PIN ); +gpio_free (DA850_PRUSS_CAN_TRX_PIN ); + } +return ret; }
Signature · 1 line
1.7.2.3
PATCH v2 9/13 can: pruss CAN driver.
In reply to Subhasish GhoshThis patch adds support for the CAN device emulated on PRUSS.
--- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/da8xx_pruss/Kconfig | 73 ++ drivers/net/can/da8xx_pruss/Makefile | 7 + drivers/net/can/da8xx_pruss/pruss_can.c | 758 +++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.h | 290 +++++++ 7 files changed, 2357 insertions(+), 0 deletions(-) create mode 100644 drivers/net/can/da8xx_pruss/Kconfig create mode 100644 drivers/net/can/da8xx_pruss/Makefile create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h
drivers/net/can/Kconfig +1 -0
@@ -112,6 +112,7 @@ config PCH_CAN This driver can access CAN bus. source "drivers/net/can/mscan/Kconfig" +source "drivers/net/can/da8xx_pruss/Kconfig" source "drivers/net/can/sja1000/Kconfig"
drivers/net/can/Makefile +1 -0
@@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += da8xx_pruss/ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
drivers/net/can/da8xx_pruss/Kconfig new file +73 -0
73 lines not on this page · raw message
drivers/net/can/da8xx_pruss/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# +# Makefile for CAN Lite emulation +# +can_emu-objs := pruss_can.o \ + pruss_can_api.o + +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += can_emu.o
drivers/net/can/da8xx_pruss/pruss_can.c new file +758 -0
758 lines not on this page · raw message
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +1227 -0
1,227 lines not on this page · raw message
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +290 -0
290 lines not on this page · raw message
Signature · 1 line
1.7.2.3
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 53 lines · Subhasish Ghosh
drivers/net/can/da8xx_pruss/Kconfig new file +53
-0+config DA8XX_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help---
drivers/net/can/da8xx_pruss/Kconfig line 73
Quoted 10 lines
drivers/net/can/da8xx_pruss/Kconfig new file +10
-0+ Enter the CANID for mailbox 6 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 + Default value is set to 0x123, change this as required.
Why is filling the mailboxes the job of kernel config?
Regards,
Kurt
Re: [PATCH v2 09/13] can: pruss CAN driver.
Hello,
I had a discussion regarding this with Wolfgang:
http://www.mail-archive.com/[email protected]/msg00324.html
The problem here is that we must configure the mailbox ID's and this support is not available in the socketCan sub-system.
--------------------------------------------------
From: "Kurt Van Dijck" <[email protected]>
Sent: Friday, February 11, 2011 8:36 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Wolfgang Grandegger" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 68 lines · Subhasish Ghosh
Quoted 53 lines
drivers/net/can/da8xx_pruss/Kconfig new file +53
-0+config DA8XX_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help---drivers/net/can/da8xx_pruss/Kconfig line 73
Quoted 10 lines
drivers/net/can/da8xx_pruss/Kconfig new file +10
-0+ Enter the CANID for mailbox 6 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 + Default value is set to 0x123, change this as required.Why is filling the mailboxes the job of kernel config?
Regards,
Kurt
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 8 lines · Subhasish Ghosh
Hello,
I had a discussion regarding this with Wolfgang:
http://www.mail-archive.com/[email protected]/msg00324.html
The problem here is that we must configure the mailbox ID's and this support is not available in the socketCan sub-system.
To understand you correctly. A mailbox (or message object) can *only* receive messages with the pre-programmed CAN id? Isn't there a chance to receive all or a range of CAN ids? That's a very unusual piece of hardware. Anyway, using kernel configuration parameters to define the CAN id's would be the less flexible method. The user will not have a chance to change them at run-time. Using SysFS files would already be much better.
Wolfgang.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 11 lines · Wolfgang Grandegger
Quoted 8 lines · Subhasish Ghosh
Hello,
I had a discussion regarding this with Wolfgang:
http://www.mail-archive.com/socketcan-users at lists.berlios.de/msg00324.html
The problem here is that we must configure the mailbox ID's and this support is not available in the socketCan sub-system.
Using SysFS files would already be much better.
Ack.
Kurt
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to Wolfgang GrandeggerThat is correct, we receive only pre-programmed CAN ids and "all" or "range" implementation is not there in the PRU firmware. Will check the sysfs option and update.
--------------------------------------------------
From: "Wolfgang Grandegger" <[email protected]>
Sent: Monday, February 14, 2011 12:53 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: "Kurt Van Dijck" <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 19 lines · Subhasish Ghosh
Quoted 8 lines
Hello,
I had a discussion regarding this with Wolfgang:
http://www.mail-archive.com/[email protected]/msg00324.html
The problem here is that we must configure the mailbox ID's and this support is not available in the socketCan sub-system.
To understand you correctly. A mailbox (or message object) can *only* receive messages with the pre-programmed CAN id? Isn't there a chance to receive all or a range of CAN ids? That's a very unusual piece of hardware. Anyway, using kernel configuration parameters to define the CAN id's would be the less flexible method. The user will not have a chance to change them at run-time. Using SysFS files would already be much better.
Wolfgang.
Re: [PATCH v2 09/13] can: pruss CAN driver.
Hi Subhasish,
Quoted 2 lines · Subhasish Ghosh
That is correct, we receive only pre-programmed CAN ids and "all" or "range" implementation is not there in the PRU firmware.
I'm curious about that CAN hardware and firmware. I found a nice block diagram in [PATCH 0/13]:
http://marc.info/?l=linux-arm-kernel&m=129743511311286&w=4
So, one PRU is used for TX and the second for RX. Who is providing the firmware you are using? Wouldn't it be possible to provide a firmware for RX using just one message object (mailbox) with some buffering or fifo? That would fit much better the SocketCAN approach favoring Basic CAN controllers (in contrast to Full CAN [1]). And such an implementation seems even simpler too me requiring less PRU resources. And how about RTR and Extended CAN IDs? Is that supported?
Thanks,
Wolfgang.
[1] http://www.kvaser.com/en/about-can/the-can-protocol/18.html
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to Subhasish GhoshHello,
Quoted 2 lines · Subhasish Ghosh
That is correct, we receive only pre-programmed CAN ids and "all" or "range" implementation is not there in the PRU firmware.
I'd really like to see that you add a "all" implementation to the firmware. Or even better use the standard id/mask approach.
cheers, Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
_______________________________________________
Socketcan-core mailing list [email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core
Re: [PATCH v2 09/13] can: pruss CAN driver.
Hello,
The problem with the "all" implementation is that it hogs the ARM/DSP heavily and that's the reason why we specifically avoided this in our firmware design. Hence, implementing this condition spoils the whole purpose of the PRU!!
--------------------------------------------------
From: "Marc Kleine-Budde" <[email protected]>
Sent: Monday, February 14, 2011 3:05 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: "Wolfgang Grandegger" <[email protected]>; "Kurt Van Dijck" <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
Hello,
Quoted 2 lines · Subhasish Ghosh
That is correct, we receive only pre-programmed CAN ids and "all" or "range" implementation is not there in the PRU firmware.
I'd really like to see that you add a "all" implementation to the firmware. Or even better use the standard id/mask approach.
cheers, Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 6 lines · Subhasish Ghosh
Hello,
The problem with the "all" implementation is that it hogs the ARM/DSP heavily and that's the reason why we specifically avoided this in our firmware design.
Hence, implementing this condition spoils the whole purpose of the PRU!!
What about implementing the standard id/mask approach?
if (canid & mask == id & mask)
aceept(); else discard();
To keep the hot-path as small as possible, the id & mask operation is done during setup, only one. This is probably just an additional "and" operation (the "& mask"). This opens the way to act like a normal can controller.
As long as we don't have any support for hardware filters in socketcan, it's a good choice to use sysfs to configure your filters.
Have a look at [1] and [2] for how to use sysfs files.
cheers, Marc
[1]
http://git.kernel.org/linus/3a5655a5b545e9647c3437473ee3d815fe1b9050
[2]
http://git.kernel.org/linus/fef52b0171dfd7dd9b85c9cc201bd433b42a8ded
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
_______________________________________________
Socketcan-core mailing list [email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to Subhasish GhoshQuoted 6 lines · Subhasish Ghosh
Hello,
The problem with the "all" implementation is that it hogs the ARM/DSP heavily and that's the reason why we specifically avoided this in our firmware design.
Hence, implementing this condition spoils the whole purpose of the PRU!!
Well, I doubt that a CAN controller just supporting 8 CAN identifiers will make many CAN users happy. Anyway, the CAN identifiers could/should be configured via SysFS files (as Marc suggested).
Wolfgang.
Quoted 25 lines
--------------------------------------------------
From: "Marc Kleine-Budde" <[email protected]>
Sent: Monday, February 14, 2011 3:05 PM
To: "Subhasish Ghosh" <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Cc: "Wolfgang Grandegger" <[email protected]>; "Kurt Van Dijck" <kurt.van.dijck-/[email protected]>; <davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org>; <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>; <[email protected]>; <[email protected]>; <sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list:CAN NETWORK
DRIVERS" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.Hello,
Quoted 2 lines · Subhasish Ghosh
That is correct, we receive only pre-programmed CAN ids and "all" or "range" implementation is not there in the PRU firmware.
I'd really like to see that you add a "all" implementation to the firmware. Or even better use the standard id/mask approach.
cheers, Marc
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to Subhasish GhoshHi,
I looked a bit at the TX path:
drivers/net/can/da8xx_pruss/pruss_can.c line 124
Quoted 9 lines · Subhasish Ghosh
drivers/net/can/da8xx_pruss/pruss_can.c new file +9
-0+static int omapl_pru_can_set_bittiming (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_bittiming *bt = &priv->can.bittiming; +long bit_error =0 ; + +if (priv->can.ctrlmode &CAN_CTRLMODE_3_SAMPLES ) { +dev_warn (priv->dev,"WARN: Triple" +"sampling not set due to h/w limitations" );
You should not have enabled CAN_CTRLMODE_3_SAMPLES in the first place?
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +8
-0+ } +if (pru_can_calc_timing (priv->dev, priv->can.clock.freq, + bt->bitrate) !=0 ) +return -EINVAL ; + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000 ) / bt->bitrate; +if (bit_error) {
drivers/net/can/da8xx_pruss/pruss_can.c line 142
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+ bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000000 ) / bt->bitrate; +printk (KERN_INFO "\nBitrate error %ld.%ld%%\n" , + bit_error /10000 , bit_error %1000 ); + }else +printk (KERN_INFO "\nBitrate error 0.0%%\n" ); + +return 0 ; +}
I wonder how much of this code is duplicated from drivers/net/can/dev.c ?
drivers/net/can/da8xx_pruss/pruss_can.c line 210
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+static netdev_tx_t omapl_pru_can_start_xmit (struct sk_buff *skb, +struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_frame *cf = (struct can_frame *)skb->data; +int count; +u8 *data = cf->data; +u8 dlc = cf->can_dlc; +u8 *ptr8data =NULL ; +
most drivers start with:
if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK;
Review
Quoted 1 line
(quoted diff) +1
-0+ netif_stop_queue(ndev);
why would you stop when you just resumed the queue?
Quoted 21 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +21
-0+if (cf->can_id &CAN_EFF_FLAG )/* Extended frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_EFF_MASK ) |PRU_CANMID_IDE ; +else /* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_SFF_MASK ) <<18 ; + +if (cf->can_id &CAN_RTR_FLAG )/* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |=CAN_RTR_FLAG ; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc -1 ); +for (count =0 ; count < (u8 ) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32 ) dlc; +/* +* search for the next available mbx +* if the next mbx is busy, then try the next + 1 +* do this until the head is reached. +* if still unable to tx, stop accepting any packets +* if able to tx and the head is reached, then reset next to tail, i.e mbx0
drivers/net/can/da8xx_pruss/pruss_can.c line 242
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+* if head is not reached, then just point to the next mbx +*/ +for (; priv->tx_next <= priv->tx_head; priv->tx_next++) { + priv->can_tx_hndl.ecanmailboxnumber = + (can_mailbox_number ) priv->tx_next; +if (-1 ==pru_can_write_data_to_mailbox (priv->dev, + &priv->can_tx_hndl)) { +if (priv->tx_next == priv->tx_head) { + priv->tx_next = priv->tx_tail; +if (!netif_queue_stopped (ndev))
If you get here, the queue is not stopped. This test is therefore useless.
Quoted 54 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +53
-0+netif_stop_queue (ndev);/* IF stalled */ +dev_err (priv->dev, +"%s: no tx mbx available" , __func__); +return NETDEV_TX_BUSY ; + }else +continue ; + }else { +/* set transmit request */ +pru_can_tx (priv->dev, priv->tx_next,CAN_TX_PRU_1 ); +pru_can_tx_mode_set (priv->dev, false, ecanreceive); +pru_can_tx_mode_set (priv->dev, true, ecantransmit); +pru_can_start_abort_tx (priv->dev,PRU_CAN_START ); + priv->tx_next++; +can_put_echo_skb (skb, ndev,0 ); +break ; + } + } +if (priv->tx_next > priv->tx_head) { + priv->tx_next = priv->tx_tail; + } +return NETDEV_TX_OK ; +} + + +irqreturn_t omapl_tx_can_intr (int irq,void *dev_id) +{ +struct net_device *ndev = dev_id; +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct net_device_stats *stats = &ndev->stats; +u32 bit_set, mbxno; + +pru_can_get_intr_status (priv->dev, &priv->can_tx_hndl); +if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus) + || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) { +__can_debug ("tx_int_status = 0x%X\n" , + priv->can_tx_hndl.u32interruptstatus); +can_free_echo_skb (ndev,0 ); + }else { +for (bit_set =0 ; ((priv->can_tx_hndl.u32interruptstatus &0xFF ) + >> bit_set !=0 ); bit_set++) + ; +if (0 == bit_set) { +__can_err ("%s: invalid mailbox number\n" , __func__); +can_free_echo_skb (ndev,0 ); + }else { + mbxno = bit_set -1 ;/* mail box numbering starts from 0 */ +if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl. + u32interruptstatus) { +/* read gsr and ack pru */ +pru_can_get_global_status (priv->dev, &priv->can_tx_hndl); + omapl_pru_can_err(ndev, + priv->can_tx_hndl. + u32interruptstatus,
drivers/net/can/da8xx_pruss/pruss_can.c line 461
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+ priv->can_tx_hndl. + u32globalstatus); + }else { + stats->tx_packets++; +/* stats->tx_bytes += dlc; */ +/*can_get_echo_skb(ndev, 0);*/ + } + } + } +if (netif_queue_stopped (ndev))
you can call netif_wake_queue(ndev) multiple times, so there is no need for netif_queue_stopped()
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +5
-0+netif_wake_queue (ndev); + +can_get_echo_skb (ndev,0 ); +pru_can_tx_mode_set (priv->dev, true, ecanreceive); +return IRQ_HANDLED ;
drivers/net/can/da8xx_pruss/pruss_can.c line 494
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+} + +static int omapl_pru_can_open (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +int err; + +/* register interrupt handler */ + err =request_irq (priv->trx_irq, &omapl_rx_can_intr,IRQF_SHARED , +"pru_can_irq" , ndev);
you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
drivers/net/can/da8xx_pruss/pruss_can.c line 533
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +5
-0+static int omapl_pru_can_close (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +if (!netif_queue_stopped (ndev))
check is not needed.
drivers/net/can/da8xx_pruss/pruss_can.c line 541
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +8
-0+netif_stop_queue (ndev); + +close_candev (ndev); + +free_irq (priv->trx_irq, ndev); +return 0 ; +} +
Regards,
Kurt
Re: [PATCH v2 09/13] can: pruss CAN driver.
--------------------------------------------------
From: "Kurt Van Dijck" <[email protected]>
Sent: Friday, February 11, 2011 8:50 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Wolfgang Grandegger" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list:CAN NETWORK DRIVERS" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 5 lines
Hi,
I looked a bit at the TX path:
On Fri, Feb 11, 2011 at 08:21:28PM +0530, Subhasish Ghosh wrote:
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 124
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +9
-0+static int omapl_pru_can_set_bittiming (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_bittiming *bt = &priv->can.bittiming; +long bit_error =0 ; + +if (priv->can.ctrlmode &CAN_CTRLMODE_3_SAMPLES ) { +dev_warn (priv->dev,"WARN: Triple" +"sampling not set due to h/w limitations" );You should not have enabled
CAN_CTRLMODE_3_SAMPLESin the first place?
SG - Ok Will remove.
Quoted 11 lines
Quoted 11 lines
+ }
+ if (pru_can_calc_timing(priv->dev,priv->can.clock.freq,
+bt->bitrate) != 0)
+ return-EINVAL;
+bit_error=drivers/net/can/da8xx_pruss/pruss_can.c new file +6
-0+ (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000 ) / bt->bitrate; +if (bit_error) { + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000000 ) / bt->bitrate;
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 114
Quoted 7 lines
+ printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
+bit_error/ 10000,bit_error% 1000);
+ } else
+printk(KERN_INFO "\nBitrate error 0.0%%\n");drivers/net/can/da8xx_pruss/pruss_can.c new file +3
-0+ +return 0 ; +}I wonder how much of this code is duplicated from
drivers/net/can/dev.c?
SG - Well, I just followed ti_hecc.c :-)
Quoted 14 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 210
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+static netdev_tx_t omapl_pru_can_start_xmit (struct sk_buff *skb, +struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_frame *cf = (struct can_frame *)skb->data; +int count; +u8 *data = cf->data; +u8 dlc = cf->can_dlc; +u8 *ptr8data =NULL ; +most drivers start with:
if (can_dropped_invalid_skb(dev, skb))
returnNETDEV_TX_OK;
SG - Will do.
Quoted 3 lines
Quoted 2 lines
+
netif_stop_queue(ndev);why would you stop when you just resumed the queue?
SG - I do not want more than one transmit request at one time. Hence, on entering the transmit I am using netif_stop_queue to disable tx.
Quoted 25 lines
Quoted 25 lines
+ if (
cf->can_id&CAN_EFF_FLAG) /* Extended frame format */
+ *((u32 *)&priv->can_tx_hndl.strcanmailbox) =drivers/net/can/da8xx_pruss/pruss_can.c new file +19
-0+ (cf->can_id &CAN_EFF_MASK ) |PRU_CANMID_IDE ; + else/* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_SFF_MASK ) <<18 ; + +if (cf->can_id &CAN_RTR_FLAG )/* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |=CAN_RTR_FLAG ; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc -1 ); +for (count =0 ; count < (u8 ) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32 ) dlc; +/* +* search for the next available mbx +* if the next mbx is busy, then try the next + 1 +* do this until the head is reached. +* if still unable to tx, stop accepting any packets +* if able to tx and the head is reached, then reset next to tail, i.e mbx0
+ * if head is not reached, then just point to the next mbx
+ */
+ for (;priv->tx_next<=priv->tx_head; priv->tx_next++) {
Quoted 8 lines
Quoted 7 lines
+
priv->can_tx_hndl.ecanmailboxnumber=
+ (can_mailbox_number)priv->tx_next;
+ if (-1 == pru_can_write_data_to_mailbox(priv->dev,
+&priv->can_tx_hndl)) {
+ if (priv->tx_next==priv->tx_head) {
+priv->tx_next=priv->tx_tail;
+ if (!netif_queue_stopped(ndev))If you get here, the queue is not stopped. This test is therefore useless.
SG -Ok, will remove
Quoted 58 lines
Quoted 58 lines
+
netif_stop_queue(ndev); /* IF stalled */
+ dev_err(priv->dev,
+ "%s: no tx mbx available",__func__);
+ returnNETDEV_TX_BUSY;
+ } else
+ continue;
+ } else {
+ /* set transmit request */
+pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1);
+pru_can_tx_mode_set(priv->dev, false, ecanreceive);
+pru_can_tx_mode_set(priv->dev, true, ecantransmit);
+pru_can_start_abort_tx(priv->dev, PRU_CAN_START);
+ priv->tx_next++;
+can_put_echo_skb(skb, ndev, 0);
+ break;
+ }
+ }
+ if (priv->tx_next>priv->tx_head) {
+priv->tx_next=priv->tx_tail;
+ }
+ returnNETDEV_TX_OK;drivers/net/can/da8xx_pruss/pruss_can.c new file +36
-0+} + + +irqreturn_t omapl_tx_can_intr (int irq,void *dev_id) +{ +struct net_device *ndev = dev_id; +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct net_device_stats *stats = &ndev->stats; +u32 bit_set, mbxno; + +pru_can_get_intr_status (priv->dev, &priv->can_tx_hndl); +if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus) + || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) { +__can_debug ("tx_int_status = 0x%X\n" , + priv->can_tx_hndl.u32interruptstatus); +can_free_echo_skb (ndev,0 ); + }else { +for (bit_set =0 ; ((priv->can_tx_hndl.u32interruptstatus &0xFF ) + >> bit_set !=0 ); bit_set++) + ; +if (0 == bit_set) { +__can_err ("%s: invalid mailbox number\n" , __func__); +can_free_echo_skb (ndev,0 ); + }else { + mbxno = bit_set -1 ;/* mail box numbering starts from 0 */ +if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl. + u32interruptstatus) { +/* read gsr and ack pru */ +pru_can_get_global_status (priv->dev, &priv->can_tx_hndl); +omapl_pru_can_err (ndev, + priv->can_tx_hndl. + u32interruptstatus, + priv->can_tx_hndl. + u32globalstatus); + }else { + stats->tx_packets++;
Quoted 8 lines
Quoted 6 lines
+ /*
stats->tx_bytes+= dlc; */
+ /*can_get_echo_skb(ndev, 0);*/
+ }
+ }
+ }
+ if (netif_queue_stopped(ndev))you can call
netif_wake_queue(ndev)multiple times, so there is no need fornetif_queue_stopped()
SG -Ok, will remove
Quoted 8 lines
Quoted 8 lines
+
netif_wake_queue(ndev);drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+ +can_get_echo_skb (ndev,0 ); +pru_can_tx_mode_set (priv->dev, true, ecanreceive); +return IRQ_HANDLED ; +} + +static int omapl_pru_can_open (struct net_device *ndev)
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 494
Quoted 7 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +int err; + +/* register interrupt handler */ + err =request_irq (priv->trx_irq, &omapl_rx_can_intr,IRQF_SHARED , +"pru_can_irq" , ndev);you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
SG -Ok, will do
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 533
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +5
-0+static int omapl_pru_can_close (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +if (!netif_queue_stopped (ndev))check is not needed.
SG -Ok, will remove
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can.c line 541
Quoted 8 lines
+
netif_stop_queue(ndev);drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+ +close_candev (ndev); + +free_irq (priv->trx_irq, ndev); +return 0 ; +} +Regards,
Kurt
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 2 lines · Subhasish Ghosh
--------------------------------------------------
From: "Kurt Van Dijck" <kurt.van.dijck-/[email protected]>
...
Quoted 6 lines
Quoted 5 lines
Quoted 3 lines
+ /* register interrupt handler */
+ err = request_irq(priv->trx_irq,&omapl_rx_can_intr,IRQF_SHARED,
+ "pru_can_irq", ndev);you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
SG -Ok, will do
No, please use NAPI instead.
Wolfgang
Re: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 5 lines · Subhasish Ghosh
Quoted 2 lines
--------------------------------------------------
From: "Kurt Van Dijck" <[email protected]>...
Quoted 8 lines
Quoted 6 lines
Quoted 5 lines
Quoted 3 lines
+ /* register interrupt handler */
+ err = request_irq(priv->trx_irq,&omapl_rx_can_intr,IRQF_SHARED,
+ "pru_can_irq", ndev);you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
SG -Ok, will do
No, please use NAPI instead.
We are using h/w filters, so the number of interrupts coming into the processor are not hogging it. I feel that we may not require an interrupt mitigation.
-Subhasish
Marc Kleine-Budde
maintainerRe: [PATCH v2 09/13] can: pruss CAN driver.
Quoted 10 lines · Subhasish Ghosh
Quoted 10 lines · Subhasish Ghosh
Quoted 2 lines
--------------------------------------------------
From: "Kurt Van Dijck" <[email protected]>...
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
+ /* register interrupt handler */
+ err = request_irq(priv->trx_irq,&omapl_rx_can_intr,IRQF_SHARED,
+ "pru_can_irq", ndev);you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
SG -Ok, will do
No, please use NAPI instead.
We are using h/w filters, so the number of interrupts coming into the processor are not hogging it.
I feel that we may not require an interrupt mitigation.
As davem stated the other day, all new drivers should use NAPI.
regards, Marc
Signature · 12 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de | -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 262 bytes Desc: OpenPGP digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110218/ce017071/attachment.sig>
Re: [PATCH v2 09/13] can: pruss CAN driver.
Ok, will do NAPI
Quoted 10 lines · Subhasish Ghosh
Quoted 10 lines · Subhasish Ghosh
Quoted 2 lines
--------------------------------------------------
From: "Kurt Van Dijck" <[email protected]>...
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
+ /* register interrupt handler */
+ err = request_irq(priv->trx_irq,&omapl_rx_can_intr,IRQF_SHARED,
+ "pru_can_irq", ndev);you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
SG -Ok, will do
No, please use NAPI instead.
We are using h/w filters, so the number of interrupts coming into the processor are not hogging it.
I feel that we may not require an interrupt mitigation.
As davem stated the other day, all new drivers should use NAPI.
regards, Marc
Signature · 3 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
A message that is not in the archive (sent off-list or not yet received): 1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org
Re: [PATCH v2 09/13] can: pruss CAN driver.
Hello,
thanks for your contribution.
First some general comments:
- Please send a separate patch for the Socket-CAN driver.
Or are there good reasons why we should look at the other 12 patches?
- Please run checkpatch.pl and fix the reported warnings. There are many.
- You are using casts extensively. Please get rid of them.
- Decoding the variable type into the name is *deprecated* in Linux.
- Also very long names are *deprecated* in Linux.
- Don't use typedef's.
Some more comments inline...
Quoted 17 lines · Subhasish Ghosh
This patch adds support for the CAN device emulated on PRUSS.
--- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/da8xx_pruss/Kconfig | 73 ++ drivers/net/can/da8xx_pruss/Makefile | 7 + drivers/net/can/da8xx_pruss/pruss_can.c | 758 +++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.h | 290 +++++++ 7 files changed, 2357 insertions(+), 0 deletions(-) create mode 100644 drivers/net/can/da8xx_pruss/Kconfig create mode 100644 drivers/net/can/da8xx_pruss/Makefile create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h
Why not s/da8xx_pruss/pruss_can/ ?
Quoted 17 lines
drivers/net/can/Kconfig +1
-0@@ -112,6 +112,7 @@ config PCH_CAN This driver can access CAN bus. source "drivers/net/can/mscan/Kconfig" +source "drivers/net/can/da8xx_pruss/Kconfig" source "drivers/net/can/sja1000/Kconfig"drivers/net/can/Makefile +0
-0
drivers/net/can/Makefile obj-$(CONFIG_CAN_SJA1000) += sja1000/ · line 17
Quoted 4 lines
drivers/net/can/Makefile +1
-0@@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += da8xx_pruss/
Please use a common name/prefix, e.g. pruss_can.
Quoted 72 lines
drivers/net/can/Makefile +0
-0obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.odrivers/net/can/da8xx_pruss/Kconfig new file +63
-0@@ -0,0 +1,73 @@ +# +# CAN Lite Kernel Configuration +# +config CAN_TI_DA8XX_PRU + depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850 + tristate "PRU based CAN emulation for DA8XX" + ---help--- + Enable this to emulate a CAN controller on the PRU of DA8XX. + If not sure, mark N + +config DA8XX_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help---
drivers/net/can/da8xx_pruss/Kconfig line 73
Quoted 10 lines
drivers/net/can/da8xx_pruss/Kconfig new file +10
-0+ Enter the CANID for mailbox 6 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 + Default value is set to 0x123, change this as required.
Well, defining CAN identifiers via Kconfig entries is really wired. Could you please explain why that's necessary and what's so special with that CAN hardware. We need a better solution if the CAN controller cannot handle and CAN id.
drivers/net/can/da8xx_pruss/Makefile line 7
Quoted 13 lines
drivers/net/can/da8xx_pruss/Makefile new file +7
-0@@ -0,0 +1,7 @@ +# +# Makefile for CAN Lite emulation +# +can_emu-objs := pruss_can.o \ + pruss_can_api.o + +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += can_emu.o
Again another name.
Quoted 79 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +73
-0@@ -0,0 +1,758 @@ +/* +* TI DA8XX PRU CAN Emulation device driver +* Author: subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org +* +* This driver supports TI's PRU CAN Emulation and the +* specs for the same is available at <http://www.ti.com> +* +* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +* +* 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/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/platform_device.h> +#include <linux/firmware.h> +#include <linux/clk.h> +#include <linux/types.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <mach/da8xx.h> +#include "pruss_can_api.h" + +#define DRV_NAME "da8xx_pruss_can" +#define DRV_DESC "TI PRU CAN Controller Driver v0.1" +#define PRU_CAN_START 1 +#define PRU_CAN_STOP 0 +#define MB_MIN 0 +#define MB_MAX 7 + +#define PRU_CANMID_IDE BIT(29)/* Extended frame format */ + +#define PRU_CAN_ISR_BIT_CCI BIT(15) +#define PRU_CAN_ISR_BIT_ESI BIT(14) +#define PRU_CAN_ISR_BIT_SRDI BIT(13) +#define PRU_CAN_ISR_BIT_RRI BIT(8) + +#define PRU_CAN_MBXSR_BIT_STATE BIT(7) +#define PRU_CAN_MBXSR_BIT_TC BIT(6) +#define PRU_CAN_MBXSR_BIT_ERR BIT(5) +#define PRU_CAN_MBXSR_BIT_OF BIT(0) + +#define PRU_CAN_GSR_BIT_TXM BIT(7) +#define PRU_CAN_GSR_BIT_RXM BIT(6) +#define PRU_CAN_GSR_BIT_CM BIT(5) +#define PRU_CAN_GSR_BIT_EPM BIT(4) +#define PRU_CAN_GSR_BIT_BFM BIT(3) +#define RTR_MBX_NO 8 +#define MAX_INIT_RETRIES 20 +#define L138_PRU_ARM_FREQ 312000 +#define DFLT_PRU_FREQ 156000000 +#define DFLT_PRU_BITRATE 125000 + +#define CONFIG_DA8XX_PRU_CANID_MBX0 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX1 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX2 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX3 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX4 0x123
drivers/net/can/da8xx_pruss/pruss_can.c line 83
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+#define CONFIG_DA8XX_PRU_CANID_MBX5 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX6 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX7 0x123 + +#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args) +#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)
Please use dev_dbg, dev_err, ... or netif_dbg, netdev_err, ... instead.
Quoted 20 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +20
-0+/* +* omapl_pru can private data +*/ +struct omapl_pru_can_priv { +struct can_priv can; +struct workqueue_struct *pru_can_wQ; +struct work_struct rx_work; +struct net_device *ndev; +struct device *dev;/* pdev->dev */ +struct clk *clk_timer; +u32 timer_freq; +can_emu_app_hndl can_tx_hndl; +can_emu_app_hndl can_rx_hndl; +const struct firmware *fw_rx; +const struct firmware *fw_tx; +spinlock_t mbox_lock; +u32 trx_irq; +u32 tx_head; +u32 tx_tail; +u32 tx_next;
drivers/net/can/da8xx_pruss/pruss_can.c line 114
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+u32 rx_next; +}; + +static int omapl_pru_can_get_state (const struct net_device *ndev, +enum can_state *state) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + *state = priv->can.state; +return 0 ; +}
There is no need for that function as you handle state changes in the interrupt context.
drivers/net/can/da8xx_pruss/pruss_can.c line 125
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+static int omapl_pru_can_set_bittiming (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_bittiming *bt = &priv->can.bittiming; +long bit_error =0 ; + +if (priv->can.ctrlmode &CAN_CTRLMODE_3_SAMPLES ) { +dev_warn (priv->dev,"WARN: Triple" +"sampling not set due to h/w limitations" ); + }
No need for this test as you have not set the CAN_CTRLMODE_3_SAMPLES bit in priv.ctrlmode_supported.
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +6
-0+if (pru_can_calc_timing (priv->dev, priv->can.clock.freq, + bt->bitrate) !=0 ) +return -EINVAL ; + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000 ) / bt->bitrate;
drivers/net/can/da8xx_pruss/pruss_can.c line 141
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+if (bit_error) { + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000000 ) / bt->bitrate; +printk (KERN_INFO "\nBitrate error %ld.%ld%%\n" , + bit_error /10000 , bit_error %1000 ); + }else +printk (KERN_INFO "\nBitrate error 0.0%%\n" ); + +return 0 ;
Please use the pre-calculated bit-timing parameters. Have a look to the SJA1000 driver for further information:
http://lxr.linux.no/#linux+v2.6.37/drivers/net/can/sja1000/sja1000.c#L202
In general, please use the bit-timing interface of Socket-CAN and drop you own.
Quoted 20 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +20
-0+} + +static void omapl_pru_can_stop (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u16 int_mask =0 ; + +pru_can_mask_ints (priv->dev, int_mask);/* mask all ints */ +pru_can_start_abort_tx (priv->dev,PRU_CAN_STOP ); + priv->can.state =CAN_STATE_STOPPED ; +} + +/* +* This is to just set the can state to ERROR_ACTIVE +* ip link set canX up type can bitrate 125000 +*/ +static void omapl_pru_can_start (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u16 int_mask =0xFFFF ;
drivers/net/can/da8xx_pruss/pruss_can.c line 171
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+ +if (priv->can.state !=CAN_STATE_STOPPED ) +omapl_pru_can_stop (ndev); + +pru_can_mask_ints (priv->dev, int_mask);/* unmask all ints */ + +pru_can_get_global_status (priv->dev, &priv->can_tx_hndl); +pru_can_get_global_status (priv->dev, &priv->can_rx_hndl); + +if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus)
Decoding the variable type into the name is deprecated in Linux.
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +12
-0+ priv->can.state =CAN_STATE_ERROR_PASSIVE ; + else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus) + priv->can.state =CAN_STATE_BUS_OFF ; + else + priv->can.state = CAN_STATE_ERROR_ACTIVE; +} + +static int omapl_pru_can_set_mode (struct net_device *ndev,enum can_mode mode) +{ +int ret =0 ; + +switch (mode) {
drivers/net/can/da8xx_pruss/pruss_can.c line 193
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+case CAN_MODE_START : +omapl_pru_can_start (ndev); +if (netif_queue_stopped (ndev)) +netif_wake_queue (ndev); +break ; +case CAN_MODE_STOP : +omapl_pru_can_stop (ndev); +if (!netif_queue_stopped (ndev)) +netif_stop_queue (ndev); +break ;
This case is not supported.
Quoted 17 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +17
-0+default : + ret = -EOPNOTSUPP ; +break ; + } +return ret; +} + +static netdev_tx_t omapl_pru_can_start_xmit (struct sk_buff *skb, +struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_frame *cf = (struct can_frame *)skb->data; +int count; +u8 *data = cf->data; +u8 dlc = cf->can_dlc; +u8 *ptr8data =NULL ; +
drivers/net/can/da8xx_pruss/pruss_can.c line 217
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+netif_stop_queue (ndev); +if (cf->can_id &CAN_EFF_FLAG )/* Extended frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_EFF_MASK ) |PRU_CANMID_IDE ; +else /* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_SFF_MASK ) <<18 ;
You use many of such wired expressions. strcanmailbox is a struct
typedef struct {
u16 u16extendedidentifier;
u16 u16baseidentifier;
... } can_mail_box_structure;
and you obviously set the fist two fields. In contrast, the member u16extendedidentifier is never directly used. Puh, that's magic. Please make your code more transparent and readable.
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +8
-0+if (cf->can_id &CAN_RTR_FLAG )/* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |=CAN_RTR_FLAG ; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc -1 ); +for (count =0 ; count < (u8 ) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32 ) dlc;
...
drivers/net/can/da8xx_pruss/pruss_can.c line 481
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +13
-0+irqreturn_t omapl_rx_can_intr (int irq,void *dev_id) +{ + +struct net_device *ndev = dev_id; +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u32 intc_status =0 ; + + intc_status =pru_can_get_intc_status (priv->dev); +if (intc_status &4 ) +return omapl_tx_can_intr (irq, dev_id); +if (intc_status &2 ) { +if (!work_pending (&priv->rx_work)) +queue_work (priv->pru_can_wQ, &priv->rx_work);
You handle RX in a work queue!? Please use NAPI instead.
Quoted 168 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +168
-0+ } + +return IRQ_HANDLED ; +} + +static int omapl_pru_can_open (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +int err; + +/* register interrupt handler */ + err =request_irq (priv->trx_irq, &omapl_rx_can_intr,IRQF_SHARED , +"pru_can_irq" , ndev); +if (err) { +dev_err (priv->dev,"error requesting rx interrupt\n" ); + goto exit_trx_irq; + } +/* common open */ + err =open_candev (ndev); +if (err) { +dev_err (priv->dev,"open_candev() failed %d\n" , err); + goto exit_open; + } + +pru_can_emu_init (priv->dev, priv->can.clock.freq); + priv->tx_tail =MB_MIN ; + priv->tx_head =MB_MAX ; + +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX0 ,0 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX1 ,1 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX2 ,2 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX3 ,3 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX4 ,4 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX5 ,5 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX6 ,6 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX7 ,7 ); + +omapl_pru_can_start (ndev); +netif_start_queue (ndev); +return 0 ; + +exit_open: +free_irq (priv->trx_irq, ndev); +exit_trx_irq: +return err; +} + +static int omapl_pru_can_close (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +if (!netif_queue_stopped (ndev)) +netif_stop_queue (ndev); + +close_candev (ndev); + +free_irq (priv->trx_irq, ndev); +return 0 ; +} + +static const struct net_device_ops omapl_pru_can_netdev_ops = { + .ndo_open = omapl_pru_can_open, + .ndo_stop = omapl_pru_can_close, + .ndo_start_xmit = omapl_pru_can_start_xmit, +}; + +static int __devinit omapl_pru_can_probe (struct platform_device *pdev) +{ +struct net_device *ndev =NULL ; +const struct da8xx_pru_can_data *pdata; +struct omapl_pru_can_priv *priv =NULL ; +struct device *dev = &pdev->dev; +u32 err; + + pdata = dev->platform_data; +if (!pdata) { +dev_err (&pdev->dev,"platform data not found\n" ); +return -EINVAL ; + } + + ndev =alloc_candev (sizeof (struct omapl_pru_can_priv ),MB_MAX +1 ); +if (!ndev) { +dev_err (&pdev->dev,"alloc_candev failed\n" ); + err = -ENOMEM ; + goto probe_exit; + } + priv =netdev_priv (ndev); + + priv->trx_irq =platform_get_irq (to_platform_device (dev->parent),0 ); +if (!priv->trx_irq) { +dev_err (&pdev->dev,"unable to get pru interrupt resources!\n" ); + err = -ENODEV ; + goto probe_exit; + } + + priv->ndev = ndev; + priv->dev = dev;/* priv->dev = pdev->dev */ + + priv->can.bittiming_const =NULL ; + priv->can.do_set_bittiming = omapl_pru_can_set_bittiming; + priv->can.do_set_mode = omapl_pru_can_set_mode; + priv->can.do_get_state = omapl_pru_can_get_state; + priv->can_tx_hndl.u8prunumber =CAN_TX_PRU_1 ; + priv->can_rx_hndl.u8prunumber =CAN_RX_PRU_0 ; + +/* we support local echo, no arp */ + ndev->flags |= (IFF_ECHO |IFF_NOARP ); + +/* pdev->dev->device_private->driver_data = ndev */ +platform_set_drvdata (pdev, ndev); +SET_NETDEV_DEV (ndev, &pdev->dev); + ndev->netdev_ops = &omapl_pru_can_netdev_ops; + + priv->can.clock.freq =pruss_get_clk_freq (priv->dev); + + priv->clk_timer =clk_get (&pdev->dev,"pll1_sysclk2" ); +if (IS_ERR (priv->clk_timer)) { +dev_err (&pdev->dev,"no timer clock available\n" ); + err =PTR_ERR (priv->clk_timer); + priv->clk_timer =NULL ; + goto probe_exit_candev; + } + priv->timer_freq =clk_get_rate (priv->clk_timer); + + err =register_candev (ndev); +if (err) { +dev_err (&pdev->dev,"register_candev() failed\n" ); + err = -ENODEV ; + goto probe_exit_clk; + } + + err =request_firmware (&priv->fw_tx,"PRU_CAN_Emulation_Tx.bin" , + &pdev->dev); +if (err) { +dev_err (&pdev->dev,"can't load firmware\n" ); + err = -ENODEV ; + goto probe_exit_clk; + } + +dev_info (&pdev->dev,"fw_tx size %d. downloading...\n" , + priv->fw_tx->size); + + err =request_firmware (&priv->fw_rx,"PRU_CAN_Emulation_Rx.bin" , + &pdev->dev); +if (err) { +dev_err (&pdev->dev,"can't load firmware\n" ); + err = -ENODEV ; + goto probe_release_fw; + } +dev_info (&pdev->dev,"fw_rx size %d. downloading...\n" , + priv->fw_rx->size); + +/* init the pru */ +pru_can_emu_init (priv->dev, priv->can.clock.freq); +udelay (200 ); + +pruss_enable (priv->dev,CAN_RX_PRU_0 ); +pruss_enable (priv->dev,CAN_TX_PRU_1 ); + +/* download firmware into pru */ + err =pruss_load (priv->dev,CAN_RX_PRU_0 , + (u32 *)priv->fw_rx->data, (priv->fw_rx->size /4 )); +if (err) { +dev_err (&pdev->dev,"firmware download error\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + err = pruss_load(priv->dev, CAN_TX_PRU_1,
drivers/net/can/da8xx_pruss/pruss_can.c line 659
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+ (u32 *)priv->fw_tx->data, (priv->fw_tx->size / 4)); +if (err) { +dev_err (&pdev->dev,"firmware download error\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + +if (pru_can_calc_timing (priv->dev,DFLT_PRU_FREQ , +DFLT_PRU_BITRATE ) !=0 ) +return -EINVAL ;
Please don't define a default bit-rate. It's error prune.
Quoted 223 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +99
-0+ +pruss_run (priv->dev,CAN_RX_PRU_0 ); +pruss_run (priv->dev,CAN_TX_PRU_1 ); + +/*Create The Work Queue */ + priv->pru_can_wQ =create_freezeable_workqueue ("omapl_pru_wQ" ); +if (priv->pru_can_wQ ==NULL ) { +dev_err (&pdev->dev,"failed to create work queue\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + +INIT_WORK (&priv->rx_work, omapl_pru_can_rx_wQ); +dev_info (&pdev->dev, +"%s device registered (trx_irq = %d, clk = %d)\n" , +DRV_NAME , priv->trx_irq, priv->can.clock.freq); + +return 0 ; + +probe_release_fw_1: +release_firmware (priv->fw_rx); +probe_release_fw: +release_firmware (priv->fw_tx); +probe_exit_clk: +clk_put (priv->clk_timer); +probe_exit_candev: +if (NULL != ndev) +free_candev (ndev); +probe_exit: +return err; +} + +static int __devexit omapl_pru_can_remove(struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +omapl_pru_can_stop (ndev); + +pru_can_emu_exit (priv->dev); +release_firmware (priv->fw_tx); +release_firmware (priv->fw_rx); +clk_put (priv->clk_timer); +flush_workqueue (priv->pru_can_wQ); +destroy_workqueue (priv->pru_can_wQ); +unregister_candev (ndev); +free_candev (ndev); +platform_set_drvdata (pdev,NULL ); +return 0 ; +} + +#ifdef CONFIG_PM +static int omapl_pru_can_suspend (struct platform_device *pdev, +pm_message_t mesg) +{ +dev_info (&pdev->dev,"%s not yet implemented\n" , __func__); +return 0 ; +} + +static int omapl_pru_can_resume (struct platform_device *pdev) +{ +dev_info (&pdev->dev,"%s not yet implemented\n" , __func__); +return 0 ; +} +#else +#define omapl_pru_can_suspend NULL +#define omapl_pru_can_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver omapl_pru_can_driver = { + .probe = omapl_pru_can_probe, + .remove =__devexit_p (omapl_pru_can_remove), + .suspend = omapl_pru_can_suspend, + .resume = omapl_pru_can_resume, + .driver = { + .name =DRV_NAME , + .owner =THIS_MODULE , + }, +}; + +static int __init omapl_pru_can_init (void ) +{ + __can_debug(KERN_INFO DRV_DESC "\n"); + return platform_driver_register(&omapl_pru_can_driver); +} + +module_init (omapl_pru_can_init); + +static void __exit omapl_pru_can_exit(void) +{ + __can_debug(KERN_INFO DRV_DESC " unloaded\n"); +platform_driver_unregister (&omapl_pru_can_driver); +} + +module_exit (omapl_pru_can_exit); + +MODULE_AUTHOR ("Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>" ); +MODULE_LICENSE ("GPL" ); +MODULE_DESCRIPTION ("omapl pru CAN netdevice driver" );drivers/net/can/da8xx_pruss/pruss_can_api.c new file +118
-0@@ -0,0 +1,1227 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Wilfred Felix +* +* 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 "pruss_can_api.h" + +static can_emu_drv_inst gstr_can_inst[ecanmaxinst]; + +/* +* pru_can_set_brp() Updates the BRP register of PRU0 +* and PRU1 of OMAP L138. This API will be called by the +* Application to updtae the BRP register of PRU0 and PRU1 +* +* param u16bitrateprescaler The can bus bitrate +* prescaler value be set +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_brp (struct device *dev,u16 u16bitrateprescaler) +{ + +u32 u32offset; + +if (u16bitrateprescaler >255 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 ); + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 ); + +return 0 ; + +} + +/* +* pru_can_set_bit_timing() Updates the timing register +* of PRU0 and PRU1 of OMAP L138. This API will be called by +* the Application to updtae the timing register of PRU0 and PRU1 +* +* param pstrbittiming Pointer to structure holding +* the bit timing values for can bus. +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_bit_timing (struct device *dev, +can_bit_timing_consts *pstrbittiming) +{ + +u32 u32offset; +u32 u32serregister; + + u32serregister =0 ; + +if (pstrbittiming ==NULL ) { +return -1 ; + } + +if ((pstrbittiming->u8syncjumpwidth >PRU_CAN_MAX_SJW ) || + (pstrbittiming->u8phseg1 >PRU_CAN_MAX_PHSEG1 ) || + (pstrbittiming->u8phseg2 >PRU_CAN_MAX_PHSEG2 )) { +return -1 ; + } + + u32serregister = u32serregister | + ((pstrbittiming->u8syncjumpwidth <<7 ) | + (pstrbittiming->u8phseg1 <<3 ) | + (pstrbittiming->u8phseg2)); + + u32offset = (PRU_CAN_TX_TIMING_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u32serregister,1 ); + + u32offset = (PRU_CAN_RX_TIMING_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u32serregister,1 ); + +return 0 ; +} + + +/* +* pru_can_calc_timing() +* Updates the timing values of PRU0 and PRU1 of OMAP L138. +* This API will be called by the +* Application to updtae the timing values of PRU0 and PRU1 +* +* return SUCCESS or FAILURE +*/ + +s16 pru_can_calc_timing (struct device *dev,u32 pru_freq,u32 bit_rate) +{ +u16 u16phaseseg1; +u16 u16phaseseg2; +u32 u32offset; +u32 u32timing_value; +u32 u32setup_value; + u32timing_value =TIMER_CLK_FREQ / bit_rate; + u32offset = (PRU_CAN_TIMING_VAL_TX ); +pruss_writel (dev, u32offset, (u32 *) &u32timing_value,4 ); +pruss_readl (dev, u32offset, (u32 *) &u32timing_value,4 ); + u32setup_value = + (GPIO_SETUP_DELAY * (pru_freq /1000000 ) /1000 ) / +DELAY_LOOP_LENGTH ; + u32offset = (PRU_CAN_TIMING_VAL_TX_SJW ); +pruss_writel (dev, u32offset, (u32 *) &u32setup_value,4 ); + u16phaseseg1 = (u16) (u32timing_value /2 ); + u16phaseseg2 = u32timing_value - u16phaseseg1;
drivers/net/can/da8xx_pruss/pruss_can_api.c line 128
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ u16phaseseg1 -=TIMER_SETUP_DELAY ; + u16phaseseg2 -=TIMER_SETUP_DELAY ; + u32setup_value = (u16phaseseg1 <<16 ) | u16phaseseg2; + u32offset = (PRU_CAN_TIMING_VAL_RX ); +pruss_writel (dev, u32offset, (u32 *) &u32setup_value,4 ); + u32offset = (PRU_CAN_TIMING_VAL_RX +4 ); +pruss_writel (dev, u32offset, (u32 *) &u32timing_value,4 ); + +return 0 ; +}
Why can't you use the common Socket-CAN bit-timing infrastructure.
Quoted 40 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +40
-0+/* +* pru_can_write_data_to_mailbox() +* Updates the transmit mailboxes of PRU1 of OMAP L138. +* This API will be called by the Application to update +* the transmit mailboxes of PRU1 +* +* param pu16canframedata Can mailbox data buffer +* +* param u8mailboxnum Mailbox to be updated +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_write_data_to_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +switch ((u8 ) pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0 ); +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1 ); +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2 ); +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3 ); +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4 ); +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5 );
drivers/net/can/da8xx_pruss/pruss_can_api.c line 179
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6 ); +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7 ); +break ; +default : +return -1 ; + }
There are more efficient ways to implemet that, e.g. by using an array.
Quoted 51 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +51
-0+ s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox),4 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +/* +* pru_can_get_data_from_mailbox() +* Receive data from the receive mailboxes of PRU0 of OMAP L138. +* This API will be called by the Application to get data from +* the receive mailboxes of PRU0 +* +* param pu16canframedata Can mailbox data buffer +* +* param u8mailboxnum Mailbox to be updated +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_data_from_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +switch ((u8 ) pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0 ); +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1 ); +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2 ); +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3 ); +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4 ); +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5 ); +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6 );
drivers/net/can/da8xx_pruss/pruss_can_api.c line 241
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7 ); +break ; +case 8 : + u32offset = (PRU_CAN_RX_MAILBOX8 ); +break ; +default : +return -1 ; + }
Ditto.
Quoted 645 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +645
-0+ s16subrtnretval = +pruss_readl (dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox), +4 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +/* +* pru_can_receive_id_map() +* Receive mailboxes ID Mapping of PRU0 of OMAP L138. +* This API will be called by the Application +* to map the IDs to receive mailboxes of PRU0 +* +* param u32nodeid Can node ID +* +* param ecanmailboxno Mailbox to be mapped +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_rx_id_map (struct device *dev,u32 u32nodeid, +can_mailbox_number ecanmailboxno) +{ + +pruss_writel (dev, (PRU_CAN_ID_MAP + + (((u8 ) ecanmailboxno) *4 )), (u32 *) &u32nodeid,1 ); + +return 0 ; +} + +/* +* pru_can_get_intr_status() +* Gets the interrupts status register value. +* This API will be called by the Application +* to get the interrupts status register value +* +* param u8prunumber PRU number for which IntStatusReg +* has to be read +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_intr_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER ); + }else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER ); + }else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32interruptstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +/* +* pru_can_get_global_status() Gets the globalstatus +* register value. This API will be called by the Application +* to get the global status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_global_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +int s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); + }else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); + }else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32globalstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +/* +* pru_can_get_mailbox_status() Gets the mailbox status +* register value. This API will be called by the Application +* to get the mailbox status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_mailbox_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { +switch (pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER ); +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER ); +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER ); +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER ); +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER ); +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER ); +break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER ); +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER ); +break ; +default : +return -1 ; + } + } + +else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { +switch (pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER ); +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER ); +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER ); +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER ); +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER ); +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER ); +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER ); +break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER ); +break ; +case 8 : + u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER ); +break ; +default : +return -1 ; + } + } + +else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32mailboxstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +s16 pru_can_tx_mode_set (struct device *dev,bool btransfer_flag, +can_transfer_direction ecan_trx) +{ +u32 u32offset; +u32 u32value; + +if (ecan_trx == ecantransmit) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); +pruss_readl (dev, u32offset, &u32value,1 ); +if (btransfer_flag == true) { + u32value &=0x1F ; + u32value |=0x80 ; + }else { + u32value &=0x7F ; + } +pruss_writel (dev, u32offset, &u32value,1 ); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); +pruss_writel (dev, u32offset, &u32value,1 ); + }else if (ecan_trx == ecanreceive) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); +pruss_readl (dev, u32offset, &u32value,1 ); +if (btransfer_flag == true) { + u32value &=0x1F ; + u32value |=0x40 ; + }else { + u32value &=0xBF ; + } +pruss_writel (dev, u32offset, &u32value,1 ); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); +pruss_writel (dev, u32offset, &u32value,1 ); + }else +return -1 ; + +return 0 ; +} + +/* +* pru_can_config_mode_set() Sets the timing value +* for data transfer. This API will be called by the Application +* to set timing valus for data transfer +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_config_mode_set (struct device *dev,bool bconfigmodeflag) +{ + +u32 u32bitrateprescaler; +u32 u32canbittiming; + +pruss_readl (dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER ), + (u32 *) &u32bitrateprescaler,1 ); +pruss_readl (dev, (PRU_CAN_TX_TIMING_REGISTER ), + (u32 *) &u32canbittiming,1 ); + +if (bconfigmodeflag ==1 ) { +pru_can_calc_timing (dev, u32canbittiming, u32bitrateprescaler); + } + +else { +pru_can_calc_timing (dev,0 ,0 ); + } + +return 0 ; +} + +/* +* pru_can_emu_init() Initializes the Can +* Emulation Parameters. This API will be called by the Application +* to Initialize the Can Emulation Parameters +* +* param u32pruclock PRU Clock value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_init (struct device *dev,u32 u32pruclock) +{ +u32 u32offset; +u32 u32value; +s16 s16subrtnretval =-1 ; +u8 u8loop; + +for (u8loop =0 ; u8loop < (u8 ) ecanmaxinst; u8loop++) { + gstr_can_inst[u8loop].bcaninststate = (bool )0 ; + gstr_can_inst[u8loop].ecantransferdirection = + (can_transfer_direction )0 ; + gstr_can_inst[u8loop].u32apphandlerptr =0 ; + } + + u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER &0xFFFF ); + u32value =0x00004000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval = +pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_TIMING_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_POLARITY0 &0xFFFF ); + u32value =0xFFFFFFFF ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_POLARITY1 &0xFFFF ); + u32value =0xFFFFFFFF ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_TYPE0 &0xFFFF ); + u32value =0x1C000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_TYPE1 &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HSTINTENIDXCLR &0xFFFF ); + u32value =0x0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_GLBLEN &0xFFFF ); + u32value =0x1 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +/* tx intr map arm->pru */ + u32offset = (PRUSS_INTC_HSTINTENIDXSET &0xFFFF ); + u32value =0x0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP0 &0xFFFF ); + u32value =0x03020100 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP1 &0xFFFF ); + u32value =0x07060504 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP2 &0xFFFF ); + u32value =0x0000908 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_CHANMAP0 &0xFFFF ); + u32value =0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_CHANMAP8 &0xFFFF ); + u32value =0x00020200 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =19 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =19 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =18 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =18 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =34 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =34 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTINTEN &0xFFFF ); + u32value =0x5 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +/* PRU0 - Rx Internal Registers Initializations */ + + u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER &0xFFFF ); + u32value =0x00004000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x0000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_TIMING_REGISTER &0xFFFF ); + u32value =0x0000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 );
drivers/net/can/da8xx_pruss/pruss_can_api.c line 897
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + }
Above I realize a lot of duplicated code. Could be handled by an array more efficiently, I believe.
Quoted 258 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +258
-0+return 0 ; +} + + +/* +* pru_can_emu_open() Opens the can emu for +* application to use. This API will be called by the Application +* to Open the can emu for application to use. +* +* param pstremuapphndl Pointer to application handler +* structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_open (struct device *dev,can_emu_app_hndl *pstremuapphndl) +{ + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate ==1 ) { +return -1 ; + } + + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance]. + bcaninststate = (bool )1 ; + gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].ecantransferdirection = + (can_transfer_direction )(u8 )pstremuapphndl->ecantransferdirection; + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance]. + u32apphandlerptr = (u32 ) pstremuapphndl; + +return 0 ; +} + + +/* +* brief pru_can_emu_close() Closes the can emu for other +* applications to use. This API will be called by the Application to Close +* the can emu for other applications to use +* +* param pstremuapphndl Pointer to application handler structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_close (struct device *dev,can_emu_app_hndl *pstremuapphndl) +{ + +if (pstremuapphndl ==NULL ) { +return -1 ; + } +if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate ==0 ) { +return -1 ; + } +if ((u32 ) pstremuapphndl != gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].u32apphandlerptr){ +return -1 ; + } + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance].bcaninststate + = (bool )0 ; + gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].ecantransferdirection = (can_transfer_direction )0 ; + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance].u32apphandlerptr =0 ; + +return 0 ; +} + +/* +* brief pru_can_emu_exit() Diables all the PRUs +* This API will be called by the Application to disable all PRUs +* param None +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_exit (struct device *dev) +{ +s16 s16subrtnretval; + + s16subrtnretval =pruss_disable (dev,CAN_RX_PRU_0 ); +if (s16subrtnretval ==-1 ) +return -1 ; + s16subrtnretval =pruss_disable (dev,CAN_TX_PRU_1 ); +if (s16subrtnretval ==-1 ) +return -1 ; + +return 0 ; +} + +s16 pru_can_emu_sreset (struct device *dev) +{ +return 0 ; +} + +s16 pru_can_tx (struct device *dev,u8 u8mailboxnumber,u8 u8prunumber) +{ +u32 u32offset =0 ; +u32 u32value =0 ; +s16 s16subrtnretval =-1 ; + +if (DA8XX_PRUCORE_1 == u8prunumber) { +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +default : +return -1 ; + } + }else { + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32value = u32value & ~(1 << u8mailboxnumber); + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER &0xFFFF );
drivers/net/can/da8xx_pruss/pruss_can_api.c line 1165
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +default : +return -1 ; + }
Ditto.
Quoted 156 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +62
-0+ } +return 0 ; +} + +s16 pru_can_start_abort_tx (struct device *dev,bool bcantransmitabortflag) +{ +u32 u32offset; +u32 u32value; +s16 s16subrtnretval; + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); + + u32offset = (PRUSS_INTC_STATIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +s16 pru_can_mask_ints (struct device *dev,u32 int_mask) +{ +return 0 ; +} + +int pru_can_get_error_cnt (struct device *dev,u8 u8prunumber) +{ +return 0 ; +} + +int pru_can_get_intc_status (struct device *dev) +{ +u32 u32offset =0 ; +u32 u32getvalue =0 ; +u32 u32clrvalue =0 ; + + u32offset = (PRUSS_INTC_STATCLRINT1 &0xFFFF ); +pruss_readl (dev, u32offset, (u32 *) &u32getvalue,1 ); + +if (u32getvalue &4 ) + u32clrvalue =34 ;/* CLR Event 34 */ + +if (u32getvalue &2 ) + u32clrvalue =33 ;/* CLR Event 33 */ + +if (u32clrvalue) { + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); +pruss_writel (dev, u32offset, &u32clrvalue,1 ); + }else +return -1 ; + +return u32getvalue; +}drivers/net/can/da8xx_pruss/pruss_can_api.h new file +88
-0@@ -0,0 +1,290 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Ganeshan N +* +* 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. +*/ + +#ifndef _PRU_CAN_API_H_ +#define _PRU_CAN_API_H_ + +#include <linux/types.h> +#include <linux/mfd/pruss/da8xx_pru.h> + + +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000 + +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +#define CAN_RX_PRU_0 PRUSS_NUM0 +#define CAN_TX_PRU_1 PRUSS_NUM1 + +/* Number of Instruction in the Delay loop */ +#define DELAY_LOOP_LENGTH 2 + +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04) +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C) +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14) +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER (PRU1_BASE_ADDR + 0x18) +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER (PRU1_BASE_ADDR + 0x1C) +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER (PRU1_BASE_ADDR + 0x20) +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER (PRU1_BASE_ADDR + 0x24) +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER (PRU1_BASE_ADDR + 0x28) +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER (PRU1_BASE_ADDR + 0x2C) +#define PRU_CAN_TX_ERROR_COUNTER_REGISTER (PRU1_BASE_ADDR + 0x30) +#define PRU_CAN_TX_TIMING_REGISTER (PRU1_BASE_ADDR + 0x34) +#define PRU_CAN_TX_CLOCK_BRP_REGISTER (PRU1_BASE_ADDR + 0x38) + +#define PRU_CAN_TX_MAILBOX0 (PRU1_BASE_ADDR + 0x40) +#define PRU_CAN_TX_MAILBOX1 (PRU1_BASE_ADDR + 0x50) +#define PRU_CAN_TX_MAILBOX2 (PRU1_BASE_ADDR + 0x60) +#define PRU_CAN_TX_MAILBOX3 (PRU1_BASE_ADDR + 0x70) +#define PRU_CAN_TX_MAILBOX4 (PRU1_BASE_ADDR + 0x80) +#define PRU_CAN_TX_MAILBOX5 (PRU1_BASE_ADDR + 0x90) +#define PRU_CAN_TX_MAILBOX6 (PRU1_BASE_ADDR + 0xA0) +#define PRU_CAN_TX_MAILBOX7 (PRU1_BASE_ADDR + 0xB0) + +#define PRU_CAN_TIMING_VAL_TX (PRU1_BASE_ADDR + 0xC0) +#define PRU_CAN_TIMING_VAL_TX_SJW (PRU1_BASE_ADDR + 0xC4) +#define PRU_CAN_TRANSMIT_FRAME (PRU1_BASE_ADDR + 0xE0) + +#define PRU0_BASE_ADDR 0 + +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER (PRU0_BASE_ADDR) +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER (PRU0_BASE_ADDR + 0x04) +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER (PRU0_BASE_ADDR + 0x08) +#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER (PRU0_BASE_ADDR + 0x0C) +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER (PRU0_BASE_ADDR + 0x10) +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER (PRU0_BASE_ADDR + 0x14) +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER (PRU0_BASE_ADDR + 0x18) +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER (PRU0_BASE_ADDR + 0x1C) +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER (PRU0_BASE_ADDR + 0x20) +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER (PRU0_BASE_ADDR + 0x24) +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER (PRU0_BASE_ADDR + 0x28) +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER (PRU0_BASE_ADDR + 0x2C) +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER (PRU0_BASE_ADDR + 0x30) +#define PRU_CAN_RX_ERROR_COUNTER_REGISTER (PRU0_BASE_ADDR + 0x34) +#define PRU_CAN_RX_TIMING_REGISTER (PRU0_BASE_ADDR + 0x38) +#define PRU_CAN_RX_CLOCK_BRP_REGISTER (PRU0_BASE_ADDR + 0x3C) + +#define PRU_CAN_RX_MAILBOX0 (PRU0_BASE_ADDR + 0x40) +#define PRU_CAN_RX_MAILBOX1 (PRU0_BASE_ADDR + 0x50) +#define PRU_CAN_RX_MAILBOX2 (PRU0_BASE_ADDR + 0x60)
drivers/net/can/da8xx_pruss/pruss_can_api.h line 98
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+#define PRU_CAN_RX_MAILBOX3 (PRU0_BASE_ADDR + 0x70) +#define PRU_CAN_RX_MAILBOX4 (PRU0_BASE_ADDR + 0x80) +#define PRU_CAN_RX_MAILBOX5 (PRU0_BASE_ADDR + 0x90) +#define PRU_CAN_RX_MAILBOX6 (PRU0_BASE_ADDR + 0xA0) +#define PRU_CAN_RX_MAILBOX7 (PRU0_BASE_ADDR + 0xB0) +#define PRU_CAN_RX_MAILBOX8 (PRU0_BASE_ADDR + 0xC0) + +#define PRU_CAN_TIMING_VAL_RX (PRU0_BASE_ADDR + 0xD0) +#define PRU_CAN_RECEIVE_FRAME (PRU0_BASE_ADDR + 0xD4) +#define PRU_CAN_ID_MAP (PRU0_BASE_ADDR + 0xF0)
Please consider using a struct to define the register layout. This would make you code much much more readable and compact:
writel(®s->brp_register, bitrateprescaler);
instead of:
u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER); pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
Quoted 76 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +76
-0+#define PRU_CAN_ERROR_ACTIVE 128 + +#define CAN_ACK_FAILED 0xE +#define CAN_ARBTR_FAIL 0xD +#define CAN_BIT_ERROR 0xC +#define CAN_TRANSMISSION_SUCCESS 0xA + +#define STD_DATA_FRAME 0x1 +#define EXTD_DATA_FRAME 0x2 +#define STD_REMOTE_FRAME 0x3 +#define EXTD_REMOTE_FRAME 0x4 + +#define PRU_CAN_MAX_SJW 8 +#define PRU_CAN_MAX_PHSEG1 25 +#define PRU_CAN_MAX_PHSEG2 25 + +#define DA8XX_PRUCANCORE_0_REGS 0x7000 +#define DA8XX_PRUCANCORE_1_REGS 0x7800 +#define PRU0_PROG_RAM_START_OFFSET 0x8000 +#define PRU1_PROG_RAM_START_OFFSET 0xC000 +#define PRU_CAN_INIT_MAX_TIMEOUT 0xFF + +typedef enum { + ecaninst0 =0 , + ecaninst1, + ecanmaxinst +}can_instance_enum ; + +typedef enum { + ecanmailbox0 =0 , + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4, + ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +}can_mailbox_number ; + +typedef enum { + ecandirectioninit =0 , + ecantransmit, + ecanreceive +}can_transfer_direction ; + +typedef struct { +u16 u16extendedidentifier; +u16 u16baseidentifier; +u8 u8data7; +u8 u8data6; +u8 u8data5; +u8 u8data4; +u8 u8data3; +u8 u8data2; +u8 u8data1; +u8 u8data0; +u16 u16datalength; +u16 u16crc; +}can_mail_box_structure ; + +typedef struct { +can_transfer_direction ecantransferdirection; +}can_mailbox_config ; + +typedef struct { +can_instance_enum ecaninstance; +can_transfer_direction ecantransferdirection; +can_mail_box_structure strcanmailbox; +can_mailbox_number ecanmailboxnumber; +u8 u8prunumber; +u32 u32globalstatus; +u32 u32interruptstatus; +u32 u32mailboxstatus; +}can_emu_app_hndl ; + +typedef struct {
drivers/net/can/da8xx_pruss/pruss_can_api.h line 185
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+bool bcaninststate; +can_transfer_direction ecantransferdirection; +u32 u32apphandlerptr; +} can_emu_drv_inst; + +typedef struct { +u8 u8syncjumpwidth; +u8 u8phseg1; +u8 u8phseg2; +}can_bit_timing_consts ;
Don't use typedef's!
Thanks.
Wolfgang.
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to a message not in the archiveQuoted 1 line · Subhasish Ghosh
This patch adds support for the CAN device emulated on PRUSS.
Is this a software CAN device running on the omap dsp? Nice :) My first impression is that this driver needs a lot of work, but we'll help you.
Being new to the OMAP world here are soo many names for the same thing, i.e. the CAN core and driver:
- da8cc
- pruss
- omap
- pru
These or combination of these are used all over the code. I'm preferring one common prefix. I like the PRU_ prefix for the defines and the pru_ for functions.
Please don't encode the variable type into their names (a.k.a. polish notation), e.g. it's "u8 data" not "u8 u8data", No typedefs, enums just like defines in uppercase.
Get rid of the of the extra layer in pruss_can_api.c.
More comments inline:
Quoted 46 lines
--- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/da8xx_pruss/Kconfig | 73 ++ drivers/net/can/da8xx_pruss/Makefile | 7 + drivers/net/can/da8xx_pruss/pruss_can.c | 758 +++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.h | 290 +++++++ 7 files changed, 2357 insertions(+), 0 deletions(-) create mode 100644 drivers/net/can/da8xx_pruss/Kconfig create mode 100644 drivers/net/can/da8xx_pruss/Makefile create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.hdrivers/net/can/Kconfig +1
-0@@ -112,6 +112,7 @@ config PCH_CAN This driver can access CAN bus. source "drivers/net/can/mscan/Kconfig" +source "drivers/net/can/da8xx_pruss/Kconfig" source "drivers/net/can/sja1000/Kconfig"drivers/net/can/Makefile +1
-0@@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += da8xx_pruss/ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.odrivers/net/can/da8xx_pruss/Kconfig new file +0
-0
drivers/net/can/da8xx_pruss/Kconfig line 2
Quoted 2 lines
drivers/net/can/da8xx_pruss/Kconfig new file +2
-0@@ -0,0 +1,73 @@ +# +# CAN Lite Kernel Configuration
^^^^^^^^^^^^^^^
what's can lite?
Quoted 61 lines
drivers/net/can/da8xx_pruss/Kconfig new file +61
-0+# +config CAN_TI_DA8XX_PRU + depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850 + tristate "PRU based CAN emulation for DA8XX" + ---help--- + Enable this to emulate a CAN controller on the PRU of DA8XX. + If not sure, mark N + +config DA8XX_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help---
drivers/net/can/da8xx_pruss/Kconfig line 73
Quoted 10 lines
drivers/net/can/da8xx_pruss/Kconfig new file +10
-0+ Enter the CANID for mailbox 6 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 + Default value is set to 0x123, change this as required.
This doesn't fit to the Socketcan abstraction of a CAN card. Please remove. After this "da8xx_pruss/Kconfig" just contains the CAN_TI_DA8XX_PRU symbol, which can be added directly to drivers/net/can/Kconfig. (With a perhaps a simpler kconfig symbol name.)
drivers/net/can/da8xx_pruss/Makefile line 5
Quoted 11 lines
drivers/net/can/da8xx_pruss/Makefile new file +5
-0@@ -0,0 +1,7 @@ +# +# Makefile for CAN Lite emulation +# +can_emu-objs := pruss_can.o \ + pruss_can_api.o
Do we need two c file? I haven't look at them, yet.
Quoted 8 lines
drivers/net/can/da8xx_pruss/Makefile new file +2
-0+ +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += can_emu.odrivers/net/can/da8xx_pruss/pruss_can.c new file +0
-0
drivers/net/can/da8xx_pruss/pruss_can.c line 8
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +8
-0@@ -0,0 +1,758 @@ +/* +* TI DA8XX PRU CAN Emulation device driver +* Author: subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org +* +* This driver supports TI's PRU CAN Emulation and the +* specs for the same is available at <http://www.ti.com> +* +* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
You'll probably do some work on the driver, so add a 2011, here :)
Quoted 19 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +19
-0+* +* 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/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h>
drivers/net/can/da8xx_pruss/pruss_can.c line 37
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+#include <linux/platform_device.h> +#include <linux/firmware.h> +#include <linux/clk.h> +#include <linux/types.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <mach/da8xx.h> +#include "pruss_can_api.h"
Do we need a separate header file?
drivers/net/can/da8xx_pruss/pruss_can.c line 44
Quoted 7 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+ +#define DRV_NAME "da8xx_pruss_can" +#define DRV_DESC "TI PRU CAN Controller Driver v0.1" +#define PRU_CAN_START 1 +#define PRU_CAN_STOP 0 +#define MB_MIN 0 +#define MB_MAX 7
please add the common PRU_ prefis to the MB_*, too.
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +9
-0+ +#define PRU_CANMID_IDE BIT(29)/* Extended frame format */ + +#define PRU_CAN_ISR_BIT_CCI BIT(15) +#define PRU_CAN_ISR_BIT_ESI BIT(14) +#define PRU_CAN_ISR_BIT_SRDI BIT(13) +#define PRU_CAN_ISR_BIT_RRI BIT(8) + +#define PRU_CAN_MBXSR_BIT_STATE BIT(7)
drivers/net/can/da8xx_pruss/pruss_can.c line 63
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+#define PRU_CAN_MBXSR_BIT_TC BIT(6) +#define PRU_CAN_MBXSR_BIT_ERR BIT(5) +#define PRU_CAN_MBXSR_BIT_OF BIT(0) + +#define PRU_CAN_GSR_BIT_TXM BIT(7) +#define PRU_CAN_GSR_BIT_RXM BIT(6) +#define PRU_CAN_GSR_BIT_CM BIT(5) +#define PRU_CAN_GSR_BIT_EPM BIT(4) +#define PRU_CAN_GSR_BIT_BFM BIT(3) +#define RTR_MBX_NO 8
We don't have special mailboxes for RTR, pleae remove.
add the PRU_ prefix here, too.
drivers/net/can/da8xx_pruss/pruss_can.c line 66
Quoted 3 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +3
-0+#define MAX_INIT_RETRIES 20 +#define L138_PRU_ARM_FREQ 312000 +#define DFLT_PRU_FREQ 156000000
Any change that you get these values from the a clock device? e.g.:
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/flexcan.c#L909
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/flexcan.c#L946
drivers/net/can/da8xx_pruss/pruss_can.c line 67
Quoted 1 line
drivers/net/can/da8xx_pruss/pruss_can.c new file +1
-0+#define DFLT_PRU_BITRATE 125000
Please remove, we don't have a default bitrate.
drivers/net/can/da8xx_pruss/pruss_can.c line 76
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +9
-0+ +#define CONFIG_DA8XX_PRU_CANID_MBX0 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX1 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX2 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX3 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX4 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX5 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX6 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX7 0x123
as alreadt said, we don't have default canids, please remove.
drivers/net/can/da8xx_pruss/pruss_can.c line 83
Quoted 7 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +7
-0+ +#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args) +#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)
please use pr_<level> and and friends, use pr_fmt to set a common prefix. Or even better use netdev_<level>.
drivers/net/can/da8xx_pruss/pruss_can.c line 93
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+ +/* +* omapl_pru can private data +*/ +struct omapl_pru_can_priv { +struct can_priv can; +struct workqueue_struct *pru_can_wQ; +struct work_struct rx_work; +struct net_device *ndev; +struct device *dev;/* pdev->dev */
nitpick: pointless comment :)
drivers/net/can/da8xx_pruss/pruss_can.c line 97
Quoted 4 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +4
-0+struct clk *clk_timer; +u32 timer_freq; +can_emu_app_hndl can_tx_hndl; +can_emu_app_hndl can_rx_hndl;
please no new typedefs.
drivers/net/can/da8xx_pruss/pruss_can.c line 105
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +8
-0+const struct firmware *fw_rx; +const struct firmware *fw_tx; +spinlock_t mbox_lock; +u32 trx_irq; +u32 tx_head; +u32 tx_tail; +u32 tx_next; +u32 rx_next;
If these don't reflect register values, just use "unsigned int"s here.
drivers/net/can/da8xx_pruss/pruss_can.c line 109
Quoted 4 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +4
-0+}; + +static int omapl_pru_can_get_state (const struct net_device *ndev, +enum can_state *state)
just for consistency most other can drivers use "struct net_device *dev".
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +6
-0+{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + *state = priv->can.state; +return 0 ; +} +
drivers/net/can/da8xx_pruss/pruss_can.c line 125
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +10
-0+static int omapl_pru_can_set_bittiming (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_bittiming *bt = &priv->can.bittiming; +long bit_error =0 ; + +if (priv->can.ctrlmode &CAN_CTRLMODE_3_SAMPLES ) { +dev_warn (priv->dev,"WARN: Triple" +"sampling not set due to h/w limitations" ); + }
No need to check this, just set the modes you support in "priv->can.ctrlmode_supported".
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L1091
drivers/net/can/da8xx_pruss/pruss_can.c line 127
Quoted 2 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +2
-0+if (pru_can_calc_timing (priv->dev, priv->can.clock.freq, + bt->bitrate) !=0 )
The above function does _set_ the bit timing into the hardware, calling it "can_calc_timing" is a bit misleading.
Don't calculate the bit timing yoursef. Please define your bittiming_const and set it, see:
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L173
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L1088
Quoted 1,885 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +631
-0+return -EINVAL ; + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000 ) / bt->bitrate; +if (bit_error) { + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) *1000000 ) / bt->bitrate; +printk (KERN_INFO "\nBitrate error %ld.%ld%%\n" , + bit_error /10000 , bit_error %1000 ); + }else +printk (KERN_INFO "\nBitrate error 0.0%%\n" ); + +return 0 ; +} + +static void omapl_pru_can_stop (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u16 int_mask =0 ; + +pru_can_mask_ints (priv->dev, int_mask);/* mask all ints */ +pru_can_start_abort_tx (priv->dev,PRU_CAN_STOP ); + priv->can.state =CAN_STATE_STOPPED ; +} + +/* +* This is to just set the can state to ERROR_ACTIVE +* ip link set canX up type can bitrate 125000 +*/ +static void omapl_pru_can_start (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u16 int_mask =0xFFFF ; + +if (priv->can.state !=CAN_STATE_STOPPED ) +omapl_pru_can_stop (ndev); + +pru_can_mask_ints (priv->dev, int_mask);/* unmask all ints */ + +pru_can_get_global_status (priv->dev, &priv->can_tx_hndl); +pru_can_get_global_status (priv->dev, &priv->can_rx_hndl); + +if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus) + priv->can.state =CAN_STATE_ERROR_PASSIVE ; +else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus) + priv->can.state =CAN_STATE_BUS_OFF ; +else + priv->can.state =CAN_STATE_ERROR_ACTIVE ; +} + +static int omapl_pru_can_set_mode (struct net_device *ndev,enum can_mode mode) +{ +int ret =0 ; + +switch (mode) { +case CAN_MODE_START : +omapl_pru_can_start (ndev); +if (netif_queue_stopped (ndev)) +netif_wake_queue (ndev); +break ; +case CAN_MODE_STOP : +omapl_pru_can_stop (ndev); +if (!netif_queue_stopped (ndev)) +netif_stop_queue (ndev); +break ; +default : + ret = -EOPNOTSUPP ; +break ; + } +return ret; +} + +static netdev_tx_t omapl_pru_can_start_xmit (struct sk_buff *skb, +struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct can_frame *cf = (struct can_frame *)skb->data; +int count; +u8 *data = cf->data; +u8 dlc = cf->can_dlc; +u8 *ptr8data =NULL ; + +netif_stop_queue (ndev); +if (cf->can_id &CAN_EFF_FLAG )/* Extended frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_EFF_MASK ) |PRU_CANMID_IDE ; +else /* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id &CAN_SFF_MASK ) <<18 ; + +if (cf->can_id &CAN_RTR_FLAG )/* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |=CAN_RTR_FLAG ; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc -1 ); +for (count =0 ; count < (u8 ) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32 ) dlc; +/* +* search for the next available mbx +* if the next mbx is busy, then try the next + 1 +* do this until the head is reached. +* if still unable to tx, stop accepting any packets +* if able to tx and the head is reached, then reset next to tail, i.e mbx0 +* if head is not reached, then just point to the next mbx +*/ +for (; priv->tx_next <= priv->tx_head; priv->tx_next++) { + priv->can_tx_hndl.ecanmailboxnumber = + (can_mailbox_number ) priv->tx_next; +if (-1 ==pru_can_write_data_to_mailbox (priv->dev, + &priv->can_tx_hndl)) { +if (priv->tx_next == priv->tx_head) { + priv->tx_next = priv->tx_tail; +if (!netif_queue_stopped (ndev)) +netif_stop_queue (ndev);/* IF stalled */ +dev_err (priv->dev, +"%s: no tx mbx available" , __func__); +return NETDEV_TX_BUSY ; + }else +continue ; + }else { +/* set transmit request */ +pru_can_tx (priv->dev, priv->tx_next,CAN_TX_PRU_1 ); +pru_can_tx_mode_set (priv->dev, false, ecanreceive); +pru_can_tx_mode_set (priv->dev, true, ecantransmit); +pru_can_start_abort_tx (priv->dev,PRU_CAN_START ); + priv->tx_next++; +can_put_echo_skb (skb, ndev,0 ); +break ; + } + } +if (priv->tx_next > priv->tx_head) { + priv->tx_next = priv->tx_tail; + } +return NETDEV_TX_OK ; +} + +static int omapl_pru_can_rx (struct net_device *ndev,u32 mbxno) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct net_device_stats *stats = &ndev->stats; +struct can_frame *cf; +struct sk_buff *skb; +u32 pru_can_mbx_data; +u8 *data =NULL ; +u8 *ptr8data =NULL ; +int count =0 ; + + skb =alloc_can_skb (ndev, &cf); +if (!skb) { +if (printk_ratelimit ()) +dev_err (priv->dev, +"alloc_can_skb() failed\n" ); +return -ENOMEM ; + } + data = cf->data; +/* get payload */ + priv->can_rx_hndl.ecanmailboxnumber = (can_mailbox_number ) mbxno; +if (pru_can_get_data_from_mailbox (priv->dev, &priv->can_rx_hndl)) { +__can_err ("failed to get data from mailbox\n" ); +return -EAGAIN ; + } +/* give ownweship to pru */ +pru_can_tx (priv->dev, mbxno,CAN_RX_PRU_0 ); + +/* get data length code */ + cf->can_dlc = +get_can_dlc (* + ((u32 *) &priv->can_rx_hndl.strcanmailbox. + u16datalength) &0xF ); +if (cf->can_dlc <=4 ) { + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data3 + (4 - + cf->can_dlc); +for (count =0 ; count < cf->can_dlc; count++) { + *data++ = *ptr8data++; + } + }else { + ptr8data = &priv->can_rx_hndl.strcanmailbox.u8data3; +for (count =0 ; count <4 ; count++) { + *data++ = *ptr8data++; + } + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data4 - (cf->can_dlc - +5 ); +for (count =0 ; count < cf->can_dlc -4 ; count++) { + *data++ = *ptr8data++; + } + } + + pru_can_mbx_data = *((u32 *) &priv->can_rx_hndl.strcanmailbox); +/* get id extended or std */ +if (pru_can_mbx_data &PRU_CANMID_IDE ) + cf->can_id = (pru_can_mbx_data &CAN_EFF_MASK ) |CAN_EFF_FLAG ; +else + cf->can_id = (pru_can_mbx_data >>18 ) &CAN_SFF_MASK ; + +if (pru_can_mbx_data &CAN_RTR_FLAG ) + cf->can_id |=CAN_RTR_FLAG ; + +netif_rx_ni (skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +return 0 ; +} + +static int omapl_pru_can_err (struct net_device *ndev,int int_status, +int err_status) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct net_device_stats *stats = &ndev->stats; +struct can_frame *cf; +struct sk_buff *skb; +int tx_err_cnt, rx_err_cnt; + +/* propogate the error condition to the can stack */ + skb =alloc_can_err_skb (ndev, &cf); +if (!skb) { +if (printk_ratelimit ()) +dev_err (priv->dev, +"alloc_can_err_skb() failed\n" ); +return -ENOMEM ; + } + +if (err_status &PRU_CAN_GSR_BIT_EPM ) {/* error passive int */ + priv->can.state =CAN_STATE_ERROR_PASSIVE ; + ++priv->can.can_stats.error_passive; + cf->can_id |=CAN_ERR_CRTL ; + tx_err_cnt =pru_can_get_error_cnt (priv->dev,CAN_TX_PRU_1 ); + rx_err_cnt =pru_can_get_error_cnt (priv->dev,CAN_RX_PRU_0 ); +if (tx_err_cnt >127 ) + cf->data[1 ] |=CAN_ERR_CRTL_TX_PASSIVE ; +if (rx_err_cnt >127 ) + cf->data[1 ] |=CAN_ERR_CRTL_RX_PASSIVE ; + +dev_dbg (priv->ndev->dev.parent,"Error passive interrupt\n" ); + } + +if (err_status &PRU_CAN_GSR_BIT_BFM ) { + priv->can.state =CAN_STATE_BUS_OFF ; + cf->can_id |=CAN_ERR_BUSOFF ; +/* +* Disable all interrupts in bus-off to avoid int hog +* this should be handled by the pru +*/ +pru_can_mask_ints (priv->dev,0xFFFF ); +can_bus_off (ndev); +dev_dbg (priv->ndev->dev.parent,"Bus off mode\n" ); + } + +netif_rx (skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +return 0 ; +} + +void omapl_pru_can_rx_wQ (struct work_struct *work) +{ +struct omapl_pru_can_priv *priv =container_of (work, + struct omapl_pru_can_priv, rx_work); +struct net_device *ndev = priv->ndev; +u32 bit_set, mbxno =0 ; + +if (-1 ==pru_can_get_intr_status (priv->dev, &priv->can_rx_hndl)) +return ; + +if (PRU_CAN_ISR_BIT_RRI & priv->can_rx_hndl.u32interruptstatus) { + mbxno =RTR_MBX_NO ; +omapl_pru_can_rx (ndev, mbxno); + }else { +/* Extract the mboxno from the status */ +for (bit_set =0 ; ((priv->can_rx_hndl.u32interruptstatus &0xFF ) + >> bit_set !=0 ); bit_set++) + ; +if (0 == bit_set) { +dev_err (priv->dev, +"%s: invalid mailbox number: %X\n" , __func__, + priv->can_rx_hndl.u32interruptstatus); + }else { + mbxno = bit_set -1 ; +if (PRU_CAN_ISR_BIT_ESI & priv->can_rx_hndl. + u32interruptstatus) { +pru_can_get_global_status (priv->dev, + &priv->can_rx_hndl); +omapl_pru_can_err (ndev, + priv->can_rx_hndl.u32interruptstatus, + priv->can_rx_hndl.u32globalstatus); + }else { +omapl_pru_can_rx (ndev, mbxno); + } + } + } +} + +irqreturn_t omapl_tx_can_intr (int irq,void *dev_id) +{ +struct net_device *ndev = dev_id; +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +struct net_device_stats *stats = &ndev->stats; +u32 bit_set, mbxno; + +pru_can_get_intr_status (priv->dev, &priv->can_tx_hndl); +if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus) + || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) { +__can_debug ("tx_int_status = 0x%X\n" , + priv->can_tx_hndl.u32interruptstatus); +can_free_echo_skb (ndev,0 ); + }else { +for (bit_set =0 ; ((priv->can_tx_hndl.u32interruptstatus &0xFF ) + >> bit_set !=0 ); bit_set++) + ; +if (0 == bit_set) { +__can_err ("%s: invalid mailbox number\n" , __func__); +can_free_echo_skb (ndev,0 ); + }else { + mbxno = bit_set -1 ;/* mail box numbering starts from 0 */ +if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl. + u32interruptstatus) { +/* read gsr and ack pru */ +pru_can_get_global_status (priv->dev, &priv->can_tx_hndl); +omapl_pru_can_err (ndev, + priv->can_tx_hndl. + u32interruptstatus, + priv->can_tx_hndl. + u32globalstatus); + }else { + stats->tx_packets++; +/* stats->tx_bytes += dlc; */ +/*can_get_echo_skb(ndev, 0);*/ + } + } + } +if (netif_queue_stopped (ndev)) +netif_wake_queue (ndev); + +can_get_echo_skb (ndev,0 ); +pru_can_tx_mode_set (priv->dev, true, ecanreceive); +return IRQ_HANDLED ; +} + +irqreturn_t omapl_rx_can_intr (int irq,void *dev_id) +{ + +struct net_device *ndev = dev_id; +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +u32 intc_status =0 ; + + intc_status =pru_can_get_intc_status (priv->dev); +if (intc_status &4 ) +return omapl_tx_can_intr (irq, dev_id); +if (intc_status &2 ) { +if (!work_pending (&priv->rx_work)) +queue_work (priv->pru_can_wQ, &priv->rx_work); + } + +return IRQ_HANDLED ; +} + +static int omapl_pru_can_open (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); +int err; + +/* register interrupt handler */ + err =request_irq (priv->trx_irq, &omapl_rx_can_intr,IRQF_SHARED , +"pru_can_irq" , ndev); +if (err) { +dev_err (priv->dev,"error requesting rx interrupt\n" ); + goto exit_trx_irq; + } +/* common open */ + err =open_candev (ndev); +if (err) { +dev_err (priv->dev,"open_candev() failed %d\n" , err); + goto exit_open; + } + +pru_can_emu_init (priv->dev, priv->can.clock.freq); + priv->tx_tail =MB_MIN ; + priv->tx_head =MB_MAX ; + +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX0 ,0 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX1 ,1 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX2 ,2 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX3 ,3 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX4 ,4 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX5 ,5 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX6 ,6 ); +pru_can_rx_id_map (priv->dev,CONFIG_DA8XX_PRU_CANID_MBX7 ,7 ); + +omapl_pru_can_start (ndev); +netif_start_queue (ndev); +return 0 ; + +exit_open: +free_irq (priv->trx_irq, ndev); +exit_trx_irq: +return err; +} + +static int omapl_pru_can_close (struct net_device *ndev) +{ +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +if (!netif_queue_stopped (ndev)) +netif_stop_queue (ndev); + +close_candev (ndev); + +free_irq (priv->trx_irq, ndev); +return 0 ; +} + +static const struct net_device_ops omapl_pru_can_netdev_ops = { + .ndo_open = omapl_pru_can_open, + .ndo_stop = omapl_pru_can_close, + .ndo_start_xmit = omapl_pru_can_start_xmit, +}; + +static int __devinit omapl_pru_can_probe (struct platform_device *pdev) +{ +struct net_device *ndev =NULL ; +const struct da8xx_pru_can_data *pdata; +struct omapl_pru_can_priv *priv =NULL ; +struct device *dev = &pdev->dev; +u32 err; + + pdata = dev->platform_data; +if (!pdata) { +dev_err (&pdev->dev,"platform data not found\n" ); +return -EINVAL ; + } + + ndev =alloc_candev (sizeof (struct omapl_pru_can_priv ),MB_MAX +1 ); +if (!ndev) { +dev_err (&pdev->dev,"alloc_candev failed\n" ); + err = -ENOMEM ; + goto probe_exit; + } + priv =netdev_priv (ndev); + + priv->trx_irq =platform_get_irq (to_platform_device (dev->parent),0 ); +if (!priv->trx_irq) { +dev_err (&pdev->dev,"unable to get pru interrupt resources!\n" ); + err = -ENODEV ; + goto probe_exit; + } + + priv->ndev = ndev; + priv->dev = dev;/* priv->dev = pdev->dev */ + + priv->can.bittiming_const =NULL ; + priv->can.do_set_bittiming = omapl_pru_can_set_bittiming; + priv->can.do_set_mode = omapl_pru_can_set_mode; + priv->can.do_get_state = omapl_pru_can_get_state; + priv->can_tx_hndl.u8prunumber =CAN_TX_PRU_1 ; + priv->can_rx_hndl.u8prunumber =CAN_RX_PRU_0 ; + +/* we support local echo, no arp */ + ndev->flags |= (IFF_ECHO |IFF_NOARP ); + +/* pdev->dev->device_private->driver_data = ndev */ +platform_set_drvdata (pdev, ndev); +SET_NETDEV_DEV (ndev, &pdev->dev); + ndev->netdev_ops = &omapl_pru_can_netdev_ops; + + priv->can.clock.freq =pruss_get_clk_freq (priv->dev); + + priv->clk_timer =clk_get (&pdev->dev,"pll1_sysclk2" ); +if (IS_ERR (priv->clk_timer)) { +dev_err (&pdev->dev,"no timer clock available\n" ); + err =PTR_ERR (priv->clk_timer); + priv->clk_timer =NULL ; + goto probe_exit_candev; + } + priv->timer_freq =clk_get_rate (priv->clk_timer); + + err =register_candev (ndev); +if (err) { +dev_err (&pdev->dev,"register_candev() failed\n" ); + err = -ENODEV ; + goto probe_exit_clk; + } + + err =request_firmware (&priv->fw_tx,"PRU_CAN_Emulation_Tx.bin" , + &pdev->dev); +if (err) { +dev_err (&pdev->dev,"can't load firmware\n" ); + err = -ENODEV ; + goto probe_exit_clk; + } + +dev_info (&pdev->dev,"fw_tx size %d. downloading...\n" , + priv->fw_tx->size); + + err =request_firmware (&priv->fw_rx,"PRU_CAN_Emulation_Rx.bin" , + &pdev->dev); +if (err) { +dev_err (&pdev->dev,"can't load firmware\n" ); + err = -ENODEV ; + goto probe_release_fw; + } +dev_info (&pdev->dev,"fw_rx size %d. downloading...\n" , + priv->fw_rx->size); + +/* init the pru */ +pru_can_emu_init (priv->dev, priv->can.clock.freq); +udelay (200 ); + +pruss_enable (priv->dev,CAN_RX_PRU_0 ); +pruss_enable (priv->dev,CAN_TX_PRU_1 ); + +/* download firmware into pru */ + err =pruss_load (priv->dev,CAN_RX_PRU_0 , + (u32 *)priv->fw_rx->data, (priv->fw_rx->size /4 )); +if (err) { +dev_err (&pdev->dev,"firmware download error\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + err =pruss_load (priv->dev,CAN_TX_PRU_1 , + (u32 *)priv->fw_tx->data, (priv->fw_tx->size /4 )); +if (err) { +dev_err (&pdev->dev,"firmware download error\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + +if (pru_can_calc_timing (priv->dev,DFLT_PRU_FREQ , +DFLT_PRU_BITRATE ) !=0 ) +return -EINVAL ; + +pruss_run (priv->dev,CAN_RX_PRU_0 ); +pruss_run (priv->dev,CAN_TX_PRU_1 ); + +/*Create The Work Queue */ + priv->pru_can_wQ =create_freezeable_workqueue ("omapl_pru_wQ" ); +if (priv->pru_can_wQ ==NULL ) { +dev_err (&pdev->dev,"failed to create work queue\n" ); + err = -ENODEV ; + goto probe_release_fw_1; + } + +INIT_WORK (&priv->rx_work, omapl_pru_can_rx_wQ); +dev_info (&pdev->dev, +"%s device registered (trx_irq = %d, clk = %d)\n" , +DRV_NAME , priv->trx_irq, priv->can.clock.freq); + +return 0 ; + +probe_release_fw_1: +release_firmware (priv->fw_rx); +probe_release_fw: +release_firmware (priv->fw_tx); +probe_exit_clk: +clk_put (priv->clk_timer); +probe_exit_candev: +if (NULL != ndev) +free_candev (ndev); +probe_exit: +return err; +} + +static int __devexit omapl_pru_can_remove(struct platform_device *pdev) +{ +struct net_device *ndev =platform_get_drvdata (pdev); +struct omapl_pru_can_priv *priv =netdev_priv (ndev); + +omapl_pru_can_stop (ndev); + +pru_can_emu_exit (priv->dev); +release_firmware (priv->fw_tx); +release_firmware (priv->fw_rx); +clk_put (priv->clk_timer); +flush_workqueue (priv->pru_can_wQ); +destroy_workqueue (priv->pru_can_wQ); +unregister_candev (ndev); +free_candev (ndev); +platform_set_drvdata (pdev,NULL ); +return 0 ; +} + +#ifdef CONFIG_PM +static int omapl_pru_can_suspend (struct platform_device *pdev, +pm_message_t mesg) +{ +dev_info (&pdev->dev,"%s not yet implemented\n" , __func__); +return 0 ; +} + +static int omapl_pru_can_resume (struct platform_device *pdev) +{ +dev_info (&pdev->dev,"%s not yet implemented\n" , __func__); +return 0 ; +} +#else +#define omapl_pru_can_suspend NULL +#define omapl_pru_can_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver omapl_pru_can_driver = { + .probe = omapl_pru_can_probe, + .remove =__devexit_p (omapl_pru_can_remove), + .suspend = omapl_pru_can_suspend, + .resume = omapl_pru_can_resume, + .driver = { + .name =DRV_NAME , + .owner =THIS_MODULE , + }, +}; + +static int __init omapl_pru_can_init (void ) +{ + __can_debug(KERN_INFO DRV_DESC "\n"); + return platform_driver_register(&omapl_pru_can_driver); +} + +module_init (omapl_pru_can_init); + +static void __exit omapl_pru_can_exit(void) +{ + __can_debug(KERN_INFO DRV_DESC " unloaded\n"); +platform_driver_unregister (&omapl_pru_can_driver); +} + +module_exit (omapl_pru_can_exit); + +MODULE_AUTHOR ("Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>" ); +MODULE_LICENSE ("GPL" ); +MODULE_DESCRIPTION ("omapl pru CAN netdevice driver" );drivers/net/can/da8xx_pruss/pruss_can_api.c new file +1227
-0@@ -0,0 +1,1227 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Wilfred Felix +* +* 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 "pruss_can_api.h" + +static can_emu_drv_inst gstr_can_inst[ecanmaxinst]; + +/* +* pru_can_set_brp() Updates the BRP register of PRU0 +* and PRU1 of OMAP L138. This API will be called by the +* Application to updtae the BRP register of PRU0 and PRU1 +* +* param u16bitrateprescaler The can bus bitrate +* prescaler value be set +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_brp (struct device *dev,u16 u16bitrateprescaler) +{ + +u32 u32offset; + +if (u16bitrateprescaler >255 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 ); + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 ); + +return 0 ; + +} + +/* +* pru_can_set_bit_timing() Updates the timing register +* of PRU0 and PRU1 of OMAP L138. This API will be called by +* the Application to updtae the timing register of PRU0 and PRU1 +* +* param pstrbittiming Pointer to structure holding +* the bit timing values for can bus. +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_bit_timing (struct device *dev, +can_bit_timing_consts *pstrbittiming) +{ + +u32 u32offset; +u32 u32serregister; + + u32serregister =0 ; + +if (pstrbittiming ==NULL ) { +return -1 ; + } + +if ((pstrbittiming->u8syncjumpwidth >PRU_CAN_MAX_SJW ) || + (pstrbittiming->u8phseg1 >PRU_CAN_MAX_PHSEG1 ) || + (pstrbittiming->u8phseg2 >PRU_CAN_MAX_PHSEG2 )) { +return -1 ; + } + + u32serregister = u32serregister | + ((pstrbittiming->u8syncjumpwidth <<7 ) | + (pstrbittiming->u8phseg1 <<3 ) | + (pstrbittiming->u8phseg2)); + + u32offset = (PRU_CAN_TX_TIMING_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u32serregister,1 ); + + u32offset = (PRU_CAN_RX_TIMING_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u32serregister,1 ); + +return 0 ; +} + + +/* +* pru_can_calc_timing() +* Updates the timing values of PRU0 and PRU1 of OMAP L138. +* This API will be called by the +* Application to updtae the timing values of PRU0 and PRU1 +* +* return SUCCESS or FAILURE +*/ + +s16 pru_can_calc_timing (struct device *dev,u32 pru_freq,u32 bit_rate) +{ +u16 u16phaseseg1; +u16 u16phaseseg2; +u32 u32offset; +u32 u32timing_value; +u32 u32setup_value; + u32timing_value =TIMER_CLK_FREQ / bit_rate; + u32offset = (PRU_CAN_TIMING_VAL_TX ); +pruss_writel (dev, u32offset, (u32 *) &u32timing_value,4 ); +pruss_readl (dev, u32offset, (u32 *) &u32timing_value,4 ); + u32setup_value = + (GPIO_SETUP_DELAY * (pru_freq /1000000 ) /1000 ) / +DELAY_LOOP_LENGTH ; + u32offset = (PRU_CAN_TIMING_VAL_TX_SJW ); +pruss_writel (dev, u32offset, (u32 *) &u32setup_value,4 ); + u16phaseseg1 = (u16) (u32timing_value /2 ); + u16phaseseg2 = u32timing_value - u16phaseseg1; + u16phaseseg1 -=TIMER_SETUP_DELAY ; + u16phaseseg2 -=TIMER_SETUP_DELAY ; + u32setup_value = (u16phaseseg1 <<16 ) | u16phaseseg2; + u32offset = (PRU_CAN_TIMING_VAL_RX ); +pruss_writel (dev, u32offset, (u32 *) &u32setup_value,4 ); + u32offset = (PRU_CAN_TIMING_VAL_RX +4 ); +pruss_writel (dev, u32offset, (u32 *) &u32timing_value,4 ); + +return 0 ; +} + +/* +* pru_can_write_data_to_mailbox() +* Updates the transmit mailboxes of PRU1 of OMAP L138. +* This API will be called by the Application to update +* the transmit mailboxes of PRU1 +* +* param pu16canframedata Can mailbox data buffer +* +* param u8mailboxnum Mailbox to be updated +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_write_data_to_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +switch ((u8 ) pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0 ); +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1 ); +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2 ); +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3 ); +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4 ); +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5 ); +break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6 ); +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7 ); +break ; +default : +return -1 ; + } + + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox),4 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +/* +* pru_can_get_data_from_mailbox() +* Receive data from the receive mailboxes of PRU0 of OMAP L138. +* This API will be called by the Application to get data from +* the receive mailboxes of PRU0 +* +* param pu16canframedata Can mailbox data buffer +* +* param u8mailboxnum Mailbox to be updated +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_data_from_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +switch ((u8 ) pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0 ); +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1 ); +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2 ); +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3 ); +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4 ); +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5 ); +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6 ); +break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7 ); +break ; +case 8 : + u32offset = (PRU_CAN_RX_MAILBOX8 ); +break ; +default : +return -1 ; + } + + s16subrtnretval = +pruss_readl (dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox), +4 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +/* +* pru_can_receive_id_map() +* Receive mailboxes ID Mapping of PRU0 of OMAP L138. +* This API will be called by the Application +* to map the IDs to receive mailboxes of PRU0 +* +* param u32nodeid Can node ID +* +* param ecanmailboxno Mailbox to be mapped +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_rx_id_map (struct device *dev,u32 u32nodeid, +can_mailbox_number ecanmailboxno) +{ + +pruss_writel (dev, (PRU_CAN_ID_MAP + + (((u8 ) ecanmailboxno) *4 )), (u32 *) &u32nodeid,1 ); + +return 0 ; +} + +/* +* pru_can_get_intr_status() +* Gets the interrupts status register value. +* This API will be called by the Application +* to get the interrupts status register value +* +* param u8prunumber PRU number for which IntStatusReg +* has to be read +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_intr_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER ); + }else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER ); + }else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32interruptstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +/* +* pru_can_get_global_status() Gets the globalstatus +* register value. This API will be called by the Application +* to get the global status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_global_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +int s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); + }else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); + }else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32globalstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +/* +* pru_can_get_mailbox_status() Gets the mailbox status +* register value. This API will be called by the Application +* to get the mailbox status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_mailbox_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { +switch (pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER ); +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER ); +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER ); +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER ); +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER ); +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER ); +break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER ); +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER ); +break ; +default : +return -1 ; + } + } + +else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { +switch (pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER ); +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER ); +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER ); +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER ); +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER ); +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER ); +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER ); +break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER ); +break ; +case 8 : + u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER ); +break ; +default : +return -1 ; + } + } + +else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32mailboxstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +return 0 ; +} + +s16 pru_can_tx_mode_set (struct device *dev,bool btransfer_flag, +can_transfer_direction ecan_trx) +{ +u32 u32offset; +u32 u32value; + +if (ecan_trx == ecantransmit) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); +pruss_readl (dev, u32offset, &u32value,1 ); +if (btransfer_flag == true) { + u32value &=0x1F ; + u32value |=0x80 ; + }else { + u32value &=0x7F ; + } +pruss_writel (dev, u32offset, &u32value,1 ); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); +pruss_writel (dev, u32offset, &u32value,1 ); + }else if (ecan_trx == ecanreceive) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER ); +pruss_readl (dev, u32offset, &u32value,1 ); +if (btransfer_flag == true) { + u32value &=0x1F ; + u32value |=0x40 ; + }else { + u32value &=0xBF ; + } +pruss_writel (dev, u32offset, &u32value,1 ); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER ); +pruss_writel (dev, u32offset, &u32value,1 ); + }else +return -1 ; + +return 0 ; +} + +/* +* pru_can_config_mode_set() Sets the timing value +* for data transfer. This API will be called by the Application +* to set timing valus for data transfer +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_config_mode_set (struct device *dev,bool bconfigmodeflag) +{ + +u32 u32bitrateprescaler; +u32 u32canbittiming; + +pruss_readl (dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER ), + (u32 *) &u32bitrateprescaler,1 ); +pruss_readl (dev, (PRU_CAN_TX_TIMING_REGISTER ), + (u32 *) &u32canbittiming,1 ); + +if (bconfigmodeflag ==1 ) { +pru_can_calc_timing (dev, u32canbittiming, u32bitrateprescaler); + } + +else { +pru_can_calc_timing (dev,0 ,0 ); + } + +return 0 ; +} + +/* +* pru_can_emu_init() Initializes the Can +* Emulation Parameters. This API will be called by the Application +* to Initialize the Can Emulation Parameters +* +* param u32pruclock PRU Clock value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_init (struct device *dev,u32 u32pruclock) +{ +u32 u32offset; +u32 u32value; +s16 s16subrtnretval =-1 ; +u8 u8loop; + +for (u8loop =0 ; u8loop < (u8 ) ecanmaxinst; u8loop++) { + gstr_can_inst[u8loop].bcaninststate = (bool )0 ; + gstr_can_inst[u8loop].ecantransferdirection = + (can_transfer_direction )0 ; + gstr_can_inst[u8loop].u32apphandlerptr =0 ; + } + + u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER &0xFFFF ); + u32value =0x00004000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval = +pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000001 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_TIMING_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_POLARITY0 &0xFFFF ); + u32value =0xFFFFFFFF ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_POLARITY1 &0xFFFF ); + u32value =0xFFFFFFFF ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_TYPE0 &0xFFFF ); + u32value =0x1C000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_TYPE1 &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HSTINTENIDXCLR &0xFFFF ); + u32value =0x0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_GLBLEN &0xFFFF ); + u32value =0x1 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +/* tx intr map arm->pru */ + u32offset = (PRUSS_INTC_HSTINTENIDXSET &0xFFFF ); + u32value =0x0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP0 &0xFFFF ); + u32value =0x03020100 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP1 &0xFFFF ); + u32value =0x07060504 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTMAP2 &0xFFFF ); + u32value =0x0000908 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_CHANMAP0 &0xFFFF ); + u32value =0 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_CHANMAP8 &0xFFFF ); + u32value =0x00020200 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =19 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =19 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =18 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =18 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =34 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =34 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRUSS_INTC_HOSTINTEN &0xFFFF ); + u32value =0x5 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +/* PRU0 - Rx Internal Registers Initializations */ + + u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER &0xFFFF ); + u32value =0x00004000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x0000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_TIMING_REGISTER &0xFFFF ); + u32value =0x0000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + + +/* +* pru_can_emu_open() Opens the can emu for +* application to use. This API will be called by the Application +* to Open the can emu for application to use. +* +* param pstremuapphndl Pointer to application handler +* structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_open (struct device *dev,can_emu_app_hndl *pstremuapphndl) +{ + +if (pstremuapphndl ==NULL ) { +return -1 ; + } + +if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate ==1 ) { +return -1 ; + } + + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance]. + bcaninststate = (bool )1 ; + gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].ecantransferdirection = + (can_transfer_direction )(u8 )pstremuapphndl->ecantransferdirection; + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance]. + u32apphandlerptr = (u32 ) pstremuapphndl; + +return 0 ; +} + + +/* +* brief pru_can_emu_close() Closes the can emu for other +* applications to use. This API will be called by the Application to Close +* the can emu for other applications to use +* +* param pstremuapphndl Pointer to application handler structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_close (struct device *dev,can_emu_app_hndl *pstremuapphndl) +{ + +if (pstremuapphndl ==NULL ) { +return -1 ; + } +if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate ==0 ) { +return -1 ; + } +if ((u32 ) pstremuapphndl != gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].u32apphandlerptr){ +return -1 ; + } + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance].bcaninststate + = (bool )0 ; + gstr_can_inst[(u8 ) pstremuapphndl-> + ecaninstance].ecantransferdirection = (can_transfer_direction )0 ; + gstr_can_inst[(u8 ) pstremuapphndl->ecaninstance].u32apphandlerptr =0 ; + +return 0 ; +} + +/* +* brief pru_can_emu_exit() Diables all the PRUs +* This API will be called by the Application to disable all PRUs +* param None +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_exit (struct device *dev) +{ +s16 s16subrtnretval; + + s16subrtnretval =pruss_disable (dev,CAN_RX_PRU_0 ); +if (s16subrtnretval ==-1 ) +return -1 ; + s16subrtnretval =pruss_disable (dev,CAN_TX_PRU_1 ); +if (s16subrtnretval ==-1 ) +return -1 ; + +return 0 ; +} + +s16 pru_can_emu_sreset (struct device *dev) +{ +return 0 ; +} + +s16 pru_can_tx (struct device *dev,u8 u8mailboxnumber,u8 u8prunumber) +{ +u32 u32offset =0 ; +u32 u32value =0 ; +s16 s16subrtnretval =-1 ; + +if (DA8XX_PRUCORE_1 == u8prunumber) { +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +default : +return -1 ; + } + }else { + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32value = u32value & ~(1 << u8mailboxnumber); + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 : + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 2 : + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 3 : + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 4 : + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 5 : + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 6 : + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 7 : + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +default : +return -1 ; + } + } +return 0 ; +} + +s16 pru_can_start_abort_tx (struct device *dev,bool bcantransmitabortflag) +{ +u32 u32offset; +u32 u32value; +s16 s16subrtnretval; + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); + + u32offset = (PRUSS_INTC_ENIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); + + u32offset = (PRUSS_INTC_STATIDXSET &0xFFFF ); + u32value =32 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +} + +s16 pru_can_mask_ints (struct device *dev,u32 int_mask) +{ +return 0 ; +} + +int pru_can_get_error_cnt (struct device *dev,u8 u8prunumber) +{ +return 0 ; +} + +int pru_can_get_intc_status (struct device *dev) +{ +u32 u32offset =0 ; +u32 u32getvalue =0 ; +u32 u32clrvalue =0 ; + + u32offset = (PRUSS_INTC_STATCLRINT1 &0xFFFF ); +pruss_readl (dev, u32offset, (u32 *) &u32getvalue,1 ); + +if (u32getvalue &4 ) + u32clrvalue =34 ;/* CLR Event 34 */ + +if (u32getvalue &2 ) + u32clrvalue =33 ;/* CLR Event 33 */ + +if (u32clrvalue) { + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); +pruss_writel (dev, u32offset, &u32clrvalue,1 ); + }else +return -1 ; + +return u32getvalue; +}drivers/net/can/da8xx_pruss/pruss_can_api.h new file +15
-0@@ -0,0 +1,290 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Ganeshan N +* +* 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. +*/ + +#ifndef _PRU_CAN_API_H_
drivers/net/can/da8xx_pruss/pruss_can_api.h line 25
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+#define _PRU_CAN_API_H_ + +#include <linux/types.h> +#include <linux/mfd/pruss/da8xx_pru.h> + + +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000
any change to get this from a clk_dev?
drivers/net/can/da8xx_pruss/pruss_can_api.h line 34
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +9
-0+ +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +#define CAN_RX_PRU_0 PRUSS_NUM0 +#define CAN_TX_PRU_1 PRUSS_NUM1 + +/* Number of Instruction in the Delay loop */ +#define DELAY_LOOP_LENGTH 2
please create a struct describing your register layout.
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +5
-0+ +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04)
drivers/net/can/da8xx_pruss/pruss_can_api.h line 49
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C) +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14) +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER (PRU1_BASE_ADDR + 0x18) +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER (PRU1_BASE_ADDR + 0x1C) +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER (PRU1_BASE_ADDR + 0x20) +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER (PRU1_BASE_ADDR + 0x24) +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER (PRU1_BASE_ADDR + 0x28) +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER (PRU1_BASE_ADDR + 0x2C)
please use an array for the mailbox status register.
drivers/net/can/da8xx_pruss/pruss_can_api.h line 61
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +12
-0+#define PRU_CAN_TX_ERROR_COUNTER_REGISTER (PRU1_BASE_ADDR + 0x30) +#define PRU_CAN_TX_TIMING_REGISTER (PRU1_BASE_ADDR + 0x34) +#define PRU_CAN_TX_CLOCK_BRP_REGISTER (PRU1_BASE_ADDR + 0x38) + +#define PRU_CAN_TX_MAILBOX0 (PRU1_BASE_ADDR + 0x40) +#define PRU_CAN_TX_MAILBOX1 (PRU1_BASE_ADDR + 0x50) +#define PRU_CAN_TX_MAILBOX2 (PRU1_BASE_ADDR + 0x60) +#define PRU_CAN_TX_MAILBOX3 (PRU1_BASE_ADDR + 0x70) +#define PRU_CAN_TX_MAILBOX4 (PRU1_BASE_ADDR + 0x80) +#define PRU_CAN_TX_MAILBOX5 (PRU1_BASE_ADDR + 0x90) +#define PRU_CAN_TX_MAILBOX6 (PRU1_BASE_ADDR + 0xA0) +#define PRU_CAN_TX_MAILBOX7 (PRU1_BASE_ADDR + 0xB0)
also use an array here
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+ +#define PRU_CAN_TIMING_VAL_TX (PRU1_BASE_ADDR + 0xC0) +#define PRU_CAN_TIMING_VAL_TX_SJW (PRU1_BASE_ADDR + 0xC4) +#define PRU_CAN_TRANSMIT_FRAME (PRU1_BASE_ADDR + 0xE0) + +#define PRU0_BASE_ADDR 0 + +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER (PRU0_BASE_ADDR) +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER (PRU0_BASE_ADDR + 0x04) +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER (PRU0_BASE_ADDR + 0x08)
drivers/net/can/da8xx_pruss/pruss_can_api.h line 81
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER (PRU0_BASE_ADDR + 0x0C) +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER (PRU0_BASE_ADDR + 0x10) +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER (PRU0_BASE_ADDR + 0x14) +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER (PRU0_BASE_ADDR + 0x18) +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER (PRU0_BASE_ADDR + 0x1C) +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER (PRU0_BASE_ADDR + 0x20) +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER (PRU0_BASE_ADDR + 0x24) +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER (PRU0_BASE_ADDR + 0x28) +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER (PRU0_BASE_ADDR + 0x2C) +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER (PRU0_BASE_ADDR + 0x30)
...array
drivers/net/can/da8xx_pruss/pruss_can_api.h line 94
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +13
-0+#define PRU_CAN_RX_ERROR_COUNTER_REGISTER (PRU0_BASE_ADDR + 0x34) +#define PRU_CAN_RX_TIMING_REGISTER (PRU0_BASE_ADDR + 0x38) +#define PRU_CAN_RX_CLOCK_BRP_REGISTER (PRU0_BASE_ADDR + 0x3C) + +#define PRU_CAN_RX_MAILBOX0 (PRU0_BASE_ADDR + 0x40) +#define PRU_CAN_RX_MAILBOX1 (PRU0_BASE_ADDR + 0x50) +#define PRU_CAN_RX_MAILBOX2 (PRU0_BASE_ADDR + 0x60) +#define PRU_CAN_RX_MAILBOX3 (PRU0_BASE_ADDR + 0x70) +#define PRU_CAN_RX_MAILBOX4 (PRU0_BASE_ADDR + 0x80) +#define PRU_CAN_RX_MAILBOX5 (PRU0_BASE_ADDR + 0x90) +#define PRU_CAN_RX_MAILBOX6 (PRU0_BASE_ADDR + 0xA0) +#define PRU_CAN_RX_MAILBOX7 (PRU0_BASE_ADDR + 0xB0) +#define PRU_CAN_RX_MAILBOX8 (PRU0_BASE_ADDR + 0xC0)
..array
The rx and tx register set look quite similar. Is it intended that you have 8 tx but 9 rx mailboxes? Anyway....make a struct descriing the register set and use it twice, one for rx and one for tx.
Quoted 22 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +22
-0+ +#define PRU_CAN_TIMING_VAL_RX (PRU0_BASE_ADDR + 0xD0) +#define PRU_CAN_RECEIVE_FRAME (PRU0_BASE_ADDR + 0xD4) +#define PRU_CAN_ID_MAP (PRU0_BASE_ADDR + 0xF0) + +#define PRU_CAN_ERROR_ACTIVE 128 + +#define CAN_ACK_FAILED 0xE +#define CAN_ARBTR_FAIL 0xD +#define CAN_BIT_ERROR 0xC +#define CAN_TRANSMISSION_SUCCESS 0xA + +#define STD_DATA_FRAME 0x1 +#define EXTD_DATA_FRAME 0x2 +#define STD_REMOTE_FRAME 0x3 +#define EXTD_REMOTE_FRAME 0x4 + +#define PRU_CAN_MAX_SJW 8 +#define PRU_CAN_MAX_PHSEG1 25 +#define PRU_CAN_MAX_PHSEG2 25 + +#define DA8XX_PRUCANCORE_0_REGS 0x7000
drivers/net/can/da8xx_pruss/pruss_can_api.h line 126
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+#define DA8XX_PRUCANCORE_1_REGS 0x7800 +#define PRU0_PROG_RAM_START_OFFSET 0x8000 +#define PRU1_PROG_RAM_START_OFFSET 0xC000 +#define PRU_CAN_INIT_MAX_TIMEOUT 0xFF + +typedef enum { + ecaninst0 =0 , + ecaninst1, + ecanmaxinst +}can_instance_enum ;
seens unused
drivers/net/can/da8xx_pruss/pruss_can_api.h line 137
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +11
-0+ +typedef enum { + ecanmailbox0 =0 , + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4, + ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +}can_mailbox_number ;
unused, too
drivers/net/can/da8xx_pruss/pruss_can_api.h line 143
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +6
-0+ +typedef enum { + ecandirectioninit =0 , + ecantransmit, + ecanreceive +}can_transfer_direction ;
please add a common prefix and please write them uppsercase.
drivers/net/can/da8xx_pruss/pruss_can_api.h line 155
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +12
-0+ +typedef struct { + u16 u16extendedidentifier; + u16 u16baseidentifier; + u8 u8data7; + u8 u8data6; + u8 u8data5; + u8 u8data4; + u8 u8data3; + u8 u8data2; + u8 u8data1; + u8 u8data0;
use an array for the data.
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +8
-0+u16 u16datalength; +u16 u16crc; +} can_mail_box_structure; + +typedef struct { +can_transfer_direction ecantransferdirection; +}can_mailbox_config ; +
drivers/net/can/da8xx_pruss/pruss_can_api.h line 173
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+typedef struct { +can_instance_enum ecaninstance; +can_transfer_direction ecantransferdirection; +can_mail_box_structure strcanmailbox; +can_mailbox_number ecanmailboxnumber; +u8 u8prunumber; +u32 u32globalstatus; +u32 u32interruptstatus; +u32 u32mailboxstatus; +}can_emu_app_hndl ;
You already have defines your priv. No need for further structs.
drivers/net/can/da8xx_pruss/pruss_can_api.h line 179
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +6
-0+ +typedef struct { +bool bcaninststate; +can_transfer_direction ecantransferdirection; +u32 u32apphandlerptr; +}can_emu_drv_inst ;
dito
drivers/net/can/da8xx_pruss/pruss_can_api.h line 189
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+ +typedef struct { +u8 u8syncjumpwidth; +u8 u8phseg1; +u8 u8phseg2; +}can_bit_timing_consts ; + +/* Field Definition Macros */ + +/* CONTROL */
get rid of all the following functions, you don't need that extra layer in the can driver.
Quoted 90 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +90
-0+/* +* pru_can_set_brp() Updates the BRP register of PRU. +*/ +s16 pru_can_set_brp (struct device *dev,u16 u16prescaler); + +/* +* pru_can_set_bit_timing() Updates the timing register of PRU +*/ +s16 pru_can_set_bit_timing (struct device *dev, +can_bit_timing_consts *pstrbittiming); + +/* +* pru_can_calc_timing() Updates the timing values of PRU +*/ +s16 pru_can_calc_timing (struct device *dev, +u32 u32bittiming,u32 u32bitrateprescaler); + +/* +* pru_can_write_data_to_mailbox() Updates the transmit mailboxes of PRU1 +*/ +s16 pru_can_write_data_to_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_get_data_from_mailbox() Receive data from receive mailboxes +*/ +s16 pru_can_get_data_from_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_rx_id_map() Receive mailboxes ID Mapping of PRU0 +*/ +s16 pru_can_rx_id_map (struct device *dev, +u32 u32nodeid,can_mailbox_number ecanmailboxno); + +/* +*pru_can_get_intr_status() Get interrupts status register value +*/ +s16 pru_can_get_intr_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + + +/* +* pru_can_get_global_status() Get the globalstatus register value +*/ +s16 pru_can_get_global_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_get_mailbox_status() Get mailbox status reg value +*/ +s16 pru_can_get_mailbox_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_configuration_mode_set() Sets timing val for data transfer +*/ +s16 pru_can_config_mode_set (struct device *dev, +bool bconfig_modeflag); + +/* +* pru_can_emu_init() Initializes Can Emulation Parameters +*/ +s16 pru_can_emu_init (struct device *dev, +u32 u32pruclock); + +/* +* pru_can_emu_open() Opens can emu for application to use +*/ +s16 pru_can_emu_open (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_emu_close() Closes can emu for applications to use +*/ +s16 pru_can_emu_close (struct device *dev, +can_emu_app_hndl *pstremuapphndl); + +/* +* pru_can_emu_exit() Diables all the PRUs +*/ +s16 pru_can_emu_exit (struct device *dev); + +s16 pru_can_tx_mode_set (struct device *dev,bool btransfer_flag, +can_transfer_direction ecan_trx); + +s16 pru_can_emu_sreset (struct device *dev); + +s16 pru_can_tx (struct device *dev, +u8 u8mailboxnumber,u8 u8prunumber);
drivers/net/can/da8xx_pruss/pruss_can_api.h line 290
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.h new file +10
-0+ +s16 pru_can_start_abort_tx (struct device *dev, +bool btxabort_flag); + +s16 pru_can_mask_ints (struct device *dev,u32 int_mask); + +s32 pru_can_get_error_cnt (struct device *dev,u8 u8prunumber); + +s32 pru_can_get_intc_status (struct device *dev); +#endif
regards, Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
_______________________________________________
Socketcan-core mailing list [email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core
Re: [PATCH v2 09/13] can: pruss CAN driver.
In reply to Subhasish GhoshQuoted 1 line · Subhasish Ghosh
This patch adds support for the CAN device emulated on PRUSS.
Hi Subhasish,
This is a detailed walk through the can driver. The pruss_can.c file mostly looks good, there are very tiny changes that I'm suggesting to improve the code. I assume that you wrote that file.
The pruss_can_api.c is a bit of a mess and looks like it was copied from some other code base and just barely changed to follow Linux coding style. I can tell from the main driver file that you can do better than that.
My recommendation for that would be to throw it away and reimplement the few parts that you actually need, in proper coding style. You can also try to fix the file according to the comments I give you below, but I assume that would be signficantly more work.
Moving everything into one file also makes things easier to read here and lets you identifer more quickly what is unused.
Arnd
drivers/net/can/da8xx_pruss/pruss_can.c line 83
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +6
-0+#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args) +#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)
Better use the existing dev_dbg() and dev_err() macros that provide the same functionality in a more standard way. You already use them in some places, as I noticed.
If you don't have a way to pass a meaningful device, you can use pr_debug/pr_err.
Review
Quoted 2 lines
(quoted diff) +2
-0+void omapl_pru_can_rx_wQ(struct work_struct *work) +{
This is only used in the same file, so better make it static.
drivers/net/can/da8xx_pruss/pruss_can.c line 393
Quoted 2 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +2
-0+if (-1 ==pru_can_get_intr_status (priv->dev, &priv->can_rx_hndl)) +return ;
Don't make up your own return values, just use the standard error codes, e.g. -EIO or -EAGAIN, whatever fits.
The more common way to write the comparison would be the other way round,
if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl) == -EAGAIN) return;
or, simpler
if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl)) return;
Review
Quoted 2 lines
(quoted diff) +2
-0+irqreturn_t omapl_tx_can_intr(int irq, void *dev_id) +{
This also should be static
drivers/net/can/da8xx_pruss/pruss_can.c line 439
Quoted 3 lines
drivers/net/can/da8xx_pruss/pruss_can.c new file +3
-0+for (bit_set =0 ; ((priv->can_tx_hndl.u32interruptstatus &0xFF ) + >> bit_set !=0 ); bit_set++) + ;
bit_set = fls(priv->can_tx_hndl.u32interruptstatus & 0xFF); ?
Quoted 1 line
+irqreturn_t
omapl_rx_can_intr(int irq, void *dev_id)
static
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +0
-0
A lot of code in this file seems to be unused. Is that right? I would suggest adding only the code that is actually being used. If you add more functionality later, you can always add back the low-level functions, but dead code usually turns into broken code quickly.
Quoted 1 line
+static
can_emu_drv_instgstr_can_inst[ecanmaxinst];
This is global data and probably needs some for of locking
drivers/net/can/da8xx_pruss/pruss_can_api.c line 30
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +12
-0+/* +* pru_can_set_brp() Updates the BRP register of PRU0 +* and PRU1 of OMAP L138. This API will be called by the +* Application to updtae the BRP register of PRU0 and PRU1 +* +* param u16bitrateprescaler The can bus bitrate +* prescaler value be set +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_brp (struct device *dev,u16 u16bitrateprescaler) +{
unused.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 36
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +5
-0+u32 u32offset; + +if (u16bitrateprescaler >255 ) { +return -1 ; + }
non-standard error code. It also doesn't match the comment, which claims it is SUCCESS or FAILURE, both of which are (rightfully) not defined.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 42
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +5
-0+ u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 ); + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER ); +pruss_writel (dev, u32offset, (u32 *) &u16bitrateprescaler,1 );
You pass a 32 bit pointer to a 16 bit local variable here. This has an undefined effect, and if you build this code on a big-endian platform, it cannot possibly do anything good.
pruss_writel() is defined in a funny way if it takes a thirty-two bit input argument by reference, rather than by value. What is going on there?
drivers/net/can/da8xx_pruss/pruss_can_api.c line 59
Quoted 2 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +2
-0+s16 pru_can_set_bit_timing (struct device *dev, +can_bit_timing_consts *pstrbittiming)
unused.
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 2 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +2
-0+u32 u32offset; +u32 u32serregister;
It's a bit silly to put the name of the type into the name of a variable. You already spell it out in the definition.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 150
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+s16 pru_can_write_data_to_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + }
nonstandard error code. Also, why the heck is type function return type s16 when the only possible return values are 0 and -1? Just make this an int.
Quoted 18 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +18
-0+switch ((u8 ) pstremuapphndl->ecanmailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0 ); +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1 ); +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2 ); +break ; +case 3 : + u32offset = (PRU_CAN_TX_MAILBOX3 ); +break ; +case 4 : + u32offset = (PRU_CAN_TX_MAILBOX4 ); +break ; +case 5 : + u32offset = (PRU_CAN_TX_MAILBOX5 );
drivers/net/can/da8xx_pruss/pruss_can_api.c line 179
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+break ; +case 6 : + u32offset = (PRU_CAN_TX_MAILBOX6 ); +break ; +case 7 : + u32offset = (PRU_CAN_TX_MAILBOX7 ); +break ; +default : +return -1 ; + }
Lovely switch statement. I'm sure you find a better way to express this ;-)
drivers/net/can/da8xx_pruss/pruss_can_api.c line 187
Quoted 7 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +7
-0+ s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox),4 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +return 0 ; +}
return pruss_writel(...) ?
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +11
-0+ +/* +* pru_can_get_intr_status() +* Gets the interrupts status register value. +* This API will be called by the Application +* to get the interrupts status register value +* +* param u8prunumber PRU number for which IntStatusReg +* has to be read +* +* return SUCCESS or FAILURE
drivers/net/can/da8xx_pruss/pruss_can_api.c line 294
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+*/ +s16 pru_can_get_intr_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; + +if (pstremuapphndl ==NULL ) { +return -1 ; + }
In every function you check that pstremuapphndl is present. This seems rather pointless. How about just making sure you never pass a NULL value to these functions? That should not be hard at all from the high-level driver.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 308
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +13
-0+if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_1 ) { + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER ); + }else if (pstremuapphndl->u8prunumber ==DA8XX_PRUCORE_0 ) { + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER ); + }else { +return -1 ; + } + + s16subrtnretval =pruss_readl (dev, u32offset, + (u32 *) &pstremuapphndl->u32interruptstatus,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + }
You can also get rid of all these {} braces around one-line statements.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 355
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+/* +* pru_can_get_mailbox_status() Gets the mailbox status +* register value. This API will be called by the Application +* to get the mailbox status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_mailbox_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl)
unused.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 485
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +8
-0+/* +* pru_can_config_mode_set() Sets the timing value +* for data transfer. This API will be called by the Application +* to set timing valus for data transfer +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_config_mode_set (struct device *dev,bool bconfigmodeflag)
unused.
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+ u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER &0xFFFF ); + u32value =0x00000000 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ;
drivers/net/can/da8xx_pruss/pruss_can_api.c line 548
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER &0xFFFF ); + u32value =0x00000040 ; + s16subrtnretval =pruss_writel (dev, u32offset, (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + }
<skipping 50 (!) more of these>
After the third time of writing the same code, you should have noticed that there is some duplication involved that can trivially be reduced. A good way to express the same would be a table with the contents:
static struct pru_can_register_init {
u16 offset;
u32 value;
} = {
{ PRU_CAN_TX_GLOBAL_CONTROL_REGISTER, 0, },
{ PRU_CAN_TX_GLOBAL_STATUS_REGISTER, 0x40, },
{ PRU_CAN_RX_GLOBAL_STATUS_REGISTER, 0x40, },
...
};drivers/net/can/da8xx_pruss/pruss_can_api.c line 912
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +13
-0+ + +/* +* pru_can_emu_open() Opens the can emu for +* application to use. This API will be called by the Application +* to Open the can emu for application to use. +* +* param pstremuapphndl Pointer to application handler +* structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_open (struct device *dev,can_emu_app_hndl *pstremuapphndl)
unused.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 944
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+/* +* brief pru_can_emu_close() Closes the can emu for other +* applications to use. This API will be called by the Application to Close +* the can emu for other applications to use +* +* param pstremuapphndl Pointer to application handler structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_close (struct device *dev,can_emu_app_hndl *pstremuapphndl)
unused
drivers/net/can/da8xx_pruss/pruss_can_api.c line 989
Quoted 4 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +4
-0+s16 pru_can_emu_sreset (struct device *dev) +{ +return 0 ; +}
pointless.
Quoted 18 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +18
-0+s16 pru_can_tx (struct device *dev,u8 u8mailboxnumber,u8 u8prunumber) +{ +u32 u32offset =0 ; +u32 u32value =0 ; +s16 s16subrtnretval =-1 ; + +if (DA8XX_PRUCORE_1 == u8prunumber) { +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 :
drivers/net/can/da8xx_pruss/pruss_can_api.c line 1018
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 2 : + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER &0xFFFF );
Another pointless switch statement.
drivers/net/can/da8xx_pruss/pruss_can_api.c line 1203
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+s16 pru_can_mask_ints (struct device *dev,u32 int_mask) +{ +return 0 ; +} + +int pru_can_get_error_cnt (struct device *dev,u8 u8prunumber) +{ +return 0 ; +}
useless.
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+int pru_can_get_intc_status (struct device *dev) +{ +u32 u32offset =0 ; +u32 u32getvalue =0 ; +u32 u32clrvalue =0 ; + + u32offset = (PRUSS_INTC_STATCLRINT1 &0xFFFF ); +pruss_readl (dev, u32offset, (u32 *) &u32getvalue,1 ); + +if (u32getvalue &4 )
drivers/net/can/da8xx_pruss/pruss_can_api.c line 1224
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ u32clrvalue =34 ;/* CLR Event 34 */ + +if (u32getvalue &2 ) + u32clrvalue =33 ;/* CLR Event 33 */ + +if (u32clrvalue) { + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF ); +pruss_writel (dev, u32offset, &u32clrvalue,1 ); + }else +return -1 ;
Could the controller signal both event 34 and 33 simultaneously? The only user of this function looks at the individual bits of the return value again, which looks wrong for all possible return values here.
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +13
-0+#ifndef _PRU_CAN_API_H_ +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000 + +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +#define CAN_RX_PRU_0 PRUSS_NUM0 +#define CAN_TX_PRU_1 PRUSS_NUM1 + +/* Number of Instruction in the Delay loop */
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+#define DELAY_LOOP_LENGTH 2 + +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04) +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C) +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14)
The header file should be used for interfaces between the two .c files, don't mix that with hardware specific definitions. Sometimes you may want to have register number lists in a header, if that list is going to be used in multiple places. In this case, there is just one user, so better move all those definitions over there.
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +12
-0+typedef enum { + ecaninst0 =0 , + ecaninst1, + ecanmaxinst +}can_instance_enum ; + +typedef enum { + ecanmailbox0 = 0, + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4,
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +} can_mailbox_number; + +typedef enum { + ecandirectioninit =0 , + ecantransmit, + ecanreceive +}can_transfer_direction ;
The values are all unused, you only use the typedefs. IMHO it would be more sensible to just pass these as unsigned int or u32 values, but if you prefer, there is no reason to just do
typedef u32 can_mailbox_number;
etc.
Quoted 4 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +4
-0+typedef struct { + u16 u16extendedidentifier; + u16 u16baseidentifier; + u8 u8data7;
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+u8 u8data6; +u8 u8data5; +u8 u8data4; +u8 u8data3; +u8 u8data2; +u8 u8data1; +u8 u8data0; +u16 u16datalength; +u16 u16crc; +} can_mail_box_structure;
Please don't use typedef for complex data structures, and learn about better naming of identifiers. I would suggest writing this as
struct pru_can_mailbox {
u16 ext_id;
u16 base_id;
u8 data[8]; /* note: reverse order */
u16 len;
u16 crc;
};Sames rules apply to the other structures.
Arnd
Re: [PATCH v2 09/13] can: pruss CAN driver.
Hello,
Quoted 13 lines
This is a detailed walk through the can driver. The
pruss_can.cfile mostly looks good, there are very tiny changes that I'm suggesting to improve the code. I assume that you wrote that file.The
pruss_can_api.cis a bit of a mess and looks like it was copied from some other code base and just barely changed to follow Linux coding style. I can tell from the main driver file that you can do better than that.
My recommendation for that would be to throw it away and reimplement the few parts that you actually need, in proper coding style. You can also try to fix the file according to the comments I give you below, but I assume that would be signficantly more work.
Quoted 2 lines
Moving everything into one file also makes things easier to read here and lets you identifer more quickly what is unused.
SG - I have almost re-implemented the API layer, will be merging with the driver file itself.
Quoted 13 lines
Quoted 8 lines
(quoted diff) +2
-0+#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt,## args)
drivers/net/can/da8xx_pruss/pruss_can.c new file +4
-0+#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ##args)
Better use the existing
dev_dbg()anddev_err()macros that provide the same functionality in a more standard way. You already use them in some places, as I noticed.
Quoted 3 lines
If you don't have a way to pass a meaningful device, you can use pr_debug/pr_err.
SG - Ok
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+void omapl_pru_can_rx_wQ(struct work_struct *work) +{This is only used in the same file, so better make it static.
SG - This is removed, used NAPI as recommended.
Quoted 6 lines
Quoted 3 lines
+ if (-1 ==
pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
+ return;Don't make up your own return values, just use the standard error codes, e.g.
-EIOor-EAGAIN, whatever fits.
SG - Ok
Quoted 10 lines
The more common way to write the comparison would be the other way round,
if (
pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl)==-EAGAIN) return;or, simpler
if (
pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl)) return;
SG - Ok
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+irqreturn_t omapl_tx_can_intr(int irq, void *dev_id) +{This also should be static
SG - Ok
Quoted 7 lines
Quoted 4 lines
+ for (
bit_set= 0; ((priv->can_tx_hndl.u32interruptstatus&0xFF)
+ >>bit_set!= 0); bit_set++)
+ ;
bit_set=fls(priv->can_tx_hndl.u32interruptstatus & 0xFF); ?
SG - Ok
Quoted 3 lines
Quoted 1 line
+irqreturn_t
omapl_rx_can_intr(int irq, void *dev_id)static
SG - Ok
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 6 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +0
-0A lot of code in this file seems to be unused. Is that right? I would suggest adding only the code that is actually being used. If you add more functionality later, you can always add back the low-level functions, but dead code usually turns into broken code quickly.
SG - Ok
Quoted 3 lines
Quoted 1 line
+static
can_emu_drv_instgstr_can_inst[ecanmaxinst];This is global data and probably needs some for of locking
SG - Ok
Quoted 15 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 30
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +12
-0+/* +* pru_can_set_brp() Updates the BRP register of PRU0 +* and PRU1 of OMAP L138. This API will be called by the +* Application to updtae the BRP register of PRU0 and PRU1 +* +* param u16bitrateprescaler The can bus bitrate +* prescaler value be set +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_set_brp (struct device *dev,u16 u16bitrateprescaler) +{unused.
SG - Ok
Quoted 10 lines
Quoted 6 lines
+ u32 u32offset;
+
+ if (u16bitrateprescaler > 255) {
+ return -1;
+ }non-standard error code. It also doesn't match the comment, which claims it is SUCCESS or FAILURE, both of which are (rightfully) not defined.
SG - Ok
Quoted 7 lines
Quoted 6 lines
+ u32offset = (
PRU_CAN_RX_CLOCK_BRP_REGISTER);
+pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1); +
+ u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
+pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
SG - Ok
Quoted 4 lines
You pass a 32 bit pointer to a 16 bit local variable here. This has an undefined effect, and if you build this code on a big-endian platform, it cannot possibly do anything good.
Quoted 9 lines
pruss_writel()is defined in a funny way if it takes a thirty-two bit input argument by reference, rather than by value. What is going on there?Quoted 2 lines
+s16 pru_can_set_bit_timing(struct device *dev,
+can_bit_timing_consts*pstrbittiming)unused.
SG - Ok
Quoted 5 lines
Quoted 2 lines
+ u32 u32offset;
+ u32 u32serregister;It's a bit silly to put the name of the type into the name of a variable. You already spell it out in the definition.
SG - Ok
Quoted 14 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 150
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+s16 pru_can_write_data_to_mailbox (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +s16 s16subrtnretval; +u32 u32offset; + +if (pstremuapphndl ==NULL ) { +return -1 ; + }nonstandard error code. Also, why the heck is type function return type s16 when the only possible return values are 0 and -1? Just make this an int.
SG - Ok
Quoted 30 lines
Quoted 21 lines
+ switch ((u8)
pstremuapphndl->ecanmailboxnumber) {
+ case 0:
+ u32offset = (PRU_CAN_TX_MAILBOX0);
+ break;
+ case 1:
+ u32offset = (PRU_CAN_TX_MAILBOX1);
+ break;
+ case 2:
+ u32offset = (PRU_CAN_TX_MAILBOX2);
+ break;
+ case 3:
+ u32offset = (PRU_CAN_TX_MAILBOX3);
+ break;
+ case 4:
+ u32offset = (PRU_CAN_TX_MAILBOX4);
+ break;
+ case 5:
+ u32offset = (PRU_CAN_TX_MAILBOX5);
+ break;
+ case 6:Quoted 8 lines
+ u32offset = (
PRU_CAN_TX_MAILBOX6);
+ break;
+ case 7:
+ u32offset = (PRU_CAN_TX_MAILBOX7);
+ break;
+ default:
+ return -1;
+ }
Quoted 1 line
Lovely switch statement. I'm sure you find a better way to express this ;-)
SG - Ok.
Quoted 10 lines
Quoted 8 lines
+ s16subrtnretval = pruss_writel(dev, u32offset,
+ (u32 *) &(pstremuapphndl->strcanmailbox), 4);
+ if (s16subrtnretval == -1) {
+ return -1;
+ }
+ return 0;
+}return
pruss_writel(...)?
SG - Ok.
Quoted 19 lines
Quoted 19 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +18
-0+ +/* +* pru_can_get_intr_status() +* Gets the interrupts status register value. +* This API will be called by the Application +* to get the interrupts status register value +* +* param u8prunumber PRU number for which IntStatusReg +* has to be read +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_intr_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl) +{ +u32 u32offset; +s16 s16subrtnretval =-1 ; +
Quoted 8 lines
Quoted 3 lines
+ if (pstremuapphndl == NULL) {
+ return -1;
+ }In every function you check that pstremuapphndl is present. This seems rather pointless. How about just making sure you never pass a NULL value to these functions? That should not be hard at all from the high-level driver.
SG - OK.
Quoted 15 lines
Quoted 14 lines
+ if (
pstremuapphndl->u8prunumber==DA8XX_PRUCORE_1) {
+ u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
+ } else if (pstremuapphndl->u8prunumber==DA8XX_PRUCORE_0) {
+ u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
+ } else {
+ return -1;
+ }
+
+ s16subrtnretval = pruss_readl(dev, u32offset,
+ (u32 *)&pstremuapphndl->u32interruptstatus, 1);
+ if (s16subrtnretval == -1) {
+ return -1;
+ }
Quoted 1 line
You can also get rid of all these {} braces around one-line statements.
SG - OK.
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 355
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+/* +* pru_can_get_mailbox_status() Gets the mailbox status +* register value. This API will be called by the Application +* to get the mailbox status register value +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_get_mailbox_status (struct device *dev, +can_emu_app_hndl *pstremuapphndl)unused
.
SG - OK.
Quoted 11 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 485
Quoted 9 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +8
-0+/* +* pru_can_config_mode_set() Sets the timing value +* for data transfer. This API will be called by the Application +* to set timing valus for data transfer +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_config_mode_set (struct device *dev,bool bconfigmodeflag)unused.
SG - OK.
Quoted 21 lines
Quoted 12 lines
+ u32offset = (
PRU_CAN_TX_GLOBAL_CONTROL_REGISTER&0xFFFF);
+ u32value =0x00000000;
+ s16subrtnretval =pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+ if (s16subrtnretval == -1) {
+ return -1;
+ }
+
+ u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER&0xFFFF);
+ u32value =0x00000040;
+ s16subrtnretval =pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+ if (s16subrtnretval == -1) {Quoted 8 lines
+ return -1;
+ }
+ u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER&0xFFFF);
+ u32value =0x00000040;
+ s16subrtnretval =pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+ if (s16subrtnretval == -1) {
+ return -1;
+ }
Quoted 6 lines
<skipping 50 (!) more of these>
After the third time of writing the same code, you should have noticed that there is some duplication involved that can trivially be reduced. A good way to express the same would be a table with the contents:
SG - OK.
Thanks for taking the pain to review this. But, the good
part is that
everything works fine. All this got cluttered as
development &
design changes happened. Hopefully, the cleaned up code
will
also work as well :-)
Quoted 11 lines
static struct
pru_can_register_init{
u16 offset;
u32 value;
} = {
{PRU_CAN_TX_GLOBAL_CONTROL_REGISTER, 0, },
{PRU_CAN_TX_GLOBAL_STATUS_REGISTER,0x40, },
{PRU_CAN_RX_GLOBAL_STATUS_REGISTER,0x40, },
...
};
Quoted 16 lines
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +13
-0+ + +/* +* pru_can_emu_open() Opens the can emu for +* application to use. This API will be called by the Application +* to Open the can emu for application to use. +* +* param pstremuapphndl Pointer to application handler +* structure +* +* return SUCCESS or FAILURE +*/ +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndlQuoted 1 line
*pstremuapphndl)
unused.
SG - OK.
Quoted 15 lines
Quoted 13 lines
+/*
+ * briefpru_can_emu_close()Closes the can emu for other
+ * applications to use. This API will be called by the Application to Close
+ * the can emu for other applications to use
+ *
+ * param pstremuapphndl Pointer to application handler structure
+ *
+ * return SUCCESS or FAILURE
+ */
+s16pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl)unused
SG - OK.
Quoted 7 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 989
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +4
-0+s16 pru_can_emu_sreset (struct device *dev) +{ +return 0 ; +}pointless.
SG - OK.
Quoted 23 lines
Quoted 23 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +22
-0+s16 pru_can_tx (struct device *dev,u8 u8mailboxnumber,u8 u8prunumber) +{ +u32 u32offset =0 ; +u32 u32value =0 ; +s16 s16subrtnretval =-1 ; + +if (DA8XX_PRUCORE_1 == u8prunumber) { +switch (u8mailboxnumber) { +case 0 : + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 ); +if (s16subrtnretval ==-1 ) { +return -1 ; + } +break ; +case 1 : + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER &0xFFFF ); + u32value =0x00000080 ; + s16subrtnretval =pruss_writel (dev, u32offset, + (u32 *) &u32value,1 );
Quoted 8 lines
Quoted 6 lines
+ if (s16subrtnretval == -1) {
+ return -1;
+ }
+ break;
+ case 2:
+ u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER&0xFFFF);Another pointless switch statement.
SG - OK.
Quoted 12 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c line 1203
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +9
-0+s16 pru_can_mask_ints (struct device *dev,u32 int_mask) +{ +return 0 ; +} + +int pru_can_get_error_cnt (struct device *dev,u8 u8prunumber) +{ +return 0 ; +}useless.
SG - OK.
Quoted 18 lines
Quoted 18 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +17
-0+int pru_can_get_intc_status (struct device *dev) +{ +u32 u32offset =0 ; +u32 u32getvalue =0 ; +u32 u32clrvalue =0 ; + + u32offset = (PRUSS_INTC_STATCLRINT1 &0xFFFF ); +pruss_readl (dev, u32offset, (u32 *) &u32getvalue,1 ); + +if (u32getvalue &4 ) + u32clrvalue =34 ;/* CLR Event 34 */ + +if (u32getvalue &2 ) + u32clrvalue =33 ;/* CLR Event 33 */ + +if (u32clrvalue) { + u32offset = (PRUSS_INTC_STATIDXCLR &0xFFFF );
Quoted 9 lines
Quoted 3 lines
+
pruss_writel(dev, u32offset, &u32clrvalue, 1);
+ } else
+ return -1;Could the controller signal both event 34 and 33 simultaneously? The only user of this function looks at the individual bits of the return value again, which looks wrong for all possible return values here.
SG - OK. The System Events are mapped to 10 host interrupts (PRU to ARM/DSP),
as I our case two system events can be mapped to a single
host interrupt.
Quoted 21 lines
Quoted 21 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +21
-0+#ifndef _PRU_CAN_API_H_ +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000 + +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +#define CAN_RX_PRU_0 PRUSS_NUM0 +#define CAN_TX_PRU_1 PRUSS_NUM1 + +/* Number of Instruction in the Delay loop */ +#define DELAY_LOOP_LENGTH 2 + +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04) +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C)
Quoted 8 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 2 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +2
-0+#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14)The header file should be used for interfaces between the two .c files, don't mix that with hardware specific definitions. Sometimes you may want to have register number lists in a header, if that list is going to be used in multiple places. In this case, there is just one user, so better move all those definitions over there.
SG - OK.
Quoted 28 lines
Quoted 13 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +12
-0+typedef enum { + ecaninst0 =0 , + ecaninst1, + ecanmaxinst +}can_instance_enum ; + +typedef enum { + ecanmailbox0 = 0, + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4,drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+ ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +} can_mailbox_number; + +typedef enum { + ecandirectioninit =0 , + ecantransmit, + ecanreceive +}can_transfer_direction ;The values are all unused, you only use the typedefs. IMHO it would be more sensible to just pass these as unsigned int or u32 values, but if you prefer, there is no reason to just do
Quoted 3 lines
typedef u32
can_mailbox_number;etc.
SG - OK.
Quoted 27 lines
Quoted 5 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +4
-0+typedef struct { + u16 u16extendedidentifier; + u16 u16baseidentifier; + u8 u8data7;drivers/net/can/da8xx_pruss/pruss_can_api.c
Quoted 10 lines
drivers/net/can/da8xx_pruss/pruss_can_api.c new file +10
-0+u8 u8data6; +u8 u8data5; +u8 u8data4; +u8 u8data3; +u8 u8data2; +u8 u8data1; +u8 u8data0; +u16 u16datalength; +u16 u16crc; +} can_mail_box_structure;Please don't use typedef for complex data structures, and learn about better naming of identifiers. I would suggest writing this as
struct
pru_can_mailbox{
u16ext_id;
u16base_id;
u8 data[8]; /* note: reverse order */
u16 len;
u16 crc;
};
Quoted 1 line
Sames rules apply to the other structures.
SG - OK.
Quoted 2 lines
Arnd
PATCH v2 10/13 mfd: pruss SUART private data.
In reply to Subhasish GhoshThis patch adds the PRUSS SUART data.
--- include/linux/mfd/pruss/da8xx_pru.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
include/linux/mfd/pruss/da8xx_pru.h +5 -0
@@ -93,6 +93,11 @@ struct da8xx_pruss_can_data {u32 version; }; +struct da850_evm_pruss_suart_data { +u32 version; +struct resource resource; +}; +u32 pruss_get_clk_freq (struct device *dev);u32 pruss_enable (struct device *dev,u8 pruss_num);
Signature · 1 line
1.7.2.3
PATCH v2 11/13 da850: pruss SUART board specific additions.
In reply to Subhasish GhoshThis patch adds the pruss SUART pin mux and registers the device with the pruss mfd driver.
--- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/board-da850-evm.c +36 -0
@@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = { -1 }; +const short da850_evm_pruss_suart_pins[] = { +DA850_AHCLKX ,DA850_ACLKX ,DA850_AFSX , +DA850_AHCLKR ,DA850_ACLKR ,DA850_AFSR , +DA850_AXR_13 ,DA850_AXR_9 ,DA850_AXR_7 , +DA850_AXR_14 ,DA850_AXR_10 ,DA850_AXR_8 , +-1 +}; + +static int __init da850_evm_setup_pruss_suart (void ) +{ +int ret; + + ret =davinci_cfg_reg_list (da850_evm_pruss_suart_pins); +if (ret) +pr_warning ("%s: da850_evm_pruss_suart_pins " +"mux setup failed: %d\n" , __func__, ret); +return ret; +} +static int __init da850_evm_setup_pruss_can (void ) {int ret, val =0 ;
@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)return ret; } +static struct da850_evm_pruss_suart_data suart_data = { + .version =1 , + .resource = { + .name ="da8xx_mcasp0_iomem" , + .start =DAVINCI_DA8XX_MCASP0_REG_BASE , + .end =DAVINCI_DA8XX_MCASP0_REG_BASE + + (SZ_1K *12 ) -1 , + .flags =IORESOURCE_MEM , + }, +}; +static struct da8xx_pruss_can_data can_data = { .version =1 , };
@@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = { .dev_name = "da8xx_pruss_can", .pdata = &can_data, .pdata_size = sizeof(can_data), + .setup = da850_evm_setup_pruss_suart, + }, + { + .dev_name = "da8xx_pruss_uart", + .pdata = &suart_data, + .pdata_size = sizeof(suart_data), .setup = da850_evm_setup_pruss_can, }, {
Signature · 1 line
1.7.2.3
Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
Hi Subhasish,
Quoted 14 lines · Subhasish Ghosh
This patch adds the pruss SUART pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>--- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {-1
arch/arm/mach-davinci/board-da850-evm.c const short da850_evm_pruss_can_pins[] = { · line 1070
Quoted 10 lines
arch/arm/mach-davinci/board-da850-evm.c +8
-0}; +const short da850_evm_pruss_suart_pins[] = { +DA850_AHCLKX ,DA850_ACLKX ,DA850_AFSX , +DA850_AHCLKR ,DA850_ACLKR ,DA850_AFSR , +DA850_AXR_13 ,DA850_AXR_9 ,DA850_AXR_7 , +DA850_AXR_14 ,DA850_AXR_10 ,DA850_AXR_8 , +-1 +}; +
Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP functions? E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.
Quoted 33 lines
arch/arm/mach-davinci/board-da850-evm.c +22
-0+static int __init da850_evm_setup_pruss_suart (void ) +{ +int ret; + + ret =davinci_cfg_reg_list (da850_evm_pruss_suart_pins); +if (ret) +pr_warning ("%s: da850_evm_pruss_suart_pins " +"mux setup failed: %d\n" , __func__, ret); +return ret; +} +static int __init da850_evm_setup_pruss_can (void ) {int ret, val =0 ;@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)return ret; } +static struct da850_evm_pruss_suart_data suart_data = { + .version =1 , + .resource = { + .name ="da8xx_mcasp0_iomem" , + .start =DAVINCI_DA8XX_MCASP0_REG_BASE , + .end =DAVINCI_DA8XX_MCASP0_REG_BASE + + (SZ_1K *12 ) -1 , + .flags =IORESOURCE_MEM , + }, +}; +static struct da8xx_pruss_can_data can_data = { .version =1 , };
arch/arm/mach-davinci/board-da850-evm.c static struct da8xx_pruss_devices pruss_devices[] = { · line 1127
Quoted 4 lines
arch/arm/mach-davinci/board-da850-evm.c +1
-0@@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = { .dev_name = "da8xx_pruss_can", .pdata = &can_data, .pdata_size = sizeof(can_data), + .setup = da850_evm_setup_pruss_suart,
Should this be da850_evm_setup_pruss_can instead?
arch/arm/mach-davinci/board-da850-evm.c static struct da8xx_pruss_devices pruss_devices[] = { · line 1133
Quoted 6 lines
arch/arm/mach-davinci/board-da850-evm.c +5
-0+ }, + { + .dev_name = "da8xx_pruss_uart", + .pdata = &suart_data, + .pdata_size = sizeof(suart_data), .setup = da850_evm_setup_pruss_can,
Should this be da850_evm_setup_pruss_suart instead?
arch/arm/mach-davinci/board-da850-evm.c static struct da8xx_pruss_devices pruss_devices[] = { · line 1135
Quoted 2 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0}, {
-Mike
Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
--------------------------------------------------
From: "Michael Williamson" <[email protected]>
Sent: Friday, February 11, 2011 8:56 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
Quoted 21 lines
Hi Subhasish,
Quoted 17 lines · Subhasish Ghosh
This patch adds the pruss SUART pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>--- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = { -1 };
Quoted 13 lines
arch/arm/mach-davinci/board-da850-evm.c const short da850_evm_pruss_can_pins[] = { · line 1070
Quoted 8 lines
arch/arm/mach-davinci/board-da850-evm.c +8
-0+const short da850_evm_pruss_suart_pins[] = { +DA850_AHCLKX ,DA850_ACLKX ,DA850_AFSX , +DA850_AHCLKR ,DA850_ACLKR ,DA850_AFSR , +DA850_AXR_13 ,DA850_AXR_9 ,DA850_AXR_7 , +DA850_AXR_14 ,DA850_AXR_10 ,DA850_AXR_8 , +-1 +}; +Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP functions? E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.
SG - The Soft-UART implementation uses the McASP as shift registers to push out the data sequentially.
Hence, we configure the McASP PINS and not the PRU PINS.
Quoted 33 lines
Quoted 33 lines
arch/arm/mach-davinci/board-da850-evm.c +22
-0+static int __init da850_evm_setup_pruss_suart (void ) +{ +int ret; + + ret =davinci_cfg_reg_list (da850_evm_pruss_suart_pins); +if (ret) +pr_warning ("%s: da850_evm_pruss_suart_pins " +"mux setup failed: %d\n" , __func__, ret); +return ret; +} +static int __init da850_evm_setup_pruss_can (void ) {int ret, val =0 ;@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)return ret; } +static struct da850_evm_pruss_suart_data suart_data = { + .version =1 , + .resource = { + .name ="da8xx_mcasp0_iomem" , + .start =DAVINCI_DA8XX_MCASP0_REG_BASE , + .end =DAVINCI_DA8XX_MCASP0_REG_BASE + + (SZ_1K *12 ) -1 , + .flags =IORESOURCE_MEM , + }, +}; +static struct da8xx_pruss_can_data can_data = { .version =1 , };@@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[]
Quoted 8 lines
arch/arm/mach-davinci/board-da850-evm.c static struct da8xx_pruss_devices pruss_devices[] = { · line 1127
Quoted 5 lines
arch/arm/mach-davinci/board-da850-evm.c +1
-0= { .dev_name = "da8xx_pruss_can", .pdata = &can_data, .pdata_size = sizeof(can_data), + .setup = da850_evm_setup_pruss_suart,Should this be
da850_evm_setup_pruss_caninstead?
SG - This just the way the patch is displayed. In the code the order is correct.
Quoted 10 lines
arch/arm/mach-davinci/board-da850-evm.c static struct da8xx_pruss_devices pruss_devices[] = { · line 1133
Quoted 7 lines
arch/arm/mach-davinci/board-da850-evm.c +5
-0+ }, + { + .dev_name = "da8xx_pruss_uart", + .pdata = &suart_data, + .pdata_size = sizeof(suart_data), .setup = da850_evm_setup_pruss_can,Should this be
da850_evm_setup_pruss_suartinstead?
SG - Ditto
Quoted 7 lines
Quoted 3 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0},{
-Mike
Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
In reply to Subhasish GhoshQuoted 12 lines · Subhasish Ghosh
This patch adds the pruss SUART pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>--- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)arch/arm/mach-davinci/board-da850-evm.c +0
-0
[...]
Quoted 5 lines
arch/arm/mach-davinci/board-da850-evm.c +1
-0@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)return ret; } +static struct da850_evm_pruss_suart_data suart_data = {
arch/arm/mach-davinci/board-da850-evm.c static int __init da850_evm_setup_pruss_can(void) · line 1117
Quoted 10 lines
arch/arm/mach-davinci/board-da850-evm.c +10
-0+ .version = 1, + .resource = { + .name = "da8xx_mcasp0_iomem", + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, + .end = DAVINCI_DA8XX_MCASP0_REG_BASE + + (SZ_1K * 12) - 1, + .flags = IORESOURCE_MEM, + }, +}; +
I don't think passing a resource thru platform data is good idea...
Resources should be bound to the platform device.
WBR, Sergei
Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
Hello,
Have modified this as shown below:
Please let me know if this looks ok.
(quoted diff) +0 -0
b/arch/arm/mach-davinci/board-da850-evm.c +static struct da850_evm_pruss_can_data can_data = {
.version = 1,
};
+static struct resource da850_evm_suart_resource[] =
------------------------->>> Added a separate resource structure for
suart.
+ {
+ .name = "da8xx_mcasp0_iomem", + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, + .end = DAVINCI_DA8XX_MCASP0_REG_BASE +
+ (SZ_1K * 12) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
static struct da8xx_pruss_devices pruss_devices[] = {
{
.dev_name = "da8xx_pruss_can",
.pdata = &can_data,
.pdata_size = sizeof(can_data),
.setup = da850_evm_setup_pruss_can,
+ .num_resources = 0,
+ .resources = NULL,
},
{
.dev_name = "da8xx_pruss_uart",
.pdata = &suart_data,
.pdata_size = sizeof(suart_data),
.setup = da850_evm_setup_pruss_suart,
+ .num_resources = ARRAY_SIZE(da850_evm_suart_resource),
+ .resources =
a850_evm_suart_resource, ---------------------------- >>>>> Initialized it
here
},
{
.dev_name = NULL,drivers/mfd/da8xx_pru.c +0 -0
@@ -332,6 +332,8 @@ static int pruss_mfd_add_devices(struct platform_device
*pdev)
cell.name = (dev_data + count)->dev_name;
cell.platform_data = (dev_data + count)->pdata;
cell.data_size = (dev_data + count)->pdata_size;
+ cell.resources = (dev_data + ount)->resources; ---------------------->>>Modified the MFD driver to add the resources.
+ cell.num_resources = (dev_data + count)->num_resources;
(quoted diff) +0 -0
b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+ res = platform_get_resource(pdev, IORESOURCE_MEM,
0); ------------------>> Used platform infrastructure to get the data.
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get resource");
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(res->start,
+ resource_size(res),
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:20 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
Quoted 36 lines
Quoted 14 lines · Subhasish Ghosh
This patch adds the pruss SUART pin mux and registers the device with the pruss mfd driver.
Signed-off-by Subhasish Ghosh <[email protected]>--- arch/arm/mach-davinci/board-da850-evm.c | 36 +++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)arch/arm/mach-davinci/board-da850-evm.c +0
-0[...]
Quoted 4 lines
arch/arm/mach-davinci/board-da850-evm.c +0
-0@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)return ret; } +static struct da850_evm_pruss_suart_data suart_data = {arch/arm/mach-davinci/board-da850-evm.c static int __init da850_evm_setup_pruss_can(void) · line 1116
Quoted 10 lines
arch/arm/mach-davinci/board-da850-evm.c +10
-0+ .version = 1, + .resource = { + .name = "da8xx_mcasp0_iomem", + .start = DAVINCI_DA8XX_MCASP0_REG_BASE, + .end = DAVINCI_DA8XX_MCASP0_REG_BASE + + (SZ_1K * 12) - 1, + .flags = IORESOURCE_MEM, + }, +}; +I don't think passing a resource thru platform data is good idea...
Resources should be bound to the platform device.WBR, Sergei
PATCH v2 12/13 da850: pruss SUART platform specific additions.
In reply to Subhasish GhoshThis patch adds the McASP clock alias.
The alias is used by the pruss suart driver
for enabling the McASP PSC.
--- arch/arm/mach-davinci/devices-da8xx.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
arch/arm/mach-davinci/devices-da8xx.c +11 -0
@@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {int __init da8xx_register_pruss (struct da8xx_pruss_devices *pruss_device) { +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE +int ret; +#endif + da8xx_pruss_dev.dev.platform_data = pruss_device; + +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE + ret =clk_add_alias (NULL ,"da8xx_pruss_uart.1" , +NULL , &da850_mcasp_device.dev); +if (ret <0 ) +return ret; +#endif return platform_device_register (&da8xx_pruss_dev); }
Signature · 1 line
1.7.2.3
Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Quoted 5 lines · Subhasish Ghosh
This patch adds the McASP clock alias.
The alias is used by the pruss suart driver
for enabling the McASP PSC.Signed-off-by Subhasish Ghosh <[email protected]>
[...]
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 563
Quoted 9 lines
arch/arm/mach-davinci/devices-da8xx.c +1
-0@@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {int __init da8xx_register_pruss (struct da8xx_pruss_devices *pruss_device) { +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
#ifdef's in the function body are generally fromned upon.
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 566
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +3
-0+int ret; +#endif +
This line should have been inside #ifdef...
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 569
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +2
-0da8xx_pruss_dev.dev.platform_data = pruss_device; + +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
Why not do it before assigning the platform data and avoid extra #ifdef?
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 571
Quoted 2 lines
arch/arm/mach-davinci/devices-da8xx.c +2
-0+ ret =clk_add_alias (NULL ,"da8xx_pruss_uart.1" , +NULL , &da850_mcasp_device.dev);
This line should be indented more to the right.
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 574
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +3
-0+if (ret <0 ) +return ret; +#endif
WBR, Sergei
Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Hello,
I could not follow your recommendations clearly, are you suggesting this:
int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device) {
#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
int ret;
ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
NULL, &da850_mcasp_device.dev);
if (ret < 0)
return ret;
#endif
da8xx_pruss_dev.dev.platform_data = pruss_device;
return platform_device_register(&da8xx_pruss_dev);
}--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Saturday, February 12, 2011 12:25 AM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Quoted 45 lines
Quoted 5 lines · Subhasish Ghosh
This patch adds the McASP clock alias.
The alias is used by the pruss suart driver
for enabling the McASP PSC.Signed-off-by Subhasish Ghosh <[email protected]>[...]
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 563
Quoted 10 lines
arch/arm/mach-davinci/devices-da8xx.c +1
-0@@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {int __init da8xx_register_pruss (struct da8xx_pruss_devices *pruss_device) { +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE #ifdef's in the function body are generally fromned upon.arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 566
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +3
-0+int ret; +#endif +This line should have been inside #ifdef...
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 569
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +2
-0da8xx_pruss_dev.dev.platform_data = pruss_device; + +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE Why not do it before assigning the platform data and avoid extra
#ifdef?arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 571
Quoted 2 lines
arch/arm/mach-davinci/devices-da8xx.c +2
-0+ ret =clk_add_alias (NULL ,"da8xx_pruss_uart.1" , +NULL , &da850_mcasp_device.dev);This line should be indented more to the right.
arch/arm/mach-davinci/devices-da8xx.c struct platform_device da8xx_pruss_dev = { · line 574
Quoted 3 lines
arch/arm/mach-davinci/devices-da8xx.c +3
-0+if (ret <0 ) +return ret; +#endif WBR, Sergei
Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Hello.
Quoted 7 lines · Subhasish Ghosh
I could not follow your recommendations clearly, are you suggesting this:
int
__initda8xx_register_pruss(struct da8xx_pruss_devices *pruss_device){
#ifdefCONFIG_SERIAL_PRUSS_SUART_MODULE
int ret;
Quoted 8 lines
ret =
clk_add_alias(NULL, "da8xx_pruss_uart.1", NULL, &da850_mcasp_device.dev);
if (ret < 0)
return ret;
#endif
da8xx_pruss_dev.dev.platform_data =pruss_device; returnplatform_device_register(&da8xx_pruss_dev); }
Yes. But still better would be to wrap clk_add_alias() into a function of
its own (defining it empty if CONFIG_SERIAL_PRUSS_SUART_MODULE is not defined).
WBR, Sergei
Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Ok, will do.
--------------------------------------------------
From: "Sergei Shtylyov" <[email protected]>
Sent: Tuesday, February 22, 2011 4:50 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; "Russell King" <[email protected]>; "Kevin Hilman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
Quoted 24 lines
Hello.
Quoted 7 lines · Subhasish Ghosh
I could not follow your recommendations clearly, are you suggesting this:
int
__initda8xx_register_pruss(struct da8xx_pruss_devices *pruss_device){
#ifdefCONFIG_SERIAL_PRUSS_SUART_MODULE
int ret;Quoted 8 lines
ret =
clk_add_alias(NULL, "da8xx_pruss_uart.1", NULL, &da850_mcasp_device.dev);
if (ret < 0)
return ret;
#endif
da8xx_pruss_dev.dev.platform_data =pruss_device; returnplatform_device_register(&da8xx_pruss_dev); }Yes. But still better would be to wrap
clk_add_alias()into a function
of its own (defining it empty ifCONFIG_SERIAL_PRUSS_SUART_MODULEis not defined).WBR, Sergei
PATCH v2 13/13 tty: pruss SUART driver
In reply to Subhasish GhoshThis patch adds support for the TTY compliant
Soft-UART device emulated on PRUSS.
--- drivers/tty/serial/Kconfig | 2 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/da8xx_pruss/Kconfig | 19 + drivers/tty/serial/da8xx_pruss/Makefile | 9 + drivers/tty/serial/da8xx_pruss/pruss_suart.c | 1014 +++++++++ drivers/tty/serial/da8xx_pruss/pruss_suart_api.c | 2350 ++++++++++++++++++++ drivers/tty/serial/da8xx_pruss/pruss_suart_api.h | 345 +++ drivers/tty/serial/da8xx_pruss/pruss_suart_board.h | 58 + drivers/tty/serial/da8xx_pruss/pruss_suart_err.h | 48 + drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h | 526 +++++ drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h | 153 ++ drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c | 384 ++++ drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h | 63 + include/linux/serial_core.h | 2 + 14 files changed, 4974 insertions(+), 0 deletions(-) create mode 100644 drivers/tty/serial/da8xx_pruss/Kconfig create mode 100644 drivers/tty/serial/da8xx_pruss/Makefile create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
drivers/tty/serial/Kconfig +2 -0
@@ -1595,4 +1595,6 @@ config SERIAL_PCH_UART This driver is for PCH(Platform controller Hub) UART of Intel EG20T which is an IOH(Input/Output Hub) for x86 embedded processor. Enabling PCH_DMA, this PCH UART works as DMA mode. + +source "drivers/tty/serial/da8xx_pruss/Kconfig" endmenu
drivers/tty/serial/Makefile +1 -0
@@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o +obj-$(CONFIG_SERIAL_PRUSS_SUART) += da8xx_pruss/
drivers/tty/serial/da8xx_pruss/Kconfig new file +19 -0
@@ -0,0 +1,19 @@ +# +# SUART Kernel Configuration +# + +config SERIAL_PRUSS_SUART + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850 + select SERIAL_CORE + tristate "PRUSS based SoftUART emulation on DA8XX" + ---help--- + Enable this to emulate a UART controller on the PRUSS of DA8XX. + If not sure, mark N + +config PRUSS_SUART_MCASP + int "McASP number" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART + default "0" + ---help--- + Enter the McASP number to use with SUART (0, 1 or 2). + You will need to recompile the kernel if this is changed.
drivers/tty/serial/da8xx_pruss/Makefile new file +9 -0
@@ -0,0 +1,9 @@ +# +# Makefile for SoftUART emulation +# + +suart_emu-objs := pruss_suart.o \ + pruss_suart_api.o \ + pruss_suart_utils.o + +obj-$(CONFIG_SERIAL_PRUSS_SUART) += suart_emu.o
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +1014 -0
1,014 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +2350 -0
1,948 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_api.h new file +345 -0
345 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_board.h new file +58 -0
58 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_err.h new file +48 -0
48 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h new file +526 -0
526 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h new file +153 -0
153 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c new file +384 -0
384 lines not on this page · raw message
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h new file +63 -0
63 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.2.3
Part of the diff is not shown here. View the raw message.
Re: [PATCH v2 13/13] tty: pruss SUART driver
Don't see why it needs its own sub-directory
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 57
Quoted 8 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +8
-0+#ifdef __SUART_DEBUG +#define __suart_debug(fmt, args...) \ + printk(KERN_DEBUG "suart_debug: " fmt, ## args) +#else +#define __suart_debug(fmt, args...) +#endif + +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)
Use dev_dbg/dev_err/pr_debug/pr_err
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 126
Quoted 11 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +11
-0+static void omapl_pru_tx_chars (struct omapl_pru_suart *soft_uart,u32 uart_no) +{ +struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit; +struct device *dev = soft_uart->dev; +s32 count =0 ; + +if (!(suart_get_duplex (soft_uart, uart_no) & ePRU_SUART_HALF_TX)) +return ; + +if (down_trylock (&soft_uart->port_sem[uart_no])) +return ;
Please use a mutex not a semaphore. We are trying to get almost all the kernel using mutexes as it is needed for hard real time.
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 214
Quoted 13 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +13
-0+pru_softuart_read_data (dev, &soft_uart->suart_hdl[uart_no], + suart_data, data_len +1 , + &data_len_read); + +for (i =0 ; i <= data_len_read; i++) { + soft_uart->port[uart_no].icount.rx++; +/* check for sys rq */ +if (uart_handle_sysrq_char + (&soft_uart->port[uart_no], suart_data)) +continue ; + } +/* update the tty data structure */ +tty_insert_flip_string (tty, suart_data, data_len_read);
You can avoid a copy here by using tty_prepare_flip_string()
Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty refcounting is right
Quoted 9 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +9
-0+static void pruss_suart_set_termios (struct uart_port *port, +struct ktermios *termios, +struct ktermios *old) +{ +struct omapl_pru_suart *soft_uart = + container_of(port, struct omapl_pru_suart, port[port->line]); +struct device *dev = soft_uart->dev; +u8 cval =0 ; +unsigned long flags =0 ;
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 360
Quoted 10 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +10
-0+u32 baud =0 ; +u32 old_csize = old ? old->c_cflag &CSIZE :CS8 ; + +/* +* Do not allow unsupported configurations to be set +*/ +if (1 ) { + termios->c_cflag &= ~(HUPCL |CRTSCTS |CMSPAR |CSTOPB + |PARENB |PARODD |CMSPAR ); + termios->c_cflag |=CLOCAL ;
No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them even if in fact they have no effect, so leave those two alone. The rest is fine.
Quoted 2 lines
+/*
+ * Characteres to ignore
Typo
Quoted 21 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +15
-0@@ -0,0 +1,2350 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Jitendra Kumar <[email protected]> +* +* 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/types.h>
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 25
Quoted 10 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +10
-0+#include <linux/mfd/pruss/da8xx_pru.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include "pruss_suart_api.h" +#include "pruss_suart_regs.h" +#include "pruss_suart_board.h" +#include "pruss_suart_utils.h" +#include "pruss_suart_err.h" + +static u8 g_uart_statu_table[8 ];
Can you lose the g_, its a windows naming convention we dont use
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 441
Quoted 2 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +2
-0+s16 pru_softuart_open (suart_handle h_suart) +{
If you just used normal integers you could surely make this routine trivial and remove all the duplication in the switches
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 28
Quoted 1 line
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +1
-0+s16 status =PRU_SUART_SUCCESS ;
And please stick to Linux error codes
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 583
Quoted 7 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +7
-0+/* suart instance close routine */ +s16 pru_softuart_close (suart_handle h_uart) +{ +s16 status =SUART_SUCCESS ; + +if (h_uart ==NULL ) { +return PRU_SUART_ERR_HANDLE_INVALID ;
Which is never checked. Far better to use WARN_ON and the like for such cases - or if like this one they don't appear to be possible to simply delete them
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 613
Quoted 4 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +4
-0+if ((tx_clk_divisor >385 ) || (tx_clk_divisor ==0 )) +return SUART_INVALID_CLKDIVISOR ; +if ((rx_clk_divisor >385 ) || (rx_clk_divisor ==0 )) +return SUART_INVALID_CLKDIVISOR ;
[minor] Lots of excess brackets
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 1923
Quoted 5 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +5
-0+ u32offset = (u32) (PRUSS_INTC_CHANMAP9 &0xFFFF ); + u32value =PRU_INTC_CHAN_34_SYSEVT_36_39 ; + s16retval =pruss_writel (dev, u32offset, (u32 *)&u32value,1 ); +if (-1 == s16retval) +return -1 ;
If you fixed the API here you'd be able to just write
if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF, PRU_INTC_BLAH)
or similar which would clean up a lot of messy code and shrink it dramatically. Given you have lots of series of writes some kind of
pruss_writel_multi(dev, array, len)
that took an array of addr/value pairs might also clean up a ton of code and turn it into trivial tables
Re: [PATCH v2 13/13] tty: pruss SUART driver
Hello,
Regarding the semaphore to mutex migration.
We are using down_trylock in interrupt context,mutex_trylock cannot be used in interrupt context, so we cannot use mutex in our driver.
--------------------------------------------------
From: "Alan Cox" <[email protected]>
Sent: Friday, February 11, 2011 9:58 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Greg Kroah-Hartman" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 172 lines
Don't see why it needs its own sub-directory
Quoted 9 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +8
-0+#ifdef __SUART_DEBUG +#define __suart_debug(fmt, args...) \ + printk(KERN_DEBUG "suart_debug: " fmt, ## args) +#else +#define __suart_debug(fmt, args...) +#endif + +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##args)
Use dev_dbg/dev_err/pr_debug/pr_err
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 126
Quoted 12 lines
+static void
omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +10
-0+{ +struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit; +struct device *dev = soft_uart->dev; +s32 count =0 ; + +if (!(suart_get_duplex (soft_uart, uart_no) & ePRU_SUART_HALF_TX)) +return ; + +if (down_trylock (&soft_uart->port_sem[uart_no])) +return ;Please use a mutex not a semaphore. We are trying to get almost all the kernel using mutexes as it is needed for hard real time.
drivers/tty/serial/da8xx_pruss/pruss_suart.c line 214
Quoted 13 lines
+ pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +12
-0+ suart_data, data_len +1 , + &data_len_read); + +for (i =0 ; i <= data_len_read; i++) { + soft_uart->port[uart_no].icount.rx++; +/* check for sys rq */ +if (uart_handle_sysrq_char + (&soft_uart->port[uart_no], suart_data)) +continue ; + } +/* update the tty data structure */ +tty_insert_flip_string (tty, suart_data, data_len_read);You can avoid a copy here by using
tty_prepare_flip_string()Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty refcounting is right
Quoted 9 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +9
-0+static void pruss_suart_set_termios (struct uart_port *port, +struct ktermios *termios, +struct ktermios *old) +{ +struct omapl_pru_suart *soft_uart = + container_of(port, struct omapl_pru_suart, port[port->line]); +struct device *dev = soft_uart->dev; +u8 cval =0 ; +unsigned long flags =0 ;drivers/tty/serial/da8xx_pruss/pruss_suart.c line 360
Quoted 10 lines
drivers/tty/serial/da8xx_pruss/pruss_suart.c new file +10
-0+u32 baud =0 ; +u32 old_csize = old ? old->c_cflag &CSIZE :CS8 ; + +/* +* Do not allow unsupported configurations to be set +*/ +if (1 ) { + termios->c_cflag &= ~(HUPCL |CRTSCTS |CMSPAR |CSTOPB + |PARENB |PARODD |CMSPAR ); + termios->c_cflag |=CLOCAL ;No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them even if in fact they have no effect, so leave those two alone. The rest is fine.
Quoted 2 lines
+/*
+ * Characteres to ignoreTypo
Quoted 23 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +5
-0@@ -0,0 +1,2350 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Jitendra Kumar <[email protected]> +* +* 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.
+ */drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +2
-0+ +#include <linux/types.h> drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 25
Quoted 10 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +10
-0+#include <linux/mfd/pruss/da8xx_pru.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include "pruss_suart_api.h" +#include "pruss_suart_regs.h" +#include "pruss_suart_board.h" +#include "pruss_suart_utils.h" +#include "pruss_suart_err.h" + +static u8 g_uart_statu_table[8 ];Can you lose the g_, its a windows naming convention we dont use
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 441
Quoted 2 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +2
-0+s16 pru_softuart_open (suart_handle h_suart) +{If you just used normal integers you could surely make this routine trivial and remove all the duplication in the switches
Quoted 1 line
+ s16 status =
PRU_SUART_SUCCESS;And please stick to Linux error codes
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c line 583
Quoted 7 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +7
-0+/* suart instance close routine */ +s16 pru_softuart_close (suart_handle h_uart) +{ +s16 status =SUART_SUCCESS ; + +if (h_uart ==NULL ) { +return PRU_SUART_ERR_HANDLE_INVALID ;Which is never checked. Far better to use
WARN_ONand the like for such cases - or if like this one they don't appear to be possible to simply delete themQuoted 4 lines
+ if ((
tx_clk_divisor> 385) || (tx_clk_divisor== 0))
+ returnSUART_INVALID_CLKDIVISOR;
+ if ((rx_clk_divisor> 385) || (rx_clk_divisor== 0))
+ returnSUART_INVALID_CLKDIVISOR;[minor] Lots of excess brackets
Quoted 5 lines
+ u32offset = (u32) (
PRUSS_INTC_CHANMAP9&0xFFFF);
+ u32value =PRU_INTC_CHAN_34_SYSEVT_36_39;
+ s16retval =pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;If you fixed the API here you'd be able to just write
if (
pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF, PRU_INTC_BLAH)or similar which would clean up a lot of messy code and shrink it dramatically. Given you have lots of series of writes some kind of
pruss_writel_multi(dev, array, len)that took an array of addr/value pairs might also clean up a ton of code and turn it into trivial tables
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 6 lines · On Fri, 18 Feb 2011 19:17:38 +0530 "Subhasish Ghosh"…
Hello,
Regarding the semaphore to mutex migration.
We are usingdown_trylockin interrupt context,mutex_trylockcannot be used in interrupt context, so we cannot use mutex in our driver.
Then you probably need to rework your locking. Best bet might be to fix all the other stuff and report the driver, and people can think about the locking problem.
Alan
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Fri, 18 Feb 2011 19:17:38 +0530 "Subhasish Ghosh"…
Hello,
Quoted 8 lines
Quoted 4 lines
Regarding the semaphore to mutex migration.
We are usingdown_trylockin interrupt context,mutex_trylockcannot be used in interrupt context, so we cannot use mutex in our driver.Then you probably need to rework your locking. Best bet might be to fix all the other stuff and report the driver, and people can think about the locking problem.
That semaphore is utterly useless to begin with. There are more serious locking problems than this one. Non serialized calls to suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
Aside of that the code is complete unreadable.
Thanks,
tglx
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 16 lines · On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Fri, 18 Feb 2011 19:17:38 +0530 "Subhasish Ghosh"…
Hello,
Quoted 8 lines
Quoted 4 lines
Regarding the semaphore to mutex migration.
We are usingdown_trylockin interrupt context,mutex_trylockcannot be used in interrupt context, so we cannot use mutex in our driver.Then you probably need to rework your locking. Best bet might be to fix all the other stuff and report the driver, and people can think about the locking problem.
Quoted 5 lines
That semaphore is utterly useless to begin with. There are more serious locking problems than this one. Non serialized calls to suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
Aside of that the code is complete unreadable.
I think it mostly suffers from the same problem as the CAN driver I commented on earlier: One of the files (pruss_suart_api.c) was clearly not written with Linux as the target, and the other files try to work around this by wrapping a Linux driver around it.
The suart_api HAL stuff clearly needs to go away, so that the rest can be rewritten into a proper device driver.
Arnd
Re: [PATCH v2 13/13] tty: pruss SUART driver
Hello,
I had kept separate files to affirm the modularity and ease of portability of the system.
There are three different interfaces,
1. The Linux driver interface
2. The PRU control interface
3. The McASP serializer interface.
To maintain modularity, I had classified the files respectively as :
1. pruss_suart.c 2. pruss_suart_api.c 3. pruss_suart_utils.c
This is not a single device which can be expressed as a single file, but functionally different devices logically cascaded together to work in unison.
We use the PRU for packet processing, but the actual data is transmitted/received through the McASP, which we use as a serializer.
I feel to combine these disparate functionalities into a single file will not
1. Help better understanding the device. I mean, why should a TTY UART driver be aware of the McASP or the PRU.
2. In case of a bug in the API layer or McASP, the driver need not be touched, thus improve maintainability.
3. If we need to port it to another Linux version, just editing the driver file should suffice, this will reduce bugs while porting.
To me, combining all of these into a single file only creates a mess. This is the reason I had separated them into different files!! I don't understand why should it be better to have all of these into a single file.
--------------------------------------------------
From: "Arnd Bergmann" <[email protected]>
Sent: Saturday, February 19, 2011 12:21 AM
To: <[email protected]>
Cc: "Thomas Gleixner" <[email protected]>; "Alan Cox" <[email protected]>; <[email protected]>; <[email protected]>; "Subhasish Ghosh" <[email protected]>; "Greg Kroah-Hartman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 32 lines · On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
Quoted 16 lines · Alan Cox
Quoted 6 lines
Quoted 2 lines · On Fri, 18 Feb 2011 19:17:38 +0530 "Subhasish Ghosh"…
Hello,
Quoted 8 lines
Quoted 4 lines
Regarding the semaphore to mutex migration.
We are usingdown_trylockin interrupt context,mutex_trylockcannot be used in interrupt context, so we cannot use mutex in our driver.Then you probably need to rework your locking. Best bet might be to fix all the other stuff and report the driver, and people can think about the locking problem.
Quoted 5 lines
That semaphore is utterly useless to begin with. There are more serious locking problems than this one. Non serialized calls to suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
Aside of that the code is complete unreadable.
I think it mostly suffers from the same problem as the CAN driver I commented on earlier: One of the files (
pruss_suart_api.c) was clearly not written with Linux as the target, and the other files try to work around this by wrapping a Linux driver around it.The
suart_apiHAL stuff clearly needs to go away, so that the rest can be rewritten into a proper device driver.Arnd
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 26 lines · Subhasish Ghosh
Hello,
I had kept separate files to affirm the modularity and ease of portability of the system.
There are three different interfaces,
1. The Linux driver interface
2. The PRU control interface
3. The McASP serializer interface.To maintain modularity, I had classified the files respectively as :
1. pruss_suart.c 2. pruss_suart_api.c 3. pruss_suart_utils.cThis is not a single device which can be expressed as a single file, but functionally different devices logically cascaded together to work in unison.
We use the PRU for packet processing, but the actual data is transmitted/received through the
McASP, which we use as a serializer.I feel to combine these disparate functionalities into a single file will not
Quoted 6 lines
1. Help better understanding the device. I mean, why should a TTY UART driver be aware of the McASP or the PRU.
2. In case of a bug in the API layer or McASP, the driver need not be touched, thus improve maintainability.
3. If we need to port it to another Linux version, just editing the driver file should suffice, this will reduce bugs while porting.
If your code is in the kernel tree, you do not need to ever port it to a new version, as it will happen automatically as new kernels are released, so this really isn't anything to worry about.
Quoted 4 lines
To me, combining all of these into a single file only creates a mess. This is the reason I had separated them into different files!! I don't understand why should it be better to have all of these into a single file.
As Alan stated, just use 3 files in the directory with the other drivers, you don't need a subdir for something small like this.
thanks,
greg k-h
Re: [PATCH v2 13/13] tty: pruss SUART driver
I could not follow the recommendations clearly.
This is just to clarify.
Currently, I have the following files for the suart implementation:
drivers/tty/serial/da8xx_pruss/pruss_suart_api.h drivers/tty/serial/da8xx_pruss/pruss_suart_err.h drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h drivers/tty/serial/da8xx_pruss/pruss_suart_board.h drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c drivers/tty/serial/da8xx_pruss/pruss_suart.c drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
Of these, I will be removing pruss_suart_err.h as part of the Linux error code cleanup. But, I need to keep at least pruss_suart_board.h as a separate file, as this defines configurations which will be often modified by users, I don't want to mix it with other files.
Should I combine rest of the headers into a single file ? and keep the other three .c files under "drivers/tty/serial/" and remove the da8xx_pruss directory altogether.
--------------------------------------------------
From: "Greg KH" <[email protected]>
Sent: Tuesday, February 22, 2011 8:07 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: "Arnd Bergmann" <[email protected]>; <[email protected]>; "Thomas Gleixner" <[email protected]>; "Alan Cox" <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 49 lines · Subhasish Ghosh
Quoted 26 lines
Hello,
I had kept separate files to affirm the modularity and ease of portability of the system.
There are three different interfaces,
1. The Linux driver interface
2. The PRU control interface
3. The McASP serializer interface.To maintain modularity, I had classified the files respectively as :
1. pruss_suart.c 2. pruss_suart_api.c 3. pruss_suart_utils.cThis is not a single device which can be expressed as a single file, but functionally different devices logically cascaded together to work in unison.
We use the PRU for packet processing, but the actual data is transmitted/received through the
McASP, which we use as a serializer.I feel to combine these disparate functionalities into a single file will not
Quoted 6 lines
1. Help better understanding the device. I mean, why should a TTY UART driver be aware of the McASP or the PRU.
2. In case of a bug in the API layer or McASP, the driver need not be touched, thus improve maintainability.
3. If we need to port it to another Linux version, just editing the driver file should suffice, this will reduce bugs while porting.If your code is in the kernel tree, you do not need to ever port it to a new version, as it will happen automatically as new kernels are released, so this really isn't anything to worry about.
Quoted 4 lines
To me, combining all of these into a single file only creates a mess. This is the reason I had separated them into different files!! I don't understand why should it be better to have all of these into a single file.
As Alan stated, just use 3 files in the directory with the other drivers, you don't need a subdir for something small like this.
thanks,
greg k-h
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 16 lines · Subhasish Ghosh
I could not follow the recommendations clearly.
This is just to clarify.Currently, I have the following files for the suart implementation:
drivers/tty/serial/da8xx_pruss/pruss_suart_api.hdrivers/tty/serial/da8xx_pruss/pruss_suart_err.hdrivers/tty/serial/da8xx_pruss/pruss_suart_regs.hdrivers/tty/serial/da8xx_pruss/pruss_suart_board.hdrivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.hdrivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
drivers/tty/serial/da8xx_pruss/pruss_suart_api.cdrivers/tty/serial/da8xx_pruss/pruss_suart.cdrivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
Quoted 6 lines
Of these, I will be removing
pruss_suart_err.has part of the Linux error code cleanup.
But, I need to keep at leastpruss_suart_board.has a separate file, as this defines
configurations which will be often modified by users, I don't want to mix it with other files.
Why would a .h file ever need to be "modified by users"? That sounds wrong to me.
Quoted 1 line
Should I combine rest of the headers into a single file ?
Yes, why would they need to be separate?
Quoted 2 lines
and keep the other three .c files under "
drivers/tty/serial/" and remove theda8xx_prussdirectory altogether.
Yes.
thanks,
greg k-h
Re: [PATCH v2 13/13] tty: pruss SUART driver
In reply to Arnd BergmannI agree with the Codingstyle which needs to be fixed and would appreciate more feedback on it.
I have also gotten rid of the semaphore completely, please let me know what you feel of this implementation:
I have tested this without any problem.
What I am basically doing below is that, I am getting the data from the circ buff and then using the interrupt handler to pump out the data. As the circ buff empties, I am accepting another request from the TTY.
Are you noticing any problems with this:
drivers/tty/serial/da8xx_pruss/pruss_suart.c +0 -0
@@ -72,7 +72,7 @@ struct suart_fifo {
struct omapl_pru_suart {
struct uart_port port[NR_SUART];
struct device *dev; /* pdev->dev */
- struct semaphore port_sem[NR_SUART];
+ bool tx_empty[NR_SUART];
struct clk *clk_mcasp;
struct suart_fifo suart_fifo_addr[NR_SUART];
const struct firmware *fw;@@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
return;
- if (down_trylock(&soft_uart->port_sem[uart_no]))
- return;
-
if (uart_circ_empty(xmit) ||
uart_tx_stopped(&soft_uart->port[uart_no])) {
pruss_suart_stop_tx(&soft_uart->port[uart_no]);
- up(&soft_uart->port_sem[uart_no]);
+ soft_uart->tx_empty[uart_no] = true;
return;
}@@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void *dev_id)
pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
pru_softuart_clr_tx_status(dev,
&soft_uart->suart_hdl
[port->line]);
- up(&soft_uart->port_sem[port->line]);
omapl_pru_tx_chars(soft_uart, port->line);
}
} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));@@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port *port)
suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);- omapl_pru_tx_chars(soft_uart, port->line);
+ if (soft_uart->tx_empty[port->line] == true) {
+ soft_uart->tx_empty[port->line] = false;
+ omapl_pru_tx_chars(soft_uart, port->line);
+ }
}
--------------------------------------------------
From: "Arnd Bergmann" <[email protected]>
Sent: Saturday, February 19, 2011 12:21 AM
To: <[email protected]>
Cc: "Thomas Gleixner" <[email protected]>; "Alan Cox" <[email protected]>; <[email protected]>; <[email protected]>; "Subhasish Ghosh" <[email protected]>; "Greg Kroah-Hartman" <[email protected]>; <[email protected]>; "open list" <[email protected]>; <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 32 lines · On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
Quoted 16 lines · Alan Cox
Quoted 6 lines
Quoted 2 lines · On Fri, 18 Feb 2011 19:17:38 +0530 "Subhasish Ghosh"…
Hello,
Quoted 8 lines
Quoted 4 lines
Regarding the semaphore to mutex migration.
We are usingdown_trylockin interrupt context,mutex_trylockcannot be used in interrupt context, so we cannot use mutex in our driver.Then you probably need to rework your locking. Best bet might be to fix all the other stuff and report the driver, and people can think about the locking problem.
Quoted 5 lines
That semaphore is utterly useless to begin with. There are more serious locking problems than this one. Non serialized calls to suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
Aside of that the code is complete unreadable.
I think it mostly suffers from the same problem as the CAN driver I commented on earlier: One of the files (
pruss_suart_api.c) was clearly not written with Linux as the target, and the other files try to work around this by wrapping a Linux driver around it.The
suart_apiHAL stuff clearly needs to go away, so that the rest can be rewritten into a proper device driver.Arnd
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 26 lines · Subhasish Ghosh
(quoted diff) +1
-5@@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no) if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX)) return; - if (down_trylock(&soft_uart->port_sem[uart_no])) - return; - if (uart_circ_empty(xmit) || uart_tx_stopped(&soft_uart->port[uart_no])) { pruss_suart_stop_tx(&soft_uart->port[uart_no]); - up(&soft_uart->port_sem[uart_no]); + soft_uart->tx_empty[uart_no] = true; return; }@@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void *dev_id) pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR); pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl [port->line]); - up(&soft_uart->port_sem[port->line]); omapl_pru_tx_chars(soft_uart, port->line); }} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
Review static void pruss_suart_start_tx(struct uart_port · line 298
Quoted 10 lines
(quoted diff) +4
-1@@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port *port) suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num, PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT); - omapl_pru_tx_chars(soft_uart, port->line); + if (soft_uart->tx_empty[port->line] == true) { + soft_uart->tx_empty[port->line] = false; + omapl_pru_tx_chars(soft_uart, port->line); + } }
This looks racy, and I think you at least need to take the spinlock in pruss_suart_start_tx(), but I don't fully understand the intention of the code.
I guess you could also use a bitmask for tx_empty and use test_and_clear_bit() on that to guarantee atomicity.
Arnd
Re: [PATCH v2 13/13] tty: pruss SUART driver
Hello,
Ok, have implemented the test_and_clear_bit.
Quoted 52 lines · Subhasish Ghosh
Quoted 32 lines
(quoted diff) +0
-0@@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct
omapl_pru_suart*soft_uart, u32uart_no)
if (!(suart_get_duplex(soft_uart,uart_no) &ePRU_SUART_HALF_TX))
return;(quoted diff) +1
-4- if (down_trylock(&soft_uart->port_sem[uart_no])) - return; - if (uart_circ_empty(xmit) || uart_tx_stopped(&soft_uart->port[uart_no])) { pruss_suart_stop_tx(&soft_uart->port[uart_no]); - up(&soft_uart->port_sem[uart_no]); + soft_uart->tx_empty[uart_no] = true; return; }@@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq,void
*dev_id)
pru_intr_clr_isrstatus(dev,uart_num,PRU_TX_INTR);
pru_softuart_clr_tx_status(dev,&soft_uart->suart_hdl[port->line]);(quoted diff) +0
-1- up(&soft_uart->port_sem[port->line]); omapl_pru_tx_chars(soft_uart, port->line); } } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));@@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port *port)Review static void pruss_suart_start_tx(struct uart_port · line 299
Quoted 10 lines
(quoted diff) +4
-1suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num, PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT); - omapl_pru_tx_chars(soft_uart, port->line); + if (soft_uart->tx_empty[port->line] == true) { + soft_uart->tx_empty[port->line] = false; + omapl_pru_tx_chars(soft_uart, port->line); + } }This looks racy, and I think you at least need to take the spinlock in
pruss_suart_start_tx(), but I don't fully understand the intention of the code.I guess you could also use a bitmask for
tx_emptyand usetest_and_clear_bit()on that to guarantee atomicity.Arnd
Re: [PATCH v2 13/13] tty: pruss SUART driver
In reply to Alan Cox--------------------------------------------------
From: "Alan Cox" <[email protected]>
Sent: Friday, February 11, 2011 9:58 PM
To: "Subhasish Ghosh" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Greg Kroah-Hartman" <[email protected]>; "open list" <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 1 line
Don't see why it needs its own sub-directory
SG - We have two different layers of implementation. One is the driver layer, which interacts with the TTY sub-system and the other is the API layer,
which interacts with the PRUSS. To maintain this (also explained in the other mail),
we used separate files and hence we decided to keep the code in a separate directory so that the related files can be identified easily.
Quoted 14 lines
Quoted 11 lines
(quoted diff) +8
-0+#ifdef __SUART_DEBUG +#define __suart_debug(fmt, args...) \ + printk(KERN_DEBUG "suart_debug: " fmt, ## args) +#else +#define __suart_debug(fmt, args...) +#endif + +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##Quoted 1 line
args)
Use dev_dbg/dev_err/pr_debug/pr_err
SG - did you mean replace the printks above with dev_dgb/err or the suart_dbg/err.
Quoted 17 lines
Quoted 4 lines
+static void
omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)Review
Quoted 10 lines
(quoted diff) +10
-0+{ + struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit; + struct device *dev = soft_uart->dev; + s32 count = 0; + + if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX)) + return; + + if (down_trylock(&soft_uart->port_sem[uart_no])) + return;Please use a mutex not a semaphore. We are trying to get almost all the kernel using mutexes as it is needed for hard real time.
SG - Have removed, need your feedback.
Quoted 16 lines
Quoted 5 lines
+ pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
(quoted diff) +2
-0+ suart_data, data_len + 1, + &data_len_read);Review
Quoted 10 lines
(quoted diff) +10
-0+ + for (i = 0; i <= data_len_read; i++) { + soft_uart->port[uart_no].icount.rx++; + /* check for sys rq */ + if (uart_handle_sysrq_char + (&soft_uart->port[uart_no], suart_data)) + continue; + } + /* update the tty data structure */ + tty_insert_flip_string(tty, suart_data, data_len_read);
Quoted 1 line
You can avoid a copy here by using
tty_prepare_flip_string()
SG - Ok, Thus this look ok ?
==================================================================================
drivers/tty/serial/da8xx_pruss/pruss_suart.c +0 -0
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
s8 flags = TTY_NORMAL;
u16 rx_status, data_len = SUART_FIFO_LEN;
u32 data_len_read;
- u8 suart_data[SUART_FIFO_LEN + 1];
+ u8 *suart_data = NULL;
s32 i = 0;+ s32 alloc_len = 0;
if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
soft_uart->port[uart_no].sysrq = 0;
#endif
} else {
+ alloc_len = tty_prepare_flip_string(tty, &suart_data,
data_len + 1);
pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],- suart_data, data_len + 1,
- &data_len_read);
+ suart_data, alloc_len,
+ &data_len_read);
for (i = 0; i <= data_len_read; i++) {
soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
(&soft_uart->port[uart_no], suart_data))
continue;
}
- /* update the tty data structure */
- tty_insert_flip_string(tty, suart_data, data_len_read);
}============================================================================================
Quoted 2 lines
Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty refcounting is right
SG - Ok, Will do.
Quoted 17 lines
Quoted 17 lines
(quoted diff) +15
-0+static void pruss_suart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct omapl_pru_suart *soft_uart = + container_of(port, struct omapl_pru_suart, port[port->line]); + struct device *dev = soft_uart->dev; + u8 cval = 0; + unsigned long flags = 0; + u32 baud = 0; + u32 old_csize = old ? old->c_cflag & CSIZE : CS8; + +/* + * Do not allow unsupported configurations to be set + */
Quoted 8 lines
Quoted 4 lines
+ if (1) {
+termios->c_cflag&= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
+ | PARENB | PARODD | CMSPAR);
+termios->c_cflag|= CLOCAL;No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them even if in fact they have no effect, so leave those two alone. The rest is fine.
SG -Ok, will do.
Quoted 7 lines
Quoted 4 lines
+/*
+ * Characteres to ignoreTypo
SG - ok.
Quoted 29 lines
Quoted 29 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +5
-0@@ -0,0 +1,2350 @@ +/* +* Copyright (C) 2010 Texas Instruments Incorporated +* Author: Jitendra Kumar <[email protected]> +* +* 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.
+ */drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +5
-0+ +#include <linux/types.h> +#include <linux/mfd/pruss/da8xx_pru.h> +#include <linux/io.h> +#include <mach/hardware.h>
Quoted 8 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
Quoted 7 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +7
-0+#include "pruss_suart_api.h" +#include "pruss_suart_regs.h" +#include "pruss_suart_board.h" +#include "pruss_suart_utils.h" +#include "pruss_suart_err.h" + +static u8 g_uart_statu_table[8 ];Can you lose the g_, its a windows naming convention we dont use
SG -- Ok, I can also see the Hungarian style like u32Offset, will get rid of these as well.
Would really appreciate if you may please point me out more such
problems.
Quoted 7 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
Quoted 4 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +2
-0+s16 pru_softuart_open (suart_handle h_suart) +{If you just used normal integers you could surely make this routine trivial and remove all the duplication in the switches
SG -- Ok, will do.
Quoted 4 lines
Quoted 2 lines
+ s16 status =
PRU_SUART_SUCCESS;And please stick to Linux error codes
SG - Ok, Will do
Quoted 13 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
Quoted 9 lines
drivers/tty/serial/da8xx_pruss/pruss_suart_api.c new file +7
-0+/* suart instance close routine */ +s16 pru_softuart_close (suart_handle h_uart) +{ +s16 status =SUART_SUCCESS ; + +if (h_uart ==NULL ) { +return PRU_SUART_ERR_HANDLE_INVALID ;Which is never checked. Far better to use
WARN_ONand the like for such cases - or if like this one they don't appear to be possible to simply delete them
SG -- OK, does this look ok ?
=================================
if (h_uart == NULL) {
+WARN_ON(1);
- return PRU_SUART_ERR_HANDLE_INVALID;
+return -EINVAL;
}
=================================
Quoted 7 lines
Quoted 5 lines
+ if ((
tx_clk_divisor> 385) || (tx_clk_divisor== 0))
+ returnSUART_INVALID_CLKDIVISOR;
+ if ((rx_clk_divisor> 385) || (rx_clk_divisor== 0))
+ returnSUART_INVALID_CLKDIVISOR;[minor] Lots of excess brackets
Ok - Will do.
Quoted 13 lines
Quoted 7 lines
+ u32offset = (u32) (
PRUSS_INTC_CHANMAP9&0xFFFF);
+ u32value =PRU_INTC_CHAN_34_SYSEVT_36_39;
+ s16retval =pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;If you fixed the API here you'd be able to just write
if (
pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF, PRU_INTC_BLAH)
Quoted 7 lines
or similar which would clean up a lot of messy code and shrink it dramatically. Given you have lots of series of writes some kind of
pruss_writel_multi(dev, array, len)that took an array of addr/value pairs might also clean up a ton of code and turn it into trivial tables
SG -- Will shrink this function.
Quoted 1 line
Please do not print this email unless it is absolutely necessary. Spread environmental awareness.
-------------------------------------------------------DISCLAIMER------------------------------------------------------
The information transmitted herewith is confidential and proprietary information intended only for use by the individual or entity to which it is addressed. If the reader of this message is not the intended recipient, you are hereby notified that any review, retransmission, dissemination, distribution, copying or other use of, or taking of any action in reliance upon this information is strictly prohibited. If you have received this communication in error, please contact the sender and delete the material from your computer.
---------------------------------------------------------------------------------------------------------------------------
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 2 lines
we used separate files and hence we decided to keep the code in a separate directory so that the related files can be identified easily.
Fair enough but I would have thought you could drop the two files in the serial directory if they have obviously related names- trivial item/
Quoted 16 lines
Quoted 4 lines
Quoted 11 lines
Quoted 9 lines
(quoted diff) +8
-0+#ifdef __SUART_DEBUG +#define __suart_debug(fmt, args...) \ + printk(KERN_DEBUG "suart_debug: " fmt, ## args) +#else +#define __suart_debug(fmt, args...) +#endif + +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##args)
Use dev_dbg/dev_err/pr_debug/pr_err
Quoted 2 lines
SG - did you mean replace the printks above with dev_dgb/err or the suart_dbg/err.
Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you to configure debug levels and the like nicely as well as producing clearer printk info. In some cases with tty code you may not know the device so have to use pr_err/pr_debug etc.
Ok
Quoted 11 lines
Quoted 3 lines
Which is never checked. Far better to use
WARN_ONand the like for such cases - or if like this one they don't appear to be possible to simply delete themSG -- OK, does this look ok ?
=================================
if (h_uart== NULL) {(quoted diff) +2
-1+WARN_ON(1); - return PRU_SUART_ERR_HANDLE_INVALID; +return -EINVAL;}
Yep - the user will now get a backtrace, and in addition kerneloops.org can capture it if that is set up in the distro in use.
Alan
Re: [PATCH v2 13/13] tty: pruss SUART driver
Hello,
I tried using the tty_prepare_flip_string as shown below, but this is causing some latency issues.
Problem is, we do not have any flow control, so we must copy the FIFO data before the next data is available. As we are using the tty_prepare_flip_string just before the read API, the FIFO is getting overwritten and we are ending up missing chunks (FIFO sized) of data.
I tried using a tasklet for the TX part, but that did not help.
Another way is to prepare the buffer for the next read and read the data immediately. Something like this:
1. Call tty_prepare_flip_string while startup.
2. When the read interrupt arrives, read the data immediately.
3. Call tty_prepare_flip_string for the next read.
Again, the problem here is that we need to use global variables to store the pre-allocated buffers and at the last read, we allocated the buffer but never used it. I think this will cause a memory leak. Or we can de-allocate it while driver close, not sure how to.
The best way is if we can keep the current implementation, one extra copy is not hurting us as we do it after the read_data API.
==================================================================================
drivers/tty/serial/da8xx_pruss/pruss_suart.c +0 -0
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
s8 flags = TTY_NORMAL;
u16 rx_status, data_len = SUART_FIFO_LEN;
u32 data_len_read;
- u8 suart_data[SUART_FIFO_LEN + 1];
+ u8 *suart_data = NULL;
s32 i = 0;+ s32 alloc_len = 0;
if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
soft_uart->port[uart_no].sysrq = 0;
#endif
} else {
+ alloc_len = tty_prepare_flip_string(tty, &suart_data,
data_len + 1);
pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],- suart_data, data_len + 1,
- &data_len_read);
+ suart_data, alloc_len,
+ &data_len_read);
for (i = 0; i <= data_len_read; i++) {
soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
(&soft_uart->port[uart_no], suart_data))
continue;
}
- /* update the tty data structure */
- tty_insert_flip_string(tty, suart_data, data_len_read);
}============================================================================================
--------------------------------------------------
From: "Alan Cox" <[email protected]>
Sent: Tuesday, February 22, 2011 4:41 PM
To: "Subhasish" <[email protected]>
Cc: <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; <[email protected]>; "Greg Kroah-Hartman" <[email protected]>; "open list" <[email protected]>; "Stalin Srinivasan" <[email protected]>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 48 lines
Quoted 2 lines
we used separate files and hence we decided to keep the code in a separate directory so that the related files can be identified easily.
Fair enough but I would have thought you could drop the two files in the serial directory if they have obviously related names- trivial item/
Quoted 17 lines
Quoted 4 lines
Quoted 12 lines
Quoted 10 lines
(quoted diff) +8
-0+#ifdef __SUART_DEBUG +#define __suart_debug(fmt, args...) \ + printk(KERN_DEBUG "suart_debug: " fmt, ## args) +#else +#define __suart_debug(fmt, args...) +#endif + +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt,##
args)Use dev_dbg/dev_err/pr_debug/pr_err
Quoted 2 lines
SG - did you mean replace the printks above with dev_dgb/err or the suart_dbg/err.
Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you to configure debug levels and the like nicely as well as producing clearer printk info. In some cases with tty code you may not know the device so have to use pr_err/pr_debug etc.
Ok
Quoted 11 lines
Quoted 3 lines
Which is never checked. Far better to use
WARN_ONand the like for such cases - or if like this one they don't appear to be possible to simply delete themSG -- OK, does this look ok ?
=================================
if (h_uart== NULL) {(quoted diff) +2
-1+WARN_ON(1); - return PRU_SUART_ERR_HANDLE_INVALID; +return -EINVAL;}
Yep - the user will now get a backtrace, and in addition kerneloops.org can capture it if that is set up in the distro in use.
Alan
Re: [PATCH v2 13/13] tty: pruss SUART driver
Quoted 8 lines
I tried using a tasklet for the TX part, but that did not help. Another way is to prepare the buffer for the next read and read the data immediately.
Something like this:1. Call
tty_prepare_flip_stringwhile startup.
2. When the read interrupt arrives, read the data immediately.
3. Calltty_prepare_flip_stringfor the next read.
Only you then don't know the size of space required/
Quoted 2 lines
Again, the problem here is that we need to use global variables to store the pre-allocated buffers
You don't. You can store them per port in the existing objects !
Quoted 3 lines
The best way is if we can keep the current implementation, one extra copy is not hurting us
as we do it after theread_dataAPI.
No problem with that at all.