diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 99 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hdmi.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hdmi.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 202 | ||||
-rw-r--r-- | drivers/gpu/host1x/syncpt.c | 6 |
9 files changed, 404 insertions, 82 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e67d4d6..41c38ed 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2069,6 +2069,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); /** + * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state + * @crtc: CRTC object + * @state: atomic CRTC state + * + * Copies atomic state from a CRTC's current state and resets inferred values. + * This is useful for drivers that subclass the CRTC state. + */ +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + memcpy(state, crtc->state, sizeof(*state)); + + state->mode_changed = false; + state->active_changed = false; + state->planes_changed = false; + state->event = NULL; +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); + +/** * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook * @crtc: drm CRTC * @@ -2083,20 +2103,35 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) if (WARN_ON(!crtc->state)) return NULL; - state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL); - - if (state) { - state->mode_changed = false; - state->active_changed = false; - state->planes_changed = false; - state->event = NULL; - } + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_duplicate_state(crtc, state); return state; } EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); /** + * __drm_atomic_helper_crtc_destroy_state - release CRTC state + * @crtc: CRTC object + * @state: CRTC state object to release + * + * Releases all resources stored in the CRTC state without actually freeing + * the memory of the CRTC state. This is useful for drivers that subclass the + * CRTC state. + */ +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + /* + * This is currently a placeholder so that drivers that subclass the + * state will automatically do the right thing if code is ever added + * to this function. + */ +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); + +/** * drm_atomic_helper_crtc_destroy_state - default state destroy hook * @crtc: drm CRTC * @state: CRTC state object to release @@ -2107,6 +2142,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { + __drm_atomic_helper_crtc_destroy_state(crtc, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); @@ -2132,6 +2168,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) EXPORT_SYMBOL(drm_atomic_helper_plane_reset); /** + * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state + * @plane: plane object + * @state: atomic plane state + * + * Copies atomic state from a plane's current state. This is useful for + * drivers that subclass the plane state. + */ +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + memcpy(state, plane->state, sizeof(*state)); + + if (state->fb) + drm_framebuffer_reference(state->fb); +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); + +/** * drm_atomic_helper_plane_duplicate_state - default state duplicate hook * @plane: drm plane * @@ -2146,16 +2200,32 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) if (WARN_ON(!plane->state)) return NULL; - state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL); - - if (state && state->fb) - drm_framebuffer_reference(state->fb); + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_duplicate_state(plane, state); return state; } EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); /** + * __drm_atomic_helper_plane_destroy_state - release plane state + * @plane: plane object + * @state: plane state object to release + * + * Releases all resources stored in the plane state without actually freeing + * the memory of the plane state. This is useful for drivers that subclass the + * plane state. + */ +void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb) + drm_framebuffer_unreference(state->fb); +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); + +/** * drm_atomic_helper_plane_destroy_state - default state destroy hook * @plane: drm plane * @state: plane state object to release @@ -2166,9 +2236,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); @@ -2192,6 +2260,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) EXPORT_SYMBOL(drm_atomic_helper_connector_reset); /** + * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state + * @connector: connector object + * @state: atomic connector state + * + * Copies atomic state from a connector's current state. This is useful for + * drivers that subclass the connector state. + */ +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + memcpy(state, connector->state, sizeof(*state)); +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); + +/** * drm_atomic_helper_connector_duplicate_state - default state duplicate hook * @connector: drm connector * @@ -2201,14 +2285,41 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset); struct drm_connector_state * drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) { + struct drm_connector_state *state; + if (WARN_ON(!connector->state)) return NULL; - return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL); + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_connector_duplicate_state(connector, state); + + return state; } EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); /** + * __drm_atomic_helper_connector_destroy_state - release connector state + * @connector: connector object + * @state: connector state object to release + * + * Releases all resources stored in the connector state without actually + * freeing the memory of the connector state. This is useful for drivers that + * subclass the connector state. + */ +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + /* + * This is currently a placeholder so that drivers that subclass the + * state will automatically do the right thing if code is ever added + * to this function. + */ +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); + +/** * drm_atomic_helper_connector_destroy_state - default state destroy hook * @connector: drm connector * @state: connector state object to release @@ -2219,6 +2330,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state) { + __drm_atomic_helper_connector_destroy_state(connector, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index b7f7815..a287e4f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -425,8 +425,8 @@ static void tegra_plane_reset(struct drm_plane *plane) { struct tegra_plane_state *state; - if (plane->state && plane->state->fb) - drm_framebuffer_unreference(plane->state->fb); + if (plane->state) + __drm_atomic_helper_plane_destroy_state(plane, plane->state); kfree(plane->state); plane->state = NULL; @@ -443,12 +443,14 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla struct tegra_plane_state *state = to_tegra_plane_state(plane->state); struct tegra_plane_state *copy; - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + copy = kmalloc(sizeof(*copy), GFP_KERNEL); if (!copy) return NULL; - if (copy->base.fb) - drm_framebuffer_reference(copy->base.fb); + __drm_atomic_helper_plane_duplicate_state(plane, ©->base); + copy->tiling = state->tiling; + copy->format = state->format; + copy->swap = state->swap; return ©->base; } @@ -456,9 +458,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(state); } @@ -908,6 +908,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) return 0; } +u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc) +{ + if (dc->syncpt) + return host1x_syncpt_read(dc->syncpt); + + /* fallback to software emulated VBLANK counter */ + return drm_crtc_vblank_count(&dc->base); +} + void tegra_dc_enable_vblank(struct tegra_dc *dc) { unsigned long value, flags; @@ -995,6 +1004,9 @@ static void tegra_crtc_reset(struct drm_crtc *crtc) { struct tegra_dc_state *state; + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state); + kfree(crtc->state); crtc->state = NULL; @@ -1011,14 +1023,15 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc_state *copy; - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + copy = kmalloc(sizeof(*copy), GFP_KERNEL); if (!copy) return NULL; - copy->base.mode_changed = false; - copy->base.active_changed = false; - copy->base.planes_changed = false; - copy->base.event = NULL; + __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base); + copy->clk = state->clk; + copy->pclk = state->pclk; + copy->div = state->div; + copy->planes = state->planes; return ©->base; } @@ -1026,6 +1039,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { + __drm_atomic_helper_crtc_destroy_state(crtc, state); kfree(state); } @@ -1152,26 +1166,18 @@ static int tegra_dc_set_timings(struct tegra_dc *dc, return 0; } -int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent, - unsigned long pclk, unsigned int div) -{ - u32 value; - int err; - - err = clk_set_parent(dc->clk, parent); - if (err < 0) { - dev_err(dc->dev, "failed to set parent clock: %d\n", err); - return err; - } - - DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div); - - value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; - tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); - - return 0; -} - +/** + * tegra_dc_state_setup_clock - check clock settings and store them in atomic + * state + * @dc: display controller + * @crtc_state: CRTC atomic state + * @clk: parent clock for display controller + * @pclk: pixel clock + * @div: shift clock divider + * + * Returns: + * 0 on success or a negative error-code on failure. + */ int tegra_dc_state_setup_clock(struct tegra_dc *dc, struct drm_crtc_state *crtc_state, struct clk *clk, unsigned long pclk, @@ -1179,6 +1185,9 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc, { struct tegra_dc_state *state = to_dc_state(crtc_state); + if (!clk_has_parent(dc->clk, clk)) + return -EINVAL; + state->clk = clk; state->pclk = pclk; state->div = div; @@ -1294,9 +1303,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc) static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { .disable = tegra_crtc_disable, .mode_fixup = tegra_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = tegra_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, .prepare = tegra_crtc_prepare, .commit = tegra_crtc_commit, .atomic_check = tegra_crtc_atomic_check, @@ -1631,7 +1638,6 @@ static int tegra_dc_init(struct host1x_client *client) struct tegra_drm *tegra = drm->dev_private; struct drm_plane *primary = NULL; struct drm_plane *cursor = NULL; - unsigned int syncpt; u32 value; int err; @@ -1700,13 +1706,15 @@ static int tegra_dc_init(struct host1x_client *client) } /* initialize display controller */ - if (dc->pipe) - syncpt = SYNCPT_VBLANK1; - else - syncpt = SYNCPT_VBLANK0; + if (dc->syncpt) { + u32 syncpt = host1x_syncpt_id(dc->syncpt); - tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); - tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); + value = SYNCPT_CNTRL_NO_STALL; + tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); + + value = SYNCPT_VSYNC_ENABLE | syncpt; + tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); + } value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT; tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); @@ -1874,6 +1882,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc) static int tegra_dc_probe(struct platform_device *pdev) { + unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; const struct of_device_id *id; struct resource *regs; struct tegra_dc *dc; @@ -1965,6 +1974,10 @@ static int tegra_dc_probe(struct platform_device *pdev) return err; } + dc->syncpt = host1x_syncpt_request(&pdev->dev, flags); + if (!dc->syncpt) + dev_warn(&pdev->dev, "failed to allocate syncpoint\n"); + platform_set_drvdata(pdev, dc); return 0; @@ -1975,6 +1988,8 @@ static int tegra_dc_remove(struct platform_device *pdev) struct tegra_dc *dc = platform_get_drvdata(pdev); int err; + host1x_syncpt_free(dc->syncpt); + err = host1x_client_unregister(&dc->client); if (err < 0) { dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 705c93b..55792da 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -12,6 +12,8 @@ #define DC_CMD_GENERAL_INCR_SYNCPT 0x000 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 +#define SYNCPT_CNTRL_NO_STALL (1 << 8) +#define SYNCPT_CNTRL_SOFT_RESET (1 << 0) #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002 #define DC_CMD_WIN_A_INCR_SYNCPT 0x008 #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009 @@ -23,6 +25,7 @@ #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019 #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a #define DC_CMD_CONT_SYNCPT_VSYNC 0x028 +#define SYNCPT_VSYNC_ENABLE (1 << 8) #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 #define DC_CMD_DISPLAY_COMMAND 0x032 #define DISP_CTRL_MODE_STOP (0 << 5) @@ -438,8 +441,4 @@ #define DC_WINBUF_BD_UFLOW_STATUS 0xdca #define DC_WINBUF_CD_UFLOW_STATUS 0xfca -/* synchronization points */ -#define SYNCPT_VBLANK0 26 -#define SYNCPT_VBLANK1 27 - #endif /* TEGRA_DC_H */ diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 5f18807..1833abd 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) */ drm->irq_enabled = true; + /* syncpoints are used for full 32-bit hardware VBLANK counters */ + drm->vblank_disable_immediate = true; + drm->max_vblank_count = 0xffffffff; + err = drm_vblank_init(drm, drm->mode_config.num_crtc); if (err < 0) goto device; @@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) { struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + struct tegra_dc *dc = to_tegra_dc(crtc); if (!crtc) return 0; - /* TODO: implement real hardware counter using syncpoints */ - return drm_crtc_vblank_count(crtc); + return tegra_dc_get_vblank_counter(dc); } static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) @@ -879,8 +883,18 @@ static int tegra_debugfs_framebuffers(struct seq_file *s, void *data) return 0; } +static int tegra_debugfs_iova(struct seq_file *s, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)s->private; + struct drm_device *drm = node->minor->dev; + struct tegra_drm *tegra = drm->dev_private; + + return drm_mm_dump_table(s, &tegra->mm); +} + static struct drm_info_list tegra_debugfs_list[] = { { "framebuffers", tegra_debugfs_framebuffers, 0 }, + { "iova", tegra_debugfs_iova, 0 }, }; static int tegra_debugfs_init(struct drm_minor *minor) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 8cb2dfe..659b2fc 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -106,6 +106,7 @@ struct tegra_output; struct tegra_dc { struct host1x_client client; + struct host1x_syncpt *syncpt; struct device *dev; spinlock_t lock; @@ -180,12 +181,11 @@ struct tegra_dc_window { }; /* from dc.c */ +u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc); void tegra_dc_enable_vblank(struct tegra_dc *dc); void tegra_dc_disable_vblank(struct tegra_dc *dc); void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); void tegra_dc_commit(struct tegra_dc *dc); -int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent, - unsigned long pclk, unsigned int div); int tegra_dc_state_setup_clock(struct tegra_dc *dc, struct drm_crtc_state *crtc_state, struct clk *clk, unsigned long pclk, diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 7eaaee74..06ab178 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -952,7 +952,7 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder, } tegra_hdmi_writel(hdmi, - SOR_SEQ_CTL_PU_PC(0) | + SOR_SEQ_PU_PC(0) | SOR_SEQ_PU_PC_ALT(0) | SOR_SEQ_PD_PC(8) | SOR_SEQ_PD_PC_ALT(8), @@ -1394,8 +1394,8 @@ static int tegra_hdmi_exit(struct host1x_client *client) tegra_output_exit(&hdmi->output); - clk_disable_unprepare(hdmi->clk); reset_control_assert(hdmi->rst); + clk_disable_unprepare(hdmi->clk); regulator_disable(hdmi->vdd); regulator_disable(hdmi->pll); diff --git a/drivers/gpu/drm/tegra/hdmi.h b/drivers/gpu/drm/tegra/hdmi.h index 919a19d..a882514 100644 --- a/drivers/gpu/drm/tegra/hdmi.h +++ b/drivers/gpu/drm/tegra/hdmi.h @@ -201,7 +201,7 @@ #define HDMI_NV_PDISP_SOR_CRCB 0x5d #define HDMI_NV_PDISP_SOR_BLANK 0x5e #define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f -#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0) +#define SOR_SEQ_PU_PC(x) (((x) & 0xf) << 0) #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4) #define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8) #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 2afe478..7591d89 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -41,6 +41,8 @@ struct tegra_sor { struct mutex lock; bool enabled; + struct drm_info_list *debugfs_files; + struct drm_minor *minor; struct dentry *debugfs; }; @@ -68,13 +70,12 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output) return container_of(output, struct tegra_sor, output); } -static inline unsigned long tegra_sor_readl(struct tegra_sor *sor, - unsigned long offset) +static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset) { return readl(sor->regs + (offset << 2)); } -static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value, +static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, unsigned long offset) { writel(value, sor->regs + (offset << 2)); @@ -83,9 +84,9 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value, static int tegra_sor_dp_train_fast(struct tegra_sor *sor, struct drm_dp_link *link) { - unsigned long value; unsigned int i; u8 pattern; + u32 value; int err; /* setup lane parameters */ @@ -202,7 +203,7 @@ static void tegra_sor_update(struct tegra_sor *sor) static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) { - unsigned long value; + u32 value; value = tegra_sor_readl(sor, SOR_PWM_DIV); value &= ~SOR_PWM_DIV_MASK; @@ -281,7 +282,7 @@ static int tegra_sor_wakeup(struct tegra_sor *sor) static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) { - unsigned long value; + u32 value; value = tegra_sor_readl(sor, SOR_PWR); value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; @@ -674,38 +675,195 @@ static const struct file_operations tegra_sor_crc_fops = { .release = tegra_sor_crc_release, }; +static int tegra_sor_show_regs(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct tegra_sor *sor = node->info_ent->data; + +#define DUMP_REG(name) \ + seq_printf(s, "%-38s %#05x %08x\n", #name, name, \ + tegra_sor_readl(sor, name)) + + DUMP_REG(SOR_CTXSW); + DUMP_REG(SOR_SUPER_STATE_0); + DUMP_REG(SOR_SUPER_STATE_1); + DUMP_REG(SOR_STATE_0); + DUMP_REG(SOR_STATE_1); + DUMP_REG(SOR_HEAD_STATE_0(0)); + DUMP_REG(SOR_HEAD_STATE_0(1)); + DUMP_REG(SOR_HEAD_STATE_1(0)); + DUMP_REG(SOR_HEAD_STATE_1(1)); + DUMP_REG(SOR_HEAD_STATE_2(0)); + DUMP_REG(SOR_HEAD_STATE_2(1)); + DUMP_REG(SOR_HEAD_STATE_3(0)); + DUMP_REG(SOR_HEAD_STATE_3(1)); + DUMP_REG(SOR_HEAD_STATE_4(0)); + DUMP_REG(SOR_HEAD_STATE_4(1)); + DUMP_REG(SOR_HEAD_STATE_5(0)); + DUMP_REG(SOR_HEAD_STATE_5(1)); + DUMP_REG(SOR_CRC_CNTRL); + DUMP_REG(SOR_DP_DEBUG_MVID); + DUMP_REG(SOR_CLK_CNTRL); + DUMP_REG(SOR_CAP); + DUMP_REG(SOR_PWR); + DUMP_REG(SOR_TEST); + DUMP_REG(SOR_PLL_0); + DUMP_REG(SOR_PLL_1); + DUMP_REG(SOR_PLL_2); + DUMP_REG(SOR_PLL_3); + DUMP_REG(SOR_CSTM); + DUMP_REG(SOR_LVDS); + DUMP_REG(SOR_CRC_A); + DUMP_REG(SOR_CRC_B); + DUMP_REG(SOR_BLANK); + DUMP_REG(SOR_SEQ_CTL); + DUMP_REG(SOR_LANE_SEQ_CTL); + DUMP_REG(SOR_SEQ_INST(0)); + DUMP_REG(SOR_SEQ_INST(1)); + DUMP_REG(SOR_SEQ_INST(2)); + DUMP_REG(SOR_SEQ_INST(3)); + DUMP_REG(SOR_SEQ_INST(4)); + DUMP_REG(SOR_SEQ_INST(5)); + DUMP_REG(SOR_SEQ_INST(6)); + DUMP_REG(SOR_SEQ_INST(7)); + DUMP_REG(SOR_SEQ_INST(8)); + DUMP_REG(SOR_SEQ_INST(9)); + DUMP_REG(SOR_SEQ_INST(10)); + DUMP_REG(SOR_SEQ_INST(11)); + DUMP_REG(SOR_SEQ_INST(12)); + DUMP_REG(SOR_SEQ_INST(13)); + DUMP_REG(SOR_SEQ_INST(14)); + DUMP_REG(SOR_SEQ_INST(15)); + DUMP_REG(SOR_PWM_DIV); + DUMP_REG(SOR_PWM_CTL); + DUMP_REG(SOR_VCRC_A_0); + DUMP_REG(SOR_VCRC_A_1); + DUMP_REG(SOR_VCRC_B_0); + DUMP_REG(SOR_VCRC_B_1); + DUMP_REG(SOR_CCRC_A_0); + DUMP_REG(SOR_CCRC_A_1); + DUMP_REG(SOR_CCRC_B_0); + DUMP_REG(SOR_CCRC_B_1); + DUMP_REG(SOR_EDATA_A_0); + DUMP_REG(SOR_EDATA_A_1); + DUMP_REG(SOR_EDATA_B_0); + DUMP_REG(SOR_EDATA_B_1); + DUMP_REG(SOR_COUNT_A_0); + DUMP_REG(SOR_COUNT_A_1); + DUMP_REG(SOR_COUNT_B_0); + DUMP_REG(SOR_COUNT_B_1); + DUMP_REG(SOR_DEBUG_A_0); + DUMP_REG(SOR_DEBUG_A_1); + DUMP_REG(SOR_DEBUG_B_0); + DUMP_REG(SOR_DEBUG_B_1); + DUMP_REG(SOR_TRIG); + DUMP_REG(SOR_MSCHECK); + DUMP_REG(SOR_XBAR_CTRL); + DUMP_REG(SOR_XBAR_POL); + DUMP_REG(SOR_DP_LINKCTL_0); + DUMP_REG(SOR_DP_LINKCTL_1); + DUMP_REG(SOR_LANE_DRIVE_CURRENT_0); + DUMP_REG(SOR_LANE_DRIVE_CURRENT_1); + DUMP_REG(SOR_LANE4_DRIVE_CURRENT_0); + DUMP_REG(SOR_LANE4_DRIVE_CURRENT_1); + DUMP_REG(SOR_LANE_PREEMPHASIS_0); + DUMP_REG(SOR_LANE_PREEMPHASIS_1); + DUMP_REG(SOR_LANE4_PREEMPHASIS_0); + DUMP_REG(SOR_LANE4_PREEMPHASIS_1); + DUMP_REG(SOR_LANE_POST_CURSOR_0); + DUMP_REG(SOR_LANE_POST_CURSOR_1); + DUMP_REG(SOR_DP_CONFIG_0); + DUMP_REG(SOR_DP_CONFIG_1); + DUMP_REG(SOR_DP_MN_0); + DUMP_REG(SOR_DP_MN_1); + DUMP_REG(SOR_DP_PADCTL_0); + DUMP_REG(SOR_DP_PADCTL_1); + DUMP_REG(SOR_DP_DEBUG_0); + DUMP_REG(SOR_DP_DEBUG_1); + DUMP_REG(SOR_DP_SPARE_0); + DUMP_REG(SOR_DP_SPARE_1); + DUMP_REG(SOR_DP_AUDIO_CTRL); + DUMP_REG(SOR_DP_AUDIO_HBLANK_SYMBOLS); + DUMP_REG(SOR_DP_AUDIO_VBLANK_SYMBOLS); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_HEADER); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_0); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_1); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_2); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_3); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_4); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_5); + DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_6); + DUMP_REG(SOR_DP_TPG); + DUMP_REG(SOR_DP_TPG_CONFIG); + DUMP_REG(SOR_DP_LQ_CSTM_0); + DUMP_REG(SOR_DP_LQ_CSTM_1); + DUMP_REG(SOR_DP_LQ_CSTM_2); + +#undef DUMP_REG + + return 0; +} + +static const struct drm_info_list debugfs_files[] = { + { "regs", tegra_sor_show_regs, 0, NULL }, +}; + static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct drm_minor *minor) { struct dentry *entry; + unsigned int i; int err = 0; sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root); if (!sor->debugfs) return -ENOMEM; + sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), + GFP_KERNEL); + if (!sor->debugfs_files) { + err = -ENOMEM; + goto remove; + } + + for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) + sor->debugfs_files[i].data = sor; + + err = drm_debugfs_create_files(sor->debugfs_files, + ARRAY_SIZE(debugfs_files), + sor->debugfs, minor); + if (err < 0) + goto free; + entry = debugfs_create_file("crc", 0644, sor->debugfs, sor, &tegra_sor_crc_fops); if (!entry) { - dev_err(sor->dev, - "cannot create /sys/kernel/debug/dri/%s/sor/crc\n", - minor->debugfs_root->d_name.name); err = -ENOMEM; - goto remove; + goto free; } return err; +free: + kfree(sor->debugfs_files); + sor->debugfs_files = NULL; remove: - debugfs_remove(sor->debugfs); + debugfs_remove_recursive(sor->debugfs); sor->debugfs = NULL; return err; } static void tegra_sor_debugfs_exit(struct tegra_sor *sor) { - debugfs_remove_recursive(sor->debugfs); + drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files), + sor->minor); + sor->minor = NULL; + + kfree(sor->debugfs_files); sor->debugfs = NULL; + + debugfs_remove_recursive(sor->debugfs); + sor->debugfs_files = NULL; } static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode) @@ -791,8 +949,8 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder, struct tegra_sor_config config; struct drm_dp_link link; struct drm_dp_aux *aux; - unsigned long value; int err = 0; + u32 value; mutex_lock(&sor->lock); @@ -1354,12 +1512,30 @@ static int tegra_sor_init(struct host1x_client *client) } } + /* + * XXX: Remove this reset once proper hand-over from firmware to + * kernel is possible. + */ + err = reset_control_assert(sor->rst); + if (err < 0) { + dev_err(sor->dev, "failed to assert SOR reset: %d\n", err); + return err; + } + err = clk_prepare_enable(sor->clk); if (err < 0) { dev_err(sor->dev, "failed to enable clock: %d\n", err); return err; } + usleep_range(1000, 3000); + + err = reset_control_deassert(sor->rst); + if (err < 0) { + dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err); + return err; + } + err = clk_prepare_enable(sor->clk_safe); if (err < 0) return err; diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index b10550e..6b7fdc1 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -425,6 +425,12 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) } EXPORT_SYMBOL(host1x_syncpt_read_min); +u32 host1x_syncpt_read(struct host1x_syncpt *sp) +{ + return host1x_syncpt_load(sp); +} +EXPORT_SYMBOL(host1x_syncpt_read); + int host1x_syncpt_nb_pts(struct host1x *host) { return host->info->nb_pts; |