]> Git Repo - linux.git/blob - arch/x86/platform/atom/punit_atom_debug.c
ACPI: EC: Evaluate orphan _REG under EC device
[linux.git] / arch / x86 / platform / atom / punit_atom_debug.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel SOC Punit device state debug driver
4  * Punit controls power management for North Complex devices (Graphics
5  * blocks, Image Signal Processing, video processing, display, DSP etc.)
6  *
7  * Copyright (c) 2015, Intel Corporation.
8  */
9
10 #define pr_fmt(fmt) "punit_atom: " fmt
11
12 #include <linux/acpi.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/device.h>
16 #include <linux/debugfs.h>
17 #include <linux/seq_file.h>
18 #include <linux/io.h>
19 #include <asm/cpu_device_id.h>
20 #include <asm/intel-family.h>
21 #include <asm/iosf_mbi.h>
22
23 /* Subsystem config/status Video processor */
24 #define VED_SS_PM0              0x32
25 /* Subsystem config/status ISP (Image Signal Processor) */
26 #define ISP_SS_PM0              0x39
27 /* Subsystem config/status Input/output controller */
28 #define MIO_SS_PM               0x3B
29 /* Shift bits for getting status for video, isp and i/o */
30 #define SSS_SHIFT               24
31
32 /* Power gate status reg */
33 #define PWRGT_STATUS            0x61
34 /* Shift bits for getting status for graphics rendering */
35 #define RENDER_POS              0
36 /* Shift bits for getting status for media control */
37 #define MEDIA_POS               2
38 /* Shift bits for getting status for Valley View/Baytrail display */
39 #define VLV_DISPLAY_POS         6
40
41 /* Subsystem config/status display for Cherry Trail SOC */
42 #define CHT_DSP_SSS             0x36
43 /* Shift bits for getting status for display */
44 #define CHT_DSP_SSS_POS         16
45
46 struct punit_device {
47         char *name;
48         int reg;
49         int sss_pos;
50 };
51
52 static const struct punit_device punit_device_tng[] = {
53         { "DISPLAY",    CHT_DSP_SSS,    SSS_SHIFT },
54         { "VED",        VED_SS_PM0,     SSS_SHIFT },
55         { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
56         { "MIO",        MIO_SS_PM,      SSS_SHIFT },
57         { NULL }
58 };
59
60 static const struct punit_device punit_device_byt[] = {
61         { "GFX RENDER", PWRGT_STATUS,   RENDER_POS },
62         { "GFX MEDIA",  PWRGT_STATUS,   MEDIA_POS },
63         { "DISPLAY",    PWRGT_STATUS,   VLV_DISPLAY_POS },
64         { "VED",        VED_SS_PM0,     SSS_SHIFT },
65         { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
66         { "MIO",        MIO_SS_PM,      SSS_SHIFT },
67         { NULL }
68 };
69
70 static const struct punit_device punit_device_cht[] = {
71         { "GFX RENDER", PWRGT_STATUS,   RENDER_POS },
72         { "GFX MEDIA",  PWRGT_STATUS,   MEDIA_POS },
73         { "DISPLAY",    CHT_DSP_SSS,    CHT_DSP_SSS_POS },
74         { "VED",        VED_SS_PM0,     SSS_SHIFT },
75         { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
76         { "MIO",        MIO_SS_PM,      SSS_SHIFT },
77         { NULL }
78 };
79
80 static const char * const dstates[] = {"D0", "D0i1", "D0i2", "D0i3"};
81
82 static int punit_dev_state_show(struct seq_file *seq_file, void *unused)
83 {
84         u32 punit_pwr_status;
85         struct punit_device *punit_devp = seq_file->private;
86         int index;
87         int status;
88
89         seq_puts(seq_file, "\n\nPUNIT NORTH COMPLEX DEVICES :\n");
90         while (punit_devp->name) {
91                 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
92                                        punit_devp->reg, &punit_pwr_status);
93                 if (status) {
94                         seq_printf(seq_file, "%9s : Read Failed\n",
95                                    punit_devp->name);
96                 } else  {
97                         index = (punit_pwr_status >> punit_devp->sss_pos) & 3;
98                         seq_printf(seq_file, "%9s : %s\n", punit_devp->name,
99                                    dstates[index]);
100                 }
101                 punit_devp++;
102         }
103
104         return 0;
105 }
106 DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
107
108 static struct dentry *punit_dbg_file;
109
110 static void punit_dbgfs_register(struct punit_device *punit_device)
111 {
112         punit_dbg_file = debugfs_create_dir("punit_atom", NULL);
113
114         debugfs_create_file("dev_power_state", 0444, punit_dbg_file,
115                             punit_device, &punit_dev_state_fops);
116 }
117
118 static void punit_dbgfs_unregister(void)
119 {
120         debugfs_remove_recursive(punit_dbg_file);
121 }
122
123 #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
124 static const struct punit_device *punit_dev;
125
126 static void punit_s2idle_check(void)
127 {
128         const struct punit_device *punit_devp;
129         u32 punit_pwr_status, dstate;
130         int status;
131
132         for (punit_devp = punit_dev; punit_devp->name; punit_devp++) {
133                 /* Skip MIO, it is on till the very last moment */
134                 if (punit_devp->reg == MIO_SS_PM)
135                         continue;
136
137                 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
138                                        punit_devp->reg, &punit_pwr_status);
139                 if (status) {
140                         pr_err("%s read failed\n", punit_devp->name);
141                 } else  {
142                         dstate = (punit_pwr_status >> punit_devp->sss_pos) & 3;
143                         if (!dstate)
144                                 pr_err("%s is in D0 prior to s2idle\n", punit_devp->name);
145                 }
146         }
147 }
148
149 static struct acpi_s2idle_dev_ops punit_s2idle_ops = {
150         .check = punit_s2idle_check,
151 };
152
153 static void punit_s2idle_check_register(struct punit_device *punit_device)
154 {
155         punit_dev = punit_device;
156         acpi_register_lps0_dev(&punit_s2idle_ops);
157 }
158
159 static void punit_s2idle_check_unregister(void)
160 {
161         acpi_unregister_lps0_dev(&punit_s2idle_ops);
162 }
163 #else
164 static void punit_s2idle_check_register(struct punit_device *punit_device) {}
165 static void punit_s2idle_check_unregister(void) {}
166 #endif
167
168 #define X86_MATCH(model, data)                                           \
169         X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
170                                            X86_FEATURE_MWAIT, data)
171
172 static const struct x86_cpu_id intel_punit_cpu_ids[] = {
173         X86_MATCH(ATOM_SILVERMONT,              &punit_device_byt),
174         X86_MATCH(ATOM_SILVERMONT_MID,          &punit_device_tng),
175         X86_MATCH(ATOM_AIRMONT,                 &punit_device_cht),
176         {}
177 };
178 MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
179
180 static int __init punit_atom_debug_init(void)
181 {
182         struct punit_device *punit_device;
183         const struct x86_cpu_id *id;
184
185         id = x86_match_cpu(intel_punit_cpu_ids);
186         if (!id)
187                 return -ENODEV;
188
189         punit_device = (struct punit_device *)id->driver_data;
190         punit_dbgfs_register(punit_device);
191         punit_s2idle_check_register(punit_device);
192
193         return 0;
194 }
195
196 static void __exit punit_atom_debug_exit(void)
197 {
198         punit_s2idle_check_unregister();
199         punit_dbgfs_unregister();
200 }
201
202 module_init(punit_atom_debug_init);
203 module_exit(punit_atom_debug_exit);
204
205 MODULE_AUTHOR("Kumar P, Mahesh <[email protected]>");
206 MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
207 MODULE_DESCRIPTION("Driver for Punit devices states debugging");
208 MODULE_LICENSE("GPL v2");
This page took 0.044912 seconds and 4 git commands to generate.