aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid E. Box <david.e.box@linux.intel.com>2013-12-19 13:37:22 -0500
committerMatthew Garrett <matthew.garrett@nebula.com>2014-01-21 08:44:17 -0500
commit997ab407d2b4e7d7ce2788d2de68435eb94fcfec (patch)
tree52defddea0b41a79b9dd3ad75cb07227d75959ce
parent475879d65123eaf0b1490d603c4a4f5faac4179d (diff)
X86 platform: New BayTrail IOSF-SB MBI driver
Current Intel SOC cores use a MailBox Interface (MBI) to provide access to unit devices connected to the system fabric. This driver implements access to this interface on BayTrail platforms. This is a requirement for drivers that need access to unit registers on the platform (e.g. accessing the PUNIT for power management features such as RAPL). Serialized access is handled by all exported routines with spinlocks. The API includes 3 functions for access to unit registers: int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr) int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr) int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask) port: indicating the unit being accessed opcode: the read or write port specific opcode offset: the register offset within the port mdr: the register data to be read, written, or modified mask: bit locations in mdr to change Returns nonzero on error Note: GPU code handles access to the GFX unit. Therefore access to that unit with this driver is disallowed to avoid conflicts. Signed-off-by: David E. Box <david.e.box@linux.intel.com> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
-rw-r--r--drivers/platform/x86/Kconfig8
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/intel_baytrail.c224
-rw-r--r--drivers/platform/x86/intel_baytrail.h90
4 files changed, 323 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index d9dcd37b5a52..a698b928327d 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -808,4 +808,12 @@ config PVPANIC
808 a paravirtualized device provided by QEMU; it lets a virtual machine 808 a paravirtualized device provided by QEMU; it lets a virtual machine
809 (guest) communicate panic events to the host. 809 (guest) communicate panic events to the host.
810 810
811config INTEL_BAYTRAIL_MBI
812 tristate
813 depends on PCI
814 ---help---
815 Needed on Baytrail platforms for access to the IOSF Sideband Mailbox
816 Interface. This is a requirement for systems that need to configure
817 the PUNIT for power management features such as RAPL.
818
811endif # X86_PLATFORM_DEVICES 819endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index f0e6aa407ffb..79bd3c49be3d 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_INTEL_RST) += intel-rst.o
54obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o 54obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
55 55
56obj-$(CONFIG_PVPANIC) += pvpanic.o 56obj-$(CONFIG_PVPANIC) += pvpanic.o
57obj-$(CONFIG_INTEL_BAYTRAIL_MBI) += intel_baytrail.o
diff --git a/drivers/platform/x86/intel_baytrail.c b/drivers/platform/x86/intel_baytrail.c
new file mode 100644
index 000000000000..f96626b17260
--- /dev/null
+++ b/drivers/platform/x86/intel_baytrail.c
@@ -0,0 +1,224 @@
1/*
2 * Baytrail IOSF-SB MailBox Interface Driver
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *
15 * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a
16 * mailbox interface (MBI) to communicate with mutiple devices. This
17 * driver implements BayTrail-specific access to this interface.
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/spinlock.h>
23#include <linux/pci.h>
24
25#include "intel_baytrail.h"
26
27static DEFINE_SPINLOCK(iosf_mbi_lock);
28
29static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
30{
31 return (op << 24) | (port << 16) | (offset << 8) | BT_MBI_ENABLE;
32}
33
34static struct pci_dev *mbi_pdev; /* one mbi device */
35
36/* Hold lock before calling */
37static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
38{
39 int result;
40
41 if (!mbi_pdev)
42 return -ENODEV;
43
44 if (mcrx) {
45 result = pci_write_config_dword(mbi_pdev,
46 BT_MBI_MCRX_OFFSET, mcrx);
47 if (result < 0)
48 goto iosf_mbi_read_err;
49 }
50
51 result = pci_write_config_dword(mbi_pdev,
52 BT_MBI_MCR_OFFSET, mcr);
53 if (result < 0)
54 goto iosf_mbi_read_err;
55
56 result = pci_read_config_dword(mbi_pdev,
57 BT_MBI_MDR_OFFSET, mdr);
58 if (result < 0)
59 goto iosf_mbi_read_err;
60
61 return 0;
62
63iosf_mbi_read_err:
64 dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
65 result);
66 return result;
67}
68
69/* Hold lock before calling */
70static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
71{
72 int result;
73
74 if (!mbi_pdev)
75 return -ENODEV;
76
77 result = pci_write_config_dword(mbi_pdev,
78 BT_MBI_MDR_OFFSET, mdr);
79 if (result < 0)
80 goto iosf_mbi_write_err;
81
82 if (mcrx) {
83 result = pci_write_config_dword(mbi_pdev,
84 BT_MBI_MCRX_OFFSET, mcrx);
85 if (result < 0)
86 goto iosf_mbi_write_err;
87 }
88
89 result = pci_write_config_dword(mbi_pdev,
90 BT_MBI_MCR_OFFSET, mcr);
91 if (result < 0)
92 goto iosf_mbi_write_err;
93
94 return 0;
95
96iosf_mbi_write_err:
97 dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
98 result);
99 return result;
100}
101
102int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
103{
104 u32 mcr, mcrx;
105 unsigned long flags;
106 int ret;
107
108 /*Access to the GFX unit is handled by GPU code */
109 BUG_ON(port == BT_MBI_UNIT_GFX);
110
111 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
112 mcrx = offset & BT_MBI_MASK_HI;
113
114 spin_lock_irqsave(&iosf_mbi_lock, flags);
115 ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
116 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
117
118 return ret;
119}
120EXPORT_SYMBOL(bt_mbi_read);
121
122int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
123{
124 u32 mcr, mcrx;
125 unsigned long flags;
126 int ret;
127
128 /*Access to the GFX unit is handled by GPU code */
129 BUG_ON(port == BT_MBI_UNIT_GFX);
130
131 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
132 mcrx = offset & BT_MBI_MASK_HI;
133
134 spin_lock_irqsave(&iosf_mbi_lock, flags);
135 ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
136 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
137
138 return ret;
139}
140EXPORT_SYMBOL(bt_mbi_write);
141
142int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
143{
144 u32 mcr, mcrx;
145 u32 value;
146 unsigned long flags;
147 int ret;
148
149 /*Access to the GFX unit is handled by GPU code */
150 BUG_ON(port == BT_MBI_UNIT_GFX);
151
152 mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
153 mcrx = offset & BT_MBI_MASK_HI;
154
155 spin_lock_irqsave(&iosf_mbi_lock, flags);
156
157 /* Read current mdr value */
158 ret = iosf_mbi_pci_read_mdr(mcrx, mcr & BT_MBI_RD_MASK, &value);
159 if (ret < 0) {
160 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
161 return ret;
162 }
163
164 /* Apply mask */
165 value &= ~mask;
166 mdr &= mask;
167 value |= mdr;
168
169 /* Write back */
170 ret = iosf_mbi_pci_write_mdr(mcrx, mcr | BT_MBI_WR_MASK, value);
171
172 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
173
174 return ret;
175}
176EXPORT_SYMBOL(bt_mbi_modify);
177
178static int iosf_mbi_probe(struct pci_dev *pdev,
179 const struct pci_device_id *unused)
180{
181 int ret;
182
183 ret = pci_enable_device(pdev);
184 if (ret < 0) {
185 dev_err(&pdev->dev, "error: could not enable device\n");
186 return ret;
187 }
188
189 mbi_pdev = pci_dev_get(pdev);
190 return 0;
191}
192
193static DEFINE_PCI_DEVICE_TABLE(iosf_mbi_pci_ids) = {
194 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F00) },
195 { 0, },
196};
197MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
198
199static struct pci_driver iosf_mbi_pci_driver = {
200 .name = "iosf_mbi_pci",
201 .probe = iosf_mbi_probe,
202 .id_table = iosf_mbi_pci_ids,
203};
204
205static int __init bt_mbi_init(void)
206{
207 return pci_register_driver(&iosf_mbi_pci_driver);
208}
209
210static void __exit bt_mbi_exit(void)
211{
212 pci_unregister_driver(&iosf_mbi_pci_driver);
213 if (mbi_pdev) {
214 pci_dev_put(mbi_pdev);
215 mbi_pdev = NULL;
216 }
217}
218
219module_init(bt_mbi_init);
220module_exit(bt_mbi_exit);
221
222MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
223MODULE_DESCRIPTION("BayTrail Mailbox Interface accessor");
224MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_baytrail.h b/drivers/platform/x86/intel_baytrail.h
new file mode 100644
index 000000000000..8bcc311262e9
--- /dev/null
+++ b/drivers/platform/x86/intel_baytrail.h
@@ -0,0 +1,90 @@
1/*
2 * intel_baytrail.h: MailBox access support for Intel BayTrail platforms
3 */
4
5#ifndef INTEL_BAYTRAIL_MBI_SYMS_H
6#define INTEL_BAYTRAIL_MBI_SYMS_H
7
8#define BT_MBI_MCR_OFFSET 0xD0
9#define BT_MBI_MDR_OFFSET 0xD4
10#define BT_MBI_MCRX_OFFSET 0xD8
11
12#define BT_MBI_RD_MASK 0xFEFFFFFF
13#define BT_MBI_WR_MASK 0X01000000
14
15#define BT_MBI_MASK_HI 0xFFFFFF00
16#define BT_MBI_MASK_LO 0x000000FF
17#define BT_MBI_ENABLE 0xF0
18
19/* BT-SB unit access methods */
20#define BT_MBI_UNIT_AUNIT 0x00
21#define BT_MBI_UNIT_SMC 0x01
22#define BT_MBI_UNIT_CPU 0x02
23#define BT_MBI_UNIT_BUNIT 0x03
24#define BT_MBI_UNIT_PMC 0x04
25#define BT_MBI_UNIT_GFX 0x06
26#define BT_MBI_UNIT_SMI 0x0C
27#define BT_MBI_UNIT_USB 0x43
28#define BT_MBI_UNIT_SATA 0xA3
29#define BT_MBI_UNIT_PCIE 0xA6
30
31/* Read/write opcodes */
32#define BT_MBI_AUNIT_READ 0x10
33#define BT_MBI_AUNIT_WRITE 0x11
34#define BT_MBI_SMC_READ 0x10
35#define BT_MBI_SMC_WRITE 0x11
36#define BT_MBI_CPU_READ 0x10
37#define BT_MBI_CPU_WRITE 0x11
38#define BT_MBI_BUNIT_READ 0x10
39#define BT_MBI_BUNIT_WRITE 0x11
40#define BT_MBI_PMC_READ 0x06
41#define BT_MBI_PMC_WRITE 0x07
42#define BT_MBI_GFX_READ 0x00
43#define BT_MBI_GFX_WRITE 0x01
44#define BT_MBI_SMIO_READ 0x06
45#define BT_MBI_SMIO_WRITE 0x07
46#define BT_MBI_USB_READ 0x06
47#define BT_MBI_USB_WRITE 0x07
48#define BT_MBI_SATA_READ 0x00
49#define BT_MBI_SATA_WRITE 0x01
50#define BT_MBI_PCIE_READ 0x00
51#define BT_MBI_PCIE_WRITE 0x01
52
53/**
54 * bt_mbi_read() - MailBox Interface read command
55 * @port: port indicating subunit being accessed
56 * @opcode: port specific read or write opcode
57 * @offset: register address offset
58 * @mdr: register data to be read
59 *
60 * Locking is handled by spinlock - cannot sleep.
61 * Return: Nonzero on error
62 */
63int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr);
64
65/**
66 * bt_mbi_write() - MailBox unmasked write command
67 * @port: port indicating subunit being accessed
68 * @opcode: port specific read or write opcode
69 * @offset: register address offset
70 * @mdr: register data to be written
71 *
72 * Locking is handled by spinlock - cannot sleep.
73 * Return: Nonzero on error
74 */
75int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr);
76
77/**
78 * bt_mbi_modify() - MailBox masked write command
79 * @port: port indicating subunit being accessed
80 * @opcode: port specific read or write opcode
81 * @offset: register address offset
82 * @mdr: register data being modified
83 * @mask: mask indicating bits in mdr to be modified
84 *
85 * Locking is handled by spinlock - cannot sleep.
86 * Return: Nonzero on error
87 */
88int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
89
90#endif /* INTEL_BAYTRAIL_MBI_SYMS_H */