new file mode 100644
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2013
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STI_DRM_DRV_H_
+#define _STI_DRM_DRV_H_
+
+#include <linux/platform_device.h>
+
+#include <drm/drmP.h>
+
+#include "sti_compositor.h"
+#include "sti_tvout.h"
+
+extern struct platform_driver sti_compositor_driver;
+extern struct platform_driver sti_vtac_tx_driver;
+extern struct platform_driver sti_vtac_rx_driver;
+extern struct platform_driver sti_vtg_driver;
+extern struct platform_driver sti_tvout_driver;
+extern struct platform_driver sti_hdmi_driver;
+extern struct platform_driver sti_hda_driver;
+
+/*
+ * STI drm private structure
+ * This structure is stored as private in the drm_device
+ *
+ * @compo: compositor
+ * @tvout: TV OUT
+ * @pageflip_evt_list: list of pending page flip requests
+ * @plane_zorder_property: z-order property for CRTC planes
+ */
+struct sti_drm_private {
+ struct sti_compositor *compo;
+ struct sti_tvout *tvout;
+ struct list_head pageflip_evt_list;
+ struct drm_property *plane_zorder_property;
+};
+
+#define STI_MAX_FB_HEIGHT 4096
+#define STI_MAX_FB_WIDTH 4096
+
+#endif
@@ -9,9 +9,11 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include "sti_drm_drv.h"
#include "sti_layer.h"
#include "sti_gdp.h"
#include "sti_vtg_utils.h"
+#include "sti_compositor.h"
#define ENA_COLOR_FILL (1 << 8)
#define WAIT_NEXT_VSYNC (1 << 31)
@@ -29,6 +31,25 @@
#define GDP_YCBR422R 0x12
#define GDP_AYCBR8888 0x15
+#define GDP2STR(fmt) { GDP_ ## fmt, #fmt }
+
+static struct gdp_format_to_str {
+ int format;
+ char name[20];
+} sti_gdp_format_to_str[] = {
+ GDP2STR(RGB565),
+ GDP2STR(RGB888),
+ GDP2STR(RGB888_32),
+ GDP2STR(ARGB8565),
+ GDP2STR(ARGB8888),
+ GDP2STR(ARGB1555),
+ GDP2STR(ARGB4444),
+ GDP2STR(CLUT8),
+ GDP2STR(YCBR888),
+ GDP2STR(YCBR422R),
+ GDP2STR(AYCBR8888)
+ };
+
#define GAM_GDP_CTL_OFFSET 0x00
#define GAM_GDP_AGC_OFFSET 0x04
#define GAM_GDP_VPO_OFFSET 0x0C
@@ -137,6 +158,9 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer)
return &gdp->node_list[i];
end:
+ DRM_DEBUG_DRIVER("Warning, inconsistent NVN for %s: 0x%08X\n",
+ sti_layer_to_str(layer), hw_nvn);
+
return &gdp->node_list[0];
}
@@ -169,6 +193,8 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer)
return &gdp->node_list[i];
end:
+ DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
+ hw_nvn, sti_layer_to_str(layer));
return NULL;
}
@@ -198,6 +224,9 @@ static int sti_gdp_prepare_layer(void *lay, bool first_prepare)
top_field = list->top_field;
btm_field = list->btm_field;
+ dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
+ sti_layer_to_str(layer), top_field, btm_field);
+
/* Build the top field from layer params */
top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
@@ -294,6 +323,9 @@ static int sti_gdp_commit_layer(void *lay)
u32 dma_updated_btm = virt_to_dma(gdp->dev, updated_btm_node);
struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer);
+ dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
+ sti_layer_to_str(layer),
+ updated_top_node, updated_btm_node);
dev_dbg(gdp->dev, "Current NVN:0x%X\n",
readl(gdp->regs + GAM_GDP_NVN_OFFSET));
dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
@@ -303,6 +335,8 @@ static int sti_gdp_commit_layer(void *lay)
if (curr_list == NULL) {
/* First update or invalid node should directly write in the
* hw register */
+ DRM_DEBUG_DRIVER("%s first update (or invalid node)",
+ sti_layer_to_str(layer));
writel(gdp->is_curr_top == true ?
dma_updated_btm : dma_updated_top,
gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -342,6 +376,8 @@ static int sti_gdp_disable_layer(void *lay)
struct sti_layer *layer = (struct sti_layer *)lay;
struct sti_gdp *gdp = layer->gdp;
+ DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
+
/* Set the nodes as 'to be ignored on mixer' */
for (i = 0; i < GDP_NODE_NB_BANK; i++) {
gdp->node_list[i].top_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
@@ -489,3 +525,202 @@ mem_err:
devm_kfree(dev, gdp);
return NULL;
}
+
+static void sti_gdp_dbg_ctl(struct seq_file *m, int val)
+{
+ int i;
+
+ seq_puts(m, "\tColor:");
+ for (i = 0; i < ARRAY_SIZE(sti_gdp_format_to_str); i++) {
+ if (sti_gdp_format_to_str[i].format == (val & 0x1F)) {
+ seq_printf(m, sti_gdp_format_to_str[i].name);
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sti_gdp_format_to_str))
+ seq_puts(m, "<UNKNOWN>");
+
+ seq_printf(m, "\tWaitNextVsync:%d", val & WAIT_NEXT_VSYNC ? 1 : 0);
+}
+
+static void sti_gdp_dbg_vpo(struct seq_file *m, int val)
+{
+ seq_printf(m, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
+}
+
+static void sti_gdp_dbg_vps(struct seq_file *m, int val)
+{
+ seq_printf(m, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
+}
+
+static void sti_gdp_dbg_size(struct seq_file *m, int val)
+{
+ seq_printf(m, "\t%d x %d", val & 0x07FF, (val >> 16) & 0x07FF);
+}
+
+static void sti_gdp_dbg_nvn(struct seq_file *m, struct device *dev, int val)
+{
+ seq_puts(m, "\tVirt @: ");
+ if (val)
+ seq_printf(m, "%p", dma_to_virt(dev, (dma_addr_t) val));
+}
+
+static void sti_gdp_dbg_ppt(struct seq_file *m, int val)
+{
+ if (val & GAM_GDP_PPT_IGNORE)
+ seq_puts(m, "\tNot displayed on mixer!");
+}
+
+static void sti_gdp_dbg_mst(struct seq_file *m, int val)
+{
+ if (val & 1)
+ seq_puts(m, "\tBUFFER UNDERFLOW!");
+}
+
+#define GDP_DBG_DUMP(reg) seq_printf(m, "\n " #reg "\t 0x%08X", \
+ readl(gdp->regs + reg ## _OFFSET))
+
+int sti_gdp_dbg_show(struct seq_file *m, void *arg)
+{
+ 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_compositor *compo = dev_priv->compo;
+ int i, ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ if (compo == NULL) {
+ seq_puts(m, "No compositor available\n");
+ goto out;
+ }
+
+ for (i = 0; i < compo->nb_layers; i++) {
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct drm_framebuffer *fb;
+ struct sti_layer *layer = compo->layer[i];
+ struct sti_gdp *gdp = layer->gdp;
+ if ((layer->desc & STI_LAYER_TYPE_MASK) != STI_GDP)
+ continue;
+ seq_printf(m, "\n%s (associated with the mixer_id %d)",
+ sti_layer_to_str(layer), layer->mixer_id);
+ seq_printf(m, "\t %d frame updates",
+ layer->fps_info.curr_frame_counter);
+
+ GDP_DBG_DUMP(GAM_GDP_CTL);
+ sti_gdp_dbg_ctl(m, readl(gdp->regs + GAM_GDP_CTL_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_AGC);
+ GDP_DBG_DUMP(GAM_GDP_VPO);
+ sti_gdp_dbg_vpo(m, readl(gdp->regs + GAM_GDP_VPO_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_VPS);
+ sti_gdp_dbg_vps(m, readl(gdp->regs + GAM_GDP_VPS_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_PML);
+ GDP_DBG_DUMP(GAM_GDP_PMP);
+ GDP_DBG_DUMP(GAM_GDP_SIZE);
+ sti_gdp_dbg_size(m, readl(gdp->regs + GAM_GDP_SIZE_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_NVN);
+ sti_gdp_dbg_nvn(m, gdp->dev,
+ readl(gdp->regs + GAM_GDP_NVN_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_KEY1);
+ GDP_DBG_DUMP(GAM_GDP_KEY2);
+ GDP_DBG_DUMP(GAM_GDP_PPT);
+ sti_gdp_dbg_ppt(m, readl(gdp->regs + GAM_GDP_PPT_OFFSET));
+ GDP_DBG_DUMP(GAM_GDP_CML);
+ GDP_DBG_DUMP(GAM_GDP_MST);
+ sti_gdp_dbg_mst(m, readl(gdp->regs + GAM_GDP_MST_OFFSET));
+ seq_puts(m, "\n");
+
+ plane = &layer->plane;
+ if (!plane->base.id) {
+ seq_puts(m, " Not connected to any DRM PLANE\n");
+ continue;
+ }
+ seq_printf(m, " Connected to DRM PLANE #%d which is:\n",
+ plane->base.id);
+
+ crtc = plane->crtc;
+ if (!crtc) {
+ seq_puts(m, "\tNot connected to any DRM CRTC\n");
+ continue;
+ }
+ seq_printf(m, "\tConnected to DRM CRTC #%d\n", crtc->base.id);
+
+ fb = crtc->fb;
+ if (!fb) {
+ seq_puts(m, "\tNot connected to any DRM FB\n");
+ continue;
+ }
+ seq_printf(m, "\tConnected to DRM FB #%d, %dx%d, %.4s\n",
+ fb->base.id,
+ fb->width, fb->height, (char *)&fb->pixel_format);
+ }
+
+out:
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+static void sti_gdp_node_dump_node(struct seq_file *m,
+ struct sti_gdp_node *node)
+{
+ seq_printf(m, "\t@:0x%p", node);
+ seq_printf(m, "\n\tCTL 0x%08X", node->gam_gdp_ctl);
+ sti_gdp_dbg_ctl(m, node->gam_gdp_ctl);
+ seq_printf(m, "\n\tAGC 0x%08X", node->gam_gdp_agc);
+ seq_printf(m, "\n\tVPO 0x%08X", node->gam_gdp_vpo);
+ sti_gdp_dbg_vpo(m, node->gam_gdp_vpo);
+ seq_printf(m, "\n\tVPS 0x%08X", node->gam_gdp_vps);
+ sti_gdp_dbg_vps(m, node->gam_gdp_vps);
+ seq_printf(m, "\n\tPML 0x%08X", node->gam_gdp_pml);
+ seq_printf(m, "\n\tPMP 0x%08X", node->gam_gdp_pmp);
+ seq_printf(m, "\n\tSIZE 0x%08X", node->gam_gdp_size);
+ sti_gdp_dbg_size(m, node->gam_gdp_size);
+ seq_printf(m, "\n\tNVN 0x%08X", node->gam_gdp_nvn);
+ seq_printf(m, "\n\tKEY1 0x%08X", node->gam_gdp_key1);
+ seq_printf(m, "\n\tKEY2 0x%08X", node->gam_gdp_key2);
+ seq_printf(m, "\n\tPPT 0x%08X", node->gam_gdp_ppt);
+ sti_gdp_dbg_ppt(m, node->gam_gdp_ppt);
+ seq_printf(m, "\n\tCML 0x%08X", node->gam_gdp_cml);
+ seq_puts(m, "\n");
+}
+
+int sti_gdp_node_dbg_show(struct seq_file *m, void *arg)
+{
+ 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_compositor *compo = dev_priv->compo;
+ int i, ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ if (!compo) {
+ seq_puts(m, "No compositor available\n");
+ goto out;
+ }
+
+ for (i = 0; i < compo->nb_layers; i++) {
+ int b;
+ struct sti_layer *layer = compo->layer[i];
+ struct sti_gdp *gdp = layer->gdp;
+ if ((layer->desc & STI_LAYER_TYPE_MASK) != STI_GDP)
+ continue;
+
+ for (b = 0; b < GDP_NODE_NB_BANK; b++) {
+ seq_printf(m, "\n%s[%d].top",
+ sti_layer_to_str(layer), b);
+ sti_gdp_node_dump_node(m, gdp->node_list[b].top_field);
+ seq_printf(m, "\n%s[%d].btm",
+ sti_layer_to_str(layer), b);
+ sti_gdp_node_dump_node(m, gdp->node_list[b].btm_field);
+ }
+ }
+out:
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
@@ -69,5 +69,7 @@ struct sti_gdp {
struct sti_gdp *sti_gdp_create(struct device *dev, int id,
void __iomem *baseaddr);
+int sti_gdp_dbg_show(struct seq_file *m, void *arg);
+int sti_gdp_node_dbg_show(struct seq_file *m, void *arg);
#endif