1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright(c) 2023 Intel Corporation. All rights reserved. |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/debugfs.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/device.h> |
8 | #include <linux/io.h> |
9 | #include <linux/pm_runtime.h> |
10 | #include <linux/soundwire/sdw.h> |
11 | #include <linux/soundwire/sdw_intel.h> |
12 | #include <linux/soundwire/sdw_registers.h> |
13 | #include "bus.h" |
14 | #include "cadence_master.h" |
15 | #include "intel.h" |
16 | |
17 | /* |
18 | * debugfs |
19 | */ |
20 | #ifdef CONFIG_DEBUG_FS |
21 | |
22 | #define RD_BUF (2 * PAGE_SIZE) |
23 | |
24 | static ssize_t intel_sprintf(void __iomem *mem, bool l, |
25 | char *buf, size_t pos, unsigned int reg) |
26 | { |
27 | int value; |
28 | |
29 | if (l) |
30 | value = intel_readl(base: mem, offset: reg); |
31 | else |
32 | value = intel_readw(base: mem, offset: reg); |
33 | |
34 | return scnprintf(buf: buf + pos, RD_BUF - pos, fmt: "%4x\t%4x\n" , reg, value); |
35 | } |
36 | |
37 | static int intel_reg_show(struct seq_file *s_file, void *data) |
38 | { |
39 | struct sdw_intel *sdw = s_file->private; |
40 | void __iomem *s = sdw->link_res->shim; |
41 | void __iomem *vs_s = sdw->link_res->shim_vs; |
42 | ssize_t ret; |
43 | u32 pcm_cap; |
44 | int pcm_bd; |
45 | char *buf; |
46 | int j; |
47 | |
48 | buf = kzalloc(RD_BUF, GFP_KERNEL); |
49 | if (!buf) |
50 | return -ENOMEM; |
51 | |
52 | ret = scnprintf(buf, RD_BUF, fmt: "Register Value\n" ); |
53 | ret += scnprintf(buf: buf + ret, RD_BUF - ret, fmt: "\nShim\n" ); |
54 | |
55 | ret += intel_sprintf(mem: s, l: true, buf, pos: ret, SDW_SHIM2_LECAP); |
56 | ret += intel_sprintf(mem: s, l: false, buf, pos: ret, SDW_SHIM2_PCMSCAP); |
57 | |
58 | pcm_cap = intel_readw(base: s, SDW_SHIM2_PCMSCAP); |
59 | pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap); |
60 | |
61 | for (j = 0; j < pcm_bd; j++) { |
62 | ret += intel_sprintf(mem: s, l: false, buf, pos: ret, |
63 | SDW_SHIM2_PCMSYCHM(j)); |
64 | ret += intel_sprintf(mem: s, l: false, buf, pos: ret, |
65 | SDW_SHIM2_PCMSYCHC(j)); |
66 | } |
67 | |
68 | ret += scnprintf(buf: buf + ret, RD_BUF - ret, fmt: "\nVS CLK controls\n" ); |
69 | ret += intel_sprintf(mem: vs_s, l: true, buf, pos: ret, SDW_SHIM2_INTEL_VS_LVSCTL); |
70 | |
71 | ret += scnprintf(buf: buf + ret, RD_BUF - ret, fmt: "\nVS Wake registers\n" ); |
72 | ret += intel_sprintf(mem: vs_s, l: false, buf, pos: ret, SDW_SHIM2_INTEL_VS_WAKEEN); |
73 | ret += intel_sprintf(mem: vs_s, l: false, buf, pos: ret, SDW_SHIM2_INTEL_VS_WAKESTS); |
74 | |
75 | ret += scnprintf(buf: buf + ret, RD_BUF - ret, fmt: "\nVS IOCTL, ACTMCTL\n" ); |
76 | ret += intel_sprintf(mem: vs_s, l: false, buf, pos: ret, SDW_SHIM2_INTEL_VS_IOCTL); |
77 | ret += intel_sprintf(mem: vs_s, l: false, buf, pos: ret, SDW_SHIM2_INTEL_VS_ACTMCTL); |
78 | |
79 | seq_printf(m: s_file, fmt: "%s" , buf); |
80 | kfree(objp: buf); |
81 | |
82 | return 0; |
83 | } |
84 | DEFINE_SHOW_ATTRIBUTE(intel_reg); |
85 | |
86 | static int intel_set_m_datamode(void *data, u64 value) |
87 | { |
88 | struct sdw_intel *sdw = data; |
89 | struct sdw_bus *bus = &sdw->cdns.bus; |
90 | |
91 | if (value > SDW_PORT_DATA_MODE_STATIC_1) |
92 | return -EINVAL; |
93 | |
94 | /* Userspace changed the hardware state behind the kernel's back */ |
95 | add_taint(TAINT_USER, LOCKDEP_STILL_OK); |
96 | |
97 | bus->params.m_data_mode = value; |
98 | |
99 | return 0; |
100 | } |
101 | DEFINE_DEBUGFS_ATTRIBUTE(intel_set_m_datamode_fops, NULL, |
102 | intel_set_m_datamode, "%llu\n" ); |
103 | |
104 | static int intel_set_s_datamode(void *data, u64 value) |
105 | { |
106 | struct sdw_intel *sdw = data; |
107 | struct sdw_bus *bus = &sdw->cdns.bus; |
108 | |
109 | if (value > SDW_PORT_DATA_MODE_STATIC_1) |
110 | return -EINVAL; |
111 | |
112 | /* Userspace changed the hardware state behind the kernel's back */ |
113 | add_taint(TAINT_USER, LOCKDEP_STILL_OK); |
114 | |
115 | bus->params.s_data_mode = value; |
116 | |
117 | return 0; |
118 | } |
119 | DEFINE_DEBUGFS_ATTRIBUTE(intel_set_s_datamode_fops, NULL, |
120 | intel_set_s_datamode, "%llu\n" ); |
121 | |
122 | void intel_ace2x_debugfs_init(struct sdw_intel *sdw) |
123 | { |
124 | struct dentry *root = sdw->cdns.bus.debugfs; |
125 | |
126 | if (!root) |
127 | return; |
128 | |
129 | sdw->debugfs = debugfs_create_dir(name: "intel-sdw" , parent: root); |
130 | |
131 | debugfs_create_file(name: "intel-registers" , mode: 0400, parent: sdw->debugfs, data: sdw, |
132 | fops: &intel_reg_fops); |
133 | |
134 | debugfs_create_file(name: "intel-m-datamode" , mode: 0200, parent: sdw->debugfs, data: sdw, |
135 | fops: &intel_set_m_datamode_fops); |
136 | |
137 | debugfs_create_file(name: "intel-s-datamode" , mode: 0200, parent: sdw->debugfs, data: sdw, |
138 | fops: &intel_set_s_datamode_fops); |
139 | |
140 | sdw_cdns_debugfs_init(cdns: &sdw->cdns, root: sdw->debugfs); |
141 | } |
142 | |
143 | void intel_ace2x_debugfs_exit(struct sdw_intel *sdw) |
144 | { |
145 | debugfs_remove_recursive(dentry: sdw->debugfs); |
146 | } |
147 | #endif /* CONFIG_DEBUG_FS */ |
148 | |