Re: [PATCH v3 5/8] mailbox: tegra-hsp: Add support for shared mailboxes

2018-07-02 Thread Thierry Reding
On Mon, Jul 02, 2018 at 02:40:30PM +0300, Mikko Perttunen wrote:
> The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
> registers consisting of a FULL bit in MSB position and 31 bits of data.
> The hardware can be configured to trigger interrupts when a mailbox
> is empty or full. Add support for these shared mailboxes to the HSP
> driver.
> 
> The initial use for the mailboxes is the Tegra Combined UART. For this
> purpose, we use interrupts to receive data, and spinning to wait for
> the transmit mailbox to be emptied to minimize unnecessary overhead.
> 
> Signed-off-by: Mikko Perttunen 
> Reviewed-by: Jon Hunter 
> ---
> 
> Notes:
> v3:
> - Added define HSP_INT0_IE_FULL_SHIFT
> - Added Jon's Reviewed-by
> 
> v2:
> - Added defines for some register fields
> - Simplified bit looping logic in interrupt handler
> - Changed write done polling to use readl_poll_timeout
> - Removed unnecessary zero assignments
> - Fixed two error cases in probe to do proper cleanup
> 
>  drivers/mailbox/tegra-hsp.c | 211 
> +++-
>  1 file changed, 191 insertions(+), 20 deletions(-)

Looks good to me:

Acked-by: Thierry Reding 


signature.asc
Description: PGP signature


[PATCH v3 5/8] mailbox: tegra-hsp: Add support for shared mailboxes

2018-07-02 Thread Mikko Perttunen
The Tegra HSP block supports 'shared mailboxes' that are simple 32-bit
registers consisting of a FULL bit in MSB position and 31 bits of data.
The hardware can be configured to trigger interrupts when a mailbox
is empty or full. Add support for these shared mailboxes to the HSP
driver.

The initial use for the mailboxes is the Tegra Combined UART. For this
purpose, we use interrupts to receive data, and spinning to wait for
the transmit mailbox to be emptied to minimize unnecessary overhead.

Signed-off-by: Mikko Perttunen 
Reviewed-by: Jon Hunter 
---

Notes:
v3:
- Added define HSP_INT0_IE_FULL_SHIFT
- Added Jon's Reviewed-by

v2:
- Added defines for some register fields
- Simplified bit looping logic in interrupt handler
- Changed write done polling to use readl_poll_timeout
- Removed unnecessary zero assignments
- Fixed two error cases in probe to do proper cleanup

 drivers/mailbox/tegra-hsp.c | 211 +++-
 1 file changed, 191 insertions(+), 20 deletions(-)

diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 5dc21a6d01bb..e0e238287502 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -13,6 +13,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,6 +22,14 @@
 
 #include 
 
+#include "mailbox.h"
+
+#define HSP_INT0_IE0x100
+#define HSP_INT0_IE_FULL_SHIFT 8
+#define HSP_INT_IR 0x304
+#define HSP_INT_IR_FULL_SHIFT  8
+#define HSP_INT_IR_FULL_MASK   0xff
+
 #define HSP_INT_DIMENSIONING   0x380
 #define HSP_nSM_SHIFT  0
 #define HSP_nSS_SHIFT  4
@@ -34,6 +43,9 @@
 #define HSP_DB_RAW 0x8
 #define HSP_DB_PENDING 0xc
 
+#define HSP_SM_SHRD_MBOX   0x0
+#define HSP_SM_SHRD_MBOX_FULL  BIT(31)
+
 #define HSP_DB_CCPLEX  1
 #define HSP_DB_BPMP3
 #define HSP_DB_MAX 7
@@ -68,6 +80,18 @@ struct tegra_hsp_db_map {
unsigned int index;
 };
 
+struct tegra_hsp_mailbox {
+   struct tegra_hsp_channel channel;
+   unsigned int index;
+   bool sending;
+};
+
+static inline struct tegra_hsp_mailbox *
+channel_to_mailbox(struct tegra_hsp_channel *channel)
+{
+   return container_of(channel, struct tegra_hsp_mailbox, channel);
+}
+
 struct tegra_hsp_soc {
const struct tegra_hsp_db_map *map;
 };
@@ -77,6 +101,7 @@ struct tegra_hsp {
struct mbox_controller mbox;
void __iomem *regs;
unsigned int doorbell_irq;
+   unsigned int shared_irq;
unsigned int num_sm;
unsigned int num_as;
unsigned int num_ss;
@@ -85,6 +110,7 @@ struct tegra_hsp {
spinlock_t lock;
 
struct list_head doorbells;
+   struct tegra_hsp_mailbox *mailboxes;
 };
 
 static inline struct tegra_hsp *
@@ -189,6 +215,33 @@ static irqreturn_t tegra_hsp_doorbell_irq(int irq, void 
*data)
return IRQ_HANDLED;
 }
 
+static irqreturn_t tegra_hsp_shared_irq(int irq, void *data)
+{
+   struct tegra_hsp_mailbox *mb;
+   struct tegra_hsp *hsp = data;
+   unsigned long bit, mask;
+   u32 value;
+
+   mask = tegra_hsp_readl(hsp, HSP_INT_IR);
+   /* Only interested in FULL interrupts */
+   mask = (mask >> HSP_INT_IR_FULL_SHIFT) & HSP_INT_IR_FULL_MASK;
+
+   for_each_set_bit(bit, &mask, 8) {
+   mb = &hsp->mailboxes[bit];
+
+   if (!mb->sending) {
+   value = tegra_hsp_channel_readl(&mb->channel,
+   HSP_SM_SHRD_MBOX);
+   value &= ~HSP_SM_SHRD_MBOX_FULL;
+   mbox_chan_received_data(mb->channel.chan, &value);
+   tegra_hsp_channel_writel(&mb->channel, value,
+HSP_SM_SHRD_MBOX);
+   }
+   }
+
+   return IRQ_HANDLED;
+}
+
 static struct tegra_hsp_channel *
 tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
  unsigned int master, unsigned int index)
@@ -277,14 +330,57 @@ static void tegra_hsp_doorbell_shutdown(struct 
tegra_hsp_doorbell *db)
spin_unlock_irqrestore(&hsp->lock, flags);
 }
 
+static int tegra_hsp_mailbox_startup(struct tegra_hsp_mailbox *mb)
+{
+   struct tegra_hsp *hsp = mb->channel.hsp;
+   u32 value;
+
+   mb->channel.chan->txdone_method = TXDONE_BY_BLOCK;
+
+   /* Route FULL interrupt to external IRQ 0 */
+   value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+   value |= BIT(HSP_INT0_IE_FULL_SHIFT + mb->index);
+   tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+   return 0;
+}
+
+static int tegra_hsp_mailbox_shutdown(struct tegra_hsp_mailbox *mb)
+{
+   struct tegra_hsp *hsp = mb->channel.hsp;
+   u32 value;
+
+   value = tegra_hsp_readl(hsp, HSP_INT0_IE);
+   value &= ~BIT(mb->index + 8);
+   tegra_hsp_writel(hsp, value, HSP_INT0_IE);
+
+   return 0;
+}
+
 static int tegra_hsp_sen