From def35e7c592616bc09be328de8795e5e624a3cf8 Mon Sep 17 00:00:00 2001 From: Shayenne Moura Date: Wed, 30 Jan 2019 14:06:36 -0200 Subject: drm/vkms: Bugfix extra vblank frame kms_flip tests are breaking on vkms when simulate vblank because vblank event sequence count returns one extra frame after arm vblank event to make a page flip. When vblank interrupt happens, userspace processes the vblank event and issues the next page flip command. Kernel calls queue_work to call commit_planes and arm the new page flip. The next vblank picks up the newly armed vblank event and vblank interrupt happens again. The arm and vblank event are asynchronous, then, on the next vblank, we receive x+2 from `get_vblank_timestamp`, instead x+1, although timestamp and vblank seqno matches. Function `get_vblank_timestamp` is reached by 2 ways: - from `drm_mode_page_flip_ioctl`: driver is doing one atomic operation to synchronize planes in the same output. There is no vblank simulation, the `drm_crtc_arm_vblank_event` function adds 1 on vblank count, and the variable in_vblank_irq is false - from `vkms_vblank_simulate`: since the driver is doing a vblank simulation, the variable in_vblank_irq is true. Fix this problem subtracting one vblank period from vblank_time when `get_vblank_timestamp` is called from trace `drm_mode_page_flip_ioctl`, i.e., is not a real vblank interrupt, and getting the timestamp and vblank seqno when it is a real vblank interrupt. The reason for all this is that get_vblank_timestamp always supplies the timestamp for the next vblank event. The hrtimer is the vblank simulator, and it needs the correct previous value to present the next vblank. Since this is how hw timestamp registers work and what the vblank core expects. Signed-off-by: Shayenne Moura Signed-off-by: Daniel Vetter Reviewed-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Link: https://patchwork.freedesktop.org/patch/msgid/171e6e1c239cbca0c3df7183ed8acdfeeace9cf4.1548856186.git.shayenneluzmoura@gmail.com --- drivers/gpu/drm/vkms/vkms_crtc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index d44bfc392491..23146ff2a25b 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -87,6 +87,9 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, *vblank_time = output->vblank_hrtimer.node.expires; + if (!in_vblank_irq) + *vblank_time -= output->period_ns; + return true; } -- cgit v1.2.3 From ba420afab565bdc7b028ddd4f222260f2de7a1db Mon Sep 17 00:00:00 2001 From: Shayenne Moura Date: Wed, 30 Jan 2019 14:07:11 -0200 Subject: drm/vkms: Bugfix racing hrtimer vblank handle When the vblank irq happens, kernel time subsystem executes `vkms_vblank_simulate`. In parallel or not, it prepares all stuff necessary to the next vblank with arm, and it must flush these stuff before the next vblank irq. However, vblank counter is ahead when arm is executed in parallel with handle vblank. CPU 0: CPU 1: | | atomic_commit_tail is ongoing | | | | hrtimer: vkms_vblank_simulate() | | | drm_crtc_handle_vblank() | | drm_crtc_arm_vblank() | | | ->get_vblank_timestamp() | | | | hrtimer_forward_now() Then, we should guarantee that the vblank interval time is correct (not changed) before finish the vblank handle. Fix the bug including the call to `hrtimer_forward_now()` in the same lock of `drm_crtc_handle_vblank()` to ensure that the timestamp update is correct when finish the vblank handle. Signed-off-by: Shayenne Moura Signed-off-by: Daniel Vetter Reviewed-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Link: https://patchwork.freedesktop.org/patch/msgid/e2e4b8f3a5cab7b2dba75bf1930f86b0a4ee08c9.1548856186.git.shayenneluzmoura@gmail.com --- drivers/gpu/drm/vkms/vkms_crtc.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 23146ff2a25b..5a095610726b 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -10,13 +10,17 @@ #include #include -static void _vblank_handle(struct vkms_output *output) +static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) { + struct vkms_output *output = container_of(timer, struct vkms_output, + vblank_hrtimer); struct drm_crtc *crtc = &output->crtc; struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state); + int ret_overrun; bool ret; spin_lock(&output->lock); + ret = drm_crtc_handle_vblank(crtc); if (!ret) DRM_ERROR("vkms failure on handling vblank"); @@ -37,19 +41,9 @@ static void _vblank_handle(struct vkms_output *output) DRM_WARN("failed to queue vkms_crc_work_handle"); } - spin_unlock(&output->lock); -} - -static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) -{ - struct vkms_output *output = container_of(timer, struct vkms_output, - vblank_hrtimer); - int ret_overrun; - - _vblank_handle(output); - ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, output->period_ns); + spin_unlock(&output->lock); return HRTIMER_RESTART; } -- cgit v1.2.3 From 938010ab072221f9b396770bbe78001ee3b74302 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 26 Jan 2019 12:05:38 +0000 Subject: drm/xen-front: Drop pointless static qualifier in fb_destroy() There is no need to have the 'struct drm_framebuffer *fb' variable static since new value always be assigned before use it. Signed-off-by: YueHaibing Reviewed-by: Oleksandr Andrushchenko Signed-off-by: Oleksandr Andrushchenko Link: https://patchwork.freedesktop.org/patch/msgid/1548504338-114487-1-git-send-email-yuehaibing@huawei.com --- drivers/gpu/drm/xen/xen_drm_front_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c index 860da055c6bb..c2955d375394 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_kms.c +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c @@ -54,7 +54,7 @@ fb_create(struct drm_device *dev, struct drm_file *filp, const struct drm_mode_fb_cmd2 *mode_cmd) { struct xen_drm_front_drm_info *drm_info = dev->dev_private; - static struct drm_framebuffer *fb; + struct drm_framebuffer *fb; struct drm_gem_object *gem_obj; int ret; -- cgit v1.2.3 From 24ded292a5c2ed476f01c77fee65f8320552cd27 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Tue, 29 Jan 2019 17:04:22 +0200 Subject: drm/xen-front: Fix mmap attributes for display buffers When GEM backing storage is allocated those are normal pages, so there is no point using pgprot_writecombine while mmaping. This fixes mismatch of buffer pages' memory attributes between the frontend and backend which may cause screen artifacts. Fixes: c575b7eeb89f ("drm/xen-front: Add support for Xen PV display frontend") Signed-off-by: Oleksandr Andrushchenko Suggested-by: Julien Grall Acked-by: Julien Grall Link: https://patchwork.freedesktop.org/patch/msgid/20190129150422.19867-1-andr2000@gmail.com --- drivers/gpu/drm/xen/xen_drm_front_gem.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c index d303a2e17f5e..53c376d55fcf 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_gem.c +++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c @@ -235,8 +235,14 @@ static int gem_mmap_obj(struct xen_gem_object *xen_obj, vma->vm_flags &= ~VM_PFNMAP; vma->vm_flags |= VM_MIXEDMAP; vma->vm_pgoff = 0; - vma->vm_page_prot = - pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + /* + * According to Xen on ARM ABI (xen/include/public/arch-arm.h): + * all memory which is shared with other entities in the system + * (including the hypervisor and other guests) must reside in memory + * which is mapped as Normal Inner Write-Back Outer Write-Back + * Inner-Shareable. + */ + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); /* * vm_operations_struct.fault handler will be called if CPU access @@ -282,8 +288,9 @@ void *xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj) if (!xen_obj->pages) return NULL; + /* Please see comment in gem_mmap_obj on mapping and attributes. */ return vmap(xen_obj->pages, xen_obj->num_pages, - VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + VM_MAP, PAGE_KERNEL); } void xen_drm_front_gem_prime_vunmap(struct drm_gem_object *gem_obj, -- cgit v1.2.3 From 1e55a53a28d3e52a68e11917dd25a216c3e7c182 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 1 Feb 2019 17:23:26 -0800 Subject: drm: Trivial comment grammar cleanups Most of these are just cases where code comments used contractions (it's, who's) where they actually mean to use a possessive pronoun (its, whose) or vice-versa. Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190202012326.20096-1-matthew.d.roper@intel.com --- drivers/gpu/drm/drm_agpsupport.c | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++---- drivers/gpu/drm/drm_atomic_uapi.c | 4 ++-- drivers/gpu/drm/drm_bufs.c | 4 ++-- drivers/gpu/drm/drm_connector.c | 2 +- drivers/gpu/drm/drm_dp_mst_topology.c | 30 +++++++++++++++--------------- drivers/gpu/drm/drm_fb_helper.c | 2 +- drivers/gpu/drm/drm_file.c | 2 +- drivers/gpu/drm/drm_framebuffer.c | 2 +- drivers/gpu/drm/drm_gem.c | 2 +- drivers/gpu/drm/drm_mm.c | 2 +- drivers/gpu/drm/drm_modes.c | 2 +- drivers/gpu/drm/drm_property.c | 2 +- drivers/gpu/drm/drm_vblank.c | 2 +- include/drm/drm_atomic.h | 2 +- include/drm/drm_client.h | 2 +- include/drm/drm_connector.h | 2 +- include/drm/drm_mode_config.h | 2 +- include/drm/drm_modeset_helper_vtables.h | 2 +- include/drm/drm_modeset_lock.h | 2 +- include/drm/ttm/ttm_bo_driver.h | 2 +- 21 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 737f02885c28..40fba1c04dfc 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -348,7 +348,7 @@ int drm_agp_bind_ioctl(struct drm_device *dev, void *data, * \return zero on success or a negative number on failure. * * Verifies the AGP device is present and has been acquired and looks up the - * AGP memory entry. If the memory it's currently bound, unbind it via + * AGP memory entry. If the memory is currently bound, unbind it via * unbind_agp(). Frees it via free_agp() as well as the entry itself * and unlinks from the doubly linked list it's inserted in. */ diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 6fe2303fccd9..440cfa91162a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -330,7 +330,7 @@ update_connector_routing(struct drm_atomic_state *state, * Since the connector can be unregistered at any point during an * atomic check or commit, this is racy. But that's OK: all we care * about is ensuring that userspace can't do anything but shut off the - * display on a connector that was destroyed after its been notified, + * display on a connector that was destroyed after it's been notified, * not before. */ if (drm_connector_is_unregistered(connector) && crtc_state->active) { @@ -685,7 +685,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, /* * After all the routing has been prepared we need to add in any - * connector which is itself unchanged, but who's crtc changes it's + * connector which is itself unchanged, but whose crtc changes its * configuration. This must be done before calling mode_fixup in case a * crtc only changed its mode but has the same set of connectors. */ @@ -1670,7 +1670,7 @@ EXPORT_SYMBOL(drm_atomic_helper_async_commit); * drm_atomic_helper_setup_commit() and related functions. * * Committing the actual hardware state is done through the - * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or it's default + * &drm_mode_config_helper_funcs.atomic_commit_tail callback, or its default * implementation drm_atomic_helper_commit_tail(). * * RETURNS: @@ -1893,7 +1893,7 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc) * functions. drm_atomic_helper_wait_for_dependencies() must be called before * actually committing the hardware state, and for nonblocking commits this call * must be placed in the async worker. See also drm_atomic_helper_swap_state() - * and it's stall parameter, for when a driver's commit hooks look at the + * and its stall parameter, for when a driver's commit hooks look at the * &drm_crtc.state, &drm_plane.state or &drm_connector.state pointer directly. * * Completion of the hardware commit step must be signalled using diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index c40889888a16..defc03a9cd1c 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -44,8 +44,8 @@ * DOC: overview * * This file contains the marshalling and demarshalling glue for the atomic UAPI - * in all it's form: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and - * SET_PROPERTY IOCTls. Plus interface functions for compatibility helpers and + * in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and + * SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and * drivers which have special needs to construct their own atomic updates, e.g. * for load detect or similiar. */ diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index a39ab2193bfe..e407adb033e7 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -494,7 +494,7 @@ int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data, * isn't in use. * * Searches the map on drm_device::maplist, removes it from the list, see if - * its being used, and free any associate resource (such as MTRR's) if it's not + * it's being used, and free any associated resource (such as MTRR's) if it's not * being on use. * * \sa drm_legacy_addmap @@ -621,7 +621,7 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, } } - /* List has wrapped around to the head pointer, or its empty we didn't + /* List has wrapped around to the head pointer, or it's empty we didn't * find anything. */ if (list_empty(&dev->maplist) || !map) { diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index e3ff73695c32..dd40eff0911c 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1066,7 +1066,7 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); * * content type (HDMI specific): * Indicates content type setting to be used in HDMI infoframes to indicate - * content type for the external device, so that it adjusts it's display + * content type for the external device, so that it adjusts its display * settings accordingly. * * The value of this property can be one of the following: diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index b1c63e9cdf8a..6d0d8e01f16e 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -941,7 +941,7 @@ static void drm_dp_free_mst_branch_device(struct kref *kref) * in-memory topology state from being changed in the middle of critical * operations like changing the internal state of payload allocations. This * means each branch and port will be considered to be connected to the rest - * of the topology until it's topology refcount reaches zero. Additionally, + * of the topology until its topology refcount reaches zero. Additionally, * for ports this means that their associated &struct drm_connector will stay * registered with userspace until the port's refcount reaches 0. * @@ -979,8 +979,8 @@ static void drm_dp_free_mst_branch_device(struct kref *kref) * same way as the C pointers used to reference a structure. * * As you can see in the above figure, every branch increments the topology - * refcount of it's children, and increments the malloc refcount of it's - * parent. Additionally, every payload increments the malloc refcount of it's + * refcount of its children, and increments the malloc refcount of its + * parent. Additionally, every payload increments the malloc refcount of its * assigned port by 1. * * So, what would happen if MSTB #3 from the above figure was unplugged from @@ -997,9 +997,9 @@ static void drm_dp_free_mst_branch_device(struct kref *kref) * of its parent, and finally its own malloc refcount. For MSTB #4 and port * #4, this means they both have been disconnected from the topology and freed * from memory. But, because payload #2 is still holding a reference to port - * #3, port #3 is removed from the topology but it's &struct drm_dp_mst_port + * #3, port #3 is removed from the topology but its &struct drm_dp_mst_port * is still accessible from memory. This also means port #3 has not yet - * decremented the malloc refcount of MSTB #3, so it's &struct + * decremented the malloc refcount of MSTB #3, so its &struct * drm_dp_mst_branch will also stay allocated in memory until port #3's * malloc refcount reaches 0. * @@ -1139,7 +1139,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) /** * drm_dp_mst_topology_try_get_mstb() - Increment the topology refcount of a - * branch device unless its zero + * branch device unless it's zero * @mstb: &struct drm_dp_mst_branch to increment the topology refcount of * * Attempts to grab a topology reference to @mstb, if it hasn't yet been @@ -1265,7 +1265,7 @@ static void drm_dp_destroy_port(struct kref *kref) /** * drm_dp_mst_topology_try_get_port() - Increment the topology refcount of a - * port unless its zero + * port unless it's zero * @port: &struct drm_dp_mst_port to increment the topology refcount of * * Attempts to grab a topology reference to @port, if it hasn't yet been @@ -1471,7 +1471,7 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) port->mstb->port_parent = port; /* * Make sure this port's memory allocation stays - * around until it's child MSTB releases it + * around until its child MSTB releases it */ drm_dp_mst_get_port_malloc(port); @@ -2271,7 +2271,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_payload *payload) { DRM_DEBUG_KMS("\n"); - /* its okay for these to fail */ + /* it's okay for these to fail */ if (port) { drm_dp_payload_send_msg(mgr, port, id, 0); } @@ -2947,7 +2947,7 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector { enum drm_connector_status status = connector_status_disconnected; - /* we need to search for the port in the mgr in case its gone */ + /* we need to search for the port in the mgr in case it's gone */ port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return connector_status_disconnected; @@ -3013,7 +3013,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ { struct edid *edid = NULL; - /* we need to search for the port in the mgr in case its gone */ + /* we need to search for the port in the mgr in case it's gone */ port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) return NULL; @@ -3180,7 +3180,7 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * Releases any VCPI slots that have been allocated to a port in the atomic * state. Any atomic drivers which support MST must call this function in * their &drm_connector_helper_funcs.atomic_check() callback when the - * connector will no longer have VCPI allocated (e.g. because it's CRTC was + * connector will no longer have VCPI allocated (e.g. because its CRTC was * removed) when it had VCPI allocated in the previous atomic state. * * It is OK to call this even if @port has been removed from the system. @@ -3268,7 +3268,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", pbn, port->vcpi.num_slots); - /* Keep port allocated until it's payload has been removed */ + /* Keep port allocated until its payload has been removed */ drm_dp_mst_get_port_malloc(port); drm_dp_mst_topology_put_port(port); return true; @@ -3300,7 +3300,7 @@ EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { /* - * A port with VCPI will remain allocated until it's VCPI is + * A port with VCPI will remain allocated until its VCPI is * released, no verified ref needed */ @@ -3317,7 +3317,7 @@ void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { /* - * A port with VCPI will remain allocated until it's VCPI is + * A port with VCPI will remain allocated until its VCPI is * released, no verified ref needed */ diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c5c79986f9c5..523b1067f1ed 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2483,7 +2483,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, /* * This function checks if rotation is necessary because of panel orientation * and if it is, if it is supported. - * If rotation is necessary and supported, its gets set in fb_crtc.rotation. + * If rotation is necessary and supported, it gets set in fb_crtc.rotation. * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 46f48f245eb5..b1838a41ad43 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -701,7 +701,7 @@ int drm_event_reserve_init(struct drm_device *dev, EXPORT_SYMBOL(drm_event_reserve_init); /** - * drm_event_cancel_free - free a DRM event and release it's space + * drm_event_cancel_free - free a DRM event and release its space * @dev: DRM device * @p: tracking structure for the pending event * diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 7abcb265a108..d8d75e25f6fb 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -773,7 +773,7 @@ EXPORT_SYMBOL(drm_framebuffer_lookup); * @fb: fb to unregister * * Drivers need to call this when cleaning up driver-private framebuffers, e.g. - * those used for fbdev. Note that the caller must hold a reference of it's own, + * those used for fbdev. Note that the caller must hold a reference of its own, * i.e. the object may not be destroyed through this call (since it'll lead to a * locking inversion). * diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 2896ff60552f..d0b9f6a9953f 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -660,7 +660,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, EXPORT_SYMBOL(drm_gem_put_pages); /** - * drm_gem_object_lookup - look up a GEM object from it's handle + * drm_gem_object_lookup - look up a GEM object from its handle * @filp: DRM file private date * @handle: userspace handle * diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 3cc5fbd78ee2..2b4f373736c7 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -816,7 +816,7 @@ EXPORT_SYMBOL(drm_mm_scan_add_block); * When the scan list is empty, the selected memory nodes can be freed. An * immediately following drm_mm_insert_node_in_range_generic() or one of the * simpler versions of that function with !DRM_MM_SEARCH_BEST will then return - * the just freed block (because its at the top of the free_stack list). + * the just freed block (because it's at the top of the free_stack list). * * Returns: * True if this block should be evicted, false otherwise. Will always diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index adce9a26bac9..a28e7a91c8be 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1272,7 +1272,7 @@ const char *drm_get_mode_status_name(enum drm_mode_status status) * @verbose: be verbose about it * * This helper function can be used to prune a display mode list after - * validation has been completed. All modes who's status is not MODE_OK will be + * validation has been completed. All modes whose status is not MODE_OK will be * removed from the list, and if @verbose the status code and mode name is also * printed to dmesg. */ diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 79c77c3cad86..f8ec8f9c3e7a 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -866,7 +866,7 @@ err: * value doesn't become invalid part way through the property update due to * race). The value returned by reference via 'obj' should be passed back * to drm_property_change_valid_put() after the property is set (and the - * object to which the property is attached has a chance to take it's own + * object to which the property is attached has a chance to take its own * reference). */ bool drm_property_change_valid_get(struct drm_property *property, diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index cde71ee95a8f..a1b65d26d761 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -48,7 +48,7 @@ * Drivers must initialize the vertical blanking handling core with a call to * drm_vblank_init(). Minimally, a driver needs to implement * &drm_crtc_funcs.enable_vblank and &drm_crtc_funcs.disable_vblank plus call - * drm_crtc_handle_vblank() in it's vblank interrupt handler for working vblank + * drm_crtc_handle_vblank() in its vblank interrupt handler for working vblank * support. * * Vertical blanking interrupts can be enabled by the DRM core or by drivers diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 811b4a92568f..3b97b2bfaad9 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -192,7 +192,7 @@ struct drm_private_state; * private objects. The structure itself is used as a vtable to identify the * associated private object type. Each private object type that needs to be * added to the atomic states is expected to have an implementation of these - * hooks and pass a pointer to it's drm_private_state_funcs struct to + * hooks and pass a pointer to its drm_private_state_funcs struct to * drm_atomic_get_private_obj_state(). */ struct drm_private_state_funcs { diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index 971bb7853776..8b552b1a6ce9 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -26,7 +26,7 @@ struct drm_client_funcs { * @unregister: * * Called when &drm_device is unregistered. The client should respond by - * releasing it's resources using drm_client_release(). + * releasing its resources using drm_client_release(). * * This callback is optional. */ diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 994161374a49..8fe22abb1e10 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -912,7 +912,7 @@ struct drm_connector { /** * @ycbcr_420_allowed : This bool indicates if this connector is * capable of handling YCBCR 420 output. While parsing the EDID - * blocks, its very helpful to know, if the source is capable of + * blocks it's very helpful to know if the source is capable of * handling YCBCR 420 outputs. */ bool ycbcr_420_allowed; diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 1e6cb885994d..7f60e8eb269a 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -361,7 +361,7 @@ struct drm_mode_config { * * This is the big scary modeset BKL which protects everything that * isn't protect otherwise. Scope is unclear and fuzzy, try to remove - * anything from under it's protection and move it into more well-scoped + * anything from under its protection and move it into more well-scoped * locks. * * The one important thing this protects is the use of @acquire_ctx. diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 61142aa0ab23..cfb7be40bed7 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -1013,7 +1013,7 @@ struct drm_plane_helper_funcs { * @prepare_fb: * * This hook is to prepare a framebuffer for scanout by e.g. pinning - * it's backing storage or relocating it into a contiguous block of + * its backing storage or relocating it into a contiguous block of * VRAM. Other possible preparatory work includes flushing caches. * * This function must not block for outstanding rendering, since it is diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index a308f2d6496f..7b8841065b11 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -68,7 +68,7 @@ struct drm_modeset_acquire_ctx { /** * struct drm_modeset_lock - used for locking modeset resources. * @mutex: resource locking - * @head: used to hold it's place on &drm_atomi_state.locked list when + * @head: used to hold its place on &drm_atomi_state.locked list when * part of an atomic update * * Used for locking CRTCs and other modeset resources. diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 1021106438b2..56642fbb6f73 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -867,7 +867,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, * * @bo: A pointer to a struct ttm_buffer_object. * - * Pipelined gutting a BO of it's backing store. + * Pipelined gutting a BO of its backing store. */ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo); -- cgit v1.2.3 From db97dd0eef3af860a7e9886e271709590feafee7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 4 Feb 2019 12:01:31 +0100 Subject: drm/cirrus: add plane setup Commit "f4bd542bca drm/fb-helper: Scale back depth to supported maximum" uncovered a bug in the cirrus driver. It must create its own primary plane, using the correct format list, depending on the bpp module parameter, so it is consistent with mode_config->preferred_depth. Signed-off-by: Gerd Hoffmann Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20190204110131.21467-1-kraxel@redhat.com --- drivers/gpu/drm/cirrus/cirrus_mode.c | 70 +++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index a830e70fc0bb..7f9bc32af685 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -360,10 +360,70 @@ static const struct drm_crtc_helper_funcs cirrus_helper_funcs = { }; /* CRTC setup */ +static const uint32_t cirrus_formats_16[] = { + DRM_FORMAT_RGB565, +}; + +static const uint32_t cirrus_formats_24[] = { + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, +}; + +static const uint32_t cirrus_formats_32[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, +}; + +static struct drm_plane *cirrus_primary_plane(struct drm_device *dev) +{ + const uint32_t *formats; + uint32_t nformats; + struct drm_plane *primary; + int ret; + + switch (cirrus_bpp) { + case 16: + formats = cirrus_formats_16; + nformats = ARRAY_SIZE(cirrus_formats_16); + break; + case 24: + formats = cirrus_formats_24; + nformats = ARRAY_SIZE(cirrus_formats_24); + break; + case 32: + formats = cirrus_formats_32; + nformats = ARRAY_SIZE(cirrus_formats_32); + break; + default: + return NULL; + } + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (primary == NULL) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + ret = drm_universal_plane_init(dev, primary, 0, + &drm_primary_helper_funcs, + formats, nformats, + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + kfree(primary); + primary = NULL; + } + + return primary; +} + static void cirrus_crtc_init(struct drm_device *dev) { struct cirrus_device *cdev = dev->dev_private; struct cirrus_crtc *cirrus_crtc; + struct drm_plane *primary; cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) + (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)), @@ -372,7 +432,15 @@ static void cirrus_crtc_init(struct drm_device *dev) if (cirrus_crtc == NULL) return; - drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs); + primary = cirrus_primary_plane(dev); + if (primary == NULL) { + kfree(cirrus_crtc); + return; + } + + drm_crtc_init_with_planes(dev, &cirrus_crtc->base, + primary, NULL, + &cirrus_crtc_funcs, NULL); drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE); cdev->mode_info.crtc = cirrus_crtc; -- cgit v1.2.3 From 86c5b359d9e10b21eac1f936c498d8a81aa4373f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 4 Feb 2019 19:38:58 +0100 Subject: drm/bochs: fix bochs_gem_prime_mmap ttm_fbdev_mmap() just doesn't work. It appears to work fine, mmap() returns success, but any attempt to actually access the mapping causes a SIGBUS. We can just use drm_gem_prime_mmap() instead. Almost. We have to copy over the start offset from the ttm_buffer_object vm_node to the drm_gem_object vm_node so the offset math in drm_gem_prime_mmap() works correctly for us even though we use ttm to manage our objects. Signed-off-by: Gerd Hoffmann Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20190204183858.8976-1-kraxel@redhat.com --- drivers/gpu/drm/bochs/bochs_mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 641a33f134ee..49463348a07a 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -442,5 +442,6 @@ int bochs_gem_prime_mmap(struct drm_gem_object *obj, { struct bochs_bo *bo = gem_to_bochs_bo(obj); - return ttm_fbdev_mmap(vma, &bo->bo); + bo->gem.vma_node.vm_node.start = bo->bo.vma_node.vm_node.start; + return drm_gem_prime_mmap(obj, vma); } -- cgit v1.2.3 From 3a8844c298522fa22df4bdd863011e5b639a4e84 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 1 Feb 2019 19:20:01 -0500 Subject: drm/dp_mst: Fix unbalanced malloc ref in drm_dp_mst_deallocate_vcpi() In drm_dp_mst_deallocate_vcpi(), we currently unconditionally call drm_dp_mst_put_port_malloc() on the port that's passed to us, even if we never successfully allocated VCPI to it. This is contrary to what we do in drm_dp_mst_allocate_vcpi(), where we only call drm_dp_mst_get_port_malloc() on the passed port if we successfully allocated VCPI to it. As a result, if drm_dp_mst_allocate_vcpi() fails during a modeset and another successive modeset calls drm_dp_mst_deallocate_vcpi() we will end up dropping someone else's malloc reference to the port. Example: [ 962.309260] ================================================================== [ 962.309290] BUG: KASAN: use-after-free in drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309296] Read of size 4 at addr ffff888416c30004 by task kworker/0:1H/500 [ 962.309308] CPU: 0 PID: 500 Comm: kworker/0:1H Tainted: G W O 5.0.0-rc2Lyude-Test+ #1 [ 962.309313] Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018 [ 962.309428] Workqueue: events_highpri intel_atomic_cleanup_work [i915] [ 962.309434] Call Trace: [ 962.309452] dump_stack+0xad/0x150 [ 962.309462] ? dump_stack_print_info.cold.0+0x1b/0x1b [ 962.309472] ? kmsg_dump_rewind_nolock+0xd9/0xd9 [ 962.309504] ? drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309515] print_address_description+0x6c/0x23c [ 962.309542] ? drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309568] ? drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309577] kasan_report.cold.3+0x1a/0x32 [ 962.309605] ? drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309631] drm_dp_mst_put_port_malloc+0x72/0x180 [drm_kms_helper] [ 962.309658] ? drm_dp_mst_put_mstb_malloc+0x180/0x180 [drm_kms_helper] [ 962.309687] drm_dp_mst_destroy_state+0xcd/0x120 [drm_kms_helper] [ 962.309745] drm_atomic_state_default_clear+0x6ee/0xcc0 [drm] [ 962.309864] intel_atomic_state_clear+0xe/0x80 [i915] [ 962.309928] __drm_atomic_state_free+0x35/0xd0 [drm] [ 962.310044] intel_atomic_cleanup_work+0x56/0x70 [i915] [ 962.310057] process_one_work+0x884/0x1400 [ 962.310067] ? drain_workqueue+0x5a0/0x5a0 [ 962.310075] ? __schedule+0x87f/0x1e80 [ 962.310086] ? __sched_text_start+0x8/0x8 [ 962.310095] ? run_rebalance_domains+0x400/0x400 [ 962.310110] ? deref_stack_reg+0xb4/0x120 [ 962.310117] ? __read_once_size_nocheck.constprop.7+0x10/0x10 [ 962.310124] ? worker_enter_idle+0x47f/0x6a0 [ 962.310134] ? schedule+0xd7/0x2e0 [ 962.310141] ? __schedule+0x1e80/0x1e80 [ 962.310148] ? _raw_spin_lock_irq+0x9f/0x130 [ 962.310155] ? _raw_write_unlock_irqrestore+0x110/0x110 [ 962.310164] worker_thread+0x196/0x11e0 [ 962.310175] ? set_load_weight+0x2e0/0x2e0 [ 962.310181] ? __switch_to_asm+0x34/0x70 [ 962.310187] ? __switch_to_asm+0x40/0x70 [ 962.310194] ? process_one_work+0x1400/0x1400 [ 962.310199] ? __switch_to_asm+0x40/0x70 [ 962.310205] ? __switch_to_asm+0x34/0x70 [ 962.310211] ? __switch_to_asm+0x34/0x70 [ 962.310216] ? __switch_to_asm+0x40/0x70 [ 962.310221] ? __switch_to_asm+0x34/0x70 [ 962.310226] ? __switch_to_asm+0x40/0x70 [ 962.310231] ? __switch_to_asm+0x34/0x70 [ 962.310236] ? __switch_to_asm+0x40/0x70 [ 962.310242] ? syscall_return_via_sysret+0xf/0x7f [ 962.310248] ? __switch_to_asm+0x34/0x70 [ 962.310253] ? __switch_to_asm+0x40/0x70 [ 962.310258] ? __switch_to_asm+0x34/0x70 [ 962.310263] ? __switch_to_asm+0x40/0x70 [ 962.310268] ? __switch_to_asm+0x34/0x70 [ 962.310273] ? __switch_to_asm+0x40/0x70 [ 962.310281] ? __schedule+0x87f/0x1e80 [ 962.310292] ? __sched_text_start+0x8/0x8 [ 962.310300] ? save_stack+0x8c/0xb0 [ 962.310308] ? __kasan_kmalloc.constprop.6+0xc6/0xd0 [ 962.310313] ? kthread+0x98/0x3a0 [ 962.310318] ? ret_from_fork+0x35/0x40 [ 962.310334] ? __wake_up_common+0x178/0x6f0 [ 962.310343] ? _raw_spin_lock_irqsave+0xa4/0x140 [ 962.310349] ? __lock_text_start+0x8/0x8 [ 962.310355] ? _raw_write_lock_irqsave+0x70/0x130 [ 962.310360] ? __lock_text_start+0x8/0x8 [ 962.310371] ? process_one_work+0x1400/0x1400 [ 962.310376] kthread+0x2e2/0x3a0 [ 962.310383] ? kthread_create_on_node+0xc0/0xc0 [ 962.310389] ret_from_fork+0x35/0x40 [ 962.310401] Allocated by task 1462: [ 962.310410] __kasan_kmalloc.constprop.6+0xc6/0xd0 [ 962.310437] drm_dp_add_port+0xd60/0x1960 [drm_kms_helper] [ 962.310464] drm_dp_send_link_address+0x4b0/0x770 [drm_kms_helper] [ 962.310491] drm_dp_check_and_send_link_address+0x197/0x1f0 [drm_kms_helper] [ 962.310515] drm_dp_mst_link_probe_work+0x2b6/0x330 [drm_kms_helper] [ 962.310522] process_one_work+0x884/0x1400 [ 962.310529] worker_thread+0x196/0x11e0 [ 962.310533] kthread+0x2e2/0x3a0 [ 962.310538] ret_from_fork+0x35/0x40 [ 962.310543] Freed by task 500: [ 962.310550] __kasan_slab_free+0x133/0x180 [ 962.310555] kfree+0x92/0x1a0 [ 962.310581] drm_dp_mst_put_port_malloc+0x14d/0x180 [drm_kms_helper] [ 962.310693] intel_connector_destroy+0xb2/0xe0 [i915] [ 962.310747] drm_mode_object_put.part.0+0x12b/0x1a0 [drm] [ 962.310802] drm_atomic_state_default_clear+0x1f2/0xcc0 [drm] [ 962.310916] intel_atomic_state_clear+0xe/0x80 [i915] [ 962.310972] __drm_atomic_state_free+0x35/0xd0 [drm] [ 962.311083] intel_atomic_cleanup_work+0x56/0x70 [i915] [ 962.311092] process_one_work+0x884/0x1400 [ 962.311098] worker_thread+0x196/0x11e0 [ 962.311103] kthread+0x2e2/0x3a0 [ 962.311108] ret_from_fork+0x35/0x40 [ 962.311116] The buggy address belongs to the object at ffff888416c30000 which belongs to the cache kmalloc-2k of size 2048 [ 962.311122] The buggy address is located 4 bytes inside of 2048-byte region [ffff888416c30000, ffff888416c30800) [ 962.311124] The buggy address belongs to the page: [ 962.311132] page:ffffea00105b0c00 count:1 mapcount:0 mapping:ffff88841d003040 index:0x0 compound_mapcount: 0 [ 962.311142] flags: 0x8000000000010200(slab|head) [ 962.311152] raw: 8000000000010200 dead000000000100 dead000000000200 ffff88841d003040 [ 962.311159] raw: 0000000000000000 00000000000f000f 00000001ffffffff 0000000000000000 [ 962.311162] page dumped because: kasan: bad access detected So, bail early if drm_dp_mst_deallocate_vcpi() is called on a port with no VCPI allocation. Additionally, clean up the surrounding kerneldoc while we're at it since the port is assumed to be kept around because the DRM driver is expected to hold a malloc reference to it, not just us. Changes since v1: * Doc changes - danvet Signed-off-by: Lyude Paul Fixes: eceae1472467 ("drm/dp_mst: Start tracking per-port VCPI allocations") Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190202002023.29665-2-lyude@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 6d0d8e01f16e..db0fdc513b9c 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3311,15 +3311,16 @@ EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); /** * drm_dp_mst_deallocate_vcpi() - deallocate a VCPI * @mgr: manager for this port - * @port: unverified port to deallocate vcpi for + * @port: port to deallocate vcpi for + * + * This can be called unconditionally, regardless of whether + * drm_dp_mst_allocate_vcpi() succeeded or not. */ void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { - /* - * A port with VCPI will remain allocated until its VCPI is - * released, no verified ref needed - */ + if (!port->vcpi.vcpi) + return; drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); port->vcpi.num_slots = 0; -- cgit v1.2.3 From a3d15c4b0ecd169c77dfdf659b2ff2e502179d19 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 1 Feb 2019 19:20:02 -0500 Subject: drm/dp_mst: Remove port validation in drm_dp_atomic_find_vcpi_slots() Since we now have an easy way of refcounting drm_dp_mst_port structs and safely accessing their contents, there isn't any good reason to keep validating ports here. It doesn't prevent us from performing modesets on branch devices that have been removed either, and we already disallow enabling new displays on unregistered connectors in update_connector_routing() in drm_atomic_check_modeset(). All it does is cause us to have to make weird special exceptions in our atomic modesetting code. So, get rid of it entirely. Signed-off-by: Lyude Paul Fixes: eceae1472467 ("drm/dp_mst: Start tracking per-port VCPI allocations") Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190202002023.29665-3-lyude@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 12 ++---------- drivers/gpu/drm/i915/intel_dp_mst.c | 17 ++++++----------- drivers/gpu/drm/nouveau/dispnv50/disp.c | 3 +-- 3 files changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index db0fdc513b9c..dc7ac0c60547 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3117,10 +3117,6 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, if (IS_ERR(topology_state)) return PTR_ERR(topology_state); - port = drm_dp_mst_topology_get_port_validated(mgr, port); - if (port == NULL) - return -EINVAL; - /* Find the current allocation for this port, if any */ list_for_each_entry(pos, &topology_state->vcpis, next) { if (pos->port == port) { @@ -3153,10 +3149,8 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, /* Add the new allocation to the state */ if (!vcpi) { vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); - if (!vcpi) { - ret = -ENOMEM; - goto out; - } + if (!vcpi) + return -ENOMEM; drm_dp_mst_get_port_malloc(port); vcpi->port = port; @@ -3165,8 +3159,6 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, vcpi->vcpi = req_slots; ret = req_slots; -out: - drm_dp_mst_topology_put_port(port); return ret; } EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index b61e291367b4..5d8471f080d9 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -80,17 +80,12 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); pipe_config->pbn = mst_pbn; - /* Zombie connectors can't have VCPI slots */ - if (!drm_connector_is_unregistered(connector)) { - slots = drm_dp_atomic_find_vcpi_slots(state, - &intel_dp->mst_mgr, - port, - mst_pbn); - if (slots < 0) { - DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", - slots); - return slots; - } + slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, port, + mst_pbn); + if (slots < 0) { + DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", + slots); + return slots; } intel_link_compute_m_n(bpp, lane_count, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 2e8a5fd9b262..60d858c2f2ce 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -771,8 +771,7 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); - if (drm_atomic_crtc_needs_modeset(crtc_state) && - !drm_connector_is_unregistered(connector)) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) { slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port, mstc->pbn); if (slots < 0) -- cgit v1.2.3 From 022debad063e4d3fb456218273821c010757f6f7 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 1 Feb 2019 19:20:03 -0500 Subject: drm/atomic: Add drm_atomic_state->duplicated Since commit 39b50c603878 ("drm/atomic_helper: Stop modesets on unregistered connectors harder") We've been failing atomic checks if they try to enable new displays on unregistered connectors. This is fine except for the one situation that breaks atomic assumptions: suspend/resume. If a connector is unregistered before we attempt to restore the atomic state, something we end up failing the atomic check that happens when trying to restore the state during resume. Normally this would be OK: we try our best to make sure that the atomic state pre-suspend can be restored post-suspend, but failures at that point usually don't cause problems. That is of course, until we introduced the new atomic MST VCPI helpers: [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] [CRTC:65:pipe B] active changed [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Updating routing for [CONNECTOR:123:DP-5] [drm:drm_atomic_helper_check_modeset [drm_kms_helper]] Disabling [CONNECTOR:123:DP-5] [drm:drm_atomic_get_private_obj_state [drm]] Added new private object 0000000025844636 state 000000009fd2899a to 000000003a13d7b8 WARNING: CPU: 6 PID: 1070 at drivers/gpu/drm/drm_dp_mst_topology.c:3153 drm_dp_atomic_release_vcpi_slots+0xb9/0x200 [drm_kms_helper] Modules linked in: fuse vfat fat snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic joydev iTCO_wdt i915(O) wmi_bmof intel_rapl btusb btrtl x86_pkg_temp_thermal btbcm btintel coretemp i2c_algo_bit drm_kms_helper(O) crc32_pclmul snd_hda_intel syscopyarea sysfillrect snd_hda_codec sysimgblt snd_hda_core bluetooth fb_sys_fops snd_pcm pcspkr drm(O) psmouse snd_timer mei_me ecdh_generic i2c_i801 mei i2c_core ucsi_acpi typec_ucsi typec wmi thinkpad_acpi ledtrig_audio snd soundcore tpm_tis rfkill tpm_tis_core video tpm acpi_pad pcc_cpufreq uas usb_storage crc32c_intel nvme serio_raw xhci_pci nvme_core xhci_hcd CPU: 6 PID: 1070 Comm: gnome-shell Tainted: G W O 5.0.0-rc2Lyude-Test+ #1 Hardware name: LENOVO 20L8S2N800/20L8S2N800, BIOS N22ET35W (1.12 ) 04/09/2018 RIP: 0010:drm_dp_atomic_release_vcpi_slots+0xb9/0x200 [drm_kms_helper] Code: 00 4c 39 6d f0 74 49 48 8d 7b 10 48 89 f9 48 c1 e9 03 42 80 3c 21 00 0f 85 d2 00 00 00 48 8b 6b 10 48 8d 5d f0 49 39 ee 75 c5 <0f> 0b 48 c7 c7 c0 78 b3 a0 48 89 c2 4c 89 ee e8 03 6c aa ff b8 ea RSP: 0018:ffff88841235f268 EFLAGS: 00010246 RAX: ffff88841bf12ab0 RBX: ffff88841bf12aa8 RCX: 1ffff110837e2557 RDX: dffffc0000000000 RSI: 0000000000000000 RDI: ffffed108246bde0 RBP: ffff88841bf12ab8 R08: ffffed1083db3c93 R09: ffffed1083db3c92 R10: ffffed1083db3c92 R11: ffff88841ed9e497 R12: ffff888419555d80 R13: ffff8883bc499100 R14: ffff88841bf12ab8 R15: 0000000000000000 FS: 00007f16fbd4cd00(0000) GS:ffff88841ed80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1687c9f000 CR3: 00000003ba3cc003 CR4: 00000000003606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: drm_atomic_helper_check_modeset+0xf21/0x2f50 [drm_kms_helper] ? drm_atomic_helper_commit_modeset_enables+0xa90/0xa90 [drm_kms_helper] ? __printk_safe_exit+0x10/0x10 ? save_stack+0x8c/0xb0 ? vprintk_func+0x96/0x1bf ? __printk_safe_exit+0x10/0x10 intel_atomic_check+0x234/0x4750 [i915] ? printk+0x9f/0xc5 ? kmsg_dump_rewind_nolock+0xd9/0xd9 ? _raw_spin_lock_irqsave+0xa4/0x140 ? drm_atomic_check_only+0xb1/0x28b0 [drm] ? drm_dbg+0x186/0x1b0 [drm] ? drm_dev_dbg+0x200/0x200 [drm] ? intel_link_compute_m_n+0xb0/0xb0 [i915] ? drm_mode_put_tile_group+0x20/0x20 [drm] ? skl_plane_format_mod_supported+0x17f/0x1b0 [i915] ? drm_plane_check_pixel_format+0x14a/0x310 [drm] drm_atomic_check_only+0x13c4/0x28b0 [drm] ? drm_state_info+0x220/0x220 [drm] ? drm_atomic_helper_disable_plane+0x1d0/0x1d0 [drm_kms_helper] ? pick_single_encoder_for_connector+0xe0/0xe0 [drm_kms_helper] ? kasan_unpoison_shadow+0x35/0x40 drm_atomic_commit+0x3b/0x100 [drm] drm_atomic_helper_set_config+0xd5/0x100 [drm_kms_helper] drm_mode_setcrtc+0x636/0x1660 [drm] ? vprintk_func+0x96/0x1bf ? drm_dev_dbg+0x200/0x200 [drm] ? drm_mode_getcrtc+0x790/0x790 [drm] ? printk+0x9f/0xc5 ? mutex_unlock+0x1d/0x40 ? drm_mode_addfb2+0x2e9/0x3a0 [drm] ? rcu_sync_dtor+0x2e0/0x2e0 ? drm_dbg+0x186/0x1b0 [drm] ? set_page_dirty+0x271/0x4d0 drm_ioctl_kernel+0x203/0x290 [drm] ? drm_mode_getcrtc+0x790/0x790 [drm] ? drm_setversion+0x7f0/0x7f0 [drm] ? __switch_to_asm+0x34/0x70 ? __switch_to_asm+0x34/0x70 drm_ioctl+0x445/0x950 [drm] ? drm_mode_getcrtc+0x790/0x790 [drm] ? drm_getunique+0x220/0x220 [drm] ? expand_files.part.10+0x920/0x920 do_vfs_ioctl+0x1a1/0x13d0 ? ioctl_preallocate+0x2b0/0x2b0 ? __fget_light+0x2d6/0x390 ? schedule+0xd7/0x2e0 ? fget_raw+0x10/0x10 ? apic_timer_interrupt+0xa/0x20 ? apic_timer_interrupt+0xa/0x20 ? rcu_cleanup_dead_rnp+0x2c0/0x2c0 ksys_ioctl+0x60/0x90 __x64_sys_ioctl+0x6f/0xb0 do_syscall_64+0x136/0x440 ? syscall_return_slowpath+0x2d0/0x2d0 ? do_page_fault+0x89/0x330 ? __do_page_fault+0x9c0/0x9c0 ? prepare_exit_to_usermode+0x188/0x200 ? perf_trace_sys_enter+0x1090/0x1090 ? __x64_sys_sigaltstack+0x280/0x280 ? __put_user_4+0x1c/0x30 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7f16ff89a09b Code: 0f 1e fa 48 8b 05 ed bd 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bd bd 0c 00 f7 d8 64 89 01 48 RSP: 002b:00007fff001232b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007fff001232f0 RCX: 00007f16ff89a09b RDX: 00007fff001232f0 RSI: 00000000c06864a2 RDI: 000000000000000b RBP: 00007fff001232f0 R08: 0000000000000000 R09: 000055a79d484460 R10: 000055a79d44e770 R11: 0000000000000246 R12: 00000000c06864a2 R13: 000000000000000b R14: 0000000000000000 R15: 000055a79d44e770 WARNING: CPU: 6 PID: 1070 at drivers/gpu/drm/drm_dp_mst_topology.c:3153 drm_dp_atomic_release_vcpi_slots+0xb9/0x200 [drm_kms_helper] ---[ end trace d536c05c13c83be2 ]--- [drm:drm_dp_atomic_release_vcpi_slots [drm_kms_helper]] *ERROR* no VCPI for [MST PORT:00000000f9e2b143] found in mst state 000000009fd2899a This appears to be happening because we destroy the VCPI allocations when disabling all connected displays while suspending, and those VCPI allocations don't get restored on resume due to failing to restore the atomic state. So, fix this by introducing the suspending option to drm_atomic_helper_duplicate_state() and use that to indicate in the atomic state that it's being used for suspending or resuming the system, and thus needs to be fixed up by the driver. We can then use the new state->duplicated hook to tell update_connector_routing() in drm_atomic_check_modeset() to allow for modesets on unregistered connectors, which allows us to restore atomic states that contain MST topologies that were removed after the state was duplicated and thus: mostly fixing suspend and resume. This just leaves some issues that were introduced with nouveau, that will be addressed next. Changes since v3: * Remove ->duplicated hunks that I left in the VCPI helpers by accident. These don't need to be here, that was the supposed to be the purpose of the last revision Changes since v2: * Remove the changes in this patch to the VCPI helpers, they aren't needed anymore Changes since v1: * Rename suspend_or_resume to duplicated Signed-off-by: Lyude Paul Fixes: eceae1472467 ("drm/dp_mst: Start tracking per-port VCPI allocations") Cc: Daniel Vetter Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190202002023.29665-4-lyude@redhat.com --- drivers/gpu/drm/drm_atomic_helper.c | 10 +++++++++- drivers/gpu/drm/drm_dp_mst_topology.c | 9 +++++++++ include/drm/drm_atomic.h | 9 +++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 440cfa91162a..c53ecbd9abdd 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -332,8 +332,15 @@ update_connector_routing(struct drm_atomic_state *state, * about is ensuring that userspace can't do anything but shut off the * display on a connector that was destroyed after it's been notified, * not before. + * + * Additionally, we also want to ignore connector registration when + * we're trying to restore an atomic state during system resume since + * there's a chance the connector may have been destroyed during the + * process, but it's better to ignore that then cause + * drm_atomic_helper_resume() to fail. */ - if (drm_connector_is_unregistered(connector) && crtc_state->active) { + if (!state->duplicated && drm_connector_is_unregistered(connector) && + crtc_state->active) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n", connector->base.id, connector->name); return -EINVAL; @@ -3180,6 +3187,7 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, return ERR_PTR(-ENOMEM); state->acquire_ctx = ctx; + state->duplicated = true; drm_for_each_crtc(crtc, dev) { struct drm_crtc_state *crtc_state; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index dc7ac0c60547..5a99135d39cd 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3097,6 +3097,10 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, * @port as needed. It is not OK however, to call this function and * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. * + * When &drm_atomic_state.duplicated is set to %true%, this function will not + * perform any error checking and will instead simply return the previously + * recorded VCPI allocations. + * * See also: * drm_dp_atomic_release_vcpi_slots() * drm_dp_mst_atomic_check() @@ -3181,6 +3185,11 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check * phase. * + * When &drm_atomic_state.duplicated is set, this function will not + * modify the VCPI allocations in &drm_dp_mst_topology_state.vcpis, so that + * those VCPI allocations may be restored as-is from the duplicated state. In + * this scenario, this function will always return 0. + * * See also: * drm_dp_atomic_find_vcpi_slots() * drm_dp_mst_atomic_check() diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 3b97b2bfaad9..824a5ed4e216 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -329,6 +329,15 @@ struct drm_atomic_state { bool allow_modeset : 1; bool legacy_cursor_update : 1; bool async_update : 1; + /** + * @duplicated: + * + * Indicates whether or not this atomic state was duplicated using + * drm_atomic_helper_duplicate_state(). Drivers and atomic helpers + * should use this to fixup normal inconsistencies in duplicated + * states. + */ + bool duplicated : 1; struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; -- cgit v1.2.3 From 88ec89adec3630a67d682c032c946e1bd4f59ac2 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 1 Feb 2019 19:20:04 -0500 Subject: drm/nouveau: Move PBN and VCPI allocation into nv50_head_atom Atomic checks should never modify anything outside of the state that they're passed in. Unfortunately this appears to be exactly what we're doing in nv50_msto_atomic_check() where we update mstc->pbn every time the function is called. This hasn't caused any bugs yet, but it needs to be fixed in order to ensure that when committing an artificially duplicated state (like during system resume), that we reuse the PBN of that state to perform VCPI allocations and don't recalculate a different value from the drm connector's reported bpc. Also, move the VCPI slot allocations while we're at it as well. With this, removing a topology in suspend while using nouveau no longer causes the new atomic VCPI helpers to complain. Signed-off-by: Lyude Paul Fixes: eceae1472467 ("drm/dp_mst: Start tracking per-port VCPI allocations") Cc: Daniel Vetter Reviewed-by: Ben Skeggs Link: https://patchwork.freedesktop.org/patch/msgid/20190202002023.29665-5-lyude@redhat.com --- drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 ++++++ drivers/gpu/drm/nouveau/dispnv50/disp.c | 28 +++++++++++++++++----------- drivers/gpu/drm/nouveau/dispnv50/head.c | 1 + 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index a194990d2b0d..b5fae5ab3fa8 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -116,6 +116,12 @@ struct nv50_head_atom { u8 depth:4; } or; + /* Currently only used for MST */ + struct { + int pbn; + u8 tu:6; + } dp; + union nv50_head_atom_mask { struct { bool olut:1; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 60d858c2f2ce..e8bb35f6d015 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -659,8 +659,6 @@ struct nv50_mstc { struct drm_display_mode *native; struct edid *edid; - - int pbn; }; struct nv50_msto { @@ -765,17 +763,26 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, struct drm_connector *connector = conn_state->connector; struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstm *mstm = mstc->mstm; - int bpp = connector->display_info.bpc * 3; + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); int slots; - mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, - bpp); + /* When restoring duplicated states, we need to make sure that the + * bw remains the same and avoid recalculating it, as the connector's + * bpc may have changed after the state was duplicated + */ + if (!state->duplicated) + asyh->dp.pbn = + drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, + connector->display_info.bpc * 3); if (drm_atomic_crtc_needs_modeset(crtc_state)) { slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, - mstc->port, mstc->pbn); + mstc->port, + asyh->dp.pbn); if (slots < 0) return slots; + + asyh->dp.tu = slots; } return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, @@ -786,13 +793,13 @@ static void nv50_msto_enable(struct drm_encoder *encoder) { struct nv50_head *head = nv50_head(encoder->crtc); + struct nv50_head_atom *armh = nv50_head_atom(head->base.base.state); struct nv50_msto *msto = nv50_msto(encoder); struct nv50_mstc *mstc = NULL; struct nv50_mstm *mstm = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; u8 proto, depth; - int slots; bool r; drm_connector_list_iter_begin(encoder->dev, &conn_iter); @@ -808,8 +815,8 @@ nv50_msto_enable(struct drm_encoder *encoder) if (WARN_ON(!mstc)) return; - slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); - r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); + r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, armh->dp.pbn, + armh->dp.tu); WARN_ON(!r); if (!mstm->links++) @@ -827,8 +834,7 @@ nv50_msto_enable(struct drm_encoder *encoder) default: depth = 0x6; break; } - mstm->outp->update(mstm->outp, head->base.index, - nv50_head_atom(head->base.base.state), proto, depth); + mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth); msto->head = head; msto->mstc = mstc; diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index ac97ebce5b35..2e7a0c347ddb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -413,6 +413,7 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) asyh->ovly = armh->ovly; asyh->dither = armh->dither; asyh->procamp = armh->procamp; + asyh->dp = armh->dp; asyh->clr.mask = 0; asyh->set.mask = 0; return &asyh->state; -- cgit v1.2.3 From 123cbb6c70e1a6270a19aa48765394b549a12cdf Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Wed, 6 Feb 2019 13:31:01 -0500 Subject: drm/dp_mst: Remove rebase-detritus in VCPI helper kernel-docs Looks like when making the final revision of: commit 022debad063e ("drm/atomic: Add drm_atomic_state->duplicated") I forgot to remove some of the comments that I had added to drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() that were no longer valid due to us having removed the state->duplicated checks from each function. This also introduced an error while building the docs with sphinx: ./drivers/gpu/drm/drm_dp_mst_topology.c:3100: WARNING: Inline literal start-string without end-string. So, fix that by just removing the kerneldoc comments. Signed-off-by: Lyude Paul Fixes: 022debad063e ("drm/atomic: Add drm_atomic_state->duplicated") Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190202002023.29665-5-lyude@redhat.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 5a99135d39cd..dc7ac0c60547 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3097,10 +3097,6 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, * @port as needed. It is not OK however, to call this function and * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. * - * When &drm_atomic_state.duplicated is set to %true%, this function will not - * perform any error checking and will instead simply return the previously - * recorded VCPI allocations. - * * See also: * drm_dp_atomic_release_vcpi_slots() * drm_dp_mst_atomic_check() @@ -3185,11 +3181,6 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check * phase. * - * When &drm_atomic_state.duplicated is set, this function will not - * modify the VCPI allocations in &drm_dp_mst_topology_state.vcpis, so that - * those VCPI allocations may be restored as-is from the duplicated state. In - * this scenario, this function will always return 0. - * * See also: * drm_dp_atomic_find_vcpi_slots() * drm_dp_mst_atomic_check() -- cgit v1.2.3 From 1eb6ea4a820291107d1192df7d279f344ee2053f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 30 Jan 2019 19:00:15 -0600 Subject: drm/vc4: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + count * sizeof(struct boo), GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20190131010015.GA32272@embeddedor --- drivers/gpu/drm/vc4/vc4_perfmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c index 437e7a27f21d..495150415020 100644 --- a/drivers/gpu/drm/vc4/vc4_perfmon.c +++ b/drivers/gpu/drm/vc4/vc4_perfmon.c @@ -117,7 +117,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - perfmon = kzalloc(sizeof(*perfmon) + (req->ncounters * sizeof(u64)), + perfmon = kzalloc(struct_size(perfmon, counters, req->ncounters), GFP_KERNEL); if (!perfmon) return -ENOMEM; -- cgit v1.2.3 From bb3b6fcb68496e405057456ef1453ce963afba14 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 21 Jan 2019 16:45:49 +0100 Subject: sun6i: dsi: Convert to generic phy handling Now that we have everything in place in the PHY framework to deal in a generic way with MIPI D-PHY phys, let's convert our PHY driver and its associated DSI driver to that new API. Reviewed-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/dc6450e2978b6dafcc464595ad06204d22d2658f.1548085432.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/Kconfig | 11 ++- drivers/gpu/drm/sun4i/Makefile | 6 +- drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c | 164 ++++++++++++++++++-------------- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 31 +++--- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 17 +--- 5 files changed, 126 insertions(+), 103 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index c2c042287c19..2b8db82c4bab 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -45,10 +45,19 @@ config DRM_SUN6I_DSI default MACH_SUN8I select CRC_CCITT select DRM_MIPI_DSI + select DRM_SUN6I_DPHY help Choose this option if you want have an Allwinner SoC with MIPI-DSI support. If M is selected the module will be called - sun6i-dsi + sun6i_mipi_dsi. + +config DRM_SUN6I_DPHY + tristate "Allwinner A31 MIPI D-PHY Support" + select GENERIC_PHY_MIPI_DPHY + help + Choose this option if you have an Allwinner SoC with + MIPI-DSI support. If M is selected, the module will be + called sun6i_mipi_dphy. config DRM_SUN8I_DW_HDMI tristate "Support for Allwinner version of DesignWare HDMI" diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 0eb38ac8e86e..1e2320d824b5 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -24,9 +24,6 @@ sun4i-tcon-y += sun4i_lvds.o sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_rgb.o -sun6i-dsi-y += sun6i_mipi_dphy.o -sun6i-dsi-y += sun6i_mipi_dsi.o - obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o @@ -37,7 +34,8 @@ ifdef CONFIG_DRM_SUN4I_BACKEND obj-$(CONFIG_DRM_SUN4I) += sun4i-frontend.o endif obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o -obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o +obj-$(CONFIG_DRM_SUN6I_DPHY) += sun6i_mipi_dphy.o +obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i_mipi_dsi.o obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c index e4d19431fa0e..79c8af5c7c1d 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c @@ -8,11 +8,14 @@ #include #include +#include #include +#include #include #include -#include "sun6i_mipi_dsi.h" +#include +#include #define SUN6I_DPHY_GCTL_REG 0x00 #define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4) @@ -81,12 +84,46 @@ #define SUN6I_DPHY_DBG5_REG 0xf4 -int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes) +struct sun6i_dphy { + struct clk *bus_clk; + struct clk *mod_clk; + struct regmap *regs; + struct reset_control *reset; + + struct phy *phy; + struct phy_configure_opts_mipi_dphy config; +}; + +static int sun6i_dphy_init(struct phy *phy) { + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + reset_control_deassert(dphy->reset); clk_prepare_enable(dphy->mod_clk); clk_set_rate_exclusive(dphy->mod_clk, 150000000); + return 0; +} + +static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + int ret; + + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); + if (ret) + return ret; + + memcpy(&dphy->config, opts, sizeof(dphy->config)); + + return 0; +} + +static int sun6i_dphy_power_on(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); + regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); @@ -111,16 +148,9 @@ int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes) SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, - SUN6I_DPHY_GCTL_LANE_NUM(lanes) | + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | SUN6I_DPHY_GCTL_EN); - return 0; -} - -int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes) -{ - u8 lanes_mask = GENMASK(lanes - 1, 0); - regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, SUN6I_DPHY_ANA0_REG_PWS | SUN6I_DPHY_ANA0_REG_DMPC | @@ -181,16 +211,20 @@ int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes) return 0; } -int sun6i_dphy_power_off(struct sun6i_dphy *dphy) +static int sun6i_dphy_power_off(struct phy *phy) { + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, SUN6I_DPHY_ANA1_REG_VTTMODE, 0); return 0; } -int sun6i_dphy_exit(struct sun6i_dphy *dphy) +static int sun6i_dphy_exit(struct phy *phy) { + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + clk_rate_exclusive_put(dphy->mod_clk); clk_disable_unprepare(dphy->mod_clk); reset_control_assert(dphy->reset); @@ -198,6 +232,15 @@ int sun6i_dphy_exit(struct sun6i_dphy *dphy) return 0; } + +static struct phy_ops sun6i_dphy_ops = { + .configure = sun6i_dphy_configure, + .power_on = sun6i_dphy_power_on, + .power_off = sun6i_dphy_power_off, + .init = sun6i_dphy_init, + .exit = sun6i_dphy_exit, +}; + static struct regmap_config sun6i_dphy_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -206,87 +249,70 @@ static struct regmap_config sun6i_dphy_regmap_config = { .name = "mipi-dphy", }; -static const struct of_device_id sun6i_dphy_of_table[] = { - { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, - { } -}; - -int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node) +static int sun6i_dphy_probe(struct platform_device *pdev) { + struct phy_provider *phy_provider; struct sun6i_dphy *dphy; - struct resource res; + struct resource *res; void __iomem *regs; - int ret; - - if (!of_match_node(sun6i_dphy_of_table, node)) { - dev_err(dsi->dev, "Incompatible D-PHY\n"); - return -EINVAL; - } - dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL); + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); if (!dphy) return -ENOMEM; - ret = of_address_to_resource(node, 0, &res); - if (ret) { - dev_err(dsi->dev, "phy: Couldn't get our resources\n"); - return ret; - } - - regs = devm_ioremap_resource(dsi->dev, &res); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(regs)) { - dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n"); + dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); return PTR_ERR(regs); } - dphy->regs = devm_regmap_init_mmio(dsi->dev, regs, - &sun6i_dphy_regmap_config); + dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", + regs, &sun6i_dphy_regmap_config); if (IS_ERR(dphy->regs)) { - dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n"); + dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); return PTR_ERR(dphy->regs); } - dphy->reset = of_reset_control_get_shared(node, NULL); + dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); if (IS_ERR(dphy->reset)) { - dev_err(dsi->dev, "Couldn't get our reset line\n"); + dev_err(&pdev->dev, "Couldn't get our reset line\n"); return PTR_ERR(dphy->reset); } - dphy->bus_clk = of_clk_get_by_name(node, "bus"); - if (IS_ERR(dphy->bus_clk)) { - dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n"); - ret = PTR_ERR(dphy->bus_clk); - goto err_free_reset; - } - regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk); - - dphy->mod_clk = of_clk_get_by_name(node, "mod"); + dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(dphy->mod_clk)) { - dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n"); - ret = PTR_ERR(dphy->mod_clk); - goto err_free_bus; + dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); + return PTR_ERR(dphy->mod_clk); } - dsi->dphy = dphy; + dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); + if (IS_ERR(dphy->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(dphy->phy); + } - return 0; + phy_set_drvdata(dphy->phy, dphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); -err_free_bus: - regmap_mmio_detach_clk(dphy->regs); - clk_put(dphy->bus_clk); -err_free_reset: - reset_control_put(dphy->reset); - return ret; + return PTR_ERR_OR_ZERO(phy_provider); } -int sun6i_dphy_remove(struct sun6i_dsi *dsi) -{ - struct sun6i_dphy *dphy = dsi->dphy; - - regmap_mmio_detach_clk(dphy->regs); - clk_put(dphy->mod_clk); - clk_put(dphy->bus_clk); - reset_control_put(dphy->reset); +static const struct of_device_id sun6i_dphy_of_table[] = { + { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, + { } +}; +MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); + +static struct platform_driver sun6i_dphy_platform_driver = { + .probe = sun6i_dphy_probe, + .driver = { + .name = "sun6i-mipi-dphy", + .of_match_table = sun6i_dphy_of_table, + }, +}; +module_platform_driver(sun6i_dphy_platform_driver); - return 0; -} +MODULE_AUTHOR("Maxime Ripard "); +MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 1ebe56817fa9..9b7bef696957 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -616,6 +617,8 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder); struct mipi_dsi_device *device = dsi->device; + union phy_configure_opts opts = { 0 }; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; u16 delay; DRM_DEBUG_DRIVER("Enabling DSI output\n"); @@ -634,8 +637,15 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) sun6i_dsi_setup_format(dsi, mode); sun6i_dsi_setup_timings(dsi, mode); - sun6i_dphy_init(dsi->dphy, device->lanes); - sun6i_dphy_power_on(dsi->dphy, device->lanes); + phy_init(dsi->dphy); + + phy_mipi_dphy_get_default_config(mode->clock * 1000, + mipi_dsi_pixel_format_to_bpp(device->format), + device->lanes, cfg); + + phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(dsi->dphy, &opts); + phy_power_on(dsi->dphy); if (!IS_ERR(dsi->panel)) drm_panel_prepare(dsi->panel); @@ -673,8 +683,8 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder) drm_panel_unprepare(dsi->panel); } - sun6i_dphy_power_off(dsi->dphy); - sun6i_dphy_exit(dsi->dphy); + phy_power_off(dsi->dphy); + phy_exit(dsi->dphy); pm_runtime_put(dsi->dev); } @@ -967,7 +977,6 @@ static const struct component_ops sun6i_dsi_ops = { static int sun6i_dsi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *dphy_node; struct sun6i_dsi *dsi; struct resource *res; void __iomem *base; @@ -1013,10 +1022,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev) */ clk_set_rate_exclusive(dsi->mod_clk, 297000000); - dphy_node = of_parse_phandle(dev->of_node, "phys", 0); - ret = sun6i_dphy_probe(dsi, dphy_node); - of_node_put(dphy_node); - if (ret) { + dsi->dphy = devm_phy_get(dev, "dphy"); + if (IS_ERR(dsi->dphy)) { dev_err(dev, "Couldn't get the MIPI D-PHY\n"); goto err_unprotect_clk; } @@ -1026,7 +1033,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev) ret = mipi_dsi_host_register(&dsi->host); if (ret) { dev_err(dev, "Couldn't register MIPI-DSI host\n"); - goto err_remove_phy; + goto err_pm_disable; } ret = component_add(&pdev->dev, &sun6i_dsi_ops); @@ -1039,9 +1046,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev) err_remove_dsi_host: mipi_dsi_host_unregister(&dsi->host); -err_remove_phy: +err_pm_disable: pm_runtime_disable(dev); - sun6i_dphy_remove(dsi); err_unprotect_clk: clk_rate_exclusive_put(dsi->mod_clk); return ret; @@ -1055,7 +1061,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev) component_del(&pdev->dev, &sun6i_dsi_ops); mipi_dsi_host_unregister(&dsi->host); pm_runtime_disable(dev); - sun6i_dphy_remove(dsi); clk_rate_exclusive_put(dsi->mod_clk); return 0; diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h index dbbc5b3ecbda..a07090579f84 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h @@ -13,13 +13,6 @@ #include #include -struct sun6i_dphy { - struct clk *bus_clk; - struct clk *mod_clk; - struct regmap *regs; - struct reset_control *reset; -}; - struct sun6i_dsi { struct drm_connector connector; struct drm_encoder encoder; @@ -29,7 +22,7 @@ struct sun6i_dsi { struct clk *mod_clk; struct regmap *regs; struct reset_control *reset; - struct sun6i_dphy *dphy; + struct phy *dphy; struct device *dev; struct sun4i_drv *drv; @@ -52,12 +45,4 @@ static inline struct sun6i_dsi *encoder_to_sun6i_dsi(const struct drm_encoder *e return container_of(encoder, struct sun6i_dsi, encoder); }; -int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node); -int sun6i_dphy_remove(struct sun6i_dsi *dsi); - -int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes); -int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes); -int sun6i_dphy_power_off(struct sun6i_dphy *dphy); -int sun6i_dphy_exit(struct sun6i_dphy *dphy); - #endif /* _SUN6I_MIPI_DSI_H_ */ -- cgit v1.2.3 From 5d134abf9530de2f453a2a5c97d5e165bcc95b83 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 21 Jan 2019 16:45:50 +0100 Subject: phy: Move Allwinner A31 D-PHY driver to drivers/phy/ Now that our MIPI D-PHY driver has been converted to the phy framework, let's move it into the drivers/phy directory. Reviewed-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/2447609da5b80f148c79b2b2a263a0e779f3e82f.1548085432.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/Kconfig | 10 +- drivers/gpu/drm/sun4i/Makefile | 1 - drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c | 318 ---------------------------- drivers/phy/allwinner/Kconfig | 12 ++ drivers/phy/allwinner/Makefile | 1 + drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 318 ++++++++++++++++++++++++++++ 6 files changed, 332 insertions(+), 328 deletions(-) delete mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c create mode 100644 drivers/phy/allwinner/phy-sun6i-mipi-dphy.c (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 2b8db82c4bab..1dbbc3a1b763 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -45,20 +45,12 @@ config DRM_SUN6I_DSI default MACH_SUN8I select CRC_CCITT select DRM_MIPI_DSI - select DRM_SUN6I_DPHY + select PHY_SUN6I_MIPI_DPHY help Choose this option if you want have an Allwinner SoC with MIPI-DSI support. If M is selected the module will be called sun6i_mipi_dsi. -config DRM_SUN6I_DPHY - tristate "Allwinner A31 MIPI D-PHY Support" - select GENERIC_PHY_MIPI_DPHY - help - Choose this option if you have an Allwinner SoC with - MIPI-DSI support. If M is selected, the module will be - called sun6i_mipi_dphy. - config DRM_SUN8I_DW_HDMI tristate "Support for Allwinner version of DesignWare HDMI" depends on DRM_SUN4I diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 1e2320d824b5..0d04f2447b01 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -34,7 +34,6 @@ ifdef CONFIG_DRM_SUN4I_BACKEND obj-$(CONFIG_DRM_SUN4I) += sun4i-frontend.o endif obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o -obj-$(CONFIG_DRM_SUN6I_DPHY) += sun6i_mipi_dphy.o obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i_mipi_dsi.o obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c deleted file mode 100644 index 79c8af5c7c1d..000000000000 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c +++ /dev/null @@ -1,318 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2016 Allwinnertech Co., Ltd. - * Copyright (C) 2017-2018 Bootlin - * - * Maxime Ripard - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define SUN6I_DPHY_GCTL_REG 0x00 -#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4) -#define SUN6I_DPHY_GCTL_EN BIT(0) - -#define SUN6I_DPHY_TX_CTL_REG 0x04 -#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) - -#define SUN6I_DPHY_TX_TIME0_REG 0x10 -#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) -#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) -#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff) - -#define SUN6I_DPHY_TX_TIME1_REG 0x14 -#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24) -#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16) -#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8) -#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff) - -#define SUN6I_DPHY_TX_TIME2_REG 0x18 -#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff) - -#define SUN6I_DPHY_TX_TIME3_REG 0x1c - -#define SUN6I_DPHY_TX_TIME4_REG 0x20 -#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) -#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) - -#define SUN6I_DPHY_ANA0_REG 0x4c -#define SUN6I_DPHY_ANA0_REG_PWS BIT(31) -#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) -#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) -#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) -#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) - -#define SUN6I_DPHY_ANA1_REG 0x50 -#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) -#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28) -#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24) - -#define SUN6I_DPHY_ANA2_REG 0x54 -#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24) -#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24) -#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4) -#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1) - -#define SUN6I_DPHY_ANA3_REG 0x58 -#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28) -#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28) -#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27) -#define SUN6I_DPHY_ANA3_EN_DIV BIT(26) -#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25) -#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24) -#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) - -#define SUN6I_DPHY_ANA4_REG 0x5c -#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) -#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) -#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) -#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) -#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) -#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6) -#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4) -#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2) -#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3) - -#define SUN6I_DPHY_DBG5_REG 0xf4 - -struct sun6i_dphy { - struct clk *bus_clk; - struct clk *mod_clk; - struct regmap *regs; - struct reset_control *reset; - - struct phy *phy; - struct phy_configure_opts_mipi_dphy config; -}; - -static int sun6i_dphy_init(struct phy *phy) -{ - struct sun6i_dphy *dphy = phy_get_drvdata(phy); - - reset_control_deassert(dphy->reset); - clk_prepare_enable(dphy->mod_clk); - clk_set_rate_exclusive(dphy->mod_clk, 150000000); - - return 0; -} - -static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) -{ - struct sun6i_dphy *dphy = phy_get_drvdata(phy); - int ret; - - ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); - if (ret) - return ret; - - memcpy(&dphy->config, opts, sizeof(dphy->config)); - - return 0; -} - -static int sun6i_dphy_power_on(struct phy *phy) -{ - struct sun6i_dphy *dphy = phy_get_drvdata(phy); - u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, - SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, - SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | - SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | - SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, - SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | - SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | - SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | - SUN6I_DPHY_TX_TIME1_CLK_POST(10)); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, - SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); - - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, - SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | - SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); - - regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, - SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | - SUN6I_DPHY_GCTL_EN); - - regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, - SUN6I_DPHY_ANA0_REG_PWS | - SUN6I_DPHY_ANA0_REG_DMPC | - SUN6I_DPHY_ANA0_REG_SLV(7) | - SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) | - SUN6I_DPHY_ANA0_REG_DEN(lanes_mask)); - - regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, - SUN6I_DPHY_ANA1_REG_CSMPS(1) | - SUN6I_DPHY_ANA1_REG_SVTT(7)); - - regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, - SUN6I_DPHY_ANA4_REG_CKDV(1) | - SUN6I_DPHY_ANA4_REG_TMSC(1) | - SUN6I_DPHY_ANA4_REG_TMSD(1) | - SUN6I_DPHY_ANA4_REG_TXDNSC(1) | - SUN6I_DPHY_ANA4_REG_TXDNSD(1) | - SUN6I_DPHY_ANA4_REG_TXPUSC(1) | - SUN6I_DPHY_ANA4_REG_TXPUSD(1) | - SUN6I_DPHY_ANA4_REG_DMPLVC | - SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask)); - - regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, - SUN6I_DPHY_ANA2_REG_ENIB); - udelay(5); - - regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, - SUN6I_DPHY_ANA3_EN_LDOR | - SUN6I_DPHY_ANA3_EN_LDOC | - SUN6I_DPHY_ANA3_EN_LDOD); - udelay(1); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, - SUN6I_DPHY_ANA3_EN_VTTC | - SUN6I_DPHY_ANA3_EN_VTTD_MASK, - SUN6I_DPHY_ANA3_EN_VTTC | - SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask)); - udelay(1); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, - SUN6I_DPHY_ANA3_EN_DIV, - SUN6I_DPHY_ANA3_EN_DIV); - udelay(1); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, - SUN6I_DPHY_ANA2_EN_CK_CPU, - SUN6I_DPHY_ANA2_EN_CK_CPU); - udelay(1); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, - SUN6I_DPHY_ANA1_REG_VTTMODE, - SUN6I_DPHY_ANA1_REG_VTTMODE); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, - SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK, - SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask)); - - return 0; -} - -static int sun6i_dphy_power_off(struct phy *phy) -{ - struct sun6i_dphy *dphy = phy_get_drvdata(phy); - - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, - SUN6I_DPHY_ANA1_REG_VTTMODE, 0); - - return 0; -} - -static int sun6i_dphy_exit(struct phy *phy) -{ - struct sun6i_dphy *dphy = phy_get_drvdata(phy); - - clk_rate_exclusive_put(dphy->mod_clk); - clk_disable_unprepare(dphy->mod_clk); - reset_control_assert(dphy->reset); - - return 0; -} - - -static struct phy_ops sun6i_dphy_ops = { - .configure = sun6i_dphy_configure, - .power_on = sun6i_dphy_power_on, - .power_off = sun6i_dphy_power_off, - .init = sun6i_dphy_init, - .exit = sun6i_dphy_exit, -}; - -static struct regmap_config sun6i_dphy_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = SUN6I_DPHY_DBG5_REG, - .name = "mipi-dphy", -}; - -static int sun6i_dphy_probe(struct platform_device *pdev) -{ - struct phy_provider *phy_provider; - struct sun6i_dphy *dphy; - struct resource *res; - void __iomem *regs; - - dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); - if (!dphy) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) { - dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); - return PTR_ERR(regs); - } - - dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", - regs, &sun6i_dphy_regmap_config); - if (IS_ERR(dphy->regs)) { - dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); - return PTR_ERR(dphy->regs); - } - - dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); - if (IS_ERR(dphy->reset)) { - dev_err(&pdev->dev, "Couldn't get our reset line\n"); - return PTR_ERR(dphy->reset); - } - - dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(dphy->mod_clk)) { - dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); - return PTR_ERR(dphy->mod_clk); - } - - dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); - if (IS_ERR(dphy->phy)) { - dev_err(&pdev->dev, "failed to create PHY\n"); - return PTR_ERR(dphy->phy); - } - - phy_set_drvdata(dphy->phy, dphy); - phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); - - return PTR_ERR_OR_ZERO(phy_provider); -} - -static const struct of_device_id sun6i_dphy_of_table[] = { - { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, - { } -}; -MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); - -static struct platform_driver sun6i_dphy_platform_driver = { - .probe = sun6i_dphy_probe, - .driver = { - .name = "sun6i-mipi-dphy", - .of_match_table = sun6i_dphy_of_table, - }, -}; -module_platform_driver(sun6i_dphy_platform_driver); - -MODULE_AUTHOR("Maxime Ripard "); -MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig index cdc1e745ba47..fb1204bcc454 100644 --- a/drivers/phy/allwinner/Kconfig +++ b/drivers/phy/allwinner/Kconfig @@ -17,6 +17,18 @@ config PHY_SUN4I_USB This driver controls the entire USB PHY block, both the USB OTG parts, as well as the 2 regular USB 2 host PHYs. +config PHY_SUN6I_MIPI_DPHY + tristate "Allwinner A31 MIPI D-PHY Support" + depends on ARCH_SUNXI && HAS_IOMEM && OF + depends on RESET_CONTROLLER + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + select REGMAP_MMIO + help + Choose this option if you have an Allwinner SoC with + MIPI-DSI support. If M is selected, the module will be + called sun6i_mipi_dphy. + config PHY_SUN9I_USB tristate "Allwinner sun9i SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile index 8605529c01a1..7d0053efbfaa 100644 --- a/drivers/phy/allwinner/Makefile +++ b/drivers/phy/allwinner/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o +obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o diff --git a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c new file mode 100644 index 000000000000..79c8af5c7c1d --- /dev/null +++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2016 Allwinnertech Co., Ltd. + * Copyright (C) 2017-2018 Bootlin + * + * Maxime Ripard + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SUN6I_DPHY_GCTL_REG 0x00 +#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4) +#define SUN6I_DPHY_GCTL_EN BIT(0) + +#define SUN6I_DPHY_TX_CTL_REG 0x04 +#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) + +#define SUN6I_DPHY_TX_TIME0_REG 0x10 +#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) +#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) +#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff) + +#define SUN6I_DPHY_TX_TIME1_REG 0x14 +#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24) +#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16) +#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8) +#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff) + +#define SUN6I_DPHY_TX_TIME2_REG 0x18 +#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff) + +#define SUN6I_DPHY_TX_TIME3_REG 0x1c + +#define SUN6I_DPHY_TX_TIME4_REG 0x20 +#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) +#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) + +#define SUN6I_DPHY_ANA0_REG 0x4c +#define SUN6I_DPHY_ANA0_REG_PWS BIT(31) +#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) +#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) +#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) +#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) + +#define SUN6I_DPHY_ANA1_REG 0x50 +#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) +#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28) +#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24) + +#define SUN6I_DPHY_ANA2_REG 0x54 +#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24) +#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24) +#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4) +#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1) + +#define SUN6I_DPHY_ANA3_REG 0x58 +#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28) +#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28) +#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27) +#define SUN6I_DPHY_ANA3_EN_DIV BIT(26) +#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25) +#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24) +#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) + +#define SUN6I_DPHY_ANA4_REG 0x5c +#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) +#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) +#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) +#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) +#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) +#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6) +#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4) +#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2) +#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3) + +#define SUN6I_DPHY_DBG5_REG 0xf4 + +struct sun6i_dphy { + struct clk *bus_clk; + struct clk *mod_clk; + struct regmap *regs; + struct reset_control *reset; + + struct phy *phy; + struct phy_configure_opts_mipi_dphy config; +}; + +static int sun6i_dphy_init(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + + reset_control_deassert(dphy->reset); + clk_prepare_enable(dphy->mod_clk); + clk_set_rate_exclusive(dphy->mod_clk, 150000000); + + return 0; +} + +static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + int ret; + + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); + if (ret) + return ret; + + memcpy(&dphy->config, opts, sizeof(dphy->config)); + + return 0; +} + +static int sun6i_dphy_power_on(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, + SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, + SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | + SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | + SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, + SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | + SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | + SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | + SUN6I_DPHY_TX_TIME1_CLK_POST(10)); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, + SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); + + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, + SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | + SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); + + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | + SUN6I_DPHY_GCTL_EN); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, + SUN6I_DPHY_ANA0_REG_PWS | + SUN6I_DPHY_ANA0_REG_DMPC | + SUN6I_DPHY_ANA0_REG_SLV(7) | + SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) | + SUN6I_DPHY_ANA0_REG_DEN(lanes_mask)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, + SUN6I_DPHY_ANA1_REG_CSMPS(1) | + SUN6I_DPHY_ANA1_REG_SVTT(7)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, + SUN6I_DPHY_ANA4_REG_CKDV(1) | + SUN6I_DPHY_ANA4_REG_TMSC(1) | + SUN6I_DPHY_ANA4_REG_TMSD(1) | + SUN6I_DPHY_ANA4_REG_TXDNSC(1) | + SUN6I_DPHY_ANA4_REG_TXDNSD(1) | + SUN6I_DPHY_ANA4_REG_TXPUSC(1) | + SUN6I_DPHY_ANA4_REG_TXPUSD(1) | + SUN6I_DPHY_ANA4_REG_DMPLVC | + SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, + SUN6I_DPHY_ANA2_REG_ENIB); + udelay(5); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, + SUN6I_DPHY_ANA3_EN_LDOR | + SUN6I_DPHY_ANA3_EN_LDOC | + SUN6I_DPHY_ANA3_EN_LDOD); + udelay(1); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, + SUN6I_DPHY_ANA3_EN_VTTC | + SUN6I_DPHY_ANA3_EN_VTTD_MASK, + SUN6I_DPHY_ANA3_EN_VTTC | + SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask)); + udelay(1); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, + SUN6I_DPHY_ANA3_EN_DIV, + SUN6I_DPHY_ANA3_EN_DIV); + udelay(1); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, + SUN6I_DPHY_ANA2_EN_CK_CPU, + SUN6I_DPHY_ANA2_EN_CK_CPU); + udelay(1); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, + SUN6I_DPHY_ANA1_REG_VTTMODE, + SUN6I_DPHY_ANA1_REG_VTTMODE); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, + SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK, + SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask)); + + return 0; +} + +static int sun6i_dphy_power_off(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, + SUN6I_DPHY_ANA1_REG_VTTMODE, 0); + + return 0; +} + +static int sun6i_dphy_exit(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + + clk_rate_exclusive_put(dphy->mod_clk); + clk_disable_unprepare(dphy->mod_clk); + reset_control_assert(dphy->reset); + + return 0; +} + + +static struct phy_ops sun6i_dphy_ops = { + .configure = sun6i_dphy_configure, + .power_on = sun6i_dphy_power_on, + .power_off = sun6i_dphy_power_off, + .init = sun6i_dphy_init, + .exit = sun6i_dphy_exit, +}; + +static struct regmap_config sun6i_dphy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = SUN6I_DPHY_DBG5_REG, + .name = "mipi-dphy", +}; + +static int sun6i_dphy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct sun6i_dphy *dphy; + struct resource *res; + void __iomem *regs; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); + return PTR_ERR(regs); + } + + dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", + regs, &sun6i_dphy_regmap_config); + if (IS_ERR(dphy->regs)) { + dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); + return PTR_ERR(dphy->regs); + } + + dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(dphy->reset)) { + dev_err(&pdev->dev, "Couldn't get our reset line\n"); + return PTR_ERR(dphy->reset); + } + + dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(dphy->mod_clk)) { + dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); + return PTR_ERR(dphy->mod_clk); + } + + dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); + if (IS_ERR(dphy->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(dphy->phy); + } + + phy_set_drvdata(dphy->phy, dphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id sun6i_dphy_of_table[] = { + { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, + { } +}; +MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); + +static struct platform_driver sun6i_dphy_platform_driver = { + .probe = sun6i_dphy_probe, + .driver = { + .name = "sun6i-mipi-dphy", + .of_match_table = sun6i_dphy_of_table, + }, +}; +module_platform_driver(sun6i_dphy_platform_driver); + +MODULE_AUTHOR("Maxime Ripard "); +MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4dad3e7f12f702980f42033cf8f93525f95d8db9 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 21 Jan 2019 16:45:51 +0100 Subject: drm/bridge: cdns: Separate DSI and D-PHY configuration The current configuration of the DSI bridge and its associated D-PHY is intertwined. In order to ease the future conversion to the phy framework for the D-PHY part, let's split the configuration in two. Reviewed-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/0b3bea44e05745b65c23af7926ca546bc80a1bcc.1548085432.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/bridge/cdns-dsi.c | 101 +++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 28 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 924abe82ea3c..0f5bb3dca828 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -547,6 +547,15 @@ bridge_to_cdns_dsi_input(struct drm_bridge *bridge) return container_of(bridge, struct cdns_dsi_input, bridge); } +static unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode, + bool mode_valid_check) +{ + if (mode_valid_check) + return mode->hsync_start - mode->hdisplay; + + return mode->crtc_hsync_start - mode->crtc_hdisplay; +} + static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, struct cdns_dphy_cfg *cfg, unsigned int dpi_htotal, @@ -733,14 +742,12 @@ static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, const struct drm_display_mode *mode, struct cdns_dsi_cfg *dsi_cfg, - struct cdns_dphy_cfg *dphy_cfg, bool mode_valid_check) { - unsigned long dsi_htotal = 0, dsi_hss_hsa_hse_hbp = 0; struct cdns_dsi_output *output = &dsi->output; - unsigned int dsi_hfp_ext = 0, dpi_hfp, tmp; + unsigned int tmp; bool sync_pulse = false; - int bpp, nlanes, ret; + int bpp, nlanes; memset(dsi_cfg, 0, sizeof(*dsi_cfg)); @@ -759,8 +766,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, mode->crtc_hsync_end : mode->crtc_hsync_start); dsi_cfg->hbp = dpi_to_dsi_timing(tmp, bpp, DSI_HBP_FRAME_OVERHEAD); - dsi_htotal += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; - dsi_hss_hsa_hse_hbp += dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; if (sync_pulse) { if (mode_valid_check) @@ -770,49 +775,91 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, dsi_cfg->hsa = dpi_to_dsi_timing(tmp, bpp, DSI_HSA_FRAME_OVERHEAD); - dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; - dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; } dsi_cfg->hact = dpi_to_dsi_timing(mode_valid_check ? mode->hdisplay : mode->crtc_hdisplay, bpp, 0); - dsi_htotal += dsi_cfg->hact; + dsi_cfg->hfp = dpi_to_dsi_timing(mode_to_dpi_hfp(mode, mode_valid_check), + bpp, DSI_HFP_FRAME_OVERHEAD); - if (mode_valid_check) - dpi_hfp = mode->hsync_start - mode->hdisplay; - else - dpi_hfp = mode->crtc_hsync_start - mode->crtc_hdisplay; + return 0; +} + +static int cdns_dphy_validate(struct cdns_dsi *dsi, + struct cdns_dsi_cfg *dsi_cfg, + struct cdns_dphy_cfg *dphy_cfg, + const struct drm_display_mode *mode, + bool mode_valid_check) +{ + struct cdns_dsi_output *output = &dsi->output; + unsigned long dsi_htotal; + unsigned int dsi_hfp_ext = 0; + + int ret; + + dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; + if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + dsi_htotal += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; - dsi_cfg->hfp = dpi_to_dsi_timing(dpi_hfp, bpp, DSI_HFP_FRAME_OVERHEAD); + dsi_htotal += dsi_cfg->hact; dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; if (mode_valid_check) ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, - mode->htotal, bpp, + mode->htotal, + mipi_dsi_pixel_format_to_bpp(output->dev->format), mode->clock * 1000, - dsi_htotal, nlanes, + dsi_htotal, + output->dev->lanes, &dsi_hfp_ext); else ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, - mode->crtc_htotal, bpp, + mode->crtc_htotal, + mipi_dsi_pixel_format_to_bpp(output->dev->format), mode->crtc_clock * 1000, - dsi_htotal, nlanes, + dsi_htotal, + output->dev->lanes, &dsi_hfp_ext); - if (ret) return ret; dsi_cfg->hfp += dsi_hfp_ext; - dsi_htotal += dsi_hfp_ext; - dsi_cfg->htotal = dsi_htotal; + dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; + + return 0; +} + +static int cdns_dsi_check_conf(struct cdns_dsi *dsi, + const struct drm_display_mode *mode, + struct cdns_dsi_cfg *dsi_cfg, + struct cdns_dphy_cfg *dphy_cfg, + bool mode_valid_check) +{ + struct cdns_dsi_output *output = &dsi->output; + unsigned long dsi_hss_hsa_hse_hbp; + unsigned int nlanes = output->dev->lanes; + int ret; + + ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check); + if (ret) + return ret; + + ret = cdns_dphy_validate(dsi, dsi_cfg, dphy_cfg, mode, mode_valid_check); + if (ret) + return ret; + + dsi_hss_hsa_hse_hbp = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; + if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + dsi_hss_hsa_hse_hbp += dsi_cfg->hsa + DSI_HSA_FRAME_OVERHEAD; /* * Make sure DPI(HFP) > DSI(HSS+HSA+HSE+HBP) to guarantee that the FIFO * is empty before we start a receiving a new line on the DPI * interface. */ - if ((u64)dphy_cfg->lane_bps * dpi_hfp * nlanes < + if ((u64)dphy_cfg->lane_bps * + mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < (u64)dsi_hss_hsa_hse_hbp * (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) return -EINVAL; @@ -844,7 +891,7 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, struct cdns_dsi_output *output = &dsi->output; struct cdns_dphy_cfg dphy_cfg; struct cdns_dsi_cfg dsi_cfg; - int bpp, nlanes, ret; + int bpp, ret; /* * VFP_DSI should be less than VFP_DPI and VFP_DSI should be at @@ -862,11 +909,9 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, if ((mode->hdisplay * bpp) % 32) return MODE_H_ILLEGAL; - nlanes = output->dev->lanes; - - ret = cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, true); + ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, true); if (ret) - return MODE_CLOCK_RANGE; + return MODE_BAD; return MODE_OK; } @@ -992,7 +1037,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); nlanes = output->dev->lanes; - WARN_ON_ONCE(cdns_dsi_mode2cfg(dsi, mode, &dsi_cfg, &dphy_cfg, false)); + WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, false)); cdns_dsi_hs_init(dsi, &dphy_cfg); cdns_dsi_init_link(dsi); -- cgit v1.2.3 From fced5a364dee9d3a3ed1e3290ea3b83984b78007 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 21 Jan 2019 16:45:54 +0100 Subject: drm/bridge: cdns: Convert to phy framework Now that we have everything we need in the phy framework to allow to tune the phy parameters, let's convert the Cadence DSI bridge to that API instead of creating a ad-hoc driver for its phy. Acked-by: Sean Paul Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/8772ad061f07cd91fa48bb05880095b25eccec08.1548085432.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/bridge/Kconfig | 1 + drivers/gpu/drm/bridge/cdns-dsi.c | 485 +++++--------------------------------- 2 files changed, 60 insertions(+), 426 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 2fee47b0d50b..8840f396a7b6 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -30,6 +30,7 @@ config DRM_CDNS_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + select GENERIC_PHY_MIPI_DPHY depends on OF help Support Cadence DPI to DSI bridge. This is an internal diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 0f5bb3dca828..6166dca6be81 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -23,6 +23,9 @@ #include #include +#include +#include + #define IP_CONF 0x0 #define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26) #define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21) @@ -421,44 +424,11 @@ #define DSI_NULL_FRAME_OVERHEAD 6 #define DSI_EOT_PKT_SIZE 4 -#define REG_WAKEUP_TIME_NS 800 -#define DPHY_PLL_RATE_HZ 108000000 - -/* DPHY registers */ -#define DPHY_PMA_CMN(reg) (reg) -#define DPHY_PMA_LCLK(reg) (0x100 + (reg)) -#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg)) -#define DPHY_PMA_RCLK(reg) (0x600 + (reg)) -#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg)) -#define DPHY_PCS(reg) (0xb00 + (reg)) - -#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) -#define DPHY_CMN_SSM_EN BIT(0) -#define DPHY_CMN_TX_MODE_EN BIT(9) - -#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40) -#define DPHY_CMN_PWM_DIV(x) ((x) << 20) -#define DPHY_CMN_PWM_LOW(x) ((x) << 10) -#define DPHY_CMN_PWM_HIGH(x) (x) - -#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c) -#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22)) -#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21)) - -#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50) -#define DPHY_CMN_IPDIV_FROM_REG BIT(0) -#define DPHY_CMN_IPDIV(x) ((x) << 1) -#define DPHY_CMN_OPDIV_FROM_REG BIT(6) -#define DPHY_CMN_OPDIV(x) ((x) << 7) - -#define DPHY_PSM_CFG DPHY_PCS(0x4) -#define DPHY_PSM_CFG_FROM_REG BIT(0) -#define DPHY_PSM_CLK_DIV(x) ((x) << 1) - struct cdns_dsi_output { struct mipi_dsi_device *dev; struct drm_panel *panel; struct drm_bridge *bridge; + union phy_configure_opts phy_opts; }; enum cdns_dsi_input_id { @@ -467,14 +437,6 @@ enum cdns_dsi_input_id { CDNS_DSC_INPUT, }; -struct cdns_dphy_cfg { - u8 pll_ipdiv; - u8 pll_opdiv; - u16 pll_fbdiv; - unsigned long lane_bps; - unsigned int nlanes; -}; - struct cdns_dsi_cfg { unsigned int hfp; unsigned int hsa; @@ -483,34 +445,6 @@ struct cdns_dsi_cfg { unsigned int htotal; }; -struct cdns_dphy; - -enum cdns_dphy_clk_lane_cfg { - DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0, - DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1, - DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2, - DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3, -}; - -struct cdns_dphy_ops { - int (*probe)(struct cdns_dphy *dphy); - void (*remove)(struct cdns_dphy *dphy); - void (*set_psm_div)(struct cdns_dphy *dphy, u8 div); - void (*set_clk_lane_cfg)(struct cdns_dphy *dphy, - enum cdns_dphy_clk_lane_cfg cfg); - void (*set_pll_cfg)(struct cdns_dphy *dphy, - const struct cdns_dphy_cfg *cfg); - unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); -}; - -struct cdns_dphy { - struct cdns_dphy_cfg cfg; - void __iomem *regs; - struct clk *psm_clk; - struct clk *pll_ref_clk; - const struct cdns_dphy_ops *ops; -}; - struct cdns_dsi_input { enum cdns_dsi_input_id id; struct drm_bridge bridge; @@ -528,7 +462,7 @@ struct cdns_dsi { struct reset_control *dsi_p_rst; struct clk *dsi_sys_clk; bool link_initialized; - struct cdns_dphy *dphy; + struct phy *dphy; }; static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input) @@ -556,175 +490,6 @@ static unsigned int mode_to_dpi_hfp(const struct drm_display_mode *mode, return mode->crtc_hsync_start - mode->crtc_hdisplay; } -static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, - struct cdns_dphy_cfg *cfg, - unsigned int dpi_htotal, - unsigned int dpi_bpp, - unsigned int dpi_hz, - unsigned int dsi_htotal, - unsigned int dsi_nlanes, - unsigned int *dsi_hfp_ext) -{ - u64 dlane_bps, dlane_bps_max, fbdiv, fbdiv_max, adj_dsi_htotal; - unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); - - memset(cfg, 0, sizeof(*cfg)); - - cfg->nlanes = dsi_nlanes; - - if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000) - return -EINVAL; - else if (pll_ref_hz < 19200000) - cfg->pll_ipdiv = 1; - else if (pll_ref_hz < 38400000) - cfg->pll_ipdiv = 2; - else if (pll_ref_hz < 76800000) - cfg->pll_ipdiv = 4; - else - cfg->pll_ipdiv = 8; - - /* - * Make sure DSI htotal is aligned on a lane boundary when calculating - * the expected data rate. This is done by extending HFP in case of - * misalignment. - */ - adj_dsi_htotal = dsi_htotal; - if (dsi_htotal % dsi_nlanes) - adj_dsi_htotal += dsi_nlanes - (dsi_htotal % dsi_nlanes); - - dlane_bps = (u64)dpi_hz * adj_dsi_htotal; - - /* data rate in bytes/sec is not an integer, refuse the mode. */ - if (do_div(dlane_bps, dsi_nlanes * dpi_htotal)) - return -EINVAL; - - /* data rate was in bytes/sec, convert to bits/sec. */ - dlane_bps *= 8; - - if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL) - return -EINVAL; - else if (dlane_bps >= 1250000000) - cfg->pll_opdiv = 1; - else if (dlane_bps >= 630000000) - cfg->pll_opdiv = 2; - else if (dlane_bps >= 320000000) - cfg->pll_opdiv = 4; - else if (dlane_bps >= 160000000) - cfg->pll_opdiv = 8; - - /* - * Allow a deviation of 0.2% on the per-lane data rate to try to - * recover a potential mismatch between DPI and PPI clks. - */ - dlane_bps_max = dlane_bps + DIV_ROUND_DOWN_ULL(dlane_bps, 500); - fbdiv_max = DIV_ROUND_DOWN_ULL(dlane_bps_max * 2 * - cfg->pll_opdiv * cfg->pll_ipdiv, - pll_ref_hz); - fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv * - cfg->pll_ipdiv, - pll_ref_hz); - - /* - * Iterate over all acceptable fbdiv and try to find an adjusted DSI - * htotal length providing an exact match. - * - * Note that we could do something even trickier by relying on the fact - * that a new line is not necessarily aligned on a lane boundary, so, - * by making adj_dsi_htotal non aligned on a dsi_lanes we can improve a - * bit the precision. With this, the step would be - * - * pll_ref_hz / (2 * opdiv * ipdiv * nlanes) - * - * instead of - * - * pll_ref_hz / (2 * opdiv * ipdiv) - * - * The drawback of this approach is that we would need to make sure the - * number or lines is a multiple of the realignment periodicity which is - * a function of the number of lanes and the original misalignment. For - * example, for NLANES = 4 and HTOTAL % NLANES = 3, it takes 4 lines - * to realign on a lane: - * LINE 0: expected number of bytes, starts emitting first byte of - * LINE 1 on LANE 3 - * LINE 1: expected number of bytes, starts emitting first 2 bytes of - * LINE 2 on LANES 2 and 3 - * LINE 2: expected number of bytes, starts emitting first 3 bytes of - * of LINE 3 on LANES 1, 2 and 3 - * LINE 3: one byte less, now things are realigned on LANE 0 for LINE 4 - * - * I figured this extra complexity was not worth the benefit, but if - * someone really has unfixable mismatch, that would be something to - * investigate. - */ - for (; fbdiv <= fbdiv_max; fbdiv++) { - u32 rem; - - adj_dsi_htotal = (u64)fbdiv * pll_ref_hz * dsi_nlanes * - dpi_htotal; - - /* - * Do the division in 2 steps to avoid an overflow on the - * divider. - */ - rem = do_div(adj_dsi_htotal, dpi_hz); - if (rem) - continue; - - rem = do_div(adj_dsi_htotal, - cfg->pll_opdiv * cfg->pll_ipdiv * 2 * 8); - if (rem) - continue; - - cfg->pll_fbdiv = fbdiv; - *dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; - break; - } - - /* No match, let's just reject the display mode. */ - if (!cfg->pll_fbdiv) - return -EINVAL; - - dlane_bps = DIV_ROUND_DOWN_ULL((u64)dpi_hz * adj_dsi_htotal * 8, - dsi_nlanes * dpi_htotal); - cfg->lane_bps = dlane_bps; - - return 0; -} - -static int cdns_dphy_setup_psm(struct cdns_dphy *dphy) -{ - unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk); - unsigned long psm_div; - - if (!psm_clk_hz || psm_clk_hz > 100000000) - return -EINVAL; - - psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000); - if (dphy->ops->set_psm_div) - dphy->ops->set_psm_div(dphy, psm_div); - - return 0; -} - -static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy, - enum cdns_dphy_clk_lane_cfg cfg) -{ - if (dphy->ops->set_clk_lane_cfg) - dphy->ops->set_clk_lane_cfg(dphy, cfg); -} - -static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy, - const struct cdns_dphy_cfg *cfg) -{ - if (dphy->ops->set_pll_cfg) - dphy->ops->set_pll_cfg(dphy, cfg); -} - -static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy) -{ - return dphy->ops->get_wakeup_time_ns(dphy); -} - static unsigned int dpi_to_dsi_timing(unsigned int dpi_timing, unsigned int dpi_bpp, unsigned int dsi_pkt_overhead) @@ -786,17 +551,20 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, return 0; } -static int cdns_dphy_validate(struct cdns_dsi *dsi, +static int cdns_dsi_adjust_phy_config(struct cdns_dsi *dsi, struct cdns_dsi_cfg *dsi_cfg, - struct cdns_dphy_cfg *dphy_cfg, + struct phy_configure_opts_mipi_dphy *phy_cfg, const struct drm_display_mode *mode, bool mode_valid_check) { struct cdns_dsi_output *output = &dsi->output; + unsigned long long dlane_bps; + unsigned long adj_dsi_htotal; unsigned long dsi_htotal; - unsigned int dsi_hfp_ext = 0; - - int ret; + unsigned long dpi_htotal; + unsigned long dpi_hz; + unsigned int dsi_hfp_ext; + unsigned int lanes = output->dev->lanes; dsi_htotal = dsi_cfg->hbp + DSI_HBP_FRAME_OVERHEAD; if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) @@ -805,25 +573,27 @@ static int cdns_dphy_validate(struct cdns_dsi *dsi, dsi_htotal += dsi_cfg->hact; dsi_htotal += dsi_cfg->hfp + DSI_HFP_FRAME_OVERHEAD; - if (mode_valid_check) - ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, - mode->htotal, - mipi_dsi_pixel_format_to_bpp(output->dev->format), - mode->clock * 1000, - dsi_htotal, - output->dev->lanes, - &dsi_hfp_ext); - else - ret = cdns_dsi_get_dphy_pll_cfg(dsi->dphy, dphy_cfg, - mode->crtc_htotal, - mipi_dsi_pixel_format_to_bpp(output->dev->format), - mode->crtc_clock * 1000, - dsi_htotal, - output->dev->lanes, - &dsi_hfp_ext); - if (ret) - return ret; + /* + * Make sure DSI htotal is aligned on a lane boundary when calculating + * the expected data rate. This is done by extending HFP in case of + * misalignment. + */ + adj_dsi_htotal = dsi_htotal; + if (dsi_htotal % lanes) + adj_dsi_htotal += lanes - (dsi_htotal % lanes); + + dpi_hz = (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000; + dlane_bps = (unsigned long long)dpi_hz * adj_dsi_htotal; + + /* data rate in bytes/sec is not an integer, refuse the mode. */ + dpi_htotal = mode_valid_check ? mode->htotal : mode->crtc_htotal; + if (do_div(dlane_bps, lanes * dpi_htotal)) + return -EINVAL; + /* data rate was in bytes/sec, convert to bits/sec. */ + phy_cfg->hs_clk_rate = dlane_bps * 8; + + dsi_hfp_ext = adj_dsi_htotal - dsi_htotal; dsi_cfg->hfp += dsi_hfp_ext; dsi_cfg->htotal = dsi_htotal + dsi_hfp_ext; @@ -833,10 +603,10 @@ static int cdns_dphy_validate(struct cdns_dsi *dsi, static int cdns_dsi_check_conf(struct cdns_dsi *dsi, const struct drm_display_mode *mode, struct cdns_dsi_cfg *dsi_cfg, - struct cdns_dphy_cfg *dphy_cfg, bool mode_valid_check) { struct cdns_dsi_output *output = &dsi->output; + struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; unsigned long dsi_hss_hsa_hse_hbp; unsigned int nlanes = output->dev->lanes; int ret; @@ -845,7 +615,15 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi, if (ret) return ret; - ret = cdns_dphy_validate(dsi, dsi_cfg, dphy_cfg, mode, mode_valid_check); + phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000, + mipi_dsi_pixel_format_to_bpp(output->dev->format), + nlanes, phy_cfg); + + ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check); + if (ret) + return ret; + + ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &output->phy_opts); if (ret) return ret; @@ -858,7 +636,7 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi, * is empty before we start a receiving a new line on the DPI * interface. */ - if ((u64)dphy_cfg->lane_bps * + if ((u64)phy_cfg->hs_clk_rate * mode_to_dpi_hfp(mode, mode_valid_check) * nlanes < (u64)dsi_hss_hsa_hse_hbp * (mode_valid_check ? mode->clock : mode->crtc_clock) * 1000) @@ -889,7 +667,6 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); struct cdns_dsi *dsi = input_to_dsi(input); struct cdns_dsi_output *output = &dsi->output; - struct cdns_dphy_cfg dphy_cfg; struct cdns_dsi_cfg dsi_cfg; int bpp, ret; @@ -909,7 +686,7 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, if ((mode->hdisplay * bpp) % 32) return MODE_H_ILLEGAL; - ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, true); + ret = cdns_dsi_check_conf(dsi, mode, &dsi_cfg, true); if (ret) return MODE_BAD; @@ -932,9 +709,9 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge) pm_runtime_put(dsi->base.dev); } -static void cdns_dsi_hs_init(struct cdns_dsi *dsi, - const struct cdns_dphy_cfg *dphy_cfg) +static void cdns_dsi_hs_init(struct cdns_dsi *dsi) { + struct cdns_dsi_output *output = &dsi->output; u32 status; /* @@ -945,30 +722,10 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi, DPHY_CMN_PDN | DPHY_PLL_PDN, dsi->regs + MCTL_DPHY_CFG0); - /* - * Configure the internal PSM clk divider so that the DPHY has a - * 1MHz clk (or something close). - */ - WARN_ON_ONCE(cdns_dphy_setup_psm(dsi->dphy)); - - /* - * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes - * and 8 data lanes, each clk lane can be attache different set of - * data lanes. The 2 groups are named 'left' and 'right', so here we - * just say that we want the 'left' clk lane to drive the 'left' data - * lanes. - */ - cdns_dphy_set_clk_lane_cfg(dsi->dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT); - - /* - * Configure the DPHY PLL that will be used to generate the TX byte - * clk. - */ - cdns_dphy_set_pll_cfg(dsi->dphy, dphy_cfg); - - /* Start TX state machine. */ - writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, - dsi->dphy->regs + DPHY_CMN_SSM); + phy_init(dsi->dphy); + phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(dsi->dphy, &output->phy_opts); + phy_power_on(dsi->dphy); /* Activate the PLL and wait until it's locked. */ writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR); @@ -978,7 +735,7 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi, status & PLL_LOCKED, 100, 100)); /* De-assert data and clock reset lines. */ writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | - DPHY_D_RSTB(dphy_cfg->nlanes) | DPHY_C_RSTB, + DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB, dsi->regs + MCTL_DPHY_CFG0); } @@ -1024,7 +781,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) struct cdns_dsi *dsi = input_to_dsi(input); struct cdns_dsi_output *output = &dsi->output; struct drm_display_mode *mode; - struct cdns_dphy_cfg dphy_cfg; + struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy; unsigned long tx_byte_period; struct cdns_dsi_cfg dsi_cfg; u32 tmp, reg_wakeup, div; @@ -1037,9 +794,9 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); nlanes = output->dev->lanes; - WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, &dphy_cfg, false)); + WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); - cdns_dsi_hs_init(dsi, &dphy_cfg); + cdns_dsi_hs_init(dsi); cdns_dsi_init_link(dsi); writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa), @@ -1075,9 +832,8 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, - dphy_cfg.lane_bps); - reg_wakeup = cdns_dphy_get_wakeup_time_ns(dsi->dphy) / - tx_byte_period; + phy_cfg->hs_clk_rate); + reg_wakeup = (phy_cfg->hs_prepare + phy_cfg->hs_zero) / tx_byte_period; writel(REG_WAKEUP_TIME(reg_wakeup) | REG_LINE_DURATION(tmp), dsi->regs + VID_DPHY_TIME); @@ -1391,8 +1147,6 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev) reset_control_deassert(dsi->dsi_p_rst); clk_prepare_enable(dsi->dsi_p_clk); clk_prepare_enable(dsi->dsi_sys_clk); - clk_prepare_enable(dsi->dphy->psm_clk); - clk_prepare_enable(dsi->dphy->pll_ref_clk); return 0; } @@ -1401,8 +1155,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) { struct cdns_dsi *dsi = dev_get_drvdata(dev); - clk_disable_unprepare(dsi->dphy->pll_ref_clk); - clk_disable_unprepare(dsi->dphy->psm_clk); clk_disable_unprepare(dsi->dsi_sys_clk); clk_disable_unprepare(dsi->dsi_p_clk); reset_control_assert(dsi->dsi_p_rst); @@ -1413,121 +1165,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, NULL); -static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy) -{ - /* Default wakeup time is 800 ns (in a simulated environment). */ - return 800; -} - -static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy, - const struct cdns_dphy_cfg *cfg) -{ - u32 fbdiv_low, fbdiv_high; - - fbdiv_low = (cfg->pll_fbdiv / 4) - 2; - fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2; - - writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG | - DPHY_CMN_IPDIV(cfg->pll_ipdiv) | - DPHY_CMN_OPDIV(cfg->pll_opdiv), - dphy->regs + DPHY_CMN_OPIPDIV); - writel(DPHY_CMN_FBDIV_FROM_REG | - DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high), - dphy->regs + DPHY_CMN_FBDIV); - writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) | - DPHY_CMN_PWM_DIV(0x8), - dphy->regs + DPHY_CMN_PWM); -} - -static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div) -{ - writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div), - dphy->regs + DPHY_PSM_CFG); -} - -/* - * This is the reference implementation of DPHY hooks. Specific integration of - * this IP may have to re-implement some of them depending on how they decided - * to wire things in the SoC. - */ -static const struct cdns_dphy_ops ref_dphy_ops = { - .get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns, - .set_pll_cfg = cdns_dphy_ref_set_pll_cfg, - .set_psm_div = cdns_dphy_ref_set_psm_div, -}; - -static const struct of_device_id cdns_dphy_of_match[] = { - { .compatible = "cdns,dphy", .data = &ref_dphy_ops }, - { /* sentinel */ }, -}; - -static struct cdns_dphy *cdns_dphy_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct cdns_dphy *dphy; - struct of_phandle_args args; - struct resource res; - int ret; - - ret = of_parse_phandle_with_args(pdev->dev.of_node, "phys", - "#phy-cells", 0, &args); - if (ret) - return ERR_PTR(-ENOENT); - - match = of_match_node(cdns_dphy_of_match, args.np); - if (!match || !match->data) - return ERR_PTR(-EINVAL); - - dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); - if (!dphy) - return ERR_PTR(-ENOMEM); - - dphy->ops = match->data; - - ret = of_address_to_resource(args.np, 0, &res); - if (ret) - return ERR_PTR(ret); - - dphy->regs = devm_ioremap_resource(&pdev->dev, &res); - if (IS_ERR(dphy->regs)) - return ERR_CAST(dphy->regs); - - dphy->psm_clk = of_clk_get_by_name(args.np, "psm"); - if (IS_ERR(dphy->psm_clk)) - return ERR_CAST(dphy->psm_clk); - - dphy->pll_ref_clk = of_clk_get_by_name(args.np, "pll_ref"); - if (IS_ERR(dphy->pll_ref_clk)) { - ret = PTR_ERR(dphy->pll_ref_clk); - goto err_put_psm_clk; - } - - if (dphy->ops->probe) { - ret = dphy->ops->probe(dphy); - if (ret) - goto err_put_pll_ref_clk; - } - - return dphy; - -err_put_pll_ref_clk: - clk_put(dphy->pll_ref_clk); - -err_put_psm_clk: - clk_put(dphy->psm_clk); - - return ERR_PTR(ret); -} - -static void cdns_dphy_remove(struct cdns_dphy *dphy) -{ - if (dphy->ops->remove) - dphy->ops->remove(dphy); - - clk_put(dphy->pll_ref_clk); - clk_put(dphy->psm_clk); -} - static int cdns_dsi_drm_probe(struct platform_device *pdev) { struct cdns_dsi *dsi; @@ -1566,13 +1203,13 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) if (irq < 0) return irq; - dsi->dphy = cdns_dphy_probe(pdev); + dsi->dphy = devm_phy_get(&pdev->dev, "dphy"); if (IS_ERR(dsi->dphy)) return PTR_ERR(dsi->dphy); ret = clk_prepare_enable(dsi->dsi_p_clk); if (ret) - goto err_remove_dphy; + return ret; val = readl(dsi->regs + ID_REG); if (REV_VENDOR_ID(val) != 0xcad) { @@ -1630,9 +1267,6 @@ err_disable_runtime_pm: err_disable_pclk: clk_disable_unprepare(dsi->dsi_p_clk); -err_remove_dphy: - cdns_dphy_remove(dsi->dphy); - return ret; } @@ -1642,7 +1276,6 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev) mipi_dsi_host_unregister(&dsi->base); pm_runtime_disable(&pdev->dev); - cdns_dphy_remove(dsi->dphy); return 0; } -- cgit v1.2.3 From 2ebb2428c3d4732bb0fab9522c605e6af55c2fa5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 6 Feb 2019 20:32:04 +0200 Subject: drm: Nuke drm_calc_{h,v}scale_relaxed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fuzzy drm_calc_{h,v}scale_relaxed() helpers are no longer used. Throw them in the bin. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20190206183204.21127-1-ville.syrjala@linux.intel.com Acked-by: Alex Deucher --- drivers/gpu/drm/drm_rect.c | 108 --------------------------------------------- include/drm/drm_rect.h | 6 --- 2 files changed, 114 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index 8c057829b804..66c41b12719c 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -207,114 +207,6 @@ int drm_rect_calc_vscale(const struct drm_rect *src, } EXPORT_SYMBOL(drm_rect_calc_vscale); -/** - * drm_calc_hscale_relaxed - calculate the horizontal scaling factor - * @src: source window rectangle - * @dst: destination window rectangle - * @min_hscale: minimum allowed horizontal scaling factor - * @max_hscale: maximum allowed horizontal scaling factor - * - * Calculate the horizontal scaling factor as - * (@src width) / (@dst width). - * - * If the calculated scaling factor is below @min_vscale, - * decrease the height of rectangle @dst to compensate. - * - * If the calculated scaling factor is above @max_vscale, - * decrease the height of rectangle @src to compensate. - * - * If the scale is below 1 << 16, round down. If the scale is above - * 1 << 16, round up. This will calculate the scale with the most - * pessimistic limit calculation. - * - * RETURNS: - * The horizontal scaling factor. - */ -int drm_rect_calc_hscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_hscale, int max_hscale) -{ - int src_w = drm_rect_width(src); - int dst_w = drm_rect_width(dst); - int hscale = drm_calc_scale(src_w, dst_w); - - if (hscale < 0 || dst_w == 0) - return hscale; - - if (hscale < min_hscale) { - int max_dst_w = src_w / min_hscale; - - drm_rect_adjust_size(dst, max_dst_w - dst_w, 0); - - return min_hscale; - } - - if (hscale > max_hscale) { - int max_src_w = dst_w * max_hscale; - - drm_rect_adjust_size(src, max_src_w - src_w, 0); - - return max_hscale; - } - - return hscale; -} -EXPORT_SYMBOL(drm_rect_calc_hscale_relaxed); - -/** - * drm_rect_calc_vscale_relaxed - calculate the vertical scaling factor - * @src: source window rectangle - * @dst: destination window rectangle - * @min_vscale: minimum allowed vertical scaling factor - * @max_vscale: maximum allowed vertical scaling factor - * - * Calculate the vertical scaling factor as - * (@src height) / (@dst height). - * - * If the calculated scaling factor is below @min_vscale, - * decrease the height of rectangle @dst to compensate. - * - * If the calculated scaling factor is above @max_vscale, - * decrease the height of rectangle @src to compensate. - * - * If the scale is below 1 << 16, round down. If the scale is above - * 1 << 16, round up. This will calculate the scale with the most - * pessimistic limit calculation. - * - * RETURNS: - * The vertical scaling factor. - */ -int drm_rect_calc_vscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_vscale, int max_vscale) -{ - int src_h = drm_rect_height(src); - int dst_h = drm_rect_height(dst); - int vscale = drm_calc_scale(src_h, dst_h); - - if (vscale < 0 || dst_h == 0) - return vscale; - - if (vscale < min_vscale) { - int max_dst_h = src_h / min_vscale; - - drm_rect_adjust_size(dst, 0, max_dst_h - dst_h); - - return min_vscale; - } - - if (vscale > max_vscale) { - int max_src_h = dst_h * max_vscale; - - drm_rect_adjust_size(src, 0, max_src_h - src_h); - - return max_vscale; - } - - return vscale; -} -EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed); - /** * drm_rect_debug_print - print the rectangle information * @prefix: prefix string diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h index 6c54544a4be7..6195820aa5c5 100644 --- a/include/drm/drm_rect.h +++ b/include/drm/drm_rect.h @@ -182,12 +182,6 @@ int drm_rect_calc_hscale(const struct drm_rect *src, int drm_rect_calc_vscale(const struct drm_rect *src, const struct drm_rect *dst, int min_vscale, int max_vscale); -int drm_rect_calc_hscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_hscale, int max_hscale); -int drm_rect_calc_vscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_vscale, int max_vscale); void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point); void drm_rect_rotate(struct drm_rect *r, -- cgit v1.2.3 From d0e93599d396db606489104a1166c425f365696c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 26 Jan 2019 13:25:24 +0100 Subject: drm/i915: prepare for drmP.h removal from drm_modeset_helper.h The use of drmP.h is discouraged and removal of it from drm_modeset_helper.h caused i915 to fail to build. This patch introduce the necessary fixes to prepare for the drmP.h removal from drm_modeset_helper.h. In the files touched the lists of include files was grouped and sorted. Build tested on x86 and arm allmodconfig / allyesconfig. Signed-off-by: Sam Ravnborg Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: David Airlie Cc: Daniel Vetter Cc: intel-gfx@lists.freedesktop.org Acked-by: Jani Nikula Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190126122527.11647-3-sam@ravnborg.org --- drivers/gpu/drm/i915/i915_drv.c | 4 +++- drivers/gpu/drm/i915/intel_atomic.c | 2 ++ drivers/gpu/drm/i915/intel_atomic_plane.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++------------- drivers/gpu/drm/i915/intel_pm.c | 7 +++++-- 5 files changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index aba502dadd66..16fd5ae06997 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -41,8 +41,10 @@ #include #include -#include #include +#include +#include +#include #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index d8dbc9980281..f415ed239184 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -31,7 +31,9 @@ #include #include +#include #include + #include "intel_drv.h" /** diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 683a75dad4fb..79139d496c78 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -32,7 +32,9 @@ */ #include +#include #include + #include "intel_drv.h" struct intel_plane *intel_plane_alloc(void) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 15d758cd0c1b..e0f40be07131 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -24,29 +24,32 @@ * Eric Anholt */ -#include -#include #include +#include +#include #include +#include +#include #include #include -#include -#include "intel_drv.h" -#include "intel_frontbuffer.h" -#include -#include "i915_drv.h" -#include "i915_gem_clflush.h" -#include "intel_dsi.h" -#include "i915_trace.h" + #include #include +#include #include +#include +#include #include #include #include -#include -#include -#include +#include + +#include "i915_drv.h" +#include "i915_gem_clflush.h" +#include "i915_trace.h" +#include "intel_drv.h" +#include "intel_dsi.h" +#include "intel_frontbuffer.h" /* Primary plane formats for gen <= 3 */ static const uint32_t i8xx_primary_formats[] = { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 83b01cde8113..48c755dc895b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -26,13 +26,16 @@ */ #include +#include #include + +#include +#include #include + #include "i915_drv.h" #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" -#include -#include /** * DOC: RC6 -- cgit v1.2.3 From 7d0b0adaee5f5aac557bffa747fdf57771fdb5e5 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 26 Jan 2019 13:25:25 +0100 Subject: drm/rcar-du: prepare for drmP.h removal from drm_modeset_helper.h The use of drmP.h is discouraged and removal of it from drm_modeset_helper.h caused rcar-du to fail to build. This patch introduce the necessary fixes to prepare for the drmP.h removal from drm_modeset_helper.h. Build tested on arm allmodconfig/allyesconfig. v2: - new patch. Changes like drm_probe_helper and other required several updates Signed-off-by: Sam Ravnborg Cc: Laurent Pinchart Cc: Kieran Bingham Cc: David Airlie Cc: Daniel Vetter Cc: linux-renesas-soc@vger.kernel.org Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190126122527.11647-4-sam@ravnborg.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 3 +++ drivers/gpu/drm/rcar-du/rcar_du_drv.c | 1 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_plane.c | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 1 + 5 files changed, 9 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 93ee0020c9b1..4d1e5098b70e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -9,14 +9,17 @@ #include #include +#include #include #include #include #include +#include #include #include #include +#include #include "rcar_du_crtc.h" #include "rcar_du_drv.h" diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index abd70d2931b0..75ab17af13a9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 663ab98d1f97..18d21bc1d265 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 321ac80b48d3..c6430027169f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 76a39eee7c9c..0878accbd134 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From d713e330963522ffa406b61ae4478daa69def2d6 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 26 Jan 2019 13:25:26 +0100 Subject: drm: prepare for drmP.h removal from drm_modeset_helper.h The use of drmP.h is discouraged and removal of it from drm_modeset_helper.h caused drm/ to fail to build. This patch introduce the necessary fixes to prepare for the drmP.h removal from drm_modeset_helper.h. Build tested on x86, arm, alpha, ia64 allmodconfig/allyesconfig. Signed-off-by: Sam Ravnborg Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Sean Paul Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190126122527.11647-5-sam@ravnborg.org --- drivers/gpu/drm/drm_damage_helper.c | 1 + drivers/gpu/drm/drm_modeset_helper.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index e16aa5ae00b4..ee67c96841fa 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -32,6 +32,7 @@ #include #include +#include /** * DOC: overview diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 890eee07892d..da483125e063 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -22,8 +22,10 @@ #include #include +#include #include #include +#include #include /** -- cgit v1.2.3 From 1c7c62a37a5fc50599e1aa7e72dd0fc785fc958a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 8 Feb 2019 10:05:40 +0100 Subject: drm/sun4i: dsi: Fix unitialized variable warning Since the DPHY rework, one error path doesn't set the return error code before jumping to its error label, which in turns make gcc (rightfully) complain about the variable holding the error code being uninitialized. Fix this. Fixes: bb3b6fcb6849 ("sun6i: dsi: Convert to generic phy handling") Reported-by: Stephen Rothwell Reviewed-by: Daniel Vetter Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20190208090540.19626-1-maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 9b7bef696957..318994cd1b85 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -1025,6 +1025,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev) dsi->dphy = devm_phy_get(dev, "dphy"); if (IS_ERR(dsi->dphy)) { dev_err(dev, "Couldn't get the MIPI D-PHY\n"); + ret = PTR_ERR(dsi->dphy); goto err_unprotect_clk; } -- cgit v1.2.3 From 05f8bc82fc428dbaf41764e95167dd759769f33d Mon Sep 17 00:00:00 2001 From: Randy Li Date: Thu, 10 Jan 2019 03:57:09 +0800 Subject: drm/fourcc: Add new P010, P016 video format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P010 is a planar 4:2:0 YUV with interleaved UV plane, 10 bits per channel video format. P012 is a planar 4:2:0 YUV 12 bits per channel P016 is a planar 4:2:0 YUV with interleaved UV plane, 16 bits per channel video format. V3: Added P012 and fixed cpp for P010. V4: format definition refined per review. V5: Format comment block for each new pixel format. V6: reversed Cb/Cr order in comments. v7: reversed Cb/Cr order in comments of header files, remove the wrong part of commit message. V8: reversed V7 changes except commit message and rebased. v9: used the new properties to describe those format and rebased. Cc: Daniel Stone Cc: Ville Syrjälä Signed-off-by: Randy Li Signed-off-by: Clint Taylor Reviewed-by: Ayan Kumar Halder Reviewed-by: Neil Armstrong Reviewed-by: Daniel Vetter Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20190109195710.28501-2-ayaka@soulik.info --- drivers/gpu/drm/drm_fourcc.c | 9 +++++++++ include/uapi/drm/drm_fourcc.h | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index d90ee03a84c6..ba7e19d4336c 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -238,6 +238,15 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_X0L2, .depth = 0, .num_planes = 1, .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_P010, .depth = 0, .num_planes = 2, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_P012, .depth = 0, .num_planes = 2, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_P016, .depth = 0, .num_planes = 2, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .hsub = 2, .vsub = 2, .is_yuv = true}, }; unsigned int i; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 91d08a23f125..0fa360223255 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -195,6 +195,27 @@ extern "C" { #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [12:4] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian + */ +#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane 12 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y little endian + * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian + */ +#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + /* * 3 plane YCbCr * index 0: Y plane, [7:0] Y -- cgit v1.2.3 From 05bad2357afcb9f89804f04f0ae5ac58ae898ec5 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Wed, 6 Feb 2019 13:31:48 -0800 Subject: drm/dsc: Add kernel documentation for DRM DP DSC helpers This patch adds appropriate kernel documentation for DRM DP helpers used for enabling Display Stream compression functionality in drm_dp_helper.h and drm_dp_helper.c as well as for the DSC spec related structure definitions and helpers in drm_dsc.c and drm_dsc.h Also add links between the functions and structures in the documentation. v3: * Fix the checkpatch warnings (Sean Paul) v2: * Add inline comments for longer structs (Daniel Vetter) * Split the summary and description (Daniel Vetter) Suggested-by: Daniel Vetter Suggested-by: Sean Paul Cc: Daniel Vetter Cc: Sean Paul Signed-off-by: Manasi Navare Acked-by: Sean Paul Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190206213148.21390-1-manasi.d.navare@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 47 +++++++- drivers/gpu/drm/drm_dsc.c | 30 ++++-- include/drm/drm_dp_helper.h | 15 ++- include/drm/drm_dsc.h | 233 ++++++++++++++++++++++++++++++---------- 4 files changed, 259 insertions(+), 66 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 54120b6319e7..54a6414c5d96 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1360,7 +1360,20 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, EXPORT_SYMBOL(drm_dp_read_desc); /** - * DRM DP Helpers for DSC + * drm_dp_dsc_sink_max_slice_count() - Get the max slice count + * supported by the DSC sink. + * @dsc_dpcd: DSC capabilities from DPCD + * @is_edp: true if its eDP, false for DP + * + * Read the slice capabilities DPCD register from DSC sink to get + * the maximum slice count supported. This is used to populate + * the DSC parameters in the &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Maximum slice count supported by DSC sink or 0 its invalid */ u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], bool is_edp) @@ -1405,6 +1418,21 @@ u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], } EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count); +/** + * drm_dp_dsc_sink_line_buf_depth() - Get the line buffer depth in bits + * @dsc_dpcd: DSC capabilities from DPCD + * + * Read the DSC DPCD register to parse the line buffer depth in bits which is + * number of bits of precision within the decoder line buffer supported by + * the DSC sink. This is used to populate the DSC parameters in the + * &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Line buffer depth supported by DSC panel or 0 its invalid + */ u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) { u8 line_buf_depth = dsc_dpcd[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT]; @@ -1434,6 +1462,23 @@ u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) } EXPORT_SYMBOL(drm_dp_dsc_sink_line_buf_depth); +/** + * drm_dp_dsc_sink_supported_input_bpcs() - Get all the input bits per component + * values supported by the DSC sink. + * @dsc_dpcd: DSC capabilities from DPCD + * @dsc_bpc: An array to be filled by this helper with supported + * input bpcs. + * + * Read the DSC DPCD from the sink device to parse the supported bits per + * component values. This is used to populate the DSC parameters + * in the &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Number of input BPC values parsed from the DPCD + */ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], u8 dsc_bpc[3]) { diff --git a/drivers/gpu/drm/drm_dsc.c b/drivers/gpu/drm/drm_dsc.c index bc2b23adb072..bce99f95c1a3 100644 --- a/drivers/gpu/drm/drm_dsc.c +++ b/drivers/gpu/drm/drm_dsc.c @@ -17,6 +17,12 @@ /** * DOC: dsc helpers * + * VESA specification for DP 1.4 adds a new feature called Display Stream + * Compression (DSC) used to compress the pixel bits before sending it on + * DP/eDP/MIPI DSI interface. DSC is required to be enabled so that the existing + * display interfaces can support high resolutions at higher frames rates uisng + * the maximum available link capacity of these interfaces. + * * These functions contain some common logic and helpers to deal with VESA * Display Stream Compression standard required for DSC on Display Port/eDP or * MIPI display interfaces. @@ -26,6 +32,13 @@ * drm_dsc_dp_pps_header_init() - Initializes the PPS Header * for DisplayPort as per the DP 1.4 spec. * @pps_sdp: Secondary data packet for DSC Picture Parameter Set + * as defined in &struct drm_dsc_pps_infoframe + * + * DP 1.4 spec defines the secondary data packet for sending the + * picture parameter infoframes from the source to the sink. + * This function populates the pps header defined in + * &struct drm_dsc_pps_infoframe as per the header bytes defined + * in &struct dp_sdp_header. */ void drm_dsc_dp_pps_header_init(struct drm_dsc_pps_infoframe *pps_sdp) { @@ -38,15 +51,20 @@ EXPORT_SYMBOL(drm_dsc_dp_pps_header_init); /** * drm_dsc_pps_infoframe_pack() - Populates the DSC PPS infoframe - * using the DSC configuration parameters in the order expected - * by the DSC Display Sink device. For the DSC, the sink device - * expects the PPS payload in the big endian format for the fields - * that span more than 1 byte. * * @pps_sdp: - * Secondary data packet for DSC Picture Parameter Set + * Secondary data packet for DSC Picture Parameter Set. This is defined + * by &struct drm_dsc_pps_infoframe * @dsc_cfg: - * DSC Configuration data filled by driver + * DSC Configuration data filled by driver as defined by + * &struct drm_dsc_config + * + * DSC source device sends a secondary data packet filled with all the + * picture parameter set (PPS) information required by the sink to decode + * the compressed frame. Driver populates the dsC PPS infoframe using the DSC + * configuration parameters in the order expected by the DSC Display Sink + * device. For the DSC, the sink device expects the PPS payload in the big + * endian format for the fields that span more than 1 byte. */ void drm_dsc_pps_infoframe_pack(struct drm_dsc_pps_infoframe *pps_sdp, const struct drm_dsc_config *dsc_cfg) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 5db7fb8c8b50..2711cdfa0c13 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1052,11 +1052,18 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw); #define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */ /* 0x80+ CEA-861 infoframe types */ +/** + * struct dp_sdp_header - DP secondary data packet header + * @HB0: Secondary Data Packet ID + * @HB1: Secondary Data Packet Type + * @HB2: Secondary Data Packet Specific header, Byte 0 + * @HB3: Secondary Data packet Specific header, Byte 1 + */ struct dp_sdp_header { - u8 HB0; /* Secondary Data Packet ID */ - u8 HB1; /* Secondary Data Packet Type */ - u8 HB2; /* Secondary Data Packet Specific header, Byte 0 */ - u8 HB3; /* Secondary Data packet Specific header, Byte 1 */ + u8 HB0; + u8 HB1; + u8 HB2; + u8 HB3; } __packed; #define EDP_SDP_HEADER_REVISION_MASK 0x1F diff --git a/include/drm/drm_dsc.h b/include/drm/drm_dsc.h index d03f1b83421a..9c26f083c70f 100644 --- a/include/drm/drm_dsc.h +++ b/include/drm/drm_dsc.h @@ -44,111 +44,231 @@ #define DSC_1_2_MAX_LINEBUF_DEPTH_VAL 0 #define DSC_1_1_MAX_LINEBUF_DEPTH_BITS 13 -/* Configuration for a single Rate Control model range */ +/** + * struct drm_dsc_rc_range_parameters - DSC Rate Control range parameters + * + * This defines different rate control parameters used by the DSC engine + * to compress the frame. + */ struct drm_dsc_rc_range_parameters { - /* Min Quantization Parameters allowed for this range */ + /** + * @range_min_qp: Min Quantization Parameters allowed for this range + */ u8 range_min_qp; - /* Max Quantization Parameters allowed for this range */ + /** + * @range_max_qp: Max Quantization Parameters allowed for this range + */ u8 range_max_qp; - /* Bits/group offset to apply to target for this group */ + /** + * @range_bpg_offset: + * Bits/group offset to apply to target for this group + */ u8 range_bpg_offset; }; +/** + * struct drm_dsc_config - Parameters required to configure DSC + * + * Driver populates this structure with all the parameters required + * to configure the display stream compression on the source. + */ struct drm_dsc_config { - /* Bits / component for previous reconstructed line buffer */ + /** + * @line_buf_depth: + * Bits per component for previous reconstructed line buffer + */ u8 line_buf_depth; - /* Bits per component to code (must be 8, 10, or 12) */ + /** + * @bits_per_component: Bits per component to code (8/10/12) + */ u8 bits_per_component; - /* - * Flag indicating to do RGB - YCoCg conversion - * and back (should be 1 for RGB input) + /** + * @convert_rgb: + * Flag to indicate if RGB - YCoCg conversion is needed + * True if RGB input, False if YCoCg input */ bool convert_rgb; + /** + * @slice_count: Number fo slices per line used by the DSC encoder + */ u8 slice_count; - /* Slice Width */ + /** + * @slice_width: Width of each slice in pixels + */ u16 slice_width; - /* Slice Height */ + /** + * @slice_height: Slice height in pixels + */ u16 slice_height; - /* - * 4:2:2 enable mode (from PPS, 4:2:2 conversion happens - * outside of DSC encode/decode algorithm) + /** + * @enable422: True for 4_2_2 sampling, false for 4_4_4 sampling */ bool enable422; - /* Picture Width */ + /** + * @pic_width: Width of the input display frame in pixels + */ u16 pic_width; - /* Picture Height */ + /** + * @pic_height: Vertical height of the input display frame + */ u16 pic_height; - /* Offset to bits/group used by RC to determine QP adjustment */ + /** + * @rc_tgt_offset_high: + * Offset to bits/group used by RC to determine QP adjustment + */ u8 rc_tgt_offset_high; - /* Offset to bits/group used by RC to determine QP adjustment */ + /** + * @rc_tgt_offset_low: + * Offset to bits/group used by RC to determine QP adjustment + */ u8 rc_tgt_offset_low; - /* Bits/pixel target << 4 (ie., 4 fractional bits) */ + /** + * @bits_per_pixel: + * Target bits per pixel with 4 fractional bits, bits_per_pixel << 4 + */ u16 bits_per_pixel; - /* - * Factor to determine if an edge is present based - * on the bits produced + /** + * @rc_edge_factor: + * Factor to determine if an edge is present based on the bits produced */ u8 rc_edge_factor; - /* Slow down incrementing once the range reaches this value */ + /** + * @rc_quant_incr_limit1: + * Slow down incrementing once the range reaches this value + */ u8 rc_quant_incr_limit1; - /* Slow down incrementing once the range reaches this value */ + /** + * @rc_quant_incr_limit0: + * Slow down incrementing once the range reaches this value + */ u8 rc_quant_incr_limit0; - /* Number of pixels to delay the initial transmission */ + /** + * @initial_xmit_delay: + * Number of pixels to delay the initial transmission + */ u16 initial_xmit_delay; - /* Number of pixels to delay the VLD on the decoder,not including SSM */ + /** + * @initial_dec_delay: + * Initial decoder delay, number of pixel times that the decoder + * accumulates data in its rate buffer before starting to decode + * and output pixels. + */ u16 initial_dec_delay; - /* Block prediction enable */ + /** + * @block_pred_enable: + * True if block prediction is used to code any groups within the + * picture. False if BP not used + */ bool block_pred_enable; - /* Bits/group offset to use for first line of the slice */ + /** + * @first_line_bpg_offset: + * Number of additional bits allocated for each group on the first + * line of slice. + */ u8 first_line_bpg_offset; - /* Value to use for RC model offset at slice start */ + /** + * @initial_offset: Value to use for RC model offset at slice start + */ u16 initial_offset; - /* Thresholds defining each of the buffer ranges */ + /** + * @rc_buf_thresh: Thresholds defining each of the buffer ranges + */ u16 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1]; - /* Parameters for each of the RC ranges */ + /** + * @rc_range_params: + * Parameters for each of the RC ranges defined in + * &struct drm_dsc_rc_range_parameters + */ struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES]; - /* Total size of RC model */ + /** + * @rc_model_size: Total size of RC model + */ u16 rc_model_size; - /* Minimum QP where flatness information is sent */ + /** + * @flatness_min_qp: Minimum QP where flatness information is sent + */ u8 flatness_min_qp; - /* Maximum QP where flatness information is sent */ + /** + * @flatness_max_qp: Maximum QP where flatness information is sent + */ u8 flatness_max_qp; - /* Initial value for scale factor */ + /** + * @initial_scale_value: Initial value for the scale factor + */ u8 initial_scale_value; - /* Decrement scale factor every scale_decrement_interval groups */ + /** + * @scale_decrement_interval: + * Specifies number of group times between decrementing the scale factor + * at beginning of a slice. + */ u16 scale_decrement_interval; - /* Increment scale factor every scale_increment_interval groups */ + /** + * @scale_increment_interval: + * Number of group times between incrementing the scale factor value + * used at the beginning of a slice. + */ u16 scale_increment_interval; - /* Non-first line BPG offset to use */ + /** + * @nfl_bpg_offset: Non first line BPG offset to be used + */ u16 nfl_bpg_offset; - /* BPG offset used to enforce slice bit */ + /** + * @slice_bpg_offset: BPG offset used to enforce slice bit + */ u16 slice_bpg_offset; - /* Final RC linear transformation offset value */ + /** + * @final_offset: Final RC linear transformation offset value + */ u16 final_offset; - /* Enable on-off VBR (ie., disable stuffing bits) */ + /** + * @vbr_enable: True if VBR mode is enabled, false if disabled + */ bool vbr_enable; - /* Mux word size (in bits) for SSM mode */ + /** + * @mux_word_size: Mux word size (in bits) for SSM mode + */ u8 mux_word_size; - /* - * The (max) size in bytes of the "chunks" that are - * used in slice multiplexing + /** + * @slice_chunk_size: + * The (max) size in bytes of the "chunks" that are used in slice + * multiplexing. */ u16 slice_chunk_size; - /* Rate Control buffer siz in bits */ + /** + * @rc_bits: Rate control buffer size in bits + */ u16 rc_bits; - /* DSC Minor Version */ + /** + * @dsc_version_minor: DSC minor version + */ u8 dsc_version_minor; - /* DSC Major version */ + /** + * @dsc_version_major: DSC major version + */ u8 dsc_version_major; - /* Native 4:2:2 support */ + /** + * @native_422: True if Native 4:2:2 supported, else false + */ bool native_422; - /* Native 4:2:0 support */ + /** + * @native_420: True if Native 4:2:0 supported else false. + */ bool native_420; - /* Additional bits/grp for seconnd line of slice for native 4:2:0 */ + /** + * @second_line_bpg_offset: + * Additional bits/grp for seconnd line of slice for native 4:2:0 + */ u8 second_line_bpg_offset; - /* Num of bits deallocated for each grp that is not in second line of slice */ + /** + * @nsl_bpg_offset: + * Num of bits deallocated for each grp that is not in second line of + * slice + */ u16 nsl_bpg_offset; - /* Offset adj fr second line in Native 4:2:0 mode */ + /** + * @second_line_offset_adj: + * Offset adjustment for second line in Native 4:2:0 mode + */ u16 second_line_offset_adj; }; @@ -468,10 +588,13 @@ struct drm_dsc_picture_parameter_set { * This structure represents the DSC PPS infoframe required to send the Picture * Parameter Set metadata required before enabling VESA Display Stream * Compression. This is based on the DP Secondary Data Packet structure and - * comprises of SDP Header as defined in drm_dp_helper.h and PPS payload. + * comprises of SDP Header as defined &struct struct dp_sdp_header in drm_dp_helper.h + * and PPS payload defined in &struct drm_dsc_picture_parameter_set. * - * @pps_header: Header for PPS as per DP SDP header format + * @pps_header: Header for PPS as per DP SDP header format of type + * &struct dp_sdp_header * @pps_payload: PPS payload fields as per DSC specification Table 4-1 + * as represented in &struct drm_dsc_picture_parameter_set */ struct drm_dsc_pps_infoframe { struct dp_sdp_header pps_header; -- cgit v1.2.3 From 09ef09b4ab95dc405ad4171ec2cd8a4ff5227108 Mon Sep 17 00:00:00 2001 From: Shayenne Moura Date: Wed, 6 Feb 2019 18:08:13 -0200 Subject: drm/vkms: WARN when hrtimer_forward_now fails Add a warn to verify the hrtimer_forward_now return and changes ret_overrun from int to u64 to match the return value provided by hrtimer_forward_now. Signed-off-by: Shayenne Moura Signed-off-by: Rodrigo Siqueira Link: https://patchwork.freedesktop.org/patch/msgid/20190206200813.d5w7gjpepoeeadiy@smtp.gmail.com --- drivers/gpu/drm/vkms/vkms_crtc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 5a095610726b..734a3e197df8 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -16,7 +16,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) vblank_hrtimer); struct drm_crtc *crtc = &output->crtc; struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state); - int ret_overrun; + u64 ret_overrun; bool ret; spin_lock(&output->lock); @@ -43,6 +43,8 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, output->period_ns); + WARN_ON(ret_overrun != 1); + spin_unlock(&output->lock); return HRTIMER_RESTART; -- cgit v1.2.3 From 6649a95d35d850e417f125821a803ca7889c713c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 8 Feb 2019 23:13:24 +0100 Subject: drm/komeda: fix build with drm_modeset_helper.h update With drmP.h removed from drm_modeset_helper.h the build of komeda filed as reported by linux-next Add missing include files to fix build. For the files touched group include files and sort them. The fix was tested on a tree with drm-misc-next merged. And the patch was also tested to work without drm-misc-next merged. Build tested on arm + x86. Signed-off-by: Sam Ravnborg Reported-by: Stephen Rothwell [linux-next] Cc: Stephen Rothwell Cc: James Wang Cc: Liviu Dudau Cc: Brian Starkey Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20190208221324.27002-1-sam@ravnborg.org --- drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 8 ++++++-- drivers/gpu/drm/arm/display/komeda/komeda_dev.c | 6 +++++- drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 ++++-- drivers/gpu/drm/arm/display/komeda/komeda_kms.c | 12 ++++++++---- drivers/gpu/drm/arm/display/komeda/komeda_kms.h | 1 + drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c | 2 ++ 6 files changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 5bb5a55f6b31..3ca5718aa0c2 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -5,12 +5,16 @@ * */ #include +#include #include + #include #include -#include #include -#include +#include +#include +#include + #include "komeda_dev.h" #include "komeda_kms.h" diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 0fe6954fbbf4..70e9bb7fa30c 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -4,9 +4,13 @@ * Author: James.Qian.Wang * */ -#include +#include #include #include +#include + +#include + #include "komeda_dev.h" static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c index 23ee74d42239..9cc9935024f7 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c @@ -4,10 +4,12 @@ * Author: James.Qian.Wang * */ -#include -#include +#include #include +#include #include +#include + #include "komeda_framebuffer.h" #include "komeda_dev.h" diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 3fc096d3883e..47a58ab20434 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -5,15 +5,19 @@ * */ #include +#include + #include #include -#include -#include +#include #include -#include +#include +#include +#include + #include "komeda_dev.h" -#include "komeda_kms.h" #include "komeda_framebuffer.h" +#include "komeda_kms.h" DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index f13666004a42..874e9c9f0749 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -10,6 +10,7 @@ #include #include #include +#include #include /** struct komeda_plane - komeda instance of drm_plane */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c index edb1cd7795f9..f1908e9ef128 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c @@ -4,6 +4,8 @@ * Author: James.Qian.Wang * */ +#include + #include "komeda_dev.h" #include "komeda_pipeline.h" -- cgit v1.2.3