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