nouveau-fixes 5.6
Hey, Nothing major here, another TU1xx modesetting fix, and hooking up ACR/GR support on TU11x now that NVIDIA have made the firmware available. Thanks, Ben. The following changes since commit 137c4ba7163ad9d5696b9fde78b1c0898a9c115b: drm/nouveau/kms/gv100-: avoid sending a core update until the first modeset (2020-02-03 21:36:54 +1000) are available in the Git repository at: git://github.com/skeggsb/linux linux-5.6 for you to fetch changes up to f287d3d19769b1d22cba4e51fa0487f2697713c9: drm/nouveau/kms/gv100-: Re-set LUT after clearing for modesets (2020-02-17 17:19:00 +1000) Ben Skeggs (2): drm/nouveau/acr/tu11x: initial support drm/nouveau/gr/tu11x: initial support Lyude Paul (1): drm/nouveau/kms/gv100-: Re-set LUT after clearing for modesets drivers/gpu/drm/nouveau/dispnv50/wndw.c | 2 ++ drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 4 drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c| 26 +++ drivers/gpu/drm/nouveau/nvkm/subdev/acr/tu102.c | 14 drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c| 2 ++ ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
RE: [PATCH 3/3] drm/dp_mst: Remove single tx msg restriction.
[AMD Public Use] > -Original Message- > From: Sean Paul > Sent: Saturday, February 15, 2020 12:09 AM > To: Lin, Wayne > Cc: dri-devel@lists.freedesktop.org; ly...@redhat.com; Sean Paul > ; Maarten Lankhorst > ; Maxime Ripard ; > David Airlie > Subject: Re: [PATCH 3/3] drm/dp_mst: Remove single tx msg restriction. > > On Fri, Feb 14, 2020 at 12:58 AM Lin, Wayne wrote: > > > > [AMD Public Use] > > > > Hi Paul, > > > > Thanks for the mail! > > > > I tried to solve this problem by having restriction on sending one msg at a > time due to hub/dock compatibility problems. > > From my experience, some branch devices don't handle well on > > interleaved replies (Dock from HP I think) > > Hi Wayne, > Hmm, that's interesting, do you have a part number of the failing dock so I > can > test it? > Hi Paul, Sorry but it's been quite a while. I can't exactly tell the part number. If I remember correctly, when the specific branch device receives interleaved replies, it just doesn't reply to any requests. > > As the result of that, correct me if I'm wrong, I remember most gpu vendors > just send one down request at a time now in windows environment. > > I would suggest the original solution :) > > I can't really say what happens on the Windows side of the world, but I > suppose > that makes sense if this is a widespread issue with docks. I do worry about > the > performance hit. > > If indeed this is a problem, could we ratelimit per branch device instead of > globally? Even that would be better than serializing everything. > Since the problem was because some branch devices can't simultaneously handle two replies, I'm afraid that we might still encounter the same problem? Thanks! > Sean > > > > > Thanks! > > > -Original Message- > > > From: Sean Paul > > > Sent: Friday, February 14, 2020 5:15 AM > > > To: dri-devel@lists.freedesktop.org > > > Cc: ly...@redhat.com; Lin, Wayne ; Sean Paul > > > ; Maarten Lankhorst > > > ; Maxime Ripard > > > ; David Airlie > > > Subject: [PATCH 3/3] drm/dp_mst: Remove single tx msg restriction. > > > > > > From: Sean Paul > > > > > > Now that we can support multiple simultaneous replies, remove the > > > restrictions placed on sending new tx msgs. > > > > > > This patch essentially just reverts commit > > > 5a64967a2f3b ("drm/dp_mst: Have DP_Tx send one msg at a time") > now > > > that the problem is solved in a different way. > > > > > > Cc: Wayne Lin > > > Signed-off-by: Sean Paul > > > --- > > > drivers/gpu/drm/drm_dp_mst_topology.c | 14 ++ > > > include/drm/drm_dp_mst_helper.h | 6 -- > > > 2 files changed, 2 insertions(+), 18 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c > > > b/drivers/gpu/drm/drm_dp_mst_topology.c > > > index 7e6a82efdfc02..cbf0bb0ddeb84 100644 > > > --- a/drivers/gpu/drm/drm_dp_mst_topology.c > > > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c > > > @@ -1203,8 +1203,6 @@ static int drm_dp_mst_wait_tx_reply(struct > > > drm_dp_mst_branch *mstb, > > > txmsg->state == DRM_DP_SIDEBAND_TX_SENT) { > > > mstb->tx_slots[txmsg->seqno] = NULL; > > > } > > > - mgr->is_waiting_for_dwn_reply = false; > > > - > > > } > > > out: > > > if (unlikely(ret == -EIO) && drm_debug_enabled(DRM_UT_DP)) { > > > @@ > > > -1214,7 +1212,6 @@ static int drm_dp_mst_wait_tx_reply(struct > > > drm_dp_mst_branch *mstb, > > > } > > > mutex_unlock(>qlock); > > > > > > - drm_dp_mst_kick_tx(mgr); > > > return ret; > > > } > > > > > > @@ -2797,11 +2794,9 @@ static void > > > process_single_down_tx_qlock(struct > > > drm_dp_mst_topology_mgr *mgr) > > > ret = process_single_tx_qlock(mgr, txmsg, false); > > > if (ret == 1) { > > > /* txmsg is sent it should be in the slots now */ > > > - mgr->is_waiting_for_dwn_reply = true; > > > list_del(>next); > > > } else if (ret) { > > > DRM_DEBUG_KMS("failed to send msg in q %d\n", ret); > > > - mgr->is_waiting_for_dwn_reply = false; > > > list_del(>next); > > > if (txmsg->seqno != -1) > > > txmsg->dst->tx_slots[txmsg->seqno] = NULL; > @@ > > > -2841,8 > > > +2836,7 @@ static void drm_dp_queue_down_tx(struct > > > drm_dp_mst_topology_mgr *mgr, > > > drm_dp_mst_dump_sideband_msg_tx(, txmsg); > > > } > > > > > > - if (list_is_singular(>tx_msg_downq) && > > > - !mgr->is_waiting_for_dwn_reply) > > > + if (list_is_singular(>tx_msg_downq)) > > > process_single_down_tx_qlock(mgr); > > > mutex_unlock(>qlock); > > > } > > > @@ -3822,7 +3816,6 @@ static int drm_dp_mst_handle_down_rep(struct > > > drm_dp_mst_topology_mgr *mgr) > > > mutex_lock(>qlock); > > > txmsg->state = DRM_DP_SIDEBAND_TX_RX; > > > mstb->tx_slots[seqno] = NULL; > > > - mgr->is_waiting_for_dwn_reply =
Re: [PATCHv4,03/36] drm/gem-fb-helper: Allow drivers to allocate struct drm_framebuffer on their own
Hi Andrzej: Good work. It's a real useful patch, with it seems most vendor-specific fb_create can be simplified by these helper funcs. On Fri, Dec 13, 2019 at 04:58:34PM +0100, Andrzej Pietrasiewicz wrote: > Prepare tools for drivers which need to allocate a struct drm_framebuffer > (or a container of struct drm_framebuffer) explicitly, before calling > helpers. In such a case we need new helpers which omit allocating the > struct drm_framebuffer and this patch provides them. Consequently, they > are used also inside the helpers themselves. > > The interested drivers will likely need to be able to perform object > lookups and size checks in separate invocations and this patch provides > that as well. Helpers themselves are updated, too. > > Signed-off-by: Andrzej Pietrasiewicz > --- > drivers/gpu/drm/drm_gem_framebuffer_helper.c | 184 ++- > include/drm/drm_gem_framebuffer_helper.h | 17 ++ > 2 files changed, 153 insertions(+), 48 deletions(-) > > diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c > b/drivers/gpu/drm/drm_gem_framebuffer_helper.c > index b9bcd310ca2d..787edb9a916b 100644 > --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c > +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c > @@ -54,6 +54,44 @@ struct drm_gem_object *drm_gem_fb_get_obj(struct > drm_framebuffer *fb, > } > EXPORT_SYMBOL_GPL(drm_gem_fb_get_obj); > > +int drm_gem_fb_init_with_funcs(struct drm_framebuffer *fb, > +struct drm_device *dev, > +const struct drm_mode_fb_cmd2 *mode_cmd, > +struct drm_gem_object **obj, > +unsigned int num_planes, > +const struct drm_framebuffer_funcs *funcs) > +{ > + int ret, i; > + > + drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); > + > + for (i = 0; i < num_planes; i++) > + fb->obj[i] = obj[i]; > + > + ret = drm_framebuffer_init(dev, fb, funcs); > + if (ret) > + DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", > + ret); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs); > + > +static const struct drm_framebuffer_funcs drm_gem_fb_funcs = { > + .destroy= drm_gem_fb_destroy, > + .create_handle = drm_gem_fb_create_handle, > +}; > + > +int drm_gem_fb_init(struct drm_framebuffer *fb, > + struct drm_device *dev, > + const struct drm_mode_fb_cmd2 *mode_cmd, > + struct drm_gem_object **obj, unsigned int num_planes) > +{ > + return drm_gem_fb_init_with_funcs(fb, dev, mode_cmd, obj, num_planes, > + _gem_fb_funcs); > +} > +EXPORT_SYMBOL_GPL(drm_gem_fb_init); > + > static struct drm_framebuffer * > drm_gem_fb_alloc(struct drm_device *dev, >const struct drm_mode_fb_cmd2 *mode_cmd, > @@ -61,21 +99,15 @@ drm_gem_fb_alloc(struct drm_device *dev, >const struct drm_framebuffer_funcs *funcs) > { > struct drm_framebuffer *fb; > - int ret, i; > + int ret; > > fb = kzalloc(sizeof(*fb), GFP_KERNEL); > if (!fb) > return ERR_PTR(-ENOMEM); > > - drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); > - > - for (i = 0; i < num_planes; i++) > - fb->obj[i] = obj[i]; > - > - ret = drm_framebuffer_init(dev, fb, funcs); > + ret = drm_gem_fb_init_with_funcs(fb, dev, mode_cmd, obj, num_planes, > + funcs); > if (ret) { > - DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", > - ret); > kfree(fb); > return ERR_PTR(ret); > } > @@ -124,79 +156,135 @@ int drm_gem_fb_create_handle(struct drm_framebuffer > *fb, struct drm_file *file, > EXPORT_SYMBOL(drm_gem_fb_create_handle); > > /** > - * drm_gem_fb_create_with_funcs() - Helper function for the > - * _mode_config_funcs.fb_create > - * callback > + * drm_gem_fb_lookup() - Helper function for use in > + *_mode_config_funcs.fb_create implementations > * @dev: DRM device > * @file: DRM file that holds the GEM handle(s) backing the framebuffer > * @mode_cmd: Metadata from the userspace framebuffer creation request > - * @funcs: vtable to be used for the new framebuffer object > * > - * This function can be used to set _framebuffer_funcs for drivers that > need > - * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to > - * change _framebuffer_funcs. The function does buffer size validation. > + * This function can be used to look up the objects for all planes. > + * In case an error is returned all the objects are put by the > + * function before returning. > * > * Returns: > - * Pointer to a _framebuffer on success or an error pointer on failure. > +
Re: [PATCHv4,02/36] drm/core: Add afbc helper functions
On Fri, Dec 13, 2019 at 04:58:33PM +0100, Andrzej Pietrasiewicz wrote: > Add checking if a modifier is afbc and getting afbc block size. > > Signed-off-by: Andrzej Pietrasiewicz > --- > drivers/gpu/drm/drm_fourcc.c | 53 > include/drm/drm_fourcc.h | 4 +++ > 2 files changed, 57 insertions(+) > > diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c > index b234bfaeda06..d14dd7c86020 100644 > --- a/drivers/gpu/drm/drm_fourcc.c > +++ b/drivers/gpu/drm/drm_fourcc.c > @@ -29,6 +29,7 @@ > > #include > #include > +#include > > static char printable_char(int c) > { > @@ -393,3 +394,55 @@ uint64_t drm_format_info_min_pitch(const struct > drm_format_info *info, > drm_format_info_block_height(info, plane)); > } > EXPORT_SYMBOL(drm_format_info_min_pitch); > + > +/** > + * drm_is_afbc - test if the modifier describes an afbc buffer > + * @modifier - modifier to be tested > + * > + * Returns: true if the modifier describes an afbc buffer > + */ > +bool drm_is_afbc(u64 modifier) > +{ > + /* is it ARM AFBC? */ > + if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0) > + return false; > + > + /* Block size must be known */ > + if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0) > + return false; Do we really need this block size check here ? Since modifier with ARM AFBC modifier but have no BLOCK_SIZE which should be an error, but this check returns such error to NONE-AFBC. And i saw you already have such error check in func get_superblock_wh(), so I think we can del this size check in this func. James. > + > + return true; > +} > +EXPORT_SYMBOL_GPL(drm_is_afbc); > + > +/** > + * drm_afbc_get_superblock_wh - extract afbc block width/height from modifier > + * @modifier: the modifier to be looked at > + * @w: address of a place to store the block width > + * @h: address of a place to store the block height > + * > + * Returns: true if the modifier describes a supported block size > + */ > +bool drm_afbc_get_superblock_wh(u64 modifier, u32 *w, u32 *h) > +{ > + switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { > + case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: > + *w = 16; > + *h = 16; > + break; > + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: > + *w = 32; > + *h = 8; > + break; > + case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: > + /* fall through */ > + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: > + /* fall through */ > + default: > + DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n", > + modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK); > + return false; > + } > + return true; > +} > +EXPORT_SYMBOL_GPL(drm_afbc_get_superblock_wh); > diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h > index 306d1efeb5e0..7eb23062bf45 100644 > --- a/include/drm/drm_fourcc.h > +++ b/include/drm/drm_fourcc.h > @@ -320,4 +320,8 @@ uint64_t drm_format_info_min_pitch(const struct > drm_format_info *info, > int plane, unsigned int buffer_width); > const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf > *buf); > > +bool drm_is_afbc(u64 modifier); > + > +bool drm_afbc_get_superblock_wh(u64 modifier, u32 *w, u32 *h); > + > #endif /* __DRM_FOURCC_H__ */ ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCHv4,01/36] drm/framebuffer: Add optional modifier info
Hi Andrzej: Sorry for late due to the outbreak of coronavirus in china. Reviewed-by: James Qian Wang James. On Fri, Dec 13, 2019 at 04:58:32PM +0100, Andrzej Pietrasiewicz wrote: > modifier_info is a pointer to an optional modifier-related information. > Managing the memory needed for that information is the responsibility > of drivers. > > Signed-off-by: Andrzej Pietrasiewicz > --- > include/drm/drm_framebuffer.h | 16 > 1 file changed, 16 insertions(+) > > diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h > index c0e0256e3e98..2b3341b526d7 100644 > --- a/include/drm/drm_framebuffer.h > +++ b/include/drm/drm_framebuffer.h > @@ -29,6 +29,7 @@ > > #include > > +struct drm_afbc; > struct drm_clip_rect; > struct drm_device; > struct drm_file; > @@ -139,6 +140,21 @@ struct drm_framebuffer { >* @format: framebuffer format information >*/ > const struct drm_format_info *format; > + > + union { > + /** > + * @modifier_info: pointer to an optional modifier-related > + * information. Managing the memory holding that information > + * is driver's responsibility. > + */ > + void *modifier_info; > + > + /** > + * @afbc_info: afbc-specific pointer > + */ > + struct drm_afbc *afbc_info; > + }; > + > /** >* @funcs: framebuffer vfunc table >*/ ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 2/2] drm/mediatek: fix race condition for HDMI jack status reporting
On Mon, 2020-02-17 at 11:55 +0800, Tzung-Bi Shih wrote: > On Mon, Feb 17, 2020 at 11:44 AM CK Hu wrote: > > On Mon, 2020-02-17 at 11:16 +0800, Tzung-Bi Shih wrote: > > > Fixes: 5d3c64477392 ("drm/mediatek: support HDMI jack status reporting") > > > > This patch looks good to me, but please merge this patch with the patch > > it fix. > > 5d3c64477392 ("drm/mediatek: support HDMI jack status reporting") has > applied to ASoC for-next branch. This is a fixup patch. I thought a patch need an ack by the maintainer. OK, so I could do is, for this patch, Acked-by: CK Hu ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 2/2] drm/mediatek: fix race condition for HDMI jack status reporting
Hi, Tzhung-Bi: On Mon, 2020-02-17 at 11:16 +0800, Tzung-Bi Shih wrote: > hdmi_conn_detect and mtk_hdmi_audio_hook_plugged_cb would be called > by different threads. > > Imaging the following calling sequence: >Thread AThread B > > mtk_hdmi_audio_hook_plugged_cb() > mtk_cec_hpd_high() -> disconnected > hdmi_conn_detect() > mtk_cec_hpd_high() -> connected > plugged_cb(connected) > plugged_cb(disconnected) > > The latest disconnected is false reported. Makes mtk_cec_hpd_high > and plugged_cb atomic to fix. > > Also uses the same lock to protect read/write of plugged_cb and codec_dev. > > Fixes: 5d3c64477392 ("drm/mediatek: support HDMI jack status reporting") This patch looks good to me, but please merge this patch with the patch it fix. Regards, CK > Signed-off-by: Tzung-Bi Shih > --- > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 ++- > 1 file changed, 10 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c > b/drivers/gpu/drm/mediatek/mtk_hdmi.c > index 03aeb73005ef..d80017e3d84a 100644 > --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c > +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c > @@ -12,6 +12,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -171,6 +172,7 @@ struct mtk_hdmi { > bool enabled; > hdmi_codec_plugged_cb plugged_cb; > struct device *codec_dev; > + struct mutex update_plugged_status_lock; > }; > > static inline struct mtk_hdmi *hdmi_ctx_from_bridge(struct drm_bridge *b) > @@ -1199,10 +1201,13 @@ static void mtk_hdmi_clk_disable_audio(struct > mtk_hdmi *hdmi) > static enum drm_connector_status > mtk_hdmi_update_plugged_status(struct mtk_hdmi *hdmi) > { > - bool connected = mtk_cec_hpd_high(hdmi->cec_dev); > + bool connected; > > + mutex_lock(>update_plugged_status_lock); > + connected = mtk_cec_hpd_high(hdmi->cec_dev); > if (hdmi->plugged_cb && hdmi->codec_dev) > hdmi->plugged_cb(hdmi->codec_dev, connected); > + mutex_unlock(>update_plugged_status_lock); > > return connected ? > connector_status_connected : connector_status_disconnected; > @@ -1669,8 +1674,11 @@ static int mtk_hdmi_audio_hook_plugged_cb(struct > device *dev, void *data, > { > struct mtk_hdmi *hdmi = data; > > + mutex_lock(>update_plugged_status_lock); > hdmi->plugged_cb = fn; > hdmi->codec_dev = codec_dev; > + mutex_unlock(>update_plugged_status_lock); > + > mtk_hdmi_update_plugged_status(hdmi); > > return 0; > @@ -1729,6 +1737,7 @@ static int mtk_drm_hdmi_probe(struct platform_device > *pdev) > return ret; > } > > + mutex_init(>update_plugged_status_lock); > platform_set_drvdata(pdev, hdmi); > > ret = mtk_hdmi_output_init(hdmi); ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] drm/lima: fix recovering from PLBU out of memory
applied to drm-misc-next. On Mon, Feb 17, 2020 at 9:20 AM Qiang Yu wrote: > > Looks good for me, patch is: > Reviewed-by: Qiang Yu > > Regards, > Qiang > > On Sat, Feb 15, 2020 at 11:50 AM Vasily Khoruzhick wrote: > > > > It looks like on PLBU_OUT_OF_MEM interrupt we need to resume from where we > > stopped, i.e. new PLBU heap start is old end. Also update end address > > in GP frame to grow heap on 2nd and subsequent out of memory interrupts. > > > > Fixes: 2081e8dcf1ee ("drm/lima: recover task by enlarging heap buffer") > > Signed-off-by: Vasily Khoruzhick > > --- > > drivers/gpu/drm/lima/lima_gp.c | 7 ++- > > 1 file changed, 6 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c > > index d1e7826c2d74..325604262def 100644 > > --- a/drivers/gpu/drm/lima/lima_gp.c > > +++ b/drivers/gpu/drm/lima/lima_gp.c > > @@ -224,8 +224,13 @@ static int lima_gp_task_recover(struct lima_sched_pipe > > *pipe) > > } > > > > gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); > > + /* Resume from where we stopped, i.e. new start is old end */ > > + gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR, > > +f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); > > + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = > > + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + > > task->heap->heap_size; > > gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR, > > -f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + > > task->heap->heap_size); > > +f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); > > gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); > > return 0; > > } > > -- > > 2.25.0 > > ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v3 3/7] drm/exynos: Use drm_encoder_mask()
20. 2. 12. 오전 1:22에 Ville Syrjala 이(가) 쓴 글: > From: Ville Syrjälä > > Replace the hand rolled encoder bitmask thing with drm_encoder_mask() > > Cc: Inki Dae > Cc: Joonyoung Shim > Cc: Seung-Woo Kim > Cc: Kyungmin Park > Acked-by: Thomas Zimmermann > Signed-off-by: Ville Syrjälä Acked-by: Inki Dae THanks, Inki Dae > --- > drivers/gpu/drm/exynos/exynos_drm_drv.c | 5 ++--- > 1 file changed, 2 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c > b/drivers/gpu/drm/exynos/exynos_drm_drv.c > index ba0f868b2477..57defeb44522 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c > @@ -270,7 +270,7 @@ static int exynos_drm_bind(struct device *dev) > struct drm_encoder *encoder; > struct drm_device *drm; > unsigned int clone_mask; > - int cnt, ret; > + int ret; > > drm = drm_dev_alloc(_drm_driver, dev); > if (IS_ERR(drm)) > @@ -293,10 +293,9 @@ static int exynos_drm_bind(struct device *dev) > exynos_drm_mode_config_init(drm); > > /* setup possible_clones. */ > - cnt = 0; > clone_mask = 0; > list_for_each_entry(encoder, >mode_config.encoder_list, head) > - clone_mask |= (1 << (cnt++)); > + clone_mask |= drm_encoder_mask(encoder); > > list_for_each_entry(encoder, >mode_config.encoder_list, head) > encoder->possible_clones = clone_mask; > ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] drm/lima: fix recovering from PLBU out of memory
Looks good for me, patch is: Reviewed-by: Qiang Yu Regards, Qiang On Sat, Feb 15, 2020 at 11:50 AM Vasily Khoruzhick wrote: > > It looks like on PLBU_OUT_OF_MEM interrupt we need to resume from where we > stopped, i.e. new PLBU heap start is old end. Also update end address > in GP frame to grow heap on 2nd and subsequent out of memory interrupts. > > Fixes: 2081e8dcf1ee ("drm/lima: recover task by enlarging heap buffer") > Signed-off-by: Vasily Khoruzhick > --- > drivers/gpu/drm/lima/lima_gp.c | 7 ++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c > index d1e7826c2d74..325604262def 100644 > --- a/drivers/gpu/drm/lima/lima_gp.c > +++ b/drivers/gpu/drm/lima/lima_gp.c > @@ -224,8 +224,13 @@ static int lima_gp_task_recover(struct lima_sched_pipe > *pipe) > } > > gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); > + /* Resume from where we stopped, i.e. new start is old end */ > + gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR, > +f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); > + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = > + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size; > gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR, > -f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + > task->heap->heap_size); > +f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); > gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); > return 0; > } > -- > 2.25.0 > ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[Bug 200695] Blank screen on RX 580 with amdgpu.dc=1 enabled (no displays detected)
https://bugzilla.kernel.org/show_bug.cgi?id=200695 babgozd (babgoz...@outlook.com) changed: What|Removed |Added CC||babgoz...@outlook.com --- Comment #38 from babgozd (babgoz...@outlook.com) --- (In reply to Adam from comment #37) > As several comments mention different behavior between the different > connector types I found a spare DVI cable and tried connecting to the same > monitor via that input and it worked! So once logged in I plugged in the > HDMI cable and switched input and it worked just fine (monitor was glitchy > at first but once I disabled DVI output in monitor configuration it worked > perfectly). To confirm this was indeed working with the DC code path I > tested audio over HDMI and it worked just fine (and does not work with DC > disabled, as expected). So I rebooted with both the DVI and HDMI in and the > output over HDMI worked all through boot. I then disconnected the DVI and > rebooted and the HDMI continues to work so far. Unfortunately I don't have a > displayport monitor around to test if that behaves as weirdly. Just to be > clear, I had tried to make this monitor work for a couple weeks over HDMI > and the only thing that worked was amdgpu.dc=0 until I plugged in the DVI > connector so this was not a one off fail. > > I forgot to mention before that when the HDMI output was not working with DC > my Xorg logs also showed no monitor detected. > > I can attach the two different Xorg logs if that helps? I am following this thread since it has created. My R9 380 with DVI-I output is connected to my VGA monitor with DVI-I male to VGA female adapter and I am getting black/blank screen while booting with amdgpu.dc=1 which is default since kernel 4.17. It is fine with amdgpu.dc=0. I can provide logs too if any kernel contributor wants to investigate the problem any further. -- You are receiving this mail because: You are watching the assignee of the bug. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 41/51] drm/omap: hdmi5: Simplify EDID read
Now that the omap_dss_device EDID read operation has been removed, simplify the bridge-based EDID access by merging multiple functions together. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 86 - 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 6cb709c775d6..4d4c1fabd0a1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -307,50 +307,6 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi) mutex_unlock(>lock); } -static struct edid * -hdmi_do_read_edid(struct omap_hdmi *hdmi, - struct edid *(*read)(struct omap_hdmi *hdmi, - struct drm_connector *connector), - struct drm_connector *connector) -{ - struct edid *edid; - bool need_enable; - int idlemode; - int r; - - need_enable = hdmi->core_enabled == false; - - if (need_enable) { - r = hdmi_core_enable(hdmi); - if (r) - return NULL; - } - - mutex_lock(>lock); - r = hdmi_runtime_get(hdmi); - BUG_ON(r); - - idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); - /* No-idle mode */ - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); - - hdmi5_core_ddc_init(>core); - - edid = read(hdmi, connector); - - hdmi5_core_ddc_uninit(>core); - - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); - - hdmi_runtime_put(hdmi); - mutex_unlock(>lock); - - if (need_enable) - hdmi_core_disable(hdmi); - - return (struct edid *)edid; -} - /* - * DRM Bridge Operations */ @@ -469,18 +425,46 @@ static void hdmi5_bridge_disable(struct drm_bridge *bridge, mutex_unlock(>lock); } -static struct edid *hdmi5_bridge_read_edid(struct omap_hdmi *hdmi, - struct drm_connector *connector) -{ - return drm_do_get_edid(connector, hdmi5_core_ddc_read, >core); -} - static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct edid *edid; + bool need_enable; + int idlemode; + int r; + + need_enable = hdmi->core_enabled == false; + + if (need_enable) { + r = hdmi_core_enable(hdmi); + if (r) + return NULL; + } + + mutex_lock(>lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); - return hdmi_do_read_edid(hdmi, hdmi5_bridge_read_edid, connector); + idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); + /* No-idle mode */ + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + + hdmi5_core_ddc_init(>core); + + edid = drm_do_get_edid(connector, hdmi5_core_ddc_read, >core); + + hdmi5_core_ddc_uninit(>core); + + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); + + hdmi_runtime_put(hdmi); + mutex_unlock(>lock); + + if (need_enable) + hdmi_core_disable(hdmi); + + return (struct edid *)edid; } static const struct drm_bridge_funcs hdmi5_bridge_funcs = { -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 42/51] drm/omap: dpi: Sort includes alphabetically
This makes it easier to quickly locate duplicate includes. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dpi.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 2d0eb5fcbb5b..f8354271ce6f 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -9,20 +9,20 @@ #define DSS_SUBSYS_NAME "DPI" -#include +#include #include -#include #include #include +#include +#include +#include #include #include #include -#include -#include #include -#include "omapdss.h" #include "dss.h" +#include "omapdss.h" struct dpi_data { struct platform_device *pdev; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 38/51] drm/omap: hdmi: Remove omap_dss_device operations
Now that the HDMI outputs are driven fully through the drm_bridge API their omap_dss_device operations are not used anymore. Remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 - drivers/gpu/drm/omapdrm/dss/hdmi4.c | 18 -- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 18 -- 3 files changed, 37 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index bd43f6abf27b..3a40833d3368 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -380,7 +380,6 @@ struct omap_hdmi { bool display_enabled; }; -#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) #define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge) #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index b9bcd6e681e8..96ef7bd52199 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -309,18 +309,6 @@ void hdmi4_core_disable(struct hdmi_core_data *core) mutex_unlock(>lock); } -static int hdmi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void hdmi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - static struct edid * hdmi_do_read_edid(struct omap_hdmi *hdmi, struct edid *(*read)(struct omap_hdmi *hdmi, @@ -370,11 +358,6 @@ hdmi_do_read_edid(struct omap_hdmi *hdmi, return edid; } -static const struct omap_dss_device_ops hdmi_ops = { - .connect= hdmi_connect, - .disconnect = hdmi_disconnect, -}; - /* - * DRM Bridge Operations */ @@ -741,7 +724,6 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = _ops; out->owner = THIS_MODULE; out->of_port = 0; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index effe4a9401ff..6cb709c775d6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -307,18 +307,6 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi) mutex_unlock(>lock); } -static int hdmi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void hdmi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - static struct edid * hdmi_do_read_edid(struct omap_hdmi *hdmi, struct edid *(*read)(struct omap_hdmi *hdmi, @@ -363,11 +351,6 @@ hdmi_do_read_edid(struct omap_hdmi *hdmi, return (struct edid *)edid; } -static const struct omap_dss_device_ops hdmi_ops = { - .connect= hdmi_connect, - .disconnect = hdmi_disconnect, -}; - /* - * DRM Bridge Operations */ @@ -715,7 +698,6 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = _ops; out->owner = THIS_MODULE; out->of_port = 0; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 43/51] drm/omap: dpi: Reorder functions in sections
Group functions based on their purpose and split them in sections to make the source code easier to navigate. No functional change is included. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dpi.c | 146 -- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index f8354271ce6f..dccf81e4ce64 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -48,6 +48,10 @@ static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) return container_of(dssdev, struct dpi_data, output); } +/* - + * Clock Handling and PLL + */ + static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi, enum omap_channel channel) { @@ -366,6 +370,62 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dss_mgr_set_lcd_config(>output, >mgr_config); } +static int dpi_verify_pll(struct dss_pll *pll) +{ + int r; + + /* do initial setup with the PLL to see if it is operational */ + + r = dss_pll_enable(pll); + if (r) + return r; + + dss_pll_disable(pll); + + return 0; +} + +static void dpi_init_pll(struct dpi_data *dpi) +{ + struct dss_pll *pll; + + if (dpi->pll) + return; + + dpi->clk_src = dpi_get_clk_src(dpi); + + pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); + if (!pll) + return; + + if (dpi_verify_pll(pll)) { + DSSWARN("PLL not operational\n"); + return; + } + + dpi->pll = pll; +} + +/* - + * omap_dss_device Operations + */ + +static int dpi_connect(struct omap_dss_device *src, + struct omap_dss_device *dst) +{ + struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); + + dpi_init_pll(dpi); + + return omapdss_device_connect(dst->dss, dst, dst->next); +} + +static void dpi_disconnect(struct omap_dss_device *src, + struct omap_dss_device *dst) +{ + omapdss_device_disconnect(dst, dst->next); +} + static void dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); @@ -446,20 +506,6 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) mutex_unlock(>lock); } -static void dpi_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - - DSSDBG("dpi_set_timings\n"); - - mutex_lock(>lock); - - dpi->pixelclock = mode->clock * 1000; - - mutex_unlock(>lock); -} - static int dpi_check_timings(struct omap_dss_device *dssdev, struct drm_display_mode *mode) { @@ -500,41 +546,30 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, return 0; } -static int dpi_verify_pll(struct dss_pll *pll) +static void dpi_set_timings(struct omap_dss_device *dssdev, + const struct drm_display_mode *mode) { - int r; + struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - /* do initial setup with the PLL to see if it is operational */ + DSSDBG("dpi_set_timings\n"); - r = dss_pll_enable(pll); - if (r) - return r; + mutex_lock(>lock); - dss_pll_disable(pll); + dpi->pixelclock = mode->clock * 1000; - return 0; + mutex_unlock(>lock); } -static void dpi_init_pll(struct dpi_data *dpi) -{ - struct dss_pll *pll; - - if (dpi->pll) - return; - - dpi->clk_src = dpi_get_clk_src(dpi); - - pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); - if (!pll) - return; +static const struct omap_dss_device_ops dpi_ops = { + .connect = dpi_connect, + .disconnect = dpi_disconnect, - if (dpi_verify_pll(pll)) { - DSSWARN("PLL not operational\n"); - return; - } + .enable = dpi_display_enable, + .disable = dpi_display_disable, - dpi->pll = pll; -} + .check_timings = dpi_check_timings, + .set_timings = dpi_set_timings, +}; /* * Return a hardcoded channel for the DPI output. This should work for @@ -572,33 +607,6 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi) } } -static int dpi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); - - dpi_init_pll(dpi); - - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void
[PATCH v6 50/51] drm/omap: dss: Inline the omapdss_display_get() function
Inline the omapdss_display_get() in its only caller to simplify the code. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/display.c | 9 - drivers/gpu/drm/omapdrm/dss/omapdss.h | 1 - drivers/gpu/drm/omapdrm/omap_drv.c| 7 --- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 8a3f61f5825f..3b82158b1bfd 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -40,15 +40,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev) } EXPORT_SYMBOL_GPL(omapdss_display_init); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output) -{ - while (output->next) - output = output->next; - - return omapdss_device_get(output); -} -EXPORT_SYMBOL_GPL(omapdss_display_get); - int omapdss_display_get_modes(struct drm_connector *connector, const struct videomode *vm) { diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 64aedc50cb0b..6ecbc7273032 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -432,7 +432,6 @@ static inline bool omapdss_is_initialized(void) } void omapdss_display_init(struct omap_dss_device *dssdev); -struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output); int omapdss_display_get_modes(struct drm_connector *connector, const struct videomode *vm); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index e6a065030523..cdafd7ef1c32 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -207,11 +207,12 @@ static int omap_display_id(struct omap_dss_device *output) struct device_node *node = NULL; if (output->next) { - struct omap_dss_device *display; + struct omap_dss_device *display = output; + + while (display->next) + display = display->next; - display = omapdss_display_get(output); node = display->dev->of_node; - omapdss_device_put(display); } else if (output->bridge) { struct drm_bridge *bridge = output->bridge; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 39/51] drm/omap: venc: Remove omap_dss_device operations
Now that the VENC output is driven fully through the drm_bridge API its omap_dss_device operations are not used anymore. Remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/venc.c | 45 -- 1 file changed, 45 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index c8c19967a42f..766553bb2f87 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -306,7 +306,6 @@ struct venc_device { struct drm_bridge bridge; }; -#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) #define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge) static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val) @@ -479,30 +478,6 @@ static void venc_power_off(struct venc_device *venc) venc_runtime_put(venc); } -static int venc_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - static const struct drm_display_mode *modes[] = { - _dss_pal_mode, - _dss_ntsc_mode, - }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(modes); ++i) { - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, modes[i]); - if (!mode) - return i; - - mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_set_name(mode); - drm_mode_probed_add(connector, mode); - } - - return ARRAY_SIZE(modes); -} - static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode) { if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) @@ -598,25 +573,6 @@ static int venc_get_clocks(struct venc_device *venc) return 0; } -static int venc_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return omapdss_device_connect(dst->dss, dst, dst->next); -} - -static void venc_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - omapdss_device_disconnect(dst, dst->next); -} - -static const struct omap_dss_device_ops venc_ops = { - .connect = venc_connect, - .disconnect = venc_disconnect, - - .get_modes = venc_get_modes, -}; - /* - * DRM Bridge Operations */ @@ -816,7 +772,6 @@ static int venc_init_output(struct venc_device *venc) out->type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops = _ops; out->owner = THIS_MODULE; out->of_port = 0; out->ops_flags = OMAP_DSS_DEVICE_OP_MODES; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 32/51] drm/omap: hdmi4: Implement drm_bridge .hpd_notify() operation
The HDMI4 encoder is transitioning to the drm_bridge API, implement the last missing operation. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index a8d13a081a9a..73f1fab346e9 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -553,6 +553,15 @@ static void hdmi4_bridge_disable(struct drm_bridge *bridge, mutex_unlock(>lock); } +static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + if (status == connector_status_disconnected) + hdmi4_cec_set_phys_addr(>core, CEC_PHYS_ADDR_INVALID); +} + static struct edid *hdmi4_bridge_read_edid(struct omap_hdmi *hdmi, struct drm_connector *connector) { @@ -575,6 +584,7 @@ static const struct drm_bridge_funcs hdmi4_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_enable = hdmi4_bridge_enable, .atomic_disable = hdmi4_bridge_disable, + .hpd_notify = hdmi4_bridge_hpd_notify, .get_edid = hdmi4_bridge_get_edid, }; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 35/51] drm/omap: Create connector for bridges
Use the drm_bridge_connector helper to create a connector for pipelines that use drm_bridge. This allows splitting connector operations across multiple bridges when necessary, instead of having the last bridge in the chain creating the connector and handling all connector operations internally. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v3: - Remove outdated comment Changes since v1: - Squash with patch "drm/omap: Detach from panels at remove time" --- drivers/gpu/drm/omapdrm/omap_drv.c | 74 +- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 1df509342b5d..47afa37055b3 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -291,9 +293,14 @@ static int omap_modeset_init(struct drm_device *dev) if (pipe->output->bridge) { ret = drm_bridge_attach(pipe->encoder, - pipe->output->bridge, NULL, 0); - if (ret < 0) + pipe->output->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) { + dev_err(priv->dev, + "unable to attach bridge %pOF\n", + pipe->output->bridge->of_node); return ret; + } } id = omap_display_id(pipe->output); @@ -329,8 +336,23 @@ static int omap_modeset_init(struct drm_device *dev) encoder); if (!pipe->connector) return -ENOMEM; + } else { + pipe->connector = drm_bridge_connector_init(dev, encoder); + if (IS_ERR(pipe->connector)) { + dev_err(priv->dev, + "unable to create bridge connector for %s\n", + pipe->output->name); + return PTR_ERR(pipe->connector); + } + } - drm_connector_attach_encoder(pipe->connector, encoder); + drm_connector_attach_encoder(pipe->connector, encoder); + + if (pipe->output->panel) { + ret = drm_panel_attach(pipe->output->panel, + pipe->connector); + if (ret < 0) + return ret; } crtc = omap_crtc_init(dev, pipe, priv->planes[i]); @@ -369,6 +391,23 @@ static int omap_modeset_init(struct drm_device *dev) return 0; } +static void omap_modeset_fini(struct drm_device *ddev) +{ + struct omap_drm_private *priv = ddev->dev_private; + unsigned int i; + + omap_drm_irq_uninstall(ddev); + + for (i = 0; i < priv->num_pipes; i++) { + struct omap_drm_pipeline *pipe = >pipes[i]; + + if (pipe->output->panel) + drm_panel_detach(pipe->output->panel); + } + + drm_mode_config_cleanup(ddev); +} + /* * Enable the HPD in external components if supported */ @@ -378,8 +417,15 @@ static void omap_modeset_enable_external_hpd(struct drm_device *ddev) unsigned int i; for (i = 0; i < priv->num_pipes; i++) { - if (priv->pipes[i].connector) - omap_connector_enable_hpd(priv->pipes[i].connector); + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->next) + omap_connector_enable_hpd(connector); + else + drm_bridge_connector_enable_hpd(connector); } } @@ -392,8 +438,15 @@ static void omap_modeset_disable_external_hpd(struct drm_device *ddev) unsigned int i; for (i = 0; i < priv->num_pipes; i++) { - if (priv->pipes[i].connector) - omap_connector_disable_hpd(priv->pipes[i].connector); + struct drm_connector *connector = priv->pipes[i].connector; + + if (!connector) + continue; + + if (priv->pipes[i].output->next) + omap_connector_disable_hpd(connector); + else + drm_bridge_connector_disable_hpd(connector); } } @@ -616,8 +669,7 @@ static int omapdrm_init(struct
[PATCH v6 21/51] drm/omap: Use the drm_panel_bridge API
Replace the manual panel handling code by a drm_panel_bridge. This simplifies the driver and allows all components in the display pipeline to be treated as bridges, paving the way to generic connector handling. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v1: - Keep #include --- drivers/gpu/drm/omapdrm/dss/base.c | 12 - drivers/gpu/drm/omapdrm/dss/output.c | 31 +--- drivers/gpu/drm/omapdrm/omap_connector.c | 10 drivers/gpu/drm/omapdrm/omap_drv.c | 13 -- drivers/gpu/drm/omapdrm/omap_encoder.c | 13 -- 5 files changed, 32 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index cae5687822e2..80d48936d177 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -149,8 +149,7 @@ struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) goto done; } - if (dssdev->id && - (dssdev->next || dssdev->bridge || dssdev->panel)) + if (dssdev->id && (dssdev->next || dssdev->bridge)) goto done; } @@ -185,11 +184,10 @@ int omapdss_device_connect(struct dss_device *dss, if (!dst) { /* * The destination is NULL when the source is connected to a -* bridge or panel instead of a DSS device. Stop here, we will -* attach the bridge or panel later when we will have a DRM -* encoder. +* bridge instead of a DSS device. Stop here, we will attach +* the bridge later when we will have a DRM encoder. */ - return src && (src->bridge || src->panel) ? 0 : -EINVAL; + return src && src->bridge ? 0 : -EINVAL; } if (omapdss_device_is_connected(dst)) @@ -217,7 +215,7 @@ void omapdss_device_disconnect(struct omap_dss_device *src, dst ? dev_name(dst->dev) : "NULL"); if (!dst) { - WARN_ON(!src->bridge && !src->panel); + WARN_ON(!src->bridge); return; } diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 0693d34fca1b..99a253a424c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -21,6 +21,7 @@ int omapdss_device_init_output(struct omap_dss_device *out) { struct device_node *remote_node; + int ret; remote_node = of_graph_get_remote_node(out->dev->of_node, ffs(out->of_ports) - 1, 0); @@ -39,17 +40,39 @@ int omapdss_device_init_output(struct omap_dss_device *out) if (out->next && out->type != out->next->type) { dev_err(out->dev, "output type and display type don't match\n"); - omapdss_device_put(out->next); - out->next = NULL; - return -EINVAL; + ret = -EINVAL; + goto error; } - return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; + if (out->panel) { + struct drm_bridge *bridge; + + bridge = drm_panel_bridge_add(out->panel); + if (IS_ERR(bridge)) { + dev_err(out->dev, + "unable to create panel bridge (%ld)\n", + PTR_ERR(bridge)); + ret = PTR_ERR(bridge); + goto error; + } + + out->bridge = bridge; + } + + return out->next || out->bridge ? 0 : -EPROBE_DEFER; + +error: + omapdss_device_put(out->next); + out->next = NULL; + return ret; } EXPORT_SYMBOL(omapdss_device_init_output); void omapdss_device_cleanup_output(struct omap_dss_device *out) { + if (out->bridge && out->panel) + drm_panel_bridge_remove(out->bridge); + if (out->next) omapdss_device_put(out->next); } diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 38c7a79c5d4a..b0cb2ecb30ab 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -6,7 +6,6 @@ #include #include -#include #include #include "omap_drv.h" @@ -190,7 +189,6 @@ static int omap_connector_get_modes_edid(struct drm_connector *connector, static int omap_connector_get_modes(struct drm_connector *connector) { - struct omap_connector *omap_connector = to_omap_connector(connector); struct omap_dss_device *dssdev; DBG("%s", connector->name); @@ -213,14 +211,6 @@ static int omap_connector_get_modes(struct drm_connector *connector) if (dssdev) return dssdev->ops->get_modes(dssdev, connector); -
[PATCH v6 29/51] drm/omap: hdmi5: Register a drm_bridge for EDID read
In order to integrate with a chain of drm_bridge, the internal HDMI5 encoder has to expose the EDID read operation through the drm_bridge API. Register a bridge at initialisation time to do so. For the time being make the next bridge in the chain optional as the HDMI output is still based on omap_dss_device. The create_connector argument to the bridge attach function is also ignored for the same reason. This will be changed later when removing the related omapdrm-specific display drivers. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v2: - Unregister bridge if output initialisation fails --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 79 ++--- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 2b02b0a11696..e7fe2a24a3e1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -388,8 +388,10 @@ static void hdmi_disconnect(struct omap_dss_device *src, #define MAX_EDID 512 -static struct edid *hdmi_read_edid_data(struct hdmi_core_data *core) +static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi, + struct drm_connector *connector) { + struct hdmi_core_data *core = >core; int max_ext_blocks = 3; int r, n, i; u8 *edid; @@ -421,9 +423,12 @@ static struct edid *hdmi_read_edid_data(struct hdmi_core_data *core) return NULL; } -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +static struct edid * +hdmi_do_read_edid(struct omap_hdmi *hdmi, + struct edid *(*read)(struct omap_hdmi *hdmi, + struct drm_connector *connector), + struct drm_connector *connector) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); struct edid *edid; bool need_enable; int idlemode; @@ -447,7 +452,7 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) hdmi5_core_ddc_init(>core); - edid = hdmi_read_edid_data(>core); + edid = read(hdmi, connector); hdmi5_core_ddc_uninit(>core); @@ -462,6 +467,12 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) return (struct edid *)edid; } +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +{ + return hdmi_do_read_edid(dssdev_to_hdmi(dssdev), hdmi_read_edid_data, +NULL); +} + static int hdmi_set_infoframe(struct omap_dss_device *dssdev, const struct hdmi_avi_infoframe *avi) { @@ -497,6 +508,56 @@ static const struct omap_dss_device_ops hdmi_ops = { }, }; +/* - + * DRM Bridge Operations + */ + +static int hdmi5_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + if (!hdmi->output.next_bridge) + return 0; + + return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, +bridge, flags); +} + +static struct edid *hdmi5_bridge_read_edid(struct omap_hdmi *hdmi, + struct drm_connector *connector) +{ + return drm_do_get_edid(connector, hdmi5_core_ddc_read, >core); +} + +static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + return hdmi_do_read_edid(hdmi, hdmi5_bridge_read_edid, connector); +} + +static const struct drm_bridge_funcs hdmi5_bridge_funcs = { + .attach = hdmi5_bridge_attach, + .get_edid = hdmi5_bridge_get_edid, +}; + +static void hdmi5_bridge_init(struct omap_hdmi *hdmi) +{ + hdmi->bridge.funcs = _bridge_funcs; + hdmi->bridge.of_node = hdmi->pdev->dev.of_node; + hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + + drm_bridge_add(>bridge); +} + +static void hdmi5_bridge_cleanup(struct omap_hdmi *hdmi) +{ + drm_bridge_remove(>bridge); +} + /* - * Audio Callbacks */ @@ -679,6 +740,8 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) struct omap_dss_device *out = >output; int r; + hdmi5_bridge_init(hdmi); + out->dev = >pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI; @@ -689,9 +752,11 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->of_port = 0; out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - r = omapdss_device_init_output(out, NULL); - if (r < 0) + r = omapdss_device_init_output(out,
[PATCH v6 19/51] drm/omap: Simplify HDMI mode and infoframe configuration
Remove the omap_connector_get_hdmi_mode() function as the HDMI mode can be accessed directly from the connector's display info. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg --- drivers/gpu/drm/omapdrm/omap_connector.c | 11 --- drivers/gpu/drm/omapdrm/omap_connector.h | 1 - drivers/gpu/drm/omapdrm/omap_encoder.c | 4 +--- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 94cded387174..88dbf3fa473f 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -21,7 +21,6 @@ struct omap_connector { struct drm_connector base; struct omap_dss_device *output; struct omap_dss_device *hpd; - bool hdmi_mode; }; static void omap_connector_hpd_notify(struct drm_connector *connector, @@ -84,13 +83,6 @@ void omap_connector_disable_hpd(struct drm_connector *connector) hpd->ops->unregister_hpd_cb(hpd); } -bool omap_connector_get_hdmi_mode(struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - - return omap_connector->hdmi_mode; -} - static struct omap_dss_device * omap_connector_find_device(struct drm_connector *connector, enum omap_dss_device_ops_flag op) @@ -167,7 +159,6 @@ static void omap_connector_destroy(struct drm_connector *connector) static int omap_connector_get_modes_edid(struct drm_connector *connector, struct omap_dss_device *dssdev) { - struct omap_connector *omap_connector = to_omap_connector(connector); enum drm_connector_status status; void *edid; int n; @@ -189,8 +180,6 @@ static int omap_connector_get_modes_edid(struct drm_connector *connector, drm_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); - omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid); - kfree(edid); return n; diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h index 13607bda33d8..4aa5608f4bbe 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.h +++ b/drivers/gpu/drm/omapdrm/omap_connector.h @@ -21,7 +21,6 @@ struct omap_dss_device; struct drm_connector *omap_connector_init(struct drm_device *dev, struct omap_dss_device *output, struct drm_encoder *encoder); -bool omap_connector_get_hdmi_mode(struct drm_connector *connector); void omap_connector_enable_hpd(struct drm_connector *connector); void omap_connector_disable_hpd(struct drm_connector *connector); enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 4f2165a37795..cb5aa01d2f87 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -76,9 +76,7 @@ static void omap_encoder_hdmi_mode_set(struct drm_connector *connector, { struct omap_encoder *omap_encoder = to_omap_encoder(encoder); struct omap_dss_device *dssdev = omap_encoder->output; - bool hdmi_mode; - - hdmi_mode = omap_connector_get_hdmi_mode(connector); + bool hdmi_mode = connector->display_info.is_hdmi; if (dssdev->ops->hdmi.set_hdmi_mode) dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 47/51] drm/omap: sdi: Register a drm_bridge
In order to integrate with a chain of drm_bridge, the internal SDI output has to expose its operations through the drm_bridge API. Register a bridge at initialisation time to do so and remove the omap_dss_device operations that are now unused. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v5: - Rebased on top of drm_bridge_state Changes since v3: - Split dss/base.h and omap_connector.c cleanups to a separate patch Changes since v2: - Remove unused omapdss_device_connector_type() function - Unregister bridge if port initialisation fails --- drivers/gpu/drm/omapdrm/dss/sdi.c | 168 +++--- 1 file changed, 109 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 7dedfcc86922..417a8740ad0a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -15,6 +15,8 @@ #include #include +#include + #include "dss.h" #include "omapdss.h" @@ -30,9 +32,11 @@ struct sdi_device { int datapairs; struct omap_dss_device output; + struct drm_bridge bridge; }; -#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output) +#define drm_bridge_to_sdi(bridge) \ + container_of(bridge, struct sdi_device, bridge) struct sdi_clk_calc_ctx { struct sdi_device *sdi; @@ -118,9 +122,82 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi) dss_mgr_set_lcd_config(>output, >mgr_config); } -static void sdi_display_enable(struct omap_dss_device *dssdev) +/* - + * DRM Bridge Operations + */ + +static int sdi_bridge_attach(struct drm_bridge *bridge, +enum drm_bridge_attach_flags flags) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge, +bridge, flags); +} + +static enum drm_mode_status +sdi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + unsigned long pixelclock = mode->clock * 1000; + struct dispc_clock_info dispc_cinfo; + unsigned long fck; + int ret; + + if (pixelclock == 0) + return MODE_NOCLOCK; + + ret = sdi_calc_clock_div(sdi, pixelclock, , _cinfo); + if (ret < 0) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + unsigned long pixelclock = mode->clock * 1000; + struct dispc_clock_info dispc_cinfo; + unsigned long fck; + unsigned long pck; + int ret; + + ret = sdi_calc_clock_div(sdi, pixelclock, , _cinfo); + if (ret < 0) + return false; + + pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; + + if (pck != pixelclock) + dev_dbg(>pdev->dev, + "pixel clock adjusted from %lu Hz to %lu Hz\n", + pixelclock, pck); + + adjusted_mode->clock = pck / 1000; + + return true; +} + +static void sdi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); + + sdi->pixelclock = adjusted_mode->clock * 1000; +} + +static void sdi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); struct dispc_clock_info dispc_cinfo; unsigned long fck; int r; @@ -181,9 +258,10 @@ static void sdi_display_enable(struct omap_dss_device *dssdev) regulator_disable(sdi->vdds_sdi_reg); } -static void sdi_display_disable(struct omap_dss_device *dssdev) +static void sdi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) { - struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); dss_mgr_disable(>output); @@ -194,71 +272,40 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) regulator_disable(sdi->vdds_sdi_reg); } -static void sdi_set_timings(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode) -{ - struct
[PATCH v6 13/51] drm/bridge: Add driver for the TI TPD12S015 HDMI level shifter
The TI TPD12S015 is an HDMI level shifter and ESD protector controlled through GPIOs. Add a DRM bridge driver for the device. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg --- Changes since v2: - Control CT_CP_HPD GPIO from .hpd_enable() and .hpd_disable() - Remove unneeded hpd_gpio zero check - Update copyright notice Changes since v1: - Remove empty .hpd_enable() and .hpd_disable() operations --- drivers/gpu/drm/bridge/Kconfig| 8 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/ti-tpd12s015.c | 211 ++ 3 files changed, 220 insertions(+) create mode 100644 drivers/gpu/drm/bridge/ti-tpd12s015.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index d63283661850..aaed2347ace9 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -172,6 +172,14 @@ config DRM_TI_SN65DSI86 help Texas Instruments SN65DSI86 DSI to eDP Bridge driver +config DRM_TI_TPD12S015 + tristate "TI TPD12S015 HDMI level shifter and ESD protection" + depends on OF + select DRM_KMS_HELPER + help + Texas Instruments TPD12S015 HDMI level shifter and ESD protection + driver. + source "drivers/gpu/drm/bridge/analogix/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 17f1f155e803..6fb062b5b0f0 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o +obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o obj-y += analogix/ obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c new file mode 100644 index ..514cbf0eac75 --- /dev/null +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TPD12S015 HDMI ESD protection & level shifter chip driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific encoder-opa362 driver + * + * Copyright (C) 2013 Texas Instruments Incorporated + * Author: Tomi Valkeinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct tpd12s015_device { + struct drm_bridge bridge; + + struct gpio_desc *ct_cp_hpd_gpio; + struct gpio_desc *ls_oe_gpio; + struct gpio_desc *hpd_gpio; + int hpd_irq; + + struct drm_bridge *next_bridge; +}; + +static inline struct tpd12s015_device *to_tpd12s015(struct drm_bridge *bridge) +{ + return container_of(bridge, struct tpd12s015_device, bridge); +} + +static int tpd12s015_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct tpd12s015_device *tpd = to_tpd12s015(bridge); + int ret; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + ret = drm_bridge_attach(bridge->encoder, tpd->next_bridge, + bridge, flags); + if (ret < 0) + return ret; + + gpiod_set_value_cansleep(tpd->ls_oe_gpio, 1); + + /* DC-DC converter needs at max 300us to get to 90% of 5V. */ + usleep_range(300, 1000); + + return 0; +} + +static void tpd12s015_detach(struct drm_bridge *bridge) +{ + struct tpd12s015_device *tpd = to_tpd12s015(bridge); + + gpiod_set_value_cansleep(tpd->ls_oe_gpio, 0); +} + +static enum drm_connector_status tpd12s015_detect(struct drm_bridge *bridge) +{ + struct tpd12s015_device *tpd = to_tpd12s015(bridge); + + if (gpiod_get_value_cansleep(tpd->hpd_gpio)) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static void tpd12s015_hpd_enable(struct drm_bridge *bridge) +{ + struct tpd12s015_device *tpd = to_tpd12s015(bridge); + + gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 1); +} + +static void tpd12s015_hpd_disable(struct drm_bridge *bridge) +{ + struct tpd12s015_device *tpd = to_tpd12s015(bridge); + + gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 0); +} + +static const struct drm_bridge_funcs tpd12s015_bridge_funcs = { + .attach = tpd12s015_attach, + .detach = tpd12s015_detach, + .detect = tpd12s015_detect, + .hpd_enable = tpd12s015_hpd_enable, + .hpd_disable= tpd12s015_hpd_disable, +}; + +static irqreturn_t tpd12s015_hpd_isr(int irq, void *data) +{ + struct tpd12s015_device *tpd = data; + struct drm_bridge *bridge = >bridge; + + drm_bridge_hpd_notify(bridge, tpd12s015_detect(bridge));
[PATCH v6 46/51] drm/omap: sdi: Sort includes alphabetically
This makes it easier to quickly locate duplicate includes. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/sdi.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 11aa2f712ff4..7dedfcc86922 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -6,17 +6,17 @@ #define DSS_SUBSYS_NAME "SDI" -#include #include #include -#include #include +#include +#include #include +#include #include -#include -#include "omapdss.h" #include "dss.h" +#include "omapdss.h" struct sdi_device { struct platform_device *pdev; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 44/51] drm/omap: dpi: Simplify clock setting API
The dpi_set_pll_clk() and dpi_set_dispc_clk() return various information through pointer arguments that are never used by the callers. Remove them to simplify the clock setting API. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dpi.c | 32 --- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index dccf81e4ce64..c167bd1116ec 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -287,9 +287,7 @@ static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck, -static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, - unsigned long pck_req, unsigned long *fck, int *lck_div, - int *pck_div) +static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req) { struct dpi_clk_calc_ctx ctx; int r; @@ -303,19 +301,15 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, if (r) return r; - dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src); + dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel, + dpi->clk_src); dpi->mgr_config.clock_info = ctx.dispc_cinfo; - *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; - return 0; } -static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req) { struct dpi_clk_calc_ctx ctx; int r; @@ -331,29 +325,19 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, dpi->mgr_config.clock_info = ctx.dispc_cinfo; - *fck = ctx.fck; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; - return 0; } static int dpi_set_mode(struct dpi_data *dpi) { - int lck_div = 0, pck_div = 0; - unsigned long fck = 0; - int r = 0; + int r; if (dpi->pll) - r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, - dpi->pixelclock, , _div, _div); + r = dpi_set_pll_clk(dpi, dpi->pixelclock); else - r = dpi_set_dispc_clk(dpi, dpi->pixelclock, , - _div, _div); - if (r) - return r; + r = dpi_set_dispc_clk(dpi, dpi->pixelclock); - return 0; + return r; } static void dpi_config_lcd_manager(struct dpi_data *dpi) -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 25/51] drm/omap: hdmi: Allocate EDID in the .read_edid() operation
Bring the omapdss-specific .read_edid() operation in sync with the drm_bridge .get_edid() operation to ease code reuse. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v1: - Keep MAX_EDID macro --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 36 drivers/gpu/drm/omapdrm/dss/hdmi5.c | 24 drivers/gpu/drm/omapdrm/dss/omapdss.h| 2 +- drivers/gpu/drm/omapdrm/omap_connector.c | 12 ++-- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index dd4a14fe7e59..e15fa3862922 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -405,31 +405,45 @@ static void hdmi_disconnect(struct omap_dss_device *src, omapdss_device_disconnect(dst, dst->next); } -static int hdmi_read_edid(struct omap_dss_device *dssdev, - u8 *edid, int len) +#define MAX_EDID 512 + +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; + u8 *edid; int r; + edid = kzalloc(MAX_EDID, GFP_KERNEL); + if (!edid) + return NULL; + need_enable = hdmi->core_enabled == false; if (need_enable) { r = hdmi4_core_enable(>core); - if (r) - return r; + if (r) { + kfree(edid); + return NULL; + } + } + + r = read_edid(hdmi, edid, MAX_EDID); + if (r < 0) { + kfree(edid); + edid = NULL; + } else { + unsigned int cec_addr; + + cec_addr = r >= 256 ? cec_get_edid_phys_addr(edid, r, NULL) +: CEC_PHYS_ADDR_INVALID; + hdmi4_cec_set_phys_addr(>core, cec_addr); } - r = read_edid(hdmi, edid, len); - if (r >= 256) - hdmi4_cec_set_phys_addr(>core, - cec_get_edid_phys_addr(edid, r, NULL)); - else - hdmi4_cec_set_phys_addr(>core, CEC_PHYS_ADDR_INVALID); if (need_enable) hdmi4_core_disable(>core); - return r; + return (struct edid *)edid; } static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 8e3790dd8b98..99720dfc5769 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -410,27 +410,39 @@ static void hdmi_disconnect(struct omap_dss_device *src, omapdss_device_disconnect(dst, dst->next); } -static int hdmi_read_edid(struct omap_dss_device *dssdev, - u8 *edid, int len) +#define MAX_EDID 512 + +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; + u8 *edid; int r; + edid = kzalloc(MAX_EDID, GFP_KERNEL); + if (!edid) + return NULL; + need_enable = hdmi->core_enabled == false; if (need_enable) { r = hdmi_core_enable(hdmi); - if (r) - return r; + if (r) { + kfree(edid); + return NULL; + } } - r = read_edid(hdmi, edid, len); + r = read_edid(hdmi, edid, MAX_EDID); + if (r < 0) { + kfree(edid); + edid = NULL; + } if (need_enable) hdmi_core_disable(hdmi); - return r; + return (struct edid *)edid; } static int hdmi_set_infoframe(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 82e9bfa5530a..269e143d57be 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -367,7 +367,7 @@ struct omap_dss_device_ops { void *cb_data); void (*unregister_hpd_cb)(struct omap_dss_device *dssdev); - int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); + struct edid *(*read_edid)(struct omap_dss_device *dssdev); int (*get_modes)(struct omap_dss_device *dssdev, struct drm_connector *connector); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index a24cec4b0bb9..c636ae228130 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -153,25 +153,19 @@ static void omap_connector_destroy(struct drm_connector *connector) kfree(omap_connector); } -#define MAX_EDID 512 - static int omap_connector_get_modes_edid(struct drm_connector *connector,
[PATCH v6 16/51] drm/bridge: tfp410: Allow operation without drm_connector
The tfp410 driver can operate as part of a pipeline where the drm_connector is created by the display controller. Enable this mode of operation by skipping creation of a drm_connector internally. Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg --- drivers/gpu/drm/bridge/ti-tfp410.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 2b8741ebc696..40c4d4a5517b 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -124,10 +124,8 @@ static int tfp410_attach(struct drm_bridge *bridge, if (ret < 0) return ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; if (!bridge->encoder) { dev_err(dvi->dev, "Missing encoder\n"); -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 51/51] drm/omap: dss: Remove unused omapdss_of_find_connected_device() function
The omapdss_of_find_connected_device() function isn't used anymore, remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/Makefile | 2 +- drivers/gpu/drm/omapdrm/dss/dss-of.c | 28 --- drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 --- 3 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 drivers/gpu/drm/omapdrm/dss/dss-of.c diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile index 5950c3f52c2e..f967e6948f2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/Makefile +++ b/drivers/gpu/drm/omapdrm/dss/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o obj-$(CONFIG_OMAP_DSS_BASE) += omapdss-base.o -omapdss-base-y := base.o display.o dss-of.o output.o +omapdss-base-y := base.o display.o output.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c deleted file mode 100644 index b7981f3b80ad.. --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen - */ - -#include -#include -#include - -#include "omapdss.h" - -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port) -{ - struct device_node *remote_node; - struct omap_dss_device *dssdev; - - remote_node = of_graph_get_remote_node(node, port, 0); - if (!remote_node) - return NULL; - - dssdev = omapdss_find_device_by_node(remote_node); - of_node_put(remote_node); - - return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER); -} -EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 6ecbc7273032..ab19d4af8de7 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -471,9 +471,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; } -struct omap_dss_device * -omapdss_of_find_connected_device(struct device_node *node, unsigned int port); - enum dss_writeback_channel { DSS_WB_LCD1_MGR = 0, DSS_WB_LCD2_MGR = 1, -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 18/51] drm/omap: dss: Cleanup DSS ports on initialisation failure
When the DSS initialises its output DPI and SDI ports, failures don't clean up previous successfully initialised ports. This can lead to resource leak or memory corruption. Fix it. Reported-by: Hans Verkuil Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg --- drivers/gpu/drm/omapdrm/dss/dss.c | 43 +++ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 225ec808b01a..67b92b5d8dd7 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1151,46 +1151,38 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src= true, }; -static int dss_init_ports(struct dss_device *dss) +static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; unsigned int i; - int r; - for (i = 0; i < dss->feat->num_ports; i++) { + for (i = 0; i < num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - r = dpi_init_port(dss, pdev, port, dss->feat->model); - if (r) - return r; + dpi_uninit_port(port); break; - case OMAP_DISPLAY_TYPE_SDI: - r = sdi_init_port(dss, pdev, port); - if (r) - return r; + sdi_uninit_port(port); break; - default: break; } } - - return 0; } -static void dss_uninit_ports(struct dss_device *dss) +static int dss_init_ports(struct dss_device *dss) { struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; - int i; + unsigned int i; + int r; for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); @@ -1199,15 +1191,32 @@ static void dss_uninit_ports(struct dss_device *dss) switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_uninit_port(port); + r = dpi_init_port(dss, pdev, port, dss->feat->model); + if (r) + goto error; break; + case OMAP_DISPLAY_TYPE_SDI: - sdi_uninit_port(port); + r = sdi_init_port(dss, pdev, port); + if (r) + goto error; break; + default: break; } } + + return 0; + +error: + __dss_uninit_ports(dss, i); + return r; +} + +static void dss_uninit_ports(struct dss_device *dss) +{ + __dss_uninit_ports(dss, dss->feat->num_ports); } static int dss_video_pll_probe(struct dss_device *dss) -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 37/51] drm/omap: Remove HPD, detect and EDID omapdss operations
Due to the removal of several omapdrm display drivers, the omapdss HPD, detected and EDID operations are not used anymore. Remove them and all related code. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 61 drivers/gpu/drm/omapdrm/dss/hdmi5.c | 46 -- drivers/gpu/drm/omapdrm/dss/omapdss.h| 25 +-- drivers/gpu/drm/omapdrm/omap_connector.c | 190 +++ drivers/gpu/drm/omapdrm/omap_connector.h | 2 - drivers/gpu/drm/omapdrm/omap_drv.c | 8 +- 6 files changed, 22 insertions(+), 310 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 52daae36935a..b9bcd6e681e8 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -321,47 +321,6 @@ static void hdmi_disconnect(struct omap_dss_device *src, omapdss_device_disconnect(dst, dst->next); } -#define MAX_EDID 512 - -static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi, - struct drm_connector *connector) -{ - u8 *edid; - int r; - - edid = kzalloc(MAX_EDID, GFP_KERNEL); - if (!edid) - return NULL; - - r = hdmi4_core_ddc_read(>core, edid, 0, EDID_LENGTH); - if (r) - goto error; - - if (edid[0x7e] > 0) { - char checksum = 0; - unsigned int i; - - r = hdmi4_core_ddc_read(>core, edid + EDID_LENGTH, 1, - EDID_LENGTH); - if (r) - goto error; - - for (i = 0; i < EDID_LENGTH; ++i) - checksum += edid[EDID_LENGTH + i]; - - if (checksum != 0) { - DSSERR("E-EDID checksum failed!!\n"); - goto error; - } - } - - return (struct edid *)edid; - -error: - kfree(edid); - return NULL; -} - static struct edid * hdmi_do_read_edid(struct omap_hdmi *hdmi, struct edid *(*read)(struct omap_hdmi *hdmi, @@ -411,28 +370,9 @@ hdmi_do_read_edid(struct omap_hdmi *hdmi, return edid; } -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) -{ - return hdmi_do_read_edid(dssdev_to_hdmi(dssdev), hdmi_read_edid_data, -NULL); -} - -static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi4_cec_set_phys_addr(>core, CEC_PHYS_ADDR_INVALID); -} - static const struct omap_dss_device_ops hdmi_ops = { .connect= hdmi_connect, .disconnect = hdmi_disconnect, - - .read_edid = hdmi_read_edid, - - .hdmi = { - .lost_hotplug = hdmi_lost_hotplug, - }, }; /* - @@ -804,7 +744,6 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->ops = _ops; out->owner = THIS_MODULE; out->of_port = 0; - out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; r = omapdss_device_init_output(out, >bridge); if (r < 0) { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index f07fd5c6dc39..effe4a9401ff 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -319,43 +319,6 @@ static void hdmi_disconnect(struct omap_dss_device *src, omapdss_device_disconnect(dst, dst->next); } -#define MAX_EDID 512 - -static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi, - struct drm_connector *connector) -{ - struct hdmi_core_data *core = >core; - int max_ext_blocks = 3; - int r, n, i; - u8 *edid; - - edid = kzalloc(MAX_EDID, GFP_KERNEL); - if (!edid) - return NULL; - - r = hdmi5_core_ddc_read(core, edid, 0, EDID_LENGTH); - if (r) - goto error; - - n = edid[0x7e]; - - if (n > max_ext_blocks) - n = max_ext_blocks; - - for (i = 1; i <= n; i++) { - r = hdmi5_core_ddc_read(core, edid + i * EDID_LENGTH, i, - EDID_LENGTH); - if (r) - goto error; - } - - return (struct edid *)edid; - -error: - kfree(edid); - return NULL; -} - static struct edid * hdmi_do_read_edid(struct omap_hdmi *hdmi, struct edid *(*read)(struct omap_hdmi *hdmi, @@ -400,17 +363,9 @@ hdmi_do_read_edid(struct omap_hdmi *hdmi, return (struct edid *)edid; } -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) -{ - return hdmi_do_read_edid(dssdev_to_hdmi(dssdev), hdmi_read_edid_data, -NULL); -} - static const
[PATCH v6 26/51] drm/omap: hdmi4: Rework EDID read to isolate data read
In preparation of adding DRM bridge support to the hdmi4 encoder code, rework the EDID read to isolate data read. The hdmi_read_edid() function is the main entry point. It performs all initialisation steps required prior to reading the EDID (such as ensuring the device is powered on), as well as corresponding cleanup steps afterwards. EDID read itself is handled by hdmi_read_edid_data() that calls the hdmi4_core_ddc_read() function to read individual blocks. This new code architecture will allow reusing hdmi_read_edid() and hdmi4_core_ddc_read() for the drm_bridge EDID read implementation, while swapping out hdmi_read_edid_data() for the DRM drm_do_get_edid() function. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v2: - Expand commit message --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 94 +++- drivers/gpu/drm/omapdrm/dss/hdmi4_core.c | 59 +++ drivers/gpu/drm/omapdrm/dss/hdmi4_core.h | 4 +- 3 files changed, 73 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index e15fa3862922..37536b9f3114 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -272,23 +272,6 @@ static int hdmi_dump_regs(struct seq_file *s, void *p) return 0; } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) -{ - int r; - - mutex_lock(>lock); - - r = hdmi_runtime_get(hdmi); - BUG_ON(r); - - r = hdmi4_read_edid(>core, buf, len); - - hdmi_runtime_put(hdmi); - mutex_unlock(>lock); - - return r; -} - static void hdmi_start_audio_stream(struct omap_hdmi *hd) { hdmi_wp_audio_enable(>wp, true); @@ -407,10 +390,8 @@ static void hdmi_disconnect(struct omap_dss_device *src, #define MAX_EDID 512 -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - bool need_enable; u8 *edid; int r; @@ -418,32 +399,79 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) if (!edid) return NULL; + r = hdmi4_core_ddc_read(>core, edid, 0, EDID_LENGTH); + if (r) + goto error; + + if (edid[0x7e] > 0) { + char checksum = 0; + unsigned int i; + + r = hdmi4_core_ddc_read(>core, edid + EDID_LENGTH, 1, + EDID_LENGTH); + if (r) + goto error; + + for (i = 0; i < EDID_LENGTH; ++i) + checksum += edid[EDID_LENGTH + i]; + + if (checksum != 0) { + DSSERR("E-EDID checksum failed!!\n"); + goto error; + } + } + + return (struct edid *)edid; + +error: + kfree(edid); + return NULL; +} + +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +{ + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct edid *edid = NULL; + unsigned int cec_addr; + bool need_enable; + int r; + need_enable = hdmi->core_enabled == false; if (need_enable) { r = hdmi4_core_enable(>core); - if (r) { - kfree(edid); + if (r) return NULL; - } } - r = read_edid(hdmi, edid, MAX_EDID); - if (r < 0) { - kfree(edid); - edid = NULL; - } else { - unsigned int cec_addr; + mutex_lock(>lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); + + r = hdmi4_core_ddc_init(>core); + if (r) + goto done; - cec_addr = r >= 256 ? cec_get_edid_phys_addr(edid, r, NULL) -: CEC_PHYS_ADDR_INVALID; - hdmi4_cec_set_phys_addr(>core, cec_addr); + edid = hdmi_read_edid_data(hdmi); + +done: + hdmi_runtime_put(hdmi); + mutex_unlock(>lock); + + if (edid && edid->extensions) { + unsigned int len = (edid->extensions + 1) * EDID_LENGTH; + + cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); + } else { + cec_addr = CEC_PHYS_ADDR_INVALID; } + hdmi4_cec_set_phys_addr(>core, cec_addr); + if (need_enable) hdmi4_core_disable(>core); - return (struct edid *)edid; + return edid; } static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index ea5d5c228534..751985a2679a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -32,7 +32,7 @@ static inline void __iomem *hdmi_av_base(struct
[PATCH v6 10/51] drm/bridge: simple-bridge: Add support for enable GPIO
If an enable GPIO is declared in the firmware, assert it when enabling the bridge and deassert it when disabling it. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Stefan Agner Reviewed-by: Boris Brezillon Reviewed-by: Maxime Ripard Acked-by: Sam Ravnborg --- drivers/gpu/drm/bridge/simple-bridge.c | 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 20866c1230de..70e6092bdf6c 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -6,6 +6,7 @@ * Maxime Ripard */ +#include #include #include #include @@ -30,6 +31,7 @@ struct simple_bridge { struct i2c_adapter *ddc; struct regulator*vdd; + struct gpio_desc*enable; }; static inline struct simple_bridge * @@ -143,19 +145,23 @@ static int simple_bridge_attach(struct drm_bridge *bridge, static void simple_bridge_enable(struct drm_bridge *bridge) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); - int ret = 0; + int ret; - if (sbridge->vdd) + if (sbridge->vdd) { ret = regulator_enable(sbridge->vdd); + if (ret) + DRM_ERROR("Failed to enable vdd regulator: %d\n", ret); + } - if (ret) - DRM_ERROR("Failed to enable vdd regulator: %d\n", ret); + gpiod_set_value_cansleep(sbridge->enable, 1); } static void simple_bridge_disable(struct drm_bridge *bridge) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); + gpiod_set_value_cansleep(sbridge->enable, 0); + if (sbridge->vdd) regulator_disable(sbridge->vdd); } @@ -208,6 +214,14 @@ static int simple_bridge_probe(struct platform_device *pdev) dev_dbg(>dev, "No vdd regulator found: %d\n", ret); } + sbridge->enable = devm_gpiod_get_optional(>dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(sbridge->enable)) { + if (PTR_ERR(sbridge->enable) != -EPROBE_DEFER) + dev_err(>dev, "Unable to retrieve enable GPIO\n"); + return PTR_ERR(sbridge->enable); + } + sbridge->ddc = simple_bridge_retrieve_ddc(>dev); if (IS_ERR(sbridge->ddc)) { if (PTR_ERR(sbridge->ddc) == -ENODEV) { -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 48/51] drm/omap: Hardcode omap_connector type to DSI
The omap_connector implementation is now used for DSI only. Hardcode its type and drop unused code. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/dss/base.c | 23 -- drivers/gpu/drm/omapdrm/dss/omapdss.h| 1 - drivers/gpu/drm/omapdrm/omap_connector.c | 31 ++-- 3 files changed, 2 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 2db3bd2f19db..455b410f7401 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -286,29 +286,6 @@ void omapdss_device_post_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL_GPL(omapdss_device_post_disable); -unsigned int omapdss_device_connector_type(enum omap_display_type type) -{ - switch (type) { - case OMAP_DISPLAY_TYPE_HDMI: - return DRM_MODE_CONNECTOR_HDMIA; - case OMAP_DISPLAY_TYPE_DVI: - return DRM_MODE_CONNECTOR_DVID; - case OMAP_DISPLAY_TYPE_DSI: - return DRM_MODE_CONNECTOR_DSI; - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - return DRM_MODE_CONNECTOR_DPI; - case OMAP_DISPLAY_TYPE_VENC: - /* TODO: This could also be composite */ - return DRM_MODE_CONNECTOR_SVIDEO; - case OMAP_DISPLAY_TYPE_SDI: - return DRM_MODE_CONNECTOR_LVDS; - default: - return DRM_MODE_CONNECTOR_Unknown; - } -} -EXPORT_SYMBOL_GPL(omapdss_device_connector_type); - /* - * Components Handling */ diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index cb79e05c902d..2e5453df2293 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -454,7 +454,6 @@ void omapdss_device_pre_enable(struct omap_dss_device *dssdev); void omapdss_device_enable(struct omap_dss_device *dssdev); void omapdss_device_disable(struct omap_dss_device *dssdev); void omapdss_device_post_disable(struct omap_dss_device *dssdev); -unsigned int omapdss_device_connector_type(enum omap_display_type type); int omap_dss_get_num_overlay_managers(void); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index baa31ed1f993..528764566b17 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -24,22 +24,7 @@ struct omap_connector { static enum drm_connector_status omap_connector_detect( struct drm_connector *connector, bool force) { - enum drm_connector_status status; - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DPI: - case DRM_MODE_CONNECTOR_LVDS: - case DRM_MODE_CONNECTOR_DSI: - status = connector_status_connected; - break; - default: - status = connector_status_unknown; - break; - } - - VERB("%s: %d (force=%d)", connector->name, status, force); - - return status; + return connector_status_connected; } static void omap_connector_destroy(struct drm_connector *connector) @@ -138,18 +123,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { .mode_valid = omap_connector_mode_valid, }; -static int omap_connector_get_type(struct omap_dss_device *output) -{ - struct omap_dss_device *display; - enum omap_display_type type; - - display = omapdss_display_get(output); - type = display->type; - omapdss_device_put(display); - - return omapdss_device_connector_type(type); -} - /* initialize connector */ struct drm_connector *omap_connector_init(struct drm_device *dev, struct omap_dss_device *output, @@ -171,7 +144,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, connector->doublescan_allowed = 0; drm_connector_init(dev, connector, _connector_funcs, - omap_connector_get_type(output)); + DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, _connector_helper_funcs); return connector; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 11/51] drm/bridge: simple-bridge: Add support for the TI OPA362
The TI OPA362 is an analog video amplifier controlled through a GPIO. Add support for it to the simple-bridge driver. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Boris Brezillon Reviewed-by: Maxime Ripard Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg --- Changes since v3: - Fix device name in commit message --- drivers/gpu/drm/bridge/simple-bridge.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 70e6092bdf6c..a2dca7a3ef03 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -305,6 +305,11 @@ static const struct of_device_id simple_bridge_match[] = { .timings = _bridge_timings, .connector_type = DRM_MODE_CONNECTOR_VGA, }, + }, { + .compatible = "ti,opa362", + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_Composite, + }, }, { .compatible = "ti,ths8135", .data = &(const struct simple_bridge_info) { -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 27/51] drm/omap: hdmi5: Rework EDID read to isolate data read
In preparation of adding DRM bridge support to the hdmi5 encoder code, rework the EDID read to isolate data read. The hdmi_read_edid() function is the main entry point. It performs all initialisation steps required prior to reading the EDID (such as ensuring the device is powered on), as well as corresponding cleanup steps afterwards. EDID read itself is handled by hdmi_read_edid_data() that calls the hdmi5_core_ddc_read() function to read individual blocks. This new code architecture will allow reusing hdmi_read_edid() and hdmi5_core_ddc_read() for the drm_bridge EDID read implementation, while swapping out hdmi_read_edid_data() for the DRM drm_do_get_edid() function. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v2: - Expand commit message --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 89 ++-- drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 48 +++-- drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 5 +- 3 files changed, 65 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 99720dfc5769..2b02b0a11696 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -271,30 +271,6 @@ static int hdmi_dump_regs(struct seq_file *s, void *p) return 0; } -static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) -{ - int r; - int idlemode; - - mutex_lock(>lock); - - r = hdmi_runtime_get(hdmi); - BUG_ON(r); - - idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); - /* No-idle mode */ - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); - - r = hdmi5_read_edid(>core, buf, len); - - REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); - - hdmi_runtime_put(hdmi); - mutex_unlock(>lock); - - return r; -} - static void hdmi_start_audio_stream(struct omap_hdmi *hd) { REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); @@ -412,32 +388,73 @@ static void hdmi_disconnect(struct omap_dss_device *src, #define MAX_EDID 512 -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +static struct edid *hdmi_read_edid_data(struct hdmi_core_data *core) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - bool need_enable; + int max_ext_blocks = 3; + int r, n, i; u8 *edid; - int r; edid = kzalloc(MAX_EDID, GFP_KERNEL); if (!edid) return NULL; + r = hdmi5_core_ddc_read(core, edid, 0, EDID_LENGTH); + if (r) + goto error; + + n = edid[0x7e]; + + if (n > max_ext_blocks) + n = max_ext_blocks; + + for (i = 1; i <= n; i++) { + r = hdmi5_core_ddc_read(core, edid + i * EDID_LENGTH, i, + EDID_LENGTH); + if (r) + goto error; + } + + return (struct edid *)edid; + +error: + kfree(edid); + return NULL; +} + +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +{ + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + struct edid *edid; + bool need_enable; + int idlemode; + int r; + need_enable = hdmi->core_enabled == false; if (need_enable) { r = hdmi_core_enable(hdmi); - if (r) { - kfree(edid); + if (r) return NULL; - } } - r = read_edid(hdmi, edid, MAX_EDID); - if (r < 0) { - kfree(edid); - edid = NULL; - } + mutex_lock(>lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); + + idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); + /* No-idle mode */ + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + + hdmi5_core_ddc_init(>core); + + edid = hdmi_read_edid_data(>core); + + hdmi5_core_ddc_uninit(>core); + + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); + + hdmi_runtime_put(hdmi); + mutex_unlock(>lock); if (need_enable) hdmi_core_disable(hdmi); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index ff4d35c8771f..7dd587035160 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -23,7 +23,7 @@ #include "hdmi5_core.h" -static void hdmi_core_ddc_init(struct hdmi_core_data *core) +void hdmi5_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; const unsigned long long iclk = 26600; /* DSS L3 ICLK */ @@ -102,7 +102,7 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core) REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2); } -static void hdmi_core_ddc_uninit(struct hdmi_core_data *core) +void
[PATCH v6 24/51] drm/omap: dss: Make omap_dss_device_ops optional
As part of the move to drm_bridge ops, the dssdev ops will become empty for some of the internal encoders. Make them optional in the driver to allow them to be removed completely, easing the transition. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/base.c | 21 - drivers/gpu/drm/omapdrm/dss/dss.c| 3 ++- drivers/gpu/drm/omapdrm/omap_connector.c | 2 +- drivers/gpu/drm/omapdrm/omap_encoder.c | 12 +++- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 80d48936d177..2db3bd2f19db 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -195,10 +195,12 @@ int omapdss_device_connect(struct dss_device *dss, dst->dss = dss; - ret = dst->ops->connect(src, dst); - if (ret < 0) { - dst->dss = NULL; - return ret; + if (dst->ops && dst->ops->connect) { + ret = dst->ops->connect(src, dst); + if (ret < 0) { + dst->dss = NULL; + return ret; + } } return 0; @@ -226,7 +228,8 @@ void omapdss_device_disconnect(struct omap_dss_device *src, WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED); - dst->ops->disconnect(src, dst); + if (dst->ops && dst->ops->disconnect) + dst->ops->disconnect(src, dst); dst->dss = NULL; } EXPORT_SYMBOL_GPL(omapdss_device_disconnect); @@ -238,7 +241,7 @@ void omapdss_device_pre_enable(struct omap_dss_device *dssdev) omapdss_device_pre_enable(dssdev->next); - if (dssdev->ops->pre_enable) + if (dssdev->ops && dssdev->ops->pre_enable) dssdev->ops->pre_enable(dssdev); } EXPORT_SYMBOL_GPL(omapdss_device_pre_enable); @@ -248,7 +251,7 @@ void omapdss_device_enable(struct omap_dss_device *dssdev) if (!dssdev) return; - if (dssdev->ops->enable) + if (dssdev->ops && dssdev->ops->enable) dssdev->ops->enable(dssdev); omapdss_device_enable(dssdev->next); @@ -264,7 +267,7 @@ void omapdss_device_disable(struct omap_dss_device *dssdev) omapdss_device_disable(dssdev->next); - if (dssdev->ops->disable) + if (dssdev->ops && dssdev->ops->disable) dssdev->ops->disable(dssdev); } EXPORT_SYMBOL_GPL(omapdss_device_disable); @@ -274,7 +277,7 @@ void omapdss_device_post_disable(struct omap_dss_device *dssdev) if (!dssdev) return; - if (dssdev->ops->post_disable) + if (dssdev->ops && dssdev->ops->post_disable) dssdev->ops->post_disable(dssdev); omapdss_device_post_disable(dssdev->next); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 67b92b5d8dd7..b76fc2b56227 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1552,7 +1552,8 @@ static void dss_shutdown(struct platform_device *pdev) DSSDBG("shutdown\n"); for_each_dss_output(dssdev) { - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE && + dssdev->ops && dssdev->ops->disable) dssdev->ops->disable(dssdev); } } diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index b0cb2ecb30ab..a24cec4b0bb9 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -228,7 +228,7 @@ enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev, drm_mode_copy(adjusted_mode, mode); for (; dssdev; dssdev = dssdev->next) { - if (!dssdev->ops->check_timings) + if (!dssdev->ops || !dssdev->ops->check_timings) continue; ret = dssdev->ops->check_timings(dssdev, adjusted_mode); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index a270173a2411..b232acd3bc3d 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -77,10 +77,10 @@ static void omap_encoder_hdmi_mode_set(struct drm_connector *connector, struct omap_dss_device *dssdev = omap_encoder->output; bool hdmi_mode = connector->display_info.is_hdmi; - if (dssdev->ops->hdmi.set_hdmi_mode) + if (dssdev->ops && dssdev->ops->hdmi.set_hdmi_mode) dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); - if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) { + if (hdmi_mode && dssdev->ops && dssdev->ops->hdmi.set_infoframe) { struct hdmi_avi_infoframe avi; int r; @@ -139,7 +139,7 @@ static void omap_encoder_mode_set(struct drm_encoder
[PATCH v6 15/51] drm/bridge: tfp410: Replace manual connector handling with bridge
Now that a driver is available for display connectors, replace the manual connector handling code with usage of the DRM bridge API. The tfp410 driver doesn't deal with the display connector directly anymore, but still delegates drm_connector operations to the next bridge. This brings us one step closer to having the tfp410 driver handling the TFP410 only. Signed-off-by: Laurent Pinchart Acked-by: Sam Ravnborg --- Changes since v2: - Use drm_bridge_get_edid() and drm_bridge_detect() helpers --- drivers/gpu/drm/bridge/ti-tfp410.c | 216 ++--- 1 file changed, 75 insertions(+), 141 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 193c9368f664..2b8741ebc696 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -4,14 +4,12 @@ * Author: Jyri Sarha */ -#include -#include #include #include -#include #include #include #include +#include #include #include @@ -24,16 +22,13 @@ struct tfp410 { struct drm_bridge bridge; struct drm_connectorconnector; - unsigned intconnector_type; u32 bus_format; - struct i2c_adapter *ddc; - struct gpio_desc*hpd; - int hpd_irq; struct delayed_work hpd_work; struct gpio_desc*powerdown; struct drm_bridge_timings timings; + struct drm_bridge *next_bridge; struct device *dev; }; @@ -56,13 +51,18 @@ static int tfp410_get_modes(struct drm_connector *connector) struct edid *edid; int ret; - if (!dvi->ddc) - goto fallback; + edid = drm_bridge_get_edid(dvi->next_bridge, connector); + if (IS_ERR_OR_NULL(edid)) { + if (edid != ERR_PTR(-ENOTSUPP)) + DRM_INFO("EDID read failed. Fallback to standard modes\n"); - edid = drm_get_edid(connector, dvi->ddc); - if (!edid) { - DRM_INFO("EDID read failed. Fallback to standard modes\n"); - goto fallback; + /* +* No EDID, fallback on the XGA standard modes and prefer a mode +* pretty much anything can handle. +*/ + ret = drm_add_modes_noedid(connector, 1920, 1200); + drm_set_preferred_mode(connector, 1024, 768); + return ret; } drm_connector_update_edid_property(connector, edid); @@ -71,15 +71,6 @@ static int tfp410_get_modes(struct drm_connector *connector) kfree(edid); - return ret; - -fallback: - /* No EDID, fallback on the XGA standard modes */ - ret = drm_add_modes_noedid(connector, 1920, 1200); - - /* And prefer a mode pretty much anything can handle */ - drm_set_preferred_mode(connector, 1024, 768); - return ret; } @@ -92,21 +83,7 @@ tfp410_connector_detect(struct drm_connector *connector, bool force) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); - if (dvi->hpd) { - if (gpiod_get_value_cansleep(dvi->hpd)) - return connector_status_connected; - else - return connector_status_disconnected; - } - - if (dvi->ddc) { - if (drm_probe_ddc(dvi->ddc)) - return connector_status_connected; - else - return connector_status_disconnected; - } - - return connector_status_unknown; + return drm_bridge_detect(dvi->next_bridge); } static const struct drm_connector_funcs tfp410_con_funcs = { @@ -118,12 +95,35 @@ static const struct drm_connector_funcs tfp410_con_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; +static void tfp410_hpd_work_func(struct work_struct *work) +{ + struct tfp410 *dvi; + + dvi = container_of(work, struct tfp410, hpd_work.work); + + if (dvi->bridge.dev) + drm_helper_hpd_irq_event(dvi->bridge.dev); +} + +static void tfp410_hpd_callback(void *arg, enum drm_connector_status status) +{ + struct tfp410 *dvi = arg; + + mod_delayed_work(system_wq, >hpd_work, +msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); +} + static int tfp410_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); int ret; + ret = drm_bridge_attach(bridge->encoder, dvi->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) + return ret; + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { DRM_ERROR("Fix bridge driver to make connector optional!"); return -EINVAL; @@ -134,17 +134,23 @@ static int tfp410_attach(struct drm_bridge *bridge,
[PATCH v6 33/51] drm/omap: dss: Remove .set_hdmi_mode() and .set_infoframe() operations
The omapdss_hdmi_ops .set_hdmi_mode() and .set_infoframe() operations operations are not used anymore, remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 --- drivers/gpu/drm/omapdrm/omap_encoder.c | 26 -- 2 files changed, 29 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 269e143d57be..30a12cf91cbb 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -287,9 +287,6 @@ struct omap_dss_writeback_info { struct omapdss_hdmi_ops { void (*lost_hotplug)(struct omap_dss_device *dssdev); - int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); - int (*set_infoframe)(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi); }; struct omapdss_dsi_ops { diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index b232acd3bc3d..18a79dde6815 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -69,28 +69,6 @@ static void omap_encoder_update_videomode_flags(struct videomode *vm, } } -static void omap_encoder_hdmi_mode_set(struct drm_connector *connector, - struct drm_encoder *encoder, - struct drm_display_mode *adjusted_mode) -{ - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - struct omap_dss_device *dssdev = omap_encoder->output; - bool hdmi_mode = connector->display_info.is_hdmi; - - if (dssdev->ops && dssdev->ops->hdmi.set_hdmi_mode) - dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); - - if (hdmi_mode && dssdev->ops && dssdev->ops->hdmi.set_infoframe) { - struct hdmi_avi_infoframe avi; - int r; - - r = drm_hdmi_avi_infoframe_from_display_mode(, connector, -adjusted_mode); - if (r == 0) - dssdev->ops->hdmi.set_infoframe(dssdev, ); - } -} - static void omap_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -142,10 +120,6 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, if (dssdev->ops && dssdev->ops->set_timings) dssdev->ops->set_timings(dssdev, adjusted_mode); } - - /* Set the HDMI mode and HDMI infoframe if applicable. */ - if (output->type == OMAP_DISPLAY_TYPE_HDMI) - omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode); } static void omap_encoder_disable(struct drm_encoder *encoder) -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 30/51] drm/omap: hdmi4: Move mode set, enable and disable operations to bridge
Move the omap_dss_device .set_timings(), .enable() and .disable() operations to the drm_bridge functions. As the drm_bridge for the HDMI encoder is unconditionally registered and attached, those operations will be called at the appropriate time. The omapdss device .set_infoframe() and .set_hdmi_mode() operations have no equivalent in drm_bridge. Thir content is thus moved to the bridge .enable() operation as the data they store is not needed before the HDMI encoder gets enabled. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v5: - Rebased on top of drm_bridge_state Changes since v2: - Detail .set_infoframe() and .set_hdmi_mode() handling in the commit message --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 206 +++- 1 file changed, 111 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 67994287447b..a8d13a081a9a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -28,6 +28,9 @@ #include #include +#include +#include + #include "omapdss.h" #include "hdmi4_core.h" #include "hdmi4_cec.h" @@ -237,20 +240,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) hdmi_power_off_core(hdmi); } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, -const struct drm_display_mode *mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - mutex_lock(>lock); - - drm_display_mode_to_videomode(mode, >cfg.vm); - - dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - - mutex_unlock(>lock); -} - static int hdmi_dump_regs(struct seq_file *s, void *p) { struct omap_hdmi *hdmi = s->private; @@ -284,62 +273,6 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) hdmi_wp_audio_enable(>wp, false); } -static void hdmi_display_enable(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - unsigned long flags; - int r; - - DSSDBG("ENTER hdmi_display_enable\n"); - - mutex_lock(>lock); - - r = hdmi_power_on_full(hdmi); - if (r) { - DSSERR("failed to power on device\n"); - goto done; - } - - if (hdmi->audio_configured) { - r = hdmi4_audio_config(>core, >wp, - >audio_config, - hdmi->cfg.vm.pixelclock); - if (r) { - DSSERR("Error restoring audio configuration: %d", r); - hdmi->audio_abort_cb(>pdev->dev); - hdmi->audio_configured = false; - } - } - - spin_lock_irqsave(>audio_playing_lock, flags); - if (hdmi->audio_configured && hdmi->audio_playing) - hdmi_start_audio_stream(hdmi); - hdmi->display_enabled = true; - spin_unlock_irqrestore(>audio_playing_lock, flags); - -done: - mutex_unlock(>lock); -} - -static void hdmi_display_disable(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - unsigned long flags; - - DSSDBG("Enter hdmi_display_disable\n"); - - mutex_lock(>lock); - - spin_lock_irqsave(>audio_playing_lock, flags); - hdmi_stop_audio_stream(hdmi); - hdmi->display_enabled = false; - spin_unlock_irqrestore(>audio_playing_lock, flags); - - hdmi_power_off_full(hdmi); - - mutex_unlock(>lock); -} - int hdmi4_core_enable(struct hdmi_core_data *core) { struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); @@ -491,39 +424,14 @@ static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) hdmi4_cec_set_phys_addr(>core, CEC_PHYS_ADDR_INVALID); } -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi->cfg.infoframe = *avi; - return 0; -} - -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, - bool hdmi_mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; - return 0; -} - static const struct omap_dss_device_ops hdmi_ops = { .connect= hdmi_connect, .disconnect = hdmi_disconnect, - .enable = hdmi_display_enable, - .disable= hdmi_display_disable, - - .set_timings= hdmi_display_set_timings, - .read_edid = hdmi_read_edid, .hdmi = { .lost_hotplug = hdmi_lost_hotplug, - .set_infoframe = hdmi_set_infoframe, - .set_hdmi_mode = hdmi_set_hdmi_mode, }, }; @@ -543,6 +451,108 @@ static int
[PATCH v6 49/51] drm/omap: dss: Remove unused omap_dss_device operations
The omap_dss_device .pre_enable(), .post_disable() and .set_timings() are not used anymore. Remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/base.c | 26 --- drivers/gpu/drm/omapdrm/dss/omapdss.h | 6 drivers/gpu/drm/omapdrm/omap_encoder.c | 44 +++--- 3 files changed, 5 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 455b410f7401..c7650a7c155d 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -234,18 +234,6 @@ void omapdss_device_disconnect(struct omap_dss_device *src, } EXPORT_SYMBOL_GPL(omapdss_device_disconnect); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev) -{ - if (!dssdev) - return; - - omapdss_device_pre_enable(dssdev->next); - - if (dssdev->ops && dssdev->ops->pre_enable) - dssdev->ops->pre_enable(dssdev); -} -EXPORT_SYMBOL_GPL(omapdss_device_pre_enable); - void omapdss_device_enable(struct omap_dss_device *dssdev) { if (!dssdev) @@ -272,20 +260,6 @@ void omapdss_device_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL_GPL(omapdss_device_disable); -void omapdss_device_post_disable(struct omap_dss_device *dssdev) -{ - if (!dssdev) - return; - - if (dssdev->ops && dssdev->ops->post_disable) - dssdev->ops->post_disable(dssdev); - - omapdss_device_post_disable(dssdev->next); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} -EXPORT_SYMBOL_GPL(omapdss_device_post_disable); - /* - * Components Handling */ diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 2e5453df2293..64aedc50cb0b 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -342,15 +342,11 @@ struct omap_dss_device_ops { void (*disconnect)(struct omap_dss_device *dssdev, struct omap_dss_device *dst); - void (*pre_enable)(struct omap_dss_device *dssdev); void (*enable)(struct omap_dss_device *dssdev); void (*disable)(struct omap_dss_device *dssdev); - void (*post_disable)(struct omap_dss_device *dssdev); int (*check_timings)(struct omap_dss_device *dssdev, struct drm_display_mode *mode); - void (*set_timings)(struct omap_dss_device *dssdev, - const struct drm_display_mode *mode); int (*get_modes)(struct omap_dss_device *dssdev, struct drm_connector *connector); @@ -450,10 +446,8 @@ int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *dst); void omapdss_device_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst); -void omapdss_device_pre_enable(struct omap_dss_device *dssdev); void omapdss_device_enable(struct omap_dss_device *dssdev); void omapdss_device_disable(struct omap_dss_device *dssdev); -void omapdss_device_post_disable(struct omap_dss_device *dssdev); int omap_dss_get_num_overlay_managers(void); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 18a79dde6815..ae4b867a67a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -113,13 +113,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, bus_flags = connector->display_info.bus_flags; omap_encoder_update_videomode_flags(, bus_flags); - /* Set timings for all devices in the display pipeline. */ + /* Set timings for the dss manager. */ dss_mgr_set_timings(output, ); - - for (dssdev = output; dssdev; dssdev = dssdev->next) { - if (dssdev->ops && dssdev->ops->set_timings) - dssdev->ops->set_timings(dssdev, adjusted_mode); - } } static void omap_encoder_disable(struct drm_encoder *encoder) @@ -132,26 +127,10 @@ static void omap_encoder_disable(struct drm_encoder *encoder) /* * Disable the chain of external devices, starting at the one at the -* internal encoder's output. +* internal encoder's output. This is used for DSI outputs only, as +* dssdev->next is NULL for all other outputs. */ omapdss_device_disable(dssdev->next); - - /* -* Disable the internal encoder. This will disable the DSS output. The -* DSI is treated as an exception as DSI pipelines still use the legacy -* flow where the pipeline output controls the encoder. -*/ - if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) { - if (dssdev->ops && dssdev->ops->disable) - dssdev->ops->disable(dssdev); -
[PATCH v6 17/51] drm: Add helper to create a connector for a chain of bridges
Most bridge drivers create a DRM connector to model the connector at the output of the bridge. This model is historical and has worked pretty well so far, but causes several issues: - It prevents supporting more complex display pipelines where DRM connector operations are split over multiple components. For instance a pipeline with a bridge connected to the DDC signals to read EDID data, and another one connected to the HPD signal to detect connection and disconnection, will not be possible to support through this model. - It requires every bridge driver to implement similar connector handling code, resulting in code duplication. - It assumes that a bridge will either be wired to a connector or to another bridge, but doesn't support bridges that can be used in both positions very well (although there is some ad-hoc support for this in the analogix_dp bridge driver). In order to solve these issues, ownership of the connector needs to be moved to the display controller driver. To avoid code duplication in display controller drivers, add a new helper to create and manage a DRM connector backed by a chain of bridges. All connector operations are delegating to the appropriate bridge in the chain. Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg --- Changes since v5: - Fix the interlace_allowed flag logic Changes since v4: - Set the connector interlace_allowed flag based on interlaced support in bridges Changes since v2: - Fixed typo in documentation - Rebased on top of Boris' drm_bridge chaining rework - Pass drm_encoder instead of brm_bridge to drm_bridge_connector_init() Changes since v1: - Removed the unused MAX_EDID macro - Removed the unused drm_bridge_connector.hdmi_mode field - Use drm_connector_init_with_ddc() --- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_bridge_connector.c | 378 + include/drm/drm_bridge_connector.h | 18 ++ 3 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_bridge_connector.c create mode 100644 include/drm/drm_bridge_connector.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index ca0ca775d37f..7f72ef5e7811 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -39,7 +39,8 @@ obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o drm_ttm_helper-y := drm_gem_ttm_helper.o obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o -drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \ +drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \ + drm_dsc.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ drm_simple_kms_helper.o drm_modeset_helper.o \ diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c new file mode 100644 index ..a102755afde8 --- /dev/null +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Laurent Pinchart + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: overview + * + * The DRM bridge connector helper object provides a DRM connector + * implementation that wraps a chain of drm_bridge. The connector + * operations are fully implemented based on the operations of the bridges in + * the chain, and don't require any intervention from the display controller + * driver at runtime. + * + * To use the helper, display controller drivers create a bridge connector with + * a call to drm_bridge_connector_init(). This associates the newly created + * connector with the chain of bridges passed to the function and registers it + * with the DRM device. At that point the connector becomes fully usable, no + * further operation is needed. + * + * The DRM bridge connector operations are implemented based on the operations + * provided by the bridges in the chain. Each connector operation is delegated + * to the bridge closest to the connector (at the end of the chain) that + * provides the relevant functionality. + * + * To make use of this helper, all bridges in the chain shall report bridge + * operation flags (_bridge->ops) and bridge output type + * (_bridge->type), and none of them may create a DRM connector directly. + */ + +/** + * struct drm_bridge_connector - A connector backed by a chain of bridges + */ +struct drm_bridge_connector { + /** +* @base: The base DRM connector +*/ + struct drm_connector base; + /** +* @encoder: +* +* The encoder at the start of the bridges chain. +*/ + struct drm_encoder *encoder; + /** +* @bridge_edid: +* +* The last bridge in the chain (closest to the
[PATCH v6 45/51] drm/omap: dpi: Register a drm_bridge
In order to integrate with a chain of drm_bridge, the internal DPI output has to expose its operations through the drm_bridge API. Register a bridge at initialisation time to do so and remove the omap_dss_device operations that are now unused. Signed-off-by: Laurent Pinchart --- Changes since v5: - Rebased on top of drm_bridge_state Changes since v3: - Drop unneeded lock Changes since v2: - Unregister bridge if port initialisation fails --- drivers/gpu/drm/omapdrm/dss/dpi.c | 209 +- 1 file changed, 116 insertions(+), 93 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index c167bd1116ec..5110acb0c6c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -21,6 +21,8 @@ #include #include +#include + #include "dss.h" #include "omapdss.h" @@ -34,19 +36,15 @@ struct dpi_data { enum dss_clk_source clk_src; struct dss_pll *pll; - struct mutex lock; - struct dss_lcd_mgr_config mgr_config; unsigned long pixelclock; int data_lines; struct omap_dss_device output; + struct drm_bridge bridge; }; -static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) -{ - return container_of(dssdev, struct dpi_data, output); -} +#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge) /* - * Clock Handling and PLL @@ -354,6 +352,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dss_mgr_set_lcd_config(>output, >mgr_config); } +static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock) +{ + int lck_div, pck_div; + unsigned long fck; + struct dpi_clk_calc_ctx ctx; + + if (dpi->pll) { + if (!dpi_pll_clk_calc(dpi, *clock, )) + return -EINVAL; + + fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; + } else { + if (!dpi_dss_clk_calc(dpi, *clock, )) + return -EINVAL; + + fck = ctx.fck; + } + + lck_div = ctx.dispc_cinfo.lck_div; + pck_div = ctx.dispc_cinfo.pck_div; + + *clock = fck / lck_div / pck_div; + + return 0; +} + static int dpi_verify_pll(struct dss_pll *pll) { int r; @@ -391,44 +415,86 @@ static void dpi_init_pll(struct dpi_data *dpi) } /* - - * omap_dss_device Operations + * DRM Bridge Operations */ -static int dpi_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) +static int dpi_bridge_attach(struct drm_bridge *bridge, +enum drm_bridge_attach_flags flags) { - struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; dpi_init_pll(dpi); - return omapdss_device_connect(dst->dss, dst, dst->next); + return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge, +bridge, flags); } -static void dpi_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) +static enum drm_mode_status +dpi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) { - omapdss_device_disconnect(dst, dst->next); + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + unsigned long clock = mode->clock * 1000; + int ret; + + if (mode->hdisplay % 8 != 0) + return MODE_BAD_WIDTH; + + if (mode->clock == 0) + return MODE_NOCLOCK; + + ret = dpi_clock_update(dpi, ); + if (ret < 0) + return MODE_CLOCK_RANGE; + + return MODE_OK; } -static void dpi_display_enable(struct omap_dss_device *dssdev) +static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - struct omap_dss_device *out = >output; - int r; + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); + unsigned long clock = mode->clock * 1000; + int ret; + + ret = dpi_clock_update(dpi, ); + if (ret < 0) + return false; + + adjusted_mode->clock = clock / 1000; + + return true; +} - mutex_lock(>lock); +static void dpi_bridge_mode_set(struct drm_bridge *bridge, +const struct drm_display_mode *mode, +const struct drm_display_mode *adjusted_mode) +{ + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +
[PATCH v6 09/51] drm/bridge: simple-bridge: Add support for non-VGA bridges
Create a new simple_bridge_info structure that stores information about the bridge model, and store the bridge timings in there, along with the connector type. Use that new structure for of_device_id data. This enables support for non-VGA bridges. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Stefan Agner Reviewed-by: Boris Brezillon Reviewed-by: Maxime Ripard Acked-by: Sam Ravnborg --- Changes since v1: - Renamed simple_bridge_info.type field to connector_type --- drivers/gpu/drm/bridge/simple-bridge.c | 41 ++ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 00d810c99193..20866c1230de 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -17,10 +17,17 @@ #include #include +struct simple_bridge_info { + const struct drm_bridge_timings *timings; + unsigned int connector_type; +}; + struct simple_bridge { struct drm_bridge bridge; struct drm_connectorconnector; + const struct simple_bridge_info *info; + struct i2c_adapter *ddc; struct regulator*vdd; }; @@ -120,7 +127,7 @@ static int simple_bridge_attach(struct drm_bridge *bridge, _bridge_con_helper_funcs); ret = drm_connector_init_with_ddc(bridge->dev, >connector, _bridge_con_funcs, - DRM_MODE_CONNECTOR_VGA, + sbridge->info->connector_type, sbridge->ddc); if (ret) { DRM_ERROR("Failed to initialize connector\n"); @@ -190,6 +197,8 @@ static int simple_bridge_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, sbridge); + sbridge->info = of_device_get_match_data(>dev); + sbridge->vdd = devm_regulator_get_optional(>dev, "vdd"); if (IS_ERR(sbridge->vdd)) { int ret = PTR_ERR(sbridge->vdd); @@ -213,7 +222,7 @@ static int simple_bridge_probe(struct platform_device *pdev) sbridge->bridge.funcs = _bridge_bridge_funcs; sbridge->bridge.of_node = pdev->dev.of_node; - sbridge->bridge.timings = of_device_get_match_data(>dev); + sbridge->bridge.timings = sbridge->info->timings; drm_bridge_add(>bridge); @@ -273,19 +282,27 @@ static const struct drm_bridge_timings ti_ths8135_bridge_timings = { static const struct of_device_id simple_bridge_match[] = { { .compatible = "dumb-vga-dac", - .data = NULL, - }, - { + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_VGA, + }, + }, { .compatible = "adi,adv7123", - .data = _bridge_timings, - }, - { + .data = &(const struct simple_bridge_info) { + .timings = _bridge_timings, + .connector_type = DRM_MODE_CONNECTOR_VGA, + }, + }, { .compatible = "ti,ths8135", - .data = _ths8135_bridge_timings, - }, - { + .data = &(const struct simple_bridge_info) { + .timings = _ths8135_bridge_timings, + .connector_type = DRM_MODE_CONNECTOR_VGA, + }, + }, { .compatible = "ti,ths8134", - .data = _ths8134_bridge_timings, + .data = &(const struct simple_bridge_info) { + .timings = _ths8134_bridge_timings, + .connector_type = DRM_MODE_CONNECTOR_VGA, + }, }, {}, }; -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 31/51] drm/omap: hdmi5: Move mode set, enable and disable operations to bridge
Move the omap_dss_device .set_timings(), .enable() and .disable() operations to the drm_bridge functions. As the drm_bridge for the HDMI encoder is unconditionally registered and attached, those operations will be called at the appropriate time. The omapdss device .set_infoframe() and .set_hdmi_mode() operations have no equivalent in drm_bridge. Thir content is thus moved to the bridge .enable() operation as the data they store is not needed before the HDMI encoder gets enabled. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v5: - Rebased on top of drm_bridge_state Changes since v2: - Detail .set_infoframe() and .set_hdmi_mode() handling in the commit message --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 209 +++- 1 file changed, 111 insertions(+), 98 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index e7fe2a24a3e1..52184797c858 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -31,6 +31,9 @@ #include #include +#include +#include + #include "omapdss.h" #include "hdmi5_core.h" #include "dss.h" @@ -236,20 +239,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) hdmi_power_off_core(hdmi); } -static void hdmi_display_set_timings(struct omap_dss_device *dssdev, -const struct drm_display_mode *mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - mutex_lock(>lock); - - drm_display_mode_to_videomode(mode, >cfg.vm); - - dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); - - mutex_unlock(>lock); -} - static int hdmi_dump_regs(struct seq_file *s, void *p) { struct omap_hdmi *hdmi = s->private; @@ -285,62 +274,6 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); } -static void hdmi_display_enable(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - unsigned long flags; - int r; - - DSSDBG("ENTER hdmi_display_enable\n"); - - mutex_lock(>lock); - - r = hdmi_power_on_full(hdmi); - if (r) { - DSSERR("failed to power on device\n"); - goto done; - } - - if (hdmi->audio_configured) { - r = hdmi5_audio_config(>core, >wp, - >audio_config, - hdmi->cfg.vm.pixelclock); - if (r) { - DSSERR("Error restoring audio configuration: %d", r); - hdmi->audio_abort_cb(>pdev->dev); - hdmi->audio_configured = false; - } - } - - spin_lock_irqsave(>audio_playing_lock, flags); - if (hdmi->audio_configured && hdmi->audio_playing) - hdmi_start_audio_stream(hdmi); - hdmi->display_enabled = true; - spin_unlock_irqrestore(>audio_playing_lock, flags); - -done: - mutex_unlock(>lock); -} - -static void hdmi_display_disable(struct omap_dss_device *dssdev) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - unsigned long flags; - - DSSDBG("Enter hdmi_display_disable\n"); - - mutex_lock(>lock); - - spin_lock_irqsave(>audio_playing_lock, flags); - hdmi_stop_audio_stream(hdmi); - hdmi->display_enabled = false; - spin_unlock_irqrestore(>audio_playing_lock, flags); - - hdmi_power_off_full(hdmi); - - mutex_unlock(>lock); -} - static int hdmi_core_enable(struct omap_hdmi *hdmi) { int r = 0; @@ -473,39 +406,11 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) NULL); } -static int hdmi_set_infoframe(struct omap_dss_device *dssdev, - const struct hdmi_avi_infoframe *avi) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi->cfg.infoframe = *avi; - return 0; -} - -static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, - bool hdmi_mode) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; - return 0; -} - static const struct omap_dss_device_ops hdmi_ops = { .connect= hdmi_connect, .disconnect = hdmi_disconnect, - .enable = hdmi_display_enable, - .disable= hdmi_display_disable, - - .set_timings= hdmi_display_set_timings, - .read_edid = hdmi_read_edid, - - .hdmi = { - .set_infoframe = hdmi_set_infoframe, - .set_hdmi_mode = hdmi_set_hdmi_mode, - }, }; /* - @@ -524,6 +429,108 @@ static int hdmi5_bridge_attach(struct drm_bridge
[PATCH v6 07/51] drm/bridge: dumb-vga-dac: Rename internal symbols to simple-bridge
The dumb-vga-dac driver is a simple DRM bridge driver for simple VGA DACs that don't require configuration. Other non-VGA bridges fall in a similar category, and would benefit from a common driver. Prepare for this by renaming the internal symbols from dumb-vga-dac to simple-bridge. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Boris Brezillon Reviewed-by: Maxime Ripard Acked-by: Sam Ravnborg --- drivers/gpu/drm/bridge/dumb-vga-dac.c | 154 +- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index ad5b5a849e43..7287be2d3220 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -17,7 +17,7 @@ #include #include -struct dumb_vga { +struct simple_bridge { struct drm_bridge bridge; struct drm_connectorconnector; @@ -25,28 +25,28 @@ struct dumb_vga { struct regulator*vdd; }; -static inline struct dumb_vga * -drm_bridge_to_dumb_vga(struct drm_bridge *bridge) +static inline struct simple_bridge * +drm_bridge_to_simple_bridge(struct drm_bridge *bridge) { - return container_of(bridge, struct dumb_vga, bridge); + return container_of(bridge, struct simple_bridge, bridge); } -static inline struct dumb_vga * -drm_connector_to_dumb_vga(struct drm_connector *connector) +static inline struct simple_bridge * +drm_connector_to_simple_bridge(struct drm_connector *connector) { - return container_of(connector, struct dumb_vga, connector); + return container_of(connector, struct simple_bridge, connector); } -static int dumb_vga_get_modes(struct drm_connector *connector) +static int simple_bridge_get_modes(struct drm_connector *connector) { - struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); + struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector); struct edid *edid; int ret; - if (!vga->ddc) + if (!sbridge->ddc) goto fallback; - edid = drm_get_edid(connector, vga->ddc); + edid = drm_get_edid(connector, sbridge->ddc); if (!edid) { DRM_INFO("EDID readout failed, falling back to standard modes\n"); goto fallback; @@ -70,14 +70,14 @@ static int dumb_vga_get_modes(struct drm_connector *connector) return ret; } -static const struct drm_connector_helper_funcs dumb_vga_con_helper_funcs = { - .get_modes = dumb_vga_get_modes, +static const struct drm_connector_helper_funcs simple_bridge_con_helper_funcs = { + .get_modes = simple_bridge_get_modes, }; static enum drm_connector_status -dumb_vga_connector_detect(struct drm_connector *connector, bool force) +simple_bridge_connector_detect(struct drm_connector *connector, bool force) { - struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); + struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector); /* * Even if we have an I2C bus, we can't assume that the cable @@ -85,14 +85,14 @@ dumb_vga_connector_detect(struct drm_connector *connector, bool force) * wire the DDC pins, or the I2C bus might not be working at * all. */ - if (vga->ddc && drm_probe_ddc(vga->ddc)) + if (sbridge->ddc && drm_probe_ddc(sbridge->ddc)) return connector_status_connected; return connector_status_unknown; } -static const struct drm_connector_funcs dumb_vga_con_funcs = { - .detect = dumb_vga_connector_detect, +static const struct drm_connector_funcs simple_bridge_con_funcs = { + .detect = simple_bridge_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy= drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, @@ -100,10 +100,10 @@ static const struct drm_connector_funcs dumb_vga_con_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int dumb_vga_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) +static int simple_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) { - struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); + struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); int ret; if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { @@ -116,50 +116,50 @@ static int dumb_vga_attach(struct drm_bridge *bridge, return -ENODEV; } - drm_connector_helper_add(>connector, -_vga_con_helper_funcs); - ret = drm_connector_init_with_ddc(bridge->dev, >connector, - _vga_con_funcs, +
[PATCH v6 40/51] drm/omap: hdmi4: Simplify EDID read
Now that the omap_dss_device EDID read operation has been removed, simplify the bridge-based EDID access by merging multiple functions together. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 96 - 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 96ef7bd52199..2578c95570f6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -309,55 +309,6 @@ void hdmi4_core_disable(struct hdmi_core_data *core) mutex_unlock(>lock); } -static struct edid * -hdmi_do_read_edid(struct omap_hdmi *hdmi, - struct edid *(*read)(struct omap_hdmi *hdmi, - struct drm_connector *connector), - struct drm_connector *connector) -{ - struct edid *edid = NULL; - unsigned int cec_addr; - bool need_enable; - int r; - - need_enable = hdmi->core_enabled == false; - - if (need_enable) { - r = hdmi4_core_enable(>core); - if (r) - return NULL; - } - - mutex_lock(>lock); - r = hdmi_runtime_get(hdmi); - BUG_ON(r); - - r = hdmi4_core_ddc_init(>core); - if (r) - goto done; - - edid = read(hdmi, connector); - -done: - hdmi_runtime_put(hdmi); - mutex_unlock(>lock); - - if (edid && edid->extensions) { - unsigned int len = (edid->extensions + 1) * EDID_LENGTH; - - cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); - } else { - cec_addr = CEC_PHYS_ADDR_INVALID; - } - - hdmi4_cec_set_phys_addr(>core, cec_addr); - - if (need_enable) - hdmi4_core_disable(>core); - - return edid; -} - /* - * DRM Bridge Operations */ @@ -485,18 +436,51 @@ static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, hdmi4_cec_set_phys_addr(>core, CEC_PHYS_ADDR_INVALID); } -static struct edid *hdmi4_bridge_read_edid(struct omap_hdmi *hdmi, - struct drm_connector *connector) -{ - return drm_do_get_edid(connector, hdmi4_core_ddc_read, >core); -} - static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + struct edid *edid = NULL; + unsigned int cec_addr; + bool need_enable; + int r; + + need_enable = hdmi->core_enabled == false; + + if (need_enable) { + r = hdmi4_core_enable(>core); + if (r) + return NULL; + } + + mutex_lock(>lock); + r = hdmi_runtime_get(hdmi); + BUG_ON(r); + + r = hdmi4_core_ddc_init(>core); + if (r) + goto done; + + edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, >core); - return hdmi_do_read_edid(hdmi, hdmi4_bridge_read_edid, connector); +done: + hdmi_runtime_put(hdmi); + mutex_unlock(>lock); + + if (edid && edid->extensions) { + unsigned int len = (edid->extensions + 1) * EDID_LENGTH; + + cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL); + } else { + cec_addr = CEC_PHYS_ADDR_INVALID; + } + + hdmi4_cec_set_phys_addr(>core, cec_addr); + + if (need_enable) + hdmi4_core_disable(>core); + + return edid; } static const struct drm_bridge_funcs hdmi4_bridge_funcs = { -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 28/51] drm/omap: hdmi4: Register a drm_bridge for EDID read
In order to integrate with a chain of drm_bridge, the internal HDMI4 encoder has to expose the EDID read operation through the drm_bridge API. Register a bridge at initialisation time to do so. For the time being make the next bridge in the chain optional as the HDMI output is still based on omap_dss_device. The create_connector argument to the bridge attach function is also ignored for the same reason. This will be changed later when removing the related omapdrm-specific display drivers. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v2: - Unregister bridge if output initialisation fails --- drivers/gpu/drm/omapdrm/dss/hdmi.h | 3 ++ drivers/gpu/drm/omapdrm/dss/hdmi4.c | 78 ++--- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index c867552c925c..bd43f6abf27b 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "omapdss.h" #include "dss.h" @@ -364,6 +365,7 @@ struct omap_hdmi { bool core_enabled; struct omap_dss_device output; + struct drm_bridge bridge; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); @@ -379,5 +381,6 @@ struct omap_hdmi { }; #define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) +#define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge) #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 37536b9f3114..67994287447b 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -390,7 +390,8 @@ static void hdmi_disconnect(struct omap_dss_device *src, #define MAX_EDID 512 -static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi) +static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi, + struct drm_connector *connector) { u8 *edid; int r; @@ -428,9 +429,12 @@ static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi) return NULL; } -static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +static struct edid * +hdmi_do_read_edid(struct omap_hdmi *hdmi, + struct edid *(*read)(struct omap_hdmi *hdmi, + struct drm_connector *connector), + struct drm_connector *connector) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); struct edid *edid = NULL; unsigned int cec_addr; bool need_enable; @@ -452,7 +456,7 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) if (r) goto done; - edid = hdmi_read_edid_data(hdmi); + edid = read(hdmi, connector); done: hdmi_runtime_put(hdmi); @@ -474,6 +478,12 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) return edid; } +static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev) +{ + return hdmi_do_read_edid(dssdev_to_hdmi(dssdev), hdmi_read_edid_data, +NULL); +} + static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); @@ -517,6 +527,56 @@ static const struct omap_dss_device_ops hdmi_ops = { }, }; +/* - + * DRM Bridge Operations + */ + +static int hdmi4_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + if (!hdmi->output.next_bridge) + return 0; + + return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge, +bridge, flags); +} + +static struct edid *hdmi4_bridge_read_edid(struct omap_hdmi *hdmi, + struct drm_connector *connector) +{ + return drm_do_get_edid(connector, hdmi4_core_ddc_read, >core); +} + +static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge); + + return hdmi_do_read_edid(hdmi, hdmi4_bridge_read_edid, connector); +} + +static const struct drm_bridge_funcs hdmi4_bridge_funcs = { + .attach = hdmi4_bridge_attach, + .get_edid = hdmi4_bridge_get_edid, +}; + +static void hdmi4_bridge_init(struct omap_hdmi *hdmi) +{ + hdmi->bridge.funcs = _bridge_funcs; + hdmi->bridge.of_node = hdmi->pdev->dev.of_node; + hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + + drm_bridge_add(>bridge); +} + +static void hdmi4_bridge_cleanup(struct
[PATCH v6 34/51] drm/omap: venc: Register a drm_bridge
In order to integrate with a chain of drm_bridge, the internal VENC encoder has to expose the mode valid, fixup and set, the enable and disable and the get modes operations through the drm_bridge API. Register a bridge at initialisation time to do so. Most of those operations are removed from the omap_dss_device as they are now called through the drm_bridge API by the DRM atomic helpers. The only exception is the .get_modes() operation that is still invoked through the omap_dss_device-based pipeline. For the time being make the next bridge in the chain optional as the VENC output is still based on omap_dss_device. The create_connector argument to the bridge attach function is also ignored for the same reason. This will be changed later when removing the related omapdrm-specific display drivers. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v5: - Rebased on top of drm_bridge_state Changes since v4: - Set bridge interlace_allowed flag Changes since v3: - Drop unneeded venc_lock Changes since v2: - Unregister bridge if output initialisation fails --- drivers/gpu/drm/omapdrm/dss/venc.c | 242 ++--- 1 file changed, 154 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 977d8d525b43..cb9a689ed612 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -26,6 +25,8 @@ #include #include +#include + #include "omapdss.h" #include "dss.h" @@ -289,7 +290,6 @@ static const struct drm_display_mode omap_dss_ntsc_mode = { struct venc_device { struct platform_device *pdev; void __iomem *base; - struct mutex venc_lock; struct regulator *vdda_dac_reg; struct dss_device *dss; @@ -303,9 +303,11 @@ struct venc_device { bool requires_tv_dac_clk; struct omap_dss_device output; + struct drm_bridge bridge; }; #define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) +#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge) static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val) { @@ -477,32 +479,6 @@ static void venc_power_off(struct venc_device *venc) venc_runtime_put(venc); } -static void venc_display_enable(struct omap_dss_device *dssdev) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - - DSSDBG("venc_display_enable\n"); - - mutex_lock(>venc_lock); - - venc_power_on(venc); - - mutex_unlock(>venc_lock); -} - -static void venc_display_disable(struct omap_dss_device *dssdev) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - - DSSDBG("venc_display_disable\n"); - - mutex_lock(>venc_lock); - - venc_power_off(venc); - - mutex_unlock(>venc_lock); -} - static int venc_get_modes(struct omap_dss_device *dssdev, struct drm_connector *connector) { @@ -545,57 +521,6 @@ static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mod return VENC_MODE_UNKNOWN; } -static void venc_set_timings(struct omap_dss_device *dssdev, -const struct drm_display_mode *mode) -{ - struct venc_device *venc = dssdev_to_venc(dssdev); - enum venc_videomode venc_mode = venc_get_videomode(mode); - - DSSDBG("venc_set_timings\n"); - - mutex_lock(>venc_lock); - - switch (venc_mode) { - default: - WARN_ON_ONCE(1); - /* Fall-through */ - case VENC_MODE_PAL: - venc->config = _config_pal_trm; - break; - - case VENC_MODE_NTSC: - venc->config = _config_ntsc_trm; - break; - } - - dispc_set_tv_pclk(venc->dss->dispc, 1350); - - mutex_unlock(>venc_lock); -} - -static int venc_check_timings(struct omap_dss_device *dssdev, - struct drm_display_mode *mode) -{ - DSSDBG("venc_check_timings\n"); - - switch (venc_get_videomode(mode)) { - case VENC_MODE_PAL: - drm_mode_copy(mode, _dss_pal_mode); - break; - - case VENC_MODE_NTSC: - drm_mode_copy(mode, _dss_ntsc_mode); - break; - - default: - return -EINVAL; - } - - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - drm_mode_set_name(mode); - return 0; -} - static int venc_dump_regs(struct seq_file *s, void *p) { struct venc_device *venc = s->private; @@ -689,15 +614,152 @@ static const struct omap_dss_device_ops venc_ops = { .connect = venc_connect, .disconnect = venc_disconnect, - .enable = venc_display_enable, - .disable = venc_display_disable, + .get_modes = venc_get_modes, +}; - .check_timings =
[PATCH v6 20/51] drm/omap: Factor out display type to connector type conversion
Move the code that computes the DRM connector type for the omapdss_device display type to a new omapdss_device_connector_type() function for later reuse. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Acked-by: Sam Ravnborg --- drivers/gpu/drm/omapdrm/dss/base.c | 23 +++ drivers/gpu/drm/omapdrm/dss/omapdss.h| 1 + drivers/gpu/drm/omapdrm/omap_connector.c | 19 +-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index a1970b9db6ab..cae5687822e2 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -285,6 +285,29 @@ void omapdss_device_post_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL_GPL(omapdss_device_post_disable); +unsigned int omapdss_device_connector_type(enum omap_display_type type) +{ + switch (type) { + case OMAP_DISPLAY_TYPE_HDMI: + return DRM_MODE_CONNECTOR_HDMIA; + case OMAP_DISPLAY_TYPE_DVI: + return DRM_MODE_CONNECTOR_DVID; + case OMAP_DISPLAY_TYPE_DSI: + return DRM_MODE_CONNECTOR_DSI; + case OMAP_DISPLAY_TYPE_DPI: + case OMAP_DISPLAY_TYPE_DBI: + return DRM_MODE_CONNECTOR_DPI; + case OMAP_DISPLAY_TYPE_VENC: + /* TODO: This could also be composite */ + return DRM_MODE_CONNECTOR_SVIDEO; + case OMAP_DISPLAY_TYPE_SDI: + return DRM_MODE_CONNECTOR_LVDS; + default: + return DRM_MODE_CONNECTOR_Unknown; + } +} +EXPORT_SYMBOL_GPL(omapdss_device_connector_type); + /* - * Components Handling */ diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 79f6b195c7cf..c5672e5174c5 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -479,6 +479,7 @@ void omapdss_device_pre_enable(struct omap_dss_device *dssdev); void omapdss_device_enable(struct omap_dss_device *dssdev); void omapdss_device_disable(struct omap_dss_device *dssdev); void omapdss_device_post_disable(struct omap_dss_device *dssdev); +unsigned int omapdss_device_connector_type(enum omap_display_type type); int omap_dss_get_num_overlay_managers(void); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 88dbf3fa473f..38c7a79c5d4a 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -296,24 +296,7 @@ static int omap_connector_get_type(struct omap_dss_device *output) type = display->type; omapdss_device_put(display); - switch (type) { - case OMAP_DISPLAY_TYPE_HDMI: - return DRM_MODE_CONNECTOR_HDMIA; - case OMAP_DISPLAY_TYPE_DVI: - return DRM_MODE_CONNECTOR_DVID; - case OMAP_DISPLAY_TYPE_DSI: - return DRM_MODE_CONNECTOR_DSI; - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - return DRM_MODE_CONNECTOR_DPI; - case OMAP_DISPLAY_TYPE_VENC: - /* TODO: This could also be composite */ - return DRM_MODE_CONNECTOR_SVIDEO; - case OMAP_DISPLAY_TYPE_SDI: - return DRM_MODE_CONNECTOR_LVDS; - default: - return DRM_MODE_CONNECTOR_Unknown; - } + return omapdss_device_connector_type(type); } /* initialize connector */ -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 23/51] drm/omap: Add infrastructure to support drm_bridge local to DSS outputs
In order to support drm_bridge-based pipeline, the internal HDMI encoders will need to expose the EDID read operation through the drm_bridge API, and thus to expose a drm_bridge instance corresponding to the encoder. The HDMI encoders are however handled as omap_dss_device instances, which conflicts with this requirement. In order to move forward with the drm_bridge transition, add support for creating drm_bridge instances local to DSS outputs. If a local bridge is passed to the omapdss_device_init_output() function, it is used as the first bridge in the chain, and the omap_dss_device.next_bridge field is set to the next bridge for the use of the internal encoders' bridges. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dpi.c | 2 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 2 +- drivers/gpu/drm/omapdrm/dss/omapdss.h | 4 +++- drivers/gpu/drm/omapdrm/dss/output.c | 20 drivers/gpu/drm/omapdrm/dss/sdi.c | 2 +- drivers/gpu/drm/omapdrm/dss/venc.c| 2 +- drivers/gpu/drm/omapdrm/omap_drv.c| 2 +- 9 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 462ed6f3118a..2d0eb5fcbb5b 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -629,7 +629,7 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) out->ops = _ops; out->owner = THIS_MODULE; - r = omapdss_device_init_output(out); + r = omapdss_device_init_output(out, NULL); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 6379eea124d1..79ddfbfd1b58 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5121,7 +5121,7 @@ static int dsi_init_output(struct dsi_data *dsi) | DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; - r = omapdss_device_init_output(out); + r = omapdss_device_init_output(out, NULL); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 44075718407b..dd4a14fe7e59 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -676,7 +676,7 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->of_port = 0; out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - r = omapdss_device_init_output(out); + r = omapdss_device_init_output(out, NULL); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 1b5bd44ee09d..8e3790dd8b98 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -660,7 +660,7 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->of_port = 0; out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - r = omapdss_device_init_output(out); + r = omapdss_device_init_output(out, NULL); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index b48a51d11310..82e9bfa5530a 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -400,6 +400,7 @@ struct omap_dss_device { struct dss_device *dss; struct omap_dss_device *next; struct drm_bridge *bridge; + struct drm_bridge *next_bridge; struct drm_panel *panel; struct list_head list; @@ -488,7 +489,8 @@ int omap_dss_get_num_overlays(void); #define for_each_dss_output(d) \ while ((d = omapdss_device_next_output(d)) != NULL) struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from); -int omapdss_device_init_output(struct omap_dss_device *out); +int omapdss_device_init_output(struct omap_dss_device *out, + struct drm_bridge *local_bridge); void omapdss_device_cleanup_output(struct omap_dss_device *out); typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index c1ec9d343e53..9ba7cc8539a1 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -17,7 +17,8 @@ #include "dss.h" #include "omapdss.h" -int omapdss_device_init_output(struct omap_dss_device *out) +int omapdss_device_init_output(struct omap_dss_device *out, + struct drm_bridge *local_bridge) { struct device_node *remote_node; int ret; @@ -58,10 +59,20 @@ int omapdss_device_init_output(struct omap_dss_device *out) out->bridge = bridge; } - return out->next ||
[PATCH v6 36/51] drm/omap: Switch the HDMI and VENC outputs to drm_bridge
The TPD12S015, OPA362 and analog and HDMI connectors are now supported by DRM bridge drivers, and the omapdrm HDMI and VENC outputs can be handled through the drm_bridge API. Switch the outputs to drm_bridge by making the next bridge mandatory and removing the related omapdrm-specific display drivers. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes since v3: - Update arch/arm/configs/omap2plus_defconfig --- arch/arm/configs/omap2plus_defconfig | 7 +- drivers/gpu/drm/omapdrm/displays/Kconfig | 22 -- drivers/gpu/drm/omapdrm/displays/Makefile | 4 - .../omapdrm/displays/connector-analog-tv.c| 97 .../gpu/drm/omapdrm/displays/connector-hdmi.c | 183 --- .../gpu/drm/omapdrm/displays/encoder-opa362.c | 137 --- .../drm/omapdrm/displays/encoder-tpd12s015.c | 217 -- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 4 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 4 +- .../gpu/drm/omapdrm/dss/omapdss-boot-init.c | 5 - drivers/gpu/drm/omapdrm/dss/output.c | 5 + drivers/gpu/drm/omapdrm/dss/venc.c| 4 +- 12 files changed, 14 insertions(+), 675 deletions(-) delete mode 100644 drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c delete mode 100644 drivers/gpu/drm/omapdrm/displays/connector-hdmi.c delete mode 100644 drivers/gpu/drm/omapdrm/displays/encoder-opa362.c delete mode 100644 drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 8c37cc8ab6f2..a74abf4ac468 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -348,14 +348,13 @@ CONFIG_DRM_OMAP=m CONFIG_OMAP5_DSS_HDMI=y CONFIG_OMAP2_DSS_SDI=y CONFIG_OMAP2_DSS_DSI=y -CONFIG_DRM_OMAP_ENCODER_OPA362=m -CONFIG_DRM_OMAP_ENCODER_TPD12S015=m -CONFIG_DRM_OMAP_CONNECTOR_HDMI=m -CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV=m CONFIG_DRM_OMAP_PANEL_DSI_CM=m CONFIG_DRM_TILCDC=m CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_TI_TFP410=m +CONFIG_DRM_TI_TPD12S015=m CONFIG_DRM_PANEL_LG_LB035Q02=m CONFIG_DRM_PANEL_NEC_NL8048HL11=m CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index b562a8cd61bf..f2be594c7eff 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -1,28 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "OMAPDRM External Display Device Drivers" -config DRM_OMAP_ENCODER_OPA362 - tristate "OPA362 external analog amplifier" - help - Driver for OPA362 external analog TV amplifier controlled - through a GPIO. - -config DRM_OMAP_ENCODER_TPD12S015 - tristate "TPD12S015 HDMI ESD protection and level shifter" - help - Driver for TPD12S015, which offers HDMI ESD protection and level - shifting. - -config DRM_OMAP_CONNECTOR_HDMI - tristate "HDMI Connector" - help - Driver for a generic HDMI connector. - -config DRM_OMAP_CONNECTOR_ANALOG_TV - tristate "Analog TV Connector" - help - Driver for a generic analog TV connector. - config DRM_OMAP_PANEL_DSI_CM tristate "Generic DSI Command Mode Panel" depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/gpu/drm/omapdrm/displays/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile index cb76859dc574..488ddf153613 100644 --- a/drivers/gpu/drm/omapdrm/displays/Makefile +++ b/drivers/gpu/drm/omapdrm/displays/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_OMAP_ENCODER_OPA362) += encoder-opa362.o -obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c deleted file mode 100644 index f36aa1885d39.. --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Analog TV Connector driver - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen - */ - -#include -#include -#include -#include - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct device *dev; -}; - -#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) - -static int tvc_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void tvc_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static const struct
[PATCH v6 04/51] drm/bridge: Add connector-related bridge operations and data
To support implementation of DRM connectors on top of DRM bridges instead of by bridges, the drm_bridge needs to expose new operations and data: - Output detection, hot-plug notification, mode retrieval and EDID retrieval operations - Bitmask of supported operations - Bridge output type - I2C adapter for DDC access Add and document these. Three new bridge helper functions are also added to handle hot plug notification in a way that is as transparent as possible for the bridges. Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Reviewed-by: Sam Ravnborg --- Changes since v3: - Fix typos Changes since v2: - Add wrappers around the .detect(), .get_modes() and .get_edid() operations - Warn bridge drivers about valid usage of the connector argument to .get_modes() and .get_edid() Changes since v1: - Make .hpd_enable() and .hpd_disable() optional - Rename .lost_hotplug() to .hpd_notify() - Add ddc field to drm_bridge --- drivers/gpu/drm/drm_bridge.c | 162 + include/drm/drm_bridge.h | 192 ++- 2 files changed, 353 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 68ab933ee430..78d26a9a3ee6 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -71,6 +71,8 @@ static LIST_HEAD(bridge_list); */ void drm_bridge_add(struct drm_bridge *bridge) { + mutex_init(>hpd_mutex); + mutex_lock(_lock); list_add_tail(>list, _list); mutex_unlock(_lock); @@ -87,6 +89,8 @@ void drm_bridge_remove(struct drm_bridge *bridge) mutex_lock(_lock); list_del_init(>list); mutex_unlock(_lock); + + mutex_destroy(>hpd_mutex); } EXPORT_SYMBOL(drm_bridge_remove); @@ -919,6 +923,164 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_check); +/** + * drm_bridge_detect - check if anything is attached to the bridge output + * @bridge: bridge control structure + * + * If the bridge supports output detection, as reported by the + * DRM_BRIDGE_OP_DETECT bridge ops flag, call _bridge_funcs.detect for the + * bridge and return the connection status. Otherwise return + * connector_status_unknown. + * + * RETURNS: + * The detection status on success, or connector_status_unknown if the bridge + * doesn't support output detection. + */ +enum drm_connector_status drm_bridge_detect(struct drm_bridge *bridge) +{ + if (!(bridge->ops & DRM_BRIDGE_OP_DETECT)) + return connector_status_unknown; + + return bridge->funcs->detect(bridge); +} +EXPORT_SYMBOL_GPL(drm_bridge_detect); + +/** + * drm_bridge_get_modes - fill all modes currently valid for the sink into the + * @connector + * @bridge: bridge control structure + * @connector: the connector to fill with modes + * + * If the bridge supports output modes retrieval, as reported by the + * DRM_BRIDGE_OP_MODES bridge ops flag, call _bridge_funcs.get_modes to + * fill the connector with all valid modes and return the number of modes + * added. Otherwise return 0. + * + * RETURNS: + * The number of modes added to the connector. + */ +int drm_bridge_get_modes(struct drm_bridge *bridge, +struct drm_connector *connector) +{ + if (!(bridge->ops & DRM_BRIDGE_OP_MODES)) + return 0; + + return bridge->funcs->get_modes(bridge, connector); +} +EXPORT_SYMBOL_GPL(drm_bridge_get_modes); + +/** + * drm_bridge_get_edid - get the EDID data of the connected display + * @bridge: bridge control structure + * @connector: the connector to read EDID for + * + * If the bridge supports output EDID retrieval, as reported by the + * DRM_BRIDGE_OP_EDID bridge ops flag, call _bridge_funcs.get_edid to + * get the EDID and return it. Otherwise return ERR_PTR(-ENOTSUPP). + * + * RETURNS: + * The retrieved EDID on success, or an error pointer otherwise. + */ +struct edid *drm_bridge_get_edid(struct drm_bridge *bridge, +struct drm_connector *connector) +{ + if (!(bridge->ops & DRM_BRIDGE_OP_EDID)) + return ERR_PTR(-ENOTSUPP); + + return bridge->funcs->get_edid(bridge, connector); +} +EXPORT_SYMBOL_GPL(drm_bridge_get_edid); + +/** + * drm_bridge_hpd_enable - enable hot plug detection for the bridge + * @bridge: bridge control structure + * @cb: hot-plug detection callback + * @data: data to be passed to the hot-plug detection callback + * + * Call _bridge_funcs.hpd_enable if implemented and register the given @cb + * and @data as hot plug notification callback. From now on the @cb will be + * called with @data when an output status change is detected by the bridge, + * until hot plug notification gets disabled with drm_bridge_hpd_disable(). + * + * Hot plug detection is supported only if the DRM_BRIDGE_OP_HPD flag is set in + * bridge->ops. This function shall not be called when the flag is not set. + * + * Only one hot
[PATCH v6 08/51] drm/bridge: dumb-vga-dac: Rename driver to simple-bridge
The dumb-vga-dac driver can support simple DRM bridges without being limited to VGA DACs. Rename it to simple-bridge. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Boris Brezillon Acked-by: Maxime Ripard Acked-by: Sam Ravnborg --- arch/arm/configs/davinci_all_defconfig | 2 +- arch/arm/configs/integrator_defconfig| 2 +- arch/arm/configs/multi_v7_defconfig | 2 +- arch/arm/configs/shmobile_defconfig | 2 +- arch/arm/configs/sunxi_defconfig | 2 +- arch/arm/configs/versatile_defconfig | 2 +- drivers/gpu/drm/bridge/Kconfig | 16 drivers/gpu/drm/bridge/Makefile | 2 +- .../bridge/{dumb-vga-dac.c => simple-bridge.c} | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) rename drivers/gpu/drm/bridge/{dumb-vga-dac.c => simple-bridge.c} (99%) diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 231f8973bbb2..b370958b0579 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -160,7 +160,7 @@ CONFIG_VIDEO_TVP514X=m CONFIG_VIDEO_ADV7343=m CONFIG_DRM=m CONFIG_DRM_TILCDC=m -CONFIG_DRM_DUMB_VGA_DAC=m +CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_TINYDRM=m CONFIG_TINYDRM_ST7586=m CONFIG_FB=y diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index 2f0a762dc3a0..a9755c501bec 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -55,7 +55,7 @@ CONFIG_SMC91X=y # CONFIG_KEYBOARD_ATKBD is not set # CONFIG_SERIO_SERPORT is not set CONFIG_DRM=y -CONFIG_DRM_DUMB_VGA_DAC=y +CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_PL111=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_MATROX=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 3f1b96dc7faa..59321917d035 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -667,11 +667,11 @@ CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m CONFIG_DRM_PANEL_RAYDIUM_RM68200=m CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m -CONFIG_DRM_DUMB_VGA_DAC=m CONFIG_DRM_NXP_PTN3460=m CONFIG_DRM_PARADE_PS8622=m CONFIG_DRM_SII902X=m CONFIG_DRM_SII9234=m +CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_TOSHIBA_TC358764=m CONFIG_DRM_I2C_ADV7511=m CONFIG_DRM_I2C_ADV7511_AUDIO=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index bda57cafa2bc..3d7e9a6ca85d 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -123,8 +123,8 @@ CONFIG_VIDEO_ADV7604=y CONFIG_VIDEO_ML86V7667=y CONFIG_DRM=y CONFIG_DRM_RCAR_DU=y -CONFIG_DRM_DUMB_VGA_DAC=y CONFIG_DRM_SII902X=y +CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_I2C_ADV7511=y CONFIG_DRM_I2C_ADV7511_AUDIO=y CONFIG_FB_SH_MOBILE_LCDC=y diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index 3f5d727efc41..17958ff4a2e2 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -100,7 +100,7 @@ CONFIG_RC_DEVICES=y CONFIG_IR_SUNXI=y CONFIG_DRM=y CONFIG_DRM_SUN4I=y -CONFIG_DRM_DUMB_VGA_DAC=y +CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_FB_SIMPLE=y CONFIG_SOUND=y CONFIG_SND=y diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig index fe4d4b596585..767935337413 100644 --- a/arch/arm/configs/versatile_defconfig +++ b/arch/arm/configs/versatile_defconfig @@ -59,7 +59,7 @@ CONFIG_GPIO_PL061=y CONFIG_DRM=y CONFIG_DRM_PANEL_ARM_VERSATILE=y CONFIG_DRM_PANEL_SIMPLE=y -CONFIG_DRM_DUMB_VGA_DAC=y +CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_PL111=y CONFIG_FB_MODE_HELPERS=y CONFIG_BACKLIGHT_CLASS_DEVICE=y diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 20a439199cb8..10073ad88283 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -27,14 +27,6 @@ config DRM_CDNS_DSI Support Cadence DPI to DSI bridge. This is an internal bridge and is meant to be directly embedded in a SoC. -config DRM_DUMB_VGA_DAC - tristate "Dumb VGA DAC Bridge support" - depends on OF - select DRM_KMS_HELPER - help - Support for non-programmable RGB to VGA DAC bridges, such as ADI - ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs. - config DRM_LVDS_CODEC tristate "Transparent LVDS encoders and decoders support" depends on OF @@ -110,6 +102,14 @@ config DRM_SII9234 It is an I2C driver, that detects connection of MHL bridge and starts encapsulation of HDMI signal. +config DRM_SIMPLE_BRIDGE + tristate "Simple DRM bridge support" + depends on OF + select DRM_KMS_HELPER + help + Support for non-programmable DRM bridges, such as ADI ADV7123, TI + THS8134 and THS8135 or passive resistor ladder DACs. + config
[PATCH v6 22/51] drm/omap: dss: Fix output next device lookup in DT
The DSS core looks up the next device connected to an output by traversing the OF graph. It currently hardcodes the local port number to 0, which breaks any output with a different port number (SDI on OMAP3 and any DPI output but the first one). Fix this by repurposing the currently unused of_ports bitmask in omap_dss_device with an of_port output port number, and use it to traverse the OF graph. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c | 2 +- drivers/gpu/drm/omapdrm/displays/connector-hdmi.c | 2 +- drivers/gpu/drm/omapdrm/displays/encoder-opa362.c | 2 +- drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c | 2 +- drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c| 2 +- drivers/gpu/drm/omapdrm/dss/dpi.c | 2 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi4.c| 2 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c| 2 +- drivers/gpu/drm/omapdrm/dss/omapdss.h | 4 ++-- drivers/gpu/drm/omapdrm/dss/output.c | 3 +-- drivers/gpu/drm/omapdrm/dss/sdi.c | 2 +- drivers/gpu/drm/omapdrm/dss/venc.c | 2 +- 13 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index 0d20fab605d7..f36aa1885d39 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -55,7 +55,7 @@ static int tvc_probe(struct platform_device *pdev) dssdev->type = OMAP_DISPLAY_TYPE_VENC; dssdev->display = true; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); + dssdev->of_port = 0; omapdss_display_init(dssdev); omapdss_device_register(dssdev); diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index f5d69d810bb8..37c212491cd3 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -139,7 +139,7 @@ static int hdmic_probe(struct platform_device *pdev) dssdev->type = OMAP_DISPLAY_TYPE_HDMI; dssdev->display = true; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); + dssdev->of_port = 0; dssdev->ops_flags = ddata->hpd_gpio ? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD : 0; diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index b992387ed674..252705222ef1 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -86,7 +86,7 @@ static int opa362_probe(struct platform_device *pdev) dssdev->dev = >dev; dssdev->type = OMAP_DISPLAY_TYPE_VENC; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(1) | BIT(0); + dssdev->of_port = 1; dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1); if (IS_ERR(dssdev->next)) { diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 089105c5aa0a..857ae84cd7d1 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -165,7 +165,7 @@ static int tpd_probe(struct platform_device *pdev) dssdev->dev = >dev; dssdev->type = OMAP_DISPLAY_TYPE_HDMI; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(1) | BIT(0); + dssdev->of_port = 1; dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 3ec6a55e932a..3484b5d4a91c 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -1265,7 +1265,7 @@ static int dsicm_probe(struct platform_device *pdev) dssdev->type = OMAP_DISPLAY_TYPE_DSI; dssdev->display = true; dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); + dssdev->of_port = 0; dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 95147437b990..462ed6f3118a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -625,7 +625,7 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) out->id = OMAP_DSS_OUTPUT_DPI; out->type = OMAP_DISPLAY_TYPE_DPI; out->dispc_channel = dpi_get_channel(dpi); -
[PATCH v6 03/51] drm/edid: Add flag to drm_display_info to identify HDMI sinks
The drm_display_info structure contains many fields related to HDMI sinks, but none that identifies if a sink compliant with CEA-861 (EDID) shall be treated as an HDMI sink or a DVI sink. Add such a flag, and populate it according to section 8.3.3 ("DVI/HDMI Device Discrimination") of the HDMI v1.3 specification. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Reviewed-by: Ville Syrjälä Reviewed-by: Daniel Vetter Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg --- Changes since v1: - Link the is_hdmi field doc with drm_detect_hdmi_monitor() - Add a conversion task in todo.rst --- Documentation/gpu/todo.rst | 14 ++ drivers/gpu/drm/drm_edid.c | 6 ++ include/drm/drm_connector.h | 8 3 files changed, 28 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 370ac678106e..ccf5e8e34222 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -407,6 +407,20 @@ Contact: Daniel Vetter Level: Intermediate +Replace drm_detect_hdmi_monitor() with drm_display_info.is_hdmi +--- + +Once EDID is parsed, the monitor HDMI support information is available through +drm_display_info.is_hdmi. Many drivers still call drm_detect_hdmi_monitor() to +retrieve the same information, which is less efficient. + +Audit each individual driver calling drm_detect_hdmi_monitor() and switch to +drm_display_info.is_hdmi if applicable. + +Contact: Laurent Pinchart, respective driver maintainers + +Level: Intermediate + Core refactorings = diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8f2d5022d0bc..6a2fcfdc7272 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4647,6 +4647,9 @@ EXPORT_SYMBOL(drm_av_sync_delay); * * Parse the CEA extension according to CEA-861-B. * + * Drivers that have added the modes parsed from EDID to drm_display_info + * should use _display_info.is_hdmi instead of calling this function. + * * Return: True if the monitor is HDMI, false if not or unknown. */ bool drm_detect_hdmi_monitor(struct edid *edid) @@ -4881,6 +4884,8 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) struct drm_display_info *info = >display_info; u8 len = cea_db_payload_len(db); + info->is_hdmi = true; + if (len >= 6) info->dvi_dual = db[6] & 1; if (len >= 7) @@ -4949,6 +4954,7 @@ drm_reset_display_info(struct drm_connector *connector) info->cea_rev = 0; info->max_tmds_clock = 0; info->dvi_dual = false; + info->is_hdmi = false; info->has_hdmi_infoframe = false; info->rgb_quant_range_selectable = false; memset(>hdmi, 0, sizeof(info->hdmi)); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index c3bd5262db9c..0df7a95ca5d9 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -434,6 +434,14 @@ struct drm_display_info { */ bool dvi_dual; + /** +* @is_hdmi: True if the sink is an HDMI device. +* +* This field shall be used instead of calling +* drm_detect_hdmi_monitor() when possible. +*/ + bool is_hdmi; + /** * @has_hdmi_infoframe: Does the sink support the HDMI infoframe? */ -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 02/51] drm/connector: Add helper to get a connector type name
drm_connector.c contains a map of connector types (DRM_MODE_CONNECTOR_*) to name strings, but doesn't expose it. This leads to drivers having to store a similar map. Add a new drm_get_connector_type_name() helper function that return a name string for a connector type. Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Reviewed-by: Sam Ravnborg --- drivers/gpu/drm/drm_connector.c | 15 +++ include/drm/drm_connector.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index f632ca05960e..644f0ad10671 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -111,6 +111,21 @@ void drm_connector_ida_destroy(void) ida_destroy(_connector_enum_list[i].ida); } +/** + * drm_get_connector_type_name - return a string for connector type + * @type: The connector type (DRM_MODE_CONNECTOR_*) + * + * Returns: the name of the connector type, or NULL if the type is not valid. + */ +const char *drm_get_connector_type_name(unsigned int type) +{ + if (type < ARRAY_SIZE(drm_connector_enum_list)) + return drm_connector_enum_list[type].name; + + return NULL; +} +EXPORT_SYMBOL(drm_get_connector_type_name); + /** * drm_connector_get_cmdline_mode - reads the user's cmdline mode * @connector: connector to quwery diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b3815371c271..c3bd5262db9c 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1518,6 +1518,7 @@ drm_connector_is_unregistered(struct drm_connector *connector) DRM_CONNECTOR_UNREGISTERED; } +const char *drm_get_connector_type_name(unsigned int connector_type); const char *drm_get_connector_status_name(enum drm_connector_status status); const char *drm_get_subpixel_order_name(enum subpixel_order order); const char *drm_get_dpms_name(int val); -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 06/51] drm/bridge: Extend bridge API to disable connector creation
Most bridge drivers create a DRM connector to model the connector at the output of the bridge. This model is historical and has worked pretty well so far, but causes several issues: - It prevents supporting more complex display pipelines where DRM connector operations are split over multiple components. For instance a pipeline with a bridge connected to the DDC signals to read EDID data, and another one connected to the HPD signal to detect connection and disconnection, will not be possible to support through this model. - It requires every bridge driver to implement similar connector handling code, resulting in code duplication. - It assumes that a bridge will either be wired to a connector or to another bridge, but doesn't support bridges that can be used in both positions very well (although there is some ad-hoc support for this in the analogix_dp bridge driver). In order to solve these issues, ownership of the connector should be moved to the display controller driver (where it can be implemented using helpers provided by the core). Extend the bridge API to allow disabling connector creation in bridge drivers as a first step towards the new model. The new flags argument to the bridge .attach() operation allows instructing the bridge driver to skip creating a connector. Unconditionally set the new flags argument to 0 for now to keep the existing behaviour, and modify all existing bridge drivers to return an error when connector creation is not requested as they don't support this feature yet. The change is based on the following semantic patch, with manual review and edits. @ rule1 @ identifier funcs; identifier fn; @@ struct drm_bridge_funcs funcs = { ..., .attach = fn }; @ depends on rule1 @ identifier rule1.fn; identifier bridge; statement S, S1; @@ int fn( struct drm_bridge *bridge + , enum drm_bridge_attach_flags flags ) { ... when != S + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { + DRM_ERROR("Fix bridge driver to make connector optional!"); + return -EINVAL; + } + S1 ... } @ depends on rule1 @ identifier rule1.fn; identifier bridge, flags; expression E1, E2, E3; @@ int fn( struct drm_bridge *bridge, enum drm_bridge_attach_flags flags ) { <... drm_bridge_attach(E1, E2, E3 + , flags ) ...> } @@ expression E1, E2, E3; @@ drm_bridge_attach(E1, E2, E3 + , 0 ) Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg Reviewed-by: Tomi Valkeinen --- Changes since v5: - Handle parade-ps8640, tc358768 and tidss Changes since v3: - Print error message when DRM_BRIDGE_ATTACH_NO_CONNECTOR can't be honoured - Fix semantic patch to correctly handle drm_bridge_attach() calls from within a bridge .attach() handler - Include drm_print.h in tc358767.c and rcar_lvds.c Changes since v2: - Update commit message to the new flags argument - Replace a leftover 'true' with 0 - Update msm edp and hdmi Changes since v1: - Replace the create_connector boolean with a flags bitmask - Update ingenic driver - Add semantic patch to commit message --- drivers/gpu/drm/arc/arcpgu_hdmi.c | 2 +- .../gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 2 +- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 +++- .../drm/bridge/analogix/analogix-anx6345.c| 8 +++- .../drm/bridge/analogix/analogix-anx78xx.c| 8 +++- .../drm/bridge/analogix/analogix_dp_core.c| 10 -- drivers/gpu/drm/bridge/cdns-dsi.c | 6 -- drivers/gpu/drm/bridge/dumb-vga-dac.c | 8 +++- drivers/gpu/drm/bridge/lvds-codec.c | 5 +++-- .../bridge/megachips-stdp-ge-b850v3-fw.c | 8 +++- drivers/gpu/drm/bridge/nxp-ptn3460.c | 8 +++- drivers/gpu/drm/bridge/panel.c| 8 +++- drivers/gpu/drm/bridge/parade-ps8622.c| 8 +++- drivers/gpu/drm/bridge/parade-ps8640.c| 5 +++-- drivers/gpu/drm/bridge/sii902x.c | 8 +++- drivers/gpu/drm/bridge/sil-sii8620.c | 3 ++- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 -- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 8 +--- drivers/gpu/drm/bridge/tc358764.c | 8 +++- drivers/gpu/drm/bridge/tc358767.c | 9 - drivers/gpu/drm/bridge/tc358768.c | 6 -- drivers/gpu/drm/bridge/thc63lvd1024.c | 5 +++-- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 8 +++- drivers/gpu/drm/bridge/ti-tfp410.c| 8 +++- drivers/gpu/drm/drm_bridge.c | 6 -- drivers/gpu/drm/drm_simple_kms_helper.c | 2 +- drivers/gpu/drm/exynos/exynos_dp.c| 3 ++- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 4 ++-- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 2 +- drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c |
[PATCH v6 12/51] drm/bridge: Add bridge driver for display connectors
Display connectors are modelled in DT as a device node, but have so far been handled manually in several bridge drivers. This resulted in duplicate code in several bridge drivers, with slightly different (and thus confusing) logics. In order to fix this, implement a bridge driver for display connectors. The driver centralises logic for the DVI, HDMI, VGAn composite and S-video connectors and exposes corresponding bridge operations. This driver in itself doesn't solve the issue completely, changes in bridge and display controller drivers are needed to make use of the new connector driver. Signed-off-by: Laurent Pinchart Reviewed-by: Maxime Ripard Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg --- Changes since v5: - Set the drm_bridge.interlace_allowed flag Changes since v3: - Turn probe confirmation message into a dev_dbg() Changes since v2: - Fall back to polling if the GPIO IRQ chip doesn't support edge-triggered interrupts Changes since v1: - Use drm_get_connector_type_name() instead of open-coding display_connector_type_name() - Remove empty .hpd_enable() and .hpd_disable() operations - Set bridge.ddc --- drivers/gpu/drm/bridge/Kconfig | 11 + drivers/gpu/drm/bridge/Makefile| 1 + drivers/gpu/drm/bridge/display-connector.c | 295 + 3 files changed, 307 insertions(+) create mode 100644 drivers/gpu/drm/bridge/display-connector.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 10073ad88283..d63283661850 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -27,6 +27,17 @@ config DRM_CDNS_DSI Support Cadence DPI to DSI bridge. This is an internal bridge and is meant to be directly embedded in a SoC. +config DRM_DISPLAY_CONNECTOR + tristate "Display connector support" + depends on OF + help + Driver for display connectors with support for DDC and hot-plug + detection. Most display controller handle display connectors + internally and don't need this driver, but the DRM subsystem is + moving towards separating connector handling from display controllers + on ARM-based platforms. Saying Y here when this driver is not needed + will not cause any issue. + config DRM_LVDS_CODEC tristate "Transparent LVDS encoders and decoders support" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index b6b2e7029a78..17f1f155e803 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o +obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDP_GE_B850V3_FW) += megachips-stdp-ge-b850v3-fw.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c new file mode 100644 index ..4d278573cdb9 --- /dev/null +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Laurent Pinchart + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct display_connector { + struct drm_bridge bridge; + + struct gpio_desc*hpd_gpio; + int hpd_irq; +}; + +static inline struct display_connector * +to_display_connector(struct drm_bridge *bridge) +{ + return container_of(bridge, struct display_connector, bridge); +} + +static int display_connector_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; +} + +static enum drm_connector_status +display_connector_detect(struct drm_bridge *bridge) +{ + struct display_connector *conn = to_display_connector(bridge); + + if (conn->hpd_gpio) { + if (gpiod_get_value_cansleep(conn->hpd_gpio)) + return connector_status_connected; + else + return connector_status_disconnected; + } + + if (conn->bridge.ddc && drm_probe_ddc(conn->bridge.ddc)) + return connector_status_connected; + + switch (conn->bridge.type) { + case DRM_MODE_CONNECTOR_DVIA: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + /* +* For DVI and HDMI connectors a DDC probe failure indicates +* that no cable is connected. +*/ + return connector_status_disconnected; + + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: +
[PATCH v6 14/51] drm/bridge: panel: Implement bridge connector operations
Implement the newly added bridge connector operations, allowing the usage of drm_bridge_panel with drm_bridge_connector. Signed-off-by: Laurent Pinchart Reviewed-by: Boris Brezillon Reviewed-by: Sam Ravnborg --- Changes since v2: - Use the connector type from the panel instead of hardcoding it to DPI - Rebased on top top of Sam's panel .get_modes() rework --- drivers/gpu/drm/bridge/panel.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 81017b4afe25..bbc212cc53ac 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -60,10 +60,8 @@ static int panel_bridge_attach(struct drm_bridge *bridge, struct drm_connector *connector = _bridge->connector; int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; if (!bridge->encoder) { DRM_ERROR("Missing encoder\n"); @@ -126,6 +124,14 @@ static void panel_bridge_post_disable(struct drm_bridge *bridge) drm_panel_unprepare(panel_bridge->panel); } +static int panel_bridge_get_modes(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); + + return drm_panel_get_modes(panel_bridge->panel, connector); +} + static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { .attach = panel_bridge_attach, .detach = panel_bridge_detach, @@ -133,6 +139,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { .enable = panel_bridge_enable, .disable = panel_bridge_disable, .post_disable = panel_bridge_post_disable, + .get_modes = panel_bridge_get_modes, }; /** @@ -202,6 +209,8 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, #ifdef CONFIG_OF panel_bridge->bridge.of_node = panel->dev->of_node; #endif + panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; + panel_bridge->bridge.type = connector_type; drm_bridge_add(_bridge->bridge); -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 00/51] drm/omap: Replace custom display drivers with drm_bridge and drm_panel
Hello, This patch series is the sixth attempt to (nearly, see [1]) complete the rework of the omapdrm driver to move to drm_bridge and drm_panel. Version 2, available at [2], explains in its long cover letter the rationale for the changes. I won't duplicate it here as it is still valid as-is. Compared to v5, available at [3], this version has been rebased on top of drm-misc-next, and minor bugs have been fixed, including interlaced modes support with VENC. The patches can be found at git://linuxtv.org/pinchartl/media.git omapdrm/bridge/devel [1] The only notable exception is the omapdrm-specific DSI panel driver that implements a large number of custom operations. This is being addressed separately. [2] https://patchwork.kernel.org/cover/11102445/ [3] https://patchwork.kernel.org/cover/11349617/ Laurent Pinchart (51): video: hdmi: Change return type of hdmi_avi_infoframe_init() to void drm/connector: Add helper to get a connector type name drm/edid: Add flag to drm_display_info to identify HDMI sinks drm/bridge: Add connector-related bridge operations and data drm/bridge: Add interlace_allowed flag to drm_bridge drm/bridge: Extend bridge API to disable connector creation drm/bridge: dumb-vga-dac: Rename internal symbols to simple-bridge drm/bridge: dumb-vga-dac: Rename driver to simple-bridge drm/bridge: simple-bridge: Add support for non-VGA bridges drm/bridge: simple-bridge: Add support for enable GPIO drm/bridge: simple-bridge: Add support for the TI OPA362 drm/bridge: Add bridge driver for display connectors drm/bridge: Add driver for the TI TPD12S015 HDMI level shifter drm/bridge: panel: Implement bridge connector operations drm/bridge: tfp410: Replace manual connector handling with bridge drm/bridge: tfp410: Allow operation without drm_connector drm: Add helper to create a connector for a chain of bridges drm/omap: dss: Cleanup DSS ports on initialisation failure drm/omap: Simplify HDMI mode and infoframe configuration drm/omap: Factor out display type to connector type conversion drm/omap: Use the drm_panel_bridge API drm/omap: dss: Fix output next device lookup in DT drm/omap: Add infrastructure to support drm_bridge local to DSS outputs drm/omap: dss: Make omap_dss_device_ops optional drm/omap: hdmi: Allocate EDID in the .read_edid() operation drm/omap: hdmi4: Rework EDID read to isolate data read drm/omap: hdmi5: Rework EDID read to isolate data read drm/omap: hdmi4: Register a drm_bridge for EDID read drm/omap: hdmi5: Register a drm_bridge for EDID read drm/omap: hdmi4: Move mode set, enable and disable operations to bridge drm/omap: hdmi5: Move mode set, enable and disable operations to bridge drm/omap: hdmi4: Implement drm_bridge .hpd_notify() operation drm/omap: dss: Remove .set_hdmi_mode() and .set_infoframe() operations drm/omap: venc: Register a drm_bridge drm/omap: Create connector for bridges drm/omap: Switch the HDMI and VENC outputs to drm_bridge drm/omap: Remove HPD, detect and EDID omapdss operations drm/omap: hdmi: Remove omap_dss_device operations drm/omap: venc: Remove omap_dss_device operations drm/omap: hdmi4: Simplify EDID read drm/omap: hdmi5: Simplify EDID read drm/omap: dpi: Sort includes alphabetically drm/omap: dpi: Reorder functions in sections drm/omap: dpi: Simplify clock setting API drm/omap: dpi: Register a drm_bridge drm/omap: sdi: Sort includes alphabetically drm/omap: sdi: Register a drm_bridge drm/omap: Hardcode omap_connector type to DSI drm/omap: dss: Remove unused omap_dss_device operations drm/omap: dss: Inline the omapdss_display_get() function drm/omap: dss: Remove unused omapdss_of_find_connected_device() function Documentation/gpu/todo.rst| 14 + arch/arm/configs/davinci_all_defconfig| 2 +- arch/arm/configs/integrator_defconfig | 2 +- arch/arm/configs/multi_v7_defconfig | 2 +- arch/arm/configs/omap2plus_defconfig | 7 +- arch/arm/configs/shmobile_defconfig | 2 +- arch/arm/configs/sunxi_defconfig | 2 +- arch/arm/configs/versatile_defconfig | 2 +- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/arc/arcpgu_hdmi.c | 2 +- .../gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 2 +- drivers/gpu/drm/bridge/Kconfig| 29 +- drivers/gpu/drm/bridge/Makefile | 4 +- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 +- .../drm/bridge/analogix/analogix-anx6345.c| 8 +- .../drm/bridge/analogix/analogix-anx78xx.c| 8 +- .../drm/bridge/analogix/analogix_dp_core.c| 10 +- drivers/gpu/drm/bridge/cdns-dsi.c | 6 +- drivers/gpu/drm/bridge/display-connector.c| 295 ++ drivers/gpu/drm/bridge/dumb-vga-dac.c | 300 -- drivers/gpu/drm/bridge/lvds-codec.c | 5 +-
[PATCH v6 05/51] drm/bridge: Add interlace_allowed flag to drm_bridge
In preparation for a connector creation helper based on a chain of bridges, add a flag to the drm_bridge structure to report support for interlaced modes. This will be used to set the connector's interlace_allowed flag. Signed-off-by: Laurent Pinchart --- include/drm/drm_bridge.h | 5 + 1 file changed, 5 insertions(+) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index ba9b7c84f11e..d55bf5f61758 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -712,6 +712,11 @@ struct drm_bridge { * identifies the type of connected display. */ int type; + /** +* @interlace_allowed: Indicate that the bridge can handle interlaced +* modes. +*/ + bool interlace_allowed; /** * @ddc: Associated I2C adapter for DDC access, if any. */ -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v6 01/51] video: hdmi: Change return type of hdmi_avi_infoframe_init() to void
The hdmi_avi_infoframe_init() never needs to return an error, change its return type to void. Signed-off-by: Laurent Pinchart Reviewed-by: Andrzej Hajda Acked-by: Bartlomiej Zolnierkiewicz Reviewed-by: Boris Brezillon Acked-by: Sam Ravnborg --- Changes since v1: - Removed documentation of the return value Cc: Bartlomiej Zolnierkiewicz --- drivers/gpu/drm/drm_edid.c | 5 + drivers/video/hdmi.c | 11 ++- include/linux/hdmi.h | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 097e54a4379e..8f2d5022d0bc 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5449,14 +5449,11 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, { enum hdmi_picture_aspect picture_aspect; u8 vic, hdmi_vic; - int err; if (!frame || !mode) return -EINVAL; - err = hdmi_avi_infoframe_init(frame); - if (err < 0) - return err; + hdmi_avi_infoframe_init(frame); if (mode->flags & DRM_MODE_FLAG_DBLCLK) frame->pixel_repeat = 1; diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 9c82e2a0a411..856a8c4e84a2 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -53,18 +53,14 @@ static void hdmi_infoframe_set_checksum(void *buffer, size_t size) /** * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe * @frame: HDMI AVI infoframe - * - * Returns 0 on success or a negative error code on failure. */ -int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) +void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) { memset(frame, 0, sizeof(*frame)); frame->type = HDMI_INFOFRAME_TYPE_AVI; frame->version = 2; frame->length = HDMI_AVI_INFOFRAME_SIZE; - - return 0; } EXPORT_SYMBOL(hdmi_avi_infoframe_init); @@ -1553,7 +1549,6 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, const void *buffer, size_t size) { const u8 *ptr = buffer; - int ret; if (size < HDMI_INFOFRAME_SIZE(AVI)) return -EINVAL; @@ -1566,9 +1561,7 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0) return -EINVAL; - ret = hdmi_avi_infoframe_init(frame); - if (ret) - return ret; + hdmi_avi_infoframe_init(frame); ptr += HDMI_INFOFRAME_HEADER_SIZE; diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index 9918a6c910c5..9613d796cfb1 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -207,7 +207,7 @@ struct hdmi_drm_infoframe { u16 max_fall; }; -int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); +void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, size_t size); ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[pull] drm/msm: msm-fixes-v5.6-rc2
Hi Dave, Got a few more fixes this time around, so decided to send a dedicated -fixes PR rather than try to route these all through -misc like we do when there are only a couple misc fixes. It mostly boils down to fixing fallout from new hw enablement (sc7180): + fix UBWC on GPU and display side for sc7180 + fix DSI suspend/resume issue encountered on sc7180 + fix some breakage on so called "linux-android" devices (fallout from sc7180/a618 support, not seen earlier due to bootloader/firmware differences) + couple other misc fixes The following changes since commit bb6d3fb354c5ee8d6bde2d576eb7220ea09862b9: Linux 5.6-rc1 (2020-02-09 16:08:48 -0800) are available in the Git repository at: https://gitlab.freedesktop.org/drm/msm.git drm-msm-fixes-2020-02-16 for you to fetch changes up to 8fc7036ee652207ca992fbb9abb64090c355a9e0: drm/msm/dpu: fix BGR565 vs RGB565 confusion (2020-02-13 13:54:12 -0800) Akhil P Oommen (1): drm/msm/a6xx: Correct the highestbank configuration Brian Masney (1): drm/msm/mdp5: rate limit pp done timeout warnings Harigovindan P (2): drm/msm/dsi: save pll state before dsi host is powered off drm/msm/dsi/pll: call vco set rate explicitly John Stultz (1): drm: msm: Fix return type of dsi_mgr_connector_mode_valid for kCFI Jordan Crouse (3): drm/msm/a6xx: Remove unneeded GBIF unhalt drm/msm/a6xx: Update the GMU bus tables for sc7180 drm/msm: Fix a6xx GMU shutdown sequence Kalyan Thota (1): msm:disp:dpu1: add UBWC support for display on SC7180 Rob Clark (1): drm/msm/dpu: fix BGR565 vs RGB565 confusion drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 37 +++-- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 65 ++ drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 85 - drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 4 +- drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c| 58 +++- drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | 4 +- drivers/gpu/drm/msm/dsi/dsi_manager.c | 7 ++- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 -- drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 6 ++ 9 files changed, 170 insertions(+), 100 deletions(-) ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[RFC PATCH v3 5/5] drm/panel: simple: add panel-dpi support
RFC only - not tested yet! The panel-dpi compatible is a fallback that allows the DT to specify the timing. When matching panel-dpi expect the device tree to include the timing information for the display-panel. Background for this change: There are a lot of panels and new models hits the market very often. It is a lost cause trying to chase them all and users of new panels will often find them in situations that the panel they ues are not supported by the kernel. On top of this a lot of panels are customized based on customer specifications. Including the panel timing in the device tree allows for a simple way to describe the actual HW and use this description in a generic way in the kernel. This allows uses of proprietary panels, or panels which are not included in the kernel, to specify the timing in the device tree together with all the other HW descriptions. And thus, using the device tree it is then easy to add support for an otherwise unknown panel. The current support expect panels that do not require any delays for prepare/enable/disable/unprepare. Signed-off-by: Sam Ravnborg Cc: Thierry Reding Cc: Laurent Pinchart Cc: Maxime Ripard Cc: Oleksandr Suvorov --- drivers/gpu/drm/panel/panel-simple.c | 74 +++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 82363d05bad4..188526637398 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -351,6 +351,65 @@ static const struct drm_panel_funcs panel_simple_funcs = { .get_timings = panel_simple_get_timings, }; +static struct panel_desc panel_dpi; + +static int panel_dpi_probe(struct device *dev, + struct panel_simple *panel) +{ + struct display_timing *timing; + const struct device_node *np; + struct panel_desc *desc; + unsigned int bus_flags; + struct videomode vm; + const char *mapping; + int ret; + + np = dev->of_node; + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); + if (!timing) + return -ENOMEM; + + ret = of_get_display_timing(np, "panel-timing", timing); + if (ret < 0) { + dev_err(dev, "%pOF: no panel-timing node found for \"panel-dpi\" binding\n", + np); + return ret; + } + + desc->timings = timing; + desc->num_timings = 1; + + of_property_read_u32(np, "width-mm", >size.width); + of_property_read_u32(np, "height-mm", >size.height); + + of_property_read_string(np, "data-mapping", ); + if (!strcmp(mapping, "rgb24")) + desc->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + else if (!strcmp(mapping, "rgb565")) + desc->bus_format = MEDIA_BUS_FMT_RGB565_1X16; + else if (!strcmp(mapping, "bgr666")) + desc->bus_format = MEDIA_BUS_FMT_RGB666_1X18; + else if (!strcmp(mapping, "lvds666")) + desc->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; + + /* Extract bus_flags from display_timing */ + bus_flags = 0; + vm.flags = timing->flags; + drm_bus_flags_from_videomode(, _flags); + desc->bus_flags = bus_flags; + + /* We do not know the connector for the DT node, so guess it */ + desc->connector_type = DRM_MODE_CONNECTOR_DPI; + + panel->desc = desc; + + return 0; +} + #define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \ (to_check->field.typ >= bounds->field.min && \ to_check->field.typ <= bounds->field.max) @@ -437,8 +496,15 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) return -EPROBE_DEFER; } - if (!of_get_display_timing(dev->of_node, "panel-timing", )) - panel_simple_parse_panel_timing_node(dev, panel, ); + if (desc == _dpi) { + /* Handle the generic panel-dpi binding */ + err = panel_dpi_probe(dev, panel); + if (err) + goto free_ddc; + } else { + if (!of_get_display_timing(dev->of_node, "panel-timing", )) + panel_simple_parse_panel_timing_node(dev, panel, ); + } drm_panel_init(>base, dev, _simple_funcs, desc->connector_type); @@ -3688,6 +3754,10 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "winstar,wf35ltiacd", .data = _wf35ltiacd, + }, { + /* Must be the last entry */ + .compatible = "panel-dpi", + .data = _dpi, }, { /* sentinel */ } -- 2.20.1 ___ dri-devel mailing list
[PATCH v3 0/5] dt-bindings: convert timing + panel-dpi to DT schema
This set of patches convert display-timing.txt to DT schema. To do that add a panel-timing.yaml file that include all the panel-timing properties and use this in panel-common and in display-timings. panel-dpi was also converted so we have no .txt users left of panel-timing in panel/ Everything passed dt_binding_check - and the trivial errors I tried in the examples was all catched during validation. This work was triggered by a patch-set from Oleksandr Suvorov aiming at updating panel-lvds to support panel-dpi. This will make it simple to add additional properties to panel-dpi. Thanks for the quick responses on v2 and likewise the quick feedback on the request for the license change! Highlight from v3 - se individual patches for details. - Added panel-dpi support to panel-simple. We can now add a simple panel just by addding timing parameters in a DT node The patch [5/5] is RFC as test is pending - To support panel-dpi in panel-simple - add a data-mapping property to panel-dpi Highlights from v2 - see individual patches for details. - Got acks for the license change - Simplfied panel-timings bindings - panel-dpi can now be used without a panel specific compatible So panel-dpi can be used as a generic binding for dumb panels Feedback welcome! Sam Sam Ravnborg (5): dt-bindings: display: add panel-timing.yaml dt-bindings: display: convert display-timings to DT schema dt-bindings: display: convert panel-dpi to DT schema dt-bindings: display: add data-mapping to panel-dpi drm/panel: simple: add panel-dpi support .../bindings/display/panel/display-timing.txt | 124 +-- .../bindings/display/panel/display-timings.yaml| 77 +++ .../bindings/display/panel/panel-common.yaml | 15 +- .../bindings/display/panel/panel-dpi.txt | 50 - .../bindings/display/panel/panel-dpi.yaml | 82 .../bindings/display/panel/panel-timing.yaml | 227 + drivers/gpu/drm/panel/panel-simple.c | 74 ++- 7 files changed, 470 insertions(+), 179 deletions(-) ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v3 3/5] dt-bindings: display: convert panel-dpi to DT schema
With panel-timing converted, now convert the single remaining .txt user in panel/ of panel-timing to DT schema. v2: - Drop Thierry as maintainer, as this is not a general panel binding and I have no acks. - Drop requirement for a panel- specific binding - "panel-dpi" is enough - Updated example v3: - added yaml document terminator "..." - always require a specific binding - panel-dpi (based on feedback from Rob) - use "power-supply" for the supply property, and made it mandatory "power-supply" is the standard property for panels Signed-off-by: Sam Ravnborg Cc: Rob Herring Cc: Thierry Reding Cc: Laurent Pinchart Cc: Maxime Ripard --- .../bindings/display/panel/panel-dpi.txt | 50 - .../bindings/display/panel/panel-dpi.yaml | 72 +++ 2 files changed, 72 insertions(+), 50 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/panel/panel-dpi.txt create mode 100644 Documentation/devicetree/bindings/display/panel/panel-dpi.yaml diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.txt b/Documentation/devicetree/bindings/display/panel/panel-dpi.txt deleted file mode 100644 index 6b203bc4d932.. --- a/Documentation/devicetree/bindings/display/panel/panel-dpi.txt +++ /dev/null @@ -1,50 +0,0 @@ -Generic MIPI DPI Panel -== - -Required properties: -- compatible: "panel-dpi" - -Optional properties: -- label: a symbolic name for the panel -- enable-gpios: panel enable gpio -- reset-gpios: GPIO to control the RESET pin -- vcc-supply: phandle of regulator that will be used to enable power to the display -- backlight: phandle of the backlight device - -Required nodes: -- "panel-timing" containing video timings - (Documentation/devicetree/bindings/display/panel/display-timing.txt) -- Video port for DPI input - -Example - -lcd0: display@0 { -compatible = "samsung,lte430wq-f0c", "panel-dpi"; -label = "lcd"; - -backlight = <>; - -port { -lcd_in: endpoint { -remote-endpoint = <_out>; -}; -}; - -panel-timing { -clock-frequency = <920>; -hactive = <480>; -vactive = <272>; -hfront-porch = <8>; -hback-porch = <4>; -hsync-len = <41>; -vback-porch = <2>; -vfront-porch = <4>; -vsync-len = <10>; - -hsync-active = <0>; -vsync-active = <0>; -de-active = <1>; -pixelclk-active = <1>; -}; -}; diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml new file mode 100644 index ..40079fc24a63 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-dpi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic MIPI DPI Panel + +maintainers: + - Sam Ravnborg + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: +description: + Shall contain a panel specific compatible and "panel-dpi" + in that order. +items: + - {} + - const: panel-dpi + + backlight: true + enable-gpios: true + height-mm: true + label: true + panel-timing: true + port: true + power-supply: true + reset-gpios: true + width-mm: true + +required: + - panel-timing + - power-supply + +additionalProperties: false + +examples: + - | +panel@0 { +compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; +label = "osddisplay"; +power-supply = <_supply>; + +backlight = <>; + +port { +lcd_in: endpoint { +remote-endpoint = <_out>; +}; +}; +panel-timing { +clock-frequency = <920>; +hactive = <800>; +vactive = <480>; +hfront-porch = <8>; +hback-porch = <4>; +hsync-len = <41>; +vback-porch = <2>; +vfront-porch = <4>; +vsync-len = <10>; + +hsync-active = <0>; +vsync-active = <0>; +de-active = <1>; +pixelclk-active = <1>; +}; +}; + +... -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v3 1/5] dt-bindings: display: add panel-timing.yaml
Add meta-schema variant of panel-timing and reference it from panel-common.yaml. Part of this came form other files with other licenses - original commits: cc3f414cf2e4 ("video: add of helper for display timings/videomode") 86f46565dff3 ("dt-bindings: display: display-timing: Add property to configure sync drive edge") 9cad9c95d7e8 ("Documentation: DocBook DRM framework documentation") The original authors acked the license change to: (GPL-2.0-only OR BSD-2-Clause) v2: - Got OK from original authors for re-license Huge thanks for the quick replies! - Typo fixes (Oleksandr) - Drop -array variant when not needed (Maxime) - Replace oneOf:... with enum (Maxime) - Drop type from clock-frequency (Rob) - Drop "|" when not needed (Rob) v3: - Added comment to acks that are only for the license change - Add yaml document terminator "..." - Updated description (removed reference to native-mode) Signed-off-by: Sam Ravnborg Acked-by: Laurent Pinchart [license change] Acked-by: Peter Ujfalusi [license change] Acked-by: Steffen Trumtrar [license change] Acked-by: Philipp Zabel [license change] Reviewed-by: Rob Herring Cc: Thierry Reding Cc: Oleksandr Suvorov Cc: Maxime Ripard Cc: devicet...@vger.kernel.org --- .../bindings/display/panel/panel-common.yaml | 7 +- .../bindings/display/panel/panel-timing.yaml | 227 ++ 2 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/panel-timing.yaml diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.yaml b/Documentation/devicetree/bindings/display/panel/panel-common.yaml index ef8d8cdfcede..8070c439adbd 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-common.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-common.yaml @@ -54,13 +54,12 @@ properties: # Display Timings panel-timing: -type: object description: Most display panels are restricted to a single resolution and require specific display timings. The panel-timing subnode expresses those - timings as specified in the timing subnode section of the display timing - bindings defined in - Documentation/devicetree/bindings/display/panel/display-timing.txt. + timings. +allOf: + - $ref: panel-timing.yaml# # Connectivity port: diff --git a/Documentation/devicetree/bindings/display/panel/panel-timing.yaml b/Documentation/devicetree/bindings/display/panel/panel-timing.yaml new file mode 100644 index ..bd558ad7891f --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/panel-timing.yaml @@ -0,0 +1,227 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-timing.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: panel timing bindings + +maintainers: + - Thierry Reding + - Sam Ravnborg + +description: | + There are different ways of describing the timing data of a panel. The + devicetree representation corresponds to the one commonly found in datasheets + for panels. + + The parameters are defined as seen in the following illustration. + + +--+-+--+---+ + | |^| | | + | ||vback_porch | | | + | |v| | | + +--###--+---+ + | #^# | | + | #|# | | + | hback #|# hfront | hsync | + | porch #| hactive # porch | len | + |<>#<---+--->#<>|<->| + | #|# | | + | #|vactive # | | + | #|# | | + | #v# | | + +--###--+---+ + | |^| | | + | ||vfront_porch| | | + | |v| | | + +--+-+--+---+ + | |^| | | + | ||vsync_len | | | + | |v| | | + +--+-+--+---+ + + + The following is the panel timings shown with time on the x-axis. +
[PATCH v3 4/5] dt-bindings: display: add data-mapping to panel-dpi
Add data-mapping property that can be used to specify the media format used for the connection betwwen the display controller (connector) and the panel. Signed-off-by: Sam Ravnborg --- .../devicetree/bindings/display/panel/panel-dpi.yaml | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml index 40079fc24a63..6a03d2449701 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml @@ -21,6 +21,16 @@ properties: - {} - const: panel-dpi + data-mapping: +enum: + - rgb24 + - rgb565 + - bgr666 + - lvds666 +description: | + Describes the media format, how the display panel is connected + to the display interface. + backlight: true enable-gpios: true height-mm: true @@ -43,7 +53,7 @@ examples: compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; label = "osddisplay"; power-supply = <_supply>; - +data-mapping = "lvds666"; backlight = <>; port { -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v3 2/5] dt-bindings: display: convert display-timings to DT schema
Add display-timings.yaml - that references panel-timings.yaml. display-timings.yaml will be used for display bindings when they are converted to meta-schema format. For now the old display-timing.txt points to the new display-timings.yaml - and all users are left as-is. v2: - Updated native-mode description v3: - Simpler "^timing" pattern (Rob) - timing node is of type object (Rob) - added display-timings to panel-common.yaml - added yaml document terminator "..." Signed-off-by: Sam Ravnborg Reviewed-by: Rob Herring Cc: Laurent Pinchart Cc: Thierry Reding Cc: Oleksandr Suvorov Cc: devicet...@vger.kernel.org --- .../bindings/display/panel/display-timing.txt | 124 +- .../display/panel/display-timings.yaml| 77 +++ .../bindings/display/panel/panel-common.yaml | 8 ++ 3 files changed, 86 insertions(+), 123 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/display-timings.yaml diff --git a/Documentation/devicetree/bindings/display/panel/display-timing.txt b/Documentation/devicetree/bindings/display/panel/display-timing.txt index 78222ced1874..7f55ad4a40c4 100644 --- a/Documentation/devicetree/bindings/display/panel/display-timing.txt +++ b/Documentation/devicetree/bindings/display/panel/display-timing.txt @@ -1,123 +1 @@ -display-timing bindings -=== - -display-timings node - - -required properties: - - none - -optional properties: - - native-mode: The native mode for the display, in case multiple modes are - provided. When omitted, assume the first node is the native. - -timing subnode --- - -required properties: - - hactive, vactive: display resolution - - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters - in pixels - vfront-porch, vback-porch, vsync-len: vertical display timing parameters in - lines - - clock-frequency: display clock in Hz - -optional properties: - - hsync-active: hsync pulse is active low/high/ignored - - vsync-active: vsync pulse is active low/high/ignored - - de-active: data-enable pulse is active low/high/ignored - - pixelclk-active: with - - active high = drive pixel data on rising edge/ - sample data on falling edge - - active low = drive pixel data on falling edge/ - sample data on rising edge - - ignored = ignored - - syncclk-active: with - - active high = drive sync on rising edge/ - sample sync on falling edge of pixel - clock - - active low = drive sync on falling edge/ - sample sync on rising edge of pixel - clock - - omitted = same configuration as pixelclk-active - - interlaced (bool): boolean to enable interlaced mode - - doublescan (bool): boolean to enable doublescan mode - - doubleclk (bool): boolean to enable doubleclock mode - -All the optional properties that are not bool follow the following logic: -<1>: high active -<0>: low active -omitted: not used on hardware - -There are different ways of describing the capabilities of a display. The -devicetree representation corresponds to the one commonly found in datasheets -for displays. If a display supports multiple signal timings, the native-mode -can be specified. - -The parameters are defined as: - - +--+-+--+---+ - | |^| | | - | ||vback_porch | | | - | |v| | | - +--###--+---+ - | #^# | | - | #|# | | - | hback #|# hfront | hsync | - | porch #| hactive # porch | len | - |<>#<---+--->#<>|<->| - | #|# | | - | #|vactive # | | - | #|# | | - | #v# | | - +--###--+---+ - | |^| | | - | ||vfront_porch| | | - | |v| | | - +--+-+--+---+ -
[RFC 2/9] mfd: Add driver for Multifunction USB Device
A Multifunction USB Device is a device that supports functions like gpio and display or any other function that can be represented as a USB regmap. Interrupts over USB is also supported if such an endpoint is present. Signed-off-by: Noralf Trønnes --- drivers/mfd/Kconfig | 8 + drivers/mfd/Makefile| 1 + drivers/mfd/mud.c | 580 include/linux/mfd/mud.h | 16 ++ 4 files changed, 605 insertions(+) create mode 100644 drivers/mfd/mud.c create mode 100644 include/linux/mfd/mud.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 52818dbcfe1f..9950794d907e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1968,6 +1968,14 @@ config MFD_STMFX additional drivers must be enabled in order to use the functionality of the device. +config MFD_MUD + tristate "Multifunction USB Device core driver" + depends on USB + select MFD_CORE + select REGMAP_USB + help + Select this to get support for the Multifunction USB Device. + menu "Multimedia Capabilities Port drivers" depends on ARCH_SA1100 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 29e6767dd60c..0adfab9afaed 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -255,4 +255,5 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_STMFX)+= stmfx.o obj-$(CONFIG_MFD_RPISENSE_CORE)+= rpisense-core.o +obj-$(CONFIG_MFD_MUD) += mud.o diff --git a/drivers/mfd/mud.c b/drivers/mfd/mud.c new file mode 100644 index ..f5f31478656d --- /dev/null +++ b/drivers/mfd/mud.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Temporary debugging aid */ +#undef dev_dbg +#define dev_dbg dev_info + +#define mdebug(fmt, ...) \ +do { \ + if (1) \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) + +struct mud_irq_event { + struct list_head node; + DECLARE_BITMAP(status, REGMAP_USB_MAX_MAPS); +}; + +struct mud_irq { + struct irq_domain *domain; + unsigned int num_irqs; + + struct workqueue_struct *workq; + struct work_struct work; + struct urb *urb; + + spinlock_t lock; /* Protect the values below */ + unsigned long *mask; + u16 tag; + struct list_head eventlist; + + unsigned int stats_illegal; + unsigned int stats_already_seen; + unsigned int stats_lost; +}; + +struct mud_device { + struct usb_device *usb; + struct mud_irq *mirq; + struct mfd_cell *cells; + unsigned int num_cells; +}; + +static void mud_irq_work(struct work_struct *work) +{ + struct mud_irq *mirq = container_of(work, struct mud_irq, work); + struct mud_irq_event *event; + unsigned long n, flags; + unsigned int irq; + + mdebug("%s: IN\n", __func__); + + while (true) { + spin_lock_irqsave(>lock, flags); + event = list_first_entry_or_null(>eventlist, struct mud_irq_event, node); + if (event) { + list_del(>node); + mdebug("status: %*pb\n", mirq->num_irqs, event->status); + bitmap_and(event->status, event->status, mirq->mask, mirq->num_irqs); + } + spin_unlock_irqrestore(>lock, flags); + if (!event) + break; + + for_each_set_bit(n, event->status, mirq->num_irqs) { + irq = irq_find_mapping(mirq->domain, n); + mdebug("n=%lu irq=%u\n", n, irq); + if (irq) + handle_nested_irq(irq); + } + + kfree(event); + } + + mdebug("%s: OUT\n", __func__); +} + +#define BYTES_PER_LONG (BITS_PER_LONG / BITS_PER_BYTE) + +static void mud_irq_queue(struct urb *urb) +{ + u8 *buf = urb->transfer_buffer + sizeof(u16); + struct mud_irq *mirq = urb->context; + struct device *dev = >dev->dev; + struct mud_irq_event *event = NULL; + unsigned int i, tag, diff; + unsigned long flags; + + if (urb->actual_length != urb->transfer_buffer_length) { + dev_err_once(dev, "Interrupt packet wrong length: %u\n", +urb->actual_length); + mirq->stats_illegal++; + return; + } + + spin_lock_irqsave(>lock, flags); + + tag = le16_to_cpup(urb->transfer_buffer); + if (tag == mirq->tag) { + dev_dbg(dev, "Interrupt tag=%u already seen,
[RFC 7/9] drm: Add Multifunction USB Device display driver
The Multifunction USB Device has optional support for displays. LZ4 compression is used if the device supports it. The driver is MIT licensed in the hope that parts of it can be used on the BSD's. Signed-off-by: Noralf Trønnes --- drivers/gpu/drm/Kconfig |2 + drivers/gpu/drm/Makefile |1 + drivers/gpu/drm/mud/Kconfig | 15 + drivers/gpu/drm/mud/Makefile |3 + drivers/gpu/drm/mud/mud_drm.c | 1198 + drivers/gpu/drm/mud/mud_drm.h | 137 6 files changed, 1356 insertions(+) create mode 100644 drivers/gpu/drm/mud/Kconfig create mode 100644 drivers/gpu/drm/mud/Makefile create mode 100644 drivers/gpu/drm/mud/mud_drm.c create mode 100644 drivers/gpu/drm/mud/mud_drm.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index bfdadc3667e0..8ddc0d0e82cc 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -387,6 +387,8 @@ source "drivers/gpu/drm/aspeed/Kconfig" source "drivers/gpu/drm/mcde/Kconfig" +source "drivers/gpu/drm/mud/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACY diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 9f1c7c486f88..5a5eab598d39 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -122,3 +122,4 @@ obj-$(CONFIG_DRM_LIMA) += lima/ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ +obj-y += mud/ diff --git a/drivers/gpu/drm/mud/Kconfig b/drivers/gpu/drm/mud/Kconfig new file mode 100644 index ..440e994ca0a2 --- /dev/null +++ b/drivers/gpu/drm/mud/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config DRM_MUD + tristate "Multifunction USB Device Display" + depends on DRM && USB && MFD_MUD + select LZ4_COMPRESS + select DRM_KMS_HELPER + + select DRM_GEM_CMA_HELPER + select DRM_GEM_SHMEM_HELPER + + select BACKLIGHT_CLASS_DEVICE + help +This is a KMS driver for Multifunction USB Device displays or display +adapters. diff --git a/drivers/gpu/drm/mud/Makefile b/drivers/gpu/drm/mud/Makefile new file mode 100644 index ..d5941d33bcd9 --- /dev/null +++ b/drivers/gpu/drm/mud/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_DRM_MUD) += mud_drm.o diff --git a/drivers/gpu/drm/mud/mud_drm.c b/drivers/gpu/drm/mud/mud_drm.c new file mode 100644 index ..51ba756940fd --- /dev/null +++ b/drivers/gpu/drm/mud/mud_drm.c @@ -0,0 +1,1198 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +#include "mud_drm.h" + +/* + * freerun: Userspace is told that the flush happended immediately, before the worker has begun. + * Useful if the rendering loop handles several displays one after the other. + * steady: Notify userspace at a fixed interval (FPS). + * inline: Do flushing before returning to userspace from the update function. + * + * Rationale: + * In a worst case scenario a full buffer update can take 1 second. + * + * I believe Wayland/Weston has one rendering loop per display/device and if so doesn't need any special treatment. + * For Xorg I got the impression that it runs everything in one loop and one slow device will slow everything down. + * For games on embedded I believe maybe a fixed rate is best. + * + * I'd appreciate any insight into how userspace operates in this regard. + */ +static int pageflip; +module_param(pageflip, int, 0644); +MODULE_PARM_DESC(pageflip, "pageflip strategy: 0=freerun, 1=steady, 2=inline [default=0]"); + +#define MUD_DRM_PAGEFLIP_FREERUN0 +#define MUD_DRM_PAGEFLIP_STEADY 1 +#define MUD_DRM_PAGEFLIP_INLINE 2 + +struct mud_drm_damage { + struct list_head list; + struct drm_rect rect; + ktime_t time; +}; + +struct mud_drm_device { + struct drm_device drm; + struct drm_simple_display_pipe pipe; + struct usb_device *usb; + struct regmap *regmap; + + void *buf; + size_t buf_len; + + struct mutex lock; + + bool run; + struct workqueue_struct *workq; + struct work_struct work; + wait_queue_head_t waitq; + struct drm_framebuffer *fb; + struct list_head damagelist; + unsigned int average_pageflip_ms; +}; + +static inline struct mud_drm_device *to_mud_drm_device(struct drm_device *drm) +{ + return container_of(drm, struct mud_drm_device, drm); +} + +/**/ +/* TODO: Move to drm_encoder.c */ + +static void drm_encoder_dummy_cleanup(struct drm_encoder
[RFC 5/9] usb: gadget: function: mud: Add gpio support
Add optional gpio functionality to the Multifunction USB Device. Signed-off-by: Noralf Trønnes --- drivers/usb/gadget/Kconfig | 14 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_mud_pins.c | 962 +++ 3 files changed, 978 insertions(+) create mode 100644 drivers/usb/gadget/function/f_mud_pins.c diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9551876ffe08..d6285146ec76 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -219,6 +219,9 @@ config USB_F_TCM config USB_F_MUD tristate +config USB_F_MUD_PINS + tristate + # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -493,6 +496,17 @@ menuconfig USB_CONFIGFS_F_MUD help Core support for the Multifunction USB Device. +if USB_F_MUD + +config USB_CONFIGFS_F_MUD_PINS + bool "Multifunction USB Device GPIO" + depends on PINCTRL + select USB_F_MUD_PINS + help + GPIO support for the Multifunction USB Device. + +endif # USB_F_MUD + choice tristate "USB Gadget precomposed configurations" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index b6e31b511521..2e24227fcc12 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -52,3 +52,5 @@ usb_f_tcm-y := f_tcm.o obj-$(CONFIG_USB_F_TCM)+= usb_f_tcm.o usb_f_mud-y:= f_mud.o mud_regmap.o obj-$(CONFIG_USB_F_MUD)+= usb_f_mud.o +usb_f_mud_pins-y := f_mud_pins.o +obj-$(CONFIG_USB_F_MUD_PINS) += usb_f_mud_pins.o diff --git a/drivers/usb/gadget/function/f_mud_pins.c b/drivers/usb/gadget/function/f_mud_pins.c new file mode 100644 index ..b3466804ad5e --- /dev/null +++ b/drivers/usb/gadget/function/f_mud_pins.c @@ -0,0 +1,962 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f_mud.h" +#include "../../../pinctrl/pinctrl-mud.h" + +/* + * Even though the host side is a pinctrl driver, the device side is a gpio consumer. + * That's because not all boards have a pin controller. + */ + +/* Temporary debugging aid */ +#define fmdebug(fmt, ...) \ +do { \ + if (1) \ + printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ +} while (0) + +static DEFINE_IDA(f_mud_pins_ida); + +struct f_mud_pins_cell_item { + struct list_head node; + unsigned int index; + struct config_group group; + + struct mutex lock; /* Protect the values below */ + int refcnt; + + const char *name; + const char *chip; + int offset; +}; + +static inline struct f_mud_pins_cell_item *ci_to_f_mud_pins_cell_item(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_mud_pins_cell_item, group); +} + +struct f_mud_pins_lookup_device { + struct device dev; + int id; + struct f_mud_cell *cell; + struct gpiod_lookup_table *lookup; + const char **names; + unsigned int count; +}; + +struct f_mud_pins_pin { + struct f_mud_pins_cell *parent; + unsigned int index; + struct gpio_desc *gpio; + unsigned long dflags; + unsigned int debounce; +#define DEBOUNCE_NOT_SET UINT_MAX + bool config_requested; + int irq; + int irqflags; +}; + +struct f_mud_pins_cell { + struct f_mud_cell cell; + + struct mutex lock; /* Protect refcnt and items */ + int refcnt; + struct list_head items; + + struct f_mud_pins_lookup_device *ldev; + struct f_mud_pins_pin *pins; + unsigned int count; + spinlock_t irq_status_lock; + unsigned long *irq_status; +}; + +static inline struct f_mud_pins_cell *ci_to_f_mud_pins_cell(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_mud_pins_cell, cell.group); +} + +static inline struct f_mud_pins_cell *cell_to_pcell(struct f_mud_cell *cell) +{ + return container_of(cell, struct f_mud_pins_cell, cell); +} + +static irqreturn_t f_mud_pins_gpio_irq_thread(int irq, void *p) +{ + struct f_mud_pins_pin *pin = p; + struct f_mud_pins_cell *pcell = pin->parent; + + spin_lock(>irq_status_lock); + set_bit(pin->index, pcell->irq_status); + spin_unlock(>irq_status_lock); + + fmdebug("%s(index=%u): irq_status=%*pb\n", __func__, pin->index, + pcell->count, pcell->irq_status); + + f_mud_irq(pcell->ldev->cell); + + return IRQ_HANDLED; +} + +static int f_mud_pins_gpio_irq_request(struct f_mud_pins_cell
[RFC 3/9] usb: gadget: function: Add Multifunction USB Device support
This is the gadget side of the mfd host driver. It provides a USB function that drivers can hook into providing functions like gpio and display as regmaps to the host. These drivers are configured through configfs. Signed-off-by: Noralf Trønnes --- drivers/usb/gadget/Kconfig | 10 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_mud.c | 913 ++ drivers/usb/gadget/function/f_mud.h | 210 + drivers/usb/gadget/function/mud_regmap.c | 936 +++ 5 files changed, 2071 insertions(+) create mode 100644 drivers/usb/gadget/function/f_mud.c create mode 100644 drivers/usb/gadget/function/f_mud.h create mode 100644 drivers/usb/gadget/function/mud_regmap.c diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 02ff850278b1..9551876ffe08 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -216,6 +216,9 @@ config USB_F_PRINTER config USB_F_TCM tristate +config USB_F_MUD + tristate + # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -483,6 +486,13 @@ config USB_CONFIGFS_F_TCM Both protocols can work on USB2.0 and USB3.0. UAS utilizes the USB 3.0 feature called streams support. +menuconfig USB_CONFIGFS_F_MUD + bool "Multifunction USB Device" + depends on USB_CONFIGFS + select USB_F_MUD + help + Core support for the Multifunction USB Device. + choice tristate "USB Gadget precomposed configurations" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 5d3a6cf02218..b6e31b511521 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -50,3 +50,5 @@ usb_f_printer-y := f_printer.o obj-$(CONFIG_USB_F_PRINTER)+= usb_f_printer.o usb_f_tcm-y:= f_tcm.o obj-$(CONFIG_USB_F_TCM)+= usb_f_tcm.o +usb_f_mud-y:= f_mud.o mud_regmap.o +obj-$(CONFIG_USB_F_MUD)+= usb_f_mud.o diff --git a/drivers/usb/gadget/function/f_mud.c b/drivers/usb/gadget/function/f_mud.c new file mode 100644 index ..b15a571d2e5d --- /dev/null +++ b/drivers/usb/gadget/function/f_mud.c @@ -0,0 +1,913 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f_mud.h" + +/** + * DOC: overview + * + * f_mud is the device side counterpart to drivers/mfd/mud. + * It combines the regmap and mfd cell abstraction on the host side into one cell + * driver on the device side: @f_mud_cell_ops. The reason for not using the + * regmap library here is so drivers can do compression directly with their own + * buffers without going through a temporary buffer. + */ + +/* Temporary debugging aid */ +static unsigned int debug = 8; + +#define fmdebug(level, fmt, ...) \ +do { \ + if ((level) <= debug) \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) + +struct f_mud { + struct usb_function func; + u8 interface_id; + struct mud_regmap *mreg; + + struct f_mud_cell **cells; + unsigned int num_cells; + + int interrupt_interval_ms; + + spinlock_t irq_lock; + bool irq_enabled; + struct usb_ep *irq_ep; + struct usb_request *irq_req; + u16 int_tag; + unsigned long *irq_status; + bool irq_queued; +}; + +static inline struct f_mud *func_to_f_mud(struct usb_function *f) +{ + return container_of(f, struct f_mud, func); +} + +struct f_mud_opts { + struct usb_function_instance func_inst; + struct mutex lock; + int refcnt; + + int interrupt_interval_ms; + + struct list_head cells; +}; + +static inline struct f_mud_opts *ci_to_f_mud_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_mud_opts, + func_inst.group); +} + +static DEFINE_MUTEX(f_mud_cell_ops_list_mutex); +static LIST_HEAD(f_mud_cell_ops_list); + +struct f_mud_cell_ops_list_item { + struct list_head list; + const struct f_mud_cell_ops *ops; + unsigned int refcnt; +}; + +static struct f_mud_cell_ops_list_item *f_mud_cell_item_lookup(const char *name) +{ + struct f_mud_cell_ops_list_item *item; + + list_for_each_entry(item, _mud_cell_ops_list, list) { + if (!strcmp(name, item->ops->name)) + return item; + } + + return NULL; +} + +/** + * f_mud_cell_register() - Register a cell driver + * @ops: Cell operations structure + * + * This function registers a cell driver for use in a gadget. + * + * Returns: + * Zero on success, negative
[RFC 8/9] drm/client: Add drm_client_init_from_id() and drm_client_modeset_set()
drm_client_init_from_id() provides a way for clients to add a client based on the minor. drm_client_modeset_set() provides a way to set the modeset for clients that handles connectors and display mode on their own. Signed-off-by: Noralf Trønnes --- drivers/gpu/drm/drm_client.c | 37 drivers/gpu/drm/drm_client_modeset.c | 52 include/drm/drm_client.h | 4 +++ 3 files changed, 93 insertions(+) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index d9a2e3695525..dbd73fe8d987 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -112,6 +112,43 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, } EXPORT_SYMBOL(drm_client_init); +/** + * drm_client_init_from_id - Initialise a DRM client + * @minor_id: DRM minor id + * @client: DRM client + * @name: Client name + * @funcs: DRM client functions (optional) + * + * This function looks up the drm_device using the minor id and initializes the client. + * It also registeres the client to avoid a possible race with DRM device unregister. + * + * See drm_client_init() and drm_client_register(). + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_client_init_from_id(unsigned int minor_id, struct drm_client_dev *client, + const char *name, const struct drm_client_funcs *funcs) +{ + struct drm_minor *minor; + int ret; + + minor = drm_minor_acquire(minor_id); + if (IS_ERR(minor)) + return PTR_ERR(minor); + + mutex_lock(>dev->clientlist_mutex); + ret = drm_client_init(minor->dev, client, name, funcs); + if (!ret) + list_add(>list, >dev->clientlist); + mutex_unlock(>dev->clientlist_mutex); + + drm_minor_release(minor); + + return ret; +} +EXPORT_SYMBOL(drm_client_init_from_id); + /** * drm_client_register - Register client * @client: DRM client diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 895b73f23079..9396267e646c 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -807,6 +807,58 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, } EXPORT_SYMBOL(drm_client_modeset_probe); +/** + * drm_client_modeset_set() - Set modeset + * @client: DRM client + * @connector: Connector + * @mode: Display mode + * @fb: Framebuffer + * + * This function releases any current modeset info and sets the new modeset in + * the client's modeset array. + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_client_modeset_set(struct drm_client_dev *client, struct drm_connector *connector, + struct drm_display_mode *mode, struct drm_framebuffer *fb) +{ + struct drm_mode_set *modeset; + int ret = -ENOENT; + + mutex_lock(>modeset_mutex); + + drm_client_modeset_release(client); + + if (!connector || !mode || !fb) { + ret = 0; + goto unlock; + } + + drm_client_for_each_modeset(modeset, client) { + if (!connector_has_possible_crtc(connector, modeset->crtc)) + continue; + + modeset->mode = drm_mode_duplicate(client->dev, mode); + if (!modeset->mode) { + ret = -ENOMEM; + break; + } + + drm_connector_get(connector); + modeset->connectors[modeset->num_connectors++] = connector; + + modeset->fb = fb; + ret = 0; + break; + } +unlock: + mutex_unlock(>modeset_mutex); + + return ret; +} +EXPORT_SYMBOL(drm_client_modeset_set); + /** * drm_client_rotation() - Check the initial rotation value * @modeset: DRM modeset diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index 5cf2c5dd8b1e..97e4157d07c5 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -104,6 +104,8 @@ struct drm_client_dev { int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, const char *name, const struct drm_client_funcs *funcs); +int drm_client_init_from_id(unsigned int minor_id, struct drm_client_dev *client, + const char *name, const struct drm_client_funcs *funcs); void drm_client_release(struct drm_client_dev *client); void drm_client_register(struct drm_client_dev *client); @@ -155,6 +157,8 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer); int drm_client_modeset_create(struct drm_client_dev *client); void drm_client_modeset_free(struct drm_client_dev *client); int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height); +int drm_client_modeset_set(struct drm_client_dev *client, struct drm_connector
[RFC 9/9] usb: gadget: function: mud: Add display support
Add optional display functionality to the Multifunction USB Device. The bulk of the code is placed in the drm subsystem since it's reaching into the drm internals. Signed-off-by: Noralf Trønnes --- drivers/gpu/drm/mud/Kconfig | 3 + drivers/gpu/drm/mud/Makefile| 1 + drivers/gpu/drm/mud/mud_drm_gadget.c| 889 drivers/usb/gadget/Kconfig | 12 + drivers/usb/gadget/function/Makefile| 2 + drivers/usb/gadget/function/f_mud_drm.c | 181 + 6 files changed, 1088 insertions(+) create mode 100644 drivers/gpu/drm/mud/mud_drm_gadget.c create mode 100644 drivers/usb/gadget/function/f_mud_drm.c diff --git a/drivers/gpu/drm/mud/Kconfig b/drivers/gpu/drm/mud/Kconfig index 440e994ca0a2..b3c6d073cc9c 100644 --- a/drivers/gpu/drm/mud/Kconfig +++ b/drivers/gpu/drm/mud/Kconfig @@ -13,3 +13,6 @@ config DRM_MUD help This is a KMS driver for Multifunction USB Device displays or display adapters. + +config DRM_MUD_GADGET + tristate diff --git a/drivers/gpu/drm/mud/Makefile b/drivers/gpu/drm/mud/Makefile index d5941d33bcd9..56d2c39ac0eb 100644 --- a/drivers/gpu/drm/mud/Makefile +++ b/drivers/gpu/drm/mud/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-or-later obj-$(CONFIG_DRM_MUD) += mud_drm.o +obj-$(CONFIG_DRM_MUD_GADGET) += mud_drm_gadget.o diff --git a/drivers/gpu/drm/mud/mud_drm_gadget.c b/drivers/gpu/drm/mud/mud_drm_gadget.c new file mode 100644 index ..9395d8b7cefe --- /dev/null +++ b/drivers/gpu/drm/mud/mud_drm_gadget.c @@ -0,0 +1,889 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mud_drm.h" + +/* Temporary debugging aid */ +static unsigned int debug = 8; + +#define pdebug(level, fmt, ...)\ + if (level <= debug) \ + printk(KERN_DEBUG fmt, ##__VA_ARGS__) + +struct mud_drm_gadget_connector { + struct drm_connector *connector; + u32 capabilities; + enum drm_connector_status status; + unsigned int width_mm; + unsigned int height_mm; + void *edid; + size_t edid_len; + struct mud_drm_display_mode *modes; + unsigned int num_modes; +}; + +struct mud_drm_gadget { + struct drm_client_dev client; + + struct mud_drm_gadget_connector *connectors; + unsigned int connector_count; + + const u32 *formats; + unsigned int format_count; + + struct drm_connector *current_connector; + struct mud_drm_display_mode current_mode; + u32 current_format; + + unsigned int rect_x; + unsigned int rect_y; + unsigned int rect_width; + unsigned int rect_height; + + struct drm_client_buffer *buffer; + struct drm_client_buffer *buffer_check; + bool check_ok; + + size_t max_transfer_size; + void *work_buf; +}; + +static int mud_drm_gadget_probe_connector(struct mud_drm_gadget_connector *mconn) +{ + struct drm_connector *connector = mconn->connector; + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode; + unsigned int i = 0; + int ret = 0; + void *edid; + + pdebug(2, "%s:\n", __func__); + + mutex_lock(>mode_config.mutex); + + connector->funcs->fill_modes(connector, +dev->mode_config.max_width, +dev->mode_config.max_height); + + mconn->width_mm = connector->display_info.width_mm; + mconn->height_mm = connector->display_info.height_mm; + mconn->status = connector->status; + + mconn->num_modes = 0; + list_for_each_entry(mode, >modes, head) + mconn->num_modes++; + + pdebug(2, "num_modes=%u\n", mconn->num_modes); + + if (!mconn->num_modes) + goto unlock; + + // FIXME: Checkpatch complains: Reusing the krealloc arg is almost always a bug + mconn->modes = krealloc(mconn->modes, mconn->num_modes * sizeof(*mconn->modes), GFP_KERNEL); + if (!mconn->modes) { + ret = -ENOMEM; + mconn->num_modes = 0; + goto unlock; + } + + list_for_each_entry(mode, >modes, head) { + pdebug(2, "Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + mud_drm_from_display_mode(>modes[i++], mode); + } + + if (!connector->edid_blob_ptr) + goto unlock; + + edid = connector->edid_blob_ptr->data; + mconn->edid_len = connector->edid_blob_ptr->length; + pdebug(2, "edid_len=%zu\n", mconn->edid_len); + if (!mconn->edid_len || !edid) { + mconn->edid_len = 0; + goto unlock; + } + +
[RFC 4/9] pinctrl: Add Multifunction USB Device pinctrl driver
The Multifunction USB Device has optional support for gpio and pin configuration. Interrupts are supported if the device supports it. Signed-off-by: Noralf Trønnes --- drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-mud.c | 657 ++ drivers/pinctrl/pinctrl-mud.h | 89 + 4 files changed, 756 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-mud.c create mode 100644 drivers/pinctrl/pinctrl-mud.h diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index df0ef69dd474..ee3532c64411 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -384,6 +384,15 @@ config PINCTRL_OCELOT select OF_GPIO select REGMAP_MMIO +config PINCTRL_MUD + tristate "Multifunction USB Device pinctrl driver" + depends on MFD_MUD + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + help + Support for GPIOs on Multifunction USB Devices. + source "drivers/pinctrl/actions/Kconfig" source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 879f312bfb75..782cc7f286b7 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o obj-$(CONFIG_PINCTRL_RK805)+= pinctrl-rk805.o obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o +obj-$(CONFIG_PINCTRL_MUD) += pinctrl-mud.o obj-y += actions/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/pinctrl/pinctrl-mud.c b/drivers/pinctrl/pinctrl-mud.c new file mode 100644 index ..f890c8e68755 --- /dev/null +++ b/drivers/pinctrl/pinctrl-mud.c @@ -0,0 +1,657 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "pinconf.h" +#include "pinmux.h" +#include "pinctrl-utils.h" + +#include "pinctrl-mud.h" + +/* Temporary debugging aid */ +static unsigned int debug = 8; + +#define pdebug(level, fmt, ...)\ +do { \ + if ((level) <= debug) \ + printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ +} while (0) + +struct mud_pinctrl_pin { + unsigned int irq_types; + unsigned int irq_type; + bool irq_enabled; +}; + +struct mud_pinctrl { + struct device *dev; + struct regmap *regmap; + struct mud_pinctrl_pin *pins; + struct pinctrl_dev *pctl_dev; + struct pinctrl_desc pctl_desc; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; + struct mutex irqlock; /* IRQ bus lock */ +}; + +static unsigned int mud_pinctrl_pin_reg(unsigned int pin, unsigned int offset) +{ + return MUD_PINCTRL_REG_PIN_BASE + (pin * MUD_PINCTRL_PIN_BLOCK_SIZE) + offset; +} + +static int mud_pinctrl_pin_read_reg(struct mud_pinctrl *pctl, unsigned int pin, + unsigned int offset, unsigned int *val) +{ + return regmap_read(pctl->regmap, mud_pinctrl_pin_reg(pin, offset), val); +} + +static int mud_pinctrl_pin_write_reg(struct mud_pinctrl *pctl, unsigned int pin, +unsigned int offset, unsigned int val) +{ + return regmap_write(pctl->regmap, mud_pinctrl_pin_reg(pin, offset), val); +} + +static int mud_pinctrl_read_bitmap(struct mud_pinctrl *pctl, unsigned int reg, + unsigned long *bitmap, unsigned int nbits) +{ + unsigned int nregs = DIV_ROUND_UP(nbits, 32); + u32 *vals; + int ret; + + vals = kmalloc_array(nregs, sizeof(*vals), GFP_KERNEL); + if (!vals) + return -ENOMEM; + + ret = regmap_bulk_read(pctl->regmap, reg, vals, nregs); + if (ret) + goto free; + + bitmap_from_arr32(bitmap, vals, nbits); +free: + kfree(vals); + + return ret; +} + +static int mud_pinctrl_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + struct mud_pinctrl *pctl = gpiochip_get_data(gc); + int ret; + + pdebug(1, "%s: offset=%u\n", __func__, offset); + + ret = mud_pinctrl_pin_write_reg(pctl, offset, MUD_PIN_GPIO_REQUEST, 1); + if (ret == -EBUSY) { + dev_err(pctl->dev, + "pin %u is claimed by another function on the USB device\n", + offset); + ret = -EINVAL; /* follow pinmux.c:pin_request() */ + } + + return ret; +} + +static void mud_pinctrl_gpio_free(struct gpio_chip *gc, unsigned int offset) +{ + struct mud_pinctrl *pctl = gpiochip_get_data(gc); + + pdebug(1,
[RFC 0/9] Regmap over USB for Multifunction USB Device (gpio, display, ...)
Hi, A while back I had the idea to turn a Raspberry Pi Zero into a $5 USB to HDMI/SDTV/DSI/DPI display adapter. Thinking about how to represent the display to the driver I realised that hardware use registers as API. And Linux does have a generic register abstraction: regmap. Furthermore this means that if I can do a regmap over USB implementation, it will be easy to do other functions like gpio, adc and others. After a few iterations trying to understand the USB subsystem and satisfying driver requirements, I now have something that looks promising. I'm sending out an early version hoping to get feedback especially on the core parts that handles regmap and interrupts. Overview: USB Host : USB Device : -- : -- -- | mfd: mud | : | f_mud | -- | Driver | -- : || | Driver | -- | regmap-usb | : | (mud_regmap) | -- -- : -- I've attached 2 drivers: - gpio/pinctrl: is more or less finished - display: needs a lot more work USB3 device I've only tested this with usb2 devices (Pi, BBB) so I should get myself a usb3 gadget capable board. My searching didn't turn up much, so this seems to be quite rare. ROCK960 has USB 3.0 type C OTG but the price is $139 which is a bit expensive for this hobby project. Does anyone know of a cheap board? Noralf. Noralf Trønnes (9): regmap: Add USB support mfd: Add driver for Multifunction USB Device usb: gadget: function: Add Multifunction USB Device support pinctrl: Add Multifunction USB Device pinctrl driver usb: gadget: function: mud: Add gpio support regmap: Speed up _regmap_raw_write_impl() for large buffers drm: Add Multifunction USB Device display driver drm/client: Add drm_client_init_from_id() and drm_client_modeset_set() usb: gadget: function: mud: Add display support drivers/base/regmap/Kconfig |8 +- drivers/base/regmap/Makefile |1 + drivers/base/regmap/regmap-usb.c | 1026 ++ drivers/base/regmap/regmap.c | 10 +- drivers/gpu/drm/Kconfig |2 + drivers/gpu/drm/Makefile |1 + drivers/gpu/drm/drm_client.c | 37 + drivers/gpu/drm/drm_client_modeset.c | 52 + drivers/gpu/drm/mud/Kconfig | 18 + drivers/gpu/drm/mud/Makefile |4 + drivers/gpu/drm/mud/mud_drm.c| 1198 ++ drivers/gpu/drm/mud/mud_drm.h| 137 +++ drivers/gpu/drm/mud/mud_drm_gadget.c | 889 drivers/mfd/Kconfig |8 + drivers/mfd/Makefile |1 + drivers/mfd/mud.c| 580 +++ drivers/pinctrl/Kconfig |9 + drivers/pinctrl/Makefile |1 + drivers/pinctrl/pinctrl-mud.c| 657 drivers/pinctrl/pinctrl-mud.h| 89 ++ drivers/usb/gadget/Kconfig | 36 + drivers/usb/gadget/function/Makefile |6 + drivers/usb/gadget/function/f_mud.c | 913 + drivers/usb/gadget/function/f_mud.h | 210 drivers/usb/gadget/function/f_mud_drm.c | 181 drivers/usb/gadget/function/f_mud_pins.c | 962 + drivers/usb/gadget/function/mud_regmap.c | 936 + include/drm/drm_client.h |4 + include/linux/mfd/mud.h | 16 + include/linux/regmap.h | 23 + include/linux/regmap_usb.h | 97 ++ 31 files changed, 8107 insertions(+), 5 deletions(-) create mode 100644 drivers/base/regmap/regmap-usb.c create mode 100644 drivers/gpu/drm/mud/Kconfig create mode 100644 drivers/gpu/drm/mud/Makefile create mode 100644 drivers/gpu/drm/mud/mud_drm.c create mode 100644 drivers/gpu/drm/mud/mud_drm.h create mode 100644 drivers/gpu/drm/mud/mud_drm_gadget.c create mode 100644 drivers/mfd/mud.c create mode 100644 drivers/pinctrl/pinctrl-mud.c create mode 100644 drivers/pinctrl/pinctrl-mud.h create mode 100644 drivers/usb/gadget/function/f_mud.c create mode 100644 drivers/usb/gadget/function/f_mud.h create mode 100644 drivers/usb/gadget/function/f_mud_drm.c create mode 100644 drivers/usb/gadget/function/f_mud_pins.c create mode 100644 drivers/usb/gadget/function/mud_regmap.c create mode 100644 include/linux/mfd/mud.h create mode 100644 include/linux/regmap_usb.h -- 2.23.0 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[RFC 1/9] regmap: Add USB support
Add support for regmap over USB for use with the Multifunction USB Device. Two endpoints IN/OUT are used. Up to 255 regmaps are supported on one USB interface. The register index width is always 32-bit, but the register value can be 8, 16 or 32 bits wide. LZ4 compression is supported on bulk transfers. Signed-off-by: Noralf Trønnes --- drivers/base/regmap/Kconfig |8 +- drivers/base/regmap/Makefile |1 + drivers/base/regmap/regmap-usb.c | 1026 ++ include/linux/regmap.h | 23 + include/linux/regmap_usb.h | 97 +++ 5 files changed, 1154 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-usb.c create mode 100644 include/linux/regmap_usb.h diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 0fd6f97ee523..6c937c196825 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_USB) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -53,3 +53,9 @@ config REGMAP_SCCB config REGMAP_I3C tristate depends on I3C + +config REGMAP_USB + tristate + depends on USB + select LZ4_COMPRESS + select LZ4_DECOMPRESS diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index ff6c7d8ec1cd..7e6932f100ea 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o +obj-$(CONFIG_REGMAP_USB) += regmap-usb.o diff --git a/drivers/base/regmap/regmap-usb.c b/drivers/base/regmap/regmap-usb.c new file mode 100644 index ..bb4f0df44d1d --- /dev/null +++ b/drivers/base/regmap/regmap-usb.c @@ -0,0 +1,1026 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Register map access API - USB support + * + * Copyright 2020 Noralf Trønnes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +/** + * DOC: overview + * + * This regmap over USB supports multiple regmaps over a single USB interface. + * Two endpoints are needed and the first IN and OUT endpoints are used. + * A REGMAP_USB_DT_INTERFACE descriptor request is issued to get the number of + * regmaps supported on the interface. A REGMAP_USB_DT_MAP descriptor request is + * issued to get details about a specific regmap. This is done when + * devm_regmap_init_usb() is called to get access to a regmap. + * + * A regmap transfer begins with the host sending OUT a _usb_header which + * contains info about the index of the regmap, the register address etc. Next + * it does an IN or OUT transfer of the register value(s) depending on if it's a + * read or write. This transfer can be compressed using lz4 if the device + * supports it. Finally a _usb_status IN request is issued to receive the + * status of the transfer. + * + * If a transfer fails with the error code -EPIPE, a reset control request + * (REGMAP_USB_REQ_PROTOCOL_RESET) is issued. The device should reset it's state + * machine and return its previous error code if any. The device can halt its + * IN/OUT endpoints to force the host to perform a reset if it fails to + * understand a transfer. + */ + +/* Provides exclusive interface access */ +struct regmap_usb_interface { + struct usb_interface *interface; + struct mutex lock; /* Ensures exclusive interface access */ + unsigned int refcount; + struct list_head link; + + u32 tag; +}; + +struct regmap_usb_context; + +struct regmap_usb_transfer { + struct regmap_usb_context *ctx; + struct usb_anchor anchor; + struct urb *header_urb; + struct urb *buf_out_urb; + struct urb *buf_in_urb; + void *buf; + size_t bufsize; + struct urb *status_urb; + spinlock_t lock; /* Protect dynamic values */ + u32 tag; + int status; + + u8 compression; + void *buf_in_dest; + unsigned int length; + unsigned int actual_length; + + ktime_t start; /* FIXME: Temporary debug/perf aid */ +}; + +struct regmap_usb_context { + struct usb_device *usb; + struct regmap_usb_interface *ruif; + u8 ifnum; + unsigned int in_pipe; + unsigned int out_pipe; + u16 index; + unsigned int val_bytes; + void *lz4_comp_mem; + u8 compression; + unsigned int max_transfer_size; + struct regmap_usb_transfer *transfers[2]; +#ifdef
[RFC 6/9] regmap: Speed up _regmap_raw_write_impl() for large buffers
When writing a 3MB buffer the unwritable check in _regmap_raw_write_impl() adds a ~20ms overhead on a Raspberry Pi 4. Amend this by avoiding the check if it's not necessary. Signed-off-by: Noralf Trønnes --- drivers/base/regmap/regmap.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 19f57ccfbe1d..cd876309a74b 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1489,10 +1489,12 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, WARN_ON(!map->bus); /* Check for unwritable registers before we start */ - for (i = 0; i < val_len / map->format.val_bytes; i++) - if (!regmap_writeable(map, -reg + regmap_get_offset(map, i))) - return -EINVAL; + if (map->max_register || map->writeable_reg || map->wr_table) { + for (i = 0; i < val_len / map->format.val_bytes; i++) + if (!regmap_writeable(map, + reg + regmap_get_offset(map, i))) + return -EINVAL; + } if (!map->cache_bypass && map->format.parse_val) { unsigned int ival; -- 2.23.0 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v5 17/52] drm: Add helper to create a connector for a chain of bridges
Hi Tomi, On Tue, Jan 28, 2020 at 01:19:53PM +0200, Tomi Valkeinen wrote: > On 24/01/2020 05:54, Laurent Pinchart wrote: > > > +struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, > > + struct drm_encoder *encoder) > > +{ > > + struct drm_bridge_connector *bridge_connector; > > + struct drm_connector *connector; > > + struct i2c_adapter *ddc = NULL; > > + struct drm_bridge *bridge; > > + int connector_type; > > + > > + bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL); > > + if (!bridge_connector) > > + return ERR_PTR(-ENOMEM); > > + > > + bridge_connector->encoder = encoder; > > + > > + /* > > +* TODO: Handle doublescan_allowed, stereo_allowed and > > +* ycbcr_420_allowed. > > +*/ > > + connector = _connector->base; > > + connector->interlace_allowed = true; > > + > > + /* > > +* Initialise connector status handling. First locate the furthest > > +* bridges in the pipeline that support HPD and output detection. Then > > +* initialise the connector polling mode, using HPD if available and > > +* falling back to polling if supported. If neither HPD nor output > > +* detection are available, we don't support hotplug detection at all. > > +*/ > > + connector_type = DRM_MODE_CONNECTOR_Unknown; > > + drm_for_each_bridge_in_chain(encoder, bridge) { > > + if (bridge->interlace_allowed) > > + connector->interlace_allowed = false; > > This doesn't work on Beagle-xM's venc output. > > The above test should be !bridge->interlace_allowed. I wonder how this passed my tests :-S I'll fix it in v6. > But that doesn't solve it fully. We have VENC and display-connector as > bridges in the beagle's VENC > output path. Only VENC is marked as interlace_allowed. > > Setting "conn->bridge.interlace_allowed = true;" in display_connector_probe > got the VENC output > working. But what's the correct fix here? set interlace_allowed based on > connector type? All the supported connector types (Composite, DVII, HDMIA, SVIDEO and VGA) support interlaced modes, so I think we can just set the flag unconditionally. -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v5 1/3] dt-bindings: drm/bridge: Document Cadence MHDP bridge bindings.
Hi Yuti, Thank you for the patch. On Wed, Feb 12, 2020 at 05:26:42AM +0100, Yuti Amonkar wrote: > Document the bindings used for the Cadence MHDP DPI/DP bridge in > yaml format. > > Signed-off-by: Yuti Amonkar > Reviewed-by: Rob Herring > --- > .../bindings/display/bridge/cdns,mhdp.yaml| 125 ++ > 1 file changed, 125 insertions(+) > create mode 100644 > Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > new file mode 100644 > index ..e7f84ed1d2da > --- /dev/null > +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > @@ -0,0 +1,125 @@ > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: "http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#; > +$schema: "http://devicetree.org/meta-schemas/core.yaml#; > + > +title: Cadence MHDP bridge > + > +maintainers: > + - Swapnil Jakhade > + - Yuti Amonkar > + > +properties: > + compatible: > +enum: > + - cdns,mhdp8546 > + - ti,j721e-mhdp8546 > + > + reg: > +minItems: 1 > +maxItems: 2 > +items: > + - description: > + Register block of mhdptx apb registers upto PHY mapped > area(AUX_CONFIG_P). > + The AUX and PMA registers are mapped to associated phy driver. > + - description: > + Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI J7 > SoCs. > + > + reg-names: > +minItems: 1 > +maxItems: 2 > +items: > + - const: mhdptx > + - const: j721e-intg > + > + clocks: > +maxItems: 1 > +description: > + DP bridge clock, it's used by the IP to know how to translate a number > of > + clock cycles into a time (which is used to comply with DP standard > timings > + and delays). > + > + phys: > +description: Phandle to the DisplyPort phy. > + > + ports: > +type: object > +description: > + Ports as described in Documentation/devicetree/bindings/graph.txt > + > +properties: > + '#address-cells': > +const: 1 > + > + '#size-cells': > +const: 0 > + > + port@0: > +type: object > +description: > + input port representing the DP bridge input s/input port/Input port/ and s/bridge input/bridge input./ > + > + port@1: > +type: object > +description: > + output port representing the DP bridge output. s/output port/Output port/ > + > +required: > + - port@0 > + - port@1 > + - '#address-cells' > + - '#size-cells' > + > +allOf: > + - if: > + properties: > +compatible: > + contains: > +const: ti,j721e-mhdp8546 > +then: > + properties: > +reg: > + minItems: 2 > +reg-names: > + minItems: 2 > + > +required: > + - compatible > + - clocks > + - reg > + - reg-names > + - phys > + - ports > + > +additionalProperties: false > + > +examples: > + - | > +mhdp: dp-bridge@f0fb00 { > +compatible = "cdns,mhdp8546"; > +reg = <0xf0 0xfb00 0x0 0x100>; > +reg-names = "mhdptx"; > +clocks = <_clock>; > +phys = <_phy>; > + > +ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port@0 { > + reg = <0>; > + dp_bridge_input: endpoint { > +remote-endpoint = <_dpi_output>; > + }; > + }; > + > + port@1 { > + reg = <1>; > + dp_bridge_output: endpoint { > +remote-endpoint = <_dp_connector_input>; > + }; > + }; > +}; > +}; > +... Really good bindings ! With the above comments addressed, as well as he one in reply to Tomi's review, Reviewed-by: Laurent Pinchart -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v5 1/3] dt-bindings: drm/bridge: Document Cadence MHDP bridge bindings.
Hi Yuti, On Sun, Feb 16, 2020 at 05:28:40PM +0200, Laurent Pinchart wrote: > On Thu, Feb 13, 2020 at 11:16:51AM +0200, Tomi Valkeinen wrote: > > On 12/02/2020 06:26, Yuti Amonkar wrote: > > > Document the bindings used for the Cadence MHDP DPI/DP bridge in > > > yaml format. > > > > > > Signed-off-by: Yuti Amonkar > > > Reviewed-by: Rob Herring > > > --- > > > .../bindings/display/bridge/cdns,mhdp.yaml| 125 ++ > > > 1 file changed, 125 insertions(+) > > > create mode 100644 > > > Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > > > > > diff --git > > > a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > > b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > > new file mode 100644 > > > index ..e7f84ed1d2da > > > --- /dev/null > > > +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > > @@ -0,0 +1,125 @@ > > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) > > > +%YAML 1.2 > > > +--- > > > +$id: "http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#; > > > +$schema: "http://devicetree.org/meta-schemas/core.yaml#; > > > + > > > +title: Cadence MHDP bridge > > > + > > > +maintainers: > > > + - Swapnil Jakhade > > > + - Yuti Amonkar > > > + > > > +properties: > > > + compatible: > > > +enum: > > > + - cdns,mhdp8546 > > > + - ti,j721e-mhdp8546 > > > + > > > + reg: > > > +minItems: 1 > > > +maxItems: 2 > > > +items: > > > + - description: > > > + Register block of mhdptx apb registers upto PHY mapped > > > area(AUX_CONFIG_P). > > > > "up to". Add space before (. > > > > > + The AUX and PMA registers are mapped to associated phy driver. > > I wouldn't mention driver here, as that's a software concept unrelated > to DT bindings. You could write "The AUX and PMA registers are not part > of this range, they are instead included in the associated PHY.". > > > > + - description: > > > + Register block for DSS_EDP0_INTG_CFG_VP registers in case of > > > TI J7 SoCs. > > > + > > > + reg-names: > > > +minItems: 1 > > > +maxItems: 2 > > > +items: > > > + - const: mhdptx > > > + - const: j721e-intg > > > + > > > + clocks: > > > +maxItems: 1 > > > +description: > > > + DP bridge clock, it's used by the IP to know how to translate a > > > number of > > s/it's // > > > > + clock cycles into a time (which is used to comply with DP standard > > > timings > > > + and delays). > > > + > > > + phys: > > > +description: Phandle to the DisplyPort phy. > > > > "Display" > > And s/Phandle/phandle/, and s/phy/PHY/. > > Shouldn't this bridge also have port nodes ? Oops, sorry, I missed that Tomi's reply has removed part of the original patch. Please disregard this last comment, I'll reply to the original. -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v5 1/3] dt-bindings: drm/bridge: Document Cadence MHDP bridge bindings.
Hi Yuti, Thank you for the patch. On Thu, Feb 13, 2020 at 11:16:51AM +0200, Tomi Valkeinen wrote: > On 12/02/2020 06:26, Yuti Amonkar wrote: > > Document the bindings used for the Cadence MHDP DPI/DP bridge in > > yaml format. > > > > Signed-off-by: Yuti Amonkar > > Reviewed-by: Rob Herring > > --- > > .../bindings/display/bridge/cdns,mhdp.yaml| 125 ++ > > 1 file changed, 125 insertions(+) > > create mode 100644 > > Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > > > diff --git > > a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > new file mode 100644 > > index ..e7f84ed1d2da > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml > > @@ -0,0 +1,125 @@ > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) > > +%YAML 1.2 > > +--- > > +$id: "http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#; > > +$schema: "http://devicetree.org/meta-schemas/core.yaml#; > > + > > +title: Cadence MHDP bridge > > + > > +maintainers: > > + - Swapnil Jakhade > > + - Yuti Amonkar > > + > > +properties: > > + compatible: > > +enum: > > + - cdns,mhdp8546 > > + - ti,j721e-mhdp8546 > > + > > + reg: > > +minItems: 1 > > +maxItems: 2 > > +items: > > + - description: > > + Register block of mhdptx apb registers upto PHY mapped > > area(AUX_CONFIG_P). > > "up to". Add space before (. > > > + The AUX and PMA registers are mapped to associated phy driver. I wouldn't mention driver here, as that's a software concept unrelated to DT bindings. You could write "The AUX and PMA registers are not part of this range, they are instead included in the associated PHY.". > > + - description: > > + Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI > > J7 SoCs. > > + > > + reg-names: > > +minItems: 1 > > +maxItems: 2 > > +items: > > + - const: mhdptx > > + - const: j721e-intg > > + > > + clocks: > > +maxItems: 1 > > +description: > > + DP bridge clock, it's used by the IP to know how to translate a > > number of s/it's // > > + clock cycles into a time (which is used to comply with DP standard > > timings > > + and delays). > > + > > + phys: > > +description: Phandle to the DisplyPort phy. > > "Display" And s/Phandle/phandle/, and s/phy/PHY/. Shouldn't this bridge also have port nodes ? -- Regards, Laurent Pinchart ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[Bug 200695] Blank screen on RX 580 with amdgpu.dc=1 enabled (no displays detected)
https://bugzilla.kernel.org/show_bug.cgi?id=200695 --- Comment #37 from Adam (magicm...@magicmyth.com) --- As several comments mention different behavior between the different connector types I found a spare DVI cable and tried connecting to the same monitor via that input and it worked! So once logged in I plugged in the HDMI cable and switched input and it worked just fine (monitor was glitchy at first but once I disabled DVI output in monitor configuration it worked perfectly). To confirm this was indeed working with the DC code path I tested audio over HDMI and it worked just fine (and does not work with DC disabled, as expected). So I rebooted with both the DVI and HDMI in and the output over HDMI worked all through boot. I then disconnected the DVI and rebooted and the HDMI continues to work so far. Unfortunately I don't have a displayport monitor around to test if that behaves as weirdly. Just to be clear, I had tried to make this monitor work for a couple weeks over HDMI and the only thing that worked was amdgpu.dc=0 until I plugged in the DVI connector so this was not a one off fail. I forgot to mention before that when the HDMI output was not working with DC my Xorg logs also showed no monitor detected. I can attach the two different Xorg logs if that helps? -- You are receiving this mail because: You are watching the assignee of the bug. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v1 1/1] drm: drop unused drm_display_mode.private
On Sat, Feb 15, 2020 at 9:08 PM Sam Ravnborg wrote: > > Hi Daniel. > > > > I also checked private_flags - it is used in a few modules. > > > And it looked legit. > > > > > Iirc i915 used this, before we went full overdrive with entire atomic > > state structure subclassing :-) > > $ git grep -l private_flags > gma500/psb_intel_drv.h > i915/display/intel_display.c > i915/display/intel_display_types.h > i915/display/intel_tv.c > i915/display/vlv_dsi.c > i915/i915_irq.c > msm/disp/dpu1/dpu_encoder.c > msm/disp/dpu1/dpu_trace.h <= false hit > > i915 still has a few uses of private_flags. > Likewise msm and gma500 > > Looks doable to address this, but not on my TODO list. Oh I meant the private pointer, not the flags stuff. And yeah maybe we could add this as a todo, at least for i915 and msm. For gma500 first step would be converting that driver over to atomic, which I don't think will happen. -Daniel > > Sam > > > > > Reviewed-by: Daniel Vetter > > Thanks - applied. > > Sam -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel