xref: /openbmc/linux/arch/x86/platform/intel/iosf_mbi.c (revision e657c18a)
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