summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2017-06-06 08:25:12 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-06-09 05:42:43 -0400
commitcd446ee2e64f03d0e3d8463bf826aaebe0005149 (patch)
tree5fa90c371477035544b1909485d9108c10ccd828 /drivers/thunderbolt
parent5e2781bcb1e876d314832489ff8177ef917d9b45 (diff)
thunderbolt: Add support for NHI mailbox
The host controller includes two sets of registers that are used to communicate with the firmware. Add functions that can be used to access these registers. This code is based on the work done by Amir Levy and Michael Jamet. Signed-off-by: Michael Jamet <michael.jamet@intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Andreas Noever <andreas.noever@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/thunderbolt')
-rw-r--r--drivers/thunderbolt/nhi.c58
-rw-r--r--drivers/thunderbolt/nhi.h16
-rw-r--r--drivers/thunderbolt/nhi_regs.h11
3 files changed, 85 insertions, 0 deletions
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index fa4c2745dba2..c358c074f925 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -14,6 +14,7 @@
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/dmi.h> 16#include <linux/dmi.h>
17#include <linux/delay.h>
17 18
18#include "nhi.h" 19#include "nhi.h"
19#include "nhi_regs.h" 20#include "nhi_regs.h"
@@ -28,6 +29,8 @@
28#define MSIX_MIN_VECS 6 29#define MSIX_MIN_VECS 6
29#define MSIX_MAX_VECS 16 30#define MSIX_MAX_VECS 16
30 31
32#define NHI_MAILBOX_TIMEOUT 500 /* ms */
33
31static int ring_interrupt_index(struct tb_ring *ring) 34static int ring_interrupt_index(struct tb_ring *ring)
32{ 35{
33 int bit = ring->hop; 36 int bit = ring->hop;
@@ -525,6 +528,61 @@ void ring_free(struct tb_ring *ring)
525 kfree(ring); 528 kfree(ring);
526} 529}
527 530
531/**
532 * nhi_mailbox_cmd() - Send a command through NHI mailbox
533 * @nhi: Pointer to the NHI structure
534 * @cmd: Command to send
535 * @data: Data to be send with the command
536 *
537 * Sends mailbox command to the firmware running on NHI. Returns %0 in
538 * case of success and negative errno in case of failure.
539 */
540int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data)
541{
542 ktime_t timeout;
543 u32 val;
544
545 iowrite32(data, nhi->iobase + REG_INMAIL_DATA);
546
547 val = ioread32(nhi->iobase + REG_INMAIL_CMD);
548 val &= ~(REG_INMAIL_CMD_MASK | REG_INMAIL_ERROR);
549 val |= REG_INMAIL_OP_REQUEST | cmd;
550 iowrite32(val, nhi->iobase + REG_INMAIL_CMD);
551
552 timeout = ktime_add_ms(ktime_get(), NHI_MAILBOX_TIMEOUT);
553 do {
554 val = ioread32(nhi->iobase + REG_INMAIL_CMD);
555 if (!(val & REG_INMAIL_OP_REQUEST))
556 break;
557 usleep_range(10, 20);
558 } while (ktime_before(ktime_get(), timeout));
559
560 if (val & REG_INMAIL_OP_REQUEST)
561 return -ETIMEDOUT;
562 if (val & REG_INMAIL_ERROR)
563 return -EIO;
564
565 return 0;
566}
567
568/**
569 * nhi_mailbox_mode() - Return current firmware operation mode
570 * @nhi: Pointer to the NHI structure
571 *
572 * The function reads current firmware operation mode using NHI mailbox
573 * registers and returns it to the caller.
574 */
575enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi)
576{
577 u32 val;
578
579 val = ioread32(nhi->iobase + REG_OUTMAIL_CMD);
580 val &= REG_OUTMAIL_CMD_OPMODE_MASK;
581 val >>= REG_OUTMAIL_CMD_OPMODE_SHIFT;
582
583 return (enum nhi_fw_mode)val;
584}
585
528static void nhi_interrupt_work(struct work_struct *work) 586static void nhi_interrupt_work(struct work_struct *work)
529{ 587{
530 struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work); 588 struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work);
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 8bd9b4e5a0b1..446ff6dac91d 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -143,6 +143,22 @@ static inline int ring_tx(struct tb_ring *ring, struct ring_frame *frame)
143 return __ring_enqueue(ring, frame); 143 return __ring_enqueue(ring, frame);
144} 144}
145 145
146enum nhi_fw_mode {
147 NHI_FW_SAFE_MODE,
148 NHI_FW_AUTH_MODE,
149 NHI_FW_EP_MODE,
150 NHI_FW_CM_MODE,
151};
152
153enum nhi_mailbox_cmd {
154 NHI_MAILBOX_SAVE_DEVS = 0x05,
155 NHI_MAILBOX_DRV_UNLOADS = 0x07,
156 NHI_MAILBOX_ALLOW_ALL_DEVS = 0x23,
157};
158
159int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data);
160enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi);
161
146/* 162/*
147 * PCI IDs used in this driver from Win Ridge forward. There is no 163 * PCI IDs used in this driver from Win Ridge forward. There is no
148 * need for the PCI quirk anymore as we will use ICM also on Apple 164 * need for the PCI quirk anymore as we will use ICM also on Apple
diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h
index 48b98d3c7e6a..322fe1fa3a3c 100644
--- a/drivers/thunderbolt/nhi_regs.h
+++ b/drivers/thunderbolt/nhi_regs.h
@@ -107,4 +107,15 @@ struct ring_desc {
107#define REG_DMA_MISC 0x39864 107#define REG_DMA_MISC 0x39864
108#define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2) 108#define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2)
109 109
110#define REG_INMAIL_DATA 0x39900
111
112#define REG_INMAIL_CMD 0x39904
113#define REG_INMAIL_CMD_MASK GENMASK(7, 0)
114#define REG_INMAIL_ERROR BIT(30)
115#define REG_INMAIL_OP_REQUEST BIT(31)
116
117#define REG_OUTMAIL_CMD 0x3990c
118#define REG_OUTMAIL_CMD_OPMODE_SHIFT 8
119#define REG_OUTMAIL_CMD_OPMODE_MASK GENMASK(11, 8)
120
110#endif 121#endif