OSDN Git Service

x86: baytrail/cherrytrail: Rework and move P-Unit PMIC bus semaphore code
[uclinux-h8/linux.git] / arch / x86 / platform / intel / iosf_mbi.c
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 mutiple 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");