1 // SPDX-License-Identifier: GPL-2.0
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
8 * Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
16 * Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copy
25 * notice, this list of conditions and the following disclaimer in
26 * the documentation and/or other materials provided with the
28 * * Neither the name of AMD Corporation nor the names of its
29 * contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 * AMD PCIe MP2 Communication Driver
45 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
48 #include <linux/debugfs.h>
49 #include <linux/interrupt.h>
50 #include <linux/module.h>
51 #include <linux/pci.h>
52 #include <linux/slab.h>
54 #include "i2c-amd-pci-mp2.h"
56 #define DRIVER_NAME "pcie_mp2_amd"
57 #define DRIVER_DESC "AMD(R) PCI-E MP2 Communication Driver"
58 #define DRIVER_VER "1.0"
60 MODULE_DESCRIPTION(DRIVER_DESC
);
61 MODULE_VERSION(DRIVER_VER
);
62 MODULE_LICENSE("Dual BSD/GPL");
63 MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
65 static const struct file_operations amd_mp2_debugfs_info
;
66 static struct dentry
*debugfs_dir
;
68 int amd_mp2_connect(struct pci_dev
*dev
,
69 struct i2c_connect_config connect_cfg
)
71 struct amd_mp2_dev
*privdata
= pci_get_drvdata(dev
);
72 union i2c_cmd_base i2c_cmd_base
;
75 raw_spin_lock_irqsave(&privdata
->lock
, flags
);
76 dev_dbg(ndev_dev(privdata
), "%s addr: %x id: %d\n", __func__
,
77 connect_cfg
.dev_addr
, connect_cfg
.bus_id
);
80 i2c_cmd_base
.s
.i2c_cmd
= i2c_enable
;
81 i2c_cmd_base
.s
.bus_id
= connect_cfg
.bus_id
;
82 i2c_cmd_base
.s
.i2c_speed
= connect_cfg
.i2c_speed
;
84 if (i2c_cmd_base
.s
.bus_id
== i2c_bus_1
) {
85 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG1
);
86 } else if (i2c_cmd_base
.s
.bus_id
== i2c_bus_0
) {
87 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
89 dev_err(ndev_dev(privdata
), "%s Invalid bus id\n", __func__
);
92 raw_spin_unlock_irqrestore(&privdata
->lock
, flags
);
95 EXPORT_SYMBOL_GPL(amd_mp2_connect
);
97 int amd_mp2_read(struct pci_dev
*dev
, struct i2c_read_config read_cfg
)
99 struct amd_mp2_dev
*privdata
= pci_get_drvdata(dev
);
100 union i2c_cmd_base i2c_cmd_base
;
102 dev_dbg(ndev_dev(privdata
), "%s addr: %x id: %d\n", __func__
,
103 read_cfg
.dev_addr
, read_cfg
.bus_id
);
105 privdata
->requested
= true;
107 i2c_cmd_base
.s
.i2c_cmd
= i2c_read
;
108 i2c_cmd_base
.s
.dev_addr
= read_cfg
.dev_addr
;
109 i2c_cmd_base
.s
.length
= read_cfg
.length
;
110 i2c_cmd_base
.s
.bus_id
= read_cfg
.bus_id
;
112 if (read_cfg
.length
<= 32) {
113 i2c_cmd_base
.s
.mem_type
= use_c2pmsg
;
114 privdata
->eventval
.buf
= (u32
*)read_cfg
.buf
;
115 dev_dbg(ndev_dev(privdata
), "%s buf: %llx\n", __func__
,
116 (u64
)privdata
->eventval
.buf
);
118 i2c_cmd_base
.s
.mem_type
= use_dram
;
119 privdata
->read_cfg
.phy_addr
= read_cfg
.phy_addr
;
120 privdata
->read_cfg
.buf
= read_cfg
.buf
;
121 write64((u64
)privdata
->read_cfg
.phy_addr
,
122 privdata
->mmio
+ AMD_C2P_MSG2
);
125 switch (read_cfg
.i2c_speed
) {
127 i2c_cmd_base
.s
.i2c_speed
= speed100k
;
130 i2c_cmd_base
.s
.i2c_speed
= speed400k
;
133 i2c_cmd_base
.s
.i2c_speed
= speed1000k
;
136 i2c_cmd_base
.s
.i2c_speed
= speed1400k
;
139 i2c_cmd_base
.s
.i2c_speed
= speed3400k
;
142 dev_err(ndev_dev(privdata
), "Invalid ConnectionSpeed\n");
145 if (i2c_cmd_base
.s
.bus_id
== i2c_bus_1
) {
146 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG1
);
147 } else if (i2c_cmd_base
.s
.bus_id
== i2c_bus_0
) {
148 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
150 dev_err(ndev_dev(privdata
), "%s Invalid bus id\n", __func__
);
156 EXPORT_SYMBOL_GPL(amd_mp2_read
);
158 int amd_mp2_write(struct pci_dev
*dev
, struct i2c_write_config write_cfg
)
160 struct amd_mp2_dev
*privdata
= pci_get_drvdata(dev
);
161 union i2c_cmd_base i2c_cmd_base
;
165 privdata
->requested
= true;
166 dev_dbg(ndev_dev(privdata
), "%s addr: %x id: %d\n", __func__
,
167 write_cfg
.dev_addr
, write_cfg
.bus_id
);
170 i2c_cmd_base
.s
.i2c_cmd
= i2c_write
;
171 i2c_cmd_base
.s
.dev_addr
= write_cfg
.dev_addr
;
172 i2c_cmd_base
.s
.length
= write_cfg
.length
;
173 i2c_cmd_base
.s
.bus_id
= write_cfg
.bus_id
;
175 switch (write_cfg
.i2c_speed
) {
177 i2c_cmd_base
.s
.i2c_speed
= speed100k
;
180 i2c_cmd_base
.s
.i2c_speed
= speed400k
;
183 i2c_cmd_base
.s
.i2c_speed
= speed1000k
;
186 i2c_cmd_base
.s
.i2c_speed
= speed1400k
;
189 i2c_cmd_base
.s
.i2c_speed
= speed3400k
;
192 dev_err(ndev_dev(privdata
), "Invalid ConnectionSpeed\n");
195 if (write_cfg
.length
<= 32) {
196 i2c_cmd_base
.s
.mem_type
= use_c2pmsg
;
197 buf_len
= (write_cfg
.length
+ 3) / 4;
198 for (i
= 0; i
< buf_len
; i
++) {
199 writel(write_cfg
.buf
[i
],
200 privdata
->mmio
+ (AMD_C2P_MSG2
+ i
* 4));
203 i2c_cmd_base
.s
.mem_type
= use_dram
;
204 privdata
->write_cfg
.phy_addr
= write_cfg
.phy_addr
;
205 write64((u64
)privdata
->write_cfg
.phy_addr
,
206 privdata
->mmio
+ AMD_C2P_MSG2
);
209 if (i2c_cmd_base
.s
.bus_id
== i2c_bus_1
) {
210 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG1
);
211 } else if (i2c_cmd_base
.s
.bus_id
== i2c_bus_0
) {
212 writel(i2c_cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
214 dev_err(ndev_dev(privdata
), "%s Invalid bus id\n", __func__
);
220 EXPORT_SYMBOL_GPL(amd_mp2_write
);
222 int amd_i2c_register_cb(struct pci_dev
*dev
, const struct amd_i2c_pci_ops
*ops
,
225 struct amd_mp2_dev
*privdata
= pci_get_drvdata(dev
);
228 privdata
->i2c_dev_ctx
= dev_ctx
;
230 if (!privdata
->ops
|| !privdata
->i2c_dev_ctx
)
235 EXPORT_SYMBOL_GPL(amd_i2c_register_cb
);
237 static void amd_mp2_pci_work(struct work_struct
*work
)
239 struct amd_mp2_dev
*privdata
= mp2_dev(work
);
243 int sts
= privdata
->eventval
.base
.r
.status
;
244 int res
= privdata
->eventval
.base
.r
.response
;
245 int len
= privdata
->eventval
.base
.r
.length
;
247 if (res
== command_success
&& sts
== i2c_readcomplete_event
) {
248 if (privdata
->ops
->read_complete
) {
250 buf_len
= (len
+ 3) / 4;
251 for (i
= 0; i
< buf_len
; i
++) {
252 readdata
= readl(privdata
->mmio
+
253 (AMD_C2P_MSG2
+ i
* 4));
254 privdata
->eventval
.buf
[i
] = readdata
;
256 privdata
->ops
->read_complete(privdata
->eventval
,
257 privdata
->i2c_dev_ctx
);
259 privdata
->ops
->read_complete(privdata
->eventval
,
260 privdata
->i2c_dev_ctx
);
263 } else if (res
== command_success
&& sts
== i2c_writecomplete_event
) {
264 if (privdata
->ops
->write_complete
)
265 privdata
->ops
->write_complete(privdata
->eventval
,
266 privdata
->i2c_dev_ctx
);
267 } else if (res
== command_success
&& sts
== i2c_busenable_complete
) {
268 if (privdata
->ops
->connect_complete
)
269 privdata
->ops
->connect_complete(privdata
->eventval
,
270 privdata
->i2c_dev_ctx
);
272 dev_err(ndev_dev(privdata
), "ERROR!!nothing to be handled !\n");
276 static irqreturn_t
amd_mp2_irq_isr(int irq
, void *dev
)
278 struct amd_mp2_dev
*privdata
= dev
;
282 raw_spin_lock_irqsave(&privdata
->lock
, flags
);
283 val
= readl(privdata
->mmio
+ AMD_P2C_MSG1
);
285 writel(0, privdata
->mmio
+ AMD_P2C_MSG_INTEN
);
286 privdata
->eventval
.base
.ul
= val
;
288 val
= readl(privdata
->mmio
+ AMD_P2C_MSG2
);
290 writel(0, privdata
->mmio
+ AMD_P2C_MSG_INTEN
);
291 privdata
->eventval
.base
.ul
= val
;
295 raw_spin_unlock_irqrestore(&privdata
->lock
, flags
);
299 if (!privdata
->requested
)
302 privdata
->requested
= false;
303 schedule_delayed_work(&privdata
->work
, 0);
308 static ssize_t
amd_mp2_debugfs_read(struct file
*filp
, char __user
*ubuf
,
309 size_t count
, loff_t
*offp
)
311 struct amd_mp2_dev
*privdata
;
322 privdata
= filp
->private_data
;
323 mmio
= privdata
->mmio
;
324 buf_size
= min(count
, 0x800ul
);
325 buf
= kmalloc(buf_size
, GFP_KERNEL
);
331 off
+= scnprintf(buf
+ off
, buf_size
- off
,
332 "Mp2 Device Information:\n");
334 off
+= scnprintf(buf
+ off
, buf_size
- off
,
335 "========================\n");
336 off
+= scnprintf(buf
+ off
, buf_size
- off
,
337 "\tMP2 C2P Message Register Dump:\n\n");
338 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG0
);
339 off
+= scnprintf(buf
+ off
, buf_size
- off
,
340 "AMD_C2P_MSG0 -\t\t\t%#06x\n", u
.v32
);
342 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG1
);
343 off
+= scnprintf(buf
+ off
, buf_size
- off
,
344 "AMD_C2P_MSG1 -\t\t\t%#06x\n", u
.v32
);
346 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG2
);
347 off
+= scnprintf(buf
+ off
, buf_size
- off
,
348 "AMD_C2P_MSG2 -\t\t\t%#06x\n", u
.v32
);
350 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG3
);
351 off
+= scnprintf(buf
+ off
, buf_size
- off
,
352 "AMD_C2P_MSG3 -\t\t\t%#06x\n", u
.v32
);
354 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG4
);
355 off
+= scnprintf(buf
+ off
, buf_size
- off
,
356 "AMD_C2P_MSG4 -\t\t\t%#06x\n", u
.v32
);
358 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG5
);
359 off
+= scnprintf(buf
+ off
, buf_size
- off
,
360 "AMD_C2P_MSG5 -\t\t\t%#06x\n", u
.v32
);
362 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG6
);
363 off
+= scnprintf(buf
+ off
, buf_size
- off
,
364 "AMD_C2P_MSG6 -\t\t\t%#06x\n", u
.v32
);
366 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG7
);
367 off
+= scnprintf(buf
+ off
, buf_size
- off
,
368 "AMD_C2P_MSG7 -\t\t\t%#06x\n", u
.v32
);
370 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG8
);
371 off
+= scnprintf(buf
+ off
, buf_size
- off
,
372 "AMD_C2P_MSG8 -\t\t\t%#06x\n", u
.v32
);
374 u
.v32
= readl(privdata
->mmio
+ AMD_C2P_MSG9
);
375 off
+= scnprintf(buf
+ off
, buf_size
- off
,
376 "AMD_C2P_MSG9 -\t\t\t%#06x\n", u
.v32
);
378 off
+= scnprintf(buf
+ off
, buf_size
- off
,
379 "\n\tMP2 P2C Message Register Dump:\n\n");
381 u
.v32
= readl(privdata
->mmio
+ AMD_P2C_MSG1
);
382 off
+= scnprintf(buf
+ off
, buf_size
- off
,
383 "AMD_P2C_MSG1 -\t\t\t%#06x\n", u
.v32
);
385 u
.v32
= readl(privdata
->mmio
+ AMD_P2C_MSG2
);
386 off
+= scnprintf(buf
+ off
, buf_size
- off
,
387 "AMD_P2C_MSG2 -\t\t\t%#06x\n", u
.v32
);
389 u
.v32
= readl(privdata
->mmio
+ AMD_P2C_MSG_INTEN
);
390 off
+= scnprintf(buf
+ off
, buf_size
- off
,
391 "AMD_P2C_MSG_INTEN -\t\t%#06x\n", u
.v32
);
393 u
.v32
= readl(privdata
->mmio
+ AMD_P2C_MSG_INTSTS
);
394 off
+= scnprintf(buf
+ off
, buf_size
- off
,
395 "AMD_P2C_MSG_INTSTS -\t\t%#06x\n", u
.v32
);
397 ret
= simple_read_from_buffer(ubuf
, count
, offp
, buf
, off
);
402 static void amd_mp2_init_debugfs(struct amd_mp2_dev
*privdata
)
405 privdata
->debugfs_dir
= NULL
;
406 privdata
->debugfs_info
= NULL
;
408 privdata
->debugfs_dir
= debugfs_create_dir(ndev_name(privdata
),
410 if (!privdata
->debugfs_dir
) {
411 privdata
->debugfs_info
= NULL
;
413 privdata
->debugfs_info
= debugfs_create_file(
414 "info", 0400, privdata
->debugfs_dir
,
415 privdata
, &amd_mp2_debugfs_info
);
420 static void amd_mp2_deinit_debugfs(struct amd_mp2_dev
*privdata
)
422 debugfs_remove_recursive(privdata
->debugfs_dir
);
425 static void amd_mp2_clear_reg(struct amd_mp2_dev
*privdata
)
429 for (reg
= AMD_C2P_MSG0
; reg
<= AMD_C2P_MSG9
; reg
+= 4)
430 writel(0, privdata
->mmio
+ reg
);
432 for (reg
= AMD_P2C_MSG0
; reg
<= AMD_P2C_MSG2
; reg
+= 4)
433 writel(0, privdata
->mmio
+ reg
);
436 static int amd_mp2_pci_init(struct amd_mp2_dev
*privdata
, struct pci_dev
*pdev
)
440 resource_size_t size
, base
;
442 pci_set_drvdata(pdev
, privdata
);
444 rc
= pci_enable_device(pdev
);
448 rc
= pci_request_regions(pdev
, DRIVER_NAME
);
450 goto err_pci_regions
;
452 pci_set_master(pdev
);
454 rc
= pci_set_dma_mask(pdev
, DMA_BIT_MASK(64));
456 rc
= pci_set_dma_mask(pdev
, DMA_BIT_MASK(32));
459 dev_warn(ndev_dev(privdata
), "Cannot DMA highmem\n");
462 rc
= pci_set_consistent_dma_mask(pdev
, DMA_BIT_MASK(64));
464 rc
= pci_set_consistent_dma_mask(pdev
, DMA_BIT_MASK(32));
467 dev_warn(ndev_dev(privdata
), "Cannot DMA consistent highmem\n");
470 base
= pci_resource_start(pdev
, bar_index
);
471 size
= pci_resource_len(pdev
, bar_index
);
472 dev_dbg(ndev_dev(privdata
), "Base addr:%llx size:%llx\n", base
, size
);
474 privdata
->mmio
= ioremap(base
, size
);
475 if (!privdata
->mmio
) {
480 /* Try to set up intx irq */
482 privdata
->eventval
.buf
= NULL
;
483 privdata
->requested
= false;
484 raw_spin_lock_init(&privdata
->lock
);
485 rc
= request_irq(pdev
->irq
, amd_mp2_irq_isr
, IRQF_SHARED
, "mp2_irq_isr",
488 goto err_intx_request
;
495 pci_clear_master(pdev
);
496 pci_release_regions(pdev
);
498 pci_disable_device(pdev
);
500 pci_set_drvdata(pdev
, NULL
);
504 static void amd_mp2_pci_deinit(struct amd_mp2_dev
*privdata
)
506 struct pci_dev
*pdev
= ndev_pdev(privdata
);
508 pci_iounmap(pdev
, privdata
->mmio
);
510 pci_clear_master(pdev
);
511 pci_release_regions(pdev
);
512 pci_disable_device(pdev
);
513 pci_set_drvdata(pdev
, NULL
);
516 static int amd_mp2_pci_probe(struct pci_dev
*pdev
,
517 const struct pci_device_id
*id
)
519 struct amd_mp2_dev
*privdata
;
522 dev_info(&pdev
->dev
, "MP2 device found [%04x:%04x] (rev %x)\n",
523 (int)pdev
->vendor
, (int)pdev
->device
, (int)pdev
->revision
);
525 privdata
= kzalloc(sizeof(*privdata
), GFP_KERNEL
);
526 privdata
->pdev
= pdev
;
533 rc
= amd_mp2_pci_init(privdata
, pdev
);
536 dev_dbg(&pdev
->dev
, "pci init done.\n");
538 INIT_DELAYED_WORK(&privdata
->work
, amd_mp2_pci_work
);
540 amd_mp2_init_debugfs(privdata
);
541 dev_info(&pdev
->dev
, "MP2 device registered.\n");
547 dev_err(&pdev
->dev
, "Memory Allocation Failed\n");
551 static void amd_mp2_pci_remove(struct pci_dev
*pdev
)
553 struct amd_mp2_dev
*privdata
= pci_get_drvdata(pdev
);
555 amd_mp2_deinit_debugfs(privdata
);
556 amd_mp2_clear_reg(privdata
);
557 cancel_delayed_work_sync(&privdata
->work
);
558 free_irq(pdev
->irq
, privdata
);
560 amd_mp2_pci_deinit(privdata
);
564 static const struct file_operations amd_mp2_debugfs_info
= {
565 .owner
= THIS_MODULE
,
567 .read
= amd_mp2_debugfs_read
,
570 static const struct pci_device_id amd_mp2_pci_tbl
[] = {
571 {PCI_VDEVICE(AMD
, PCI_DEVICE_ID_AMD_MP2
)},
574 MODULE_DEVICE_TABLE(pci
, amd_mp2_pci_tbl
);
576 #ifdef CONFIG_PM_SLEEP
577 static int amd_mp2_pci_device_suspend(struct pci_dev
*pdev
, pm_message_t mesg
)
579 struct amd_mp2_dev
*privdata
= pci_get_drvdata(pdev
);
587 static int amd_mp2_pci_device_resume(struct pci_dev
*pdev
)
589 struct amd_mp2_dev
*privdata
= pci_get_drvdata(pdev
);
598 static struct pci_driver amd_mp2_pci_driver
= {
600 .id_table
= amd_mp2_pci_tbl
,
601 .probe
= amd_mp2_pci_probe
,
602 .remove
= amd_mp2_pci_remove
,
603 #ifdef CONFIG_PM_SLEEP
604 .suspend
= amd_mp2_pci_device_suspend
,
605 .resume
= amd_mp2_pci_device_resume
,
609 static int __init
amd_mp2_pci_driver_init(void)
611 pr_info("%s: %s Version: %s\n", DRIVER_NAME
, DRIVER_DESC
, DRIVER_VER
);
613 if (debugfs_initialized())
614 debugfs_dir
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
616 return pci_register_driver(&amd_mp2_pci_driver
);
618 module_init(amd_mp2_pci_driver_init
);
620 static void __exit
amd_mp2_pci_driver_exit(void)
622 pci_unregister_driver(&amd_mp2_pci_driver
);
623 debugfs_remove_recursive(debugfs_dir
);
625 module_exit(amd_mp2_pci_driver_exit
);