@@ -17,6 +17,7 @@
#include "sti_tvout.h"
#include "sti_hdmi.h"
#include "sti_hda.h"
+#include "sti_drm_drv.h"
/* glue regsiters */
#define TVO_CSC_MAIN_M0 0x000
@@ -604,6 +605,186 @@ void sti_tvout_disable(struct sti_tvout *tvout,
connector->stop(connector);
}
+/*
+ * Debugfs
+ */
+#define TVOUT_DBG_DUMP(reg) seq_printf(m, "\n %-25s 0x%08X", #reg, \
+ readl(tvout->regs + reg))
+#define TVOUT_CONNECTOR_NAME_MAX_LENGHT 10
+#define MAX_STRING_LENGTH 55
+
+static int sti_tvout_dbg_type_to_connector_name(enum sti_tvout_connector_type
+ type, char *name)
+{
+ switch (type) {
+ case STI_TVOUT_CONNECTOR_HDMI:
+ snprintf(name, TVOUT_CONNECTOR_NAME_MAX_LENGHT, "HDMI");
+ break;
+ case STI_TVOUT_CONNECTOR_HDA:
+ snprintf(name, TVOUT_CONNECTOR_NAME_MAX_LENGHT, "HD Analog");
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static void tvout_dbg_vip(struct seq_file *m, int val)
+{
+ int r, g, b, tmp, mask;
+ char str[MAX_STRING_LENGTH];
+ static const char *const reorder[] = { "Y_G", "Cb_B", "Cr_R" };
+ static const char *const clipping[] = { "No", "EAV/SAV",
+ "Limited range RGB/Y", "Limited range Cb/Cr",
+ "decided by register" };
+ static const char *const round[] = { "8-bit", "10-bit", "12-bit" };
+ static const char *const input_sel[] = { "Main (color matrix enabled)",
+ "Main (color matrix by-passed)", "", "", "", "", "", "",
+ "Aux (color matrix enabled)", "Aux (color matrix by-passed)",
+ "", "", "", "", "", "Force value"
+ };
+
+ seq_puts(m, "\t");
+
+ mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT;
+ r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT;
+ mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT;
+ g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT;
+ mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT;
+ b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT;
+ snprintf(str, MAX_STRING_LENGTH, "Reorder: %s->%s %s->%s %s->%s",
+ reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL],
+ reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL],
+ reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]);
+ seq_printf(m, "%-55s", str);
+
+ mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT;
+ tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT;
+ snprintf(str, MAX_STRING_LENGTH, "Clipping: %s", clipping[tmp]);
+ seq_printf(m, "%-55s", str);
+
+ seq_printf(m, "\n%-40s", "");
+
+ mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT;
+ tmp = (val & mask) >> TVO_VIP_RND_SHIFT;
+ snprintf(str, MAX_STRING_LENGTH,
+ "Round: input data rounded to %s per component", round[tmp]);
+ seq_printf(m, "%-55s", str);
+
+ tmp = (val & TVO_VIP_SEL_INPUT_MASK);
+ snprintf(str, MAX_STRING_LENGTH, "Input selection: %s", input_sel[tmp]);
+ seq_printf(m, "%-55s", str);
+}
+
+static void tvout_dbg_hd_dac_cfg(struct seq_file *m, int val)
+{
+ seq_puts(m, "\t HD DAC ");
+ seq_puts(m, val & 1 ? "disabled" : "enabled");
+}
+
+static int tvout_dbg_show(struct seq_file *m,
+ enum sti_tvout_connector_type type)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct sti_drm_private *dev_priv = dev->dev_private;
+ struct sti_tvout *tvout = dev_priv->tvout;
+ struct sti_tvout_connector *connector = tvout->connector[type];
+ char name[TVOUT_CONNECTOR_NAME_MAX_LENGHT];
+ int ret;
+
+ if (!connector)
+ return -1;
+
+ if (!connector->is_enabled)
+ return -1;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ if (tvout == NULL) {
+ seq_puts(m, "No tvout available");
+ goto out;
+ }
+
+ ret = sti_tvout_dbg_type_to_connector_name(type, name);
+ if (ret) {
+ seq_puts(m, "No connector!");
+ goto out;
+ }
+
+ seq_printf(m, "\n%s connector: ", name);
+ seq_printf(m, "\nTVOUT: (virt base addr = 0x%p)", tvout->regs);
+ if (connector->is_enabled(connector)) {
+ if (connector->main_path) {
+ seq_puts(m, "\n Connected to the main path");
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M0);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M1);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M2);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M3);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M4);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M5);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M6);
+ TVOUT_DBG_DUMP(TVO_CSC_MAIN_M7);
+ TVOUT_DBG_DUMP(TVO_MAIN_IN_VID_FORMAT);
+ } else {
+ seq_puts(m, "\n Connected to the auxiliary path");
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M0);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M2);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M3);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M4);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M5);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M6);
+ TVOUT_DBG_DUMP(TVO_CSC_AUX_M7);
+ TVOUT_DBG_DUMP(TVO_AUX_IN_VID_FORMAT);
+ }
+ } else
+ seq_puts(m, " Disabled");
+
+ switch (type) {
+ case STI_TVOUT_CONNECTOR_HDMI:
+ TVOUT_DBG_DUMP(TVO_VIP_HDMI);
+ tvout_dbg_vip(m, readl(tvout->regs + TVO_VIP_HDMI));
+ TVOUT_DBG_DUMP(TVO_HDMI_FORCE_COLOR_0);
+ TVOUT_DBG_DUMP(TVO_HDMI_FORCE_COLOR_1);
+ TVOUT_DBG_DUMP(TVO_HDMI_CLIP_VALUE_B_CB);
+ TVOUT_DBG_DUMP(TVO_HDMI_CLIP_VALUE_Y_G);
+ TVOUT_DBG_DUMP(TVO_HDMI_CLIP_VALUE_R_CR);
+ TVOUT_DBG_DUMP(TVO_HDMI_SYNC_SEL);
+ TVOUT_DBG_DUMP(TVO_HDMI_DFV_OBS);
+ break;
+ case STI_TVOUT_CONNECTOR_HDA:
+ TVOUT_DBG_DUMP(TVO_VIP_HDF);
+ tvout_dbg_vip(m, readl(tvout->regs + TVO_VIP_HDF));
+ TVOUT_DBG_DUMP(TVO_HD_SYNC_SEL);
+ TVOUT_DBG_DUMP(TVO_HD_DAC_CFG_OFF);
+ tvout_dbg_hd_dac_cfg(m,
+ readl(tvout->regs + TVO_HD_DAC_CFG_OFF));
+ break;
+ default:
+ goto out;
+ }
+
+ if (connector->dbg_show)
+ connector->dbg_show(connector, m);
+out:
+ seq_puts(m, "\n\n");
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+int sti_tvout_hdmi_dbg_show(struct seq_file *m, void *arg)
+{
+ return tvout_dbg_show(m, STI_TVOUT_CONNECTOR_HDMI);
+}
+
+int sti_tvout_hda_dbg_show(struct seq_file *m, void *arg)
+{
+ return tvout_dbg_show(m, STI_TVOUT_CONNECTOR_HDA);
+}
+
static int sti_tvout_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;