1 /* 2 * 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 multiple devices. This 17 * driver implements access to this interface for those platforms that can 18 * enumerate the device using PCI. 19 */ 20 21 #include <linux/delay.h> 22 #include <linux/module.h> 23 #include <linux/init.h> 24 #include <linux/spinlock.h> 25 #include <linux/pci.h> 26 #include <linux/debugfs.h> 27 #include <linux/capability.h> 28 #include <linux/pm_qos.h> 29 30 #include <asm/iosf_mbi.h> 31 32 #define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00 33 #define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280 34 #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958 35 #define PCI_DEVICE_ID_INTEL_TANGIER 0x1170 36 37 static struct pci_dev *mbi_pdev; 38 static DEFINE_SPINLOCK(iosf_mbi_lock); 39 40 /**************** Generic iosf_mbi access helpers ****************/ 41 42 static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) 43 { 44 return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE; 45 } 46 47 static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr) 48 { 49 int result; 50 51 if (!mbi_pdev) 52 return -ENODEV; 53 54 if (mcrx) { 55 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, 56 mcrx); 57 if (result < 0) 58 goto fail_read; 59 } 60 61 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); 62 if (result < 0) 63 goto fail_read; 64 65 result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); 66 if (result < 0) 67 goto fail_read; 68 69 return 0; 70 71 fail_read: 72 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); 73 return result; 74 } 75 76 static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr) 77 { 78 int result; 79 80 if (!mbi_pdev) 81 return -ENODEV; 82 83 result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr); 84 if (result < 0) 85 goto fail_write; 86 87 if (mcrx) { 88 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET, 89 mcrx); 90 if (result < 0) 91 goto fail_write; 92 } 93 94 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr); 95 if (result < 0) 96 goto fail_write; 97 98 return 0; 99 100 fail_write: 101 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); 102 return result; 103 } 104 105 int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr) 106 { 107 u32 mcr, mcrx; 108 unsigned long flags; 109 int ret; 110 111 /* Access to the GFX unit is handled by GPU code */ 112 if (port == BT_MBI_UNIT_GFX) { 113 WARN_ON(1); 114 return -EPERM; 115 } 116 117 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); 118 mcrx = offset & MBI_MASK_HI; 119 120 spin_lock_irqsave(&iosf_mbi_lock, flags); 121 ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr); 122 spin_unlock_irqrestore(&iosf_mbi_lock, flags); 123 124 return ret; 125 } 126 EXPORT_SYMBOL(iosf_mbi_read); 127 128 int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr) 129 { 130 u32 mcr, mcrx; 131 unsigned long flags; 132 int ret; 133 134 /* Access to the GFX unit is handled by GPU code */ 135 if (port == BT_MBI_UNIT_GFX) { 136 WARN_ON(1); 137 return -EPERM; 138 } 139 140 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); 141 mcrx = offset & MBI_MASK_HI; 142 143 spin_lock_irqsave(&iosf_mbi_lock, flags); 144 ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr); 145 spin_unlock_irqrestore(&iosf_mbi_lock, flags); 146 147 return ret; 148 } 149 EXPORT_SYMBOL(iosf_mbi_write); 150 151 int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask) 152 { 153 u32 mcr, mcrx; 154 u32 value; 155 unsigned long flags; 156 int ret; 157 158 /* Access to the GFX unit is handled by GPU code */ 159 if (port == BT_MBI_UNIT_GFX) { 160 WARN_ON(1); 161 return -EPERM; 162 } 163 164 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO); 165 mcrx = offset & MBI_MASK_HI; 166 167 spin_lock_irqsave(&iosf_mbi_lock, flags); 168 169 /* Read current mdr value */ 170 ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value); 171 if (ret < 0) { 172 spin_unlock_irqrestore(&iosf_mbi_lock, flags); 173 return ret; 174 } 175 176 /* Apply mask */ 177 value &= ~mask; 178 mdr &= mask; 179 value |= mdr; 180 181 /* Write back */ 182 ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value); 183 184 spin_unlock_irqrestore(&iosf_mbi_lock, flags); 185 186 return ret; 187 } 188 EXPORT_SYMBOL(iosf_mbi_modify); 189 190 bool iosf_mbi_available(void) 191 { 192 /* Mbi isn't hot-pluggable. No remove routine is provided */ 193 return mbi_pdev; 194 } 195 EXPORT_SYMBOL(iosf_mbi_available); 196 197 /* 198 **************** P-Unit/kernel shared I2C bus arbritration **************** 199 * 200 * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel) 201 * share a single I2C bus to the PMIC. Below are helpers to arbitrate the 202 * accesses between the kernel and the P-Unit. 203 * 204 * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function. 205 */ 206 207 #define SEMAPHORE_TIMEOUT 500 208 #define PUNIT_SEMAPHORE_BYT 0x7 209 #define PUNIT_SEMAPHORE_CHT 0x10e 210 #define PUNIT_SEMAPHORE_BIT BIT(0) 211 #define PUNIT_SEMAPHORE_ACQUIRE BIT(1) 212 213 static DEFINE_MUTEX(iosf_mbi_punit_mutex); 214 static DEFINE_MUTEX(iosf_mbi_block_punit_i2c_access_count_mutex); 215 static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); 216 static u32 iosf_mbi_block_punit_i2c_access_count; 217 static u32 iosf_mbi_sem_address; 218 static unsigned long iosf_mbi_sem_acquired; 219 static struct pm_qos_request iosf_mbi_pm_qos; 220 221 void iosf_mbi_punit_acquire(void) 222 { 223 mutex_lock(&iosf_mbi_punit_mutex); 224 } 225 EXPORT_SYMBOL(iosf_mbi_punit_acquire); 226 227 void iosf_mbi_punit_release(void) 228 { 229 mutex_unlock(&iosf_mbi_punit_mutex); 230 } 231 EXPORT_SYMBOL(iosf_mbi_punit_release); 232 233 static int iosf_mbi_get_sem(u32 *sem) 234 { 235 int ret; 236 237 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, 238 iosf_mbi_sem_address, sem); 239 if (ret) { 240 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n"); 241 return ret; 242 } 243 244 *sem &= PUNIT_SEMAPHORE_BIT; 245 return 0; 246 } 247 248 static void iosf_mbi_reset_semaphore(void) 249 { 250 if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, 251 iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT)) 252 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n"); 253 254 pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE); 255 256 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, 257 MBI_PMIC_BUS_ACCESS_END, NULL); 258 } 259 260 /* 261 * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel 262 * I2C code, such as e.g. a fuel-gauge driver, can access it safely. 263 * 264 * This function may be called by I2C controller code while an I2C driver has 265 * already blocked P-Unit accesses because it wants them blocked over multiple 266 * i2c-transfers, for e.g. read-modify-write of an I2C client register. 267 * 268 * The P-Unit accesses already being blocked is tracked through the 269 * iosf_mbi_block_punit_i2c_access_count variable which is protected by the 270 * iosf_mbi_block_punit_i2c_access_count_mutex this mutex is hold for the 271 * entire duration of the function. 272 * 273 * If access is not blocked yet, this function takes the following steps: 274 * 275 * 1) Some code sends request to the P-Unit which make it access the PMIC 276 * I2C bus. Testing has shown that the P-Unit does not check its internal 277 * PMIC bus semaphore for these requests. Callers of these requests call 278 * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these 279 * functions lock/unlock the iosf_mbi_punit_mutex. 280 * As the first step we lock the iosf_mbi_punit_mutex, to wait for any in 281 * flight requests to finish and to block any new requests. 282 * 283 * 2) Some code makes such P-Unit requests from atomic contexts where it 284 * cannot call iosf_mbi_punit_acquire() as that may sleep. 285 * As the second step we call a notifier chain which allows any code 286 * needing P-Unit resources from atomic context to acquire them before 287 * we take control over the PMIC I2C bus. 288 * 289 * 3) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC 290 * if this happens while the kernel itself is accessing the PMIC I2C bus 291 * the SoC hangs. 292 * As the third step we call pm_qos_update_request() to disallow the CPU 293 * to enter C6 or C7. 294 * 295 * 4) The P-Unit has a PMIC bus semaphore which we can request to stop 296 * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it. 297 * As the fourth and final step we request this semaphore and wait for our 298 * request to be acknowledged. 299 */ 300 int iosf_mbi_block_punit_i2c_access(void) 301 { 302 unsigned long start, end; 303 int ret = 0; 304 u32 sem; 305 306 if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address)) 307 return -ENXIO; 308 309 mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); 310 311 if (iosf_mbi_block_punit_i2c_access_count > 0) 312 goto success; 313 314 mutex_lock(&iosf_mbi_punit_mutex); 315 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier, 316 MBI_PMIC_BUS_ACCESS_BEGIN, NULL); 317 318 /* 319 * Disallow the CPU to enter C6 or C7 state, entering these states 320 * requires the P-Unit to talk to the PMIC and if this happens while 321 * we're holding the semaphore, the SoC hangs. 322 */ 323 pm_qos_update_request(&iosf_mbi_pm_qos, 0); 324 325 /* host driver writes to side band semaphore register */ 326 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, 327 iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE); 328 if (ret) { 329 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n"); 330 goto error; 331 } 332 333 /* host driver waits for bit 0 to be set in semaphore register */ 334 start = jiffies; 335 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); 336 do { 337 ret = iosf_mbi_get_sem(&sem); 338 if (!ret && sem) { 339 iosf_mbi_sem_acquired = jiffies; 340 dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n", 341 jiffies_to_msecs(jiffies - start)); 342 /* 343 * Success, keep iosf_mbi_punit_mutex locked till 344 * iosf_mbi_unblock_punit_i2c_access() gets called. 345 */ 346 goto success; 347 } 348 349 usleep_range(1000, 2000); 350 } while (time_before(jiffies, end)); 351 352 ret = -ETIMEDOUT; 353 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n"); 354 error: 355 iosf_mbi_reset_semaphore(); 356 mutex_unlock(&iosf_mbi_punit_mutex); 357 358 if (!iosf_mbi_get_sem(&sem)) 359 dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem); 360 success: 361 if (!WARN_ON(ret)) 362 iosf_mbi_block_punit_i2c_access_count++; 363 364 mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); 365 366 return ret; 367 } 368 EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access); 369 370 void iosf_mbi_unblock_punit_i2c_access(void) 371 { 372 mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex); 373 374 iosf_mbi_block_punit_i2c_access_count--; 375 if (iosf_mbi_block_punit_i2c_access_count == 0) { 376 iosf_mbi_reset_semaphore(); 377 mutex_unlock(&iosf_mbi_punit_mutex); 378 dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n", 379 jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired)); 380 } 381 382 mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex); 383 } 384 EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access); 385 386 int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) 387 { 388 int ret; 389 390 /* Wait for the bus to go inactive before registering */ 391 mutex_lock(&iosf_mbi_punit_mutex); 392 ret = blocking_notifier_chain_register( 393 &iosf_mbi_pmic_bus_access_notifier, nb); 394 mutex_unlock(&iosf_mbi_punit_mutex); 395 396 return ret; 397 } 398 EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier); 399 400 int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked( 401 struct notifier_block *nb) 402 { 403 iosf_mbi_assert_punit_acquired(); 404 405 return blocking_notifier_chain_unregister( 406 &iosf_mbi_pmic_bus_access_notifier, nb); 407 } 408 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked); 409 410 int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb) 411 { 412 int ret; 413 414 /* Wait for the bus to go inactive before unregistering */ 415 mutex_lock(&iosf_mbi_punit_mutex); 416 ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb); 417 mutex_unlock(&iosf_mbi_punit_mutex); 418 419 return ret; 420 } 421 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); 422 423 void iosf_mbi_assert_punit_acquired(void) 424 { 425 WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex)); 426 } 427 EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); 428 429 /**************** iosf_mbi debug code ****************/ 430 431 #ifdef CONFIG_IOSF_MBI_DEBUG 432 static u32 dbg_mdr; 433 static u32 dbg_mcr; 434 static u32 dbg_mcrx; 435 436 static int mcr_get(void *data, u64 *val) 437 { 438 *val = *(u32 *)data; 439 return 0; 440 } 441 442 static int mcr_set(void *data, u64 val) 443 { 444 u8 command = ((u32)val & 0xFF000000) >> 24, 445 port = ((u32)val & 0x00FF0000) >> 16, 446 offset = ((u32)val & 0x0000FF00) >> 8; 447 int err; 448 449 *(u32 *)data = val; 450 451 if (!capable(CAP_SYS_RAWIO)) 452 return -EACCES; 453 454 if (command & 1u) 455 err = iosf_mbi_write(port, 456 command, 457 dbg_mcrx | offset, 458 dbg_mdr); 459 else 460 err = iosf_mbi_read(port, 461 command, 462 dbg_mcrx | offset, 463 &dbg_mdr); 464 465 return err; 466 } 467 DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n"); 468 469 static struct dentry *iosf_dbg; 470 471 static void iosf_sideband_debug_init(void) 472 { 473 struct dentry *d; 474 475 iosf_dbg = debugfs_create_dir("iosf_sb", NULL); 476 if (IS_ERR_OR_NULL(iosf_dbg)) 477 return; 478 479 /* mdr */ 480 d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr); 481 if (!d) 482 goto cleanup; 483 484 /* mcrx */ 485 d = debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); 486 if (!d) 487 goto cleanup; 488 489 /* mcr - initiates mailbox tranaction */ 490 d = debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops); 491 if (!d) 492 goto cleanup; 493 494 return; 495 496 cleanup: 497 debugfs_remove_recursive(d); 498 } 499 500 static void iosf_debugfs_init(void) 501 { 502 iosf_sideband_debug_init(); 503 } 504 505 static void iosf_debugfs_remove(void) 506 { 507 debugfs_remove_recursive(iosf_dbg); 508 } 509 #else 510 static inline void iosf_debugfs_init(void) { } 511 static inline void iosf_debugfs_remove(void) { } 512 #endif /* CONFIG_IOSF_MBI_DEBUG */ 513 514 static int iosf_mbi_probe(struct pci_dev *pdev, 515 const struct pci_device_id *dev_id) 516 { 517 int ret; 518 519 ret = pci_enable_device(pdev); 520 if (ret < 0) { 521 dev_err(&pdev->dev, "error: could not enable device\n"); 522 return ret; 523 } 524 525 mbi_pdev = pci_dev_get(pdev); 526 iosf_mbi_sem_address = dev_id->driver_data; 527 528 return 0; 529 } 530 531 static const struct pci_device_id iosf_mbi_pci_ids[] = { 532 { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) }, 533 { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) }, 534 { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) }, 535 { PCI_DEVICE_DATA(INTEL, TANGIER, 0) }, 536 { 0, }, 537 }; 538 MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); 539 540 static struct pci_driver iosf_mbi_pci_driver = { 541 .name = "iosf_mbi_pci", 542 .probe = iosf_mbi_probe, 543 .id_table = iosf_mbi_pci_ids, 544 }; 545 546 static int __init iosf_mbi_init(void) 547 { 548 iosf_debugfs_init(); 549 550 pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY, 551 PM_QOS_DEFAULT_VALUE); 552 553 return pci_register_driver(&iosf_mbi_pci_driver); 554 } 555 556 static void __exit iosf_mbi_exit(void) 557 { 558 iosf_debugfs_remove(); 559 560 pci_unregister_driver(&iosf_mbi_pci_driver); 561 pci_dev_put(mbi_pdev); 562 mbi_pdev = NULL; 563 564 pm_qos_remove_request(&iosf_mbi_pm_qos); 565 } 566 567 module_init(iosf_mbi_init); 568 module_exit(iosf_mbi_exit); 569 570 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 571 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor"); 572 MODULE_LICENSE("GPL v2"); 573