linux/arch/x86/platform/atom/punit_atom_debug.c
<<
>>
Prefs
   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#include <linux/module.h>
  11#include <linux/init.h>
  12#include <linux/device.h>
  13#include <linux/debugfs.h>
  14#include <linux/seq_file.h>
  15#include <linux/io.h>
  16#include <asm/cpu_device_id.h>
  17#include <asm/intel-family.h>
  18#include <asm/iosf_mbi.h>
  19
  20/* Subsystem config/status Video processor */
  21#define VED_SS_PM0              0x32
  22/* Subsystem config/status ISP (Image Signal Processor) */
  23#define ISP_SS_PM0              0x39
  24/* Subsystem config/status Input/output controller */
  25#define MIO_SS_PM               0x3B
  26/* Shift bits for getting status for video, isp and i/o */
  27#define SSS_SHIFT               24
  28
  29/* Power gate status reg */
  30#define PWRGT_STATUS            0x61
  31/* Shift bits for getting status for graphics rendering */
  32#define RENDER_POS              0
  33/* Shift bits for getting status for media control */
  34#define MEDIA_POS               2
  35/* Shift bits for getting status for Valley View/Baytrail display */
  36#define VLV_DISPLAY_POS         6
  37
  38/* Subsystem config/status display for Cherry Trail SOC */
  39#define CHT_DSP_SSS             0x36
  40/* Shift bits for getting status for display */
  41#define CHT_DSP_SSS_POS         16
  42
  43struct punit_device {
  44        char *name;
  45        int reg;
  46        int sss_pos;
  47};
  48
  49static const struct punit_device punit_device_tng[] = {
  50        { "DISPLAY",    CHT_DSP_SSS,    SSS_SHIFT },
  51        { "VED",        VED_SS_PM0,     SSS_SHIFT },
  52        { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
  53        { "MIO",        MIO_SS_PM,      SSS_SHIFT },
  54        { NULL }
  55};
  56
  57static const struct punit_device punit_device_byt[] = {
  58        { "GFX RENDER", PWRGT_STATUS,   RENDER_POS },
  59        { "GFX MEDIA",  PWRGT_STATUS,   MEDIA_POS },
  60        { "DISPLAY",    PWRGT_STATUS,   VLV_DISPLAY_POS },
  61        { "VED",        VED_SS_PM0,     SSS_SHIFT },
  62        { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
  63        { "MIO",        MIO_SS_PM,      SSS_SHIFT },
  64        { NULL }
  65};
  66
  67static const struct punit_device punit_device_cht[] = {
  68        { "GFX RENDER", PWRGT_STATUS,   RENDER_POS },
  69        { "GFX MEDIA",  PWRGT_STATUS,   MEDIA_POS },
  70        { "DISPLAY",    CHT_DSP_SSS,    CHT_DSP_SSS_POS },
  71        { "VED",        VED_SS_PM0,     SSS_SHIFT },
  72        { "ISP",        ISP_SS_PM0,     SSS_SHIFT },
  73        { "MIO",        MIO_SS_PM,      SSS_SHIFT },
  74        { NULL }
  75};
  76
  77static const char * const dstates[] = {"D0", "D0i1", "D0i2", "D0i3"};
  78
  79static int punit_dev_state_show(struct seq_file *seq_file, void *unused)
  80{
  81        u32 punit_pwr_status;
  82        struct punit_device *punit_devp = seq_file->private;
  83        int index;
  84        int status;
  85
  86        seq_puts(seq_file, "\n\nPUNIT NORTH COMPLEX DEVICES :\n");
  87        while (punit_devp->name) {
  88                status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
  89                                       punit_devp->reg, &punit_pwr_status);
  90                if (status) {
  91                        seq_printf(seq_file, "%9s : Read Failed\n",
  92                                   punit_devp->name);
  93                } else  {
  94                        index = (punit_pwr_status >> punit_devp->sss_pos) & 3;
  95                        seq_printf(seq_file, "%9s : %s\n", punit_devp->name,
  96                                   dstates[index]);
  97                }
  98                punit_devp++;
  99        }
 100
 101        return 0;
 102}
 103DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
 104
 105static struct dentry *punit_dbg_file;
 106
 107static void punit_dbgfs_register(struct punit_device *punit_device)
 108{
 109        punit_dbg_file = debugfs_create_dir("punit_atom", NULL);
 110
 111        debugfs_create_file("dev_power_state", 0444, punit_dbg_file,
 112                            punit_device, &punit_dev_state_fops);
 113}
 114
 115static void punit_dbgfs_unregister(void)
 116{
 117        debugfs_remove_recursive(punit_dbg_file);
 118}
 119
 120#define X86_MATCH(model, data)                                           \
 121        X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
 122                                           X86_FEATURE_MWAIT, data)
 123
 124static const struct x86_cpu_id intel_punit_cpu_ids[] = {
 125        X86_MATCH(ATOM_SILVERMONT,              &punit_device_byt),
 126        X86_MATCH(ATOM_SILVERMONT_MID,          &punit_device_tng),
 127        X86_MATCH(ATOM_AIRMONT,                 &punit_device_cht),
 128        {}
 129};
 130MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
 131
 132static int __init punit_atom_debug_init(void)
 133{
 134        const struct x86_cpu_id *id;
 135
 136        id = x86_match_cpu(intel_punit_cpu_ids);
 137        if (!id)
 138                return -ENODEV;
 139
 140        punit_dbgfs_register((struct punit_device *)id->driver_data);
 141
 142        return 0;
 143}
 144
 145static void __exit punit_atom_debug_exit(void)
 146{
 147        punit_dbgfs_unregister();
 148}
 149
 150module_init(punit_atom_debug_init);
 151module_exit(punit_atom_debug_exit);
 152
 153MODULE_AUTHOR("Kumar P, Mahesh <mahesh.kumar.p@intel.com>");
 154MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 155MODULE_DESCRIPTION("Driver for Punit devices states debugging");
 156MODULE_LICENSE("GPL v2");
 157