2 * IOSF-SB MailBox Interface Driver
3 * Copyright (c) 2013, Intel Corporation.
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.
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
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 access to this interface for those platforms that can
18 * enumerate the device using PCI.
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/spinlock.h>
24 #include <linux/pci.h>
26 #include <asm/iosf_mbi.h>
28 #define PCI_DEVICE_ID_BAYTRAIL 0x0F00
29 #define PCI_DEVICE_ID_QUARK_X1000 0x0958
31 static DEFINE_SPINLOCK(iosf_mbi_lock
);
33 static inline u32
iosf_mbi_form_mcr(u8 op
, u8 port
, u8 offset
)
35 return (op
<< 24) | (port
<< 16) | (offset
<< 8) | MBI_ENABLE
;
38 static struct pci_dev
*mbi_pdev
; /* one mbi device */
40 static int iosf_mbi_pci_read_mdr(u32 mcrx
, u32 mcr
, u32
*mdr
)
48 result
= pci_write_config_dword(mbi_pdev
, MBI_MCRX_OFFSET
,
54 result
= pci_write_config_dword(mbi_pdev
, MBI_MCR_OFFSET
, mcr
);
58 result
= pci_read_config_dword(mbi_pdev
, MBI_MDR_OFFSET
, mdr
);
65 dev_err(&mbi_pdev
->dev
, "PCI config access failed with %d\n", result
);
69 static int iosf_mbi_pci_write_mdr(u32 mcrx
, u32 mcr
, u32 mdr
)
76 result
= pci_write_config_dword(mbi_pdev
, MBI_MDR_OFFSET
, mdr
);
81 result
= pci_write_config_dword(mbi_pdev
, MBI_MCRX_OFFSET
,
87 result
= pci_write_config_dword(mbi_pdev
, MBI_MCR_OFFSET
, mcr
);
94 dev_err(&mbi_pdev
->dev
, "PCI config access failed with %d\n", result
);
98 int iosf_mbi_read(u8 port
, u8 opcode
, u32 offset
, u32
*mdr
)
104 /*Access to the GFX unit is handled by GPU code */
105 if (port
== BT_MBI_UNIT_GFX
) {
110 mcr
= iosf_mbi_form_mcr(opcode
, port
, offset
& MBI_MASK_LO
);
111 mcrx
= offset
& MBI_MASK_HI
;
113 spin_lock_irqsave(&iosf_mbi_lock
, flags
);
114 ret
= iosf_mbi_pci_read_mdr(mcrx
, mcr
, mdr
);
115 spin_unlock_irqrestore(&iosf_mbi_lock
, flags
);
119 EXPORT_SYMBOL(iosf_mbi_read
);
121 int iosf_mbi_write(u8 port
, u8 opcode
, u32 offset
, u32 mdr
)
127 /*Access to the GFX unit is handled by GPU code */
128 if (port
== BT_MBI_UNIT_GFX
) {
133 mcr
= iosf_mbi_form_mcr(opcode
, port
, offset
& MBI_MASK_LO
);
134 mcrx
= offset
& MBI_MASK_HI
;
136 spin_lock_irqsave(&iosf_mbi_lock
, flags
);
137 ret
= iosf_mbi_pci_write_mdr(mcrx
, mcr
, mdr
);
138 spin_unlock_irqrestore(&iosf_mbi_lock
, flags
);
142 EXPORT_SYMBOL(iosf_mbi_write
);
144 int iosf_mbi_modify(u8 port
, u8 opcode
, u32 offset
, u32 mdr
, u32 mask
)
151 /*Access to the GFX unit is handled by GPU code */
152 if (port
== BT_MBI_UNIT_GFX
) {
157 mcr
= iosf_mbi_form_mcr(opcode
, port
, offset
& MBI_MASK_LO
);
158 mcrx
= offset
& MBI_MASK_HI
;
160 spin_lock_irqsave(&iosf_mbi_lock
, flags
);
162 /* Read current mdr value */
163 ret
= iosf_mbi_pci_read_mdr(mcrx
, mcr
& MBI_RD_MASK
, &value
);
165 spin_unlock_irqrestore(&iosf_mbi_lock
, flags
);
175 ret
= iosf_mbi_pci_write_mdr(mcrx
, mcr
| MBI_WR_MASK
, value
);
177 spin_unlock_irqrestore(&iosf_mbi_lock
, flags
);
181 EXPORT_SYMBOL(iosf_mbi_modify
);
183 bool iosf_mbi_available(void)
185 /* Mbi isn't hot-pluggable. No remove routine is provided */
188 EXPORT_SYMBOL(iosf_mbi_available
);
190 static int iosf_mbi_probe(struct pci_dev
*pdev
,
191 const struct pci_device_id
*unused
)
195 ret
= pci_enable_device(pdev
);
197 dev_err(&pdev
->dev
, "error: could not enable device\n");
201 mbi_pdev
= pci_dev_get(pdev
);
205 static const struct pci_device_id iosf_mbi_pci_ids
[] = {
206 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_BAYTRAIL
) },
207 { PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_QUARK_X1000
) },
210 MODULE_DEVICE_TABLE(pci
, iosf_mbi_pci_ids
);
212 static struct pci_driver iosf_mbi_pci_driver
= {
213 .name
= "iosf_mbi_pci",
214 .probe
= iosf_mbi_probe
,
215 .id_table
= iosf_mbi_pci_ids
,
218 static int __init
iosf_mbi_init(void)
220 return pci_register_driver(&iosf_mbi_pci_driver
);
223 static void __exit
iosf_mbi_exit(void)
225 pci_unregister_driver(&iosf_mbi_pci_driver
);
227 pci_dev_put(mbi_pdev
);
232 module_init(iosf_mbi_init
);
233 module_exit(iosf_mbi_exit
);
235 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
236 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
237 MODULE_LICENSE("GPL v2");