0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/delay.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/pci.h>
0017 #include <linux/debugfs.h>
0018 #include <linux/capability.h>
0019 #include <linux/pm_qos.h>
0020 #include <linux/wait.h>
0021
0022 #include <asm/iosf_mbi.h>
0023
0024 #define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00
0025 #define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280
0026 #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958
0027 #define PCI_DEVICE_ID_INTEL_TANGIER 0x1170
0028
0029 static struct pci_dev *mbi_pdev;
0030 static DEFINE_SPINLOCK(iosf_mbi_lock);
0031
0032
0033
0034 static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
0035 {
0036 return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE;
0037 }
0038
0039 static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
0040 {
0041 int result;
0042
0043 if (!mbi_pdev)
0044 return -ENODEV;
0045
0046 if (mcrx) {
0047 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
0048 mcrx);
0049 if (result < 0)
0050 goto fail_read;
0051 }
0052
0053 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
0054 if (result < 0)
0055 goto fail_read;
0056
0057 result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
0058 if (result < 0)
0059 goto fail_read;
0060
0061 return 0;
0062
0063 fail_read:
0064 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
0065 return result;
0066 }
0067
0068 static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
0069 {
0070 int result;
0071
0072 if (!mbi_pdev)
0073 return -ENODEV;
0074
0075 result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
0076 if (result < 0)
0077 goto fail_write;
0078
0079 if (mcrx) {
0080 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
0081 mcrx);
0082 if (result < 0)
0083 goto fail_write;
0084 }
0085
0086 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
0087 if (result < 0)
0088 goto fail_write;
0089
0090 return 0;
0091
0092 fail_write:
0093 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
0094 return result;
0095 }
0096
0097 int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
0098 {
0099 u32 mcr, mcrx;
0100 unsigned long flags;
0101 int ret;
0102
0103
0104 if (port == BT_MBI_UNIT_GFX) {
0105 WARN_ON(1);
0106 return -EPERM;
0107 }
0108
0109 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0110 mcrx = offset & MBI_MASK_HI;
0111
0112 spin_lock_irqsave(&iosf_mbi_lock, flags);
0113 ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
0114 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0115
0116 return ret;
0117 }
0118 EXPORT_SYMBOL(iosf_mbi_read);
0119
0120 int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
0121 {
0122 u32 mcr, mcrx;
0123 unsigned long flags;
0124 int ret;
0125
0126
0127 if (port == BT_MBI_UNIT_GFX) {
0128 WARN_ON(1);
0129 return -EPERM;
0130 }
0131
0132 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0133 mcrx = offset & MBI_MASK_HI;
0134
0135 spin_lock_irqsave(&iosf_mbi_lock, flags);
0136 ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
0137 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0138
0139 return ret;
0140 }
0141 EXPORT_SYMBOL(iosf_mbi_write);
0142
0143 int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
0144 {
0145 u32 mcr, mcrx;
0146 u32 value;
0147 unsigned long flags;
0148 int ret;
0149
0150
0151 if (port == BT_MBI_UNIT_GFX) {
0152 WARN_ON(1);
0153 return -EPERM;
0154 }
0155
0156 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0157 mcrx = offset & MBI_MASK_HI;
0158
0159 spin_lock_irqsave(&iosf_mbi_lock, flags);
0160
0161
0162 ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value);
0163 if (ret < 0) {
0164 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0165 return ret;
0166 }
0167
0168
0169 value &= ~mask;
0170 mdr &= mask;
0171 value |= mdr;
0172
0173
0174 ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value);
0175
0176 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0177
0178 return ret;
0179 }
0180 EXPORT_SYMBOL(iosf_mbi_modify);
0181
0182 bool iosf_mbi_available(void)
0183 {
0184
0185 return mbi_pdev;
0186 }
0187 EXPORT_SYMBOL(iosf_mbi_available);
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 #define SEMAPHORE_TIMEOUT 500
0200 #define PUNIT_SEMAPHORE_BYT 0x7
0201 #define PUNIT_SEMAPHORE_CHT 0x10e
0202 #define PUNIT_SEMAPHORE_BIT BIT(0)
0203 #define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
0204
0205 static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex);
0206 static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
0207 static DECLARE_WAIT_QUEUE_HEAD(iosf_mbi_pmic_access_waitq);
0208 static u32 iosf_mbi_pmic_punit_access_count;
0209 static u32 iosf_mbi_pmic_i2c_access_count;
0210 static u32 iosf_mbi_sem_address;
0211 static unsigned long iosf_mbi_sem_acquired;
0212 static struct pm_qos_request iosf_mbi_pm_qos;
0213
0214 void iosf_mbi_punit_acquire(void)
0215 {
0216
0217 mutex_lock(&iosf_mbi_pmic_access_mutex);
0218 while (iosf_mbi_pmic_i2c_access_count != 0) {
0219 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0220 wait_event(iosf_mbi_pmic_access_waitq,
0221 iosf_mbi_pmic_i2c_access_count == 0);
0222 mutex_lock(&iosf_mbi_pmic_access_mutex);
0223 }
0224
0225
0226
0227
0228 iosf_mbi_pmic_punit_access_count++;
0229 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0230 }
0231 EXPORT_SYMBOL(iosf_mbi_punit_acquire);
0232
0233 void iosf_mbi_punit_release(void)
0234 {
0235 bool do_wakeup;
0236
0237 mutex_lock(&iosf_mbi_pmic_access_mutex);
0238 iosf_mbi_pmic_punit_access_count--;
0239 do_wakeup = iosf_mbi_pmic_punit_access_count == 0;
0240 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0241
0242 if (do_wakeup)
0243 wake_up(&iosf_mbi_pmic_access_waitq);
0244 }
0245 EXPORT_SYMBOL(iosf_mbi_punit_release);
0246
0247 static int iosf_mbi_get_sem(u32 *sem)
0248 {
0249 int ret;
0250
0251 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
0252 iosf_mbi_sem_address, sem);
0253 if (ret) {
0254 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n");
0255 return ret;
0256 }
0257
0258 *sem &= PUNIT_SEMAPHORE_BIT;
0259 return 0;
0260 }
0261
0262 static void iosf_mbi_reset_semaphore(void)
0263 {
0264 if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ,
0265 iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
0266 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
0267
0268 cpu_latency_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
0269
0270 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
0271 MBI_PMIC_BUS_ACCESS_END, NULL);
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312 int iosf_mbi_block_punit_i2c_access(void)
0313 {
0314 unsigned long start, end;
0315 int ret = 0;
0316 u32 sem;
0317
0318 if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address))
0319 return -ENXIO;
0320
0321 mutex_lock(&iosf_mbi_pmic_access_mutex);
0322
0323 while (iosf_mbi_pmic_punit_access_count != 0) {
0324 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0325 wait_event(iosf_mbi_pmic_access_waitq,
0326 iosf_mbi_pmic_punit_access_count == 0);
0327 mutex_lock(&iosf_mbi_pmic_access_mutex);
0328 }
0329
0330 if (iosf_mbi_pmic_i2c_access_count > 0)
0331 goto success;
0332
0333 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
0334 MBI_PMIC_BUS_ACCESS_BEGIN, NULL);
0335
0336
0337
0338
0339
0340
0341 cpu_latency_qos_update_request(&iosf_mbi_pm_qos, 0);
0342
0343
0344 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
0345 iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE);
0346 if (ret) {
0347 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n");
0348 goto error;
0349 }
0350
0351
0352 start = jiffies;
0353 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
0354 do {
0355 ret = iosf_mbi_get_sem(&sem);
0356 if (!ret && sem) {
0357 iosf_mbi_sem_acquired = jiffies;
0358 dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n",
0359 jiffies_to_msecs(jiffies - start));
0360 goto success;
0361 }
0362
0363 usleep_range(1000, 2000);
0364 } while (time_before(jiffies, end));
0365
0366 ret = -ETIMEDOUT;
0367 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n");
0368 error:
0369 iosf_mbi_reset_semaphore();
0370 if (!iosf_mbi_get_sem(&sem))
0371 dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
0372 success:
0373 if (!WARN_ON(ret))
0374 iosf_mbi_pmic_i2c_access_count++;
0375
0376 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0377
0378 return ret;
0379 }
0380 EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
0381
0382 void iosf_mbi_unblock_punit_i2c_access(void)
0383 {
0384 bool do_wakeup = false;
0385
0386 mutex_lock(&iosf_mbi_pmic_access_mutex);
0387 iosf_mbi_pmic_i2c_access_count--;
0388 if (iosf_mbi_pmic_i2c_access_count == 0) {
0389 iosf_mbi_reset_semaphore();
0390 dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n",
0391 jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired));
0392 do_wakeup = true;
0393 }
0394 mutex_unlock(&iosf_mbi_pmic_access_mutex);
0395
0396 if (do_wakeup)
0397 wake_up(&iosf_mbi_pmic_access_waitq);
0398 }
0399 EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
0400
0401 int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
0402 {
0403 int ret;
0404
0405
0406 iosf_mbi_punit_acquire();
0407 ret = blocking_notifier_chain_register(
0408 &iosf_mbi_pmic_bus_access_notifier, nb);
0409 iosf_mbi_punit_release();
0410
0411 return ret;
0412 }
0413 EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
0414
0415 int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
0416 struct notifier_block *nb)
0417 {
0418 iosf_mbi_assert_punit_acquired();
0419
0420 return blocking_notifier_chain_unregister(
0421 &iosf_mbi_pmic_bus_access_notifier, nb);
0422 }
0423 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked);
0424
0425 int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
0426 {
0427 int ret;
0428
0429
0430 iosf_mbi_punit_acquire();
0431 ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb);
0432 iosf_mbi_punit_release();
0433
0434 return ret;
0435 }
0436 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
0437
0438 void iosf_mbi_assert_punit_acquired(void)
0439 {
0440 WARN_ON(iosf_mbi_pmic_punit_access_count == 0);
0441 }
0442 EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
0443
0444
0445
0446 #ifdef CONFIG_IOSF_MBI_DEBUG
0447 static u32 dbg_mdr;
0448 static u32 dbg_mcr;
0449 static u32 dbg_mcrx;
0450
0451 static int mcr_get(void *data, u64 *val)
0452 {
0453 *val = *(u32 *)data;
0454 return 0;
0455 }
0456
0457 static int mcr_set(void *data, u64 val)
0458 {
0459 u8 command = ((u32)val & 0xFF000000) >> 24,
0460 port = ((u32)val & 0x00FF0000) >> 16,
0461 offset = ((u32)val & 0x0000FF00) >> 8;
0462 int err;
0463
0464 *(u32 *)data = val;
0465
0466 if (!capable(CAP_SYS_RAWIO))
0467 return -EACCES;
0468
0469 if (command & 1u)
0470 err = iosf_mbi_write(port,
0471 command,
0472 dbg_mcrx | offset,
0473 dbg_mdr);
0474 else
0475 err = iosf_mbi_read(port,
0476 command,
0477 dbg_mcrx | offset,
0478 &dbg_mdr);
0479
0480 return err;
0481 }
0482 DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n");
0483
0484 static struct dentry *iosf_dbg;
0485
0486 static void iosf_sideband_debug_init(void)
0487 {
0488 iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
0489
0490
0491 debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
0492
0493
0494 debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
0495
0496
0497 debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
0498 }
0499
0500 static void iosf_debugfs_init(void)
0501 {
0502 iosf_sideband_debug_init();
0503 }
0504
0505 static void iosf_debugfs_remove(void)
0506 {
0507 debugfs_remove_recursive(iosf_dbg);
0508 }
0509 #else
0510 static inline void iosf_debugfs_init(void) { }
0511 static inline void iosf_debugfs_remove(void) { }
0512 #endif
0513
0514 static int iosf_mbi_probe(struct pci_dev *pdev,
0515 const struct pci_device_id *dev_id)
0516 {
0517 int ret;
0518
0519 ret = pci_enable_device(pdev);
0520 if (ret < 0) {
0521 dev_err(&pdev->dev, "error: could not enable device\n");
0522 return ret;
0523 }
0524
0525 mbi_pdev = pci_dev_get(pdev);
0526 iosf_mbi_sem_address = dev_id->driver_data;
0527
0528 return 0;
0529 }
0530
0531 static const struct pci_device_id iosf_mbi_pci_ids[] = {
0532 { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) },
0533 { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) },
0534 { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) },
0535 { PCI_DEVICE_DATA(INTEL, TANGIER, 0) },
0536 { 0, },
0537 };
0538 MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
0539
0540 static struct pci_driver iosf_mbi_pci_driver = {
0541 .name = "iosf_mbi_pci",
0542 .probe = iosf_mbi_probe,
0543 .id_table = iosf_mbi_pci_ids,
0544 };
0545
0546 static int __init iosf_mbi_init(void)
0547 {
0548 iosf_debugfs_init();
0549
0550 cpu_latency_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
0551
0552 return pci_register_driver(&iosf_mbi_pci_driver);
0553 }
0554
0555 static void __exit iosf_mbi_exit(void)
0556 {
0557 iosf_debugfs_remove();
0558
0559 pci_unregister_driver(&iosf_mbi_pci_driver);
0560 pci_dev_put(mbi_pdev);
0561 mbi_pdev = NULL;
0562
0563 cpu_latency_qos_remove_request(&iosf_mbi_pm_qos);
0564 }
0565
0566 module_init(iosf_mbi_init);
0567 module_exit(iosf_mbi_exit);
0568
0569 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
0570 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
0571 MODULE_LICENSE("GPL v2");