Commit cf481068 authored by Dave Airlie's avatar Dave Airlie

Merge branch '2016-02-26-st-drm-next' of...

Merge branch '2016-02-26-st-drm-next' of http://git.linaro.org/people/benjamin.gaignard/kernel into drm-next

Here are sti patches for drm-next.
It brings:
  - The support of the atomic_check for the planes and minor fixes for
planes
  - The support of the vendor specific infoframe for HDMI and the
support of 2 HDMI properties related to the connector
  - The support of the DVO solving panel detection issue and timing issue.
  - The support of debugfs for connectors, encoders, crtcs and planes.

* '2016-02-26-st-drm-next' of http://git.linaro.org/people/benjamin.gaignard/kernel: (36 commits)
  drm/sti: use u32 to store DMA addresses
  drm: sti: remove sti_gem_prime_export hack
  drm/sti: add debugfs fps_show/fps_get mechanism for planes
  drm/sti: add debugfs entries for TVOUT encoders
  drm/sti: add debugfs entries for MIXER crtc
  drm/sti: add debugfs entries for VID plane
  drm/sti: add debugfs entries for HQVDP plane
  drm/sti: add debugfs entries for GDP planes
  drm/sti: add debugfs entries for CURSOR plane
  drm/sti: add debugfs entries for HDA connector
  drm/sti: add debugfs entries for DVO connector
  drm/sti: add debugfs entries for HDMI connector
  drm/sti: add hdmi_mode property for HDMI connector
  drm/sti: add colorspace property to the HDMI connector
  drm/sti: add HDMI vendor specific infoframe
  drm/sti: reset infoframe transmission when HDMI is stopped
  drm/sti: HDMI infoframe transmission mode not take into account
  drm/sti: reset HD DACS when HDA connector is created
  drm/sti: fix dvo data_enable signal
  drm/sti: adjust delay for DVO
  ...
parents 9f443bf5 52807ae9
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "sti_awg_utils.h" #include "sti_awg_utils.h"
#define AWG_OPCODE_OFFSET 10 #define AWG_OPCODE_OFFSET 10
#define AWG_MAX_ARG 0x3ff
enum opcode { enum opcode {
SET, SET,
...@@ -34,6 +35,8 @@ static int awg_generate_instr(enum opcode opcode, ...@@ -34,6 +35,8 @@ static int awg_generate_instr(enum opcode opcode,
/* skip, repeat and replay arg should not exceed 1023. /* skip, repeat and replay arg should not exceed 1023.
* If user wants to exceed this value, the instruction should be * If user wants to exceed this value, the instruction should be
* duplicate and arg should be adjust for each duplicated instruction. * duplicate and arg should be adjust for each duplicated instruction.
*
* mux_sel is used in case of SAV/EAV synchronization.
*/ */
while (arg_tmp > 0) { while (arg_tmp > 0) {
...@@ -65,7 +68,7 @@ static int awg_generate_instr(enum opcode opcode, ...@@ -65,7 +68,7 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0; mux = 0;
data_enable = 0; data_enable = 0;
arg &= (0x3ff); arg &= AWG_MAX_ARG;
break; break;
case REPEAT: case REPEAT:
case REPLAY: case REPLAY:
...@@ -76,13 +79,13 @@ static int awg_generate_instr(enum opcode opcode, ...@@ -76,13 +79,13 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0; mux = 0;
data_enable = 0; data_enable = 0;
arg &= (0x3ff); arg &= AWG_MAX_ARG;
break; break;
case JUMP: case JUMP:
mux = 0; mux = 0;
data_enable = 0; data_enable = 0;
arg |= 0x40; /* for jump instruction 7th bit is 1 */ arg |= 0x40; /* for jump instruction 7th bit is 1 */
arg &= 0x3ff; arg &= AWG_MAX_ARG;
break; break;
case STOP: case STOP:
arg = 0; arg = 0;
...@@ -110,68 +113,75 @@ static int awg_generate_instr(enum opcode opcode, ...@@ -110,68 +113,75 @@ static int awg_generate_instr(enum opcode opcode,
return 0; return 0;
} }
int sti_awg_generate_code_data_enable_mode( static int awg_generate_line_signal(
struct awg_code_generation_params *fwparams, struct awg_code_generation_params *fwparams,
struct awg_timing *timing) struct awg_timing *timing)
{ {
long int val; long int val;
long int data_en;
int ret = 0; int ret = 0;
if (timing->trailing_lines > 0) {
/* skip trailing lines */
val = timing->blanking_level;
data_en = 0;
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
val = timing->trailing_lines - 1;
data_en = 0;
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
}
if (timing->trailing_pixels > 0) { if (timing->trailing_pixels > 0) {
/* skip trailing pixel */ /* skip trailing pixel */
val = timing->blanking_level; val = timing->blanking_level;
data_en = 0; ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
val = timing->trailing_pixels - 1; val = timing->trailing_pixels - 1;
data_en = 0; ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
} }
/* set DE signal high */ /* set DE signal high */
val = timing->blanking_level; val = timing->blanking_level;
data_en = 1;
ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET, ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
val, 0, data_en, fwparams); val, 0, 1, fwparams);
if (timing->blanking_pixels > 0) { if (timing->blanking_pixels > 0) {
/* skip the number of active pixel */ /* skip the number of active pixel */
val = timing->active_pixels - 1; val = timing->active_pixels - 1;
data_en = 1; ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams);
ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
/* set DE signal low */ /* set DE signal low */
val = timing->blanking_level; val = timing->blanking_level;
data_en = 0; ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
ret |= awg_generate_instr(SET, val, 0, data_en, fwparams); }
return ret;
}
int sti_awg_generate_code_data_enable_mode(
struct awg_code_generation_params *fwparams,
struct awg_timing *timing)
{
long int val, tmp_val;
int ret = 0;
if (timing->trailing_lines > 0) {
/* skip trailing lines */
val = timing->blanking_level;
ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
val = timing->trailing_lines - 1;
ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
} }
tmp_val = timing->active_lines - 1;
while (tmp_val > 0) {
/* generate DE signal for each line */
ret |= awg_generate_line_signal(fwparams, timing);
/* replay the sequence as many active lines defined */ /* replay the sequence as many active lines defined */
val = timing->active_lines - 1; ret |= awg_generate_instr(REPLAY,
data_en = 0; min_t(int, AWG_MAX_ARG, tmp_val),
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); 0, 0, fwparams);
tmp_val -= AWG_MAX_ARG;
}
if (timing->blanking_lines > 0) { if (timing->blanking_lines > 0) {
/* skip blanking lines */ /* skip blanking lines */
val = timing->blanking_level; val = timing->blanking_level;
data_en = 0; ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
val = timing->blanking_lines - 1; val = timing->blanking_lines - 1;
data_en = 0; ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
} }
return ret; return ret;
......
...@@ -75,13 +75,13 @@ static int sti_compositor_bind(struct device *dev, ...@@ -75,13 +75,13 @@ static int sti_compositor_bind(struct device *dev,
switch (desc[i].type) { switch (desc[i].type) {
case STI_VID_SUBDEV: case STI_VID_SUBDEV:
compo->vid[vid_id++] = compo->vid[vid_id++] =
sti_vid_create(compo->dev, desc[i].id, sti_vid_create(compo->dev, drm_dev, desc[i].id,
compo->regs + desc[i].offset); compo->regs + desc[i].offset);
break; break;
case STI_MIXER_MAIN_SUBDEV: case STI_MIXER_MAIN_SUBDEV:
case STI_MIXER_AUX_SUBDEV: case STI_MIXER_AUX_SUBDEV:
compo->mixer[mixer_id++] = compo->mixer[mixer_id++] =
sti_mixer_create(compo->dev, desc[i].id, sti_mixer_create(compo->dev, drm_dev, desc[i].id,
compo->regs + desc[i].offset); compo->regs + desc[i].offset);
break; break;
case STI_GPD_SUBDEV: case STI_GPD_SUBDEV:
......
...@@ -51,6 +51,15 @@ static void sti_crtc_disabling(struct drm_crtc *crtc) ...@@ -51,6 +51,15 @@ static void sti_crtc_disabling(struct drm_crtc *crtc)
mixer->status = STI_MIXER_DISABLING; mixer->status = STI_MIXER_DISABLING;
} }
static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
/* accept the provided drm_display_mode, do not fix it up */
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
return true;
}
static int static int
sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
{ {
......
...@@ -5,12 +5,10 @@ ...@@ -5,12 +5,10 @@
* for STMicroelectronics. * for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
*/ */
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
#include "sti_compositor.h" #include "sti_compositor.h"
#include "sti_cursor.h" #include "sti_cursor.h"
...@@ -74,6 +72,82 @@ static const uint32_t cursor_supported_formats[] = { ...@@ -74,6 +72,82 @@ static const uint32_t cursor_supported_formats[] = {
#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
readl(cursor->regs + reg))
static void cursor_dbg_vpo(struct seq_file *s, u32 val)
{
seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
}
static void cursor_dbg_size(struct seq_file *s, u32 val)
{
seq_printf(s, "\t%d x %d", val & 0x07FF, (val >> 16) & 0x07FF);
}
static void cursor_dbg_pml(struct seq_file *s,
struct sti_cursor *cursor, u32 val)
{
if (cursor->pixmap.paddr == val)
seq_printf(s, "\tVirt @: %p", cursor->pixmap.base);
}
static void cursor_dbg_cml(struct seq_file *s,
struct sti_cursor *cursor, u32 val)
{
if (cursor->clut_paddr == val)
seq_printf(s, "\tVirt @: %p", cursor->clut);
}
static int cursor_dbg_show(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct sti_cursor *cursor = (struct sti_cursor *)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(s, "%s: (vaddr = 0x%p)",
sti_plane_to_str(&cursor->plane), cursor->regs);
DBGFS_DUMP(CUR_CTL);
DBGFS_DUMP(CUR_VPO);
cursor_dbg_vpo(s, readl(cursor->regs + CUR_VPO));
DBGFS_DUMP(CUR_PML);
cursor_dbg_pml(s, cursor, readl(cursor->regs + CUR_PML));
DBGFS_DUMP(CUR_PMP);
DBGFS_DUMP(CUR_SIZE);
cursor_dbg_size(s, readl(cursor->regs + CUR_SIZE));
DBGFS_DUMP(CUR_CML);
cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML));
DBGFS_DUMP(CUR_AWS);
DBGFS_DUMP(CUR_AWE);
seq_puts(s, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list cursor_debugfs_files[] = {
{ "cursor", cursor_dbg_show, 0, NULL },
};
static int cursor_debugfs_init(struct sti_cursor *cursor,
struct drm_minor *minor)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cursor_debugfs_files); i++)
cursor_debugfs_files[i].data = cursor;
return drm_debugfs_create_files(cursor_debugfs_files,
ARRAY_SIZE(cursor_debugfs_files),
minor->debugfs_root, minor);
}
static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
{ {
u8 *dst = cursor->pixmap.base; u8 *dst = cursor->pixmap.base;
...@@ -110,35 +184,31 @@ static void sti_cursor_init(struct sti_cursor *cursor) ...@@ -110,35 +184,31 @@ static void sti_cursor_init(struct sti_cursor *cursor)
(b * 5); (b * 5);
} }
static void sti_cursor_atomic_update(struct drm_plane *drm_plane, static int sti_cursor_atomic_check(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *state)
{ {
struct drm_plane_state *state = drm_plane->state;
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_cursor *cursor = to_sti_cursor(plane); struct sti_cursor *cursor = to_sti_cursor(plane);
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->crtc;
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->fb;
struct drm_display_mode *mode = &crtc->mode; struct drm_crtc_state *crtc_state;
int dst_x = state->crtc_x; struct drm_display_mode *mode;
int dst_y = state->crtc_y; int dst_x, dst_y, dst_w, dst_h;
int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); int src_w, src_h;
int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
/* no need for further checks if the plane is being disabled */
if (!crtc || !fb)
return 0;
crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
mode = &crtc_state->mode;
dst_x = state->crtc_x;
dst_y = state->crtc_y;
dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
/* src_x are in 16.16 format */ /* src_x are in 16.16 format */
int src_w = state->src_w >> 16; src_w = state->src_w >> 16;
int src_h = state->src_h >> 16; src_h = state->src_h >> 16;
bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
struct drm_gem_cma_object *cma_obj;
u32 y, x;
u32 val;
DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
crtc->base.id, sti_mixer_to_str(mixer),
drm_plane->base.id, sti_plane_to_str(plane));
DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
dev_dbg(cursor->dev, "%s %s\n", __func__,
sti_plane_to_str(plane));
if (src_w < STI_CURS_MIN_SIZE || if (src_w < STI_CURS_MIN_SIZE ||
src_h < STI_CURS_MIN_SIZE || src_h < STI_CURS_MIN_SIZE ||
...@@ -146,7 +216,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, ...@@ -146,7 +216,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
src_h > STI_CURS_MAX_SIZE) { src_h > STI_CURS_MAX_SIZE) {
DRM_ERROR("Invalid cursor size (%dx%d)\n", DRM_ERROR("Invalid cursor size (%dx%d)\n",
src_w, src_h); src_w, src_h);
return; return -EINVAL;
} }
/* If the cursor size has changed, re-allocated the pixmap */ /* If the cursor size has changed, re-allocated the pixmap */
...@@ -170,16 +240,46 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, ...@@ -170,16 +240,46 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
GFP_KERNEL | GFP_DMA); GFP_KERNEL | GFP_DMA);
if (!cursor->pixmap.base) { if (!cursor->pixmap.base) {
DRM_ERROR("Failed to allocate memory for pixmap\n"); DRM_ERROR("Failed to allocate memory for pixmap\n");
return; return -EINVAL;
} }
} }
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); if (!drm_fb_cma_get_gem_obj(fb, 0)) {
if (!cma_obj) {
DRM_ERROR("Can't get CMA GEM object for fb\n"); DRM_ERROR("Can't get CMA GEM object for fb\n");
return; return -EINVAL;
} }
DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)),
drm_plane->base.id, sti_plane_to_str(plane));
DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
return 0;
}
static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate)
{
struct drm_plane_state *state = drm_plane->state;
struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_cursor *cursor = to_sti_cursor(plane);
struct drm_crtc *crtc = state->crtc;
struct drm_framebuffer *fb = state->fb;
struct drm_display_mode *mode;
int dst_x, dst_y;
struct drm_gem_cma_object *cma_obj;
u32 y, x;
u32 val;
if (!crtc || !fb)
return;
mode = &crtc->mode;
dst_x = state->crtc_x;
dst_y = state->crtc_y;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
/* Convert ARGB8888 to CLUT8 */ /* Convert ARGB8888 to CLUT8 */
sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
...@@ -193,21 +293,21 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, ...@@ -193,21 +293,21 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
val = y << 16 | x; val = y << 16 | x;
writel(val, cursor->regs + CUR_AWE); writel(val, cursor->regs + CUR_AWE);
if (first_prepare) {
/* Set and fetch CLUT */
writel(cursor->clut_paddr, cursor->regs + CUR_CML);
writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
}
/* Set memory location, size, and position */ /* Set memory location, size, and position */
writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
writel(cursor->width, cursor->regs + CUR_PMP); writel(cursor->width, cursor->regs + CUR_PMP);
writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
y = sti_vtg_get_line_number(*mode, dst_y); y = sti_vtg_get_line_number(*mode, dst_y);
x = sti_vtg_get_pixel_number(*mode, dst_y); x = sti_vtg_get_pixel_number(*mode, dst_x);
writel((y << 16) | x, cursor->regs + CUR_VPO); writel((y << 16) | x, cursor->regs + CUR_VPO);
/* Set and fetch CLUT */
writel(cursor->clut_paddr, cursor->regs + CUR_CML);
writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
sti_plane_update_fps(plane, true, false);
plane->status = STI_PLANE_UPDATED; plane->status = STI_PLANE_UPDATED;
} }
...@@ -215,7 +315,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, ...@@ -215,7 +315,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *oldstate)
{ {
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { if (!drm_plane->crtc) {
DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
...@@ -224,13 +323,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, ...@@ -224,13 +323,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
} }
DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
drm_plane->crtc->base.id, sti_mixer_to_str(mixer), drm_plane->crtc->base.id,
sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)),
drm_plane->base.id, sti_plane_to_str(plane)); drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; plane->status = STI_PLANE_DISABLING;
} }
static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
.atomic_check = sti_cursor_atomic_check,
.atomic_update = sti_cursor_atomic_update, .atomic_update = sti_cursor_atomic_update,
.atomic_disable = sti_cursor_atomic_disable, .atomic_disable = sti_cursor_atomic_disable,
}; };
...@@ -283,6 +384,9 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, ...@@ -283,6 +384,9 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
if (cursor_debugfs_init(cursor, drm_dev->primary))
DRM_ERROR("CURSOR debugfs setup failed\n");
return &cursor->plane.drm_plane; return &cursor->plane.drm_plane;
err_plane: err_plane:
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "sti_crtc.h" #include "sti_crtc.h"
#include "sti_drv.h" #include "sti_drv.h"
#include "sti_plane.h"
#define DRIVER_NAME "sti" #define DRIVER_NAME "sti"
#define DRIVER_DESC "STMicroelectronics SoC DRM" #define DRIVER_DESC "STMicroelectronics SoC DRM"
...@@ -30,6 +31,130 @@ ...@@ -30,6 +31,130 @@
#define STI_MAX_FB_HEIGHT 4096 #define STI_MAX_FB_HEIGHT 4096
#define STI_MAX_FB_WIDTH 4096 #define STI_MAX_FB_WIDTH 4096
static int sti_drm_fps_get(void *data, u64 *val)
{
struct drm_device *drm_dev = data;
struct drm_plane *p;
unsigned int i = 0;
*val = 0;
list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
struct sti_plane *plane = to_sti_plane(p);
*val |= plane->fps_info.output << i;
i++;
}
return 0;
}
static int sti_drm_fps_set(void *data, u64 val)
{
struct drm_device *drm_dev = data;
struct drm_plane *p;
unsigned int i = 0;
list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
struct sti_plane *plane = to_sti_plane(p);
plane->fps_info.output = (val >> i) & 1;
i++;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops,
sti_drm_fps_get, sti_drm_fps_set, "%llu\n");
static int sti_drm_fps_dbg_show(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct drm_device *dev = node->minor->dev;
struct drm_plane *p;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
list_for_each_entry(p, &dev->mode_config.plane_list, head) {
struct sti_plane *plane = to_sti_plane(p);
seq_printf(s, "%s%s\n",
plane->fps_info.fps_str,
plane->fps_info.fips_str);
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list sti_drm_dbg_list[] = {
{"fps_get", sti_drm_fps_dbg_show, 0},
};
static int sti_drm_debugfs_create(struct dentry *root,
struct drm_minor *minor,
const char *name,
const struct file_operations *fops)
{
struct drm_device *dev = minor->dev;
struct drm_info_node *node;
struct dentry *ent;
ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, fops);
if (IS_ERR(ent))
return PTR_ERR(ent);
node = kmalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
debugfs_remove(ent);
return -ENOMEM;
}
node->minor = minor;
node->dent = ent;
node->info_ent = (void *)fops;
mutex_lock(&minor->debugfs_lock);
list_add(&node->list, &minor->debugfs_list);
mutex_unlock(&minor->debugfs_lock);
return 0;
}
static int sti_drm_dbg_init(struct drm_minor *minor)
{
int ret;
ret = drm_debugfs_create_files(sti_drm_dbg_list,
ARRAY_SIZE(sti_drm_dbg_list),
minor->debugfs_root, minor);
if (ret)
goto err;
ret = sti_drm_debugfs_create(minor->debugfs_root, minor, "fps_show",
&sti_drm_fps_fops);
if (ret)
goto err;
DRM_INFO("%s: debugfs installed\n", DRIVER_NAME);
return 0;
err:
DRM_ERROR("%s: cannot install debugfs\n", DRIVER_NAME);
return ret;
}
void sti_drm_dbg_cleanup(struct drm_minor *minor)
{
drm_debugfs_remove_files(sti_drm_dbg_list,
ARRAY_SIZE(sti_drm_dbg_list), minor);
drm_debugfs_remove_files((struct drm_info_list *)&sti_drm_fps_fops,
1, minor);
}
static void sti_atomic_schedule(struct sti_private *private, static void sti_atomic_schedule(struct sti_private *private,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
...@@ -181,18 +306,9 @@ static const struct file_operations sti_driver_fops = { ...@@ -181,18 +306,9 @@ static const struct file_operations sti_driver_fops = {
.release = drm_release, .release = drm_release,
}; };
static struct dma_buf *sti_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *obj,
int flags)
{
/* we want to be able to write in mmapped buffer */
flags |= O_RDWR;
return drm_gem_prime_export(dev, obj, flags);
}
static struct drm_driver sti_driver = { static struct drm_driver sti_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
DRIVER_GEM | DRIVER_PRIME, DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
.load = sti_load, .load = sti_load,
.gem_free_object = drm_gem_cma_free_object, .gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
...@@ -207,7 +323,7 @@ static struct drm_driver sti_driver = { ...@@ -207,7 +323,7 @@ static struct drm_driver sti_driver = {
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = sti_gem_prime_export, .gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import, .gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
...@@ -215,6 +331,9 @@ static struct drm_driver sti_driver = { ...@@ -215,6 +331,9 @@ static struct drm_driver sti_driver = {
.gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap, .gem_prime_mmap = drm_gem_cma_prime_mmap,
.debugfs_init = sti_drm_dbg_init,
.debugfs_cleanup = sti_drm_dbg_cleanup,
.name = DRIVER_NAME, .name = DRIVER_NAME,
.desc = DRIVER_DESC, .desc = DRIVER_DESC,
.date = DRIVER_DATE, .date = DRIVER_DATE,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/debugfs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -156,6 +157,69 @@ static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb) ...@@ -156,6 +157,69 @@ static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL); writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
} }
#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
readl(dvo->regs + reg))
static void dvo_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
{
unsigned int i;
seq_puts(s, "\n\n");
seq_puts(s, " DVO AWG microcode:");
for (i = 0; i < AWG_MAX_INST; i++) {
if (i % 8 == 0)
seq_printf(s, "\n %04X:", i);
seq_printf(s, " %04X", readl(reg + i * 4));
}
}
static int dvo_dbg_show(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct sti_dvo *dvo = (struct sti_dvo *)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(s, "DVO: (vaddr = 0x%p)", dvo->regs);
DBGFS_DUMP(DVO_AWG_DIGSYNC_CTRL);
DBGFS_DUMP(DVO_DOF_CFG);
DBGFS_DUMP(DVO_LUT_PROG_LOW);
DBGFS_DUMP(DVO_LUT_PROG_MID);
DBGFS_DUMP(DVO_LUT_PROG_HIGH);
dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I);
seq_puts(s, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list dvo_debugfs_files[] = {
{ "dvo", dvo_dbg_show, 0, NULL },
};
static void dvo_debugfs_exit(struct sti_dvo *dvo, struct drm_minor *minor)
{
drm_debugfs_remove_files(dvo_debugfs_files,
ARRAY_SIZE(dvo_debugfs_files),
minor);
}
static int dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(dvo_debugfs_files); i++)
dvo_debugfs_files[i].data = dvo;
return drm_debugfs_create_files(dvo_debugfs_files,
ARRAY_SIZE(dvo_debugfs_files),
minor->debugfs_root, minor);
}
static void sti_dvo_disable(struct drm_bridge *bridge) static void sti_dvo_disable(struct drm_bridge *bridge)
{ {
struct sti_dvo *dvo = bridge->driver_private; struct sti_dvo *dvo = bridge->driver_private;
...@@ -345,11 +409,13 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) ...@@ -345,11 +409,13 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_DRIVER("\n"); DRM_DEBUG_DRIVER("\n");
if (!dvo->panel) if (!dvo->panel) {
dvo->panel = of_drm_find_panel(dvo->panel_node); dvo->panel = of_drm_find_panel(dvo->panel_node);
if (dvo->panel)
drm_panel_attach(dvo->panel, connector);
}
if (dvo->panel) if (dvo->panel)
if (!drm_panel_attach(dvo->panel, connector))
return connector_status_connected; return connector_status_connected;
return connector_status_disconnected; return connector_status_disconnected;
...@@ -453,6 +519,9 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) ...@@ -453,6 +519,9 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
goto err_sysfs; goto err_sysfs;
} }
if (dvo_debugfs_init(dvo, drm_dev->primary))
DRM_ERROR("DVO debugfs setup failed\n");
return 0; return 0;
err_sysfs: err_sysfs:
...@@ -467,6 +536,9 @@ static void sti_dvo_unbind(struct device *dev, ...@@ -467,6 +536,9 @@ static void sti_dvo_unbind(struct device *dev,
struct device *master, void *data) struct device *master, void *data)
{ {
struct sti_dvo *dvo = dev_get_drvdata(dev); struct sti_dvo *dvo = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
dvo_debugfs_exit(dvo, drm_dev->primary);
drm_bridge_remove(dvo->bridge); drm_bridge_remove(dvo->bridge);
} }
......
This diff is collapsed.
...@@ -326,6 +326,103 @@ static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable) ...@@ -326,6 +326,103 @@ static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable)
} }
} }
#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
readl(hda->regs + reg))
static void hda_dbg_cfg(struct seq_file *s, int val)
{
seq_puts(s, "\tAWG ");
seq_puts(s, val & CFG_AWG_ASYNC_EN ? "enabled" : "disabled");
}
static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
{
unsigned int i;
seq_puts(s, "\n\n");
seq_puts(s, " HDA AWG microcode:");
for (i = 0; i < AWG_MAX_INST; i++) {
if (i % 8 == 0)
seq_printf(s, "\n %04X:", i);
seq_printf(s, " %04X", readl(reg + i * 4));
}
}
static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg)
{
u32 val = readl(reg);
u32 mask;
switch ((u32)reg & VIDEO_DACS_CONTROL_MASK) {
case VIDEO_DACS_CONTROL_SYSCFG2535:
mask = DAC_CFG_HD_OFF_MASK;
break;
case VIDEO_DACS_CONTROL_SYSCFG5072:
mask = DAC_CFG_HD_HZUVW_OFF_MASK;
break;
default:
DRM_DEBUG_DRIVER("Warning: DACS ctrl register not supported!");
return;
}
seq_puts(s, "\n");
seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val);
seq_puts(s, "\tHD DACs ");
seq_puts(s, val & mask ? "disabled" : "enabled");
}
static int hda_dbg_show(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct sti_hda *hda = (struct sti_hda *)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(s, "HD Analog: (vaddr = 0x%p)", hda->regs);
DBGFS_DUMP(HDA_ANA_CFG);
hda_dbg_cfg(s, readl(hda->regs + HDA_ANA_CFG));
DBGFS_DUMP(HDA_ANA_SCALE_CTRL_Y);
DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CB);
DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CR);
DBGFS_DUMP(HDA_ANA_ANC_CTRL);
DBGFS_DUMP(HDA_ANA_SRC_Y_CFG);
DBGFS_DUMP(HDA_ANA_SRC_C_CFG);
hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI);
if (hda->video_dacs_ctrl)
hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl);
seq_puts(s, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list hda_debugfs_files[] = {
{ "hda", hda_dbg_show, 0, NULL },
};
static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor)
{
drm_debugfs_remove_files(hda_debugfs_files,
ARRAY_SIZE(hda_debugfs_files),
minor);
}
static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(hda_debugfs_files); i++)
hda_debugfs_files[i].data = hda;
return drm_debugfs_create_files(hda_debugfs_files,
ARRAY_SIZE(hda_debugfs_files),
minor->debugfs_root, minor);
}
/** /**
* Configure AWG, writing instructions * Configure AWG, writing instructions
* *
...@@ -685,6 +782,12 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) ...@@ -685,6 +782,12 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
goto err_sysfs; goto err_sysfs;
} }
/* force to disable hd dacs at startup */
hda_enable_hd_dacs(hda, false);
if (hda_debugfs_init(hda, drm_dev->primary))
DRM_ERROR("HDA debugfs setup failed\n");
return 0; return 0;
err_sysfs: err_sysfs:
...@@ -697,7 +800,10 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) ...@@ -697,7 +800,10 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
static void sti_hda_unbind(struct device *dev, static void sti_hda_unbind(struct device *dev,
struct device *master, void *data) struct device *master, void *data)
{ {
/* do nothing */ struct sti_hda *hda = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
hda_debugfs_exit(hda, drm_dev->primary);
} }
static const struct component_ops sti_hda_ops = { static const struct component_ops sti_hda_ops = {
......
This diff is collapsed.
...@@ -7,15 +7,14 @@ ...@@ -7,15 +7,14 @@
#ifndef _STI_HDMI_H_ #ifndef _STI_HDMI_H_
#define _STI_HDMI_H_ #define _STI_HDMI_H_
#include <linux/hdmi.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#define HDMI_STA 0x0010 #define HDMI_STA 0x0010
#define HDMI_STA_DLL_LCK BIT(5) #define HDMI_STA_DLL_LCK BIT(5)
#define HDMI_STA_HOT_PLUG BIT(4)
#define HDMI_STA_HOT_PLUG_SHIFT 4
#define HDMI_STA_HOT_PLUG (1 << HDMI_STA_HOT_PLUG_SHIFT)
struct sti_hdmi; struct sti_hdmi;
...@@ -24,6 +23,27 @@ struct hdmi_phy_ops { ...@@ -24,6 +23,27 @@ struct hdmi_phy_ops {
void (*stop)(struct sti_hdmi *hdmi); void (*stop)(struct sti_hdmi *hdmi);
}; };
/* values for the framing mode property */
enum sti_hdmi_modes {
HDMI_MODE_HDMI,
HDMI_MODE_DVI,
};
static const struct drm_prop_enum_list hdmi_mode_names[] = {
{ HDMI_MODE_HDMI, "hdmi" },
{ HDMI_MODE_DVI, "dvi" },
};
#define DEFAULT_HDMI_MODE HDMI_MODE_HDMI
static const struct drm_prop_enum_list colorspace_mode_names[] = {
{ HDMI_COLORSPACE_RGB, "rgb" },
{ HDMI_COLORSPACE_YUV422, "yuv422" },
{ HDMI_COLORSPACE_YUV444, "yuv444" },
};
#define DEFAULT_COLORSPACE_MODE HDMI_COLORSPACE_RGB
/** /**
* STI hdmi structure * STI hdmi structure
* *
...@@ -44,6 +64,9 @@ struct hdmi_phy_ops { ...@@ -44,6 +64,9 @@ struct hdmi_phy_ops {
* @wait_event: wait event * @wait_event: wait event
* @event_received: wait event status * @event_received: wait event status
* @reset: reset control of the hdmi phy * @reset: reset control of the hdmi phy
* @ddc_adapt: i2c ddc adapter
* @colorspace: current colorspace selected
* @hdmi_mode: select framing for HDMI or DVI
*/ */
struct sti_hdmi { struct sti_hdmi {
struct device dev; struct device dev;
...@@ -64,6 +87,8 @@ struct sti_hdmi { ...@@ -64,6 +87,8 @@ struct sti_hdmi {
bool event_received; bool event_received;
struct reset_control *reset; struct reset_control *reset;
struct i2c_adapter *ddc_adapt; struct i2c_adapter *ddc_adapt;
enum hdmi_colorspace colorspace;
enum sti_hdmi_modes hdmi_mode;
}; };
u32 hdmi_read(struct sti_hdmi *hdmi, int offset); u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
......
This diff is collapsed.
...@@ -75,6 +75,145 @@ static inline void sti_mixer_reg_write(struct sti_mixer *mixer, ...@@ -75,6 +75,145 @@ static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
writel(val, mixer->regs + reg_id); writel(val, mixer->regs + reg_id);
} }
#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
sti_mixer_reg_read(mixer, reg))
static void mixer_dbg_ctl(struct seq_file *s, int val)
{
unsigned int i;
int count = 0;
char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
"GDP1", "GDP2", "GDP3"};
seq_puts(s, "\tEnabled: ");
for (i = 0; i < 7; i++) {
if (val & 1) {
seq_printf(s, "%s ", disp_layer[i]);
count++;
}
val = val >> 1;
}
val = val >> 2;
if (val & 1) {
seq_puts(s, "CURS ");
count++;
}
if (!count)
seq_puts(s, "Nothing");
}
static void mixer_dbg_crb(struct seq_file *s, int val)
{
int i;
seq_puts(s, "\tDepth: ");
for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
switch (val & GAM_DEPTH_MASK_ID) {
case GAM_DEPTH_VID0_ID:
seq_puts(s, "VID0");
break;
case GAM_DEPTH_VID1_ID:
seq_puts(s, "VID1");
break;
case GAM_DEPTH_GDP0_ID:
seq_puts(s, "GDP0");
break;
case GAM_DEPTH_GDP1_ID:
seq_puts(s, "GDP1");
break;
case GAM_DEPTH_GDP2_ID:
seq_puts(s, "GDP2");
break;
case GAM_DEPTH_GDP3_ID:
seq_puts(s, "GDP3");
break;
default:
seq_puts(s, "---");
}
if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
seq_puts(s, " < ");
val = val >> 3;
}
}
static void mixer_dbg_mxn(struct seq_file *s, void *addr)
{
int i;
for (i = 1; i < 8; i++)
seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
}
static int mixer_dbg_show(struct seq_file *s, void *arg)
{
struct drm_info_node *node = s->private;
struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(s, "%s: (vaddr = 0x%p)",
sti_mixer_to_str(mixer), mixer->regs);
DBGFS_DUMP(GAM_MIXER_CTL);
mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
DBGFS_DUMP(GAM_MIXER_BKC);
DBGFS_DUMP(GAM_MIXER_BCO);
DBGFS_DUMP(GAM_MIXER_BCS);
DBGFS_DUMP(GAM_MIXER_AVO);
DBGFS_DUMP(GAM_MIXER_AVS);
DBGFS_DUMP(GAM_MIXER_CRB);
mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
DBGFS_DUMP(GAM_MIXER_ACT);
DBGFS_DUMP(GAM_MIXER_MBP);
DBGFS_DUMP(GAM_MIXER_MX0);
mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
seq_puts(s, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list mixer0_debugfs_files[] = {
{ "mixer_main", mixer_dbg_show, 0, NULL },
};
static struct drm_info_list mixer1_debugfs_files[] = {
{ "mixer_aux", mixer_dbg_show, 0, NULL },
};
static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
{
unsigned int i;
struct drm_info_list *mixer_debugfs_files;
int nb_files;
switch (mixer->id) {
case STI_MIXER_MAIN:
mixer_debugfs_files = mixer0_debugfs_files;
nb_files = ARRAY_SIZE(mixer0_debugfs_files);
break;
case STI_MIXER_AUX:
mixer_debugfs_files = mixer1_debugfs_files;
nb_files = ARRAY_SIZE(mixer1_debugfs_files);
break;
default:
return -EINVAL;
}
for (i = 0; i < nb_files; i++)
mixer_debugfs_files[i].data = mixer;
return drm_debugfs_create_files(mixer_debugfs_files,
nb_files,
minor->debugfs_root, minor);
}
void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
{ {
u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
...@@ -237,7 +376,9 @@ void sti_mixer_set_matrix(struct sti_mixer *mixer) ...@@ -237,7 +376,9 @@ void sti_mixer_set_matrix(struct sti_mixer *mixer)
mixerColorSpaceMatIdentity[i]); mixerColorSpaceMatIdentity[i]);
} }
struct sti_mixer *sti_mixer_create(struct device *dev, int id, struct sti_mixer *sti_mixer_create(struct device *dev,
struct drm_device *drm_dev,
int id,
void __iomem *baseaddr) void __iomem *baseaddr)
{ {
struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
...@@ -258,5 +399,8 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id, ...@@ -258,5 +399,8 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id,
DRM_DEBUG_DRIVER("%s created. Regs=%p\n", DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
sti_mixer_to_str(mixer), mixer->regs); sti_mixer_to_str(mixer), mixer->regs);
if (mixer_debugfs_init(mixer, drm_dev->primary))
DRM_ERROR("MIXER debugfs setup failed\n");
return mixer; return mixer;
} }
...@@ -42,7 +42,9 @@ struct sti_mixer { ...@@ -42,7 +42,9 @@ struct sti_mixer {
const char *sti_mixer_to_str(struct sti_mixer *mixer); const char *sti_mixer_to_str(struct sti_mixer *mixer);
struct sti_mixer *sti_mixer_create(struct device *dev, int id, struct sti_mixer *sti_mixer_create(struct device *dev,
struct drm_device *drm_dev,
int id,
void __iomem *baseaddr); void __iomem *baseaddr);
int sti_mixer_set_plane_status(struct sti_mixer *mixer, int sti_mixer_set_plane_status(struct sti_mixer *mixer,
......
...@@ -43,6 +43,69 @@ const char *sti_plane_to_str(struct sti_plane *plane) ...@@ -43,6 +43,69 @@ const char *sti_plane_to_str(struct sti_plane *plane)
} }
} }
#define STI_FPS_INTERVAL_MS 3000
static int sti_plane_timespec_ms_diff(struct timespec lhs, struct timespec rhs)
{
struct timespec tmp_ts = timespec_sub(lhs, rhs);
u64 tmp_ns = (u64)timespec_to_ns(&tmp_ts);
do_div(tmp_ns, NSEC_PER_MSEC);
return (u32)tmp_ns;
}
void sti_plane_update_fps(struct sti_plane *plane,
bool new_frame,
bool new_field)
{
struct timespec now;
struct sti_fps_info *fps;
int fpks, fipks, ms_since_last, num_frames, num_fields;
getrawmonotonic(&now);
/* Compute number of frame updates */
fps = &plane->fps_info;
if (new_field)
fps->curr_field_counter++;
/* do not perform fps calcul if new_frame is false */
if (!new_frame)
return;
fps->curr_frame_counter++;
ms_since_last = sti_plane_timespec_ms_diff(now, fps->last_timestamp);
num_frames = fps->curr_frame_counter - fps->last_frame_counter;
if (num_frames <= 0 || ms_since_last < STI_FPS_INTERVAL_MS)
return;
fps->last_timestamp = now;
fps->last_frame_counter = fps->curr_frame_counter;
fpks = (num_frames * 1000000) / ms_since_last;
snprintf(plane->fps_info.fps_str, FPS_LENGTH, "%-6s @ %d.%.3d fps",
sti_plane_to_str(plane), fpks / 1000, fpks % 1000);
if (fps->curr_field_counter) {
/* Compute number of field updates */
num_fields = fps->curr_field_counter - fps->last_field_counter;
fps->last_field_counter = fps->curr_field_counter;
fipks = (num_fields * 1000000) / ms_since_last;
snprintf(plane->fps_info.fips_str,
FPS_LENGTH, " - %d.%.3d field/sec",
fipks / 1000, fipks % 1000);
} else {
plane->fps_info.fips_str[0] = '\0';
}
if (fps->output)
DRM_INFO("%s%s\n",
plane->fps_info.fps_str,
plane->fps_info.fips_str);
}
static void sti_plane_destroy(struct drm_plane *drm_plane) static void sti_plane_destroy(struct drm_plane *drm_plane)
{ {
DRM_DEBUG_DRIVER("\n"); DRM_DEBUG_DRIVER("\n");
......
...@@ -50,6 +50,18 @@ enum sti_plane_status { ...@@ -50,6 +50,18 @@ enum sti_plane_status {
STI_PLANE_DISABLED, STI_PLANE_DISABLED,
}; };
#define FPS_LENGTH 64
struct sti_fps_info {
bool output;
unsigned int curr_frame_counter;
unsigned int last_frame_counter;
unsigned int curr_field_counter;
unsigned int last_field_counter;
struct timespec last_timestamp;
char fps_str[FPS_LENGTH];
char fips_str[FPS_LENGTH];
};
/** /**
* STI plane structure * STI plane structure
* *
...@@ -57,15 +69,20 @@ enum sti_plane_status { ...@@ -57,15 +69,20 @@ enum sti_plane_status {
* @desc: plane type & id * @desc: plane type & id
* @status: to know the status of the plane * @status: to know the status of the plane
* @zorder: plane z-order * @zorder: plane z-order
* @fps_info: frame per second info
*/ */
struct sti_plane { struct sti_plane {
struct drm_plane drm_plane; struct drm_plane drm_plane;
enum sti_plane_desc desc; enum sti_plane_desc desc;
enum sti_plane_status status; enum sti_plane_status status;
int zorder; int zorder;
struct sti_fps_info fps_info;
}; };
const char *sti_plane_to_str(struct sti_plane *plane); const char *sti_plane_to_str(struct sti_plane *plane);
void sti_plane_update_fps(struct sti_plane *plane,
bool new_frame,
bool new_field);
void sti_plane_init_property(struct sti_plane *plane, void sti_plane_init_property(struct sti_plane *plane,
enum drm_plane_type type); enum drm_plane_type type);
#endif #endif
This diff is collapsed.
...@@ -42,6 +42,104 @@ ...@@ -42,6 +42,104 @@
#define VID_MPR1_BT709 0x0AC50000 #define VID_MPR1_BT709 0x0AC50000
#define VID_MPR2_BT709 0x07150545 #define VID_MPR2_BT709 0x07150545
#define VID_MPR3_BT709 0x00000AE8 #define VID_MPR3_BT709 0x00000AE8
/* YCbCr to RGB BT709:
* R = Y+1.3711Cr
* G = Y-0.6992Cr-0.3359Cb
* B = Y+1.7344Cb
*/
#define VID_MPR0_BT601 0x0A800000
#define VID_MPR1_BT601 0x0AAF0000
#define VID_MPR2_BT601 0x094E0754
#define VID_MPR3_BT601 0x00000ADD
#define VID_MIN_HD_HEIGHT 720
#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
readl(vid->regs + reg))
static void vid_dbg_ctl(struct seq_file *s, int val)
{
val = val >> 30;
seq_puts(s, "\t");
if (!(val & 1))
seq_puts(s, "NOT ");
seq_puts(s, "ignored on main mixer - ");
if (!(val & 2))
seq_puts(s, "NOT ");
seq_puts(s, "ignored on aux mixer");
}
static void vid_dbg_vpo(struct seq_file *s, int val)
{
seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
}
static void vid_dbg_vps(struct seq_file *s, int val)
{
seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
}
static void vid_dbg_mst(struct seq_file *s, int val)
{
if (val & 1)
seq_puts(s, "\tBUFFER UNDERFLOW!");
}
static int vid_dbg_show(struct seq_file *s, void *arg)
{
struct drm_info_node *node = s->private;
struct sti_vid *vid = (struct sti_vid *)node->info_ent->data;
struct drm_device *dev = node->minor->dev;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs);
DBGFS_DUMP(VID_CTL);
vid_dbg_ctl(s, readl(vid->regs + VID_CTL));
DBGFS_DUMP(VID_ALP);
DBGFS_DUMP(VID_CLF);
DBGFS_DUMP(VID_VPO);
vid_dbg_vpo(s, readl(vid->regs + VID_VPO));
DBGFS_DUMP(VID_VPS);
vid_dbg_vps(s, readl(vid->regs + VID_VPS));
DBGFS_DUMP(VID_KEY1);
DBGFS_DUMP(VID_KEY2);
DBGFS_DUMP(VID_MPR0);
DBGFS_DUMP(VID_MPR1);
DBGFS_DUMP(VID_MPR2);
DBGFS_DUMP(VID_MPR3);
DBGFS_DUMP(VID_MST);
vid_dbg_mst(s, readl(vid->regs + VID_MST));
DBGFS_DUMP(VID_BC);
DBGFS_DUMP(VID_TINT);
DBGFS_DUMP(VID_CSAT);
seq_puts(s, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
static struct drm_info_list vid_debugfs_files[] = {
{ "vid", vid_dbg_show, 0, NULL },
};
static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++)
vid_debugfs_files[i].data = vid;
return drm_debugfs_create_files(vid_debugfs_files,
ARRAY_SIZE(vid_debugfs_files),
minor->debugfs_root, minor);
}
void sti_vid_commit(struct sti_vid *vid, void sti_vid_commit(struct sti_vid *vid,
struct drm_plane_state *state) struct drm_plane_state *state)
...@@ -52,6 +150,7 @@ void sti_vid_commit(struct sti_vid *vid, ...@@ -52,6 +150,7 @@ void sti_vid_commit(struct sti_vid *vid,
int dst_y = state->crtc_y; int dst_y = state->crtc_y;
int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
int src_h = state->src_h >> 16;
u32 val, ydo, xdo, yds, xds; u32 val, ydo, xdo, yds, xds;
/* Input / output size /* Input / output size
...@@ -71,6 +170,19 @@ void sti_vid_commit(struct sti_vid *vid, ...@@ -71,6 +170,19 @@ void sti_vid_commit(struct sti_vid *vid,
writel((ydo << 16) | xdo, vid->regs + VID_VPO); writel((ydo << 16) | xdo, vid->regs + VID_VPO);
writel((yds << 16) | xds, vid->regs + VID_VPS); writel((yds << 16) | xds, vid->regs + VID_VPS);
/* Color conversion parameters */
if (src_h >= VID_MIN_HD_HEIGHT) {
writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
} else {
writel(VID_MPR0_BT601, vid->regs + VID_MPR0);
writel(VID_MPR1_BT601, vid->regs + VID_MPR1);
writel(VID_MPR2_BT601, vid->regs + VID_MPR2);
writel(VID_MPR3_BT601, vid->regs + VID_MPR3);
}
} }
void sti_vid_disable(struct sti_vid *vid) void sti_vid_disable(struct sti_vid *vid)
...@@ -91,20 +203,14 @@ static void sti_vid_init(struct sti_vid *vid) ...@@ -91,20 +203,14 @@ static void sti_vid_init(struct sti_vid *vid)
/* Opaque */ /* Opaque */
writel(VID_ALP_OPAQUE, vid->regs + VID_ALP); writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
/* Color conversion parameters */
writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
/* Brightness, contrast, tint, saturation */ /* Brightness, contrast, tint, saturation */
writel(VID_BC_DFLT, vid->regs + VID_BC); writel(VID_BC_DFLT, vid->regs + VID_BC);
writel(VID_TINT_DFLT, vid->regs + VID_TINT); writel(VID_TINT_DFLT, vid->regs + VID_TINT);
writel(VID_CSAT_DFLT, vid->regs + VID_CSAT); writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
} }
struct sti_vid *sti_vid_create(struct device *dev, int id, struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
void __iomem *baseaddr) int id, void __iomem *baseaddr)
{ {
struct sti_vid *vid; struct sti_vid *vid;
...@@ -120,5 +226,8 @@ struct sti_vid *sti_vid_create(struct device *dev, int id, ...@@ -120,5 +226,8 @@ struct sti_vid *sti_vid_create(struct device *dev, int id,
sti_vid_init(vid); sti_vid_init(vid);
if (vid_debugfs_init(vid, drm_dev->primary))
DRM_ERROR("VID debugfs setup failed\n");
return vid; return vid;
} }
...@@ -23,7 +23,7 @@ struct sti_vid { ...@@ -23,7 +23,7 @@ struct sti_vid {
void sti_vid_commit(struct sti_vid *vid, void sti_vid_commit(struct sti_vid *vid,
struct drm_plane_state *state); struct drm_plane_state *state);
void sti_vid_disable(struct sti_vid *vid); void sti_vid_disable(struct sti_vid *vid);
struct sti_vid *sti_vid_create(struct device *dev, int id, struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
void __iomem *baseaddr); int id, void __iomem *baseaddr);
#endif #endif
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
#include "sti_vtg.h" #include "sti_vtg.h"
#define VTG_TYPE_MASTER 0 #define VTG_MODE_MASTER 0
#define VTG_TYPE_SLAVE_BY_EXT0 1 #define VTG_MODE_SLAVE_BY_EXT0 1
/* registers offset */ /* registers offset */
#define VTG_MODE 0x0000 #define VTG_MODE 0x0000
...@@ -64,6 +64,9 @@ ...@@ -64,6 +64,9 @@
/* Delay introduced by the HDMI in nb of pixel */ /* Delay introduced by the HDMI in nb of pixel */
#define HDMI_DELAY (5) #define HDMI_DELAY (5)
/* Delay introduced by the DVO in nb of pixel */
#define DVO_DELAY (2)
/* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */
#define AWG_DELAY_HD (-9) #define AWG_DELAY_HD (-9)
#define AWG_DELAY_ED (-8) #define AWG_DELAY_ED (-8)
...@@ -71,13 +74,61 @@ ...@@ -71,13 +74,61 @@
LIST_HEAD(vtg_lookup); LIST_HEAD(vtg_lookup);
/*
* STI VTG register offset structure
*
*@h_hd: stores the VTG_H_HD_x register offset
*@top_v_vd: stores the VTG_TOP_V_VD_x register offset
*@bot_v_vd: stores the VTG_BOT_V_VD_x register offset
*@top_v_hd: stores the VTG_TOP_V_HD_x register offset
*@bot_v_hd: stores the VTG_BOT_V_HD_x register offset
*/
struct sti_vtg_regs_offs {
u32 h_hd;
u32 top_v_vd;
u32 bot_v_vd;
u32 top_v_hd;
u32 bot_v_hd;
};
#define VTG_MAX_SYNC_OUTPUT 4
static const struct sti_vtg_regs_offs vtg_regs_offs[VTG_MAX_SYNC_OUTPUT] = {
{ VTG_H_HD_1,
VTG_TOP_V_VD_1, VTG_BOT_V_VD_1, VTG_TOP_V_HD_1, VTG_BOT_V_HD_1 },
{ VTG_H_HD_2,
VTG_TOP_V_VD_2, VTG_BOT_V_VD_2, VTG_TOP_V_HD_2, VTG_BOT_V_HD_2 },
{ VTG_H_HD_3,
VTG_TOP_V_VD_3, VTG_BOT_V_VD_3, VTG_TOP_V_HD_3, VTG_BOT_V_HD_3 },
{ VTG_H_HD_4,
VTG_TOP_V_VD_4, VTG_BOT_V_VD_4, VTG_TOP_V_HD_4, VTG_BOT_V_HD_4 }
};
/*
* STI VTG synchronisation parameters structure
*
*@hsync: sample number falling and rising edge
*@vsync_line_top: vertical top field line number falling and rising edge
*@vsync_line_bot: vertical bottom field line number falling and rising edge
*@vsync_off_top: vertical top field sample number rising and falling edge
*@vsync_off_bot: vertical bottom field sample number rising and falling edge
*/
struct sti_vtg_sync_params {
u32 hsync;
u32 vsync_line_top;
u32 vsync_line_bot;
u32 vsync_off_top;
u32 vsync_off_bot;
};
/** /**
* STI VTG structure * STI VTG structure
* *
* @dev: pointer to device driver * @dev: pointer to device driver
* @data: data associated to the device * @np: device node
* @regs: register mapping
* @sync_params: synchronisation parameters used to generate timings
* @irq: VTG irq * @irq: VTG irq
* @type: VTG type (main or aux) * @irq_status: store the IRQ status value
* @notifier_list: notifier callback * @notifier_list: notifier callback
* @crtc: the CRTC for vblank event * @crtc: the CRTC for vblank event
* @slave: slave vtg * @slave: slave vtg
...@@ -87,6 +138,7 @@ struct sti_vtg { ...@@ -87,6 +138,7 @@ struct sti_vtg {
struct device *dev; struct device *dev;
struct device_node *np; struct device_node *np;
void __iomem *regs; void __iomem *regs;
struct sti_vtg_sync_params sync_params[VTG_MAX_SYNC_OUTPUT];
int irq; int irq;
u32 irq_status; u32 irq_status;
struct raw_notifier_head notifier_list; struct raw_notifier_head notifier_list;
...@@ -146,13 +198,69 @@ static void vtg_set_output_window(void __iomem *regs, ...@@ -146,13 +198,69 @@ static void vtg_set_output_window(void __iomem *regs,
writel(video_bottom_field_stop, regs + VTG_VID_BFS); writel(video_bottom_field_stop, regs + VTG_VID_BFS);
} }
static void vtg_set_hsync_vsync_pos(struct sti_vtg_sync_params *sync,
int delay,
const struct drm_display_mode *mode)
{
long clocksperline, start, stop;
u32 risesync_top, fallsync_top;
u32 risesync_offs_top, fallsync_offs_top;
clocksperline = mode->htotal;
/* Get the hsync position */
start = 0;
stop = mode->hsync_end - mode->hsync_start;
start += delay;
stop += delay;
if (start < 0)
start += clocksperline;
else if (start >= clocksperline)
start -= clocksperline;
if (stop < 0)
stop += clocksperline;
else if (stop >= clocksperline)
stop -= clocksperline;
sync->hsync = (stop << 16) | start;
/* Get the vsync position */
if (delay >= 0) {
risesync_top = 1;
fallsync_top = risesync_top;
fallsync_top += mode->vsync_end - mode->vsync_start;
fallsync_offs_top = (u32)delay;
risesync_offs_top = (u32)delay;
} else {
risesync_top = mode->vtotal;
fallsync_top = mode->vsync_end - mode->vsync_start;
fallsync_offs_top = clocksperline + delay;
risesync_offs_top = clocksperline + delay;
}
sync->vsync_line_top = (fallsync_top << 16) | risesync_top;
sync->vsync_off_top = (fallsync_offs_top << 16) | risesync_offs_top;
/* Only progressive supported for now */
sync->vsync_line_bot = sync->vsync_line_top;
sync->vsync_off_bot = sync->vsync_off_top;
}
static void vtg_set_mode(struct sti_vtg *vtg, static void vtg_set_mode(struct sti_vtg *vtg,
int type, const struct drm_display_mode *mode) int type,
struct sti_vtg_sync_params *sync,
const struct drm_display_mode *mode)
{ {
u32 tmp; unsigned int i;
if (vtg->slave) if (vtg->slave)
vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); vtg_set_mode(vtg->slave, VTG_MODE_SLAVE_BY_EXT0,
vtg->sync_params, mode);
/* Set the number of clock cycles per line */ /* Set the number of clock cycles per line */
writel(mode->htotal, vtg->regs + VTG_CLKLN); writel(mode->htotal, vtg->regs + VTG_CLKLN);
...@@ -163,57 +271,31 @@ static void vtg_set_mode(struct sti_vtg *vtg, ...@@ -163,57 +271,31 @@ static void vtg_set_mode(struct sti_vtg *vtg,
/* Program output window */ /* Program output window */
vtg_set_output_window(vtg->regs, mode); vtg_set_output_window(vtg->regs, mode);
/* prepare VTG set 1 for HDMI */ /* Set hsync and vsync position for HDMI */
tmp = (mode->hsync_end - mode->hsync_start + HDMI_DELAY) << 16; vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDMI - 1], HDMI_DELAY, mode);
tmp |= HDMI_DELAY;
writel(tmp, vtg->regs + VTG_H_HD_1); /* Set hsync and vsync position for HD DCS */
vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDDCS - 1], 0, mode);
tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
tmp |= 1; /* Set hsync and vsync position for HDF */
writel(tmp, vtg->regs + VTG_TOP_V_VD_1); vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDF - 1], AWG_DELAY_HD, mode);
writel(tmp, vtg->regs + VTG_BOT_V_VD_1);
/* Set hsync and vsync position for DVO */
tmp = HDMI_DELAY << 16; vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_DVO - 1], DVO_DELAY, mode);
tmp |= HDMI_DELAY;
writel(tmp, vtg->regs + VTG_TOP_V_HD_1); /* Progam the syncs outputs */
writel(tmp, vtg->regs + VTG_BOT_V_HD_1); for (i = 0; i < VTG_MAX_SYNC_OUTPUT ; i++) {
writel(sync[i].hsync,
/* prepare VTG set 2 for for HD DCS */ vtg->regs + vtg_regs_offs[i].h_hd);
tmp = (mode->hsync_end - mode->hsync_start) << 16; writel(sync[i].vsync_line_top,
writel(tmp, vtg->regs + VTG_H_HD_2); vtg->regs + vtg_regs_offs[i].top_v_vd);
writel(sync[i].vsync_line_bot,
tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; vtg->regs + vtg_regs_offs[i].bot_v_vd);
tmp |= 1; writel(sync[i].vsync_off_top,
writel(tmp, vtg->regs + VTG_TOP_V_VD_2); vtg->regs + vtg_regs_offs[i].top_v_hd);
writel(tmp, vtg->regs + VTG_BOT_V_VD_2); writel(sync[i].vsync_off_bot,
writel(0, vtg->regs + VTG_TOP_V_HD_2); vtg->regs + vtg_regs_offs[i].bot_v_hd);
writel(0, vtg->regs + VTG_BOT_V_HD_2); }
/* prepare VTG set 3 for HD Analog in HD mode */
tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16;
tmp |= mode->htotal + AWG_DELAY_HD;
writel(tmp, vtg->regs + VTG_H_HD_3);
tmp = (mode->vsync_end - mode->vsync_start) << 16;
tmp |= mode->vtotal;
writel(tmp, vtg->regs + VTG_TOP_V_VD_3);
writel(tmp, vtg->regs + VTG_BOT_V_VD_3);
tmp = (mode->htotal + AWG_DELAY_HD) << 16;
tmp |= mode->htotal + AWG_DELAY_HD;
writel(tmp, vtg->regs + VTG_TOP_V_HD_3);
writel(tmp, vtg->regs + VTG_BOT_V_HD_3);
/* Prepare VTG set 4 for DVO */
tmp = (mode->hsync_end - mode->hsync_start) << 16;
writel(tmp, vtg->regs + VTG_H_HD_4);
tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
tmp |= 1;
writel(tmp, vtg->regs + VTG_TOP_V_VD_4);
writel(tmp, vtg->regs + VTG_BOT_V_VD_4);
writel(0, vtg->regs + VTG_TOP_V_HD_4);
writel(0, vtg->regs + VTG_BOT_V_HD_4);
/* mode */ /* mode */
writel(type, vtg->regs + VTG_MODE); writel(type, vtg->regs + VTG_MODE);
...@@ -231,7 +313,7 @@ void sti_vtg_set_config(struct sti_vtg *vtg, ...@@ -231,7 +313,7 @@ void sti_vtg_set_config(struct sti_vtg *vtg,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
/* write configuration */ /* write configuration */
vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); vtg_set_mode(vtg, VTG_MODE_MASTER, vtg->sync_params, mode);
vtg_reset(vtg); vtg_reset(vtg);
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
#define VTG_TOP_FIELD_EVENT 1 #define VTG_TOP_FIELD_EVENT 1
#define VTG_BOTTOM_FIELD_EVENT 2 #define VTG_BOTTOM_FIELD_EVENT 2
#define VTG_SYNC_ID_HDMI 1
#define VTG_SYNC_ID_HDDCS 2
#define VTG_SYNC_ID_HDF 3
#define VTG_SYNC_ID_DVO 4
struct sti_vtg; struct sti_vtg;
struct drm_display_mode; struct drm_display_mode;
struct notifier_block; struct notifier_block;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment