xref: /openbmc/linux/arch/x86/platform/intel/iosf_mbi.c (revision 2169e6da)
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 	iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
465 
466 	/* mdr */
467 	debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
468 
469 	/* mcrx */
470 	debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
471 
472 	/* mcr - initiates mailbox tranaction */
473 	debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
474 }
475 
476 static void iosf_debugfs_init(void)
477 {
478 	iosf_sideband_debug_init();
479 }
480 
481 static void iosf_debugfs_remove(void)
482 {
483 	debugfs_remove_recursive(iosf_dbg);
484 }
485 #else
486 static inline void iosf_debugfs_init(void) { }
487 static inline void iosf_debugfs_remove(void) { }
488 #endif /* CONFIG_IOSF_MBI_DEBUG */
489 
490 static int iosf_mbi_probe(struct pci_dev *pdev,
491 			  const struct pci_device_id *dev_id)
492 {
493 	int ret;
494 
495 	ret = pci_enable_device(pdev);
496 	if (ret < 0) {
497 		dev_err(&pdev->dev, "error: could not enable device\n");
498 		return ret;
499 	}
500 
501 	mbi_pdev = pci_dev_get(pdev);
502 	iosf_mbi_sem_address = dev_id->driver_data;
503 
504 	return 0;
505 }
506 
507 static const struct pci_device_id iosf_mbi_pci_ids[] = {
508 	{ PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) },
509 	{ PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) },
510 	{ PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) },
511 	{ PCI_DEVICE_DATA(INTEL, TANGIER, 0) },
512 	{ 0, },
513 };
514 MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
515 
516 static struct pci_driver iosf_mbi_pci_driver = {
517 	.name		= "iosf_mbi_pci",
518 	.probe		= iosf_mbi_probe,
519 	.id_table	= iosf_mbi_pci_ids,
520 };
521 
522 static int __init iosf_mbi_init(void)
523 {
524 	iosf_debugfs_init();
525 
526 	pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY,
527 			   PM_QOS_DEFAULT_VALUE);
528 
529 	return pci_register_driver(&iosf_mbi_pci_driver);
530 }
531 
532 static void __exit iosf_mbi_exit(void)
533 {
534 	iosf_debugfs_remove();
535 
536 	pci_unregister_driver(&iosf_mbi_pci_driver);
537 	pci_dev_put(mbi_pdev);
538 	mbi_pdev = NULL;
539 
540 	pm_qos_remove_request(&iosf_mbi_pm_qos);
541 }
542 
543 module_init(iosf_mbi_init);
544 module_exit(iosf_mbi_exit);
545 
546 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
547 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
548 MODULE_LICENSE("GPL v2");
549