On Wed, 1 Apr 2015 11:15:21 +0300 Jani Nikula <jani.nikula@xxxxxxxxx> wrote: > Occasionally it would be interesting to read some of the DPCD registers > for debug purposes, without having to resort to logging. Add an i915 > specific i915_dpcd debugfs file for DP and eDP connectors to dump parts > of the DPCD. Currently the DPCD addresses to be dumped are statically > configured, and more can be added trivially. > > The implementation also makes it relatively easy to add other i915 and > connector specific debugfs files in the future, as necessary. > > This is currently i915 specific just because there's no generic way to > do AUX transactions given just a drm_connector. However it's all pretty > straightforward to port to other drivers. > > v2: Add more DPCD registers to dump. > > Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> Reviewed-by: Bob Paauwe <bob.j.paauwe@xxxxxxxxx> > --- > drivers/gpu/drm/i915/i915_debugfs.c | 96 +++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/i915_drv.h | 1 + > drivers/gpu/drm/i915/intel_dp.c | 2 + > 3 files changed, 99 insertions(+) > > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c > index 007c7d7d8295..7164aa7d5fd3 100644 > --- a/drivers/gpu/drm/i915/i915_debugfs.c > +++ b/drivers/gpu/drm/i915/i915_debugfs.c > @@ -4780,3 +4780,99 @@ void i915_debugfs_cleanup(struct drm_minor *minor) > drm_debugfs_remove_files(info_list, 1, minor); > } > } > + > +struct dpcd_block { > + /* DPCD dump start address. */ > + unsigned int offset; > + /* DPCD dump end address, inclusive. If unset, .size will be used. */ > + unsigned int end; > + /* DPCD dump size. Used if .end is unset. If unset, defaults to 1. */ > + size_t size; > + /* Only valid for eDP. */ > + bool edp; > +}; > + > +static const struct dpcd_block i915_dpcd_debug[] = { > + { .offset = DP_DPCD_REV, .size = DP_RECEIVER_CAP_SIZE }, > + { .offset = DP_PSR_SUPPORT, .end = DP_PSR_CAPS }, > + { .offset = DP_DOWNSTREAM_PORT_0, .size = 16 }, > + { .offset = DP_LINK_BW_SET, .end = DP_EDP_CONFIGURATION_SET }, > + { .offset = DP_SINK_COUNT, .end = DP_ADJUST_REQUEST_LANE2_3 }, > + { .offset = DP_SET_POWER }, > + { .offset = DP_EDP_DPCD_REV }, > + { .offset = DP_EDP_GENERAL_CAP_1, .end = DP_EDP_GENERAL_CAP_3 }, > + { .offset = DP_EDP_DISPLAY_CONTROL_REGISTER, .end = DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB }, > + { .offset = DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET, .end = DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET }, > +}; > + > +static int i915_dpcd_show(struct seq_file *m, void *data) > +{ > + struct drm_connector *connector = m->private; > + struct intel_dp *intel_dp = > + enc_to_intel_dp(&intel_attached_encoder(connector)->base); > + uint8_t buf[16]; > + ssize_t err; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(i915_dpcd_debug); i++) { > + const struct dpcd_block *b = &i915_dpcd_debug[i]; > + size_t size = b->end ? b->end - b->offset + 1 : (b->size ?: 1); > + > + if (b->edp && > + connector->connector_type != DRM_MODE_CONNECTOR_eDP) > + continue; > + > + /* low tech for now */ > + if (WARN_ON(size > sizeof(buf))) > + continue; > + > + err = drm_dp_dpcd_read(&intel_dp->aux, b->offset, buf, size); > + if (err <= 0) { > + DRM_ERROR("dpcd read (%zu bytes at %u) failed (%zd)\n", > + size, b->offset, err); > + continue; > + } > + > + seq_printf(m, "%04x: %*ph\n", b->offset, (int) size, buf); > + }; > + > + return 0; > +} > + > +static int i915_dpcd_open(struct inode *inode, struct file *file) > +{ > + return single_open(file, i915_dpcd_show, inode->i_private); > +} > + > +static const struct file_operations i915_dpcd_fops = { > + .owner = THIS_MODULE, > + .open = i915_dpcd_open, > + .read = seq_read, > + .llseek = seq_lseek, > + .release = single_release, > +}; > + > +/** > + * i915_debugfs_connector_add - add i915 specific connector debugfs files > + * @connector: pointer to a registered drm_connector > + * > + * Cleanup will be done by drm_connector_unregister() through a call to > + * drm_debugfs_connector_remove(). > + * > + * Returns 0 on success, negative error codes on error. > + */ > +int i915_debugfs_connector_add(struct drm_connector *connector) > +{ > + struct dentry *root = connector->debugfs_entry; > + > + /* The connector must have been registered beforehands. */ > + if (!root) > + return -ENODEV; > + > + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || > + connector->connector_type == DRM_MODE_CONNECTOR_eDP) > + debugfs_create_file("i915_dpcd", S_IRUGO, root, connector, > + &i915_dpcd_fops); > + > + return 0; > +} > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index aadada5a3fe9..868f26780115 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -3011,6 +3011,7 @@ int i915_verify_lists(struct drm_device *dev); > /* i915_debugfs.c */ > int i915_debugfs_init(struct drm_minor *minor); > void i915_debugfs_cleanup(struct drm_minor *minor); > +int i915_debugfs_connector_add(struct drm_connector *connector); > #ifdef CONFIG_DEBUG_FS > void intel_display_crc_init(struct drm_device *dev); > #else > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > index 7936155acbe8..f91ce9e94aa6 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -5569,6 +5569,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, > I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); > } > > + i915_debugfs_connector_add(connector); > + > return true; > } > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx