diff options
author | Dave Airlie <airlied@redhat.com> | 2016-03-17 08:27:51 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-03-17 08:27:51 +1000 |
commit | cf481068cdd430a22425d7712c8deeb25efdedc1 (patch) | |
tree | 7ddf5043cb06c12327ae8b5529356ff45e83e5e8 /drivers/gpu/drm | |
parent | 9f443bf53b5699835e0132d62d1e6c99a1eaeee8 (diff) | |
parent | 52807ae90e76b69fd01688d6031190271536d29f (diff) |
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
...
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/sti/sti_awg_utils.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_compositor.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_crtc.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_cursor.c | 184 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_drv.c | 141 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_dvo.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.c | 476 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hda.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.c | 400 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hqvdp.c | 447 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.c | 146 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.c | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_plane.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_tvout.c | 295 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vid.c | 125 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vid.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vtg.c | 200 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_vtg.h | 5 |
20 files changed, 2399 insertions, 416 deletions
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index 00d0698be9d3..a516eb869f6f 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c @@ -7,6 +7,7 @@ #include "sti_awg_utils.h" #define AWG_OPCODE_OFFSET 10 +#define AWG_MAX_ARG 0x3ff enum opcode { SET, @@ -34,6 +35,8 @@ static int awg_generate_instr(enum opcode opcode, /* skip, repeat and replay arg should not exceed 1023. * If user wants to exceed this value, the instruction should be * duplicate and arg should be adjust for each duplicated instruction. + * + * mux_sel is used in case of SAV/EAV synchronization. */ while (arg_tmp > 0) { @@ -65,7 +68,7 @@ static int awg_generate_instr(enum opcode opcode, mux = 0; data_enable = 0; - arg &= (0x3ff); + arg &= AWG_MAX_ARG; break; case REPEAT: case REPLAY: @@ -76,13 +79,13 @@ static int awg_generate_instr(enum opcode opcode, mux = 0; data_enable = 0; - arg &= (0x3ff); + arg &= AWG_MAX_ARG; break; case JUMP: mux = 0; data_enable = 0; arg |= 0x40; /* for jump instruction 7th bit is 1 */ - arg &= 0x3ff; + arg &= AWG_MAX_ARG; break; case STOP: arg = 0; @@ -110,68 +113,75 @@ static int awg_generate_instr(enum opcode opcode, return 0; } -int sti_awg_generate_code_data_enable_mode( +static int awg_generate_line_signal( struct awg_code_generation_params *fwparams, struct awg_timing *timing) { long int val; - long int data_en; 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) { /* skip trailing pixel */ val = timing->blanking_level; - data_en = 0; - ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams); + ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); val = timing->trailing_pixels - 1; - data_en = 0; - ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams); + ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams); } /* set DE signal high */ val = timing->blanking_level; - data_en = 1; ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET, - val, 0, data_en, fwparams); + val, 0, 1, fwparams); if (timing->blanking_pixels > 0) { /* skip the number of active pixel */ val = timing->active_pixels - 1; - data_en = 1; - ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams); + ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams); /* set DE signal low */ val = timing->blanking_level; - data_en = 0; - ret |= awg_generate_instr(SET, val, 0, data_en, fwparams); + ret |= awg_generate_instr(SET, val, 0, 0, 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); } - /* replay the sequence as many active lines defined */ - val = timing->active_lines - 1; - data_en = 0; - ret |= awg_generate_instr(REPLAY, val, 0, data_en, 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 */ + ret |= awg_generate_instr(REPLAY, + min_t(int, AWG_MAX_ARG, tmp_val), + 0, 0, fwparams); + tmp_val -= AWG_MAX_ARG; + } if (timing->blanking_lines > 0) { /* skip blanking lines */ val = timing->blanking_level; - data_en = 0; - ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams); + ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); val = timing->blanking_lines - 1; - data_en = 0; - ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams); + ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams); } return ret; diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index afed2171beb9..3d2fa3ab33df 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -75,13 +75,13 @@ static int sti_compositor_bind(struct device *dev, switch (desc[i].type) { case STI_VID_SUBDEV: 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); break; case STI_MIXER_MAIN_SUBDEV: case STI_MIXER_AUX_SUBDEV: 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); break; case STI_GPD_SUBDEV: diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index e04deedabd4a..fa47f63b5316 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -51,6 +51,15 @@ static void sti_crtc_disabling(struct drm_crtc *crtc) 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 sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) { diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 807863106b8d..82b5711fefef 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -5,12 +5,10 @@ * for STMicroelectronics. * 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_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> #include "sti_compositor.h" #include "sti_cursor.h" @@ -74,6 +72,82 @@ static const uint32_t cursor_supported_formats[] = { #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) { u8 *dst = cursor->pixmap.base; @@ -110,35 +184,31 @@ static void sti_cursor_init(struct sti_cursor *cursor) (b * 5); } -static void sti_cursor_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) +static int sti_cursor_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) { - 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 sti_mixer *mixer = to_sti_mixer(crtc); struct drm_framebuffer *fb = state->fb; - struct drm_display_mode *mode = &crtc->mode; - int dst_x = state->crtc_x; - int dst_y = state->crtc_y; - 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); + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_w, src_h; + + /* 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 */ - int src_w = state->src_w >> 16; - int 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)); + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; if (src_w < 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, src_h > STI_CURS_MAX_SIZE) { DRM_ERROR("Invalid cursor size (%dx%d)\n", src_w, src_h); - return; + return -EINVAL; } /* 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, GFP_KERNEL | GFP_DMA); if (!cursor->pixmap.base) { DRM_ERROR("Failed to allocate memory for pixmap\n"); - return; + return -EINVAL; } } - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { + if (!drm_fb_cma_get_gem_obj(fb, 0)) { 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 */ 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, val = y << 16 | x; 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 */ writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); writel(cursor->width, cursor->regs + CUR_PMP); writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); 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); + /* 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; } @@ -215,7 +315,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); if (!drm_plane->crtc) { DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", @@ -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_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)); plane->status = STI_PLANE_DISABLING; } static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { + .atomic_check = sti_cursor_atomic_check, .atomic_update = sti_cursor_atomic_update, .atomic_disable = sti_cursor_atomic_disable, }; @@ -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); + if (cursor_debugfs_init(cursor, drm_dev->primary)) + DRM_ERROR("CURSOR debugfs setup failed\n"); + return &cursor->plane.drm_plane; err_plane: diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 506b5626f3ed..6bd6abaa5a70 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -20,6 +20,7 @@ #include "sti_crtc.h" #include "sti_drv.h" +#include "sti_plane.h" #define DRIVER_NAME "sti" #define DRIVER_DESC "STMicroelectronics SoC DRM" @@ -30,6 +31,130 @@ #define STI_MAX_FB_HEIGHT 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, struct drm_atomic_state *state) { @@ -181,18 +306,9 @@ static const struct file_operations sti_driver_fops = { .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 = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | - DRIVER_GEM | DRIVER_PRIME, + DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, .load = sti_load, .gem_free_object = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, @@ -207,7 +323,7 @@ static struct drm_driver sti_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .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_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, @@ -215,6 +331,9 @@ static struct drm_driver sti_driver = { .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, + .debugfs_init = sti_drm_dbg_init, + .debugfs_cleanup = sti_drm_dbg_cleanup, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 45cbe2bf7dd6..25f76632002c 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -6,6 +6,7 @@ #include <linux/clk.h> #include <linux/component.h> +#include <linux/debugfs.h> #include <linux/module.h> #include <linux/of_gpio.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) 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) { struct sti_dvo *dvo = bridge->driver_private; @@ -345,12 +409,14 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) DRM_DEBUG_DRIVER("\n"); - if (!dvo->panel) + if (!dvo->panel) { dvo->panel = of_drm_find_panel(dvo->panel_node); + if (dvo->panel) + drm_panel_attach(dvo->panel, connector); + } if (dvo->panel) - if (!drm_panel_attach(dvo->panel, connector)) - return connector_status_connected; + return connector_status_connected; return connector_status_disconnected; } @@ -453,6 +519,9 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) goto err_sysfs; } + if (dvo_debugfs_init(dvo, drm_dev->primary)) + DRM_ERROR("DVO debugfs setup failed\n"); + return 0; err_sysfs: @@ -467,6 +536,9 @@ static void sti_dvo_unbind(struct device *dev, struct device *master, void *data) { 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); } diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index f9a1d92c9d95..67f606a41c3f 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -6,9 +6,7 @@ * License terms: GNU General Public License (GPL), version 2 */ -#include <linux/clk.h> -#include <linux/dma-mapping.h> - +#include <drm/drm_atomic.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> @@ -32,10 +30,23 @@ #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) #define GDP_ARGB1555 0x06 #define GDP_ARGB4444 0x07 -#define GDP_CLUT8 0x0B -#define GDP_YCBR888 0x10 -#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]; +} gdp_format_to_str[] = { + GDP2STR(RGB565), + GDP2STR(RGB888), + GDP2STR(RGB888_32), + GDP2STR(XBGR8888), + GDP2STR(ARGB8565), + GDP2STR(ARGB8888), + GDP2STR(ABGR8888), + GDP2STR(ARGB1555), + GDP2STR(ARGB4444) + }; #define GAM_GDP_CTL_OFFSET 0x00 #define GAM_GDP_AGC_OFFSET 0x04 @@ -97,6 +108,7 @@ struct sti_gdp_node_list { * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification * @is_curr_top: true if the current node processed is the top field * @node_list: array of node list + * @vtg: registered vtg */ struct sti_gdp { struct sti_plane plane; @@ -108,6 +120,7 @@ struct sti_gdp { struct notifier_block vtg_field_nb; bool is_curr_top; struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; + struct sti_vtg *vtg; }; #define to_sti_gdp(x) container_of(x, struct sti_gdp, plane) @@ -121,12 +134,224 @@ static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_ARGB1555, DRM_FORMAT_RGB565, DRM_FORMAT_RGB888, - DRM_FORMAT_AYUV, - DRM_FORMAT_YUV444, - DRM_FORMAT_VYUY, - DRM_FORMAT_C8, }; +#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(gdp->regs + reg ## _OFFSET)) + +static void gdp_dbg_ctl(struct seq_file *s, int val) +{ + int i; + + seq_puts(s, "\tColor:"); + for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) { + if (gdp_format_to_str[i].format == (val & 0x1F)) { + seq_printf(s, gdp_format_to_str[i].name); + break; + } + } + if (i == ARRAY_SIZE(gdp_format_to_str)) + seq_puts(s, "<UNKNOWN>"); + + seq_printf(s, "\tWaitNextVsync:%d", val & WAIT_NEXT_VSYNC ? 1 : 0); +} + +static void gdp_dbg_vpo(struct seq_file *s, int val) +{ + seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_vps(struct seq_file *s, int val) +{ + seq_printf(s, "\txds:%4d\tyds:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_size(struct seq_file *s, int val) +{ + seq_printf(s, "\t%d x %d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_nvn(struct seq_file *s, struct sti_gdp *gdp, int val) +{ + void *base = NULL; + unsigned int i; + + for (i = 0; i < GDP_NODE_NB_BANK; i++) { + if (gdp->node_list[i].top_field_paddr == val) { + base = gdp->node_list[i].top_field; + break; + } + if (gdp->node_list[i].btm_field_paddr == val) { + base = gdp->node_list[i].btm_field; + break; + } + } + + if (base) + seq_printf(s, "\tVirt @: %p", base); +} + +static void gdp_dbg_ppt(struct seq_file *s, int val) +{ + if (val & GAM_GDP_PPT_IGNORE) + seq_puts(s, "\tNot displayed on mixer!"); +} + +static void gdp_dbg_mst(struct seq_file *s, int val) +{ + if (val & 1) + seq_puts(s, "\tBUFFER UNDERFLOW!"); +} + +static int gdp_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + struct drm_plane *drm_plane = &gdp->plane.drm_plane; + struct drm_crtc *crtc = drm_plane->crtc; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "%s: (vaddr = 0x%p)", + sti_plane_to_str(&gdp->plane), gdp->regs); + + DBGFS_DU |