The new omapdss API is HW independent and cleans up some of the DSS5 specific hacks from the omapdrm side and get rid off the DSS2 IRQ register bits and replace them with HW independent struct. This new generic struct makes it more straight forward to implement IRQ code for the future DSS versions that do not share the same register structure as DSS2 to DSS5 has. Signed-off-by: Jyri Sarha <jsarha@xxxxxx> --- drivers/gpu/drm/omapdrm/dss/dispc.c | 158 ++++++++++++++++++++++++---- drivers/gpu/drm/omapdrm/dss/dispc.h | 33 ++++++ drivers/gpu/drm/omapdrm/dss/omapdss.h | 68 ++++++------ drivers/gpu/drm/omapdrm/omap_crtc.c | 37 +++---- drivers/gpu/drm/omapdrm/omap_drv.h | 5 +- drivers/gpu/drm/omapdrm/omap_irq.c | 192 ++++++++++++++++++++-------------- drivers/gpu/drm/omapdrm/omap_plane.c | 18 ++-- 7 files changed, 346 insertions(+), 165 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 0f4fdb2..916c532 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -682,27 +682,30 @@ void dispc_runtime_put(void) WARN_ON(r < 0 && r != -ENOSYS); } -static u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) +static const char *dispc_get_ovl_name(enum omap_plane_id plane) { - return mgr_desc[channel].vsync_irq; -} - -static u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) -{ - if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) - return 0; + static const char *ovl_names[] = { + [OMAP_DSS_GFX] = "GFX", + [OMAP_DSS_VIDEO1] = "VID1", + [OMAP_DSS_VIDEO2] = "VID2", + [OMAP_DSS_VIDEO3] = "VID3", + [OMAP_DSS_WB] = "WB", + }; - return mgr_desc[channel].framedone_irq; + return ovl_names[plane]; } -static u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) +static const char *dispc_get_mgr_name(enum omap_channel channel) { - return mgr_desc[channel].sync_lost_irq; + return mgr_desc[channel].name; } -u32 dispc_wb_get_framedone_irq(void) +static bool dispc_mgr_has_framedone(enum omap_channel channel) { - return DISPC_IRQ_FRAMEDONEWB; + if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) + return false; + + return true; } static void dispc_mgr_enable(enum omap_channel channel, bool enable) @@ -3588,6 +3591,120 @@ static void dispc_write_irqenable(u32 mask) dispc_read_reg(DISPC_IRQENABLE); } +static void dispc_hw_to_api_irq(u32 hw, struct dss_irq *api) +{ + memset(api, 0, sizeof(*api)); + + if (hw & DISPC_IRQ_OCP_ERR) + api->device |= DSS_IRQ_DEVICE_OCP_ERR; + + if (hw & DISPC_IRQ_FRAMEDONE) + api->channel[0] |= DSS_IRQ_MGR_FRAME_DONE; + if (hw & DISPC_IRQ_VSYNC) + api->channel[0] |= DSS_IRQ_MGR_VSYNC_EVEN; + if (hw & DISPC_IRQ_SYNC_LOST) + api->channel[0] |= DSS_IRQ_MGR_SYNC_LOST; + + if (hw & DISPC_IRQ_EVSYNC_EVEN) + api->channel[1] |= DSS_IRQ_MGR_VSYNC_EVEN; + if (hw & DISPC_IRQ_EVSYNC_ODD) + api->channel[1] |= DSS_IRQ_MGR_VSYNC_ODD; + if (hw & DISPC_IRQ_SYNC_LOST_DIGIT) + api->channel[1] |= DSS_IRQ_MGR_SYNC_LOST; + if (hw & DISPC_IRQ_FRAMEDONETV) + api->channel[1] |= DSS_IRQ_MGR_FRAME_DONE; + + if (hw & DISPC_IRQ_SYNC_LOST2) + api->channel[2] |= DSS_IRQ_MGR_SYNC_LOST; + if (hw & DISPC_IRQ_VSYNC2) + api->channel[2] |= DSS_IRQ_MGR_VSYNC_EVEN; + if (hw & DISPC_IRQ_FRAMEDONE2) + api->channel[2] |= DSS_IRQ_MGR_FRAME_DONE; + + if (hw & DISPC_IRQ_SYNC_LOST3) + api->channel[3] |= DSS_IRQ_MGR_SYNC_LOST; + if (hw & DISPC_IRQ_VSYNC3) + api->channel[3] |= DSS_IRQ_MGR_VSYNC_EVEN; + if (hw & DISPC_IRQ_FRAMEDONE3) + api->channel[3] |= DSS_IRQ_MGR_FRAME_DONE; + + if (hw & DISPC_IRQ_GFX_FIFO_UNDERFLOW) + api->ovl[0] |= DSS_IRQ_OVL_FIFO_UNDERFLOW; + if (hw & DISPC_IRQ_VID1_FIFO_UNDERFLOW) + api->ovl[1] |= DSS_IRQ_OVL_FIFO_UNDERFLOW; + if (hw & DISPC_IRQ_VID2_FIFO_UNDERFLOW) + api->ovl[2] |= DSS_IRQ_OVL_FIFO_UNDERFLOW; + if (hw & DISPC_IRQ_VID3_FIFO_UNDERFLOW) + api->ovl[3] |= DSS_IRQ_OVL_FIFO_UNDERFLOW; +} + +static u32 dispc_api_to_hw_irq(const struct dss_irq *api) +{ + u32 hw = 0; + + if (api->device & DSS_IRQ_DEVICE_OCP_ERR) + hw |= DISPC_IRQ_OCP_ERR; + + if (api->channel[0] & DSS_IRQ_MGR_FRAME_DONE) + hw |= DISPC_IRQ_FRAMEDONE; + if (api->channel[0] & DSS_IRQ_MGR_VSYNC_EVEN) + hw |= DISPC_IRQ_VSYNC; + if (api->channel[0] & DSS_IRQ_MGR_SYNC_LOST) + hw |= DISPC_IRQ_SYNC_LOST; + + if (api->channel[1] & DSS_IRQ_MGR_VSYNC_EVEN) + hw |= DISPC_IRQ_EVSYNC_EVEN; + if (api->channel[1] & DSS_IRQ_MGR_VSYNC_ODD) + hw |= DISPC_IRQ_EVSYNC_ODD; + if (api->channel[1] & DSS_IRQ_MGR_SYNC_LOST) + hw |= DISPC_IRQ_SYNC_LOST_DIGIT; + if (api->channel[1] & DSS_IRQ_MGR_FRAME_DONE) + hw |= DISPC_IRQ_FRAMEDONETV; + + if (api->channel[2] & DSS_IRQ_MGR_SYNC_LOST) + hw |= DISPC_IRQ_SYNC_LOST2; + if (api->channel[2] & DSS_IRQ_MGR_VSYNC_EVEN) + hw |= DISPC_IRQ_VSYNC2; + if (api->channel[2] & DSS_IRQ_MGR_FRAME_DONE) + hw |= DISPC_IRQ_FRAMEDONE2; + + if (api->channel[3] & DSS_IRQ_MGR_SYNC_LOST) + hw |= DISPC_IRQ_SYNC_LOST3; + if (api->channel[3] & DSS_IRQ_MGR_VSYNC_EVEN) + hw |= DISPC_IRQ_VSYNC3; + if (api->channel[3] & DSS_IRQ_MGR_FRAME_DONE) + hw |= DISPC_IRQ_FRAMEDONE3; + + if (api->ovl[0] & DSS_IRQ_OVL_FIFO_UNDERFLOW) + hw |= DISPC_IRQ_GFX_FIFO_UNDERFLOW; + if (api->ovl[1] & DSS_IRQ_OVL_FIFO_UNDERFLOW) + hw |= DISPC_IRQ_VID1_FIFO_UNDERFLOW; + if (api->ovl[2] & DSS_IRQ_OVL_FIFO_UNDERFLOW) + hw |= DISPC_IRQ_VID2_FIFO_UNDERFLOW; + if (api->ovl[3] & DSS_IRQ_OVL_FIFO_UNDERFLOW) + hw |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; + + return hw; +} + +static void dispc_api_read_irqstatus(struct dss_irq *status, + const struct dss_irq *clearmask) +{ + u32 hw_clearmask = dispc_api_to_hw_irq(clearmask); + u32 hw_status = dispc_read_irqstatus(); + + dispc_clear_irqstatus(hw_clearmask & hw_status); + + dispc_hw_to_api_irq(hw_status, status); +} + +static void dispc_api_write_irqenable(const struct dss_irq *enable) +{ + u32 hw_enable = dispc_api_to_hw_irq(enable); + + dispc_write_irqenable(hw_enable); +} + void dispc_enable_sidle(void) { REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ @@ -4426,7 +4543,7 @@ static void dispc_errata_i734_wa_fini(void) static void dispc_errata_i734_wa(void) { - u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD); + u32 framedone_irq = DISPC_IRQ_FRAMEDONE; struct omap_overlay_info ovli; struct dss_lcd_mgr_config lcd_conf; u32 gatestate; @@ -4484,9 +4601,8 @@ static void dispc_errata_i734_wa(void) } static const struct dispc_ops dispc_ops = { - .read_irqstatus = dispc_read_irqstatus, - .clear_irqstatus = dispc_clear_irqstatus, - .write_irqenable = dispc_write_irqenable, + .read_irqstatus = dispc_api_read_irqstatus, + .write_irqenable = dispc_api_write_irqenable, .request_irq = dispc_request_irq, .free_irq = dispc_free_irq, @@ -4497,11 +4613,13 @@ static void dispc_errata_i734_wa(void) .get_num_ovls = dispc_get_num_ovls, .get_num_mgrs = dispc_get_num_mgrs, + .get_ovl_name = dispc_get_ovl_name, + .get_mgr_name = dispc_get_mgr_name, + + .mgr_has_framedone = dispc_mgr_has_framedone, + .mgr_enable = dispc_mgr_enable, .mgr_is_enabled = dispc_mgr_is_enabled, - .mgr_get_vsync_irq = dispc_mgr_get_vsync_irq, - .mgr_get_framedone_irq = dispc_mgr_get_framedone_irq, - .mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq, .mgr_go_busy = dispc_mgr_go_busy, .mgr_go = dispc_mgr_go, .mgr_set_lcd_config = dispc_mgr_set_lcd_config, diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h index 003adce..0835486 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.h +++ b/drivers/gpu/drm/omapdrm/dss/dispc.h @@ -21,6 +21,39 @@ #ifndef __OMAP2_DISPC_REG_H #define __OMAP2_DISPC_REG_H +/* DISPC IRQ bits */ +#define DISPC_IRQ_FRAMEDONE (1 << 0) +#define DISPC_IRQ_VSYNC (1 << 1) +#define DISPC_IRQ_EVSYNC_EVEN (1 << 2) +#define DISPC_IRQ_EVSYNC_ODD (1 << 3) +#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4) +#define DISPC_IRQ_PROG_LINE_NUM (1 << 5) +#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6) +#define DISPC_IRQ_GFX_END_WIN (1 << 7) +#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8) +#define DISPC_IRQ_OCP_ERR (1 << 9) +#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10) +#define DISPC_IRQ_VID1_END_WIN (1 << 11) +#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12) +#define DISPC_IRQ_VID2_END_WIN (1 << 13) +#define DISPC_IRQ_SYNC_LOST (1 << 14) +#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15) +#define DISPC_IRQ_WAKEUP (1 << 16) +#define DISPC_IRQ_SYNC_LOST2 (1 << 17) +#define DISPC_IRQ_VSYNC2 (1 << 18) +#define DISPC_IRQ_VID3_END_WIN (1 << 19) +#define DISPC_IRQ_VID3_FIFO_UNDERFLOW (1 << 20) +#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21) +#define DISPC_IRQ_FRAMEDONE2 (1 << 22) +#define DISPC_IRQ_FRAMEDONEWB (1 << 23) +#define DISPC_IRQ_FRAMEDONETV (1 << 24) +#define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25) +#define DISPC_IRQ_WBUNCOMPLETEERROR (1 << 26) +#define DISPC_IRQ_SYNC_LOST3 (1 << 27) +#define DISPC_IRQ_VSYNC3 (1 << 28) +#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) +#define DISPC_IRQ_FRAMEDONE3 (1 << 30) + /* DISPC common registers */ #define DISPC_REVISION 0x0000 #define DISPC_SYSCONFIG 0x0010 diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 47a3316..dbbb71b 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -27,37 +27,29 @@ #include <uapi/drm/drm_mode.h> #include <drm/drm_crtc.h> -#define DISPC_IRQ_FRAMEDONE (1 << 0) -#define DISPC_IRQ_VSYNC (1 << 1) -#define DISPC_IRQ_EVSYNC_EVEN (1 << 2) -#define DISPC_IRQ_EVSYNC_ODD (1 << 3) -#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4) -#define DISPC_IRQ_PROG_LINE_NUM (1 << 5) -#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6) -#define DISPC_IRQ_GFX_END_WIN (1 << 7) -#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8) -#define DISPC_IRQ_OCP_ERR (1 << 9) -#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10) -#define DISPC_IRQ_VID1_END_WIN (1 << 11) -#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12) -#define DISPC_IRQ_VID2_END_WIN (1 << 13) -#define DISPC_IRQ_SYNC_LOST (1 << 14) -#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15) -#define DISPC_IRQ_WAKEUP (1 << 16) -#define DISPC_IRQ_SYNC_LOST2 (1 << 17) -#define DISPC_IRQ_VSYNC2 (1 << 18) -#define DISPC_IRQ_VID3_END_WIN (1 << 19) -#define DISPC_IRQ_VID3_FIFO_UNDERFLOW (1 << 20) -#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21) -#define DISPC_IRQ_FRAMEDONE2 (1 << 22) -#define DISPC_IRQ_FRAMEDONEWB (1 << 23) -#define DISPC_IRQ_FRAMEDONETV (1 << 24) -#define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25) -#define DISPC_IRQ_WBUNCOMPLETEERROR (1 << 26) -#define DISPC_IRQ_SYNC_LOST3 (1 << 27) -#define DISPC_IRQ_VSYNC3 (1 << 28) -#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) -#define DISPC_IRQ_FRAMEDONE3 (1 << 30) +enum dss_irq_device { + DSS_IRQ_DEVICE_OCP_ERR = BIT(0), +}; + +enum dss_irq_channel { + DSS_IRQ_MGR_FRAME_DONE = BIT(0), + DSS_IRQ_MGR_VSYNC_EVEN = BIT(1), + DSS_IRQ_MGR_VSYNC_ODD = BIT(2), + DSS_IRQ_MGR_SYNC_LOST = BIT(3), +}; + +enum dss_irq_ovl { + DSS_IRQ_OVL_FIFO_UNDERFLOW = BIT(0), +}; + +#define DSS_MAX_CHANNELS 4 +#define DSS_MAX_OVLS 4 +struct dss_irq { + u8 device; + u8 channel[DSS_MAX_CHANNELS]; + u8 ovl[DSS_MAX_OVLS]; +}; + struct omap_dss_device; struct dss_lcd_mgr_config; @@ -681,9 +673,9 @@ void dss_mgr_unregister_framedone_handler(enum omap_channel channel, /* dispc ops */ struct dispc_ops { - u32 (*read_irqstatus)(void); - void (*clear_irqstatus)(u32 mask); - void (*write_irqenable)(u32 mask); + void (*read_irqstatus)(struct dss_irq *status, + const struct dss_irq *clearmask); + void (*write_irqenable)(const struct dss_irq *enable); int (*request_irq)(irq_handler_t handler, void *dev_id); void (*free_irq)(void *dev_id); @@ -694,11 +686,13 @@ struct dispc_ops { int (*get_num_ovls)(void); int (*get_num_mgrs)(void); + const char *(*get_ovl_name)(enum omap_plane_id plane); + const char *(*get_mgr_name)(enum omap_channel channel); + + bool (*mgr_has_framedone)(enum omap_channel channel); + void (*mgr_enable)(enum omap_channel channel, bool enable); bool (*mgr_is_enabled)(enum omap_channel channel); - u32 (*mgr_get_vsync_irq)(enum omap_channel channel); - u32 (*mgr_get_framedone_irq)(enum omap_channel channel); - u32 (*mgr_get_sync_lost_irq)(enum omap_channel channel); bool (*mgr_go_busy)(enum omap_channel channel); void (*mgr_go)(enum omap_channel channel); void (*mgr_set_lcd_config)(enum omap_channel channel, diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index cc85c16..a1f8ccf 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -150,7 +150,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) struct omap_crtc *omap_crtc = to_omap_crtc(crtc); enum omap_channel channel = omap_crtc->channel; struct omap_irq_wait *wait; - u32 framedone_irq, vsync_irq; + struct dss_irq vsync_irq, framedone_irq; int ret; if (WARN_ON(omap_crtc->enabled == enable)) @@ -170,11 +170,15 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) omap_crtc->ignore_digit_sync_lost = true; } - framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); - vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(channel); + + memset(&vsync_irq, 0, sizeof(vsync_irq)); + vsync_irq.channel[channel] = (DSS_IRQ_MGR_VSYNC_EVEN | + DSS_IRQ_MGR_VSYNC_ODD); + memset(&framedone_irq, 0, sizeof(framedone_irq)); + framedone_irq.channel[channel] = DSS_IRQ_MGR_FRAME_DONE; if (enable) { - wait = omap_irq_wait_init(dev, vsync_irq, 1); + wait = omap_irq_wait_init(dev, &vsync_irq, 1); } else { /* * When we disable the digit output, we need to wait for @@ -185,10 +189,10 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) * even and odd frames. */ - if (framedone_irq) - wait = omap_irq_wait_init(dev, framedone_irq, 1); + if (priv->dispc_ops->mgr_has_framedone(channel)) + wait = omap_irq_wait_init(dev, &framedone_irq, 1); else - wait = omap_irq_wait_init(dev, vsync_irq, 2); + wait = omap_irq_wait_init(dev, &vsync_irq, 2); } priv->dispc_ops->mgr_enable(channel, enable); @@ -273,17 +277,17 @@ static void omap_crtc_dss_unregister_framedone( * Setup, Flush and Page Flip */ -void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus) +void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t mgr_irqstatus) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); if (omap_crtc->ignore_digit_sync_lost) { - irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT; - if (!irqstatus) + mgr_irqstatus &= ~DSS_IRQ_MGR_SYNC_LOST; + if (!mgr_irqstatus) return; } - DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); + DRM_ERROR_RATELIMITED("%s: errors: %02x\n", omap_crtc->name, mgr_irqstatus); } void omap_crtc_vblank_irq(struct drm_crtc *crtc) @@ -627,13 +631,6 @@ static void omap_crtc_reset(struct drm_crtc *crtc) * Init and Cleanup */ -static const char *channel_names[] = { - [OMAP_DSS_CHANNEL_LCD] = "lcd", - [OMAP_DSS_CHANNEL_DIGIT] = "tv", - [OMAP_DSS_CHANNEL_LCD2] = "lcd2", - [OMAP_DSS_CHANNEL_LCD3] = "lcd3", -}; - void omap_crtc_pre_init(void) { memset(omap_crtcs, 0, sizeof(omap_crtcs)); @@ -661,7 +658,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, channel = out->dispc_channel; omap_dss_put_device(out); - DBG("%s", channel_names[channel]); + DBG("%s", priv->dispc_ops->get_mgr_name(channel)); /* Multiple displays on same channel is not allowed */ if (WARN_ON(omap_crtcs[channel] != NULL)) @@ -676,7 +673,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, init_waitqueue_head(&omap_crtc->pending_wait); omap_crtc->channel = channel; - omap_crtc->name = channel_names[channel]; + omap_crtc->name = priv->dispc_ops->get_mgr_name(channel); ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, &omap_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 4bd1e90..ffc84b0 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -42,7 +42,7 @@ */ struct omap_irq_wait; struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count); + struct dss_irq *irqmask, int count); int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, unsigned long timeout); @@ -82,7 +82,7 @@ struct omap_drm_private { /* irq handling: */ spinlock_t wait_lock; /* protects the wait_list */ struct list_head wait_list; /* list of omap_irq_wait */ - uint32_t irq_mask; /* enabled irqs in addition to wait_list */ + struct dss_irq irq_mask; /* enabled irqs in addition to wait_list */ }; @@ -130,6 +130,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, u32 possible_crtcs); void omap_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); +enum omap_plane_id omap_plane_get_id(struct drm_plane *plane); struct drm_encoder *omap_encoder_init(struct drm_device *dev, struct omap_dss_device *dssdev); diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 013b0bb..7dafa2c 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -22,25 +22,69 @@ struct omap_irq_wait { struct list_head node; wait_queue_head_t wq; - uint32_t irqmask; + struct dss_irq irqmask; int count; }; +static void dss_irq_or(struct omap_drm_private *priv, + struct dss_irq *res, const struct dss_irq *arg1, + const struct dss_irq *arg2) +{ + int i; + + for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++) + res->channel[i] = arg1->channel[i] | arg2->channel[i]; + + for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++) + res->ovl[i] = arg1->ovl[i] | arg2->ovl[i]; +} + +static void dss_irq_and(struct omap_drm_private *priv, + struct dss_irq *res, const struct dss_irq *arg1, + const struct dss_irq *arg2) +{ + int i; + + for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++) + res->channel[i] = arg1->channel[i] & arg2->channel[i]; + + for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++) + res->ovl[i] = arg1->ovl[i] & arg2->ovl[i]; +} + +static bool dss_irq_nonzero(struct omap_drm_private *priv, + struct dss_irq *status) +{ + int i; + + for (i = 0; i < priv->dispc_ops->get_num_mgrs(); i++) + if (status->channel[i]) + return true; + + for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++) + if (status->ovl[i]) + return true; + + return false; +} + /* call with wait_lock and dispc runtime held */ -static void omap_irq_update(struct drm_device *dev) +static void omap_irq_full_mask(struct drm_device *dev, struct dss_irq *irqmask) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait; - uint32_t irqmask = priv->irq_mask; assert_spin_locked(&priv->wait_lock); - list_for_each_entry(wait, &priv->wait_list, node) - irqmask |= wait->irqmask; + *irqmask = priv->irq_mask; - DBG("irqmask=%08x", irqmask); + list_for_each_entry(wait, &priv->wait_list, node) + dss_irq_or(priv, irqmask, irqmask, &wait->irqmask); - priv->dispc_ops->write_irqenable(irqmask); + DBG("irqmask ch %02x %02x %02x %02x ovl %02x %02x %02x %02x", + irqmask->channel[0], irqmask->channel[1], + irqmask->channel[2], irqmask->channel[3], + irqmask->ovl[0], irqmask->ovl[1], irqmask->ovl[2], irqmask->ovl[3]); } static void omap_irq_wait_handler(struct omap_irq_wait *wait) @@ -50,19 +94,21 @@ static void omap_irq_wait_handler(struct omap_irq_wait *wait) } struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count) + struct dss_irq *waitmask, int count) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); + struct dss_irq irqmask; unsigned long flags; init_waitqueue_head(&wait->wq); - wait->irqmask = irqmask; + wait->irqmask = *waitmask; wait->count = count; spin_lock_irqsave(&priv->wait_lock, flags); list_add(&wait->node, &priv->wait_list); - omap_irq_update(dev); + omap_irq_full_mask(dev, &irqmask); + priv->dispc_ops->write_irqenable(&irqmask); spin_unlock_irqrestore(&priv->wait_lock, flags); return wait; @@ -72,6 +118,7 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, unsigned long timeout) { struct omap_drm_private *priv = dev->dev_private; + struct dss_irq irqmask; unsigned long flags; int ret; @@ -79,7 +126,8 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, spin_lock_irqsave(&priv->wait_lock, flags); list_del(&wait->node); - omap_irq_update(dev); + omap_irq_full_mask(dev, &irqmask); + priv->dispc_ops->write_irqenable(&irqmask); spin_unlock_irqrestore(&priv->wait_lock, flags); kfree(wait); @@ -106,12 +154,15 @@ int omap_irq_enable_vblank(struct drm_crtc *crtc) struct omap_drm_private *priv = dev->dev_private; unsigned long flags; enum omap_channel channel = omap_crtc_channel(crtc); + struct dss_irq irqmask; DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(channel); - omap_irq_update(dev); + priv->irq_mask.channel[channel] |= + DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD; + omap_irq_full_mask(dev, &irqmask); + priv->dispc_ops->write_irqenable(&irqmask); spin_unlock_irqrestore(&priv->wait_lock, flags); return 0; @@ -132,41 +183,35 @@ void omap_irq_disable_vblank(struct drm_crtc *crtc) struct omap_drm_private *priv = dev->dev_private; unsigned long flags; enum omap_channel channel = omap_crtc_channel(crtc); + struct dss_irq irqmask; DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(channel); - omap_irq_update(dev); + priv->irq_mask.channel[channel] &= + ~(DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD); + omap_irq_full_mask(dev, &irqmask); + priv->dispc_ops->write_irqenable(&irqmask); spin_unlock_irqrestore(&priv->wait_lock, flags); } static void omap_irq_fifo_underflow(struct omap_drm_private *priv, - u32 irqstatus) + struct dss_irq *irqstatus) { static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - static const struct { - const char *name; - u32 mask; - } sources[] = { - { "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW }, - { "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW }, - { "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW }, - { "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW }, - }; - - const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW - | DISPC_IRQ_VID1_FIFO_UNDERFLOW - | DISPC_IRQ_VID2_FIFO_UNDERFLOW - | DISPC_IRQ_VID3_FIFO_UNDERFLOW; + bool ovl_undeflow[DSS_MAX_OVLS] = { false }; + bool underflow = false; unsigned int i; spin_lock(&priv->wait_lock); - irqstatus &= priv->irq_mask & mask; + for (i = 0; i < priv->dispc_ops->get_num_ovls(); i++) + if (irqstatus->ovl[i] & priv->irq_mask.ovl[i] & + DSS_IRQ_OVL_FIFO_UNDERFLOW) + underflow = ovl_undeflow[i] = true; spin_unlock(&priv->wait_lock); - if (!irqstatus) + if (!underflow) return; if (!__ratelimit(&_rs)) @@ -174,18 +219,18 @@ static void omap_irq_fifo_underflow(struct omap_drm_private *priv, DRM_ERROR("FIFO underflow on "); - for (i = 0; i < ARRAY_SIZE(sources); ++i) { - if (sources[i].mask & irqstatus) - pr_cont("%s ", sources[i].name); + for (i = 0; i < DSS_MAX_OVLS; ++i) { + if (ovl_undeflow[i]) + pr_cont("%u:%s ", i, priv->dispc_ops->get_ovl_name(i)); } - pr_cont("(0x%08x)\n", irqstatus); + pr_cont("\n"); } static void omap_irq_ocp_error_handler(struct drm_device *dev, - u32 irqstatus) + struct dss_irq *irqstatus) { - if (!(irqstatus & DISPC_IRQ_OCP_ERR)) + if (!(irqstatus->device & DSS_IRQ_DEVICE_OCP_ERR)) return; dev_err_ratelimited(dev->dev, "OCP error\n"); @@ -198,47 +243,48 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) struct omap_irq_wait *wait, *n; unsigned long flags; unsigned int id; - u32 irqstatus; + struct dss_irq irqstatus, clearmask; - irqstatus = priv->dispc_ops->read_irqstatus(); - priv->dispc_ops->clear_irqstatus(irqstatus); - priv->dispc_ops->read_irqstatus(); /* flush posted write */ + spin_lock_irqsave(&priv->wait_lock, flags); + omap_irq_full_mask(dev, &clearmask); + priv->dispc_ops->read_irqstatus(&irqstatus, &clearmask); + + list_for_each_entry_safe(wait, n, &priv->wait_list, node) { + struct dss_irq waitstatus; + + dss_irq_and(priv, &waitstatus, &irqstatus, &wait->irqmask); + if (dss_irq_nonzero(priv, &waitstatus)) + omap_irq_wait_handler(wait); + } + spin_unlock_irqrestore(&priv->wait_lock, flags); + + VERB("irqs: ch 0x%02x 0x%02x 0x%02x 0x%02x ovl 0x%02x 0x%02x 0x%02x 0x%02x\n", + irqstatus.channel[0], irqstatus.channel[1], + irqstatus.channel[2], irqstatus.channel[3], + irqstatus.ovl[0], irqstatus.ovl[1], + irqstatus.ovl[2], irqstatus.ovl[3]); - VERB("irqs: %08x", irqstatus); for (id = 0; id < priv->num_crtcs; id++) { struct drm_crtc *crtc = priv->crtcs[id]; enum omap_channel channel = omap_crtc_channel(crtc); - if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(channel)) { + if (irqstatus.channel[channel] & + (DSS_IRQ_MGR_VSYNC_EVEN | DSS_IRQ_MGR_VSYNC_ODD)) { drm_handle_vblank(dev, id); omap_crtc_vblank_irq(crtc); } - if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) - omap_crtc_error_irq(crtc, irqstatus); + if (irqstatus.channel[channel] & DSS_IRQ_MGR_SYNC_LOST) + omap_crtc_error_irq(crtc, irqstatus.channel[channel]); } - omap_irq_ocp_error_handler(dev, irqstatus); - omap_irq_fifo_underflow(priv, irqstatus); - - spin_lock_irqsave(&priv->wait_lock, flags); - list_for_each_entry_safe(wait, n, &priv->wait_list, node) { - if (wait->irqmask & irqstatus) - omap_irq_wait_handler(wait); - } - spin_unlock_irqrestore(&priv->wait_lock, flags); + omap_irq_ocp_error_handler(dev, &irqstatus); + omap_irq_fifo_underflow(priv, &irqstatus); return IRQ_HANDLED; } -static const u32 omap_underflow_irqs[] = { - [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, - [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, - [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, - [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, -}; - /* * We need a special version, instead of just using drm_irq_install(), * because we need to register the irq via omapdss. Once omapdss and @@ -249,29 +295,21 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) int omap_drm_irq_install(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs(); - unsigned int max_planes; unsigned int i; int ret; spin_lock_init(&priv->wait_lock); INIT_LIST_HEAD(&priv->wait_list); - priv->irq_mask = DISPC_IRQ_OCP_ERR; - - max_planes = min(ARRAY_SIZE(priv->planes), - ARRAY_SIZE(omap_underflow_irqs)); - for (i = 0; i < max_planes; ++i) { - if (priv->planes[i]) - priv->irq_mask |= omap_underflow_irqs[i]; - } + priv->irq_mask.device = DSS_IRQ_DEVICE_OCP_ERR; - for (i = 0; i < num_mgrs; ++i) - priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(i); + for (i = 0; i < priv->num_planes; ++i) + priv->irq_mask.ovl[omap_plane_get_id(priv->planes[i])] |= + DSS_IRQ_OVL_FIFO_UNDERFLOW; - priv->dispc_ops->runtime_get(); - priv->dispc_ops->clear_irqstatus(0xffffffff); - priv->dispc_ops->runtime_put(); + for (i = 0; i < priv->num_crtcs; ++i) + priv->irq_mask.channel[omap_crtc_channel(priv->crtcs[i])] |= + DSS_IRQ_MGR_SYNC_LOST; ret = priv->dispc_ops->request_irq(omap_irq_handler, dev); if (ret < 0) diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 15e5d5d..ae13b70 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -241,12 +241,12 @@ static int omap_plane_atomic_get_property(struct drm_plane *plane, .atomic_get_property = omap_plane_atomic_get_property, }; -static const char *plane_id_to_name[] = { - [OMAP_DSS_GFX] = "gfx", - [OMAP_DSS_VIDEO1] = "vid1", - [OMAP_DSS_VIDEO2] = "vid2", - [OMAP_DSS_VIDEO3] = "vid3", -}; +enum omap_plane_id omap_plane_get_id(struct drm_plane *plane) +{ + struct omap_plane *omap_plane = to_omap_plane(plane); + + return omap_plane->id; +} static const enum omap_plane_id plane_idx_to_id[] = { OMAP_DSS_GFX, @@ -274,7 +274,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, id = plane_idx_to_id[idx]; - DBG("%s: type=%d", plane_id_to_name[id], type); + DBG("%s: type=%d", priv->dispc_ops->get_ovl_name(id), type); omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); if (!omap_plane) @@ -284,7 +284,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, for (nformats = 0; formats[nformats]; ++nformats) ; omap_plane->id = id; - omap_plane->name = plane_id_to_name[id]; + omap_plane->name = priv->dispc_ops->get_ovl_name(id); plane = &omap_plane->base; @@ -303,7 +303,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, error: dev_err(dev->dev, "%s(): could not create plane: %s\n", - __func__, plane_id_to_name[id]); + __func__, priv->dispc_ops->get_ovl_name(id)); kfree(omap_plane); return NULL; -- 1.9.1 Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel