[radeon-alex:amd-staging-drm-next 1019/1033] drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:237:5: warning: no previous prototype for 'rn_vbios_smu_is_periodic_retrainin
tree: git://people.freedesktop.org/~agd5f/linux.git amd-staging-drm-next head: 2c6fefb23a0e94add694b04a82bf020aed1898a0 commit: 8e37efbf94c9516cbec8ac650ecae7c8647d4d7f [1019/1033] drm/amd/display: reduce sr_xxx_time by 3 us when ppt disable config: i386-allyesconfig (attached as .config) compiler: gcc-9 (Debian 9.3.0-14) 9.3.0 reproduce (this is a W=1 build): git checkout 8e37efbf94c9516cbec8ac650ecae7c8647d4d7f # save the attached .config to linux build tree make W=1 ARCH=i386 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All warnings (new ones prefixed by >>): drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:89:5: warning: no previous prototype for 'rn_vbios_smu_send_msg_with_param' [-Wmissing-prototypes] 89 | int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:110:5: warning: no previous prototype for 'rn_vbios_smu_get_smu_version' [-Wmissing-prototypes] 110 | int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:119:5: warning: no previous prototype for 'rn_vbios_smu_set_dispclk' [-Wmissing-prototypes] 119 | int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:142:5: warning: no previous prototype for 'rn_vbios_smu_set_dprefclk' [-Wmissing-prototypes] 142 | int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) | ^ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:156:5: warning: no previous prototype for 'rn_vbios_smu_set_hard_min_dcfclk' [-Wmissing-prototypes] 156 | int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:171:5: warning: no previous prototype for 'rn_vbios_smu_set_min_deep_sleep_dcfclk' [-Wmissing-prototypes] 171 | int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz) | ^~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:186:6: warning: no previous prototype for 'rn_vbios_smu_set_phyclk' [-Wmissing-prototypes] 186 | void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz) | ^~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:194:5: warning: no previous prototype for 'rn_vbios_smu_set_dppclk' [-Wmissing-prototypes] 194 | int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz) | ^~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:206:6: warning: no previous prototype for 'rn_vbios_smu_set_dcn_low_power_state' [-Wmissing-prototypes] 206 | void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state state) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:221:6: warning: no previous prototype for 'rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn' [-Wmissing-prototypes] 221 | void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) | ^~~~ drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:229:6: warning: no previous prototype for 'rn_vbios_smu_enable_pme_wa' [-Wmissing-prototypes] 229 | void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) | ^~ >> drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:237:5: >> warning: no previous prototype for >> 'rn_vbios_smu_is_periodic_retraining_disabled' [-Wmissing-prototypes] 237 | int rn_vbios_smu_is_periodic_retraining_disabled(struct clk_mgr_internal *clk_mgr) | ^~~~ In file included from drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:31: drivers/gpu/drm/amd/amdgpu/../include/renoir_ip_offset.h:226:29: warning: 'UVD0_BASE' defined but not used [-Wunused-const-variable=] 226 | static const struct IP_BASE UVD0_BASE ={ { { { 0x7800, 0x7E00, 0x02403000, 0, 0 } }, |
Re: [PATCH] drm/vmwgfx: Fix two list_for_each loop exit tests
Am 14.07.20 um 10:25 schrieb Dan Carpenter: > On Tue, Jul 14, 2020 at 03:39:13AM +0200, Roland Scheidegger wrote: >> Am 26.06.20 um 12:39 schrieb Dan Carpenter: >>> These if statements are supposed to be true if we ended the >>> list_for_each_entry() loops without hitting a break statement but they >>> don't work. >>> >>> In the first loop, we increment "i" after the "if (i == unit)" condition >>> so we don't necessarily know that "i" is not equal to unit at the end of >>> the loop. >> So, if I understand this right, this would only really be a problem if >> there's no list entries at all, right? That is i == unit == 0. >> Not sure if that can actually happen, but in any case the fix looks correct. > > An empty list and there is another potential issue where unit is exactly > off by one. > > list_for_each_entry(con, &dev_priv->dev->mode_config.connector_list, > head) { > if (i == unit) > break; > ++i; <-- this is the last iteration and it's off by one > so now i == unit but we didn't exit via the > break statement. > } > > if (i != unit) { > ^ > Since we didn't exit by the break statement we want this to be true but > it's false instead. > > DRM_ERROR("Could not find initial display unit.\n"); > > I don't know how *likely* this is, but static checkers complain. > Technically correct is the best kind of correct! ;) Ahh indeed seems obvious now. But kinda difficult to spot :-). Thanks again, Roland > > regards, > dan carpenter > ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[Bug 207383] [Regression] 5.7 amdgpu/polaris11 gpf: amdgpu_atomic_commit_tail
https://bugzilla.kernel.org/show_bug.cgi?id=207383 Duncan (1i5t5.dun...@cox.net) changed: What|Removed |Added Kernel Version|5.7-rc1 - 5.7 - 5.8-rc4+|5.7-rc1 - 5.7 - 5.8-rc5+ --- Comment #62 from Duncan (1i5t5.dun...@cox.net) --- (In reply to Duncan from comment #48) > (In reply to Duncan from comment #47) > > So I tried [patch-reverting] with the 11 above commits against > > 5.8.0-rc4-00025-gbfe91da29, which previously tested as triggering the > freeze > > for me. Of the 11, nine clean-reversed and I simply noted and skipped the > > other two (3202fa62f and 630f289b7) for the moment. The patched kernel > > successfully built and I'm booted to it now. > > Bah, humbug! Got a freeze and the infamous logged trace on that too After taking a few days discouragement-break I'm back at trying to pin it down. The quoted above left two candidate commits, 3202fa62f and 630f289b7, neither of which would clean-revert as commits since were preventing that. 630f289b7 is a few lines changed in many files so I'm focusing on the simpler 3202fa62f first. Turns out the reason 320... wasn't reverting was two additional fixes to it that landed before v5.7. Since they had Fixes: 320... labels they were easy enough to find and patch-revert, after which patch-reverting 320... itself worked against a current v5.8-rc5-8-g0dc589da8. I first tested it without the reverts to be sure it's still triggering this bug for me, and just confirmed it was, freeze with the telltale log dump. So for me at least, v5.8-rc5 is bad (just updated the version field to reflect that). Meanwhile I've applied the three 320-and-followups revert-patches to v5.8-rc5-8-g0dc589da8 and just did the rebuild with them applied. Now to reboot to it and see if it still has our bug. If no, great, pinned down. If yes, there's still that 630... commit to try to test. -- You are receiving this mail because: You are watching the assignee of the bug. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [Freedreno] [PATCH 0/9] drm/msm: Avoid possible infinite probe deferral and speed booting
On Tue, Jul 14, 2020 at 10:33 AM Jeffrey Hugo wrote: > > On Mon, Jul 13, 2020 at 5:50 PM Doug Anderson wrote: > > > > Hi, > > > > On Mon, Jul 13, 2020 at 1:25 PM Rob Herring wrote: > > > > > > On Mon, Jul 13, 2020 at 9:08 AM Doug Anderson > > > wrote: > > > > > > > > Hi, > > > > > > > > On Mon, Jul 13, 2020 at 7:11 AM Rob Herring wrote: > > > > > > > > > > On Fri, Jul 10, 2020 at 5:02 PM Douglas Anderson > > > > > wrote: > > > > > > > > > > > > I found that if I ever had a little mistake in my kernel config, > > > > > > or device tree, or graphics driver that my system would sit in a > > > > > > loop > > > > > > at bootup trying again and again and again. An example log was: > > > > > > > > > > Why do we care about optimizing the error case? > > > > > > > > It actually results in a _fully_ infinite loop. That is: if anything > > > > small causes a component of DRM to fail to probe then the whole system > > > > doesn't boot because it just loops trying to probe over and over > > > > again. The messages I put in the commit message are printed over and > > > > over and over again. > > > > > > Sounds like a bug as that's not what should happen. > > > > > > If you defer during boot (initcalls), then you'll be on the deferred > > > list until late_initcall and everything is retried. After > > > late_initcall, only devices getting added should trigger probing. But > > > maybe the adding and then removing a device is causing a re-trigger. > > > > Right, I'm nearly certain that the adding and then removing is causing > > a re-trigger. I believe the loop would happen for any case where we > > have a probe function that: > > > > 1. Adds devices. > > 2. After adding devices it decides that it needs to defer. > > 3. Removes the devices it added. > > 4. Return -EPROBE_DEFER from its probe function. > > > > Specifically from what I know about how -EPROBE_DEFER works I'm not > > sure how it wouldn't cause an infinite loop in that case. > > > > Perhaps the missing part of my explanation, though, is why it never > > gets out of this infinite loop. In my case I purposely made the > > bridge chip "ti-sn65dsi86.c" return an error (-EINVAL) in its probe > > every time. Obviously I wasn't going to get a display up like this, > > but I just wanted to not loop forever at bootup. I tracked down > > exactly why we get an - EPROBE_DEFER over and over in this case. > > > > You can see it in msm_dsi_host_register(). If some components haven't > > shown up when that function runs it will _always_ return > > -EPROBE_DEFER. > > > > In my case, since I caused the bridge to fail to probe, those > > components will _never_ show up. That means that > > msm_dsi_host_register() will _always_ return -EPROBE_DEFER. > > > > I haven't dug through all the DRM code enough, but it doesn't > > necessarily seem like the wrong behavior. If the bridge driver or a > > panel was a module then (presumably) they could show up later and so > > it should be OK for it to defer, right? > > > > So with all that, it doesn't really feel like this is a bug so much as > > it's an unsupported use case. The current deferral logic simply can't > > handle the case we're throwing at it. You cannot return -EPROBE_DEFER > > if your probe function adds devices each time through the probe > > function. > > > > Assuming all the above makes sense, that means we're stuck with: > > > > a) This patch series, which makes us not add devices. > > > > b) Some other patch series which rearchitects the MSM graphics stack > > to not return -EPROBE_DEFER in this case. > > This isn't a MSM specific issue. This is an issue with how the DSI > interface works, and how software is structured in Linux. I would > expect that pretty much any DSI host in the kernel would have some > version of this issue. > > The problem is that DSI is not "hot pluggable", so to give the DRM > stack the info it needs, we need both the DSI controller (aka the MSM > graphics stack in your case), and the thing it connects to (in your > case, the TI bridge, normally the actual panel) because the DRM stack > expects that if init completes, it has certain information > (resolution, etc), and some of that information is in the DSI > controller, and some of it is on the DSI device. Ah yes, DRM's lack of hot-plug and discrete component support... Is that not improved with some of the bridge rework? Anyways, given there is a child dependency on the parent, I don't think we should work-around DRM deficiencies in DT. BTW, There's also a deferred probe timeout you can use which stops deferring probe some number of seconds after late_initcall. Rob ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] ksz884x: switch from 'pci_' to 'dma_' API
From: Christophe JAILLET Date: Tue, 14 Jul 2020 20:35:01 +0200 > The wrappers in include/linux/pci-dma-compat.h should go away. > > The patch has been generated with the coccinelle script below and has been > hand modified to replace GFP_ with a correct flag. > It has been compile tested. > > When memory is allocated in 'ksz_alloc_desc()', GFP_KERNEL can be used > because a few lines below, GFP_KERNEL is also used in the > 'ksz_alloc_soft_desc()' calls. ... > Signed-off-by: Christophe JAILLET Applied, thank you. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 1/3] dma-buf/sw_sync: Avoid recursive lock during fence signal.
From: Bas Nieuwenhuizen Calltree: timeline_fence_release drm_sched_entity_wakeup dma_fence_signal_locked sync_timeline_signal sw_sync_ioctl Releasing the reference to the fence in the fence signal callback seems reasonable to me, so this patch avoids the locking issue in sw_sync. d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") fixed the recursive locking issue but caused an use-after-free. Later d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") fixed the use-after-free but reintroduced the recursive locking issue. In this attempt we avoid the use-after-free still because the release function still always locks, and outside of the locking region in the signal function we have properly refcounted references. We furthermore also avoid the recurive lock by making sure that either: 1) We have a properly refcounted reference, preventing the signal from triggering the release function inside the locked region. 2) The refcount was already zero, and hence nobody will be able to trigger the release function from the signal function. v2: Move dma_fence_signal() into second loop in preparation to moving the callback out of the timeline obj->lock. Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") Cc: Sumit Semwal Cc: Chris Wilson Cc: Gustavo Padovan Cc: Christian König Cc: Signed-off-by: Bas Nieuwenhuizen Signed-off-by: Chris Wilson --- drivers/dma-buf/sw_sync.c | 32 ++-- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 348b3a9170fa..807c82148062 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -192,6 +192,7 @@ static const struct dma_fence_ops timeline_fence_ops = { static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { struct sync_pt *pt, *next; + LIST_HEAD(signal); trace_sync_timeline(obj); @@ -203,21 +204,32 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) if (!timeline_fence_signaled(&pt->base)) break; - list_del_init(&pt->link); - rb_erase(&pt->node, &obj->pt_tree); - /* -* A signal callback may release the last reference to this -* fence, causing it to be freed. That operation has to be -* last to avoid a use after free inside this loop, and must -* be after we remove the fence from the timeline in order to -* prevent deadlocking on timeline->lock inside -* timeline_fence_release(). +* We need to take a reference to avoid a release during +* signalling (which can cause a recursive lock of obj->lock). +* If refcount was already zero, another thread is already +* taking care of destroying the fence. */ - dma_fence_signal_locked(&pt->base); + if (!dma_fence_get_rcu(&pt->base)) + continue; + + list_move_tail(&pt->link, &signal); + rb_erase(&pt->node, &obj->pt_tree); } spin_unlock_irq(&obj->lock); + + list_for_each_entry_safe(pt, next, &signal, link) { + /* +* This needs to be cleared before release, otherwise the +* timeline_fence_release function gets confused about also +* removing the fence from the pt_tree. +*/ + list_del_init(&pt->link); + + dma_fence_signal(&pt->base); + dma_fence_put(&pt->base); + } } /** -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 2/3] dma-buf/sw_sync: Separate signal/timeline locks
Since we decouple the sync_pt from the timeline tree upon release, in order to allow releasing the sync_pt from a signal callback we need to separate the sync_pt signaling lock from the timeline tree lock. v2: Mark up the unlocked read of the current timeline value. v3: Store a timeline pointer in the sync_pt as we cannot use the common fence->lock trick to find our parent anymore. Suggested-by: Bas Nieuwenhuizen Signed-off-by: Chris Wilson Cc: Bas Nieuwenhuizen --- drivers/dma-buf/sw_sync.c| 40 +--- drivers/dma-buf/sync_debug.c | 2 +- drivers/dma-buf/sync_debug.h | 13 +++- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 807c82148062..17a5c1a3b7ce 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -123,33 +123,39 @@ static const char *timeline_fence_get_driver_name(struct dma_fence *fence) static const char *timeline_fence_get_timeline_name(struct dma_fence *fence) { - struct sync_timeline *parent = dma_fence_parent(fence); - - return parent->name; + return sync_timeline(fence)->name; } static void timeline_fence_release(struct dma_fence *fence) { struct sync_pt *pt = dma_fence_to_sync_pt(fence); - struct sync_timeline *parent = dma_fence_parent(fence); - unsigned long flags; + struct sync_timeline *parent = pt->timeline; - spin_lock_irqsave(fence->lock, flags); if (!list_empty(&pt->link)) { - list_del(&pt->link); - rb_erase(&pt->node, &parent->pt_tree); + unsigned long flags; + + spin_lock_irqsave(&parent->lock, flags); + if (!list_empty(&pt->link)) { + list_del(&pt->link); + rb_erase(&pt->node, &parent->pt_tree); + } + spin_unlock_irqrestore(&parent->lock, flags); } - spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); dma_fence_free(fence); } -static bool timeline_fence_signaled(struct dma_fence *fence) +static int timeline_value(struct dma_fence *fence) { - struct sync_timeline *parent = dma_fence_parent(fence); + return READ_ONCE(sync_timeline(fence)->value); +} - return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops); +static bool timeline_fence_signaled(struct dma_fence *fence) +{ + return !__dma_fence_is_later(fence->seqno, +timeline_value(fence), +fence->ops); } static bool timeline_fence_enable_signaling(struct dma_fence *fence) @@ -166,9 +172,7 @@ static void timeline_fence_value_str(struct dma_fence *fence, static void timeline_fence_timeline_value_str(struct dma_fence *fence, char *str, int size) { - struct sync_timeline *parent = dma_fence_parent(fence); - - snprintf(str, size, "%d", parent->value); + snprintf(str, size, "%d", timeline_value(fence)); } static const struct dma_fence_ops timeline_fence_ops = { @@ -252,12 +256,14 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, return NULL; sync_timeline_get(obj); - dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + spin_lock_init(&pt->lock); + dma_fence_init(&pt->base, &timeline_fence_ops, &pt->lock, obj->context, value); INIT_LIST_HEAD(&pt->link); + pt->timeline = obj; spin_lock_irq(&obj->lock); - if (!dma_fence_is_signaled_locked(&pt->base)) { + if (!dma_fence_is_signaled(&pt->base)) { struct rb_node **p = &obj->pt_tree.rb_node; struct rb_node *parent = NULL; diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c index 101394f16930..2188ee17e889 100644 --- a/drivers/dma-buf/sync_debug.c +++ b/drivers/dma-buf/sync_debug.c @@ -65,7 +65,7 @@ static const char *sync_status_str(int status) static void sync_print_fence(struct seq_file *s, struct dma_fence *fence, bool show) { - struct sync_timeline *parent = dma_fence_parent(fence); + struct sync_timeline *parent = sync_timeline(fence); int status; status = dma_fence_get_status_locked(fence); diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index 6176e52ba2d7..56589dae2159 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -45,23 +45,26 @@ struct sync_timeline { struct list_headsync_timeline_list; }; -static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) -{ - return container_of(fence->lock, struct sync_timeline, lock); -} - /** * struct sync_pt - sync_pt object * @base: base fence object * @link: link on the sync timeline's list * @node: node in the s
[PATCH v2 3/3] dma-buf/selftests: Add locking selftests for sw_sync
While sw_sync is purely a debug facility for userspace to create fences and timelines it can control, nevertheless it has some tricky locking semantics of its own. In particular, Bas Nieuwenhuizen reported that we had reintroduced a deadlock if a signal callback attempted to destroy the fence. So let's add a few trivial selftests to make sure that once fixed again, it stays fixed. Signed-off-by: Chris Wilson Cc: Bas Nieuwenhuizen Reviewed-by: Bas Nieuwenhuizen --- drivers/dma-buf/Makefile | 3 +- drivers/dma-buf/selftests.h | 1 + drivers/dma-buf/st-sw_sync.c | 279 +++ drivers/dma-buf/sw_sync.c| 39 + drivers/dma-buf/sync_debug.h | 8 + 5 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 drivers/dma-buf/st-sw_sync.c diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 995e05f609ff..9be4d4611609 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o dmabuf_selftests-y := \ selftest.o \ st-dma-fence.o \ - st-dma-fence-chain.o + st-dma-fence-chain.o \ + st-sw_sync.o obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h index bc8cea67bf1e..232499a24872 100644 --- a/drivers/dma-buf/selftests.h +++ b/drivers/dma-buf/selftests.h @@ -12,3 +12,4 @@ selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */ selftest(dma_fence, dma_fence) selftest(dma_fence_chain, dma_fence_chain) +selftest(sw_sync, sw_sync) diff --git a/drivers/dma-buf/st-sw_sync.c b/drivers/dma-buf/st-sw_sync.c new file mode 100644 index ..145fd330f1c6 --- /dev/null +++ b/drivers/dma-buf/st-sw_sync.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sync_debug.h" +#include "selftest.h" + +static int sanitycheck(void *arg) +{ + struct sync_timeline *tl; + struct dma_fence *f; + int err = -ENOMEM; + + /* Quick check we can create the timeline and syncpt */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + f = st_sync_pt_create(tl, 1); + if (!f) + goto out; + + dma_fence_signal(f); + dma_fence_put(f); + + err = 0; +out: + st_sync_timeline_put(tl); + return err; +} + +static int signal(void *arg) +{ + struct sync_timeline *tl; + struct dma_fence *f; + int err = -EINVAL; + + /* Check that the syncpt fence is signaled when the timeline advances */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + f = st_sync_pt_create(tl, 1); + if (!f) { + err = -ENOMEM; + goto out; + } + + if (dma_fence_is_signaled(f)) { + pr_err("syncpt:%lld signaled too early\n", f->seqno); + goto out_fence; + } + + st_sync_timeline_signal(tl, 1); + + if (!dma_fence_is_signaled(f)) { + pr_err("syncpt:%lld not signaled after increment\n", f->seqno); + goto out_fence; + } + + err = 0; +out_fence: + dma_fence_signal(f); + dma_fence_put(f); +out: + st_sync_timeline_put(tl); + return err; +} + +struct cb_destroy { + struct dma_fence_cb cb; + struct dma_fence *f; +}; + +static void cb_destroy(struct dma_fence *fence, struct dma_fence_cb *_cb) +{ + struct cb_destroy *cb = container_of(_cb, typeof(*cb), cb); + + pr_info("syncpt:%llx destroying syncpt:%llx\n", + fence->seqno, cb->f->seqno); + dma_fence_put(cb->f); + cb->f = NULL; +} + +static int cb_autodestroy(void *arg) +{ + struct sync_timeline *tl; + struct cb_destroy cb; + int err = -EINVAL; + + /* Check that we can drop the final syncpt reference from a callback */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + cb.f = st_sync_pt_create(tl, 1); + if (!cb.f) { + err = -ENOMEM; + goto out; + } + + if (dma_fence_add_callback(cb.f, &cb.cb, cb_destroy)) { + pr_err("syncpt:%lld signaled before increment\n", cb.f->seqno); + goto out; + } + + st_sync_timeline_signal(tl, 1); + if (cb.f) { + pr_err("syncpt:%lld callback not run\n", cb.f->seqno); + dma_fence_put(cb.f); + goto out; + } + + err = 0; +out: + st_sync_timeline_put(tl); + return err; +} + +static int cb_destroy_12(void *arg) +{ + struct sync_timeline *tl; + struct cb_destroy cb; + struct dma_fence *f; + int err = -EINVAL; + + /* Check that we can drop some other syncpt refe
sw_sync callback deadlock
Take 2. dma_fence_parent() relied on fence->lock pointing into the sync_timeline which is no more, so we need a sync_pt->timeline backpointer instead. -Chris ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 25/59] drm/kmb: Display clock enable/disable
Get clock info from DT and enable it during initialization. Also changed name of the driver to "kmb,display" to match other entries in the DT. v2: fixed error in clk_disable Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 41 +++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 5a2ff9d..71fdb94 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -32,6 +32,25 @@ /*IRQ handler*/ static irqreturn_t kmb_isr(int irq, void *arg); +static struct clk *clk_lcd; +static struct clk *clk_mipi; + +static int kmb_display_clk_enable(void) +{ + clk_prepare_enable(clk_lcd); + clk_prepare_enable(clk_mipi); + return 0; +} + +static int kmb_display_clk_disable(void) +{ + if (clk_lcd) + clk_disable_unprepare(clk_lcd); + if (clk_mipi) + clk_disable_unprepare(clk_mipi); + return 0; +} + static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); @@ -153,6 +172,19 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } + /* enable display clocks*/ + clk_lcd = clk_get(&pdev->dev, "clk_lcd"); + if (!clk_lcd) { + DRM_ERROR("clk_get() failed clk_lcd\n"); + goto setup_fail; + } + clk_mipi = clk_get(&pdev->dev, "clk_mipi"); + if (!clk_mipi) { + DRM_ERROR("clk_get() failed clk_mipi\n"); + goto setup_fail; + } + kmb_display_clk_enable(); + ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); if (ret < 0) { DRM_ERROR("failed to install IRQ handler\n"); @@ -382,6 +414,11 @@ static void kmb_drm_unbind(struct device *dev) of_reserved_mem_device_release(drm->dev); drm_mode_config_cleanup(drm); + /*release clks */ + kmb_display_clk_disable(); + clk_put(clk_lcd); + clk_put(clk_mipi); + drm_dev_put(drm); drm->dev_private = NULL; dev_set_drvdata(dev, NULL); @@ -420,8 +457,8 @@ static int kmb_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id kmb_of_match[] = { - {.compatible = "lcd"}, +static const struct of_device_id kmb_of_match[] = { + {.compatible = "kmb,display"}, {}, }; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 43/59] drm/kmb: Changed name of driver to kmb-drm
name change Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/Makefile | 4 ++-- drivers/gpu/drm/kmb/kmb_drv.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/kmb/Makefile b/drivers/gpu/drm/kmb/Makefile index 8102bc9..527d737 100644 --- a/drivers/gpu/drm/kmb/Makefile +++ b/drivers/gpu/drm/kmb/Makefile @@ -1,2 +1,2 @@ -kmb-display-y := kmb_crtc.o kmb_drv.o kmb_plane.o kmb_dsi.o -obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb-display.o +kmb-drm-y := kmb_crtc.o kmb_drv.o kmb_plane.o kmb_dsi.o +obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb-drm.o diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 039dd21..bbf3e649 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -447,7 +447,7 @@ static struct drm_driver kmb_driver = { .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, .fops = &fops, - .name = "kmb_display", + .name = "kmb-drm", .desc = "KEEMBAY DISPLAY DRIVER ", .date = "20190122", .major = 1, @@ -630,7 +630,7 @@ static struct platform_driver kmb_platform_driver = { .probe = kmb_probe, .remove = kmb_remove, .driver = { - .name = "kmb_display", + .name = "kmb-drm", .pm = &kmb_pm_ops, .of_match_table = kmb_of_match, }, -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 55/59] drm/kmb: Added useful messages in LCD ISR
Print messages for LCD DMA FIFO errors. v2: corrected spelling Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 68 +++-- drivers/gpu/drm/kmb/kmb_plane.h | 2 ++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 55574c1..7fcab4b 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -361,15 +361,15 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev) * disabled but actually disable the plane when EOF irq is * being handled. */ - for (plane_id = LAYER_0; plane_id < KMB_MAX_PLANES; - plane_id++) { + for (plane_id = LAYER_0; plane_id < KMB_MAX_PLANES; plane_id++) { if (plane_status[plane_id].disable) { kmb_clr_bitmask_lcd(dev_p, - LCD_LAYERn_DMA_CFG(plane_id), - LCD_DMA_LAYER_ENABLE); + LCD_LAYERn_DMA_CFG + (plane_id), + LCD_DMA_LAYER_ENABLE); kmb_clr_bitmask_lcd(dev_p, LCD_CONTROL, - plane_status[plane_id].ctrl); + plane_status[plane_id].ctrl); plane_status[plane_id].disable = false; } @@ -381,11 +381,6 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev) kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_LINE_CMP); } - if (status & LCD_INT_LAYER) { - /* Clear layer interrupts */ - kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_LAYER); - } - if (status & LCD_INT_VERT_COMP) { /* Read VSTATUS */ val = kmb_read_lcd(dev_p, LCD_VSTATUS); @@ -403,6 +398,59 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev) } } + if (status & LCD_INT_DMA_ERR) { + val = (status & LCD_INT_DMA_ERR); + /* LAYER0 - VL0 */ + if (val & LAYER0_DMA_FIFO_UNDERFLOW) + DRM_INFO("LAYER0:VL0 DMA UNDERFLOW val = 0x%lx", val); + if (val & LAYER0_DMA_FIFO_OVERFLOW) + DRM_INFO("LAYER0:VL0 DMA OVERFLOW val = 0x%lx", val); + if (val & LAYER0_DMA_CB_FIFO_OVERFLOW) + DRM_INFO("LAYER0:VL0 DMA CB OVERFLOW val = 0x%lx", val); + if (val & LAYER0_DMA_CB_FIFO_UNDERFLOW) + DRM_INFO("LAYER0:VL0 DMA CB UNDERFLOW val = 0x%lx", +val); + if (val & LAYER0_DMA_CR_FIFO_UNDERFLOW) + DRM_INFO("LAYER0:VL0 DMA CR UNDERFLOW val = 0x%lx", +val); + if (val & LAYER0_DMA_CR_FIFO_OVERFLOW) + DRM_INFO("LAYER0:VL0 DMA CR OVERFLOW val = 0x%lx", val); + + /* LAYER1 - VL1 */ + if (val & LAYER1_DMA_FIFO_UNDERFLOW) + DRM_INFO("LAYER1:VL1 DMA UNDERFLOW val = 0x%lx", val); + if (val & LAYER1_DMA_FIFO_OVERFLOW) + DRM_INFO("LAYER1:VL1 DMA OVERFLOW val = 0x%lx", val); + if (val & LAYER1_DMA_CB_FIFO_OVERFLOW) + DRM_INFO("LAYER1:VL1 DMA CB OVERFLOW val = 0x%lx", val); + if (val & LAYER1_DMA_CB_FIFO_UNDERFLOW) + DRM_INFO("LAYER1:VL1 DMA CB UNDERFLOW val = 0x%lx", +val); + if (val & LAYER1_DMA_CR_FIFO_UNDERFLOW) + DRM_INFO("LAYER1:VL1 DMA CR UNDERFLOW val = 0x%lx", +val); + if (val & LAYER1_DMA_CR_FIFO_OVERFLOW) + DRM_INFO("LAYER1:VL1 DMA CR OVERFLOW val = 0x%lx", val); + + /* LAYER2 - GL0 */ + if (val & LAYER2_DMA_FIFO_UNDERFLOW) + DRM_INFO("LAYER2:GL0 DMA UNDERFLOW val = 0x%lx", val); + if (val & LAYER2_DMA_FIFO_OVERFLOW) + DRM_INFO("LAYER2:GL0 DMA OVERFLOW val = 0x%lx", val); + + /* LAYER3 - GL1 */ + if (val & LAYER3_DMA_FIFO_UNDERFLOW) + DRM_INFO("LAYER3:GL1 DMA UNDERFLOW val = 0x%lx", val); + if (val & LAYER3_DMA_FIFO_UNDERFLOW) + DRM_INFO("LAYER3:GL1 DMA OVERFLOW val = 0x%lx", val); + + } + + if (status & LCD_INT_LAYER) { + /* Clear layer interrupts */ + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_LAYER); + } + /* Clear all interrupts */ kmb_set_bitmask_lcd(dev_p, LCD_INT_CLEAR, 1); re
[PATCH v2 30/59] drm/kmb: call bridge init in the very beginning
of probe and return probe_defer early on, so that all the other initializations can be done after adv driver is loaded successfully. Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 74 +- drivers/gpu/drm/kmb/kmb_dsi.c | 144 ++ drivers/gpu/drm/kmb/kmb_dsi.h | 6 +- 3 files changed, 138 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 36edfbf..76f3c43 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -37,11 +37,24 @@ static struct clk *clk_lcd; static struct clk *clk_mipi; static int probe_deferred; +struct drm_bridge *adv_bridge; static int kmb_display_clk_enable(void) { - clk_prepare_enable(clk_lcd); - clk_prepare_enable(clk_mipi); + int ret; + + ret = clk_prepare_enable(clk_lcd); + if (ret) { + DRM_ERROR("Failed to enable LCD clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(clk_mipi); + if (ret) { + DRM_ERROR("Failed to enable MIPI clock: %d\n", ret); + return ret; + } + DRM_INFO("SUCCESS : enabled LCD MIPI clocks\n"); return 0; } @@ -86,8 +99,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) *} */ /* LCD mmio */ - if (!probe_deferred) { - probe_deferred = 1; + probe_deferred = 1; if (!request_mem_region(LCD_BASE_ADDR, LCD_MMIO_SIZE, "kmb-lcd")) { DRM_ERROR("failed to reserve LCD registers\n"); @@ -120,9 +132,10 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) * lists LCD at 79 and 82 for MIPI under MSS CPU - * firmware has to redirect it to A53 */ -/*TBD read and check for correct product version here */ - /* Get the optional framebuffer memory resource */ + /*TBD read and check for correct product version here */ + + /* Get the optional framebuffer memory resource */ ret = of_reserved_mem_device_init(drm->dev); if (ret && ret != -ENODEV) return ret; @@ -134,8 +147,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } -/* ret = kmb_dsi_init(drm, bridge);*/ - ret = kmb_dsi_init(drm); + ret = kmb_dsi_init(drm, adv_bridge); if (ret == -EPROBE_DEFER) { DRM_INFO("%s: wait for external bridge driver DT", __func__); return -EPROBE_DEFER; @@ -143,7 +155,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_ERROR("failed to initialize DSI\n"); goto setup_fail; } -} /* enable display clocks*/ clk_lcd = clk_get(&pdev->dev, "clk_lcd"); if (!clk_lcd) { @@ -157,10 +168,9 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } DRM_INFO("%s : %d\n", __func__, __LINE__); - kmb_display_clk_enable(); - - DRM_INFO("%s : %d\n", __func__, __LINE__); + ret = kmb_display_clk_enable(); + DRM_INFO("%s : %d clk enabling ret=%d\n", __func__, __LINE__, ret); return 0; drm_crtc_cleanup(&dev_p->crtc); @@ -268,7 +278,7 @@ static struct drm_driver kmb_driver = { .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, .fops = &fops, - .name = "kmb", + .name = "kmb_display", .desc = "KEEMBAY DISPLAY DRIVER ", .date = "20190122", .major = 1, @@ -277,7 +287,7 @@ static struct drm_driver kmb_driver = { static int kmb_drm_bind(struct device *dev) { - struct drm_device *drm; + struct drm_device *drm = NULL; struct kmb_drm_private *lcd; int ret; @@ -296,7 +306,9 @@ static int kmb_drm_bind(struct device *dev) dev_set_drvdata(dev, drm); kmb_setup_mode_config(drm); - DRM_DEBUG("kmb_bind : after kmb_setup_mode_config\n"); + dev_set_drvdata(dev, drm); + + /* load the driver */ ret = kmb_load(drm, 0); DRM_INFO("%s : %d ret = %d\n", __func__, __LINE__, ret); if (ret == -EPROBE_DEFER) { @@ -337,7 +349,6 @@ static int kmb_drm_bind(struct device *dev) drm_kms_helper_poll_fini(drm); err_vblank: pm_runtime_disable(drm->dev); - component_unbind_all(dev, drm); of_node_put(lcd->crtc.port); lcd->crtc.port = NULL; drm_irq_uninstall(drm); @@ -355,9 +366,9 @@ static void kmb_drm_unbind(struct device *dev) struct drm_device *drm = dev_get_drvdata(dev); struct kmb_drm_private *dev_p = to_kmb(drm); + dump_stack(); drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); - component_unbind_all(dev, drm); of_node_put(dev_p->crtc.port);
[PATCH v2 07/59] drm/kmb: Set OUT_FORMAT_CFG register
v2: code review changes Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 14 +- drivers/gpu/drm/kmb/kmb_regs.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 74a3573..cb05cb8 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -208,7 +208,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, unsigned int dma_len; struct kmb_plane *kmb_plane = to_kmb_plane(plane); unsigned int dma_cfg; - unsigned int ctrl = 0, val = 0; + unsigned int ctrl = 0, val = 0, out_format = 0; unsigned int src_w, src_h, crtc_x, crtc_y; unsigned char plane_id = kmb_plane->id; @@ -279,6 +279,18 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, /* enable DMA */ kmb_write(lcd, LCD_LAYERn_DMA_CFG(plane_id), dma_cfg); + /* FIXME no doc on how to set output format - may need to change +* this later +*/ + if (val & LCD_LAYER_BGR_ORDER) + out_format |= LCD_OUTF_BGR_ORDER; + else if (val & LCD_LAYER_CRCB_ORDER) + out_format |= LCD_OUTF_CRCB_ORDER; + /* do not interleave RGB channels for mipi Tx compatibility */ + out_format |= LCD_OUTF_MIPI_RGB_MODE; + /* pixel format from LCD_LAYER_CFG */ + out_format |= ((val >> 9) & 0x1F); + kmb_write(lcd, LCD_OUT_FORMAT_CFG, out_format); } static const struct drm_plane_helper_funcs kmb_plane_helper_funcs = { diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index 8346a04..8b67f2b 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -320,6 +320,7 @@ #define LCD_OUTF_BGR_ORDER (1 << 5) #define LCD_OUTF_Y_ORDER (1 << 6) #define LCD_OUTF_CRCB_ORDER (1 << 7) +#define LCD_OUTF_MIPI_RGB_MODE (1 << 18) #define LCD_HSYNC_WIDTH(0x4 * 0x801) #define LCD_H_BACKPORCH(0x4 * 0x802) -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 12/59] drm/kmb: Part3 of Mipi Tx initialization
This initializes the multichannel fifo in the mipi transmitter and sets the LCD to mipi interconnect which connects LCD to MIPI ctrl #6 v2: code review changes to make code simpler Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.h | 25 +++--- drivers/gpu/drm/kmb/kmb_dsi.c | 58 ++ drivers/gpu/drm/kmb/kmb_dsi.h | 3 +++ drivers/gpu/drm/kmb/kmb_regs.h | 30 +++--- 4 files changed, 99 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index d2a0f91..f1d5b3a 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -8,8 +8,8 @@ #include "kmb_regs.h" -#define KMB_MAX_WIDTH 16384 /*max width in pixels */ -#define KMB_MAX_HEIGHT 16384 /*max height in pixels */ +#define KMB_MAX_WIDTH 16384 /*max width in pixels */ +#define KMB_MAX_HEIGHT 16384 /*max height in pixels */ struct kmb_drm_private { struct drm_device drm; @@ -64,6 +64,11 @@ static inline void kmb_write_bits(struct kmb_drm_private *lcd, } #endif +static inline void kmb_write(void *reg, u32 value) +{ + writel(value, reg); +} + static inline void kmb_write_lcd(unsigned int reg, u32 value) { writel(value, (LCD_BASE_ADDR + reg)); @@ -85,7 +90,7 @@ static inline u32 kmb_read_mipi(unsigned int reg) } static inline void kmb_write_bits_mipi(unsigned int reg, u32 offset, - u32 num_bits, u32 value) + u32 num_bits, u32 value) { u32 reg_val = kmb_read_mipi(reg); u32 mask = (1 << num_bits) - 1; @@ -97,6 +102,20 @@ static inline void kmb_write_bits_mipi(unsigned int reg, u32 offset, kmb_write_mipi(reg, reg_val); } +static inline void kmb_set_bit_mipi(unsigned int reg, u32 offset) +{ + u32 reg_val = kmb_read_mipi(reg); + + kmb_write_mipi(reg, reg_val | (1 << offset)); +} + +static inline void kmb_clr_bit_mipi(unsigned int reg, u32 offset) +{ + u32 reg_val = kmb_read_mipi(reg); + + kmb_write_mipi(reg, reg_val & (~(1 << offset))); +} + int kmb_setup_crtc(struct drm_device *dev); void kmb_set_scanout(struct kmb_drm_private *lcd); #endif /* __KMB_DRV_H__ */ diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 2326d3b..a5b9681 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -503,10 +503,41 @@ static void mipi_tx_fg_cfg(struct kmb_drm_private *dev_priv, u8 frame_gen, mipi_tx_fg_cfg_regs(dev_priv, frame_gen, &fg_t_cfg); } +static void mipi_tx_multichannel_fifo_cfg(u8 active_lanes, u8 vchannel_id) +{ + u32 fifo_size, fifo_rthreshold; + u32 ctrl_no = MIPI_CTRL6; + + /*clear all mc fifo channel sizes and thresholds*/ + kmb_write_mipi(MIPI_TX_HS_MC_FIFO_CTRL_EN, 0); + kmb_write_mipi(MIPI_TX_HS_MC_FIFO_CHAN_ALLOC0, 0); + kmb_write_mipi(MIPI_TX_HS_MC_FIFO_CHAN_ALLOC1, 0); + kmb_write_mipi(MIPI_TX_HS_MC_FIFO_RTHRESHOLD0, 0); + kmb_write_mipi(MIPI_TX_HS_MC_FIFO_RTHRESHOLD1, 0); + + fifo_size = (active_lanes > MIPI_D_LANES_PER_DPHY) ? + MIPI_CTRL_4LANE_MAX_MC_FIFO_LOC : + MIPI_CTRL_2LANE_MAX_MC_FIFO_LOC; + /*MC fifo size for virtual channels 0-3 */ + /* +*REG_MC_FIFO_CHAN_ALLOC0: [8:0]-channel0, [24:16]-channel1 +*REG_MC_FIFO_CHAN_ALLOC1: [8:0]-2, [24:16]-channel3 +*/ + SET_MC_FIFO_CHAN_ALLOC(ctrl_no, vchannel_id, fifo_size); + + /*set threshold to half the fifo size, actual size=size*16*/ + fifo_rthreshold = ((fifo_size + 1) * 8) & BIT_MASK_16; + SET_MC_FIFO_RTHRESHOLD(ctrl_no, vchannel_id, fifo_rthreshold); + + /*enable the MC FIFO channel corresponding to the Virtual Channel */ + kmb_set_bit_mipi(MIPI_TXm_HS_MC_FIFO_CTRL_EN(ctrl_no), vchannel_id); +} + static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_priv, - struct mipi_ctrl_cfg *ctrl_cfg) + struct mipi_ctrl_cfg *ctrl_cfg) { u32 ret; + u8 active_vchannels = 0; u8 frame_id, sect; u32 bits_per_pclk = 0; u32 word_count = 0; @@ -544,18 +575,23 @@ static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_priv, /* set frame specific parameters */ mipi_tx_fg_cfg(dev_priv, frame_id, ctrl_cfg->active_lanes, - bits_per_pclk, - word_count, - ctrl_cfg->lane_rate_mbps, - ctrl_cfg->tx_ctrl_cfg.frames[frame_id]); - /*function for setting frame sepecific parameters will be -* called here -*/ - /*bits_per_pclk and word_count will be passed in to this -* function -*/ +
[PATCH v2 58/59] drm/kmb: Get System Clock from SCMI
System clock is different for A0 and B0 silicons, so get it directly from clk_PLL0 through SCMI calls. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 11 +++ drivers/gpu/drm/kmb/kmb_drv.h | 1 + drivers/gpu/drm/kmb/kmb_dsi.c | 12 +--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 559742b8..17d303f 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -39,6 +39,7 @@ static struct clk *clk_lcd; static struct clk *clk_mipi; static struct clk *clk_mipi_ecfg; static struct clk *clk_mipi_cfg; +static struct clk *clk_pll0; struct drm_bridge *adv_bridge; @@ -122,6 +123,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) #ifdef ICAM_LCD_QOS int val = 0; #endif + struct device_node *vpu_dev; /* Map MIPI MMIO registers */ dev_p->mipi_mmio = kmb_map_mmio(pdev, "mipi_regs"); @@ -188,6 +190,15 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_ERROR("clk_get() failed clk_mipi_cfg\n"); goto setup_fail; } + vpu_dev = of_find_node_by_path("/soc/vpu-ipc"); + DRM_INFO("vpu node = %pOF", vpu_dev); + clk_pll0 = of_clk_get_by_name(vpu_dev, "pll_0_out_0"); + if (IS_ERR(clk_pll0)) { + DRM_ERROR("clk_get() failed clk_pll0 "); + goto setup_fail; + } + dev_p->sys_clk_mhz = clk_get_rate(clk_pll0)/100; + DRM_INFO("system clk = %d Mhz", dev_p->sys_clk_mhz); #ifdef LCD_TEST /* Set LCD clock to 200 Mhz */ DRM_DEBUG("Get clk_lcd before set = %ld\n", clk_get_rate(clk_lcd)); diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 939f8b4..72d0746 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -38,6 +38,7 @@ struct kmb_drm_private { spinlock_t irq_lock; int irq_lcd; int irq_mipi; + int sys_clk_mhz; dma_addr_t fb_addr; }; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 47798ed..8f8b50c 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -588,20 +588,10 @@ static void mipi_tx_fg_cfg_regs(struct kmb_drm_private *dev_p, u8 frame_gen, u32 ppl_llp_ratio; u32 ctrl_no = MIPI_CTRL6, reg_adr, val, offset; -#ifdef GET_SYS_CLK - /* Get system clock for blanking period cnfigurations */ - sc = get_clock_frequency(CPR_CLK_SYSTEM, &sysclk); - if (sc) - return sc; - - /* Convert to MHZ */ - sysclk /= 1000; -#else /* 500 Mhz system clock minus 50 to account for the difference in * MIPI clock speed in RTL tests */ - sysclk = KMB_SYS_CLK_MHZ - 50; -#endif + sysclk = dev_p->sys_clk_mhz - 50; /* PPL-Pixel Packing Layer, LLP-Low Level Protocol * Frame genartor timing parameters are clocked on the system clock, -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 49/59] drm/kmb: Disable ping pong mode
Disable ping pong mode otherwise video corruption results, use continuous mode and also fetch the dma addresses before disabling dma. For now, only initialize the dma and planes once and for next plane updates only update the addresses for dma. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 301 drivers/gpu/drm/kmb/kmb_plane.h | 8 ++ 2 files changed, 159 insertions(+), 150 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 5fd1837..a1d616a 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -83,11 +83,12 @@ static const u32 kmb_formats_v[] = { #define LCD_INT_GL1 (LAYER3_DMA_DONE | LAYER3_DMA_IDLE | LCD_INT_GL1_ERR) const uint32_t layer_irqs[] = { - LCD_INT_VL0, - LCD_INT_VL1, - LCD_INT_GL0, - LCD_INT_GL1 - }; + LCD_INT_VL0, + LCD_INT_VL1, + LCD_INT_GL0, + LCD_INT_GL1 +}; + /*Conversion (yuv->rgb) matrix from myriadx */ static const u32 csc_coef_lcd[] = { 1024, 0, 1436, @@ -96,7 +97,6 @@ static const u32 csc_coef_lcd[] = { -179, 125, -226 }; - static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) { int i; @@ -114,7 +114,6 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb; int ret; - fb = state->fb; if (!fb || !state->crtc) @@ -130,7 +129,7 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, } static void kmb_plane_atomic_disable(struct drm_plane *plane, - struct drm_plane_state *state) +struct drm_plane_state *state) { struct kmb_plane *kmb_plane = to_kmb_plane(plane); int ctrl = 0; @@ -156,14 +155,13 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane, } kmb_clr_bitmask_lcd(dev_p, LCD_LAYERn_DMA_CFG(plane_id), - LCD_DMA_LAYER_ENABLE); + LCD_DMA_LAYER_ENABLE); kmb_clr_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); DRM_INFO("%s : %d lcd_ctrl = 0x%x lcd_int_enable=0x%x\n", - __func__, __LINE__, kmb_read_lcd(dev_p, LCD_CONTROL), - kmb_read_lcd(dev_p, LCD_INT_ENABLE)); +__func__, __LINE__, kmb_read_lcd(dev_p, LCD_CONTROL), +kmb_read_lcd(dev_p, LCD_INT_ENABLE)); } - unsigned int set_pixel_format(u32 format) { unsigned int val = 0; @@ -198,8 +196,8 @@ unsigned int set_pixel_format(u32 format) val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE | LCD_LAYER_CRCB_ORDER; break; - /* packed formats */ - /* looks hw requires B & G to be swapped when RGB */ + /* packed formats */ + /* looks hw requires B & G to be swapped when RGB */ case DRM_FORMAT_RGB332: val = LCD_LAYER_FORMAT_RGB332 | LCD_LAYER_BGR_ORDER; break; @@ -263,7 +261,7 @@ unsigned int set_bits_per_pixel(const struct drm_format_info *format) return val; } - bpp += 8*format->cpp[0]; + bpp += 8 * format->cpp[0]; switch (bpp) { case 8: @@ -310,7 +308,6 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, #ifdef LCD_TEST struct drm_framebuffer *fb; struct kmb_drm_private *dev_p; - dma_addr_t addr; unsigned int width; unsigned int height; unsigned int dma_len; @@ -320,6 +317,9 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, unsigned int src_w, src_h, crtc_x, crtc_y; unsigned char plane_id; int num_planes; + /*plane initialization status */ + static int plane_init_status[KMB_MAX_PLANES] = { 0, 0, 0, 0 }; + static dma_addr_t addr[MAX_SUB_PLANES] = { 0, 0, 0 }; if (!plane || !plane->state || !state) return; @@ -339,146 +339,145 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, crtc_x = plane->state->crtc_x; crtc_y = plane->state->crtc_y; - DRM_INFO("src_w=%d src_h=%d\n", src_w, src_h); - kmb_write_lcd(dev_p, LCD_LAYERn_WIDTH(plane_id), src_w-1); - kmb_write_lcd(dev_p, LCD_LAYERn_HEIGHT(plane_id), src_h-1); - kmb_write_lcd(dev_p, LCD_LAYERn_COL_START(plane_id), crtc_x); - kmb_write_lcd(dev_p, LCD_LAYERn_ROW_START(plane_id), crtc_y); - - val = set_pixel_format(fb->format->format); - val |= set_bits_per_pixel(fb->format); - /*CHECKME Leon drvr sets it to 100 try this for now */ - val |= LCD_LAYER_FIFO_100; - kmb_write_lcd(dev_p, LCD_LAYERn_CFG(plane_id), val); - - /*re-initialize interrupts */ -
[PATCH v2 16/59] drm/kmb: Part6 of Mipi Tx Initialization
This is part2 of DPHY initialization- sets up DPHY PLLs. v2: simplified mipi_tx_get_vco_params() based on review v3: added WARN_ON for invalid freq v4: fixed bug in mipi_tx_get_vco_params Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 194 +++-- drivers/gpu/drm/kmb/kmb_regs.h | 2 + 2 files changed, 189 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index d15cf6f..02555c6 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -28,11 +28,33 @@ #define MIPI_TX_CFG_CLK_KHZ 24000 /*DPHY Tx test codes*/ -#define TEST_CODE_HS_FREQ_RANGE_CFG0x44 -#define TEST_CODE_PLL_ANALOG_PROG 0x1F -#define TEST_CODE_SLEW_RATE_OVERRIDE_CTRL 0xA0 -#define TEST_CODE_SLEW_RATE_DDL_LOOP_CTRL 0xA3 -#define TEST_CODE_SLEW_RATE_DDL_CYCLES 0xA4 +#define TEST_CODE_PLL_PROPORTIONAL_CHARGE_PUMP_CTRL0x0E +#define TEST_CODE_PLL_INTEGRAL_CHARGE_PUMP_CTRL0x0F +#define TEST_CODE_PLL_VCO_CTRL 0x12 +#define TEST_CODE_PLL_GMP_CTRL 0x13 +#define TEST_CODE_PLL_PHASE_ERR_CTRL 0x14 +#define TEST_CODE_PLL_LOCK_FILTER 0x15 +#define TEST_CODE_PLL_UNLOCK_FILTER0x16 +#define TEST_CODE_PLL_INPUT_DIVIDER0x17 +#define TEST_CODE_PLL_FEEDBACK_DIVIDER 0x18 +#define PLL_FEEDBACK_DIVIDER_HIGH(1 << 7) +#define TEST_CODE_PLL_OUTPUT_CLK_SEL 0x19 +#define PLL_N_OVR_EN (1 << 4) +#define PLL_M_OVR_EN (1 << 5) +#define TEST_CODE_PLL_CHARGE_PUMP_BIAS 0x1C +#define TEST_CODE_PLL_LOCK_DETECTOR0x1D +#define TEST_CODE_HS_FREQ_RANGE_CFG0x44 +#define TEST_CODE_PLL_ANALOG_PROG 0x1F +#define TEST_CODE_SLEW_RATE_OVERRIDE_CTRL 0xA0 +#define TEST_CODE_SLEW_RATE_DDL_LOOP_CTRL 0xA3 +#define TEST_CODE_SLEW_RATE_DDL_CYCLES 0xA4 + +/* D-Phy params */ +#define PLL_N_MIN 0 +#define PLL_N_MAX 15 +#define PLL_M_MIN 62 +#define PLL_M_MAX 623 +#define PLL_FVCO_MAX 1250 /* * These are added here only temporarily for testing, @@ -780,8 +802,158 @@ static inline void set_test_mode_src_osc_freq_target_hi_bits(u32 dphy_no, test_mode_send(dphy_no, TEST_CODE_SLEW_RATE_DDL_CYCLES, data); } +struct vco_params { + u32 freq; + u32 range; + u32 divider; +}; + +static struct vco_params vco_table[] = { + {52, 0x3f, 8}, + {80, 0x39, 8}, + {105, 0x2f, 4}, + {160, 0x29, 4}, + {210, 0x1f, 2}, + {320, 0x19, 2}, + {420, 0x0f, 1}, + {630, 0x09, 1}, + {1100, 0x03, 1}, + {0x, 0x01, 1}, +}; + +static void mipi_tx_get_vco_params(struct vco_params *vco) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vco_table); i++) { + if (vco->freq < vco_table[i].freq) { + *vco = vco_table[i]; + return; + } + } + WARN_ONCE(1, "Invalid vco freq = %u for PLL setup\n", vco->freq); +} + +static void mipi_tx_pll_setup(u32 dphy_no, u32 ref_clk_mhz, u32 target_freq_mhz) +{ + /* pll_ref_clk: - valid range: 2~64 MHz; Typically 24 MHz +* Fvco: - valid range: 320~1250 MHz (Gen3 D-PHY) +* Fout: - valid range: 40~1250 MHz (Gen3 D-PHY) +* n: - valid range [0 15] +* N: - N = n + 1 +* -valid range: [1 16] +* -conditions: - (pll_ref_clk / N) >= 2 MHz +* -(pll_ref_clk / N) <= 8 MHz +* m: valid range [62 623] +* M: - M = m + 2 +* -valid range [64 625] +* -Fvco = (M/N) * pll_ref_clk +*/ + struct vco_params vco_p = { + .range = 0, + .divider = 1, + }; + u32 best_n = 0, best_m = 0; + u32 n = 0, m = 0, div = 0, delta, freq = 0, t_freq; + u32 best_freq_delta = 3000; + + vco_p.freq = target_freq_mhz; + mipi_tx_get_vco_params(&vco_p); + /*search pll n parameter */ + for (n = PLL_N_MIN; n <= PLL_N_MAX; n++) { + /*calculate the pll input frequency division ratio +* multiply by 1000 for precision - +* no floating point, add n for rounding +*/ + div = ((ref_clk_mhz * 1000) + n)/(n+1); + /*found a valid n parameter */ + if ((div < 2000 || div > 8000)) + continue; + /*search pll m parameter */ + for (m = PLL_M_MIN; m <= PLL_M_MAX; m++) { + /*calculate the Fvco(DPHY PLL output frequency) +* using the current n,m params +
[PATCH v2 02/59] drm/kmb: Added id to kmb_plane
This is to keep track of the id of the plane as there are 4 planes in Kmb and when update() is called, we need to know which plane need to be updated so that the corresponding plane's registers can be programmed. v2: moved extern to .h, upclassed dev_private, minor changes from code review. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 13 --- drivers/gpu/drm/kmb/kmb_crtc.h | 2 +- drivers/gpu/drm/kmb/kmb_drv.h | 2 +- drivers/gpu/drm/kmb/kmb_plane.c | 80 +++-- drivers/gpu/drm/kmb/kmb_plane.h | 28 +-- 5 files changed, 79 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 1a00015..63821ed 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -105,9 +105,8 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write(lcd, LCD_VSYNC_START_EVEN, vsync_start_offset); kmb_write(lcd, LCD_VSYNC_END_EVEN, vsync_end_offset); } - /* enable all 4 layers */ - ctrl = LCD_CTRL_ENABLE | LCD_CTRL_VL1_ENABLE - | LCD_CTRL_VL2_ENABLE | LCD_CTRL_GL1_ENABLE | LCD_CTRL_GL2_ENABLE; + /* enable VL1 layer as default */ + ctrl = LCD_CTRL_ENABLE | LCD_CTRL_VL1_ENABLE; ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE | LCD_CTRL_OUTPUT_ENABLED; kmb_write(lcd, LCD_CONTROL, ctrl); @@ -175,17 +174,17 @@ static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = { int kmb_setup_crtc(struct drm_device *drm) { struct kmb_drm_private *lcd = to_kmb(drm); - struct drm_plane *primary; + struct kmb_plane *primary; int ret; primary = kmb_plane_init(drm); if (IS_ERR(primary)) return PTR_ERR(primary); - ret = drm_crtc_init_with_planes(drm, &lcd->crtc, primary, NULL, - &kmb_crtc_funcs, NULL); + ret = drm_crtc_init_with_planes(drm, &lcd->crtc, &primary->base_plane, + NULL, &kmb_crtc_funcs, NULL); if (ret) { - kmb_plane_destroy(primary); + kmb_plane_destroy(&primary->base_plane); return ret; } diff --git a/drivers/gpu/drm/kmb/kmb_crtc.h b/drivers/gpu/drm/kmb/kmb_crtc.h index d7cc441..6c3efdd 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.h +++ b/drivers/gpu/drm/kmb/kmb_crtc.h @@ -35,5 +35,5 @@ struct kmb_crtc_state { #define to_kmb_crtc_state(x) container_of(x, struct kmb_crtc_state, crtc_base) #define to_kmb_crtc(x) container_of(x, struct kmb_crtc, crtc_base) extern void kmb_plane_destroy(struct drm_plane *plane); -extern struct drm_plane *kmb_plane_init(struct drm_device *drm); +extern struct kmb_plane *kmb_plane_init(struct drm_device *drm); #endif /* __KMB_CRTC_H__ */ diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 90e1c86..23299a5 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -16,7 +16,7 @@ struct kmb_drm_private { struct clk *clk; struct drm_fbdev_cma *fbdev; struct drm_crtc crtc; - struct drm_plane *plane; + struct kmb_plane *plane; struct drm_atomic_state *state; }; diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 9d4c8dc..7077a4c 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -41,46 +41,69 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, dma_addr_t addr; unsigned int width; unsigned int height; - unsigned int i; unsigned int dma_len; - struct kmb_plane_state *kmb_state = to_kmb_plane_state(plane->state); + struct kmb_plane *kmb_plane = to_kmb_plane(plane); unsigned int dma_cfg; + unsigned int ctrl = 0; + unsigned char plane_id = kmb_plane->id; if (!fb) return; lcd = to_kmb(plane->dev); + switch (plane_id) { + case LAYER_0: + ctrl = LCD_CTRL_VL1_ENABLE; + break; + case LAYER_1: + ctrl = LCD_CTRL_VL2_ENABLE; + break; + case LAYER_2: + ctrl = LCD_CTRL_GL1_ENABLE; + break; + case LAYER_3: + ctrl = LCD_CTRL_GL2_ENABLE; + break; + } + + ctrl |= LCD_CTRL_ENABLE; + ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE + | LCD_CTRL_OUTPUT_ENABLED; + kmb_write(lcd, LCD_CONTROL, ctrl); + /* TBD */ /*set LCD_LAYERn_WIDTH, LCD_LAYERn_HEIGHT, LCD_LAYERn_COL_START, * LCD_LAYERn_ROW_START, LCD_LAYERn_CFG * CFG should set the pixel format, FIFO level and BPP */ + /*TBD check visible? */ + /* we may have to set LCD_DMA_VSTRIDE_ENABLE in the future */ dma_cfg = LCD_DMA_LAYE
[PATCH v2 26/59] drm/kmb: rebase to newer kernel version
cleanup code Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 5 +++-- drivers/gpu/drm/kmb/kmb_drv.h | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 71fdb94..78cb91b 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -282,8 +282,7 @@ DEFINE_DRM_GEM_CMA_FOPS(fops); static struct drm_driver kmb_driver = { .driver_features = DRIVER_GEM | - DRIVER_MODESET | - DRIVER_ATOMIC, + DRIVER_MODESET | DRIVER_ATOMIC, .irq_handler = kmb_isr, .irq_preinstall = kmb_irq_reset, .irq_uninstall = kmb_irq_reset, @@ -362,6 +361,8 @@ static int kmb_drm_bind(struct device *dev) if (ret) goto err_register; + drm_fbdev_generic_setup(drm, 32); + return 0; err_register: diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 586b53e..1150505 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -18,7 +18,6 @@ struct kmb_drm_private { void __iomem*msscam_mmio; unsigned char n_layers; struct clk *clk; - struct drm_fbdev_cma*fbdev; struct drm_crtc crtc; struct kmb_plane*plane; struct drm_atomic_state *state; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 57/59] drm/kmb: workaround for dma undeflow issue
Initial issue was that display remains shifted after undeflow, this fix is to recover the dma after underflow so display is clean. Major changes are reduce LCD_CLK to 200Mhz and some changes in the lcd timing params run recovery sequence at the EOF after underflow happens do nothing in plan_update() during recovery reenable dma at the vsync interrupt after recovery is done v2: renamed global vars, upclassed dev_private. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 27 +++ drivers/gpu/drm/kmb/kmb_drv.c | 154 +++- drivers/gpu/drm/kmb/kmb_drv.h | 33 + drivers/gpu/drm/kmb/kmb_plane.c | 12 +++- drivers/gpu/drm/kmb/kmb_plane.h | 29 drivers/gpu/drm/kmb/kmb_regs.h | 5 ++ 6 files changed, 185 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index aceca94..8308a9e1 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -96,25 +96,25 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) vm.vfront_porch = 2; // vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; vm.vback_porch = 2; -// vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; - vm.vsync_len = 1; +// vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; + vm.vsync_len = 8; //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; vm.hfront_porch = 0; vm.hback_porch = 0; //vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; - vm.hsync_len = 7; -// vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; + vm.hsync_len = 28; +// vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; - vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; - vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; + vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; + vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; - DRM_DEBUG - ("%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hysnc-l=%d", -__func__, __LINE__, m->crtc_vdisplay, vm.vback_porch, -vm.vfront_porch, vm.vsync_len, m->crtc_hdisplay, vm.hback_porch, -vm.hfront_porch, vm.hsync_len); + DRM_DEBUG("%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hysnc-l=%d", + __func__, __LINE__, + m->crtc_vdisplay, vm.vback_porch, vm.vfront_porch, + vm.vsync_len, m->crtc_hdisplay, vm.hback_porch, + vm.hfront_porch, vm.hsync_len); kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT, - m->crtc_vdisplay - 1); + m->crtc_vdisplay - 1); kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch); kmb_write_lcd(dev_p, LCD_V_FRONTPORCH, vm.vfront_porch); kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH, vm.vsync_len - 1); @@ -126,7 +126,8 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) /*this is hardcoded as 0 in the Myriadx code */ kmb_write_lcd(dev_p, LCD_VSYNC_START, 0); kmb_write_lcd(dev_p, LCD_VSYNC_END, 0); - + /* back ground color */ + kmb_write_lcd(dev_p, LCD_BG_COLOUR_LS, 0x4); if (m->flags == DRM_MODE_FLAG_INTERLACE) { kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index b844c77..559742b8 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -31,10 +31,10 @@ #include "kmb_regs.h" //#define DEBUG - /* IRQ handler */ static irqreturn_t kmb_isr(int irq, void *arg); +int kmb_under_flow = 0, kmb_flush_done = 0, layer_no = 0; static struct clk *clk_lcd; static struct clk *clk_mipi; static struct clk *clk_mipi_ecfg; @@ -111,6 +111,7 @@ static void __iomem *kmb_map_mmio(struct platform_device *pdev, char *name) return mem; } +//#define ICAM_LCD_QOS static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); @@ -118,6 +119,9 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) int irq_lcd; int ret = 0; unsigned long clk; +#ifdef ICAM_LCD_QOS + int val = 0; +#endif /* Map MIPI MMIO registers */ dev_p->mipi_mmio = kmb_map_mmio(pdev, "mipi_regs"); @@ -151,6 +155,13 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) iounmap(dev_p->mipi_mmio); return -ENOMEM; } +#ifdef ICAM_LCD_QOS + dev_p->icamlcd_mmio = ioremap_nocache(ICAM_MMIO, ICAM_MMIO_SIZE); + if (IS_ERR(dev_p->icamlcd_mmio)) { + DRM_ERROR("failed to map ICAM registers\n"); + return -ENOMEM; +
[PATCH v2 21/59] drm/kmb: IRQ handlers for LCD and mipi dsi
Added handlers for lcd and mipi, it only finds and clears the interrupt as of now, more functionality can be added as needed. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 55 +++--- drivers/gpu/drm/kmb/kmb_drv.h | 2 ++ drivers/gpu/drm/kmb/kmb_dsi.c | 37 ++-- drivers/gpu/drm/kmb/kmb_dsi.h | 1 + drivers/gpu/drm/kmb/kmb_regs.h | 35 --- 5 files changed, 110 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 594e64c..f4553c2 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -38,7 +38,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) struct platform_device *pdev = to_platform_device(drm->dev); /*struct resource *res;*/ /*u32 version;*/ - /*int irq_lcd, irq_mipi; */ + int irq_lcd, irq_mipi; int ret; /* TBD - not sure if clock_get needs to be called here */ @@ -89,11 +89,29 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) dev_p->msscam_mmio = ioremap_cache(MSS_CAM_BASE_ADDR, MSS_CAM_MMIO_SIZE); - /*TODO - register irqs here - section 17.3 in databook -* lists LCD at 79 under MSS CPU - firmware has to redirect it to A53 -* May be 33 for LCD and 34 for MIPI? Will wait till firmware -* finalizes the IRQ numbers for redirection + /* register irqs here - section 17.3 in databook +* lists LCD at 79 and 82 for MIPI under MSS CPU - +* firmware has to redirect it to A53 */ + irq_lcd = platform_get_irq_byname(pdev, "irq_lcd"); + if (irq_lcd < 0) { + DRM_ERROR("irq_lcd not found"); + return irq_lcd; + } + pr_info("irq_lcd platform_get_irq = %d\n", irq_lcd); + ret = request_irq(irq_lcd, kmb_isr, IRQF_SHARED, "irq_lcd", dev_p); + dev_p->irq_lcd = irq_lcd; + + irq_mipi = platform_get_irq_byname(pdev, "irq_mipi"); + if (irq_mipi < 0) { + DRM_ERROR("irq_mipi not found"); + return irq_mipi; + } + pr_info("irq_mipi platform_get_irq = %d\n", irq_mipi); + ret = request_irq(irq_mipi, kmb_isr, IRQF_SHARED, "irq_mipi", dev_p); + dev_p->irq_mipi = irq_mipi; + + /*TBD read and check for correct product version here */ @@ -142,9 +160,9 @@ static void kmb_setup_mode_config(struct drm_device *drm) drm->mode_config.funcs = &kmb_mode_config_funcs; } -static irqreturn_t kmb_isr(int irq, void *arg) + +static irqreturn_t handle_lcd_irq(struct drm_device *dev) { - struct drm_device *dev = (struct drm_device *)arg; unsigned long status, val; struct kmb_drm_private *dev_p = to_kmb(dev); @@ -174,14 +192,33 @@ static irqreturn_t kmb_isr(int irq, void *arg) break; } } + return IRQ_HANDLED; +} +static irqreturn_t handle_mipi_irq(struct drm_device *dev) +{ + mipi_tx_handle_irqs(to_kmb(dev)); return IRQ_HANDLED; } +static irqreturn_t kmb_isr(int irq, void *arg) +{ + struct drm_device *dev = (struct drm_device *)arg; + struct kmb_drm_private *dev_p = to_kmb(dev); + irqreturn_t ret = IRQ_NONE; + + if (irq == dev_p->irq_lcd) + ret = handle_lcd_irq(dev); + else if (irq == dev_p->irq_mipi) + ret = handle_mipi_irq(dev); + + return ret; +} + static void kmb_irq_reset(struct drm_device *drm) { - kmb_write_lcd(drm->dev_private, LCD_INT_CLEAR, 0x); - kmb_write_lcd(drm->dev_private, LCD_INT_ENABLE, 0); + kmb_write_lcd(to_kmb(drm), LCD_INT_CLEAR, 0x); + kmb_write_lcd(to_kmb(drm), LCD_INT_ENABLE, 0); } DEFINE_DRM_GEM_CMA_FOPS(fops); diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index a56d548..1e81d44 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -23,6 +23,8 @@ struct kmb_drm_private { struct kmb_plane*plane; struct drm_atomic_state *state; spinlock_t irq_lock; + int irq_lcd; + int irq_mipi; }; static inline struct kmb_drm_private *to_kmb(const struct drm_device *dev) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 94c9adc..969890b 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -1214,7 +1214,7 @@ static void mipi_tx_init_irqs(struct kmb_drm_private *dev_p, SET_MIPI_TX_HS_IRQ_CLEAR(dev_p, MIPI_CTRL6, MIPI_TX_HS_IRQ_ALL); /*global interrupts */ SET_MIPI_CTRL_IRQ_CLEAR0(dev_p, MIPI_CTRL6, MIPI_HS_IRQ); - SET_MIPI_CTRL_IRQ_CLEAR0(dev_p, MIPI_CTRL6, MIPI_DHY_ERR_IRQ); + SET_MIPI_CT
[PATCH v2 37/59] drm/kmb: Set MSS_CAM_RSTN_CTRL along with enable
Also moved num_planes init before load, time out for dsi fixed kmb regs read/write to only pass dev_p and few other minor changes. Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 32 ++-- drivers/gpu/drm/kmb/kmb_drv.h | 34 +- drivers/gpu/drm/kmb/kmb_dsi.c | 37 - drivers/gpu/drm/kmb/kmb_plane.c | 27 +-- drivers/gpu/drm/kmb/kmb_regs.h | 1 + 5 files changed, 77 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 861aa97..64db9a1 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -58,11 +58,12 @@ static int kmb_display_clk_enable(void) return ret; } - ret = clk_prepare_enable(clk_msscam); +/* ret = clk_prepare_enable(clk_msscam); if (ret) { DRM_ERROR("Failed to enable MSSCAM clock: %d\n", ret); return ret; } + */ ret = clk_prepare_enable(clk_mipi_ecfg); if (ret) { @@ -116,6 +117,8 @@ static void __iomem *kmb_map_mmio(struct platform_device *pdev, char *name) release_mem_region(res->start, size); return ERR_PTR(-ENOMEM); } + DRM_INFO("%s : %d mapped %s mmio size = %d\n", __func__, __LINE__, + name, size); return mem; } @@ -130,13 +133,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) int ret = 0; unsigned long clk; - /* Map LCD MMIO registers */ - dev_p->lcd_mmio = kmb_map_mmio(pdev, "lcd_regs"); - if (IS_ERR(dev_p->lcd_mmio)) { - DRM_ERROR("failed to map LCD registers\n"); - return -ENOMEM; - } - /* Map MIPI MMIO registers */ dev_p->mipi_mmio = kmb_map_mmio(pdev, "mipi_regs"); if (IS_ERR(dev_p->mipi_mmio)) { @@ -145,6 +141,13 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) return -ENOMEM; } + /* Map LCD MMIO registers */ + dev_p->lcd_mmio = kmb_map_mmio(pdev, "lcd_regs"); + if (IS_ERR(dev_p->lcd_mmio)) { + DRM_ERROR("failed to map LCD registers\n"); + return -ENOMEM; + } + /* This is only for MIPI_TX_MSS_LCD_MIPI_CFG and MSS_CAM_CLK_CTRL * register */ @@ -169,12 +172,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } - clk_msscam = clk_get(&pdev->dev, "clk_msscam"); - if (IS_ERR(clk_msscam)) { - DRM_ERROR("clk_get() failed clk_msscam\n"); - goto setup_fail; - } - clk_mipi_ecfg = clk_get(&pdev->dev, "clk_mipi_ecfg"); if (IS_ERR(clk_mipi_ecfg)) { DRM_ERROR("clk_get() failed clk_mipi_ecfg\n"); @@ -195,7 +192,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) if (clk_get_rate(clk_lcd) != KMB_LCD_DEFAULT_CLK) { DRM_ERROR("failed to set to clk_lcd to %d\n", KMB_LCD_DEFAULT_CLK); - goto setup_fail; } DRM_INFO("Setting LCD clock to %d Mhz ret = %d\n", KMB_LCD_DEFAULT_CLK/100, ret); @@ -245,8 +241,8 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) } /* enable MSS_CAM_CLK_CTRL for MIPI TX and LCD */ - kmb_set_bitmask_msscam(dev_p, MSS_CAM_CLK_CTRL, LCD | MIPI_COMMON | - MIPI_TX0); + kmb_set_bitmask_msscam(dev_p, MSS_CAM_CLK_CTRL, 0xfff); + kmb_set_bitmask_msscam(dev_p, MSS_CAM_RSTN_CTRL, 0xfff); #ifdef WIP /* Register irqs here - section 17.3 in databook * lists LCD at 79 and 82 for MIPI under MSS CPU - @@ -514,6 +510,7 @@ static int kmb_probe(struct platform_device *pdev) dev_set_drvdata(dev, drm); /* Load driver */ + lcd->n_layers = KMB_MAX_PLANES; ret = kmb_load(drm, 0); if (ret == -EPROBE_DEFER) { DRM_INFO("wait for external bridge driver DT\n"); @@ -536,7 +533,6 @@ static int kmb_probe(struct platform_device *pdev) /* Register graphics device with the kernel */ ret = drm_dev_register(drm, 0); - lcd->n_layers = KMB_MAX_PLANES; if (ret) goto err_register; diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 71dc883..f3f2c34 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -8,9 +8,9 @@ #include "kmb_regs.h" -#define KMB_MAX_WIDTH 16384 /*max width in pixels */ -#define KMB_MAX_HEIGHT 16384 /*max height in pixels */ -#define KMB_LCD_DEFAULT_CLK2 +#define KMB_MAX_WIDTH 1920 /*max width in pixels */ +#define KMB_MAX_HEIGHT 108
[PATCH v2 38/59] drm/kmb: Mipi DPHY initialization changes
Fix test_mode_send and dphy_wait_fsm for 2-lane MIPI - Fix test_mode_send when sending normal mode test codes - Change dphy_wait_fsm to check for IDLE status rather than LOCK status for 2-lane MIPI v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus Signed-off-by: Edmund Dea --- drivers/gpu/drm/kmb/kmb_crtc.c | 23 +- drivers/gpu/drm/kmb/kmb_drv.c | 90 ++-- drivers/gpu/drm/kmb/kmb_drv.h | 23 +- drivers/gpu/drm/kmb/kmb_dsi.c | 904 +--- drivers/gpu/drm/kmb/kmb_dsi.h | 2 +- drivers/gpu/drm/kmb/kmb_plane.c | 57 ++- drivers/gpu/drm/kmb/kmb_regs.h | 34 +- 7 files changed, 838 insertions(+), 295 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index eca0f3a..21b2d7f 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -20,6 +20,7 @@ #include "kmb_drv.h" #include "kmb_plane.h" #include "kmb_regs.h" +#include "kmb_dsi.h" static void kmb_crtc_cleanup(struct drm_crtc *crtc) { @@ -74,24 +75,34 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = { static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct drm_display_mode *m = &crtc->state->adjusted_mode; struct drm_device *dev = crtc->dev; +#ifdef LCD_TEST + struct drm_display_mode *m = &crtc->state->adjusted_mode; struct videomode vm; int vsync_start_offset; int vsync_end_offset; unsigned int ctrl = 0; struct kmb_drm_private *dev_p = to_kmb(dev); - +#endif + /* initialize mipi */ + kmb_dsi_hw_init(dev); +#ifdef LCD_TEST vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; - vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; + //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; + vm.hfront_porch = 0; vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; + DRM_INFO("%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hysnc-l=%d\n", + __func__, __LINE__, m->crtc_vdisplay, + vm.vback_porch, vm.vfront_porch, + vm.vsync_len, m->crtc_hdisplay, + vm.hback_porch, vm.hfront_porch, vm.hsync_len); kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT, m->crtc_vdisplay - 1); kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch - 1); @@ -126,7 +137,7 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_CONTROL, ctrl); kmb_write_lcd(dev_p, LCD_TIMING_GEN_TRIG, ENABLE); - +#endif /* TBD */ /* set clocks here */ } @@ -138,7 +149,7 @@ static void kmb_crtc_atomic_enable(struct drm_crtc *crtc, clk_prepare_enable(lcd->clk); kmb_crtc_mode_set_nofb(crtc); - drm_crtc_vblank_on(crtc); +// drm_crtc_vblank_on(crtc); } static void kmb_crtc_atomic_disable(struct drm_crtc *crtc, @@ -149,7 +160,7 @@ static void kmb_crtc_atomic_disable(struct drm_crtc *crtc, /* always disable planes on the CRTC that is being turned off */ drm_atomic_helper_disable_planes_on_crtc(old_state, false); - drm_crtc_vblank_off(crtc); +// drm_crtc_vblank_off(crtc); clk_disable_unprepare(lcd->clk); } diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 64db9a1..2a93b13 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -37,27 +38,27 @@ static irqreturn_t kmb_isr(int irq, void *arg); static struct clk *clk_lcd; static struct clk *clk_mipi; static struct clk *clk_msscam; +static struct clk *clk_pll0out0; static struct clk *clk_mipi_ecfg; static struct clk *clk_mipi_cfg; struct drm_bridge *adv_bridge; -static int kmb_display_clk_enable(void) +int kmb_display_clk_enable(void) { int ret = 0; - +#ifdef LCD_TEST ret = clk_prepare_enable(clk_lcd); if (ret) { DRM_ERROR("Failed to enable LCD clock: %d\n", ret); return ret; } - +#endif ret = clk_prepare_enable(clk_mipi); if (ret) { DRM_ERROR("Failed to enable MIPI clock: %d\n", ret); return ret; } - /* ret = clk_prepare_enable(clk_msscam); if (ret) { DRM_ERROR("Failed to enable MSSCAM clock: %d\n", ret); @@ -158,19 +159,47 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) iounmap(dev_p->mipi_mmio); return -ENOMEM; } +/*test
[PATCH v2 24/59] drm/kmb: Add ADV7535 bridge
Find ADV 7535 from the device tree and get the bridge driver and attach it to the DRM and the MIPI encoder. v2: check for valid encoder node Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 27 ++- drivers/gpu/drm/kmb/kmb_dsi.c | 26 +- drivers/gpu/drm/kmb/kmb_dsi.h | 3 ++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index f4553c2..5a2ff9d 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -36,10 +36,12 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); + struct drm_bridge *bridge; /*struct resource *res;*/ /*u32 version;*/ int irq_lcd, irq_mipi; int ret; + struct device_node *encoder_node; /* TBD - not sure if clock_get needs to be called here */ /* @@ -127,7 +129,30 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } - kmb_dsi_init(drm); + /* find ADV7535 node and initialize it */ + encoder_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0); + if (!encoder_node) { + DRM_ERROR("failed to get bridge info from DT\n"); + ret = -EPROBE_DEFER; + goto setup_fail; + } + + /* Locate drm bridge from the hdmi encoder DT node */ + bridge = of_drm_find_bridge(encoder_node); + if (!bridge) { + DRM_ERROR("failed to get bridge driver from DT\n"); + ret = -EPROBE_DEFER; + goto setup_fail; + } + + of_node_put(encoder_node); + + ret = kmb_dsi_init(drm, bridge); + if (ret) { + DRM_ERROR("failed to initialize DSI\n"); + goto setup_fail; + } + ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); if (ret < 0) { DRM_ERROR("failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 969890b..09d5805 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1240,7 +1241,6 @@ static void mipi_tx_init_irqs(struct kmb_drm_private *dev_p, spin_unlock_irqrestore(&dev_p->irq_lock, irqflags); } - void mipi_tx_handle_irqs(struct kmb_drm_private *dev_p) { uint32_t irq_ctrl_stat_0, hs_stat, hs_enable; @@ -1273,7 +1273,7 @@ void mipi_tx_handle_irqs(struct kmb_drm_private *dev_p) } -void kmb_dsi_init(struct drm_device *dev) +int kmb_dsi_init(struct drm_device *dev, struct drm_bridge *bridge) { struct kmb_dsi *kmb_dsi; struct drm_encoder *encoder; @@ -1281,21 +1281,27 @@ void kmb_dsi_init(struct drm_device *dev) struct drm_connector *connector; struct kmb_dsi_host *host; struct kmb_drm_private *dev_p = dev->dev_private; + int ret = 0; kmb_dsi = kzalloc(sizeof(*kmb_dsi), GFP_KERNEL); - if (!kmb_dsi) - return; + if (!kmb_dsi) { + DRM_ERROR("failed to allocate kmb_dsi\n"); + return -ENOMEM; + } kmb_connector = kzalloc(sizeof(*kmb_connector), GFP_KERNEL); if (!kmb_connector) { kfree(kmb_dsi); - return; + DRM_ERROR("failed to allocate kmb_connector\n"); + return -ENOMEM; } kmb_dsi->attached_connector = kmb_connector; connector = &kmb_connector->base; encoder = &kmb_dsi->base; + encoder->possible_crtcs = 1; + encoder->possible_clones = 0; drm_encoder_init(dev, encoder, &kmb_dsi_funcs, DRM_MODE_ENCODER_DSI, "MIPI-DSI"); @@ -1313,6 +1319,14 @@ void kmb_dsi_init(struct drm_device *dev) connector->encoder = encoder; drm_connector_attach_encoder(connector, encoder); + /* Link drm_bridge to encoder */ + ret = drm_bridge_attach(encoder, bridge, NULL, 0); + if (ret) { + DRM_ERROR("failed to attach bridge to MIPI\n"); + drm_encoder_cleanup(encoder); + return ret; + } + /* initialize mipi controller */ mipi_tx_init_cntrl(dev_p, &mipi_tx_init_cfg); @@ -1321,4 +1335,6 @@ void kmb_dsi_init(struct drm_device *dev) /* irq initialization */ mipi_tx_init_irqs(dev_p, &int_cfg, &mipi_tx_init_cfg.tx_ctrl_cfg); + + return 0; } diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index f7e2f9e..702ad58 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -18,6 +18,7 @@ struct kmb_dsi { struct drm_encoder base;
[PATCH v2 45/59] drm/kmb: Enable LCD interrupts
Enabled vblank interrupts for LCD. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 36 +++- drivers/gpu/drm/kmb/kmb_drv.c | 41 + drivers/gpu/drm/kmb/kmb_plane.c | 6 +++--- drivers/gpu/drm/kmb/kmb_regs.h | 2 +- 4 files changed, 40 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 1987185e..589a841 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -41,7 +41,8 @@ static int kmb_crtc_enable_vblank(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_VSTATUS_COMPARE, LCD_VSTATUS_COMPARE_VSYNC); /* enable vertical interrupt */ - kmb_write_lcd(dev_p, LCD_INT_ENABLE, LCD_INT_VERT_COMP); + kmb_set_bitmask_lcd(dev_p, LCD_INT_ENABLE, + LCD_INT_VERT_COMP); return 0; } @@ -53,13 +54,8 @@ static void kmb_crtc_disable_vblank(struct drm_crtc *crtc) /*clear interrupt */ kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_VERT_COMP); /* disable vertical interrupt */ - kmb_write_lcd(dev_p, LCD_INT_ENABLE, 0); - -/* TBD - * set the BIT2 (VERTICAL_COMPARE_INTERRUPT) of the LCD_INT_ENABLE register - * set the required bit LCD_VSTATUS_COMPARE register - * Not sure if anything needs to be done in the ICB - */ + kmb_clr_bitmask_lcd(dev_p, LCD_INT_ENABLE, + LCD_INT_VERT_COMP); } static const struct drm_crtc_funcs kmb_crtc_funcs = { @@ -82,7 +78,7 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) int vsync_start_offset; int vsync_end_offset; struct kmb_drm_private *dev_p = to_kmb(dev); -#endif + /* initialize mipi */ kmb_dsi_hw_init(dev, m); DRM_INFO("vfp= %d vbp= %d vsyc_len=%d hfp=%d hbp=%d hsync_len=%d\n", @@ -92,7 +88,6 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) m->crtc_hsync_start - m->crtc_hdisplay, m->crtc_htotal - m->crtc_hsync_end, m->crtc_hsync_end - m->crtc_hsync_start); -#ifdef LCD_TEST // vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vfront_porch = 2; // vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; @@ -156,7 +151,7 @@ static void kmb_crtc_atomic_enable(struct drm_crtc *crtc, clk_prepare_enable(lcd->clk); kmb_crtc_mode_set_nofb(crtc); -// drm_crtc_vblank_on(crtc); + drm_crtc_vblank_on(crtc); } static void kmb_crtc_atomic_disable(struct drm_crtc *crtc, @@ -167,33 +162,32 @@ static void kmb_crtc_atomic_disable(struct drm_crtc *crtc, /* always disable planes on the CRTC that is being turned off */ drm_atomic_helper_disable_planes_on_crtc(old_state, false); -// drm_crtc_vblank_off(crtc); + drm_crtc_vblank_off(crtc); clk_disable_unprepare(lcd->clk); } static void kmb_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *state) { - /* TBD */ - /*disable vblank interrupts here -* clear BIT 2 (VERTICAL_COMPARE_INTERRUPT) LCD_INT_ENABLE -*/ + struct drm_device *dev = crtc->dev; + + kmb_clr_bitmask_lcd(dev->dev_private, LCD_INT_ENABLE, + LCD_INT_VERT_COMP); } static void kmb_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *state) { - /* TBD */ - /*enable vblank interrupts after -* set BIT 2 (VERTICAL_COMPARE_INTERRUPT) LCD_INT_ENABLE -*/ + struct drm_device *dev = crtc->dev; + + kmb_set_bitmask_lcd(dev->dev_private, LCD_INT_ENABLE, + LCD_INT_VERT_COMP); spin_lock_irq(&crtc->dev->event_lock); if (crtc->state->event) drm_crtc_send_vblank_event(crtc, crtc->state->event); crtc->state->event = NULL; spin_unlock_irq(&crtc->dev->event_lock); - } static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index bbf3e649..e6aa32c 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -127,10 +127,8 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); -#ifdef WIP /*u32 version;*/ - int irq_lcd, irq_mipi; -#endif + int irq_lcd;// irq_mipi; int ret = 0; unsigned long clk; @@ -266,10 +264,9 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) kmb_set_bitmask_msscam(dev_p, MSS_CAM_CLK_CTRL, 0x1fff); kmb_set_bitmask_msscam(dev_p, MSS_CAM_RSTN_CTRL, 0x); #endif //KMB_CLOCKS -#ifdef WIP /* Register
[PATCH v2 27/59] drm/kmb: minor name change to match device tree
name change Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 78cb91b..4afdb9c 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -459,7 +459,7 @@ static int kmb_remove(struct platform_device *pdev) } static const struct of_device_id kmb_of_match[] = { - {.compatible = "kmb,display"}, + {.compatible = "intel,kmb_display"}, {}, }; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 05/59] drm/kmb: Updated kmb_plane_atomic_check
Check if format is supported and size is within limits. v2: simplified the code as per code review Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 111 +++- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 877314a..74a3573 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -21,15 +21,66 @@ #include "kmb_plane.h" #include "kmb_regs.h" +/* graphics layer ( layers 2 & 3) formats, only packed formats are supported*/ +static const u32 kmb_formats_g[] = { + DRM_FORMAT_RGB332, + DRM_FORMAT_XRGB, DRM_FORMAT_XBGR, + DRM_FORMAT_ARGB, DRM_FORMAT_ABGR, + DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, + DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, + DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, + DRM_FORMAT_XRGB, DRM_FORMAT_XBGR, + DRM_FORMAT_ARGB, DRM_FORMAT_ABGR, +}; + +#define MAX_FORMAT_G (ARRAY_SIZE(kmb_formats_g)) +#define MAX_FORMAT_V (ARRAY_SIZE(kmb_formats_v)) + +/* video layer ( 0 & 1) formats, packed and planar formats are supported */ +static const u32 kmb_formats_v[] = { + /* packed formats */ + DRM_FORMAT_RGB332, + DRM_FORMAT_XRGB, DRM_FORMAT_XBGR, + DRM_FORMAT_ARGB, DRM_FORMAT_ABGR, + DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, + DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, + DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, + DRM_FORMAT_XRGB, DRM_FORMAT_XBGR, + DRM_FORMAT_ARGB, DRM_FORMAT_ABGR, + /*planar formats */ + DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, + DRM_FORMAT_YUV422, DRM_FORMAT_YVU422, + DRM_FORMAT_YUV444, DRM_FORMAT_YVU444, + DRM_FORMAT_NV12, DRM_FORMAT_NV21, +}; + +static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) +{ + int i; + + for (i = 0; i < plane->format_count; i++) { + if (plane->format_types[i] == format) + return 0; + } + return -EINVAL; +} + static int kmb_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { -/* TBD below structure will be used for implementation later - * struct drm_crtc_state *crtc_state; - */ - /* TBD */ - /* Plane based checking */ + struct drm_framebuffer *fb; + int ret; + + fb = state->fb; + ret = check_pixel_format(plane, fb->format->format); + if (ret) + return ret; + + if (state->crtc_w > KMB_MAX_WIDTH || state->crtc_h > KMB_MAX_HEIGHT) + return -EINVAL; return 0; } @@ -38,36 +89,36 @@ unsigned int set_pixel_format(u32 format) unsigned int val = 0; switch (format) { - /*planar formats */ + /*planar formats */ case DRM_FORMAT_YUV444: val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE; break; case DRM_FORMAT_YVU444: val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE - | LCD_LAYER_CRCB_ORDER; + | LCD_LAYER_CRCB_ORDER; break; case DRM_FORMAT_YUV422: val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE; break; case DRM_FORMAT_YVU422: val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE - | LCD_LAYER_CRCB_ORDER; + | LCD_LAYER_CRCB_ORDER; break; case DRM_FORMAT_YUV420: val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE; break; case DRM_FORMAT_YVU420: val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE - | LCD_LAYER_CRCB_ORDER; + | LCD_LAYER_CRCB_ORDER; break; case DRM_FORMAT_NV12: val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE; break; case DRM_FORMAT_NV21: val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE - | LCD_LAYER_CRCB_ORDER; + | LCD_LAYER_CRCB_ORDER; break; - /* packed formats */ + /* packed formats */ case DRM_FORMAT_RGB332: val = LCD_LAYER_FORMAT_RGB332; break; @@ -127,7 +178,7 @@ unsigned int set_bits_per_pixel(const struct drm_format_info *format) unsigned int val = 0; for (i = 0; i < format->num_planes; i++) - bpp += 8*format->cpp[i]; + bpp += 8 * format->cpp[i]; switch (bpp) { case 8: @@ -171,8 +222,8 @@ static void kmb_plane_atomic_update(struct
[PATCH v2 17/59] drm/kmb: Part7 of Mipi Tx Initialization
This completes the DPHY initialization and Tx initialization. v2: minor code review changes Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 65 ++ drivers/gpu/drm/kmb/kmb_dsi.h | 18 drivers/gpu/drm/kmb/kmb_regs.h | 15 -- 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 02555c6..f8ddb87 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -28,6 +28,7 @@ #define MIPI_TX_CFG_CLK_KHZ 24000 /*DPHY Tx test codes*/ +#define TEST_CODE_FSM_CONTROL 0x03 #define TEST_CODE_PLL_PROPORTIONAL_CHARGE_PUMP_CTRL0x0E #define TEST_CODE_PLL_INTEGRAL_CHARGE_PUMP_CTRL0x0F #define TEST_CODE_PLL_VCO_CTRL 0x12 @@ -1061,10 +1062,10 @@ static void dphy_init_sequence(struct mipi_ctrl_cfg *cfg, u32 dphy_no, cfg->lane_rate_mbps/2); /*Set clksel */ - kmb_write_bits_mipi(DPHY_INIT_CTRL1, 18, 2, 0x01); + kmb_write_bits_mipi(DPHY_INIT_CTRL1, PLL_CLKSEL_0, 2, 0x01); /*Set pll_shadow_control */ - kmb_write_bits_mipi(DPHY_INIT_CTRL1, 16, 1, 0x01); + kmb_set_bit_mipi(DPHY_INIT_CTRL1, PLL_SHADOW_CTRL); } /*Send NORMAL OPERATION test code */ @@ -1087,7 +1088,48 @@ static void dphy_init_sequence(struct mipi_ctrl_cfg *cfg, u32 dphy_no, /* enable DATA LANES */ kmb_write_bits_mipi(DPHY_ENABLE, dphy_no * 2, 2, - ((1 << cfg->active_lanes) - 1)); + ((1 << cfg->active_lanes) - 1)); + + /*Take D-PHY out of shutdown mode */ + /* deassert SHUTDOWNZ signal*/ + SET_DPHY_INIT_CTRL0(dphy_no, SHUTDOWNZ); + /*deassert RSTZ signal */ + SET_DPHY_INIT_CTRL0(dphy_no, RESETZ); +} + +static void dphy_wait_fsm(u32 dphy_no, enum dphy_tx_fsm fsm_state) +{ + enum dphy_tx_fsm val = DPHY_TX_POWERDWN; + + do { + test_mode_send(dphy_no, TEST_CODE_FSM_CONTROL, 0x80); + /*TODO-need to add a time out and return failure */ + val = GET_TEST_DOUT0_3(dphy_no); + } while (val != fsm_state); + +} + +static u32 wait_init_done(u32 dphy_no, u32 active_lanes) +{ + u32 stopstatedata = 0; + u32 data_lanes = (1 << active_lanes) - 1; + + do { + stopstatedata = GET_STOPSTATE_DATA(dphy_no); + /*TODO-need to add a time out and return failure */ + } while (stopstatedata != data_lanes); + + return 0; +} + +static u32 wait_pll_lock(u32 dphy_no) +{ + do { + ; + /*TODO-need to add a time out and return failure */ + } while (!GET_PLL_LOCK(dphy_no)); + + return 0; } static u32 mipi_tx_init_dphy(struct mipi_ctrl_cfg *cfg) @@ -1113,9 +1155,22 @@ static u32 mipi_tx_init_dphy(struct mipi_ctrl_cfg *cfg) */ /*PHY #N+1 ('slave') */ dphy_init_sequence(cfg, dphy_no + 1, MIPI_DPHY_SLAVE); - /*TODO PHY #N master */ + + dphy_wait_fsm(dphy_no + 1, DPHY_TX_LOCK); + + /*PHY #N master*/ + dphy_init_sequence(cfg, dphy_no, MIPI_DPHY_MASTER); + /* wait for DPHY init to complete */ + wait_init_done(dphy_no, MIPI_DPHY_D_LANES); + wait_init_done(dphy_no + 1, + cfg->active_lanes - MIPI_DPHY_D_LANES); + wait_pll_lock(dphy_no); + wait_pll_lock(dphy_no + 1); + } else {/* Single DPHY */ + dphy_init_sequence(cfg, dphy_no, MIPI_DPHY_MASTER); + wait_init_done(dphy_no, cfg->active_lanes); + wait_pll_lock(dphy_no); } - /*TODO- Single DPHY */ return 0; } diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index deaee3e..7db7f58 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -184,12 +184,30 @@ enum dphy_mode { MIPI_DPHY_MASTER }; +enum dphy_tx_fsm { + DPHY_TX_POWERDWN = 0, + DPHY_TX_BGPON, + DPHY_TX_TERMCAL, + DPHY_TX_TERMCALUP, + DPHY_TX_OFFSETCAL, + DPHY_TX_LOCK, + DPHY_TX_SRCAL, + DPHY_TX_IDLE, + DPHY_TX_ULP, + DPHY_TX_LANESTART, + DPHY_TX_CLKALIGN, + DPHY_TX_DDLTUNNING, + DPHY_TX_ULP_FORCE_PLL, + DPHY_TX_LOCK_LOSS +}; + struct mipi_data_type_params { uint8_t size_constraint_pixels; uint8_t size_constraint_bytes; uint8_t pixels_per_pclk; uint8_t bits_per_pclk; }; + struct mipi_tx_dsi_cfg { uint8_t hfp_blank_en; /*horizontal front porch blanking enable */ uint8_t eotp_en;/*End of transmission packet enable */ diff --git a/drivers/gpu/drm/k
[PATCH v2 23/59] drm/kmb: Additional register programming to update_plane
These changes are ported from Myriadx which has additional registers updated for planes. This change does the following reinitialize plane interrupts program Cb/Cr for planar formats set LCD_CTRL_VHSYNC_IDLE_LVL set output format and configure csc v2: code review changes v3: corrected spelling Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.h | 16 drivers/gpu/drm/kmb/kmb_plane.c | 183 drivers/gpu/drm/kmb/kmb_regs.h | 72 ++-- 3 files changed, 210 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 1e81d44..586b53e 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -92,6 +92,22 @@ static inline u32 kmb_read_lcd(struct kmb_drm_private *dev_p, unsigned int reg) return readl(dev_p->lcd_mmio + reg); } +static inline void kmb_set_bitmask_lcd(struct kmb_drm_private *dev_p, + unsigned int reg, u32 mask) +{ + u32 reg_val = kmb_read_lcd(dev_p->lcd_mmio, reg); + + kmb_write_lcd(dev_p->lcd_mmio, reg, (reg_val | mask)); +} + +static inline void kmb_clr_bitmask_lcd(struct kmb_drm_private *dev_p, + unsigned int reg, u32 mask) +{ + u32 reg_val = kmb_read_lcd(dev_p->lcd_mmio, reg); + + kmb_write_lcd(dev_p->lcd_mmio, reg, (reg_val & (~mask))); +} + static inline u32 kmb_read_mipi(struct kmb_drm_private *dev_p, unsigned int reg) { return readl(dev_p->mipi_mmio + reg); diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 946349a..2980764 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -56,6 +56,46 @@ static const u32 kmb_formats_v[] = { DRM_FORMAT_NV12, DRM_FORMAT_NV21, }; +#define LCD_INT_VL0_ERR (LAYER0_DMA_FIFO_UNDERFLOW | \ + LAYER0_DMA_FIFO_OVERFLOW | \ + LAYER0_DMA_CB_FIFO_OVERFLOW | \ + LAYER0_DMA_CB_FIFO_UNDERFLOW | \ + LAYER0_DMA_CR_FIFO_OVERFLOW | \ + LAYER0_DMA_CR_FIFO_UNDERFLOW) + +#define LCD_INT_VL1_ERR (LAYER1_DMA_FIFO_UNDERFLOW | \ + LAYER1_DMA_FIFO_OVERFLOW | \ + LAYER1_DMA_CB_FIFO_OVERFLOW | \ + LAYER1_DMA_CB_FIFO_UNDERFLOW | \ + LAYER1_DMA_CR_FIFO_OVERFLOW | \ + LAYER1_DMA_CR_FIFO_UNDERFLOW) + +#define LCD_INT_GL0_ERR (LAYER2_DMA_FIFO_OVERFLOW | LAYER2_DMA_FIFO_UNDERFLOW) + +#define LCD_INT_GL1_ERR (LAYER3_DMA_FIFO_OVERFLOW | LAYER3_DMA_FIFO_UNDERFLOW) + +#define LCD_INT_VL0 (LAYER0_DMA_DONE | LAYER0_DMA_IDLE | LCD_INT_VL0_ERR) + +#define LCD_INT_VL1 (LAYER1_DMA_DONE | LAYER1_DMA_IDLE | LCD_INT_VL1_ERR) + +#define LCD_INT_GL0 (LAYER2_DMA_DONE | LAYER2_DMA_IDLE | LCD_INT_GL0_ERR) + +#define LCD_INT_GL1 (LAYER3_DMA_DONE | LAYER3_DMA_IDLE | LCD_INT_GL1_ERR) + +const uint32_t layer_irqs[] = { + LCD_INT_VL0, + LCD_INT_VL1, + LCD_INT_GL0, + LCD_INT_GL1 + }; +/*Conversion (yuv->rgb) matrix from myriadx */ +static const u32 csc_coef_lcd[] = { + 1024, 0, 1436, + 1024, -352, -731, + 1024, 1814, 0, + -179, 125, -226 +}; + static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) { int i; @@ -197,6 +237,24 @@ unsigned int set_bits_per_pixel(const struct drm_format_info *format) return val; } +static void config_csc(struct kmb_drm_private *dev_p, int plane_id) +{ + /*YUV to RGB conversion using the fixed matrix csc_coef_lcd */ + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF11(plane_id), csc_coef_lcd[0]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF12(plane_id), csc_coef_lcd[1]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF13(plane_id), csc_coef_lcd[2]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF21(plane_id), csc_coef_lcd[3]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF22(plane_id), csc_coef_lcd[4]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF23(plane_id), csc_coef_lcd[5]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF31(plane_id), csc_coef_lcd[6]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF32(plane_id), csc_coef_lcd[7]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_COEFF33(plane_id), csc_coef_lcd[8]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF1(plane_id), csc_coef_lcd[9]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF2(plane_id), csc_coef_lcd[10]); + kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF3(plane_id), csc_coef_lcd[11]); + kmb_set_bitmask_lcd(dev_p, LCD_LAYERn_CFG(plane_id), LCD_LAYER_CSC_EN); +} + static void kmb_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *state) { @@ -211,6 +269,7 @@ static void kmb_plane_atomic_upd
[PATCH v2 46/59] drm/kmb: Enable LCD interrupts during modeset
The issue was that spurious interrupts were happening before the LCD controller was enabled and system hangs. Fix is to clear LCD interrupts and disable them before modeset and re enable them after enabling LCD controller. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 12 +--- drivers/gpu/drm/kmb/kmb_drv.c | 21 +++-- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 589a841..c390bbe 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -78,6 +78,7 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) int vsync_start_offset; int vsync_end_offset; struct kmb_drm_private *dev_p = to_kmb(dev); + unsigned int val = 0; /* initialize mipi */ kmb_dsi_hw_init(dev, m); @@ -88,6 +89,9 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) m->crtc_hsync_start - m->crtc_hdisplay, m->crtc_htotal - m->crtc_hsync_end, m->crtc_hsync_end - m->crtc_hsync_start); + val = kmb_read_lcd(dev_p, LCD_INT_ENABLE); + kmb_clr_bitmask_lcd(dev_p, LCD_INT_ENABLE, val); + kmb_set_bitmask_lcd(dev_p, LCD_INT_CLEAR, ~0x0); // vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vfront_porch = 2; // vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; @@ -136,9 +140,9 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_VSYNC_START_EVEN, 10); kmb_write_lcd(dev_p, LCD_VSYNC_END_EVEN, 10); } - /* enable VL1 layer as default */ kmb_write_lcd(dev_p, LCD_TIMING_GEN_TRIG, ENABLE); kmb_set_bitmask_lcd(dev_p, LCD_CONTROL, LCD_CTRL_ENABLE); + kmb_set_bitmask_lcd(dev_p, LCD_INT_ENABLE, val); #endif /* TBD */ /* set clocks here */ @@ -170,8 +174,9 @@ static void kmb_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct drm_device *dev = crtc->dev; + struct kmb_drm_private *dev_p = to_kmb(dev); - kmb_clr_bitmask_lcd(dev->dev_private, LCD_INT_ENABLE, + kmb_clr_bitmask_lcd(dev_p, LCD_INT_ENABLE, LCD_INT_VERT_COMP); } @@ -179,8 +184,9 @@ static void kmb_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct drm_device *dev = crtc->dev; + struct kmb_drm_private *dev_p = to_kmb(dev); - kmb_set_bitmask_lcd(dev->dev_private, LCD_INT_ENABLE, + kmb_set_bitmask_lcd(dev_p, LCD_INT_ENABLE, LCD_INT_VERT_COMP); spin_lock_irq(&crtc->dev->event_lock); diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index e6aa32c..308036e 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -37,8 +37,6 @@ static irqreturn_t kmb_isr(int irq, void *arg); static struct clk *clk_lcd; static struct clk *clk_mipi; -static struct clk *clk_msscam; -static struct clk *clk_pll0out0; static struct clk *clk_mipi_ecfg; static struct clk *clk_mipi_cfg; @@ -59,12 +57,6 @@ int kmb_display_clk_enable(void) DRM_ERROR("Failed to enable MIPI clock: %d\n", ret); return ret; } -/* ret = clk_prepare_enable(clk_msscam); - if (ret) { - DRM_ERROR("Failed to enable MSSCAM clock: %d\n", ret); - return ret; - } - */ ret = clk_prepare_enable(clk_mipi_ecfg); if (ret) { @@ -87,8 +79,6 @@ static int kmb_display_clk_disable(void) clk_disable_unprepare(clk_lcd); if (clk_mipi) clk_disable_unprepare(clk_mipi); - if (clk_msscam) - clk_disable_unprepare(clk_msscam); if (clk_mipi_ecfg) clk_disable_unprepare(clk_mipi_ecfg); if (clk_mipi_cfg) @@ -180,14 +170,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_ERROR("clk_get() failed clk_mipi\n"); goto setup_fail; } - clk_pll0out0 = clk_get(&pdev->dev, "clk_pll0_out0"); - if (IS_ERR(clk_pll0out0)) - DRM_ERROR("clk_get() failed clk_pll0_out0\n"); - - if (clk_pll0out0) - DRM_INFO("Get clk_pll0out0 = %ld\n", - clk_get_rate(clk_pll0out0)); - clk_mipi_ecfg = clk_get(&pdev->dev, "clk_mipi_ecfg"); if (IS_ERR(clk_mipi_ecfg)) { DRM_ERROR("clk_get() failed clk_mipi_ecfg\n"); @@ -394,6 +376,9 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev) break; } } + + /* clear all interrupts */ + kmb_set_bitmask_lcd(dev->dev_private, LCD_INT_CLEAR, ~0x0); ret
[PATCH v2 28/59] drm/kmb: Changed MMIO size
Also added debug messages Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 16 ++-- drivers/gpu/drm/kmb/kmb_regs.h | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 4afdb9c..d13552a 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -29,6 +29,7 @@ #include "kmb_plane.h" #include "kmb_regs.h" +#define DEBUG /*IRQ handler*/ static irqreturn_t kmb_isr(int irq, void *arg); @@ -327,6 +328,7 @@ static int kmb_drm_bind(struct device *dev) dev_set_drvdata(dev, drm); kmb_setup_mode_config(drm); + DRM_DEBUG("kmb_bind : after kmb_setup_mode_config\n"); ret = kmb_load(drm, 0); if (ret) goto err_free; @@ -439,17 +441,27 @@ static int kmb_probe(struct platform_device *pdev) { struct device_node *port; struct component_match *match = NULL; + int ret; /* there is only one output port inside each device, find it */ + DRM_DEBUG("%s : ENTER", __func__); + port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0); + DRM_DEBUG("%s : port = 0x%pOF\n", __func__, port); if (!port) return -ENODEV; + DRM_DEBUG("%s : after get_remote", __func__); + DRM_DEBUG("Adding component %pOF\n", port); drm_of_component_match_add(&pdev->dev, &match, compare_dev, port); + DRM_DEBUG("%s : after get_match", __func__); of_node_put(port); - return component_master_add_with_match(&pdev->dev, &kmb_master_ops, - match); +ret = component_master_add_with_match(&pdev->dev, &kmb_master_ops, + match); + + DRM_DEBUG("%s : EXIT ret=%d\n", __func__, ret); + return ret; } static int kmb_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index 85b55cb..e98e144 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -13,9 +13,9 @@ /*from Data Book section 12.11.6.1 page 4972 */ #define LCD_BASE_ADDR (0x2093) #define MSS_CAM_BASE_ADDR (MIPI_BASE_ADDR + 0x1) -#define LCD_MMIO_SIZE (0x1) -#define MIPI_MMIO_SIZE (0x1) -#define MSS_CAM_MMIO_SIZE (0x1) +#define LCD_MMIO_SIZE (0x3000) +#define MIPI_MMIO_SIZE (0x4000) +#define MSS_CAM_MMIO_SIZE (0x10) /*** *LCD controller control register defines -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 20/59] drm/kmb: Register IRQ for LCD
This code is commented out until firmware is updated to redirect LCD IRQ from MSSCPU to A53. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 17 ++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 5192040..594e64c 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -29,12 +29,16 @@ #include "kmb_plane.h" #include "kmb_regs.h" +/*IRQ handler*/ +static irqreturn_t kmb_isr(int irq, void *arg); + static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); /*struct resource *res;*/ /*u32 version;*/ + /*int irq_lcd, irq_mipi; */ int ret; /* TBD - not sure if clock_get needs to be called here */ @@ -85,6 +89,12 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) dev_p->msscam_mmio = ioremap_cache(MSS_CAM_BASE_ADDR, MSS_CAM_MMIO_SIZE); + /*TODO - register irqs here - section 17.3 in databook +* lists LCD at 79 under MSS CPU - firmware has to redirect it to A53 +* May be 33 for LCD and 34 for MIPI? Will wait till firmware +* finalizes the IRQ numbers for redirection +*/ + /*TBD read and check for correct product version here */ /* Get the optional framebuffer memory resource */ @@ -132,7 +142,7 @@ static void kmb_setup_mode_config(struct drm_device *drm) drm->mode_config.funcs = &kmb_mode_config_funcs; } -static irqreturn_t kmb_irq(int irq, void *arg) +static irqreturn_t kmb_isr(int irq, void *arg) { struct drm_device *dev = (struct drm_device *)arg; unsigned long status, val; @@ -178,8 +188,9 @@ DEFINE_DRM_GEM_CMA_FOPS(fops); static struct drm_driver kmb_driver = { .driver_features = DRIVER_GEM | - DRIVER_MODESET | DRIVER_ATOMIC, - .irq_handler = kmb_irq, + DRIVER_MODESET | + DRIVER_ATOMIC, + .irq_handler = kmb_isr, .irq_preinstall = kmb_irq_reset, .irq_uninstall = kmb_irq_reset, .gem_free_object_unlocked = drm_gem_cma_free_object, -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 41/59] drm/kmb: Changes for LCD to Mipi
Also free dsi resources on driver unload. System clock frequency change for llp ratio calculation. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_crtc.c | 25 drivers/gpu/drm/kmb/kmb_drv.c | 6 +- drivers/gpu/drm/kmb/kmb_drv.h | 1 + drivers/gpu/drm/kmb/kmb_dsi.c | 135 +++- drivers/gpu/drm/kmb/kmb_dsi.h | 2 +- drivers/gpu/drm/kmb/kmb_plane.c | 24 +++ drivers/gpu/drm/kmb/kmb_regs.h | 2 + 7 files changed, 70 insertions(+), 125 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index f77e6f5..cbf998f 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -90,11 +90,14 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) vm.vfront_porch = 0; // vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; vm.vback_porch = 0; - vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; +// vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; + vm.vsync_len = 1; //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; vm.hfront_porch = 0; - vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; - vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; + vm.hback_porch = 0; + //vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; + vm.hsync_len = 1; +// vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; @@ -106,13 +109,13 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) vm.hback_porch, vm.hfront_porch, vm.hsync_len); kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT, m->crtc_vdisplay - 1); - kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch - 1); - kmb_write_lcd(dev_p, LCD_V_FRONTPORCH, vm.vfront_porch - 1); + kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch); + kmb_write_lcd(dev_p, LCD_V_FRONTPORCH, vm.vfront_porch); kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH, vm.vsync_len - 1); kmb_write_lcd(dev_p, LCD_H_ACTIVEWIDTH, m->crtc_hdisplay - 1); - kmb_write_lcd(dev_p, LCD_H_BACKPORCH, vm.hback_porch - 1); - kmb_write_lcd(dev_p, LCD_H_FRONTPORCH, vm.hfront_porch - 1); + kmb_write_lcd(dev_p, LCD_H_BACKPORCH, vm.hback_porch); + kmb_write_lcd(dev_p, LCD_H_FRONTPORCH, vm.hfront_porch); kmb_write_lcd(dev_p, LCD_HSYNC_WIDTH, vm.hsync_len - 1); /*this is hardcoded as 0 in the Myriadx code */ kmb_write_lcd(dev_p, LCD_VSYNC_START, 0); @@ -122,11 +125,11 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); kmb_write_lcd(dev_p, - LCD_V_BACKPORCH_EVEN, vm.vback_porch - 1); + LCD_V_BACKPORCH_EVEN, vm.vback_porch); kmb_write_lcd(dev_p, - LCD_V_FRONTPORCH_EVEN, vm.vfront_porch - 1); - kmb_write_lcd(dev_p, - LCD_V_ACTIVEHEIGHT_EVEN, m->crtc_vdisplay - 1); + LCD_V_FRONTPORCH_EVEN, vm.vfront_porch); + kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT_EVEN, + m->crtc_vdisplay - 1); /*this is hardcoded as 10 in the Myriadx code*/ kmb_write_lcd(dev_p, LCD_VSYNC_START_EVEN, 10); kmb_write_lcd(dev_p, LCD_VSYNC_END_EVEN, 10); diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 8bd3011..039dd21 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -216,7 +216,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) #endif /* Set MIPI clock to 24 Mhz*/ DRM_INFO("Get clk_mipi before set = %ld\n", clk_get_rate(clk_mipi)); -//#define MIPI_CLK +#define MIPI_CLK #ifdef MIPI_CLK ret = clk_set_rate(clk_mipi, KMB_MIPI_DEFAULT_CLK); DRM_INFO("Get clk_mipi after set = %ld\n", clk_get_rate(clk_mipi)); @@ -497,7 +497,7 @@ static void kmb_drm_unload(struct device *dev) dev_set_drvdata(dev, NULL); /* Unregister DSI host */ - dsi_host_unregister(); + kmb_dsi_host_unregister(); } static int kmb_probe(struct platform_device *pdev) @@ -573,7 +573,7 @@ static int kmb_probe(struct platform_device *pdev) drm_mode_config_cleanup(drm); dev_set_drvdata(dev, NULL); drm_dev_put(drm); - dsi_host_unregister(); + kmb_dsi_host_unregister(); return ret; } diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 89d7845..aa77631 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@
[PATCH v2 36/59] drm/kmb: Enable MIPI TX HS Test Pattern Generation
From: Edmund Dea Added test pattern generator function. Enable this at compile time to test if mipi is working. mipi->hdmi section Signed-off-by: Edmund Dea Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 31 +++ drivers/gpu/drm/kmb/kmb_dsi.h | 7 +++ drivers/gpu/drm/kmb/kmb_regs.h | 11 +++ 3 files changed, 49 insertions(+) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 01fa378..960ecfa 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -744,6 +744,32 @@ static void mipi_tx_ctrl_cfg(struct kmb_drm_private *dev_p, u8 fg_id, kmb_write_mipi(dev_p, MIPI_TXm_HS_CTRL(ctrl_no), ctrl); } +#ifdef MIPI_TX_TEST_PATTERN_GENERATION +static void mipi_tx_hs_tp_gen(struct kmb_drm_private *dev_p, int vc, + int tp_sel, u32 stripe_width, u32 color0, u32 color1) +{ + u32 ctrl_no = MIPI_CTRL6; + + /* Select test pattern mode on the virtual channel */ + kmb_write_mipi(dev_p, MIPI_TXm_HS_TEST_PAT_CTRL(ctrl_no), + TP_SEL_VCm(vc, tp_sel)); + + if (tp_sel == MIPI_TX_HS_TP_V_STRIPES || + tp_sel == MIPI_TX_HS_TP_H_STRIPES) { + kmb_write_mipi(dev_p, MIPI_TXm_HS_TEST_PAT_CTRL(ctrl_no), + TP_STRIPE_WIDTH(stripe_width)); + } + + /* Configure test pattern colors */ + kmb_write_mipi(dev_p, MIPI_TX_HS_TEST_PAT_COLOR0, color0); + kmb_write_mipi(dev_p, MIPI_TX_HS_TEST_PAT_COLOR1, color1); + + /* Enable test pattern generation on the virtual channel */ + kmb_write_mipi(dev_p, MIPI_TXm_HS_TEST_PAT_CTRL(ctrl_no), + TP_EN_VCm(vc)); +} +#endif + static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_p, struct mipi_ctrl_cfg *ctrl_cfg) { @@ -807,6 +833,11 @@ static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_p, /*Multi-Channel FIFO Configuration*/ mipi_tx_multichannel_fifo_cfg(dev_p, ctrl_cfg->active_lanes, frame_id); +#ifdef MIPI_TX_TEST_PATTERN_GENERATION + mipi_tx_hs_tp_gen(dev_p, 0, MIPI_TX_HS_TP_WHOLE_FRAME_COLOR0, 0, + 0x, 0); +#endif + /*Frame Generator Enable */ mipi_tx_ctrl_cfg(dev_p, frame_id, ctrl_cfg); return ret; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index 811f3b8..3de68de 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -180,6 +180,13 @@ enum mipi_dsi_data_type { DSI_LP_DT_RESERVED_3F = 0x3f }; +enum mipi_tx_hs_tp_sel { + MIPI_TX_HS_TP_WHOLE_FRAME_COLOR0 = 0, + MIPI_TX_HS_TP_WHOLE_FRAME_COLOR1, + MIPI_TX_HS_TP_V_STRIPES, + MIPI_TX_HS_TP_H_STRIPES, +}; + enum dphy_mode { MIPI_DPHY_SLAVE = 0, MIPI_DPHY_MASTER diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index a3f1a3a..207a161 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -625,6 +625,17 @@ MIPI_TX_HS_IRQ_CLEAR \ + HS_OFFSET(M), val) +/* MIPI Test Pattern Generation */ +#define MIPI_TX_HS_TEST_PAT_CTRL (0x230) +#define MIPI_TXm_HS_TEST_PAT_CTRL(M) \ + (MIPI_TX_HS_TEST_PAT_CTRL + HS_OFFSET(M)) +#define TP_EN_VCm(M) ((M) * 0x04) +#define TP_SEL_VCm(M, N) \ + (N << (((M) * 0x04) + 1)) +#define TP_STRIPE_WIDTH(M) ((M) << 16) +#define MIPI_TX_HS_TEST_PAT_COLOR0 (0x234) +#define MIPI_TX_HS_TEST_PAT_COLOR1 (0x238) + /* D-PHY regs */ #define DPHY_ENABLE(0x100) #define DPHY_INIT_CTRL0(0x104) -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 44/59] drm/kmb: Mipi settings from input timings
Removed hardcoded timings, set timings based on the current mode's input timings. Also calculate and set the lane rate based on the timings. Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_crtc.c | 9 +++- drivers/gpu/drm/kmb/kmb_dsi.c | 93 +++--- drivers/gpu/drm/kmb/kmb_dsi.h | 2 +- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index a6a0444..1987185e 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -84,7 +84,14 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) struct kmb_drm_private *dev_p = to_kmb(dev); #endif /* initialize mipi */ - kmb_dsi_hw_init(dev); + kmb_dsi_hw_init(dev, m); + DRM_INFO("vfp= %d vbp= %d vsyc_len=%d hfp=%d hbp=%d hsync_len=%d\n", + m->crtc_vsync_start - m->crtc_vdisplay, + m->crtc_vtotal - m->crtc_vsync_end, + m->crtc_vsync_end - m->crtc_vsync_start, + m->crtc_hsync_start - m->crtc_hdisplay, + m->crtc_htotal - m->crtc_hsync_end, + m->crtc_hsync_end - m->crtc_hsync_start); #ifdef LCD_TEST // vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vfront_porch = 2; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index e01c4f9..e9499cf 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -27,19 +27,12 @@ static int hw_initialized; //#define MIPI_TX_TEST_PATTERN_GENERATION //#define MIPI_DMA //#define RTL_TEST -//#define IMG_WIDTH_PX 640 -//#define IMG_HEIGHT_LINES 10 - -#define LCD_BYTESPP 1 /*MIPI TX CFG*/ -//#define MIPI_TX_LANE_DATA_RATE_MBPS 1782 -//#define MIPI_TX_LANE_DATA_RATE_MBPS 800 #define MIPI_TX_LANE_DATA_RATE_MBPS 891 -//#define MIPI_TX_LANE_DATA_RATE_MBPS 80 #define MIPI_TX_REF_CLK_KHZ 24000 -//#define MIPI_TX_REF_CLK_KHZ 23809 #define MIPI_TX_CFG_CLK_KHZ 24000 +#define MIPI_TX_BPP24 /*DPHY Tx test codes*/ #define TEST_CODE_FSM_CONTROL 0x03 @@ -78,23 +71,12 @@ static struct mipi_dsi_host *dsi_host; static struct mipi_dsi_device *dsi_device; /* - * These are added here only temporarily for testing, - * these will eventually go to the device tree sections, - * and can be used as a refernce later for device tree additions + * Default setting is 1080p, 4 lanes. */ -#define RES_1920x1080 -#ifdef RES_1920x1080 #define IMG_HEIGHT_LINES 1080 #define IMG_WIDTH_PX 1920 #define MIPI_TX_ACTIVE_LANES 4 -#endif -//#define RES_1280x720 -#ifdef RES_1280x720 -#define IMG_HEIGHT_LINES 720 -#define IMG_WIDTH_PX 1280 -#define MIPI_TX_ACTIVE_LANES 2 -#endif struct mipi_tx_frame_section_cfg mipi_tx_frame0_sect_cfg = { .width_pixels = IMG_WIDTH_PX, .height_lines = IMG_HEIGHT_LINES, @@ -104,7 +86,6 @@ struct mipi_tx_frame_section_cfg mipi_tx_frame0_sect_cfg = { .dma_packed = 0 }; -#ifdef RES_1920x1080 struct mipi_tx_frame_cfg mipitx_frame0_cfg = { .sections[0] = &mipi_tx_frame0_sect_cfg, .sections[1] = NULL, @@ -117,22 +98,6 @@ struct mipi_tx_frame_cfg mipitx_frame0_cfg = { .h_backporch = 148, .h_frontporch = 88 }; -#endif - -#ifdef RES_1280x720 -struct mipi_tx_frame_cfg mipitx_frame0_cfg = { - .sections[0] = &mipi_tx_frame0_sect_cfg, - .sections[1] = NULL, - .sections[2] = NULL, - .sections[3] = NULL, - .vsync_width = 5, - .v_backporch = 20, - .v_frontporch = 5, - .hsync_width = 40, - .h_backporch = 220, - .h_frontporch = 110, -}; -#endif struct mipi_tx_dsi_cfg mipitx_dsi_cfg = { .hfp_blank_en = 0, @@ -1720,10 +1685,58 @@ int kmb_kernel_read(struct file *file, loff_t offset, return ret; } -int kmb_dsi_hw_init(struct drm_device *dev) +int kmb_dsi_hw_init(struct drm_device *dev, struct drm_display_mode *mode) { struct kmb_drm_private *dev_p = to_kmb(dev); + u64 data_rate; + + mipi_tx_init_cfg.active_lanes = MIPI_TX_ACTIVE_LANES; + if (mode != NULL) { + mipi_tx_frame0_sect_cfg.width_pixels = mode->crtc_hdisplay; + mipi_tx_frame0_sect_cfg.height_lines = mode->crtc_vdisplay; + mipitx_frame0_cfg.vsync_width = + mode->crtc_vsync_end - mode->crtc_vsync_start; + mipitx_frame0_cfg.v_backporch = + mode->crtc_vtotal - mode->crtc_vsync_end; + mipitx_frame0_cfg.v_frontporch = + mode->crtc_vsync_start - mode->crtc_vdisplay; + mipitx_frame0_cfg.hsync_width = + mode->crtc_hsync_end - mode->crtc_hsync_start; + mipitx_frame0_cfg.h_backporch = + mode->crtc_htotal - mode->crtc_hsync_end; + mipit
[PATCH v2 33/59] drm/kmb: Initialize clocks for clk_msscam, clk_mipi_ecfg, & clk_mipi_cfg.
From: Edmund Dea Note that we enable clk_msscam but do not set clk_msscam. However, we do enable and set clk_mipi_ecfg and clk_mipi_cfg. Verify that LCD and MIPI clocks are set successfully. Signed-off-by: Edmund Dea --- drivers/gpu/drm/kmb/kmb_drv.c | 112 +- drivers/gpu/drm/kmb/kmb_drv.h | 2 + 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 1368770..9dc5f91 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -36,6 +36,9 @@ static irqreturn_t kmb_isr(int irq, void *arg); static struct clk *clk_lcd; static struct clk *clk_mipi; +static struct clk *clk_msscam; +static struct clk *clk_mipi_ecfg; +static struct clk *clk_mipi_cfg; struct drm_bridge *adv_bridge; @@ -54,6 +57,24 @@ static int kmb_display_clk_enable(void) DRM_ERROR("Failed to enable MIPI clock: %d\n", ret); return ret; } + + ret = clk_prepare_enable(clk_msscam); + if (ret) { + DRM_ERROR("Failed to enable MSSCAM clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(clk_mipi_ecfg); + if (ret) { + DRM_ERROR("Failed to enable MIPI_ECFG clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(clk_mipi_cfg); + if (ret) { + DRM_ERROR("Failed to enable MIPI_CFG clock: %d\n", ret); + return ret; + } DRM_INFO("SUCCESS : enabled LCD MIPI clocks\n"); return 0; } @@ -64,6 +85,12 @@ static int kmb_display_clk_disable(void) clk_disable_unprepare(clk_lcd); if (clk_mipi) clk_disable_unprepare(clk_mipi); + if (clk_msscam) + clk_disable_unprepare(clk_msscam); + if (clk_mipi_ecfg) + clk_disable_unprepare(clk_mipi_ecfg); + if (clk_mipi_cfg) + clk_disable_unprepare(clk_mipi_cfg); return 0; } @@ -98,6 +125,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) struct platform_device *pdev = to_platform_device(drm->dev); /*u32 version;*/ int ret = 0; + unsigned long clk; /* Map LCD MMIO registers */ dev_p->lcd_mmio = kmb_map_mmio(pdev, "lcd_regs"); @@ -108,7 +136,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) /* Map MIPI MMIO registers */ dev_p->mipi_mmio = kmb_map_mmio(pdev, "mipi_regs"); - if (IS_ERR(dev_p->mipi_mmio)) { DRM_ERROR("failed to map MIPI registers\n"); iounmap(dev_p->lcd_mmio); @@ -126,33 +153,94 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) return -ENOMEM; } - /* enable display clocks*/ + /* Enable display clocks*/ clk_lcd = clk_get(&pdev->dev, "clk_lcd"); - if (!clk_lcd) { + if (IS_ERR(clk_lcd)) { DRM_ERROR("clk_get() failed clk_lcd\n"); goto setup_fail; } - DRM_INFO("%s : %d\n", __func__, __LINE__); clk_mipi = clk_get(&pdev->dev, "clk_mipi"); - if (!clk_mipi) { + if (IS_ERR(clk_mipi)) { DRM_ERROR("clk_get() failed clk_mipi\n"); goto setup_fail; } - DRM_INFO("%s : %d\n", __func__, __LINE__); + + clk_msscam = clk_get(&pdev->dev, "clk_msscam"); + if (IS_ERR(clk_msscam)) { + DRM_ERROR("clk_get() failed clk_msscam\n"); + goto setup_fail; + } + + clk_mipi_ecfg = clk_get(&pdev->dev, "clk_mipi_ecfg"); + if (IS_ERR(clk_mipi_ecfg)) { + DRM_ERROR("clk_get() failed clk_mipi_ecfg\n"); + goto setup_fail; + } + + clk_mipi_cfg = clk_get(&pdev->dev, "clk_mipi_cfg"); + if (IS_ERR(clk_mipi_cfg)) { + DRM_ERROR("clk_get() failed clk_mipi_cfg\n"); + goto setup_fail; + } + ret = kmb_display_clk_enable(); - /* set LCD clock to 200 Mhz*/ + /* Set LCD clock to 200 Mhz*/ DRM_INFO("Get clk_lcd before set = %ld\n", clk_get_rate(clk_lcd)); - ret = clk_set_rate(clk_lcd, 2); - DRM_INFO("Setting LCD clock tp 200Mhz ret = %d\n", ret); + ret = clk_set_rate(clk_lcd, KMB_LCD_DEFAULT_CLK); + if (clk_get_rate(clk_lcd) != KMB_LCD_DEFAULT_CLK) { + DRM_ERROR("failed to set to clk_lcd to %d\n", + KMB_LCD_DEFAULT_CLK); + goto setup_fail; + } + DRM_INFO("Setting LCD clock to %d Mhz ret = %d\n", + KMB_LCD_DEFAULT_CLK/100, ret); DRM_INFO("Get clk_lcd after set = %ld\n", clk_get_rate(clk_lcd)); - /* set MIPI clock to 24 Mhz*/ + + /* Set MIPI clock to 24 Mhz*/ DRM_INFO("Get clk_mipi before set = %ld\n", clk_get_rate(clk_mipi)); - ret = clk_set_rate(
[PATCH v2 15/59] drm/kmb: Part5 of Mipi Tx Intitialization
This is part1 of DPHY initialization. v2: remove kmb_write() as the function provides no benefit over calling writel() directly. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.h | 5 - drivers/gpu/drm/kmb/kmb_dsi.c | 346 ++--- drivers/gpu/drm/kmb/kmb_dsi.h | 10 ++ drivers/gpu/drm/kmb/kmb_regs.h | 48 +- 4 files changed, 376 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index f1d5b3a..3996c84 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -64,11 +64,6 @@ static inline void kmb_write_bits(struct kmb_drm_private *lcd, } #endif -static inline void kmb_write(void *reg, u32 value) -{ - writel(value, reg); -} - static inline void kmb_write_lcd(unsigned int reg, u32 value) { writel(value, (LCD_BASE_ADDR + reg)); diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index a255210..d15cf6f 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -27,6 +27,13 @@ #define MIPI_TX_REF_CLK_KHZ 24000 #define MIPI_TX_CFG_CLK_KHZ 24000 +/*DPHY Tx test codes*/ +#define TEST_CODE_HS_FREQ_RANGE_CFG0x44 +#define TEST_CODE_PLL_ANALOG_PROG 0x1F +#define TEST_CODE_SLEW_RATE_OVERRIDE_CTRL 0xA0 +#define TEST_CODE_SLEW_RATE_DDL_LOOP_CTRL 0xA3 +#define TEST_CODE_SLEW_RATE_DDL_CYCLES 0xA4 + /* * These are added here only temporarily for testing, * these will eventually go to the device tree sections, @@ -87,6 +94,77 @@ struct mipi_ctrl_cfg mipi_tx_init_cfg = { }; +typedef struct{ + uint16_t default_bit_rate_mbps; + uint8_t hsfreqrange_code; +} mipi_hs_freq_range_cfg; + +static mipi_hs_freq_range_cfg + mipi_hs_freq_range[MIPI_DPHY_DEFAULT_BIT_RATES] = { + {.default_bit_rate_mbps = 80, .hsfreqrange_code = 0x00}, + {.default_bit_rate_mbps = 90, .hsfreqrange_code = 0x10}, + {.default_bit_rate_mbps = 100, .hsfreqrange_code = 0x20}, + {.default_bit_rate_mbps = 110, .hsfreqrange_code = 0x30}, + {.default_bit_rate_mbps = 120, .hsfreqrange_code = 0x01}, + {.default_bit_rate_mbps = 130, .hsfreqrange_code = 0x11}, + {.default_bit_rate_mbps = 140, .hsfreqrange_code = 0x21}, + {.default_bit_rate_mbps = 150, .hsfreqrange_code = 0x31}, + {.default_bit_rate_mbps = 160, .hsfreqrange_code = 0x02}, + {.default_bit_rate_mbps = 170, .hsfreqrange_code = 0x12}, + {.default_bit_rate_mbps = 180, .hsfreqrange_code = 0x22}, + {.default_bit_rate_mbps = 190, .hsfreqrange_code = 0x32}, + {.default_bit_rate_mbps = 205, .hsfreqrange_code = 0x03}, + {.default_bit_rate_mbps = 220, .hsfreqrange_code = 0x13}, + {.default_bit_rate_mbps = 235, .hsfreqrange_code = 0x23}, + {.default_bit_rate_mbps = 250, .hsfreqrange_code = 0x33}, + {.default_bit_rate_mbps = 275, .hsfreqrange_code = 0x04}, + {.default_bit_rate_mbps = 300, .hsfreqrange_code = 0x14}, + {.default_bit_rate_mbps = 325, .hsfreqrange_code = 0x25}, + {.default_bit_rate_mbps = 350, .hsfreqrange_code = 0x35}, + {.default_bit_rate_mbps = 400, .hsfreqrange_code = 0x05}, + {.default_bit_rate_mbps = 450, .hsfreqrange_code = 0x16}, + {.default_bit_rate_mbps = 500, .hsfreqrange_code = 0x26}, + {.default_bit_rate_mbps = 550, .hsfreqrange_code = 0x37}, + {.default_bit_rate_mbps = 600, .hsfreqrange_code = 0x07}, + {.default_bit_rate_mbps = 650, .hsfreqrange_code = 0x18}, + {.default_bit_rate_mbps = 700, .hsfreqrange_code = 0x28}, + {.default_bit_rate_mbps = 750, .hsfreqrange_code = 0x39}, + {.default_bit_rate_mbps = 800, .hsfreqrange_code = 0x09}, + {.default_bit_rate_mbps = 850, .hsfreqrange_code = 0x19}, + {.default_bit_rate_mbps = 900, .hsfreqrange_code = 0x29}, + {.default_bit_rate_mbps = 1000, .hsfreqrange_code = 0x0A}, + {.default_bit_rate_mbps = 1050, .hsfreqrange_code = 0x1A}, + {.default_bit_rate_mbps = 1100, .hsfreqrange_code = 0x2A}, + {.default_bit_rate_mbps = 1150, .hsfreqrange_code = 0x3B}, + {.default_bit_rate_mbps = 1200, .hsfreqrange_code = 0x0B}, + {.default_bit_rate_mbps = 1250, .hsfreqrange_code = 0x1B}, + {.default_bit_rate_mbps = 1300, .hsfreqrange_code = 0x2B}, + {.default_bit_rate_mbps = 1350, .hsfreqrange_code = 0x3C}, + {.default_bit_rate_mbps = 1400, .hsfreqrange_code = 0x0C}, + {.default_bit_rate_mbps = 1450, .hsfreqrange_code = 0x1C}, + {.default_bit_rate_mbps = 1500, .hsfreqrange_code = 0x2C}, + {.default_bit_rate_mbps = 1550, .hsfreqrange_code = 0x3D}, + {.default_bit_rate_mbps = 1600, .hsfreqrange_code = 0x0D}, + {.default_bit_rate_mbps = 1650, .hsfreqrange_code = 0x1D}, + {.default_bit_rate_mbps = 1700, .hsfreqrange_code = 0x2E}, + {.default_bit_rate_mbps = 1750, .hsfreqran
[PATCH v2 35/59] drm/kmb: Remove declaration of irq_lcd/irq_mipi
From: Edmund Dea Made it conditionally compiled. Signed-off-by: Edmund Dea --- drivers/gpu/drm/kmb/kmb_drv.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 90db07c..861aa97 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -123,7 +123,10 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); +#ifdef WIP /*u32 version;*/ + int irq_lcd, irq_mipi; +#endif int ret = 0; unsigned long clk; @@ -277,9 +280,9 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) pr_info("irq_mipi platform_get_irq = %d\n", irq_mipi); ret = request_irq(irq_mipi, kmb_isr, IRQF_SHARED, "irq_mipi", dev_p); dev_p->irq_mipi = irq_mipi; -#endif - /* TBD read and check for correct product version here */ + /* TBD read and check for correct product version here */ +#endif /* Get the optional framebuffer memory resource */ ret = of_reserved_mem_device_init(drm->dev); if (ret && ret != -ENODEV) -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 31/59] drm/kmb: Cleanup probe functions
From: Edmund Dea - Removed deprecated code blocks within probe functions - In kmb_remove, unregister MIPI DSI host - In kmb_probe, if kmb_load fails, then unregister MIPI DSI host - Change kmb_dsi_host_bridge_init to return error codes using ERR_PTR - Do clock intitialization earlier - Rename kmb_drm_unbind to kmb_drm_unload. - Get mmio info from device tree v2: upclassed dev_private Signed-off-by: Edmund Dea Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 332 +++--- drivers/gpu/drm/kmb/kmb_drv.h | 1 + drivers/gpu/drm/kmb/kmb_dsi.c | 85 --- 3 files changed, 218 insertions(+), 200 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 76f3c43..25daba7 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -30,18 +30,18 @@ #include "kmb_regs.h" #define DEBUG + /*IRQ handler*/ static irqreturn_t kmb_isr(int irq, void *arg); static struct clk *clk_lcd; static struct clk *clk_mipi; -static int probe_deferred; struct drm_bridge *adv_bridge; static int kmb_display_clk_enable(void) { - int ret; + int ret = 0; ret = clk_prepare_enable(clk_lcd); if (ret) { @@ -67,86 +67,142 @@ static int kmb_display_clk_disable(void) return 0; } +static void __iomem *kmb_map_mmio(struct platform_device *pdev, char *name) +{ + struct resource *res; + u32 size; + void __iomem *mem; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + DRM_ERROR("failed to get resource for %s\n", name); + return ERR_PTR(-ENOMEM); + } + size = resource_size(res); + if (!request_mem_region(res->start, size, name)) { + DRM_ERROR("failed to reserve %s registers\n", name); + return ERR_PTR(-ENOMEM); + } + mem = ioremap(res->start, size); + if (!mem) { + DRM_ERROR("failed to ioremap %s registers\n", name); + release_mem_region(res->start, size); + return ERR_PTR(-ENOMEM); + } + return mem; +} + static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); -/* struct drm_bridge *bridge;*/ - /*struct resource *res;*/ /*u32 version;*/ - int ret; -/* struct device_node *encoder_node;*/ - - /* TBD - not sure if clock_get needs to be called here */ - /* -*dev_p->clk = devm_clk_get(drm->dev, "pxlclk"); -*if (IS_ERR(dev_p->clk)) -* return PTR_ERR(dev_p->clk); -*/ - /* -* TBD call this in the future when device tree is ready, -* use hardcoded value for now -*/ - /* -* res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -* dev_p->lcd_mmio = devm_ioremap_resource(drm->dev, res); - -*if (IS_ERR(dev_p->lcd_mmio)) { -* DRM_ERROR("failed to map control registers area\n"); -* ret = PTR_ERR(dev_p->lcd_mmio); -* dev_p->lcd_mmio = NULL; -* return ret; -*} -*/ - /* LCD mmio */ - probe_deferred = 1; + int ret = 0; - if (!request_mem_region(LCD_BASE_ADDR, LCD_MMIO_SIZE, "kmb-lcd")) { - DRM_ERROR("failed to reserve LCD registers\n"); - return -ENOMEM; - } - dev_p->lcd_mmio = ioremap_cache(LCD_BASE_ADDR, LCD_MMIO_SIZE); - if (!dev_p->lcd_mmio) { + /* Map LCD MMIO registers */ + dev_p->lcd_mmio = kmb_map_mmio(pdev, "lcd_regs"); + if (IS_ERR(dev_p->lcd_mmio)) { DRM_ERROR("failed to map LCD registers\n"); return -ENOMEM; } - /* Mipi mmio */ - if (!request_mem_region(MIPI_BASE_ADDR, MIPI_MMIO_SIZE, "kmb-mipi")) { - DRM_ERROR("failed to reserve MIPI registers\n"); + + /* Map MIPI MMIO registers */ + dev_p->mipi_mmio = kmb_map_mmio(pdev, "mipi_regs"); + + if (IS_ERR(dev_p->mipi_mmio)) { + DRM_ERROR("failed to map MIPI registers\n"); iounmap(dev_p->lcd_mmio); return -ENOMEM; } - dev_p->mipi_mmio = ioremap_cache(MIPI_BASE_ADDR, MIPI_MMIO_SIZE); - if (!dev_p->mipi_mmio) { - DRM_ERROR("failed to map MIPI registers\n"); + + /* This is only for MIPI_TX_MSS_LCD_MIPI_CFG and MSS_CAM_CLK_CTRL +* register +*/ + dev_p->msscam_mmio = kmb_map_mmio(pdev, "msscam_regs"); + if (IS_ERR(dev_p->msscam_mmio)) { + DRM_ERROR("failed to map MSSCAM registers\n"); iounmap(dev_p->lcd_mmio); + iounmap(dev_p->mipi_mmio); return -ENOMEM; } - /*this is only for MIPI_TX_MSS_LCD_MIPI_CFG register */ - if (!dev_p->msscam_mmio)
[PATCH v2 48/59] drm/kmb: SWAP R and B LCD Layer order
Set swap bit for the colors to display correctly when the format is RGB and not set when its BGR. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 36 ++-- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 1582ccf..5fd1837 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -198,54 +198,55 @@ unsigned int set_pixel_format(u32 format) val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE | LCD_LAYER_CRCB_ORDER; break; - /* packed formats */ + /* packed formats */ + /* looks hw requires B & G to be swapped when RGB */ case DRM_FORMAT_RGB332: - val = LCD_LAYER_FORMAT_RGB332; + val = LCD_LAYER_FORMAT_RGB332 | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_XBGR: - val = LCD_LAYER_FORMAT_RGBX | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGBX; break; case DRM_FORMAT_ARGB: - val = LCD_LAYER_FORMAT_RGBA; + val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_ABGR: - val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGBA; break; case DRM_FORMAT_XRGB1555: - val = LCD_LAYER_FORMAT_XRGB1555; + val = LCD_LAYER_FORMAT_XRGB1555 | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_XBGR1555: - val = LCD_LAYER_FORMAT_XRGB1555 | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_XRGB1555; break; case DRM_FORMAT_ARGB1555: - val = LCD_LAYER_FORMAT_RGBA1555; + val = LCD_LAYER_FORMAT_RGBA1555 | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_ABGR1555: - val = LCD_LAYER_FORMAT_RGBA1555 | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGBA1555; break; case DRM_FORMAT_RGB565: - val = LCD_LAYER_FORMAT_RGB565; + val = LCD_LAYER_FORMAT_RGB565 | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_BGR565: - val = LCD_LAYER_FORMAT_RGB565 | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGB565; break; case DRM_FORMAT_RGB888: - val = LCD_LAYER_FORMAT_RGB888; + val = LCD_LAYER_FORMAT_RGB888 | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_BGR888: - val = LCD_LAYER_FORMAT_RGB888 | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGB888; break; case DRM_FORMAT_XRGB: - val = LCD_LAYER_FORMAT_RGBX; + val = LCD_LAYER_FORMAT_RGBX | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_XBGR: - val = LCD_LAYER_FORMAT_RGBX | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGBX; break; case DRM_FORMAT_ARGB: - val = LCD_LAYER_FORMAT_RGBA; + val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; break; case DRM_FORMAT_ABGR: - val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; + val = LCD_LAYER_FORMAT_RGBA; break; } DRM_INFO("%s : %d layer format val=%d\n", __func__, __LINE__, val); @@ -348,7 +349,6 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, val |= set_bits_per_pixel(fb->format); /*CHECKME Leon drvr sets it to 100 try this for now */ val |= LCD_LAYER_FIFO_100; - val |= LCD_LAYER_BGR_ORDER; kmb_write_lcd(dev_p, LCD_LAYERn_CFG(plane_id), val); /*re-initialize interrupts */ -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 22/59] drm/kmb: Set hardcoded values to LCD_VSYNC_START
Myriadx code has it set to these values. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 5c1e858..eca0f3a 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -102,6 +102,9 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_H_BACKPORCH, vm.hback_porch - 1); kmb_write_lcd(dev_p, LCD_H_FRONTPORCH, vm.hfront_porch - 1); kmb_write_lcd(dev_p, LCD_HSYNC_WIDTH, vm.hsync_len - 1); + /*this is hardcoded as 0 in the Myriadx code */ + kmb_write_lcd(dev_p, LCD_VSYNC_START, 0); + kmb_write_lcd(dev_p, LCD_VSYNC_END, 0); if (m->flags == DRM_MODE_FLAG_INTERLACE) { kmb_write_lcd(dev_p, @@ -112,10 +115,9 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) LCD_V_FRONTPORCH_EVEN, vm.vfront_porch - 1); kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT_EVEN, m->crtc_vdisplay - 1); - kmb_write_lcd(dev_p, LCD_VSYNC_START_EVEN, - vsync_start_offset); - kmb_write_lcd(dev_p, LCD_VSYNC_END_EVEN, - vsync_end_offset); + /*this is hardcoded as 10 in the Myriadx code*/ + kmb_write_lcd(dev_p, LCD_VSYNC_START_EVEN, 10); + kmb_write_lcd(dev_p, LCD_VSYNC_END_EVEN, 10); } /* enable VL1 layer as default */ ctrl = LCD_CTRL_ENABLE | LCD_CTRL_VL1_ENABLE; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 18/59] drm/kmb: Part8 of Mipi Tx Initialization
This initializes the interrupts for DSI. This is the final part of mipi DSI initialization. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 1 + drivers/gpu/drm/kmb/kmb_drv.h | 30 +++- drivers/gpu/drm/kmb/kmb_dsi.c | 46 drivers/gpu/drm/kmb/kmb_dsi.h | 13 +++ drivers/gpu/drm/kmb/kmb_regs.h | 81 ++ 5 files changed, 163 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 224a7f8..19f78ba 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -58,6 +58,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) if (ret && ret != -ENODEV) return ret; + spin_lock_init(&lcd->irq_lock); ret = kmb_setup_crtc(drm); if (ret < 0) { DRM_ERROR("failed to create crtc\n"); diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 3996c84..14bdfc8 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -12,14 +12,15 @@ #define KMB_MAX_HEIGHT 16384 /*max height in pixels */ struct kmb_drm_private { - struct drm_device drm; - void __iomem *mmio; - unsigned char n_layers; - struct clk *clk; - struct drm_fbdev_cma *fbdev; - struct drm_crtc crtc; - struct kmb_plane *plane; - struct drm_atomic_state *state; + struct drm_device drm; + void __iomem*mmio; + unsigned char n_layers; + struct clk *clk; + struct drm_fbdev_cma*fbdev; + struct drm_crtc crtc; + struct kmb_plane*plane; + struct drm_atomic_state *state; + spinlock_t irq_lock; }; static inline struct kmb_drm_private *to_kmb(const struct drm_device *dev) @@ -111,6 +112,19 @@ static inline void kmb_clr_bit_mipi(unsigned int reg, u32 offset) kmb_write_mipi(reg, reg_val & (~(1 << offset))); } +static inline void kmb_set_bitmask_mipi(unsigned int reg, u32 mask) +{ + u32 reg_val = kmb_read_mipi(reg); + + kmb_write_mipi(reg, (reg_val | mask)); +} + +static inline void kmb_clr_bitmask_mipi(unsigned int reg, u32 mask) +{ + u32 reg_val = kmb_read_mipi(reg); + + kmb_write_mipi(reg, (reg_val & (~mask))); +} int kmb_setup_crtc(struct drm_device *dev); void kmb_set_scanout(struct kmb_drm_private *lcd); #endif /* __KMB_DRV_H__ */ diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index f8ddb87..47456b2 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -188,6 +189,11 @@ static mipi_hs_freq_range_cfg {.default_bit_rate_mbps = 2500, .hsfreqrange_code = 0x49} }; +union mipi_irq_cfg int_cfg = { + .irq_cfg.frame_done = 1, + .irq_cfg.ctrl_error = 1, +}; + static enum drm_mode_status kmb_dsi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -1174,6 +1180,43 @@ static u32 mipi_tx_init_dphy(struct mipi_ctrl_cfg *cfg) return 0; } +static void mipi_tx_init_irqs(union mipi_irq_cfg *cfg, + struct kmb_drm_private *dev_priv, + struct mipi_tx_ctrl_cfg *tx_ctrl_cfg) +{ + unsigned long irqflags; + uint8_t vc; + + /* clear all interrupts first */ + /*local interrupts */ + SET_MIPI_TX_HS_IRQ_CLEAR(MIPI_CTRL6, MIPI_TX_HS_IRQ_ALL); + /*global interrupts */ + SET_MIPI_CTRL_IRQ_CLEAR0(MIPI_CTRL6, MIPI_HS_IRQ); + SET_MIPI_CTRL_IRQ_CLEAR0(MIPI_CTRL6, MIPI_DHY_ERR_IRQ); + SET_MIPI_CTRL_IRQ_CLEAR1(MIPI_CTRL6, MIPI_HS_RX_EVENT_IRQ); + + /*enable interrupts */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + for (vc = 0; vc < MIPI_CTRL_VIRTUAL_CHANNELS; vc++) { + if (tx_ctrl_cfg->frames[vc] == NULL) + continue; + /*enable FRAME_DONE interrupt if VC is configured */ + SET_HS_IRQ_ENABLE(MIPI_CTRL6, + MIPI_TX_HS_IRQ_FRAME_DONE_0 << vc); + break; /*only one vc for LCD interface */ + } + + /*enable user enabled interrupts */ + if (cfg->irq_cfg.dphy_error) + SET_MIPI_CTRL_IRQ_ENABLE0(MIPI_CTRL6, MIPI_DHY_ERR_IRQ); + if (cfg->irq_cfg.line_compare) + SET_HS_IRQ_ENABLE(MIPI_CTRL6, MIPI_TX_HS_IRQ_LINE_COMPARE); + if (cfg->irq_cfg.ctrl_error) + SET_HS_IRQ_ENABLE(MIPI_CTRL6, MIPI_TX_HS_IRQ_ERROR); + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + void kmb_dsi_init(struct drm_device *dev) { struct kmb_dsi *kmb_dsi; @@ -1219,4 +1262,7 @@ void kmb_dsi_init(struct drm_dev
[PATCH v2 09/59] drm/kmb: Part 1 of Mipi Tx Initialization
Mipi TX frame section configuration This is the first part in the MIPI controller initialization. Compute and set the right values in MIPI TX frame section configuration registers like packet header(PH), unpacked bytes and line config. v2: added more comments to clarify assumptions v3: improved code readability as per code review Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.h | 14 ++ drivers/gpu/drm/kmb/kmb_dsi.c | 330 + drivers/gpu/drm/kmb/kmb_dsi.h | 232 + drivers/gpu/drm/kmb/kmb_regs.h | 25 4 files changed, 601 insertions(+) diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 23299a5..addf5ec 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -42,6 +42,20 @@ static inline u32 kmb_read(struct kmb_drm_private *lcd, unsigned int reg) return readl(lcd->mmio + reg); } +static inline void kmb_write_bits(struct kmb_drm_private *lcd, + unsigned int reg, u32 offset, u32 num_bits, + u32 value) +{ + u32 reg_val = kmb_read(lcd, reg); + u32 mask = (1 << num_bits) - 1; + + value &= mask; + mask <<= offset; + reg_val &= (~mask); + reg_val |= (value << offset); + writel(reg_val, lcd->mmio + reg); +} + int kmb_setup_crtc(struct drm_device *dev); void kmb_set_scanout(struct kmb_drm_private *lcd); #endif /* __KMB_DRV_H__ */ diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index d82411e..cb6082d 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -11,9 +11,81 @@ #include #include #include +#include #include #include "kmb_drv.h" #include "kmb_dsi.h" +#include "kmb_regs.h" + +#define IMG_WIDTH_PX 1920 +#define IMG_HEIGHT_LINES 1080 +#define LCD_BYTESPP 1 + +/*MIPI TX CFG*/ +#define MIPI_TX_ACTIVE_LANES4 +#define MIPI_TX_LANE_DATA_RATE_MBPS 888 +#define MIPI_TX_REF_CLK_KHZ 24000 +#define MIPI_TX_CFG_CLK_KHZ 24000 + +/* + * These are added here only temporarily for testing, + * these will eventually go to the device tree sections, + * and can be used as a refernce later for device tree additions + */ +struct mipi_tx_frame_section_cfg mipi_tx_frame0_sect_cfg = { + .width_pixels = IMG_WIDTH_PX, + .height_lines = IMG_HEIGHT_LINES, + .data_type = DSI_LP_DT_PPS_RGB888_24B, + .data_mode = MIPI_DATA_MODE1, + .dma_packed = 0 +}; + +struct mipi_tx_frame_cfg mipitx_frame0_cfg = { + .sections[0] = &mipi_tx_frame0_sect_cfg, + .sections[1] = NULL, + .sections[2] = NULL, + .sections[3] = NULL, + .vsync_width = 5, + .v_backporch = 36, + .v_frontporch = 4, + .hsync_width = 44, + .h_backporch = 148, + .h_frontporch = 88 +}; + +struct mipi_tx_dsi_cfg mipitx_dsi_cfg = { + .hfp_blank_en = 0, + .eotp_en = 0, + .lpm_last_vfp_line = 0, + .lpm_first_vsa_line = 0, + .sync_pulse_eventn = DSI_VIDEO_MODE_NO_BURST_EVENT, + .hfp_blanking = SEND_BLANK_PACKET, + .hbp_blanking = SEND_BLANK_PACKET, + .hsa_blanking = SEND_BLANK_PACKET, + .v_blanking = SEND_BLANK_PACKET, +}; + +struct mipi_ctrl_cfg mipi_tx_init_cfg = { + .index = MIPI_CTRL6, + .type = MIPI_DSI, + .dir = MIPI_TX, + .active_lanes = MIPI_TX_ACTIVE_LANES, + .lane_rate_mbps = MIPI_TX_LANE_DATA_RATE_MBPS, + .ref_clk_khz = MIPI_TX_REF_CLK_KHZ, + .cfg_clk_khz = MIPI_TX_CFG_CLK_KHZ, + .data_if = MIPI_IF_PARALLEL, + .tx_ctrl_cfg = { + .frames[0] = &mipitx_frame0_cfg, + .frames[1] = NULL, + .frames[2] = NULL, + .frames[3] = NULL, + .tx_dsi_cfg = &mipitx_dsi_cfg, + .line_sync_pkt_en = 0, + .line_counter_active = 0, + .frame_counter_active = 0, + } + +}; static enum drm_mode_status kmb_dsi_mode_valid(struct drm_connector *connector, @@ -111,6 +183,261 @@ static struct kmb_dsi_host *kmb_dsi_host_init(struct kmb_dsi *kmb_dsi) return host; } +u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, +struct mipi_data_type_params *params) +{ + struct mipi_data_type_params data_type_parameters; + + switch (data_type) { + case DSI_LP_DT_PPS_YCBCR420_12B: + data_type_parameters.size_constraint_pixels = 2; + data_type_parameters.size_constraint_bytes = 3; + switch (data_mode) { + /* case 0 not supported according to MDK */ + case 1: + case 2: + case 3: + data_type_parameters.pixels_per_pclk = 2; + data_type_pa
[PATCH v2 54/59] drm/kmb: Initialize uninitialized variables
general cleaning Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 6e38f16..2599ed2 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -307,7 +307,7 @@ static struct kmb_dsi_host *kmb_dsi_host_init(struct drm_device *drm, struct drm_bridge *kmb_dsi_host_bridge_init(struct device *dev) { - struct drm_bridge *bridge; + struct drm_bridge *bridge = NULL; #ifndef FCCTEST struct device_node *encoder_node; #endif @@ -815,7 +815,7 @@ static void mipi_tx_hs_tp_gen(struct kmb_drm_private *dev_p, int vc, static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_p, struct mipi_ctrl_cfg *ctrl_cfg) { - u32 ret; + u32 ret = 0; u8 active_vchannels = 0; u8 frame_id, sect; u32 bits_per_pclk = 0; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 34/59] drm/kmb: Enable MSS_CAM_CLK_CTRL for LCD and MIPI
Enable clocks for LCD, mipi common and mipi tx0 Renamed MSS_CAM_CLK_CTRL and also fixed bug in the call to set this register. Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 8 drivers/gpu/drm/kmb/kmb_drv.h | 14 ++ drivers/gpu/drm/kmb/kmb_dsi.c | 6 -- drivers/gpu/drm/kmb/kmb_regs.h | 7 ++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 9dc5f91..90db07c 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -241,6 +241,9 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_INFO("Get clk_mipi_cfg after set = %ld\n", clk); } + /* enable MSS_CAM_CLK_CTRL for MIPI TX and LCD */ + kmb_set_bitmask_msscam(dev_p, MSS_CAM_CLK_CTRL, LCD | MIPI_COMMON | + MIPI_TX0); #ifdef WIP /* Register irqs here - section 17.3 in databook * lists LCD at 79 and 82 for MIPI under MSS CPU - @@ -292,10 +295,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) /* Initialize MIPI DSI */ ret = kmb_dsi_init(drm, adv_bridge); - if (ret == -EPROBE_DEFER) { - DRM_INFO("%s: wait for external bridge driver DT", __func__); - return -EPROBE_DEFER; - } else if (ret) { + if (ret) { DRM_ERROR("failed to initialize DSI\n"); goto setup_fail; } diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 8c5ccf7..71dc883 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -88,6 +88,20 @@ static inline void kmb_write_msscam(struct kmb_drm_private *dev_p, writel(value, (dev_p->msscam_mmio + reg)); } +static inline u32 kmb_read_msscam(struct kmb_drm_private *dev_p, + unsigned int reg) +{ + return readl(dev_p->msscam_mmio + reg); +} + +static inline void kmb_set_bitmask_msscam(struct kmb_drm_private *dev_p, + unsigned int reg, u32 mask) +{ + u32 reg_val = kmb_read_msscam(dev_p, reg); + + kmb_write_msscam(dev_p, reg, (reg_val | mask)); +} + static inline u32 kmb_read_lcd(struct kmb_drm_private *dev_p, unsigned int reg) { return readl(dev_p->lcd_mmio + reg); diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 4ec1753..01fa378 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -794,9 +794,11 @@ static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_p, active_vchannels++; /*connect lcd to mipi */ - kmb_write_msscam(dev_p, MSS_CAM_BASE_ADDR + - MIPI_TX_MSS_LCD_MIPI_CFG, 1); + kmb_write_msscam(dev_p, MSS_LCD_MIPI_CFG, 1); + /*stop iterating as only one virtual channel shall be used for +* LCD connection +*/ break; } diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index e98e144..a3f1a3a 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -677,6 +677,11 @@ & (1 << (dphy - MIPI_DPHY6))) #define DPHY_CFG_CLK_EN(0x18c) -#define MIPI_TX_MSS_LCD_MIPI_CFG (0x04) +#define MSS_LCD_MIPI_CFG (0x04) +#define MSS_CAM_CLK_CTRL (0x10) +#define LCD (1<<1) +#define MIPI_COMMON (1<<2) +#define MIPI_TX0 (1<<9) + #define BIT_MASK_16(0x) #endif /* __KMB_REGS_H__ */ -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 39/59] drm/kmb: Fixed driver unload
unmap MSSCAM registers Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 15 +++ drivers/gpu/drm/kmb/kmb_drv.h | 1 - drivers/gpu/drm/kmb/kmb_regs.h | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 2a93b13..3542de7 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -159,17 +159,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) iounmap(dev_p->mipi_mmio); return -ENOMEM; } -/*testing*/ - if (!request_mem_region(CPR_BASE_ADDR, 100, "cpr")) { - DRM_ERROR("failed to reserve %s registers\n", "cpr"); - return -ENOMEM; - } - dev_p->cpr_mmio = ioremap_cache(CPR_BASE_ADDR, 0x100); - if (!dev_p->cpr_mmio) { - DRM_ERROR("failed to ioremap %s registers\n", "CPR"); - release_mem_region(CPR_BASE_ADDR, 100); - return -ENOMEM; - } if (IS_ERR(dev_p->msscam_mmio)) { DRM_ERROR("failed to map MSSCAM registers\n"); @@ -490,8 +479,10 @@ static void kmb_drm_unload(struct device *dev) release_mem_region(MIPI_BASE_ADDR, MIPI_MMIO_SIZE); } - if (dev_p->msscam_mmio) + if (dev_p->msscam_mmio) { iounmap(dev_p->msscam_mmio); + release_mem_region(MSS_CAM_BASE_ADDR, MSS_CAM_MMIO_SIZE); + } of_reserved_mem_device_release(drm->dev); drm_mode_config_cleanup(drm); diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 0bdac1a..7e6 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -20,7 +20,6 @@ struct kmb_drm_private { void __iomem*lcd_mmio; void __iomem*mipi_mmio; void __iomem*msscam_mmio; - void __iomem*cpr_mmio; unsigned char n_layers; struct clk *clk; struct drm_crtc crtc; diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index d2b884c..c83740bb 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -16,7 +16,7 @@ #define MSS_CAM_BASE_ADDR (MIPI_BASE_ADDR + 0x1) #define LCD_MMIO_SIZE (0x3000) #define MIPI_MMIO_SIZE (0x4000) -#define MSS_CAM_MMIO_SIZE (0x10) +#define MSS_CAM_MMIO_SIZE (0x30) /*** *LCD controller control register defines -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 56/59] kmb/drm: Prune unsupported modes
KMB display pipeline is LCD->Mipi->HDMI. Mipi->HDMI converter chip only accepts 4-lane input from mipi. With 4-lane mipi, KMB hardware can only support 1080p resolution. Therefore, limit supported mode to 1080p. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 4 ++-- drivers/gpu/drm/kmb/kmb_drv.h | 8 +--- drivers/gpu/drm/kmb/kmb_dsi.c | 11 +++ drivers/gpu/drm/kmb/kmb_plane.c | 2 ++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 7fcab4b..b844c77 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -337,8 +337,8 @@ static const struct drm_mode_config_funcs kmb_mode_config_funcs = { static void kmb_setup_mode_config(struct drm_device *drm) { drm_mode_config_init(drm); - drm->mode_config.min_width = 0; - drm->mode_config.min_height = 0; + drm->mode_config.min_width = KMB_MIN_WIDTH; + drm->mode_config.min_height = KMB_MIN_HEIGHT; drm->mode_config.max_width = KMB_MAX_WIDTH; drm->mode_config.max_height = KMB_MAX_HEIGHT; drm->mode_config.funcs = &kmb_mode_config_funcs; diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 94b62b9..373a059 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -8,10 +8,12 @@ #include "kmb_regs.h" -#define FCCTEST +//#define FCCTEST #define LCD_TEST -#define KMB_MAX_WIDTH 1920/*max width in pixels */ -#define KMB_MAX_HEIGHT 1080/*max height in pixels */ +#define KMB_MAX_WIDTH 1920 /*max width in pixels */ +#define KMB_MAX_HEIGHT 1080 /*max height in pixels */ +#define KMB_MIN_WIDTH 1920 /*max width in pixels */ +#define KMB_MIN_HEIGHT 1080 /*max height in pixels */ #define KMB_LCD_DEFAULT_CLK25000 #define KMB_MIPI_DEFAULT_CLK 2400 #define KMB_MIPI_DEFAULT_CFG_CLK 2400 diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 2599ed2..47798ed 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -193,6 +193,17 @@ static enum drm_mode_status kmb_dsi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_device *dev = connector->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + + if (mode->hdisplay < mode_config->min_width || + mode->hdisplay > mode_config->max_width) + return MODE_BAD_HVALUE; + + if (mode->vdisplay < mode_config->min_height || + mode->vdisplay > mode_config->max_height) + return MODE_BAD_VVALUE; + return MODE_OK; } diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 8b2b202..a6b5969 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -57,6 +57,8 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, if (state->crtc_w > KMB_MAX_WIDTH || state->crtc_h > KMB_MAX_HEIGHT) return -EINVAL; + if (state->crtc_w < KMB_MIN_WIDTH || state->crtc_h < KMB_MIN_HEIGHT) + return -EINVAL; return 0; } -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 32/59] drm/kmb: Revert dsi_host back to a static variable
From: Edmund Dea revert dsi_host to static and instead add dsi_host_unregister. Signed-off-by: Edmund Dea Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 6 +++--- drivers/gpu/drm/kmb/kmb_drv.h | 1 - drivers/gpu/drm/kmb/kmb_dsi.c | 9 +++-- drivers/gpu/drm/kmb/kmb_dsi.h | 1 + 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 25daba7..1368770 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -379,7 +379,7 @@ static void kmb_drm_unload(struct device *dev) dev_set_drvdata(dev, NULL); /* Unregister DSI host */ - mipi_dsi_host_unregister(dsi_host); + dsi_host_unregister(); } static int kmb_probe(struct platform_device *pdev) @@ -420,7 +420,7 @@ static int kmb_probe(struct platform_device *pdev) dev_set_drvdata(dev, drm); kmb_setup_mode_config(drm); - dev_set_drvdata(dev, drm); + dev_set_drvdata(dev, drm); /* Load driver */ ret = kmb_load(drm, 0); @@ -461,7 +461,7 @@ static int kmb_probe(struct platform_device *pdev) drm_mode_config_cleanup(drm); dev_set_drvdata(dev, NULL); drm_dev_put(drm); - mipi_dsi_host_unregister(dsi_host); + dsi_host_unregister(); return ret; } diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 54780ec..1150505 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -11,7 +11,6 @@ #define KMB_MAX_WIDTH 16384 /*max width in pixels */ #define KMB_MAX_HEIGHT 16384 /*max height in pixels */ -extern struct mipi_dsi_host *dsi_host; struct kmb_drm_private { struct drm_device drm; void __iomem*lcd_mmio; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 70bb231..4ec1753 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -59,7 +59,7 @@ #define PLL_M_MAX 623 #define PLL_FVCO_MAX 1250 -struct mipi_dsi_host *dsi_host; +static struct mipi_dsi_host *dsi_host; static struct mipi_dsi_device *dsi_device; /* @@ -337,8 +337,13 @@ struct drm_bridge *kmb_dsi_host_bridge_init(struct device *dev) return bridge; } +void dsi_host_unregister(void) +{ + mipi_dsi_host_unregister(dsi_host); +} + u32 mipi_get_datatype_params(u32 data_type, u32 data_mode, -struct mipi_data_type_params *params) + struct mipi_data_type_params *params) { struct mipi_data_type_params data_type_parameters; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index e9bcc7e..811f3b8 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -313,6 +313,7 @@ struct drm_bridge *kmb_dsi_host_bridge_init(struct device *dev); int kmb_dsi_init(struct drm_device *dev, struct drm_bridge *bridge); void kmb_plane_destroy(struct drm_plane *plane); void mipi_tx_handle_irqs(struct kmb_drm_private *dev_p); +void dsi_host_unregister(void); #define to_kmb_connector(x) container_of(x, struct kmb_connector, base) #define to_kmb_host(x) container_of(x, struct kmb_dsi_host, base) -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 19/59] drm/kmb: Added ioremap/iounmap for register access
Register physical addresses are remapped and the register mmio addresses for lcd,mipi and msscam are saved in drm_private. All register reads/writes are updated to get the mmio offset from this structure. We are using hardcoded values for register physical addresses and this will be modified to read from device tree in the future. v2: minor code review changes v3: upclassed dev_private Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 59 +++--- drivers/gpu/drm/kmb/kmb_drv.c | 104 --- drivers/gpu/drm/kmb/kmb_drv.h | 64 --- drivers/gpu/drm/kmb/kmb_dsi.c | 401 +--- drivers/gpu/drm/kmb/kmb_plane.c | 35 ++-- drivers/gpu/drm/kmb/kmb_regs.h | 106 ++- 6 files changed, 441 insertions(+), 328 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 984f21a..5c1e858 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -31,21 +31,28 @@ static void kmb_crtc_cleanup(struct drm_crtc *crtc) static int kmb_crtc_enable_vblank(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + struct kmb_drm_private *dev_p = to_kmb(dev); + /*clear interrupt */ - kmb_write_lcd(LCD_INT_CLEAR, LCD_INT_VERT_COMP); + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_VERT_COMP); /*set which interval to generate vertical interrupt */ - kmb_write_lcd(LCD_VSTATUS_COMPARE, LCD_VSTATUS_COMPARE_VSYNC); + kmb_write_lcd(dev_p, LCD_VSTATUS_COMPARE, + LCD_VSTATUS_COMPARE_VSYNC); /* enable vertical interrupt */ - kmb_write_lcd(LCD_INT_ENABLE, LCD_INT_VERT_COMP); + kmb_write_lcd(dev_p, LCD_INT_ENABLE, LCD_INT_VERT_COMP); return 0; } static void kmb_crtc_disable_vblank(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + struct kmb_drm_private *dev_p = to_kmb(dev); + /*clear interrupt */ - kmb_write_lcd(LCD_INT_CLEAR, LCD_INT_VERT_COMP); + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_VERT_COMP); /* disable vertical interrupt */ - kmb_write_lcd(LCD_INT_ENABLE, 0); + kmb_write_lcd(dev_p, LCD_INT_ENABLE, 0); /* TBD * set the BIT2 (VERTICAL_COMPARE_INTERRUPT) of the LCD_INT_ENABLE register @@ -68,10 +75,12 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = { static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct drm_display_mode *m = &crtc->state->adjusted_mode; + struct drm_device *dev = crtc->dev; struct videomode vm; int vsync_start_offset; int vsync_end_offset; unsigned int ctrl = 0; + struct kmb_drm_private *dev_p = to_kmb(dev); vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; @@ -83,30 +92,38 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; - kmb_write_lcd(LCD_V_ACTIVEHEIGHT, m->crtc_vdisplay - 1); - kmb_write_lcd(LCD_V_BACKPORCH, vm.vback_porch - 1); - kmb_write_lcd(LCD_V_FRONTPORCH, vm.vfront_porch - 1); - kmb_write_lcd(LCD_VSYNC_WIDTH, vm.vsync_len - 1); - kmb_write_lcd(LCD_H_ACTIVEWIDTH, m->crtc_hdisplay - 1); - kmb_write_lcd(LCD_H_BACKPORCH, vm.hback_porch - 1); - kmb_write_lcd(LCD_H_FRONTPORCH, vm.hfront_porch - 1); - kmb_write_lcd(LCD_HSYNC_WIDTH, vm.hsync_len - 1); + kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT, + m->crtc_vdisplay - 1); + kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch - 1); + kmb_write_lcd(dev_p, LCD_V_FRONTPORCH, vm.vfront_porch - 1); + kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH, vm.vsync_len - 1); + kmb_write_lcd(dev_p, LCD_H_ACTIVEWIDTH, + m->crtc_hdisplay - 1); + kmb_write_lcd(dev_p, LCD_H_BACKPORCH, vm.hback_porch - 1); + kmb_write_lcd(dev_p, LCD_H_FRONTPORCH, vm.hfront_porch - 1); + kmb_write_lcd(dev_p, LCD_HSYNC_WIDTH, vm.hsync_len - 1); if (m->flags == DRM_MODE_FLAG_INTERLACE) { - kmb_write_lcd(LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); - kmb_write_lcd(LCD_V_BACKPORCH_EVEN, vm.vback_porch - 1); - kmb_write_lcd(LCD_V_FRONTPORCH_EVEN, vm.vfront_porch - 1); - kmb_write_lcd(LCD_V_ACTIVEHEIGHT_EVEN, m->crtc_vdisplay - 1); - kmb_write_lcd(LCD_VSYNC_START_EVEN, vsync_start_offset); - kmb_write_lcd(LCD_VSYNC_END_EVEN, vsync_end_offset); + kmb_write_lcd(dev_p, + LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); + kmb_write_lcd(dev_p, + LCD_V_BACKPORCH_EVEN, vm.vback_porch - 1); + kmb_write_lcd(dev_p, + LCD_V_FRONTPORCH_
[PATCH v2 13/59] drm/kmb: Part4 of Mipi Tx Initialization
This initializes the mipi high speed transmitter CTRL and SYNC configuration registers. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 55 -- drivers/gpu/drm/kmb/kmb_regs.h | 29 +- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index a5b9681..a685a7a 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -533,6 +533,55 @@ static void mipi_tx_multichannel_fifo_cfg(u8 active_lanes, u8 vchannel_id) kmb_set_bit_mipi(MIPI_TXm_HS_MC_FIFO_CTRL_EN(ctrl_no), vchannel_id); } +static void mipi_tx_ctrl_cfg(u8 fg_id, struct mipi_ctrl_cfg *ctrl_cfg) +{ + u32 sync_cfg = 0, ctrl = 0, fg_en; + u32 ctrl_no = MIPI_CTRL6; + + /*MIPI_TX_HS_SYNC_CFG*/ + if (ctrl_cfg->tx_ctrl_cfg.line_sync_pkt_en) + sync_cfg |= LINE_SYNC_PKT_ENABLE; + if (ctrl_cfg->tx_ctrl_cfg.frame_counter_active) + sync_cfg |= FRAME_COUNTER_ACTIVE; + if (ctrl_cfg->tx_ctrl_cfg.line_counter_active) + sync_cfg |= LINE_COUNTER_ACTIVE; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->v_blanking) + sync_cfg |= DSI_V_BLANKING; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->hsa_blanking) + sync_cfg |= DSI_HSA_BLANKING; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->hbp_blanking) + sync_cfg |= DSI_HBP_BLANKING; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->hfp_blanking) + sync_cfg |= DSI_HFP_BLANKING; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->sync_pulse_eventn) + sync_cfg |= DSI_SYNC_PULSE_EVENTN; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->lpm_first_vsa_line) + sync_cfg |= DSI_LPM_FIRST_VSA_LINE; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->lpm_last_vfp_line) + sync_cfg |= DSI_LPM_LAST_VFP_LINE; + /* enable frame generator */ + fg_en = 1 << fg_id; + sync_cfg |= FRAME_GEN_EN(fg_en); + if (ctrl_cfg->tx_ctrl_cfg.tx_always_use_hact) + sync_cfg |= ALWAYS_USE_HACT(fg_en); + if (ctrl_cfg->tx_ctrl_cfg.tx_hact_wait_stop) + sync_cfg |= HACT_WAIT_STOP(fg_en); + + /* MIPI_TX_HS_CTRL*/ + ctrl = HS_CTRL_EN | TX_SOURCE; /* type:DSI,source:LCD */ + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->eotp_en) + ctrl |= DSI_EOTP_EN; + if (ctrl_cfg->tx_ctrl_cfg.tx_dsi_cfg->hfp_blank_en) + ctrl |= DSI_CMD_HFP_EN; + ctrl |= LCD_VC(fg_id); + ctrl |= ACTIVE_LANES(ctrl_cfg->active_lanes - 1); + /*67 ns stop time*/ + ctrl |= HSEXIT_CNT(0x43); + + kmb_write_mipi(MIPI_TXm_HS_SYNC_CFG(ctrl_no), sync_cfg); + kmb_write_mipi(MIPI_TXm_HS_CTRL(ctrl_no), ctrl); +} + static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_priv, struct mipi_ctrl_cfg *ctrl_cfg) { @@ -576,8 +625,7 @@ static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_priv, /* set frame specific parameters */ mipi_tx_fg_cfg(dev_priv, frame_id, ctrl_cfg->active_lanes, bits_per_pclk, - word_count, - ctrl_cfg->lane_rate_mbps, + word_count, ctrl_cfg->lane_rate_mbps, ctrl_cfg->tx_ctrl_cfg.frames[frame_id]); active_vchannels++; @@ -592,6 +640,9 @@ static u32 mipi_tx_init_cntrl(struct kmb_drm_private *dev_priv, return -EINVAL; /*Multi-Channel FIFO Configuration*/ mipi_tx_multichannel_fifo_cfg(ctrl_cfg->active_lanes, frame_id); + + /*Frame Generator Enable */ + mipi_tx_ctrl_cfg(frame_id, ctrl_cfg); return ret; } diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index ef6b4ee..2d25c50 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -378,7 +378,35 @@ #define MIPI_CTRL_HS_BASE_ADDR (0x400) #define MIPI_TX_HS_CTRL(0x0) +#define MIPI_TXm_HS_CTRL(M) (MIPI_TX_HS_CTRL + (0x400*M)) +#define HS_CTRL_EN (1 << 0) +#define HS_CTRL_CSIDSIN (1 << 2) /*1:CSI 0:DSI*/ +#define TX_SOURCE(1 << 3) /*1:LCD, 0:DMA*/ +#define ACTIVE_LANES(n) ((n) << 4) +#define LCD_VC(ch) ((ch) << 8) +#define DSI_EOTP_EN (1 << 11) +#define DSI_CMD_HFP_EN (1 << 12) +#define CRC_EN (1 << 14) +#define HSEXIT_CNT(n)((n) << 16) +#define HSCLKIDLE_CNT(1 << 24) #define MIPI_TX_HS_SYNC_CFG(0x8) +#define MIPI_TXm_HS_SYNC_CFG(M) (MIPI_TX_HS
[PATCH v2 52/59] drm/kmb: Cleaned up code
From: Edmund Dea to remove compiler warnings and general clean up v2: minor code review changes v3: upclassed dev_private, corrected spelling Signed-off-by: Edmund Dea --- drivers/gpu/drm/kmb/kmb_crtc.c | 46 +- drivers/gpu/drm/kmb/kmb_crtc.h |6 +- drivers/gpu/drm/kmb/kmb_drv.c | 111 ++-- drivers/gpu/drm/kmb/kmb_drv.h | 107 ++-- drivers/gpu/drm/kmb/kmb_dsi.c | 1074 +-- drivers/gpu/drm/kmb/kmb_dsi.h | 84 ++- drivers/gpu/drm/kmb/kmb_plane.c | 155 ++ drivers/gpu/drm/kmb/kmb_plane.h | 74 ++- drivers/gpu/drm/kmb/kmb_regs.h | 29 +- 9 files changed, 894 insertions(+), 792 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index c390bbe..aceca94 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -39,10 +39,10 @@ static int kmb_crtc_enable_vblank(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_VERT_COMP); /*set which interval to generate vertical interrupt */ kmb_write_lcd(dev_p, LCD_VSTATUS_COMPARE, - LCD_VSTATUS_COMPARE_VSYNC); + LCD_VSTATUS_COMPARE_VSYNC); /* enable vertical interrupt */ kmb_set_bitmask_lcd(dev_p, LCD_INT_ENABLE, - LCD_INT_VERT_COMP); + LCD_INT_VERT_COMP); return 0; } @@ -83,38 +83,38 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) /* initialize mipi */ kmb_dsi_hw_init(dev, m); DRM_INFO("vfp= %d vbp= %d vsyc_len=%d hfp=%d hbp=%d hsync_len=%d\n", - m->crtc_vsync_start - m->crtc_vdisplay, - m->crtc_vtotal - m->crtc_vsync_end, - m->crtc_vsync_end - m->crtc_vsync_start, - m->crtc_hsync_start - m->crtc_hdisplay, - m->crtc_htotal - m->crtc_hsync_end, - m->crtc_hsync_end - m->crtc_hsync_start); +m->crtc_vsync_start - m->crtc_vdisplay, +m->crtc_vtotal - m->crtc_vsync_end, +m->crtc_vsync_end - m->crtc_vsync_start, +m->crtc_hsync_start - m->crtc_hdisplay, +m->crtc_htotal - m->crtc_hsync_end, +m->crtc_hsync_end - m->crtc_hsync_start); val = kmb_read_lcd(dev_p, LCD_INT_ENABLE); kmb_clr_bitmask_lcd(dev_p, LCD_INT_ENABLE, val); kmb_set_bitmask_lcd(dev_p, LCD_INT_CLEAR, ~0x0); -// vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; +// vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; vm.vfront_porch = 2; -// vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; +// vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; vm.vback_porch = 2; -// vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; +// vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; vm.vsync_len = 1; //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; vm.hfront_porch = 0; vm.hback_porch = 0; //vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; vm.hsync_len = 7; -// vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; +// vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; - DRM_INFO("%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hysnc-l=%d\n", - __func__, __LINE__, m->crtc_vdisplay, - vm.vback_porch, vm.vfront_porch, - vm.vsync_len, m->crtc_hdisplay, - vm.hback_porch, vm.hfront_porch, vm.hsync_len); + DRM_DEBUG + ("%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hysnc-l=%d", +__func__, __LINE__, m->crtc_vdisplay, vm.vback_porch, +vm.vfront_porch, vm.vsync_len, m->crtc_hdisplay, vm.hback_porch, +vm.hfront_porch, vm.hsync_len); kmb_write_lcd(dev_p, LCD_V_ACTIVEHEIGHT, - m->crtc_vdisplay - 1); + m->crtc_vdisplay - 1); kmb_write_lcd(dev_p, LCD_V_BACKPORCH, vm.vback_porch); kmb_write_lcd(dev_p, LCD_V_FRONTPORCH, vm.vfront_porch); kmb_write_lcd(dev_p, LCD_VSYNC_WIDTH, vm.vsync_len - 1); @@ -129,14 +129,14 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) if (m->flags == DRM_MODE_FLAG_INTERLACE) { kmb_write_lcd(dev_p, - LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); + LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); kmb_write_lcd(dev_p, LCD_V_BACKPORCH_EVEN, vm.vback_porch); kmb_write_lcd(dev_p, LCD_V_FRONTPORCH_EVEN, vm.vfront_porch);
[PATCH v2 53/59] drm/kmb: disable the LCD layer in EOF irq handler
When disabling/enabling LCD layers, the change takes effect immediately and does not wait for EOF (end of frame). If we disable an LCD layer in kmb_plane_atomic_disable, then the frame reappears with incorrect display offsets. The solution is to mark the plane as disabled when kmb_plane_atomic_disable is called but actually disable the LCD layer when EOF irq is being handled. Also only enable one plane (video plane0) as there is no use case for multiple planes. v2: Moved extern to .h, removed license text, upclassed dev_private. Signed-off-by: Anitha Chrisanthus Signed-off-by: Edmund Dea Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 36 +--- drivers/gpu/drm/kmb/kmb_drv.h | 1 + drivers/gpu/drm/kmb/kmb_plane.c | 24 drivers/gpu/drm/kmb/kmb_plane.h | 11 ++- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index f5e1def..55574c1 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -347,25 +347,47 @@ static void kmb_setup_mode_config(struct drm_device *drm) static irqreturn_t handle_lcd_irq(struct drm_device *dev) { unsigned long status, val; + int plane_id; struct kmb_drm_private *dev_p = to_kmb(dev); status = kmb_read_lcd(dev_p, LCD_INT_STATUS); if (status & LCD_INT_EOF) { - /*To DO - handle EOF interrupt? */ - kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_EOF); + /* TODO - handle EOF interrupt? */ + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_EOF); + + /* When disabling/enabling LCD layers, the change takes effect +* immediately and does not wait for EOF (end of frame). +* When kmb_plane_atomic_disable is called, mark the plane as +* disabled but actually disable the plane when EOF irq is +* being handled. +*/ + for (plane_id = LAYER_0; plane_id < KMB_MAX_PLANES; + plane_id++) { + if (plane_status[plane_id].disable) { + kmb_clr_bitmask_lcd(dev_p, + LCD_LAYERn_DMA_CFG(plane_id), + LCD_DMA_LAYER_ENABLE); + + kmb_clr_bitmask_lcd(dev_p, LCD_CONTROL, + plane_status[plane_id].ctrl); + + plane_status[plane_id].disable = false; + } + } } + if (status & LCD_INT_LINE_CMP) { /* clear line compare interrupt */ - kmb_write_lcd(dev_p, LCD_INT_CLEAR, - LCD_INT_LINE_CMP); + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_LINE_CMP); } + if (status & LCD_INT_LAYER) { /* Clear layer interrupts */ - kmb_write_lcd(dev->dev_private, LCD_INT_CLEAR, LCD_INT_LAYER); + kmb_write_lcd(dev_p, LCD_INT_CLEAR, LCD_INT_LAYER); } if (status & LCD_INT_VERT_COMP) { - /* read VSTATUS */ + /* Read VSTATUS */ val = kmb_read_lcd(dev_p, LCD_VSTATUS); val = (val & LCD_VSTATUS_VERTICAL_STATUS_MASK); switch (val) { @@ -382,7 +404,7 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev) } /* Clear all interrupts */ - kmb_set_bitmask_lcd(dev->dev_private, LCD_INT_CLEAR, ~0x0); + kmb_set_bitmask_lcd(dev_p, LCD_INT_CLEAR, 1); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 4b97a3d..94b62b9 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -19,6 +19,7 @@ #define crtc_to_kmb_priv(x)container_of(x, struct kmb_drm_private, crtc) + struct kmb_drm_private { struct drm_device drm; void __iomem *lcd_mmio; diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index f92e191..8b2b202 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -21,6 +21,8 @@ #include "kmb_plane.h" #include "kmb_regs.h" +struct layer_status plane_status[KMB_MAX_PLANES]; + const uint32_t layer_irqs[] = { LCD_INT_VL0, LCD_INT_VL1, @@ -62,34 +64,24 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *state) { struct kmb_plane *kmb_plane = to_kmb_plane(plane); - int ctrl = 0; - struct kmb_drm_private *dev_p; - int plane_id; - - dev_p = to_kmb(plane->dev); - plane_id = kmb_plane->id; + int plane_id = kmb_plane->id; switch (plane_id) { case LAYER_0: - ctrl = LCD_CTRL_VL1_ENABLE; + plane_status[plan
[PATCH v2 29/59] drm/kmb: Defer Probe
Register DSI host first and then defer probe until ADV bridge is initialized. Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_drv.c | 144 ++ drivers/gpu/drm/kmb/kmb_dsi.c | 46 -- drivers/gpu/drm/kmb/kmb_dsi.h | 3 +- 3 files changed, 89 insertions(+), 104 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index d13552a..36edfbf 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -36,6 +36,8 @@ static irqreturn_t kmb_isr(int irq, void *arg); static struct clk *clk_lcd; static struct clk *clk_mipi; +static int probe_deferred; + static int kmb_display_clk_enable(void) { clk_prepare_enable(clk_lcd); @@ -56,12 +58,11 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) { struct kmb_drm_private *dev_p = to_kmb(drm); struct platform_device *pdev = to_platform_device(drm->dev); - struct drm_bridge *bridge; +/* struct drm_bridge *bridge;*/ /*struct resource *res;*/ /*u32 version;*/ - int irq_lcd, irq_mipi; int ret; - struct device_node *encoder_node; +/* struct device_node *encoder_node;*/ /* TBD - not sure if clock_get needs to be called here */ /* @@ -73,9 +74,10 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) * TBD call this in the future when device tree is ready, * use hardcoded value for now */ - /*res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -*dev_p->lcd_mmio = devm_ioremap_resource(drm->dev, res); -* + /* +* res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +* dev_p->lcd_mmio = devm_ioremap_resource(drm->dev, res); + *if (IS_ERR(dev_p->lcd_mmio)) { * DRM_ERROR("failed to map control registers area\n"); * ret = PTR_ERR(dev_p->lcd_mmio); @@ -83,7 +85,10 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) * return ret; *} */ -/* LCD mmio */ + /* LCD mmio */ + if (!probe_deferred) { + probe_deferred = 1; + if (!request_mem_region(LCD_BASE_ADDR, LCD_MMIO_SIZE, "kmb-lcd")) { DRM_ERROR("failed to reserve LCD registers\n"); return -ENOMEM; @@ -93,7 +98,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_ERROR("failed to map LCD registers\n"); return -ENOMEM; } - /* Mipi mmio */ if (!request_mem_region(MIPI_BASE_ADDR, MIPI_MMIO_SIZE, "kmb-mipi")) { DRM_ERROR("failed to reserve MIPI registers\n"); @@ -106,35 +110,16 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) iounmap(dev_p->lcd_mmio); return -ENOMEM; } - /*this is only for MIPI_TX_MSS_LCD_MIPI_CFG register */ - dev_p->msscam_mmio = ioremap_cache(MSS_CAM_BASE_ADDR, + if (!dev_p->msscam_mmio) { + dev_p->msscam_mmio = ioremap_cache(MSS_CAM_BASE_ADDR, MSS_CAM_MMIO_SIZE); + } /* register irqs here - section 17.3 in databook * lists LCD at 79 and 82 for MIPI under MSS CPU - * firmware has to redirect it to A53 */ - irq_lcd = platform_get_irq_byname(pdev, "irq_lcd"); - if (irq_lcd < 0) { - DRM_ERROR("irq_lcd not found"); - return irq_lcd; - } - pr_info("irq_lcd platform_get_irq = %d\n", irq_lcd); - ret = request_irq(irq_lcd, kmb_isr, IRQF_SHARED, "irq_lcd", dev_p); - dev_p->irq_lcd = irq_lcd; - - irq_mipi = platform_get_irq_byname(pdev, "irq_mipi"); - if (irq_mipi < 0) { - DRM_ERROR("irq_mipi not found"); - return irq_mipi; - } - pr_info("irq_mipi platform_get_irq = %d\n", irq_mipi); - ret = request_irq(irq_mipi, kmb_isr, IRQF_SHARED, "irq_mipi", dev_p); - dev_p->irq_mipi = irq_mipi; - - - /*TBD read and check for correct product version here */ /* Get the optional framebuffer memory resource */ @@ -149,52 +134,35 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } - /* find ADV7535 node and initialize it */ - encoder_node = of_parse_phandle(drm->dev->of_node, "encoder-slave", 0); - if (!encoder_node) { - DRM_ERROR("failed to get bridge info from DT\n"); - ret = -EPROBE_DEFER; - goto setup_fail; - } - - /* Locate drm bridge from the hdmi encoder DT node */ - bridge = of_drm_find_bridge(encoder_node); - if (!bridge) { - DRM_ERROR("failed to get bridge driver from DT\n"); - ret = -EPROBE_DEFER; - goto setup_fail; - } - - of_node_put(encoder_node); - - ret = kmb_dsi_init
[PATCH v2 51/59] drm/kmb: Write to LCD_LAYERn_CFG only once
From: Edmund Dea Video artifacts appear during playback as horizontal lines that sporadically appear every few frames. Issue was caused by writing to LCD_LAYERn_CFG register twice during plane updates. Issue is fixed by writing to LCD_LAYERn_CFG only once. Removed plane_init_status so that there are no initialization dependencies during plane updates. Signed-off-by: Edmund Dea Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 81 +++-- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 6be0997..bf93986 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -98,7 +98,6 @@ static const u32 csc_coef_lcd[] = { }; /*plane initialization status */ -static int plane_init_status[KMB_MAX_PLANES] = { 0, 0, 0, 0 }; static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) { @@ -301,7 +300,6 @@ static void config_csc(struct kmb_drm_private *dev_p, int plane_id) kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF1(plane_id), csc_coef_lcd[9]); kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF2(plane_id), csc_coef_lcd[10]); kmb_write_lcd(dev_p, LCD_LAYERn_CSC_OFF3(plane_id), csc_coef_lcd[11]); - kmb_set_bitmask_lcd(dev_p, LCD_LAYERn_CFG(plane_id), LCD_LAYER_CSC_EN); } #endif @@ -390,19 +388,27 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, addr[V_PLANE]); } } - if (plane_init_status[plane_id] != INITIALIZED) { - kmb_write_lcd(dev_p, LCD_LAYERn_WIDTH(plane_id), src_w - 1); - kmb_write_lcd(dev_p, LCD_LAYERn_HEIGHT(plane_id), src_h - 1); - kmb_write_lcd(dev_p, LCD_LAYERn_COL_START(plane_id), crtc_x); - kmb_write_lcd(dev_p, LCD_LAYERn_ROW_START(plane_id), crtc_y); - - val = set_pixel_format(fb->format->format); - val |= set_bits_per_pixel(fb->format); - /*CHECKME Leon drvr sets it to 100 try this for now */ - val |= LCD_LAYER_FIFO_100; - kmb_write_lcd(dev_p, LCD_LAYERn_CFG(plane_id), val); - - switch (plane_id) { + + kmb_write_lcd(dev_p, LCD_LAYERn_WIDTH(plane_id), src_w-1); + kmb_write_lcd(dev_p, LCD_LAYERn_HEIGHT(plane_id), src_h-1); + kmb_write_lcd(dev_p, LCD_LAYERn_COL_START(plane_id), crtc_x); + kmb_write_lcd(dev_p, LCD_LAYERn_ROW_START(plane_id), crtc_y); + + val = set_pixel_format(fb->format->format); + val |= set_bits_per_pixel(fb->format); + /*CHECKME Leon drvr sets it to 100 try this for now */ + val |= LCD_LAYER_FIFO_100; + + if (val & LCD_LAYER_PLANAR_STORAGE) { + val |= LCD_LAYER_CSC_EN; + + /*enable CSC if input is planar and output is RGB */ + config_csc(dev_p, plane_id); + } + + kmb_write_lcd(dev_p, LCD_LAYERn_CFG(plane_id), val); + + switch (plane_id) { case LAYER_0: ctrl = LCD_CTRL_VL1_ENABLE; break; @@ -415,36 +421,28 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, case LAYER_3: ctrl = LCD_CTRL_GL2_ENABLE; break; - } + } - ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE - | LCD_CTRL_CONTINUOUS | LCD_CTRL_OUTPUT_ENABLED; + ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE + | LCD_CTRL_CONTINUOUS | LCD_CTRL_OUTPUT_ENABLED; - /*LCD is connected to MIPI on kmb -* Therefore this bit is required for DSI Tx -*/ - ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; + /*LCD is connected to MIPI on kmb +* Therefore this bit is required for DSI Tx +*/ + ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; - kmb_set_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); + kmb_set_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); - /* FIXME no doc on how to set output format,these values are -* taken from the Myriadx tests -*/ - out_format |= LCD_OUTF_FORMAT_RGB888; + /* FIXME no doc on how to set output format,these values are +* taken from the Myriadx tests +*/ + out_format |= LCD_OUTF_FORMAT_RGB888; - if (val & LCD_LAYER_PLANAR_STORAGE) { - /*enable CSC if input is planar and output is RGB */ - config_csc(dev_p, plane_id); - } - - /*set background color to white */ - // kmb_write_lcd(dev_p, LCD_BG_COLOUR_LS, 0xff); - /*leave RGB order,conversion mode and clip mode to default */ - /* do not interleave RGB channels for mipi Tx compatibility */ - out_format |= LCD_OUTF_MI
[PATCH v2 59/59] drm/kmb: work around for planar formats
Set the DMA Vstride and Line width for U and V planes to the same as the Y plane and not the actual pitch. Bit18 of layer config does not have any effect when U and V planes are swapped, so swap it in the driver. Signed-off-by: Anitha Chrisanthus Reviewed-by: Edmund Dea --- drivers/gpu/drm/kmb/kmb_plane.c | 50 - 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index de225a8..e35d732 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -170,6 +170,8 @@ unsigned int set_pixel_format(u32 format) val = LCD_LAYER_FORMAT_RGBA; break; } + DRM_INFO_ONCE("%s : %d format=0x%x val=0x%x\n", +__func__, __LINE__, format, val); return val; } @@ -280,38 +282,48 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, dev_p->fb_addr = addr[Y_PLANE]; kmb_write_lcd(dev_p, LCD_LAYERn_DMA_START_ADDR(plane_id), addr[Y_PLANE] + fb->offsets[0]); + val = set_pixel_format(fb->format->format); + val |= set_bits_per_pixel(fb->format); /* Program Cb/Cr for planar formats */ if (num_planes > 1) { - if (fb->format->format == DRM_FORMAT_YUV420 || - fb->format->format == DRM_FORMAT_YVU420) - width /= 2; - kmb_write_lcd(dev_p, LCD_LAYERn_DMA_CB_LINE_VSTRIDE(plane_id), - fb->pitches[LAYER_1]); - + width*fb->format->cpp[0]); kmb_write_lcd(dev_p, LCD_LAYERn_DMA_CB_LINE_WIDTH(plane_id), (width * fb->format->cpp[0])); addr[U_PLANE] = drm_fb_cma_get_gem_addr(fb, plane->state, - U_PLANE); - kmb_write_lcd(dev_p, LCD_LAYERn_DMA_START_CB_ADR(plane_id), - addr[U_PLANE]); + U_PLANE); + /* check if Cb/Cr is swapped*/ + if ((num_planes == 3) && (val & LCD_LAYER_CRCB_ORDER)) + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_START_CR_ADR(plane_id), + addr[U_PLANE]); + else + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_START_CB_ADR(plane_id), + addr[U_PLANE]); if (num_planes == 3) { kmb_write_lcd(dev_p, - LCD_LAYERn_DMA_CR_LINE_VSTRIDE(plane_id), - fb->pitches[LAYER_2]); + LCD_LAYERn_DMA_CR_LINE_VSTRIDE(plane_id), + ((width)*fb->format->cpp[0])); kmb_write_lcd(dev_p, - LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), - (width * fb->format->cpp[0])); + LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), + ((width)*fb->format->cpp[0])); addr[V_PLANE] = drm_fb_cma_get_gem_addr(fb, - plane->state, - V_PLANE); - kmb_write_lcd(dev_p, - LCD_LAYERn_DMA_START_CR_ADR(plane_id), - addr[V_PLANE]); + plane->state, V_PLANE); + + /* check if Cb/Cr is swapped*/ + if (val & LCD_LAYER_CRCB_ORDER) + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_START_CB_ADR(plane_id), + addr[V_PLANE]); + else + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_START_CR_ADR(plane_id), + addr[V_PLANE]); } } @@ -320,8 +332,6 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, kmb_write_lcd(dev_p, LCD_LAYERn_COL_START(plane_id), crtc_x); kmb_write_lcd(dev_p, LCD_LAYERn_ROW_START(plane_id), crtc_y); - val = set_pixel_format(fb->format->format); - val |= set_bits_per_pixel(fb->format); /*CHECKME Leon drvr sets it to 100 try this for now */ val |= LCD_LAYER_FIFO_100; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 42/59] drm/kmb: Update LCD programming to match MIPI
Mipi input expects the memory layout to be unpacked with 8 bits per pixel in RGB (BRG) order. If the LCD is not configured properly, corrupted output results, changed dma_unpacked to 0 in mipi FG. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 6 +++--- drivers/gpu/drm/kmb/kmb_drv.h | 1 + drivers/gpu/drm/kmb/kmb_dsi.c | 27 +-- drivers/gpu/drm/kmb/kmb_dsi.h | 1 + drivers/gpu/drm/kmb/kmb_plane.c | 37 +++-- drivers/gpu/drm/kmb/kmb_regs.h | 1 + 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index cbf998f..a6a0444 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -87,16 +87,16 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_dsi_hw_init(dev); #ifdef LCD_TEST // vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; - vm.vfront_porch = 0; + vm.vfront_porch = 2; // vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; - vm.vback_porch = 0; + vm.vback_porch = 2; // vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; vm.vsync_len = 1; //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; vm.hfront_porch = 0; vm.hback_porch = 0; //vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end; - vm.hsync_len = 1; + vm.hsync_len = 7; // vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index aa77631..3a1b66c 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -30,6 +30,7 @@ struct kmb_drm_private { spinlock_t irq_lock; int irq_lcd; int irq_mipi; + dma_addr_t fb_addr; }; static inline struct kmb_drm_private *to_kmb(const struct drm_device *dev) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index a9f2d78..e01c4f9 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -25,6 +25,7 @@ static int hw_initialized; #define IMAGE_PATH "/home/root/1280x720.pnm" //#define MIPI_TX_TEST_PATTERN_GENERATION +//#define MIPI_DMA //#define RTL_TEST //#define IMG_WIDTH_PX 640 //#define IMG_HEIGHT_LINES 10 @@ -33,6 +34,7 @@ static int hw_initialized; /*MIPI TX CFG*/ //#define MIPI_TX_LANE_DATA_RATE_MBPS 1782 +//#define MIPI_TX_LANE_DATA_RATE_MBPS 800 #define MIPI_TX_LANE_DATA_RATE_MBPS 891 //#define MIPI_TX_LANE_DATA_RATE_MBPS 80 #define MIPI_TX_REF_CLK_KHZ 24000 @@ -80,14 +82,14 @@ static struct mipi_dsi_device *dsi_device; * these will eventually go to the device tree sections, * and can be used as a refernce later for device tree additions */ -//#define RES_1920x1080 +#define RES_1920x1080 #ifdef RES_1920x1080 #define IMG_HEIGHT_LINES 1080 #define IMG_WIDTH_PX 1920 #define MIPI_TX_ACTIVE_LANES 4 #endif -#define RES_1280x720 +//#define RES_1280x720 #ifdef RES_1280x720 #define IMG_HEIGHT_LINES 720 #define IMG_WIDTH_PX 1280 @@ -97,9 +99,9 @@ struct mipi_tx_frame_section_cfg mipi_tx_frame0_sect_cfg = { .width_pixels = IMG_WIDTH_PX, .height_lines = IMG_HEIGHT_LINES, .data_type = DSI_LP_DT_PPS_RGB888_24B, - //.data_mode = MIPI_DATA_MODE1, - .data_mode = MIPI_DATA_MODE0, - .dma_packed = 1 + .data_mode = MIPI_DATA_MODE1, +// .data_mode = MIPI_DATA_MODE0, + .dma_packed = 0 }; #ifdef RES_1920x1080 @@ -544,12 +546,15 @@ static u32 mipi_tx_fg_section_cfg_regs(struct kmb_drm_private *dev_p, << MIPI_TX_SECT_VC_SHIFT); /* bits [23:22] */ /* data mode */ cfg |= ((ph_cfg->data_mode & MIPI_TX_SECT_DM_MASK) - << MIPI_TX_SECT_DM_SHIFT); /* bits [24:25] */ - cfg |= MIPI_TX_SECT_DMA_PACKED; - DRM_INFO("%s : %d ctrl=%d frame_id=%d section=%d cfg=%x\n", -__func__, __LINE__, ctrl_no, frame_id, section, cfg); + << MIPI_TX_SECT_DM_SHIFT); /* bits [24:25]*/ + if (ph_cfg->dma_packed) + cfg |= MIPI_TX_SECT_DMA_PACKED; + DRM_INFO("%s : %d ctrl=%d frame_id=%d section=%d cfg=%x packed=%d\n", + __func__, __LINE__, ctrl_no, frame_id, section, cfg, + ph_cfg->dma_packed); kmb_write_mipi(dev_p, (MIPI_TXm_HS_FGn_SECTo_PH(ctrl_no, frame_id, - section)), cfg); + section)), cfg); + /*unpacked bytes */ /*there are 4 frame generators and each fg has 4 sections *there are 2 registers for unpacked bytes - @@ -601,6 +606,7 @@ static u32 mipi_tx_fg_
[PATCH v2 47/59] drm/kmb: Don’t inadvertantly disable LCD controller
setbits instead of write dword for LCD_CONTROL register this was inadvertantly disabling the LCD controller. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 3245ec7..1582ccf 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -158,6 +158,9 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane, kmb_clr_bitmask_lcd(dev_p, LCD_LAYERn_DMA_CFG(plane_id), LCD_DMA_LAYER_ENABLE); kmb_clr_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); + DRM_INFO("%s : %d lcd_ctrl = 0x%x lcd_int_enable=0x%x\n", + __func__, __LINE__, kmb_read_lcd(dev_p, LCD_CONTROL), + kmb_read_lcd(dev_p, LCD_INT_ENABLE)); } @@ -454,7 +457,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, */ ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; - kmb_write_lcd(dev_p, LCD_CONTROL, ctrl); + kmb_set_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); /* FIXME no doc on how to set output format,these values are taken * from the Myriadx tests -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 40/59] drm/kmb: Added LCD_TEST config
To run modetest without ADV driver, enable LCD_TEST and FCC_TEST. Also made front porches 0, and some changes in the plane init. v2: upclassed dev_private Signed-off-by: Anitha Chrisanthus --- drivers/gpu/drm/kmb/kmb_crtc.c | 13 +++ drivers/gpu/drm/kmb/kmb_drv.c | 6 +-- drivers/gpu/drm/kmb/kmb_drv.h | 3 +- drivers/gpu/drm/kmb/kmb_dsi.c | 85 +++-- drivers/gpu/drm/kmb/kmb_plane.c | 15 ++-- 5 files changed, 78 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 21b2d7f..f77e6f5 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -81,14 +81,15 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) struct videomode vm; int vsync_start_offset; int vsync_end_offset; - unsigned int ctrl = 0; struct kmb_drm_private *dev_p = to_kmb(dev); #endif /* initialize mipi */ kmb_dsi_hw_init(dev); #ifdef LCD_TEST - vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; - vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; +// vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay; + vm.vfront_porch = 0; +// vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end; + vm.vback_porch = 0; vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; //vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay; vm.hfront_porch = 0; @@ -131,12 +132,8 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) kmb_write_lcd(dev_p, LCD_VSYNC_END_EVEN, 10); } /* enable VL1 layer as default */ - ctrl = LCD_CTRL_ENABLE | LCD_CTRL_VL1_ENABLE; - ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE - | LCD_CTRL_OUTPUT_ENABLED; - kmb_write_lcd(dev_p, LCD_CONTROL, ctrl); - kmb_write_lcd(dev_p, LCD_TIMING_GEN_TRIG, ENABLE); + kmb_set_bitmask_lcd(dev_p, LCD_CONTROL, LCD_CTRL_ENABLE); #endif /* TBD */ /* set clocks here */ diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 3542de7..8bd3011 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -216,6 +216,8 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) #endif /* Set MIPI clock to 24 Mhz*/ DRM_INFO("Get clk_mipi before set = %ld\n", clk_get_rate(clk_mipi)); +//#define MIPI_CLK +#ifdef MIPI_CLK ret = clk_set_rate(clk_mipi, KMB_MIPI_DEFAULT_CLK); DRM_INFO("Get clk_mipi after set = %ld\n", clk_get_rate(clk_mipi)); if (clk_get_rate(clk_mipi) != KMB_MIPI_DEFAULT_CLK) { @@ -223,6 +225,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) KMB_MIPI_DEFAULT_CLK); goto setup_fail; } +#endif DRM_INFO("Setting MIPI clock to %d Mhz ret = %d\n", KMB_MIPI_DEFAULT_CLK/100, ret); DRM_INFO("Get clk_mipi after set = %ld\n", clk_get_rate(clk_mipi)); @@ -319,8 +322,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) DRM_ERROR("failed to initialize DSI\n"); goto setup_fail; } - - DRM_INFO("%s : %d\n", __func__, __LINE__); #ifdef WIP ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); if (ret < 0) { @@ -335,7 +336,6 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) drm_crtc_cleanup(&dev_p->crtc); #endif setup_fail: - DRM_INFO("%s : %d\n", __func__, __LINE__); of_reserved_mem_device_release(drm->dev); return ret; diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 7e6..89d7845 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -8,7 +8,8 @@ #include "kmb_regs.h" -/*#define FCCTEST*/ +#define FCCTEST +#define LCD_TEST #define KMB_MAX_WIDTH 1920 /*max width in pixels */ #define KMB_MAX_HEIGHT 1080 /*max height in pixels */ #define KMB_LCD_DEFAULT_CLK25000 diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 9da9d9f..c23719c 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -24,18 +24,19 @@ static int hw_initialized; #define IMAGE_PATH "/home/root/1280x720.pnm" -#define MIPI_TX_TEST_PATTERN_GENERATION +//#define MIPI_TX_TEST_PATTERN_GENERATION +//#define RTL_TEST +//#define IMG_WIDTH_PX 640 +//#define IMG_HEIGHT_LINES 10 -#define IMG_HEIGHT_LINES 720 -#define IMG_WIDTH_PX 1280 #define LCD_BYTESPP 1 /*MIPI TX CFG*/ -#define MIPI_TX_ACTIVE_LANES 2 //#define MIPI_TX_LANE_DATA_RATE_MBPS 1782 #define MIPI_TX_LANE_DATA_RATE_MBPS 891 //#define MIPI_TX_LANE_DATA_RATE_MBPS 80 #define MIPI_TX_REF_CLK_KHZ 24000 +//#define MIPI_TX_REF_CLK_KHZ 23809 #define MIPI_TX_CFG_CLK_KHZ
[PATCH v2 50/59] drm/kmb: Do the layer initializations only once
The issue was video starts fine, but towards the end, the color disappers. Do the layer initializations only once, but update the DMA registers for every frame. Also changed DRM_INFO to DRM_DEBUG. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 150 ++-- 1 file changed, 66 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index a1d616a..6be0997 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -97,6 +97,9 @@ static const u32 csc_coef_lcd[] = { -179, 125, -226 }; +/*plane initialization status */ +static int plane_init_status[KMB_MAX_PLANES] = { 0, 0, 0, 0 }; + static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) { int i; @@ -157,9 +160,9 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane, kmb_clr_bitmask_lcd(dev_p, LCD_LAYERn_DMA_CFG(plane_id), LCD_DMA_LAYER_ENABLE); kmb_clr_bitmask_lcd(dev_p, LCD_CONTROL, ctrl); - DRM_INFO("%s : %d lcd_ctrl = 0x%x lcd_int_enable=0x%x\n", -__func__, __LINE__, kmb_read_lcd(dev_p, LCD_CONTROL), -kmb_read_lcd(dev_p, LCD_INT_ENABLE)); + DRM_DEBUG("%s : %d lcd_ctrl = 0x%x lcd_int_enable=0x%x\n", + __func__, __LINE__, kmb_read_lcd(dev_p, LCD_CONTROL), + kmb_read_lcd(dev_p, LCD_INT_ENABLE)); } unsigned int set_pixel_format(u32 format) @@ -317,8 +320,6 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, unsigned int src_w, src_h, crtc_x, crtc_y; unsigned char plane_id; int num_planes; - /*plane initialization status */ - static int plane_init_status[KMB_MAX_PLANES] = { 0, 0, 0, 0 }; static dma_addr_t addr[MAX_SUB_PLANES] = { 0, 0, 0 }; if (!plane || !plane->state || !state) @@ -339,9 +340,56 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, crtc_x = plane->state->crtc_x; crtc_y = plane->state->crtc_y; - DRM_INFO + DRM_DEBUG ("%s : %d src_w=%d src_h=%d, fb->format->format=0x%x fb->flags=0x%x", __func__, __LINE__, src_w, src_h, fb->format->format, fb->flags); + + width = fb->width; + height = fb->height; + dma_len = (width * height * fb->format->cpp[0]); + DRM_DEBUG("%s : %d dma_len=%d ", __func__, __LINE__, dma_len); + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_LEN(plane_id), dma_len); + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_LEN_SHADOW(plane_id), dma_len); + + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_LINE_VSTRIDE(plane_id), + fb->pitches[0]); + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_LINE_WIDTH(plane_id), + (width * fb->format->cpp[0])); + + addr[Y_PLANE] = drm_fb_cma_get_gem_addr(fb, plane->state, 0); + dev_p->fb_addr = (dma_addr_t) addr; + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_START_ADDR(plane_id), + addr[Y_PLANE] + fb->offsets[0]); + /*program Cb/Cr for planar formats */ + if (num_planes > 1) { + if (fb->format->format == DRM_FORMAT_YUV420 || + fb->format->format == DRM_FORMAT_YVU420) + width /= 2; + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_CB_LINE_VSTRIDE(plane_id), + fb->pitches[LAYER_1]); + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_CB_LINE_WIDTH(plane_id), + (width * fb->format->cpp[0])); + addr[U_PLANE] = drm_fb_cma_get_gem_addr(fb, plane->state, + U_PLANE); + kmb_write_lcd(dev_p, LCD_LAYERn_DMA_START_CB_ADR(plane_id), + addr[U_PLANE]); + if (num_planes == 3) { + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_CR_LINE_VSTRIDE(plane_id), + fb->pitches[LAYER_2]); + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), + (width * fb->format->cpp[0])); + addr[V_PLANE] = drm_fb_cma_get_gem_addr(fb, + plane->state, + V_PLANE); + kmb_write_lcd(dev_p, + LCD_LAYERn_DMA_START_CR_ADR(plane_id), + addr[V_PLANE]); + } + } if (plane_init_status[plane_id] != INITIALIZED) { kmb_write_lcd(dev_p, LCD_LAYERn_WIDTH(plane_id), src_w - 1); kmb_write_lcd(dev_p, LCD_LAYERn_HEIGHT(plane_id), src_h - 1); @@
[PATCH v2 00/59] Add support for KeemBay DRM driver
This is a new DRM driver for Intel's KeemBay SOC. The SoC couples an ARM Cortex A53 CPU with an Intel Movidius VPU. This driver is tested with the KMB EVM board which is the refernce baord for Keem Bay SOC. The SOC's display pipeline is as follows +--++-++---+ |LCD controller| -> |Mipi DSI | -> |Mipi to HDMI Converter | +--++-++---+ LCD controller and Mipi DSI transmitter are part of the SOC and mipi to HDMI converter is ADV7535 for KMB EVM board. The DRM driver is a basic KMS atomic modesetting display driver and has no 2D or 3D graphics.It calls into the ADV bridge driver at the connector level. Only 1080p resolution and single plane is supported at this time. The usecase is for debugging video and camera outputs. Device tree patches are under review here https://lore.kernel.org/linux-arm-kernel/20200708175020.194436-1-daniele.alessandre...@linux.intel.com/T/ Changes since v1: - Removed redundant license text, updated license - Rearranged include blocks - renamed global vars and removed extern in c - Used upclassing for dev_private - Used drm_dev_init in drm device create (will be updated to use devm_drm_dev_alloc() in a separate patch later as kmb driver is currently developed on 5.4 kernel) - minor cleanups Anitha Chrisanthus (52): drm/kmb: Add support for KeemBay Display drm/kmb: Added id to kmb_plane drm/kmb: Set correct values in the LAYERn_CFG register drm/kmb: Use biwise operators for register definitions drm/kmb: Updated kmb_plane_atomic_check drm/kmb: Initial check-in for Mipi DSI drm/kmb: Set OUT_FORMAT_CFG register drm/kmb: Added mipi_dsi_host initialization drm/kmb: Part 1 of Mipi Tx Initialization drm/kmb: Part 2 of Mipi Tx Initialization drm/kmb: Use correct mmio offset from data book drm/kmb: Part3 of Mipi Tx initialization drm/kmb: Part4 of Mipi Tx Initialization drm/kmb: Correct address offsets for mipi registers drm/kmb: Part5 of Mipi Tx Intitialization drm/kmb: Part6 of Mipi Tx Initialization drm/kmb: Part7 of Mipi Tx Initialization drm/kmb: Part8 of Mipi Tx Initialization drm/kmb: Added ioremap/iounmap for register access drm/kmb: Register IRQ for LCD drm/kmb: IRQ handlers for LCD and mipi dsi drm/kmb: Set hardcoded values to LCD_VSYNC_START drm/kmb: Additional register programming to update_plane drm/kmb: Add ADV7535 bridge drm/kmb: Display clock enable/disable drm/kmb: rebase to newer kernel version drm/kmb: minor name change to match device tree drm/kmb: Changed MMIO size drm/kmb: Defer Probe drm/kmb: call bridge init in the very beginning drm/kmb: Enable MSS_CAM_CLK_CTRL for LCD and MIPI drm/kmb: Set MSS_CAM_RSTN_CTRL along with enable drm/kmb: Mipi DPHY initialization changes drm/kmb: Fixed driver unload drm/kmb: Added LCD_TEST config drm/kmb: Changes for LCD to Mipi drm/kmb: Update LCD programming to match MIPI drm/kmb: Changed name of driver to kmb-drm drm/kmb: Mipi settings from input timings drm/kmb: Enable LCD interrupts drm/kmb: Enable LCD interrupts during modeset drm/kmb: Don’t inadvertantly disable LCD controller drm/kmb: SWAP R and B LCD Layer order drm/kmb: Disable ping pong mode drm/kmb: Do the layer initializations only once drm/kmb: disable the LCD layer in EOF irq handler drm/kmb: Initialize uninitialized variables drm/kmb: Added useful messages in LCD ISR kmb/drm: Prune unsupported modes drm/kmb: workaround for dma undeflow issue drm/kmb: Get System Clock from SCMI drm/kmb: work around for planar formats Edmund Dea (7): drm/kmb: Cleanup probe functions drm/kmb: Revert dsi_host back to a static variable drm/kmb: Initialize clocks for clk_msscam, clk_mipi_ecfg, & clk_mipi_cfg. drm/kmb: Remove declaration of irq_lcd/irq_mipi drm/kmb: Enable MIPI TX HS Test Pattern Generation drm/kmb: Write to LCD_LAYERn_CFG only once drm/kmb: Cleaned up code drivers/gpu/drm/Kconfig |2 + drivers/gpu/drm/Makefile|1 + drivers/gpu/drm/kmb/Kconfig | 12 + drivers/gpu/drm/kmb/Makefile|2 + drivers/gpu/drm/kmb/kmb_crtc.c | 226 + drivers/gpu/drm/kmb/kmb_crtc.h | 41 + drivers/gpu/drm/kmb/kmb_drv.c | 809 drivers/gpu/drm/kmb/kmb_drv.h | 176 drivers/gpu/drm/kmb/kmb_dsi.c | 1927 +++ drivers/gpu/drm/kmb/kmb_dsi.h | 370 drivers/gpu/drm/kmb/kmb_plane.c | 518 +++ drivers/gpu/drm/kmb/kmb_plane.h | 124 +++ drivers/gpu/drm/kmb/kmb_regs.h | 738 +++ 13 files changed, 4946 insertions(+) create mode 100644 drivers/gpu/drm/kmb/Kconfig create mode 100644 drivers/gpu/drm/kmb/Makefile create mode 100644 drivers/gpu/drm/kmb/kmb_crtc.c create mode 100644 drivers/gpu/drm/kmb/kmb_crtc.h create mode 100644 drivers/gpu/drm/kmb/kmb_drv.c create mode 100644 drivers/gpu/drm/kmb/kmb_drv.h create mode 100644 drivers/gpu/drm/kmb/k
[PATCH v2 10/59] drm/kmb: Part 2 of Mipi Tx Initialization
Mipi TX Frame generator timing configuration Compute and set frame generator timings like hactive, front porch, back porch etc. v2: minor code review changes Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 132 - drivers/gpu/drm/kmb/kmb_regs.h | 37 2 files changed, 166 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index cb6082d..951a742 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -391,6 +391,123 @@ static u32 mipi_tx_fg_section_cfg(struct kmb_drm_private *dev_priv, return 0; } +static void mipi_tx_fg_cfg_regs(struct kmb_drm_private *dev_priv, + u8 frame_gen, + struct mipi_tx_frame_timing_cfg *fg_cfg) +{ + u32 sysclk; + /*float ppl_llp_ratio; */ + u32 ppl_llp_ratio; + u32 ctrl_no = MIPI_CTRL6, reg_adr, val, offset; + + /*Get system clock for blanking period cnfigurations */ + /*TODO need to get system clock from clock driver */ + /* Assume 700 Mhz system clock for now */ + sysclk = 700; + + /*ppl-pixel packing layer, llp-low level protocol +* frame genartor timing parameters are clocked on the system clock +* whereas as the equivalent parameters in the LLP blocks are clocked +* on LLP Tx clock from the D-PHY - BYTE clock +*/ + + /*multiply by 1000 to keep the precision */ + ppl_llp_ratio = ((fg_cfg->bpp / 8) * sysclk * 1000) / + ((fg_cfg->lane_rate_mbps / 8) * fg_cfg->active_lanes); + + /*frame generator number of lines */ + reg_adr = MIPI_TXm_HS_FGn_NUM_LINES(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, fg_cfg->v_active); + + /*vsync width */ + /* +*there are 2 registers for vsync width -VSA in lines for channels 0-3 +*REG_VSYNC_WIDTH0: [15:0]-VSA for channel0, [31:16]-VSA for channel1 +*REG_VSYNC_WIDTH1: [15:0]-VSA for channel2, [31:16]-VSA for channel3 +*/ + offset = (frame_gen % 2) * 16; + reg_adr = MIPI_TXm_HS_VSYNC_WIDTHn(ctrl_no, frame_gen); + kmb_write_bits(dev_priv, reg_adr, offset, 16, fg_cfg->vsync_width); + + /*v backporch - same register config like vsync width */ + reg_adr = MIPI_TXm_HS_V_BACKPORCHESn(ctrl_no, frame_gen); + kmb_write_bits(dev_priv, reg_adr, offset, 16, fg_cfg->v_backporch); + + /*v frontporch - same register config like vsync width */ + reg_adr = MIPI_TXm_HS_V_FRONTPORCHESn(ctrl_no, frame_gen); + kmb_write_bits(dev_priv, reg_adr, offset, 16, fg_cfg->v_frontporch); + + /*v active - same register config like vsync width */ + reg_adr = MIPI_TXm_HS_V_ACTIVEn(ctrl_no, frame_gen); + kmb_write_bits(dev_priv, reg_adr, offset, 16, fg_cfg->v_active); + + /*hsyc width */ + reg_adr = MIPI_TXm_HS_HSYNC_WIDTHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, + (fg_cfg->hsync_width * ppl_llp_ratio) / 1000); + + /*h backporch */ + reg_adr = MIPI_TXm_HS_H_BACKPORCHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, + (fg_cfg->h_backporch * ppl_llp_ratio) / 1000); + + /*h frontporch */ + reg_adr = MIPI_TXm_HS_H_FRONTPORCHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, + (fg_cfg->h_frontporch * ppl_llp_ratio) / 1000); + + /*h active */ + reg_adr = MIPI_TXm_HS_H_ACTIVEn(ctrl_no, frame_gen); + /*convert h_active which is wc in bytes to cycles */ + val = (fg_cfg->h_active * sysclk * 1000) / + ((fg_cfg->lane_rate_mbps / 8) * fg_cfg->active_lanes); + val /= 1000; + kmb_write(dev_priv, reg_adr, val); + + /* llp hsync width */ + reg_adr = MIPI_TXm_HS_LLP_HSYNC_WIDTHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, fg_cfg->hsync_width * (fg_cfg->bpp / 8)); + + /* llp h backporch */ + reg_adr = MIPI_TXm_HS_LLP_H_BACKPORCHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, fg_cfg->h_backporch * (fg_cfg->bpp / 8)); + + /* llp h frontporch */ + reg_adr = MIPI_TXm_HS_LLP_H_FRONTPORCHn(ctrl_no, frame_gen); + kmb_write(dev_priv, reg_adr, fg_cfg->h_frontporch * (fg_cfg->bpp / 8)); +} + +static void mipi_tx_fg_cfg(struct kmb_drm_private *dev_priv, u8 frame_gen, + u8 active_lanes, u32 bpp, u32 wc, + u32 lane_rate_mbps, struct mipi_tx_frame_cfg *fg_cfg) +{ + u32 i, fg_num_lines = 0; + struct mipi_tx_frame_timing_cfg fg_t_cfg; + + /*calculate the total frame generator number of lines based on it's +* active sections +*/ + for (i = 0; i < MIPI_TX_FRAME_GEN_SECTIONS; i++) { + if (fg_cfg->sections[i] != NULL) + fg_num_lines += fg_cfg->sections[i]->height_lines; +
[PATCH v2 04/59] drm/kmb: Use biwise operators for register definitions
Did some general clean up and organization. v2: corrected spelling Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_drv.c | 3 +- drivers/gpu/drm/kmb/kmb_regs.h | 852 +++-- 2 files changed, 307 insertions(+), 548 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 28aa625..11f8d1f 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -113,8 +113,7 @@ static irqreturn_t kmb_irq(int irq, void *arg) if (status & LCD_INT_VERT_COMP) { /* read VSTATUS */ val = kmb_read(lcd, LCD_VSTATUS); - /* BITS 13 and 14 */ - val = (val & LCD_VSTATUS_VERTICAL_STATUS_MASK) >> 12; + val = (val & LCD_VSTATUS_VERTICAL_STATUS_MASK); switch (val) { case LCD_VSTATUS_COMPARE_VSYNC: case LCD_VSTATUS_COMPARE_BACKPORCH: diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index 0f879b9..8346a04 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -6,35 +6,181 @@ #ifndef __KMB_REGS_H__ #define __KMB_REGS_H__ -/*LCD CONTROLLER REGISTERS */ -#define LCD_CONTROL(0x4 * 0x000) -#define LCD_INT_STATUS (0x4 * 0x001) -#define LCD_INT_ENABLE (0x4 * 0x002) -#define LCD_INT_CLEAR (0x4 * 0x003) -#define LCD_LINE_COUNT (0x4 * 0x004) -#define LCD_LINE_COMPARE (0x4 * 0x005) -#define LCD_VSTATUS(0x4 * 0x006) -#define LCD_VSTATUS_COMPARE(0x4 * 0x007) -#define LCD_SCREEN_WIDTH (0x4 * 0x008) -#define LCD_SCREEN_HEIGHT (0x4 * 0x009) -#define LCD_FIELD_INT_CFG (0x4 * 0x00a) -#define LCD_FIFO_FLUSH (0x4 * 0x00b) -#define LCD_BG_COLOUR_LS (0x4 * 0x00c) -#define LCD_BG_COLOUR_MS (0x4 * 0x00d) -#define LCD_RAM_CFG(0x4 * 0x00e) +#define ENABLE 1 +/*** + *LCD controller control register defines + ***/ +#define LCD_CONTROL(0x4 * 0x000) +#define LCD_CTRL_PROGRESSIVE (0<<0) +#define LCD_CTRL_INTERLACED (1<<0) +#define LCD_CTRL_ENABLE (1<<1) +#define LCD_CTRL_VL1_ENABLE (1<<2) +#define LCD_CTRL_VL2_ENABLE (1<<3) +#define LCD_CTRL_GL1_ENABLE (1<<4) +#define LCD_CTRL_GL2_ENABLE (1<<5) +#define LCD_CTRL_ALPHA_BLEND_VL1 (0<<6) +#define LCD_CTRL_ALPHA_BLEND_VL2 (1<<6) +#define LCD_CTRL_ALPHA_BLEND_GL1 (2<<6) +#define LCD_CTRL_ALPHA_BLEND_GL2 (3<<6) +#define LCD_CTRL_ALPHA_TOP_VL1 (0<<8) +#define LCD_CTRL_ALPHA_TOP_VL2 (1<<8) +#define LCD_CTRL_ALPHA_TOP_GL1 (2<<8) +#define LCD_CTRL_ALPHA_TOP_GL2 (3<<8) +#define LCD_CTRL_ALPHA_MIDDLE_VL1(0<<10) +#define LCD_CTRL_ALPHA_MIDDLE_VL2(1<<10) +#define LCD_CTRL_ALPHA_MIDDLE_GL1(2<<10) +#define LCD_CTRL_ALPHA_MIDDLE_GL2(3<<10) +#define LCD_CTRL_ALPHA_BOTTOM_VL1(0<<12) +#define LCD_CTRL_ALPHA_BOTTOM_VL2(1<<12) +#define LCD_CTRL_ALPHA_BOTTOM_GL1(2<<12) +#define LCD_CTRL_ALPHA_BOTTOM_GL2(3<<12) +#define LCD_CTRL_TIM_GEN_ENABLE (1<<14) +#define LCD_CTRL_DISPLAY_MODE_ONE_SHOT (1<<15) +#define LCD_CTRL_PWM0_EN (1<<16) +#define LCD_CTRL_PWM1_EN (1<<17) +#define LCD_CTRL_PWM2_EN (1<<18) +#define LCD_CTRL_OUTPUT_DISABLED (0<<19) +#define LCD_CTRL_OUTPUT_ENABLED (1<<19) +#define LCD_CTRL_BPORCH_ENABLE (1<<21) +#define LCD_CTRL_FPORCH_ENABLE (1<<22) +#define LCD_CTRL_PIPELINE_DMA(1<<28) + +/*interrupts */ +#define LCD_INT_STATUS (0x4 * 0x001) +#define LCD_INT_EOF (1<<0) +#define LCD_INT_LINE_CMP (1<<1) +#define LCD_INT_VERT_COMP(1<<2) +#define LAYER0_DMA_DONE_BIT (1<<3) +#define LAYER0_DMA_IDLE_BIT (1<<4) +#define LAYER0_DMA_OVERFLOW_BIT (1<<5) +#define LAYER0_DMA_FIFO_UNDERFLOW_BIT(1<<6) +#define LAYER0_DMA_CB_FIFO_OVERFLOW_BIT (1<<7) +#define LAYER0_DMA_CB_FIFO_UNDERFLOW_BIT (1<<8) +#define LAYER0_DMA_CR_FIFO_OVERFLOW_BIT (1<<9)
[PATCH v2 11/59] drm/kmb: Use correct mmio offset from data book
Also added separate macros for lcd and mipi register accesses that use the corrected mmio offset. mmio oofset will be read from the device tree in the future. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_crtc.c | 49 ++--- drivers/gpu/drm/kmb/kmb_drv.c | 17 ++ drivers/gpu/drm/kmb/kmb_drv.h | 47 --- drivers/gpu/drm/kmb/kmb_dsi.c | 41 +++--- drivers/gpu/drm/kmb/kmb_plane.c | 34 ++-- drivers/gpu/drm/kmb/kmb_regs.h | 6 - 6 files changed, 113 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 63821ed..984f21a 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -31,25 +31,21 @@ static void kmb_crtc_cleanup(struct drm_crtc *crtc) static int kmb_crtc_enable_vblank(struct drm_crtc *crtc) { - struct kmb_drm_private *lcd = crtc_to_kmb_priv(crtc); - /*clear interrupt */ - kmb_write(lcd, LCD_INT_CLEAR, LCD_INT_VERT_COMP); + kmb_write_lcd(LCD_INT_CLEAR, LCD_INT_VERT_COMP); /*set which interval to generate vertical interrupt */ - kmb_write(lcd, LCD_VSTATUS_COMPARE, LCD_VSTATUS_COMPARE_VSYNC); + kmb_write_lcd(LCD_VSTATUS_COMPARE, LCD_VSTATUS_COMPARE_VSYNC); /* enable vertical interrupt */ - kmb_write(lcd, LCD_INT_ENABLE, LCD_INT_VERT_COMP); + kmb_write_lcd(LCD_INT_ENABLE, LCD_INT_VERT_COMP); return 0; } static void kmb_crtc_disable_vblank(struct drm_crtc *crtc) { - struct kmb_drm_private *lcd = crtc_to_kmb_priv(crtc); - /*clear interrupt */ - kmb_write(lcd, LCD_INT_CLEAR, LCD_INT_VERT_COMP); + kmb_write_lcd(LCD_INT_CLEAR, LCD_INT_VERT_COMP); /* disable vertical interrupt */ - kmb_write(lcd, LCD_INT_ENABLE, 0); + kmb_write_lcd(LCD_INT_ENABLE, 0); /* TBD * set the BIT2 (VERTICAL_COMPARE_INTERRUPT) of the LCD_INT_ENABLE register @@ -71,7 +67,6 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = { static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct kmb_drm_private *lcd = crtc_to_kmb_priv(crtc); struct drm_display_mode *m = &crtc->state->adjusted_mode; struct videomode vm; int vsync_start_offset; @@ -88,30 +83,30 @@ static void kmb_crtc_mode_set_nofb(struct drm_crtc *crtc) vsync_start_offset = m->crtc_vsync_start - m->crtc_hsync_start; vsync_end_offset = m->crtc_vsync_end - m->crtc_hsync_end; - kmb_write(lcd, LCD_V_ACTIVEHEIGHT, m->crtc_vdisplay - 1); - kmb_write(lcd, LCD_V_BACKPORCH, vm.vback_porch - 1); - kmb_write(lcd, LCD_V_FRONTPORCH, vm.vfront_porch - 1); - kmb_write(lcd, LCD_VSYNC_WIDTH, vm.vsync_len - 1); - kmb_write(lcd, LCD_H_ACTIVEWIDTH, m->crtc_hdisplay - 1); - kmb_write(lcd, LCD_H_BACKPORCH, vm.hback_porch - 1); - kmb_write(lcd, LCD_H_FRONTPORCH, vm.hfront_porch - 1); - kmb_write(lcd, LCD_HSYNC_WIDTH, vm.hsync_len - 1); + kmb_write_lcd(LCD_V_ACTIVEHEIGHT, m->crtc_vdisplay - 1); + kmb_write_lcd(LCD_V_BACKPORCH, vm.vback_porch - 1); + kmb_write_lcd(LCD_V_FRONTPORCH, vm.vfront_porch - 1); + kmb_write_lcd(LCD_VSYNC_WIDTH, vm.vsync_len - 1); + kmb_write_lcd(LCD_H_ACTIVEWIDTH, m->crtc_hdisplay - 1); + kmb_write_lcd(LCD_H_BACKPORCH, vm.hback_porch - 1); + kmb_write_lcd(LCD_H_FRONTPORCH, vm.hfront_porch - 1); + kmb_write_lcd(LCD_HSYNC_WIDTH, vm.hsync_len - 1); if (m->flags == DRM_MODE_FLAG_INTERLACE) { - kmb_write(lcd, LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); - kmb_write(lcd, LCD_V_BACKPORCH_EVEN, vm.vback_porch - 1); - kmb_write(lcd, LCD_V_FRONTPORCH_EVEN, vm.vfront_porch - 1); - kmb_write(lcd, LCD_V_ACTIVEHEIGHT_EVEN, m->crtc_vdisplay - 1); - kmb_write(lcd, LCD_VSYNC_START_EVEN, vsync_start_offset); - kmb_write(lcd, LCD_VSYNC_END_EVEN, vsync_end_offset); + kmb_write_lcd(LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1); + kmb_write_lcd(LCD_V_BACKPORCH_EVEN, vm.vback_porch - 1); + kmb_write_lcd(LCD_V_FRONTPORCH_EVEN, vm.vfront_porch - 1); + kmb_write_lcd(LCD_V_ACTIVEHEIGHT_EVEN, m->crtc_vdisplay - 1); + kmb_write_lcd(LCD_VSYNC_START_EVEN, vsync_start_offset); + kmb_write_lcd(LCD_VSYNC_END_EVEN, vsync_end_offset); } /* enable VL1 layer as default */ ctrl = LCD_CTRL_ENABLE | LCD_CTRL_VL1_ENABLE; ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE - | LCD_CTRL_OUTPUT_ENABLED; - kmb_write(lcd, LCD_CONTROL, ctrl); + | LCD_CTRL_OUTPUT_ENABLED; + kmb_write_lcd(LCD_CONTROL, ctrl); - kmb_write(lcd, LCD_TIMING_GEN_TRIG, ENABLE); + kmb_write_lcd(LCD_TIMING_GEN_TRIG, ENABLE); /* TBD */
[PATCH v2 01/59] drm/kmb: Add support for KeemBay Display
Initial check-in for basic display driver for KeemBay family of SOCs. This is not tested and does not work and also there are many TBDs in the code which will be implemented in future commits. v2: moved extern to .h, removed license text use drm_dev_init, upclassed dev_private, removed HAVE_IRQ. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile| 1 + drivers/gpu/drm/kmb/Kconfig | 12 ++ drivers/gpu/drm/kmb/Makefile| 2 + drivers/gpu/drm/kmb/kmb_crtc.c | 194 ++ drivers/gpu/drm/kmb/kmb_crtc.h | 39 drivers/gpu/drm/kmb/kmb_drv.c | 355 drivers/gpu/drm/kmb/kmb_drv.h | 47 + drivers/gpu/drm/kmb/kmb_plane.c | 232 + drivers/gpu/drm/kmb/kmb_plane.h | 32 +++ drivers/gpu/drm/kmb/kmb_regs.h | 440 11 files changed, 1356 insertions(+) create mode 100644 drivers/gpu/drm/kmb/Kconfig create mode 100644 drivers/gpu/drm/kmb/Makefile create mode 100644 drivers/gpu/drm/kmb/kmb_crtc.c create mode 100644 drivers/gpu/drm/kmb/kmb_crtc.h create mode 100644 drivers/gpu/drm/kmb/kmb_drv.c create mode 100644 drivers/gpu/drm/kmb/kmb_drv.h create mode 100644 drivers/gpu/drm/kmb/kmb_plane.c create mode 100644 drivers/gpu/drm/kmb/kmb_plane.h create mode 100644 drivers/gpu/drm/kmb/kmb_regs.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c4fd57d..5292574 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -275,6 +275,8 @@ source "drivers/gpu/drm/nouveau/Kconfig" source "drivers/gpu/drm/i915/Kconfig" +source "drivers/gpu/drm/kmb/Kconfig" + config DRM_VGEM tristate "Virtual GEM provider" depends on DRM diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 2c0e5a7..bdbdc63 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ obj-$(CONFIG_DRM_MGA) += mga/ obj-$(CONFIG_DRM_I810) += i810/ obj-$(CONFIG_DRM_I915) += i915/ +obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb/ obj-$(CONFIG_DRM_MGAG200) += mgag200/ obj-$(CONFIG_DRM_V3D) += v3d/ obj-$(CONFIG_DRM_VC4) += vc4/ diff --git a/drivers/gpu/drm/kmb/Kconfig b/drivers/gpu/drm/kmb/Kconfig new file mode 100644 index 000..005a9962 --- /dev/null +++ b/drivers/gpu/drm/kmb/Kconfig @@ -0,0 +1,12 @@ +config DRM_KMB_DISPLAY + tristate "KEEMBAY DISPLAY" + depends on DRM && OF && (ARM || ARM64) + depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select VIDEOMODE_HELPERS + help + Choose this option if you have an KEEMBAY DISPLAY controller. + + If M is selected the module will be called kmb-display. diff --git a/drivers/gpu/drm/kmb/Makefile b/drivers/gpu/drm/kmb/Makefile new file mode 100644 index 000..be9f19c --- /dev/null +++ b/drivers/gpu/drm/kmb/Makefile @@ -0,0 +1,2 @@ +kmb-display-y := kmb_crtc.o kmb_drv.o kmb_plane.o +obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb-display.o diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c new file mode 100644 index 000..1a00015 --- /dev/null +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright © 2018-2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kmb_crtc.h" +#include "kmb_drv.h" +#include "kmb_plane.h" +#include "kmb_regs.h" + +static void kmb_crtc_cleanup(struct drm_crtc *crtc) +{ + struct kmb_crtc *l_crtc = to_kmb_crtc(crtc); + + drm_crtc_cleanup(crtc); + kfree(l_crtc); +} + +static int kmb_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct kmb_drm_private *lcd = crtc_to_kmb_priv(crtc); + + /*clear interrupt */ + kmb_write(lcd, LCD_INT_CLEAR, LCD_INT_VERT_COMP); + /*set which interval to generate vertical interrupt */ + kmb_write(lcd, LCD_VSTATUS_COMPARE, LCD_VSTATUS_COMPARE_VSYNC); + /* enable vertical interrupt */ + kmb_write(lcd, LCD_INT_ENABLE, LCD_INT_VERT_COMP); + return 0; +} + +static void kmb_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct kmb_drm_private *lcd = crtc_to_kmb_priv(crtc); + + /*clear interrupt */ + kmb_write(lcd, LCD_INT_CLEAR, LCD_INT_VERT_COMP); + /* disable vertical interrupt */ + kmb_write(lcd, LCD_INT_ENABLE, 0); + +/* TBD + * set the BIT2 (VERTICAL_COMPARE_INTERRUPT) of the LCD_INT_ENABLE register + * set the required bit LCD_VSTATUS_COMPARE register + * Not sure if anything needs to be done in the ICB + */ +} + +static const struct drm_crtc_funcs kmb_crtc_funcs = { + .destroy = kmb_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_fli
[PATCH v2 03/59] drm/kmb: Set correct values in the LAYERn_CFG register
During update plane, set the layer format, bpp, fifo level, RGB order, Cb/Cr order etc. in the LAYER_CFG register. v2: Return val in set_pixel and set_bpp instead of passing in pointer, Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_plane.c | 145 ++ drivers/gpu/drm/kmb/kmb_regs.h | 167 2 files changed, 298 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 7077a4c..877314a 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -33,6 +33,119 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, return 0; } +unsigned int set_pixel_format(u32 format) +{ + unsigned int val = 0; + + switch (format) { + /*planar formats */ + case DRM_FORMAT_YUV444: + val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE; + break; + case DRM_FORMAT_YVU444: + val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE + | LCD_LAYER_CRCB_ORDER; + break; + case DRM_FORMAT_YUV422: + val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE; + break; + case DRM_FORMAT_YVU422: + val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE + | LCD_LAYER_CRCB_ORDER; + break; + case DRM_FORMAT_YUV420: + val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE; + break; + case DRM_FORMAT_YVU420: + val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE + | LCD_LAYER_CRCB_ORDER; + break; + case DRM_FORMAT_NV12: + val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE; + break; + case DRM_FORMAT_NV21: + val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE + | LCD_LAYER_CRCB_ORDER; + break; + /* packed formats */ + case DRM_FORMAT_RGB332: + val = LCD_LAYER_FORMAT_RGB332; + break; + case DRM_FORMAT_XBGR: + val = LCD_LAYER_FORMAT_RGBX | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_ARGB: + val = LCD_LAYER_FORMAT_RGBA; + break; + case DRM_FORMAT_ABGR: + val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_XRGB1555: + val = LCD_LAYER_FORMAT_XRGB1555; + break; + case DRM_FORMAT_XBGR1555: + val = LCD_LAYER_FORMAT_XRGB1555 | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_ARGB1555: + val = LCD_LAYER_FORMAT_RGBA1555; + break; + case DRM_FORMAT_ABGR1555: + val = LCD_LAYER_FORMAT_RGBA1555 | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_RGB565: + val = LCD_LAYER_FORMAT_RGB565; + break; + case DRM_FORMAT_BGR565: + val = LCD_LAYER_FORMAT_RGB565 | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_RGB888: + val = LCD_LAYER_FORMAT_RGB888; + break; + case DRM_FORMAT_BGR888: + val = LCD_LAYER_FORMAT_RGB888 | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_XRGB: + val = LCD_LAYER_FORMAT_RGBX; + break; + case DRM_FORMAT_XBGR: + val = LCD_LAYER_FORMAT_RGBX | LCD_LAYER_BGR_ORDER; + break; + case DRM_FORMAT_ARGB: + val = LCD_LAYER_FORMAT_RGBA; + break; + case DRM_FORMAT_ABGR: + val = LCD_LAYER_FORMAT_RGBA | LCD_LAYER_BGR_ORDER; + break; + } + return val; +} + +unsigned int set_bits_per_pixel(const struct drm_format_info *format) +{ + int i; + u32 bpp = 0; + unsigned int val = 0; + + for (i = 0; i < format->num_planes; i++) + bpp += 8*format->cpp[i]; + + switch (bpp) { + case 8: + val = LCD_LAYER_8BPP; + break; + case 16: + val = LCD_LAYER_16BPP; + break; + case 24: + val = LCD_LAYER_24BPP; + break; + case 32: + val = LCD_LAYER_32BPP; + break; + } + return val; +} + static void kmb_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *state) { @@ -44,7 +157,8 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, unsigned int dma_len; struct kmb_plane *kmb_plane = to_kmb_plane(plane); unsigned int dma_cfg; - unsigned int c
[PATCH v2 14/59] drm/kmb: Correct address offsets for mipi registers
Mipi HS registers start at an additional offset of 0x400 which needs to be added at the register macro definition and not at the read/write function level. v2: replaced calculations with macro to make code simpler Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 16 +++--- drivers/gpu/drm/kmb/kmb_regs.h | 116 - 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index a685a7a..a255210 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -423,20 +423,20 @@ static void mipi_tx_fg_cfg_regs(struct kmb_drm_private *dev_priv, *REG_VSYNC_WIDTH0: [15:0]-VSA for channel0, [31:16]-VSA for channel1 *REG_VSYNC_WIDTH1: [15:0]-VSA for channel2, [31:16]-VSA for channel3 */ - offset = (frame_gen % 2) * 16; - reg_adr = MIPI_TXm_HS_VSYNC_WIDTHn(ctrl_no, frame_gen); + offset = (frame_gen % 2)*16; + reg_adr = MIPI_TXm_HS_VSYNC_WIDTHn(ctrl_no, frame_gen/2); kmb_write_bits_mipi(reg_adr, offset, 16, fg_cfg->vsync_width); - /*v backporch - same register config like vsync width */ - reg_adr = MIPI_TXm_HS_V_BACKPORCHESn(ctrl_no, frame_gen); + /*v backporch - same register config like vsync width*/ + reg_adr = MIPI_TXm_HS_V_BACKPORCHESn(ctrl_no, frame_gen/2); kmb_write_bits_mipi(reg_adr, offset, 16, fg_cfg->v_backporch); - /*v frontporch - same register config like vsync width */ - reg_adr = MIPI_TXm_HS_V_FRONTPORCHESn(ctrl_no, frame_gen); + /*v frontporch - same register config like vsync width*/ + reg_adr = MIPI_TXm_HS_V_FRONTPORCHESn(ctrl_no, frame_gen/2); kmb_write_bits_mipi(reg_adr, offset, 16, fg_cfg->v_frontporch); - /*v active - same register config like vsync width */ - reg_adr = MIPI_TXm_HS_V_ACTIVEn(ctrl_no, frame_gen); + /*v active - same register config like vsync width*/ + reg_adr = MIPI_TXm_HS_V_ACTIVEn(ctrl_no, frame_gen/2); kmb_write_bits_mipi(reg_adr, offset, 16, fg_cfg->v_active); /*hsyc width */ diff --git a/drivers/gpu/drm/kmb/kmb_regs.h b/drivers/gpu/drm/kmb/kmb_regs.h index 2d25c50..381e255 100644 --- a/drivers/gpu/drm/kmb/kmb_regs.h +++ b/drivers/gpu/drm/kmb/kmb_regs.h @@ -375,10 +375,10 @@ *MIPI controller control register defines ***i/ #define MIPI0_HS_BASE_ADDR (MIPI_BASE_ADDR + 0x400) -#define MIPI_CTRL_HS_BASE_ADDR (0x400) +#define HS_OFFSET(M) ((M + 1) * 0x400) #define MIPI_TX_HS_CTRL(0x0) -#define MIPI_TXm_HS_CTRL(M) (MIPI_TX_HS_CTRL + (0x400*M)) +#define MIPI_TXm_HS_CTRL(M) (MIPI_TX_HS_CTRL + HS_OFFSET(M)) #define HS_CTRL_EN (1 << 0) #define HS_CTRL_CSIDSIN (1 << 2) /*1:CSI 0:DSI*/ #define TX_SOURCE(1 << 3) /*1:LCD, 0:DMA*/ @@ -391,7 +391,7 @@ #define HSCLKIDLE_CNT(1 << 24) #define MIPI_TX_HS_SYNC_CFG(0x8) #define MIPI_TXm_HS_SYNC_CFG(M) (MIPI_TX_HS_SYNC_CFG \ - + (0x400*M)) + + HS_OFFSET(M)) #define LINE_SYNC_PKT_ENABLE (1 << 0) #define FRAME_COUNTER_ACTIVE (1 << 1) #define LINE_COUNTER_ACTIVE (1 << 2) @@ -408,75 +408,93 @@ #define FRAME_GEN_EN(f) ((f) << 23) #define HACT_WAIT_STOP(f)((f) << 28) #define MIPI_TX0_HS_FG0_SECT0_PH (0x40) -#define MIPI_TXm_HS_FGn_SECTo_PH(M, N, O) (MIPI_TX0_HS_FG0_SECT0_PH + \ - (0x400*M) + (0x2C*N) + (8*O)) -#define MIPI_TX_SECT_WC_MASK (0x) -#defineMIPI_TX_SECT_VC_MASK (3) -#define MIPI_TX_SECT_VC_SHIFT(22) -#define MIPI_TX_SECT_DT_MASK (0x3f) -#define MIPI_TX_SECT_DT_SHIFT(16) -#define MIPI_TX_SECT_DM_MASK (3) -#define MIPI_TX_SECT_DM_SHIFT(24) -#define MIPI_TX_SECT_DMA_PACKED (1<<26) +#define MIPI_TXm_HS_FGn_SECTo_PH(M, N, O)(MIPI_TX0_HS_FG0_SECT0_PH + \ + HS_OFFSET(M) + (0x2C*N) + (8*O)) +#define MIPI_TX_SECT_WC_MASK (0x) +#define MIPI_TX_SECT_VC_MASK (3) +#define MIPI_TX_SECT_VC_SHIFT(22) +#define MIPI_TX_SECT_DT_MASK (0x3f) +#define MIPI_TX_SECT_DT_SHIFT(16) +#define MIPI_TX_SECT_DM_MASK (3) +#define MIPI_TX
[PATCH v2 08/59] drm/kmb: Added mipi_dsi_host initialization
Added mipi DSI host initialization functions Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/kmb_dsi.c | 59 +++ drivers/gpu/drm/kmb/kmb_dsi.h | 4 +++ 2 files changed, 63 insertions(+) diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 654fae8..d82411e 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -65,12 +65,59 @@ static const struct drm_connector_funcs kmb_dsi_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, }; +static ssize_t kmb_dsi_host_transfer(struct mipi_dsi_host *host, +const struct mipi_dsi_msg *msg) +{ + return 0; +} + +static int kmb_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *dev) +{ + return 0; +} + +static int kmb_dsi_host_detach(struct mipi_dsi_host *host, + struct mipi_dsi_device *dev) +{ + return 0; +} + +static const struct mipi_dsi_host_ops kmb_dsi_host_ops = { + .attach = kmb_dsi_host_attach, + .detach = kmb_dsi_host_detach, + .transfer = kmb_dsi_host_transfer, +}; + +static struct kmb_dsi_host *kmb_dsi_host_init(struct kmb_dsi *kmb_dsi) +{ + struct kmb_dsi_host *host; + struct mipi_dsi_device *device; + + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) + return NULL; + + host->base.ops = &kmb_dsi_host_ops; + host->kmb_dsi = kmb_dsi; + + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) { + kfree(host); + return NULL; + } + device->host = &host->base; + host->device = device; + return host; +} + void kmb_dsi_init(struct drm_device *dev) { struct kmb_dsi *kmb_dsi; struct drm_encoder *encoder; struct kmb_connector *kmb_connector; struct drm_connector *connector; + struct kmb_dsi_host *host; kmb_dsi = kzalloc(sizeof(*kmb_dsi), GFP_KERNEL); if (!kmb_dsi) @@ -88,7 +135,19 @@ void kmb_dsi_init(struct drm_device *dev) encoder = &kmb_dsi->base; drm_encoder_init(dev, encoder, &kmb_dsi_funcs, DRM_MODE_ENCODER_DSI, "MIPI-DSI"); + + host = kmb_dsi_host_init(kmb_dsi); + if (!host) { + drm_encoder_cleanup(encoder); + kfree(kmb_dsi); + kfree(kmb_connector); + } + drm_connector_init(dev, connector, &kmb_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, &kmb_dsi_connector_helper_funcs); + + connector->encoder = encoder; + drm_connector_attach_encoder(connector, encoder); + } diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index 9a6b0b7..0f5da87 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -12,19 +12,23 @@ #include "kmb_drv.h" struct kmb_connector; +struct kmb_dsi_host; struct kmb_dsi { struct drm_encoder base; struct kmb_connector *attached_connector; + struct kmb_dsi_host *dsi_host; }; struct kmb_dsi_host { struct mipi_dsi_host base; struct kmb_dsi *kmb_dsi; + struct mipi_dsi_device *device; }; struct kmb_connector { struct drm_connector base; + struct drm_encoder *encoder; struct drm_display_mode *fixed_mode; }; -- 2.7.4 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2 06/59] drm/kmb: Initial check-in for Mipi DSI
Basic frame work for mipi encoder and connector. More hardware specific details will be added in the future commits. Signed-off-by: Anitha Chrisanthus Reviewed-by: Bob Paauwe --- drivers/gpu/drm/kmb/Makefile | 2 +- drivers/gpu/drm/kmb/kmb_drv.c | 2 + drivers/gpu/drm/kmb/kmb_dsi.c | 94 +++ drivers/gpu/drm/kmb/kmb_dsi.h | 38 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/kmb/kmb_dsi.c create mode 100644 drivers/gpu/drm/kmb/kmb_dsi.h diff --git a/drivers/gpu/drm/kmb/Makefile b/drivers/gpu/drm/kmb/Makefile index be9f19c..8102bc9 100644 --- a/drivers/gpu/drm/kmb/Makefile +++ b/drivers/gpu/drm/kmb/Makefile @@ -1,2 +1,2 @@ -kmb-display-y := kmb_crtc.o kmb_drv.o kmb_plane.o +kmb-display-y := kmb_crtc.o kmb_drv.o kmb_plane.o kmb_dsi.o obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb-display.o diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 11f8d1f..aec8a5b 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -25,6 +25,7 @@ #include #include "kmb_crtc.h" #include "kmb_drv.h" +#include "kmb_dsi.h" #include "kmb_plane.h" #include "kmb_regs.h" @@ -63,6 +64,7 @@ static int kmb_load(struct drm_device *drm, unsigned long flags) goto setup_fail; } + kmb_dsi_init(drm); ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); if (ret < 0) { DRM_ERROR("failed to install IRQ handler\n"); diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c new file mode 100644 index 000..654fae8 --- /dev/null +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright © 2019-2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kmb_drv.h" +#include "kmb_dsi.h" + +static enum drm_mode_status +kmb_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static int kmb_dsi_get_modes(struct drm_connector *connector) +{ + struct drm_display_mode *mode; + struct kmb_connector *kmb_connector = to_kmb_connector(connector); + + mode = drm_mode_duplicate(connector->dev, kmb_connector->fixed_mode); + drm_mode_probed_add(connector, mode); + return 1; +} + +static void kmb_dsi_connector_destroy(struct drm_connector *connector) +{ + struct kmb_connector *kmb_connector = to_kmb_connector(connector); + + drm_connector_cleanup(connector); + kfree(kmb_connector); +} + +static void kmb_dsi_encoder_destroy(struct drm_encoder *encoder) +{ + struct kmb_dsi *kmb_dsi = to_kmb_dsi(encoder); + + drm_encoder_cleanup(encoder); + kfree(kmb_dsi); +} + +static const struct drm_encoder_funcs kmb_dsi_funcs = { + .destroy = kmb_dsi_encoder_destroy, +}; + +static const struct +drm_connector_helper_funcs kmb_dsi_connector_helper_funcs = { + .get_modes = kmb_dsi_get_modes, + .mode_valid = kmb_dsi_mode_valid, +}; + +static const struct drm_connector_funcs kmb_dsi_connector_funcs = { + .destroy = kmb_dsi_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +}; + +void kmb_dsi_init(struct drm_device *dev) +{ + struct kmb_dsi *kmb_dsi; + struct drm_encoder *encoder; + struct kmb_connector *kmb_connector; + struct drm_connector *connector; + + kmb_dsi = kzalloc(sizeof(*kmb_dsi), GFP_KERNEL); + if (!kmb_dsi) + return; + + kmb_connector = kzalloc(sizeof(*kmb_connector), GFP_KERNEL); + if (!kmb_connector) { + kfree(kmb_dsi); + return; + } + + kmb_dsi->attached_connector = kmb_connector; + + connector = &kmb_connector->base; + encoder = &kmb_dsi->base; + drm_encoder_init(dev, encoder, &kmb_dsi_funcs, DRM_MODE_ENCODER_DSI, +"MIPI-DSI"); + drm_connector_init(dev, connector, &kmb_dsi_connector_funcs, + DRM_MODE_CONNECTOR_DSI); + drm_connector_helper_add(connector, &kmb_dsi_connector_helper_funcs); +} diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h new file mode 100644 index 000..9a6b0b7 --- /dev/null +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright © 2019-2020 Intel Corporation + */ + +#ifndef __KMB_DSI_H__ +#define __KMB_DSI_H__ + +#include +#include +#include +#include "kmb_drv.h" + +struct kmb_connector; + +struct kmb_dsi { + struct drm_encoder base; + struct kmb_connector *attached_connector; +}; + +struct kmb_dsi_host { + struct mipi_dsi_host base; + struct k
Re: [PATCH 3/3] dma-buf/selftests: Add locking selftests for sw_sync
Awsome, thanks for adding the tests! Got to say I'm not that familiar with the self-test framework idioms, but from my perspective patches 2 and 3 are Reviewed-by: Bas Nieuwenhuizen as well. On Tue, Jul 14, 2020 at 10:06 PM Chris Wilson wrote: > > While sw_sync is purely a debug facility for userspace to create fences > and timelines it can control, nevertheless it has some tricky locking > semantics of its own. In particular, Bas Nieuwenhuize reported that we > had reintroduced a deadlock if a signal callback attempted to destroy > the fence. So let's add a few trivial selftests to make sure that once > fixed again, it stays fixed. > > Signed-off-by: Chris Wilson > Cc: Bas Nieuwenhuizen > --- > drivers/dma-buf/Makefile | 3 +- > drivers/dma-buf/selftests.h | 1 + > drivers/dma-buf/st-sw_sync.c | 279 +++ > drivers/dma-buf/sw_sync.c| 39 + > drivers/dma-buf/sync_debug.h | 8 + > 5 files changed, 329 insertions(+), 1 deletion(-) > create mode 100644 drivers/dma-buf/st-sw_sync.c > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index 995e05f609ff..9be4d4611609 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o > dmabuf_selftests-y := \ > selftest.o \ > st-dma-fence.o \ > - st-dma-fence-chain.o > + st-dma-fence-chain.o \ > + st-sw_sync.o > > obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h > index bc8cea67bf1e..232499a24872 100644 > --- a/drivers/dma-buf/selftests.h > +++ b/drivers/dma-buf/selftests.h > @@ -12,3 +12,4 @@ > selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */ > selftest(dma_fence, dma_fence) > selftest(dma_fence_chain, dma_fence_chain) > +selftest(sw_sync, sw_sync) > diff --git a/drivers/dma-buf/st-sw_sync.c b/drivers/dma-buf/st-sw_sync.c > new file mode 100644 > index ..3a21e7717df7 > --- /dev/null > +++ b/drivers/dma-buf/st-sw_sync.c > @@ -0,0 +1,279 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright © 2020 Intel Corporation > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "sync_debug.h" > +#include "selftest.h" > + > +static int sanitycheck(void *arg) > +{ > + struct sync_timeline *tl; > + struct dma_fence *f; > + int err = -ENOMEM; > + > + /* Quick check we can create the timeline and syncpt */ > + > + tl = st_sync_timeline_create("mock"); > + if (!tl) > + return -ENOMEM; > + > + f = st_sync_pt_create(tl, 1); > + if (!f) > + goto out; > + > + dma_fence_signal(f); > + dma_fence_put(f); > + > + err = 0; > +out: > + st_sync_timeline_put(tl); > + return 0; > +} > + > +static int signal(void *arg) > +{ > + struct sync_timeline *tl; > + struct dma_fence *f; > + int err = -EINVAL; > + > + /* Check that the syncpt fence is signaled when the timeline advances > */ > + > + tl = st_sync_timeline_create("mock"); > + if (!tl) > + return -ENOMEM; > + > + f = st_sync_pt_create(tl, 1); > + if (!f) { > + err = -ENOMEM; > + goto out; > + } > + > + if (dma_fence_is_signaled(f)) { > + pr_err("syncpt:%lld signaled too early\n", f->seqno); > + goto out_fence; > + } > + > + st_sync_timeline_signal(tl, 1); > + > + if (!dma_fence_is_signaled(f)) { > + pr_err("syncpt:%lld not signaled after increment\n", > f->seqno); > + goto out_fence; > + } > + > + err = 0; > +out_fence: > + dma_fence_signal(f); > + dma_fence_put(f); > +out: > + st_sync_timeline_put(tl); > + return 0; > +} > + > +struct cb_destroy { > + struct dma_fence_cb cb; > + struct dma_fence *f; > +}; > + > +static void cb_destroy(struct dma_fence *fence, struct dma_fence_cb *_cb) > +{ > + struct cb_destroy *cb = container_of(_cb, typeof(*cb), cb); > + > + pr_info("syncpt:%llx destroying syncpt:%llx\n", > + fence->seqno, cb->f->seqno); > + dma_fence_put(cb->f); > + cb->f = NULL; > +} > + > +static int cb_autodestroy(void *arg) > +{ > + struct sync_timeline *tl; > + struct cb_destroy cb; > + int err = -EINVAL; > + > + /* Check that we can drop the final syncpt reference from a callback > */ > + > + tl = st_sync_timeline_create("mock"); > + if (!tl) > + return -ENOMEM; > + > + cb.f = st_sync_pt_create(tl, 1); > + if (!cb.f) { > + err = -ENOMEM; > + goto out; > + } > + > + if (dma_fence_add_callback(cb.f, &cb.cb, cb_destroy)) { > + pr_err("syncpt:%lld signaled before increment\n", > cb.f->seqn
Re: [PATCH 1/3] dma-buf/sw_sync: Avoid recursive lock during fence signal.
Thanks for updating the patch. LGTM On Tue, Jul 14, 2020 at 10:07 PM Chris Wilson wrote: > > From: Bas Nieuwenhuizen > > Calltree: > timeline_fence_release > drm_sched_entity_wakeup > dma_fence_signal_locked > sync_timeline_signal > sw_sync_ioctl > > Releasing the reference to the fence in the fence signal callback > seems reasonable to me, so this patch avoids the locking issue in > sw_sync. > > d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") > fixed the recursive locking issue but caused an use-after-free. Later > d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > fixed the use-after-free but reintroduced the recursive locking issue. > > In this attempt we avoid the use-after-free still because the release > function still always locks, and outside of the locking region in the > signal function we have properly refcounted references. > > We furthermore also avoid the recurive lock by making sure that either: > > 1) We have a properly refcounted reference, preventing the signal from >triggering the release function inside the locked region. > 2) The refcount was already zero, and hence nobody will be able to trigger >the release function from the signal function. > > v2: Move dma_fence_signal() into second loop in preparation to moving > the callback out of the timeline obj->lock. > > Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > Cc: Sumit Semwal > Cc: Chris Wilson > Cc: Gustavo Padovan > Cc: Christian König > Cc: > Signed-off-by: Bas Nieuwenhuizen > Signed-off-by: Chris Wilson > --- > drivers/dma-buf/sw_sync.c | 32 ++-- > 1 file changed, 22 insertions(+), 10 deletions(-) > > diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c > index 348b3a9170fa..807c82148062 100644 > --- a/drivers/dma-buf/sw_sync.c > +++ b/drivers/dma-buf/sw_sync.c > @@ -192,6 +192,7 @@ static const struct dma_fence_ops timeline_fence_ops = { > static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) > { > struct sync_pt *pt, *next; > + LIST_HEAD(signal); > > trace_sync_timeline(obj); > > @@ -203,21 +204,32 @@ static void sync_timeline_signal(struct sync_timeline > *obj, unsigned int inc) > if (!timeline_fence_signaled(&pt->base)) > break; > > - list_del_init(&pt->link); > - rb_erase(&pt->node, &obj->pt_tree); > - > /* > -* A signal callback may release the last reference to this > -* fence, causing it to be freed. That operation has to be > -* last to avoid a use after free inside this loop, and must > -* be after we remove the fence from the timeline in order to > -* prevent deadlocking on timeline->lock inside > -* timeline_fence_release(). > +* We need to take a reference to avoid a release during > +* signalling (which can cause a recursive lock of obj->lock). > +* If refcount was already zero, another thread is already > +* taking care of destroying the fence. > */ > - dma_fence_signal_locked(&pt->base); > + if (!dma_fence_get_rcu(&pt->base)) > + continue; > + > + list_move_tail(&pt->link, &signal); > + rb_erase(&pt->node, &obj->pt_tree); > } > > spin_unlock_irq(&obj->lock); > + > + list_for_each_entry_safe(pt, next, &signal, link) { > + /* > +* This needs to be cleared before release, otherwise the > +* timeline_fence_release function gets confused about also > +* removing the fence from the pt_tree. > +*/ > + list_del_init(&pt->link); > + > + dma_fence_signal(&pt->base); > + dma_fence_put(&pt->base); > + } > } > > /** > -- > 2.20.1 > ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH v2] dma-buf/sw_sync: Separate signal/timeline locks
Since we decouple the sync_pt from the timeline tree upon release, in order to allow releasing the sync_pt from a signal callback we need to separate the sync_pt signaling lock from the timeline tree lock. v2: Mark up the unlocked read of the current timeline value. Suggested-by: Bas Nieuwenhuizen Signed-off-by: Chris Wilson Cc: Bas Nieuwenhuizen --- drivers/dma-buf/sw_sync.c| 33 - drivers/dma-buf/sync_debug.h | 2 ++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 807c82148062..5851bf7076d0 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -132,24 +132,32 @@ static void timeline_fence_release(struct dma_fence *fence) { struct sync_pt *pt = dma_fence_to_sync_pt(fence); struct sync_timeline *parent = dma_fence_parent(fence); - unsigned long flags; - spin_lock_irqsave(fence->lock, flags); if (!list_empty(&pt->link)) { - list_del(&pt->link); - rb_erase(&pt->node, &parent->pt_tree); + unsigned long flags; + + spin_lock_irqsave(&parent->lock, flags); + if (!list_empty(&pt->link)) { + list_del(&pt->link); + rb_erase(&pt->node, &parent->pt_tree); + } + spin_unlock_irqrestore(&parent->lock, flags); } - spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); dma_fence_free(fence); } -static bool timeline_fence_signaled(struct dma_fence *fence) +static int timeline_value(struct dma_fence *fence) { - struct sync_timeline *parent = dma_fence_parent(fence); + return READ_ONCE(dma_fence_parent(fence)->value); +} - return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops); +static bool timeline_fence_signaled(struct dma_fence *fence) +{ + return !__dma_fence_is_later(fence->seqno, +timeline_value(fence), +fence->ops); } static bool timeline_fence_enable_signaling(struct dma_fence *fence) @@ -166,9 +174,7 @@ static void timeline_fence_value_str(struct dma_fence *fence, static void timeline_fence_timeline_value_str(struct dma_fence *fence, char *str, int size) { - struct sync_timeline *parent = dma_fence_parent(fence); - - snprintf(str, size, "%d", parent->value); + snprintf(str, size, "%d", timeline_value(fence)); } static const struct dma_fence_ops timeline_fence_ops = { @@ -252,12 +258,13 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, return NULL; sync_timeline_get(obj); - dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + spin_lock_init(&pt->lock); + dma_fence_init(&pt->base, &timeline_fence_ops, &pt->lock, obj->context, value); INIT_LIST_HEAD(&pt->link); spin_lock_irq(&obj->lock); - if (!dma_fence_is_signaled_locked(&pt->base)) { + if (!dma_fence_is_signaled(&pt->base)) { struct rb_node **p = &obj->pt_tree.rb_node; struct rb_node *parent = NULL; diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index 6176e52ba2d7..fd073fc32329 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -55,11 +55,13 @@ static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) * @base: base fence object * @link: link on the sync timeline's list * @node: node in the sync timeline's tree + * @lock: fence signaling lock */ struct sync_pt { struct dma_fence base; struct list_head link; struct rb_node node; + spinlock_t lock; }; extern const struct file_operations sw_sync_debugfs_fops; -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH 3/3] dma-buf/selftests: Add locking selftests for sw_sync
While sw_sync is purely a debug facility for userspace to create fences and timelines it can control, nevertheless it has some tricky locking semantics of its own. In particular, Bas Nieuwenhuize reported that we had reintroduced a deadlock if a signal callback attempted to destroy the fence. So let's add a few trivial selftests to make sure that once fixed again, it stays fixed. Signed-off-by: Chris Wilson Cc: Bas Nieuwenhuizen --- drivers/dma-buf/Makefile | 3 +- drivers/dma-buf/selftests.h | 1 + drivers/dma-buf/st-sw_sync.c | 279 +++ drivers/dma-buf/sw_sync.c| 39 + drivers/dma-buf/sync_debug.h | 8 + 5 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 drivers/dma-buf/st-sw_sync.c diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 995e05f609ff..9be4d4611609 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o dmabuf_selftests-y := \ selftest.o \ st-dma-fence.o \ - st-dma-fence-chain.o + st-dma-fence-chain.o \ + st-sw_sync.o obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h index bc8cea67bf1e..232499a24872 100644 --- a/drivers/dma-buf/selftests.h +++ b/drivers/dma-buf/selftests.h @@ -12,3 +12,4 @@ selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */ selftest(dma_fence, dma_fence) selftest(dma_fence_chain, dma_fence_chain) +selftest(sw_sync, sw_sync) diff --git a/drivers/dma-buf/st-sw_sync.c b/drivers/dma-buf/st-sw_sync.c new file mode 100644 index ..3a21e7717df7 --- /dev/null +++ b/drivers/dma-buf/st-sw_sync.c @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sync_debug.h" +#include "selftest.h" + +static int sanitycheck(void *arg) +{ + struct sync_timeline *tl; + struct dma_fence *f; + int err = -ENOMEM; + + /* Quick check we can create the timeline and syncpt */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + f = st_sync_pt_create(tl, 1); + if (!f) + goto out; + + dma_fence_signal(f); + dma_fence_put(f); + + err = 0; +out: + st_sync_timeline_put(tl); + return 0; +} + +static int signal(void *arg) +{ + struct sync_timeline *tl; + struct dma_fence *f; + int err = -EINVAL; + + /* Check that the syncpt fence is signaled when the timeline advances */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + f = st_sync_pt_create(tl, 1); + if (!f) { + err = -ENOMEM; + goto out; + } + + if (dma_fence_is_signaled(f)) { + pr_err("syncpt:%lld signaled too early\n", f->seqno); + goto out_fence; + } + + st_sync_timeline_signal(tl, 1); + + if (!dma_fence_is_signaled(f)) { + pr_err("syncpt:%lld not signaled after increment\n", f->seqno); + goto out_fence; + } + + err = 0; +out_fence: + dma_fence_signal(f); + dma_fence_put(f); +out: + st_sync_timeline_put(tl); + return 0; +} + +struct cb_destroy { + struct dma_fence_cb cb; + struct dma_fence *f; +}; + +static void cb_destroy(struct dma_fence *fence, struct dma_fence_cb *_cb) +{ + struct cb_destroy *cb = container_of(_cb, typeof(*cb), cb); + + pr_info("syncpt:%llx destroying syncpt:%llx\n", + fence->seqno, cb->f->seqno); + dma_fence_put(cb->f); + cb->f = NULL; +} + +static int cb_autodestroy(void *arg) +{ + struct sync_timeline *tl; + struct cb_destroy cb; + int err = -EINVAL; + + /* Check that we can drop the final syncpt reference from a callback */ + + tl = st_sync_timeline_create("mock"); + if (!tl) + return -ENOMEM; + + cb.f = st_sync_pt_create(tl, 1); + if (!cb.f) { + err = -ENOMEM; + goto out; + } + + if (dma_fence_add_callback(cb.f, &cb.cb, cb_destroy)) { + pr_err("syncpt:%lld signaled before increment\n", cb.f->seqno); + goto out; + } + + st_sync_timeline_signal(tl, 1); + if (cb.f) { + pr_err("syncpt:%lld callback not run\n", cb.f->seqno); + dma_fence_put(cb.f); + goto out; + } + + err = 0; +out: + st_sync_timeline_put(tl); + return 0; +} + +static int cb_destroy_12(void *arg) +{ + struct sync_timeline *tl; + struct cb_destroy cb; + struct dma_fence *f; + int err = -EINVAL; + + /* Check that we can drop some other syncpt reference from a callback */ + + t
[PATCH 2/3] dma-buf/sw_sync: Separate signal/timeline locks
Since we decouple the sync_pt from the timeline tree upon release, in order to allow releasing the sync_pt from a signal callback we need to separate the sync_pt signaling lock from the timeline tree lock. Suggested-by: Bas Nieuwenhuizen Signed-off-by: Chris Wilson Cc: Bas Nieuwenhuizen --- drivers/dma-buf/sw_sync.c| 18 +++--- drivers/dma-buf/sync_debug.h | 2 ++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 807c82148062..116dad6c7905 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -132,14 +132,17 @@ static void timeline_fence_release(struct dma_fence *fence) { struct sync_pt *pt = dma_fence_to_sync_pt(fence); struct sync_timeline *parent = dma_fence_parent(fence); - unsigned long flags; - spin_lock_irqsave(fence->lock, flags); if (!list_empty(&pt->link)) { - list_del(&pt->link); - rb_erase(&pt->node, &parent->pt_tree); + unsigned long flags; + + spin_lock_irqsave(&parent->lock, flags); + if (!list_empty(&pt->link)) { + list_del(&pt->link); + rb_erase(&pt->node, &parent->pt_tree); + } + spin_unlock_irqrestore(&parent->lock, flags); } - spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); dma_fence_free(fence); @@ -252,12 +255,13 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, return NULL; sync_timeline_get(obj); - dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + spin_lock_init(&pt->lock); + dma_fence_init(&pt->base, &timeline_fence_ops, &pt->lock, obj->context, value); INIT_LIST_HEAD(&pt->link); spin_lock_irq(&obj->lock); - if (!dma_fence_is_signaled_locked(&pt->base)) { + if (!dma_fence_is_signaled(&pt->base)) { struct rb_node **p = &obj->pt_tree.rb_node; struct rb_node *parent = NULL; diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index 6176e52ba2d7..fd073fc32329 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -55,11 +55,13 @@ static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) * @base: base fence object * @link: link on the sync timeline's list * @node: node in the sync timeline's tree + * @lock: fence signaling lock */ struct sync_pt { struct dma_fence base; struct list_head link; struct rb_node node; + spinlock_t lock; }; extern const struct file_operations sw_sync_debugfs_fops; -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH 1/3] dma-buf/sw_sync: Avoid recursive lock during fence signal.
From: Bas Nieuwenhuizen Calltree: timeline_fence_release drm_sched_entity_wakeup dma_fence_signal_locked sync_timeline_signal sw_sync_ioctl Releasing the reference to the fence in the fence signal callback seems reasonable to me, so this patch avoids the locking issue in sw_sync. d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") fixed the recursive locking issue but caused an use-after-free. Later d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") fixed the use-after-free but reintroduced the recursive locking issue. In this attempt we avoid the use-after-free still because the release function still always locks, and outside of the locking region in the signal function we have properly refcounted references. We furthermore also avoid the recurive lock by making sure that either: 1) We have a properly refcounted reference, preventing the signal from triggering the release function inside the locked region. 2) The refcount was already zero, and hence nobody will be able to trigger the release function from the signal function. v2: Move dma_fence_signal() into second loop in preparation to moving the callback out of the timeline obj->lock. Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") Cc: Sumit Semwal Cc: Chris Wilson Cc: Gustavo Padovan Cc: Christian König Cc: Signed-off-by: Bas Nieuwenhuizen Signed-off-by: Chris Wilson --- drivers/dma-buf/sw_sync.c | 32 ++-- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 348b3a9170fa..807c82148062 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -192,6 +192,7 @@ static const struct dma_fence_ops timeline_fence_ops = { static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { struct sync_pt *pt, *next; + LIST_HEAD(signal); trace_sync_timeline(obj); @@ -203,21 +204,32 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) if (!timeline_fence_signaled(&pt->base)) break; - list_del_init(&pt->link); - rb_erase(&pt->node, &obj->pt_tree); - /* -* A signal callback may release the last reference to this -* fence, causing it to be freed. That operation has to be -* last to avoid a use after free inside this loop, and must -* be after we remove the fence from the timeline in order to -* prevent deadlocking on timeline->lock inside -* timeline_fence_release(). +* We need to take a reference to avoid a release during +* signalling (which can cause a recursive lock of obj->lock). +* If refcount was already zero, another thread is already +* taking care of destroying the fence. */ - dma_fence_signal_locked(&pt->base); + if (!dma_fence_get_rcu(&pt->base)) + continue; + + list_move_tail(&pt->link, &signal); + rb_erase(&pt->node, &obj->pt_tree); } spin_unlock_irq(&obj->lock); + + list_for_each_entry_safe(pt, next, &signal, link) { + /* +* This needs to be cleared before release, otherwise the +* timeline_fence_release function gets confused about also +* removing the fence from the pt_tree. +*/ + list_del_init(&pt->link); + + dma_fence_signal(&pt->base); + dma_fence_put(&pt->base); + } } /** -- 2.20.1 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] dma-buf/sw_sync: Avoid recursive lock during fence signal.
Quoting Chris Wilson (2020-07-14 19:30:39) > Quoting Bas Nieuwenhuizen (2020-07-14 19:17:21) > > On Tue, Jul 14, 2020 at 6:26 PM Chris Wilson > > wrote: > > > > > > Quoting Bas Nieuwenhuizen (2020-07-14 16:41:02) > > > > Calltree: > > > > timeline_fence_release > > > > drm_sched_entity_wakeup > > > > dma_fence_signal_locked > > > > sync_timeline_signal > > > > sw_sync_ioctl > > > > > > > > Releasing the reference to the fence in the fence signal callback > > > > seems reasonable to me, so this patch avoids the locking issue in > > > > sw_sync. > > > > > > > > d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") > > > > fixed the recursive locking issue but caused an use-after-free. Later > > > > d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > > > > fixed the use-after-free but reintroduced the recursive locking issue. > > > > > > > > In this attempt we avoid the use-after-free still because the release > > > > function still always locks, and outside of the locking region in the > > > > signal function we have properly refcounted references. > > > > > > > > We furthermore also avoid the recurive lock by making sure that either: > > > > > > > > 1) We have a properly refcounted reference, preventing the signal from > > > >triggering the release function inside the locked region. > > > > 2) The refcount was already zero, and hence nobody will be able to > > > > trigger > > > >the release function from the signal function. > > > > > > > > Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt > > > > free") > > > > Cc: Sumit Semwal > > > > Cc: Chris Wilson > > > > Cc: Gustavo Padovan > > > > Cc: Christian König > > > > Cc: > > > > Signed-off-by: Bas Nieuwenhuizen > > > > --- > > > > drivers/dma-buf/sw_sync.c | 28 > > > > 1 file changed, 20 insertions(+), 8 deletions(-) > > > > > > > > diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c > > > > index 348b3a9170fa..30a482f75d56 100644 > > > > --- a/drivers/dma-buf/sw_sync.c > > > > +++ b/drivers/dma-buf/sw_sync.c > > > > @@ -192,9 +192,12 @@ static const struct dma_fence_ops > > > > timeline_fence_ops = { > > > > static void sync_timeline_signal(struct sync_timeline *obj, unsigned > > > > int inc) > > > > { > > > > struct sync_pt *pt, *next; > > > > + struct list_head ref_list; > > > > > > > > trace_sync_timeline(obj); > > > > > > > > + INIT_LIST_HEAD(&ref_list); > > > > + > > > > spin_lock_irq(&obj->lock); > > > > > > > > obj->value += inc; > > > > @@ -206,18 +209,27 @@ static void sync_timeline_signal(struct > > > > sync_timeline *obj, unsigned int inc) > > > > list_del_init(&pt->link); > > > > rb_erase(&pt->node, &obj->pt_tree); > > > > > > > > - /* > > > > -* A signal callback may release the last reference to > > > > this > > > > -* fence, causing it to be freed. That operation has to > > > > be > > > > -* last to avoid a use after free inside this loop, and > > > > must > > > > -* be after we remove the fence from the timeline in > > > > order to > > > > -* prevent deadlocking on timeline->lock inside > > > > -* timeline_fence_release(). > > > > -*/ > > > > + /* We need to take a reference to avoid a release during > > > > +* signalling (which can cause a recursive lock of > > > > obj->lock). > > > > +* If refcount was already zero, another thread is > > > > already taking > > > > +* care of destructing the fence, so the signal cannot > > > > release > > > > +* it again and we hence will not have the recursive > > > > lock. */ > > > > > > /* > > > * Block commentary style: > > > * > > > https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting > > > */ > > > > > > > + if (dma_fence_get_rcu(&pt->base)) > > > > + list_add_tail(&pt->link, &ref_list); > > > > > > Ok. > > > > > > > + > > > > dma_fence_signal_locked(&pt->base); > > > > } > > > > > > > > spin_unlock_irq(&obj->lock); > > > > + > > > > + list_for_each_entry_safe(pt, next, &ref_list, link) { > > > > + /* This needs to be cleared before release, otherwise > > > > the > > > > +* timeline_fence_release function gets confused about > > > > also > > > > +* removing the fence from the pt_tree. */ > > > > + list_del_init(&pt->link); > > > > + > > > > + dma_fence_put(&pt->base); > > > > + } > > > > > > How serious is the problem of one fence callback freeing another pt? > > > > > > Following the pattern here > > > > > > spin_lock(&obj->lock); > > > list_for_each_entry_safe(pt, next, &obj->pt_list, link)
Re: [PATCH v3 0/6] Generic USB Display driver
Noralf Trønnes wrote: > > In all cases, the driver on the host knows/has available how many bytes > > were successfully transfered. > > I was thinking about the device, that it could get out of sync. Let's > say the host sends a 1k framebuffer and half of it gets transferred and > the rest fails for some reason. Lubomir's MCU implementation has an > endpoint max size of 64 bytes and a callback is called for each packet. > If the 1k transfer fails at some point, will the device be able to > detect this and know that the next time the rx callback is called that > this is the start of a new framebuffer update? Ah! No, a device can not detect that the host intended to send more (bulk) packets but e.g. timed out. I can't immediately think of other reasons for a larger transfer to fail, which still allow communication to continue. When the host recognizes a timeout with partial data transfer it could simply send the remaining data in a new transfer. While the device can not detect host intent, the protocol could allow devices to specify requirements, e.g. that the host always sends full frames. In any case, please avoid making a control request mandatory for frame transfer. Because control requests are scheduled differently onto the wire and because they consist of more packets than bulk data, a control request will interrupt a bulk data stream and likely introduce unneccessary latency. If synchronization is always required then I'd suggest to place it inline with frame data, e.g. in the first packet byte. If synchronization is only required in rare cases then a control transfer is probably the better choice, to not waste any inline bytes. But the optimum would be that the device can describe its needs to the host and the host driver ensures that the device always receives the data it needs. Do you think this is possible? Kind regards //Peter ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v3 0/6] Generic USB Display driver
Den 14.07.2020 19.40, skrev Peter Stuge: > Hi Noralf, > > Noralf Trønnes wrote: >> I would like to keep the SET_BUFFER request since it will serve as a >> syncing point between the host and the device. I'm no USB expert but I >> assume that a bulk transfer can fail halfway through and result in the >> next update starting where the previous one failed and thus writing >> beyond the end of the display buffer. > > Transfers either succeed completely (possibly after many retries), > time out (after zero or more transfered bytes) or fail catastrophically > (e.g. from device disconnect). > > In all cases, the driver on the host knows/has available how many bytes > were successfully transfered. > I was thinking about the device, that it could get out of sync. Let's say the host sends a 1k framebuffer and half of it gets transferred and the rest fails for some reason. Lubomir's MCU implementation has an endpoint max size of 64 bytes and a callback is called for each packet. If the 1k transfer fails at some point, will the device be able to detect this and know that the next time the rx callback is called that this is the start of a new framebuffer update? Noralf. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] drm/vkms: add wait_for_vblanks in atomic_commit_tail
On 07/14, Daniel Vetter wrote: > On Tue, Jul 14, 2020 at 07:39:42AM -0300, Melissa Wen wrote: > > On Tue, Jul 14, 2020 at 7:20 AM Melissa Wen wrote: > > > > > > On 07/13, Daniel Vetter wrote: > > > > On Fri, Jul 10, 2020 at 02:05:33PM -0300, Melissa Wen wrote: > > > > > On 07/02, Daniel Vetter wrote: > > > > > > On Wed, Jul 01, 2020 at 03:31:34PM +, Sidong Yang wrote: > > > > > > > there is an error when igt test is run continuously. > > > > > > > vkms_atomic_commit_tail() > > > > > > > need to call drm_atomic_helper_wait_for_vblanks() for give up > > > > > > > ownership of > > > > > > > vblank events. without this code, next atomic commit will not > > > > > > > enable vblank > > > > > > > and raise timeout error. > > > > > > > > > > > > > > Signed-off-by: Sidong Yang > > > > > > > --- > > > > > > > drivers/gpu/drm/vkms/vkms_drv.c | 2 ++ > > > > > > > 1 file changed, 2 insertions(+) > > > > > > > > > > > > > > diff --git a/drivers/gpu/drm/vkms/vkms_drv.c > > > > > > > b/drivers/gpu/drm/vkms/vkms_drv.c > > > > > > > index 1e8b2169d834..10b9be67a068 100644 > > > > > > > --- a/drivers/gpu/drm/vkms/vkms_drv.c > > > > > > > +++ b/drivers/gpu/drm/vkms/vkms_drv.c > > > > > > > @@ -93,6 +93,8 @@ static void vkms_atomic_commit_tail(struct > > > > > > > drm_atomic_state *old_state) > > > > > > > flush_work(&vkms_state->composer_work); > > > > > > > } > > > > > > > > > > > > > > + drm_atomic_helper_wait_for_vblanks(dev, old_state); > > > > > > > > > > > > Uh, we have a wait_for_flip_done right above, which should be doing > > > > > > exactly the same, but more precisely: Instead of just waiting for > > > > > > any > > > > > > vblank to happen, we wait for exactly the vblank corresponding to > > > > > > this > > > > > > atomic commit. So no races possible. If this is papering over some > > > > > > issue, > > > > > > then I think more debugging is needed. > > > > > > > > > > > > What exactly is going wrong here for you? > > > > > > > > > > Hi Daniel and Sidong, > > > > > > > > > > I noticed a similar issue when running the IGT test kms_cursor_crc. > > > > > For > > > > > example, a subtest that passes on the first run (alpha-opaque) fails > > > > > on > > > > > the second due to a kind of busy waiting in subtest preparation (the > > > > > subtest fails before actually running). > > > > > > > > > > In addition, in the same test, the dpms subtest started to fail since > > > > > the commit that change from wait_for_vblanks to wait_for_flip_done. By > > > > > reverting this commit, the dpms subtest passes again and the > > > > > sequential > > > > > subtests return to normal. > > > > > > > > > > I am trying to figure out what's missing from using flip_done op on > > > > > vkms, since I am also interested in solving this problem and I > > > > > understand that the change for flip_done has been discussed in the > > > > > past. > > > > > > > > > > Do you have any idea? > > > > > > > > Uh, not at all. This is indeed rather surprising ... > > > > > > > > What exactly is the failure mode when running a test the 2nd time? Full > > > > igt logs might give me an idea. But yeah this is kinda surprising. > > > > > > Hi Daniel, > > > > > > This is the IGT log of the 2nd run of kms_cursor_crc/alpha-opaque: > > > > > > IGT-Version: 1.25-NO-GIT (x86_64) (Linux: 5.8.0-rc2-DRM+ x86_64) > > > Force option used: Using driver vkms > > > Starting subtest: pipe-A-cursor-alpha-opaque > > > Timed out: Opening crc fd, and poll for first CRC. > > > Subtest pipe-A-cursor-alpha-opaque failed. > > > DEBUG > > > (kms_cursor_crc:2317) igt_kms-DEBUG: display: Virtual-1: set_pipe(A) > > > (kms_cursor_crc:2317) igt_kms-DEBUG: display: Virtual-1: Selecting pipe A > > > (kms_cursor_crc:2317) igt_fb-DEBUG: > > > igt_create_fb_with_bo_size(width=1024, height=768, > > > format=XR24(0x34325258), modifier=0x0, size=0) > > > (kms_cursor_crc:2317) igt_fb-DEBUG: igt_create_fb_with_bo_size(handle=1, > > > pitch=4096) > > > (kms_cursor_crc:2317) igt_fb-DEBUG: Test requirement passed: > > > cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS > > > (kms_cursor_crc:2317) igt_fb-DEBUG: > > > igt_create_fb_with_bo_size(width=1024, height=768, > > > format=XR24(0x34325258), modifier=0x0, size=0) > > > (kms_cursor_crc:2317) igt_fb-DEBUG: igt_create_fb_with_bo_size(handle=2, > > > pitch=4096) > > > (kms_cursor_crc:2317) igt_fb-DEBUG: Test requirement passed: > > > cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS > > > (kms_cursor_crc:2317) igt_kms-DEBUG: Test requirement passed: plane_idx > > > >= 0 && plane_idx < pipe->n_planes > > > (kms_cursor_crc:2317) igt_kms-DEBUG: Test requirement passed: plane_idx > > > >= 0 && plane_idx < pipe->n_planes > > > (kms_cursor_crc:2317) igt_kms-DEBUG: display: A.0: plane_set_fb(37) > > > (kms_cursor_crc:2317) igt_kms-DEBUG: display: A.0: plane_set_size > > > (1024x768) > > > (kms_cursor_crc:2317) igt_kms-DEBUG: display: A.0: fb_set_position(0,
[PATCH][next] drm/rockchip: lvds: ensure ret is assigned before checking for an error
From: Colin Ian King Currently there are two places where the return status in ret is being checked for an error however the assignment of ret has been omitted making the checks redundant. Fix this by adding in the missing assignments of ret. Addresses-Coverity: ("Logically dead code") Fixes: cca1705c3d89 ("drm/rockchip: lvds: Add PX30 support") Signed-off-by: Colin Ian King --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 63f967902c2d..b45c618b9793 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -499,11 +499,11 @@ static int px30_lvds_probe(struct platform_device *pdev, if (IS_ERR(lvds->dphy)) return PTR_ERR(lvds->dphy); - phy_init(lvds->dphy); + ret = phy_init(lvds->dphy); if (ret) return ret; - phy_set_mode(lvds->dphy, PHY_MODE_LVDS); + ret = phy_set_mode(lvds->dphy, PHY_MODE_LVDS); if (ret) return ret; -- 2.27.0 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 1/2] dma-buf.rst: Document why indefinite fences are a bad idea
This matches my understanding for what it's worth. In my little bit of synchronization work in drm, I've gone out of my way to ensure we can maintain this constraint. Acked-by: Jason Ekstrand On Thu, Jul 9, 2020 at 7:33 AM Daniel Vetter wrote: > > Comes up every few years, gets somewhat tedious to discuss, let's > write this down once and for all. > > What I'm not sure about is whether the text should be more explicit in > flat out mandating the amdkfd eviction fences for long running compute > workloads or workloads where userspace fencing is allowed. > > v2: Now with dot graph! > > v3: Typo (Dave Airlie) > > Acked-by: Christian König > Acked-by: Daniel Stone > Cc: Jesse Natalie > Cc: Steve Pronovost > Cc: Jason Ekstrand > Cc: Felix Kuehling > Cc: Mika Kuoppala > Cc: Thomas Hellstrom > Cc: linux-me...@vger.kernel.org > Cc: linaro-mm-...@lists.linaro.org > Cc: linux-r...@vger.kernel.org > Cc: amd-...@lists.freedesktop.org > Cc: intel-...@lists.freedesktop.org > Cc: Chris Wilson > Cc: Maarten Lankhorst > Cc: Christian König > Signed-off-by: Daniel Vetter > --- > Documentation/driver-api/dma-buf.rst | 70 > 1 file changed, 70 insertions(+) > > diff --git a/Documentation/driver-api/dma-buf.rst > b/Documentation/driver-api/dma-buf.rst > index f8f6decde359..100bfd227265 100644 > --- a/Documentation/driver-api/dma-buf.rst > +++ b/Documentation/driver-api/dma-buf.rst > @@ -178,3 +178,73 @@ DMA Fence uABI/Sync File > .. kernel-doc:: include/linux/sync_file.h > :internal: > > +Indefinite DMA Fences > + > + > +At various times &dma_fence with an indefinite time until dma_fence_wait() > +finishes have been proposed. Examples include: > + > +* Future fences, used in HWC1 to signal when a buffer isn't used by the > display > + any longer, and created with the screen update that makes the buffer > visible. > + The time this fence completes is entirely under userspace's control. > + > +* Proxy fences, proposed to handle &drm_syncobj for which the fence has not > yet > + been set. Used to asynchronously delay command submission. > + > +* Userspace fences or gpu futexes, fine-grained locking within a command > buffer > + that userspace uses for synchronization across engines or with the CPU, > which > + are then imported as a DMA fence for integration into existing winsys > + protocols. > + > +* Long-running compute command buffers, while still using traditional end of > + batch DMA fences for memory management instead of context preemption DMA > + fences which get reattached when the compute job is rescheduled. > + > +Common to all these schemes is that userspace controls the dependencies of > these > +fences and controls when they fire. Mixing indefinite fences with normal > +in-kernel DMA fences does not work, even when a fallback timeout is included > to > +protect against malicious userspace: > + > +* Only the kernel knows about all DMA fence dependencies, userspace is not > aware > + of dependencies injected due to memory management or scheduler decisions. > + > +* Only userspace knows about all dependencies in indefinite fences and when > + exactly they will complete, the kernel has no visibility. > + > +Furthermore the kernel has to be able to hold up userspace command submission > +for memory management needs, which means we must support indefinite fences > being > +dependent upon DMA fences. If the kernel also support indefinite fences in > the > +kernel like a DMA fence, like any of the above proposal would, there is the > +potential for deadlocks. > + > +.. kernel-render:: DOT > + :alt: Indefinite Fencing Dependency Cycle > + :caption: Indefinite Fencing Dependency Cycle > + > + digraph "Fencing Cycle" { > + node [shape=box bgcolor=grey style=filled] > + kernel [label="Kernel DMA Fences"] > + userspace [label="userspace controlled fences"] > + kernel -> userspace [label="memory management"] > + userspace -> kernel [label="Future fence, fence proxy, ..."] > + > + { rank=same; kernel userspace } > + } > + > +This means that the kernel might accidentally create deadlocks > +through memory management dependencies which userspace is unaware of, which > +randomly hangs workloads until the timeout kicks in. Workloads, which from > +userspace's perspective, do not contain a deadlock. In such a mixed fencing > +architecture there is no single entity with knowledge of all dependencies. > +Thefore preventing such deadlocks from within the kernel is not possible. > + > +The only solution to avoid dependencies loops is by not allowing indefinite > +fences in the kernel. This means: > + > +* No future fences, proxy fences or userspace fences imported as DMA fences, > + with or without a timeout. > + > +* No DMA fences that signal end of batchbuffer for command submission where > + userspace is allowed to use userspace fencing or long running compute > + workloads. This also means no implicit
Re: [PATCH] drm: msm: a6xx: fix gpu failure after system resume
On Tue, Jul 14, 2020 at 10:10 AM Matthias Kaehlcke wrote: > > On Tue, Jul 14, 2020 at 06:55:30PM +0530, Akhil P Oommen wrote: > > On targets where GMU is available, GMU takes over the ownership of GX GDSC > > during its initialization. So, take a refcount on the GX PD on behalf of > > GMU before we initialize it. This makes sure that nobody can collapse the > > GX GDSC once GMU owns the GX GDSC. This patch fixes some weird failures > > during GPU wake up during system resume. > > > > Signed-off-by: Akhil P Oommen > > I went through a few dozen suspend/resume cycles on SC7180 and didn't run > into the kernel panic that typically occurs after a few iterations without > this patch. > > Reported-by: Matthias Kaehlcke > Tested-by: Matthias Kaehlcke > > On which tree is this patch based on? I had to apply it manually because > 'git am' is unhappy when I try to apply it: > > error: sha1 information is lacking or useless > (drivers/gpu/drm/msm/adreno/a6xx_gmu.c). > error: could not build fake ancestor > > Both upstream and drm-msm are in my remotes and synced, so I suspect it's > some private tree. Please make sure to base patches on the corresponding > maintainer tree or upstream, whichs makes life easier for maintainers, > testers and reviewers. I've run into the same issue frequently :-( BR, -R ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] dma-buf/sw_sync: Avoid recursive lock during fence signal.
Quoting Bas Nieuwenhuizen (2020-07-14 19:17:21) > On Tue, Jul 14, 2020 at 6:26 PM Chris Wilson wrote: > > > > Quoting Bas Nieuwenhuizen (2020-07-14 16:41:02) > > > Calltree: > > > timeline_fence_release > > > drm_sched_entity_wakeup > > > dma_fence_signal_locked > > > sync_timeline_signal > > > sw_sync_ioctl > > > > > > Releasing the reference to the fence in the fence signal callback > > > seems reasonable to me, so this patch avoids the locking issue in > > > sw_sync. > > > > > > d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") > > > fixed the recursive locking issue but caused an use-after-free. Later > > > d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > > > fixed the use-after-free but reintroduced the recursive locking issue. > > > > > > In this attempt we avoid the use-after-free still because the release > > > function still always locks, and outside of the locking region in the > > > signal function we have properly refcounted references. > > > > > > We furthermore also avoid the recurive lock by making sure that either: > > > > > > 1) We have a properly refcounted reference, preventing the signal from > > >triggering the release function inside the locked region. > > > 2) The refcount was already zero, and hence nobody will be able to trigger > > >the release function from the signal function. > > > > > > Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > > > Cc: Sumit Semwal > > > Cc: Chris Wilson > > > Cc: Gustavo Padovan > > > Cc: Christian König > > > Cc: > > > Signed-off-by: Bas Nieuwenhuizen > > > --- > > > drivers/dma-buf/sw_sync.c | 28 > > > 1 file changed, 20 insertions(+), 8 deletions(-) > > > > > > diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c > > > index 348b3a9170fa..30a482f75d56 100644 > > > --- a/drivers/dma-buf/sw_sync.c > > > +++ b/drivers/dma-buf/sw_sync.c > > > @@ -192,9 +192,12 @@ static const struct dma_fence_ops timeline_fence_ops > > > = { > > > static void sync_timeline_signal(struct sync_timeline *obj, unsigned int > > > inc) > > > { > > > struct sync_pt *pt, *next; > > > + struct list_head ref_list; > > > > > > trace_sync_timeline(obj); > > > > > > + INIT_LIST_HEAD(&ref_list); > > > + > > > spin_lock_irq(&obj->lock); > > > > > > obj->value += inc; > > > @@ -206,18 +209,27 @@ static void sync_timeline_signal(struct > > > sync_timeline *obj, unsigned int inc) > > > list_del_init(&pt->link); > > > rb_erase(&pt->node, &obj->pt_tree); > > > > > > - /* > > > -* A signal callback may release the last reference to > > > this > > > -* fence, causing it to be freed. That operation has to be > > > -* last to avoid a use after free inside this loop, and > > > must > > > -* be after we remove the fence from the timeline in > > > order to > > > -* prevent deadlocking on timeline->lock inside > > > -* timeline_fence_release(). > > > -*/ > > > + /* We need to take a reference to avoid a release during > > > +* signalling (which can cause a recursive lock of > > > obj->lock). > > > +* If refcount was already zero, another thread is > > > already taking > > > +* care of destructing the fence, so the signal cannot > > > release > > > +* it again and we hence will not have the recursive > > > lock. */ > > > > /* > > * Block commentary style: > > * > > https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting > > */ > > > > > + if (dma_fence_get_rcu(&pt->base)) > > > + list_add_tail(&pt->link, &ref_list); > > > > Ok. > > > > > + > > > dma_fence_signal_locked(&pt->base); > > > } > > > > > > spin_unlock_irq(&obj->lock); > > > + > > > + list_for_each_entry_safe(pt, next, &ref_list, link) { > > > + /* This needs to be cleared before release, otherwise the > > > +* timeline_fence_release function gets confused about > > > also > > > +* removing the fence from the pt_tree. */ > > > + list_del_init(&pt->link); > > > + > > > + dma_fence_put(&pt->base); > > > + } > > > > How serious is the problem of one fence callback freeing another pt? > > > > Following the pattern here > > > > spin_lock(&obj->lock); > > list_for_each_entry_safe(pt, next, &obj->pt_list, link) { > > if (!timeline_fence_signaled(&pt->base)) > > break; > > > > if (!dma_fence_get_rcu(&pt->base)) > > continue; /* too late! */ > > > > rb_erase(&pt->node, &obj->pt_tree); > > list_move_tail(&pt->link, &ref_l
Re: [PATCH] dma-buf/sw_sync: Avoid recursive lock during fence signal.
On Tue, Jul 14, 2020 at 6:26 PM Chris Wilson wrote: > > Quoting Bas Nieuwenhuizen (2020-07-14 16:41:02) > > Calltree: > > timeline_fence_release > > drm_sched_entity_wakeup > > dma_fence_signal_locked > > sync_timeline_signal > > sw_sync_ioctl > > > > Releasing the reference to the fence in the fence signal callback > > seems reasonable to me, so this patch avoids the locking issue in > > sw_sync. > > > > d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") > > fixed the recursive locking issue but caused an use-after-free. Later > > d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > > fixed the use-after-free but reintroduced the recursive locking issue. > > > > In this attempt we avoid the use-after-free still because the release > > function still always locks, and outside of the locking region in the > > signal function we have properly refcounted references. > > > > We furthermore also avoid the recurive lock by making sure that either: > > > > 1) We have a properly refcounted reference, preventing the signal from > >triggering the release function inside the locked region. > > 2) The refcount was already zero, and hence nobody will be able to trigger > >the release function from the signal function. > > > > Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > > Cc: Sumit Semwal > > Cc: Chris Wilson > > Cc: Gustavo Padovan > > Cc: Christian König > > Cc: > > Signed-off-by: Bas Nieuwenhuizen > > --- > > drivers/dma-buf/sw_sync.c | 28 > > 1 file changed, 20 insertions(+), 8 deletions(-) > > > > diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c > > index 348b3a9170fa..30a482f75d56 100644 > > --- a/drivers/dma-buf/sw_sync.c > > +++ b/drivers/dma-buf/sw_sync.c > > @@ -192,9 +192,12 @@ static const struct dma_fence_ops timeline_fence_ops = > > { > > static void sync_timeline_signal(struct sync_timeline *obj, unsigned int > > inc) > > { > > struct sync_pt *pt, *next; > > + struct list_head ref_list; > > > > trace_sync_timeline(obj); > > > > + INIT_LIST_HEAD(&ref_list); > > + > > spin_lock_irq(&obj->lock); > > > > obj->value += inc; > > @@ -206,18 +209,27 @@ static void sync_timeline_signal(struct sync_timeline > > *obj, unsigned int inc) > > list_del_init(&pt->link); > > rb_erase(&pt->node, &obj->pt_tree); > > > > - /* > > -* A signal callback may release the last reference to this > > -* fence, causing it to be freed. That operation has to be > > -* last to avoid a use after free inside this loop, and must > > -* be after we remove the fence from the timeline in order > > to > > -* prevent deadlocking on timeline->lock inside > > -* timeline_fence_release(). > > -*/ > > + /* We need to take a reference to avoid a release during > > +* signalling (which can cause a recursive lock of > > obj->lock). > > +* If refcount was already zero, another thread is already > > taking > > +* care of destructing the fence, so the signal cannot > > release > > +* it again and we hence will not have the recursive lock. > > */ > > /* > * Block commentary style: > * https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting > */ > > > + if (dma_fence_get_rcu(&pt->base)) > > + list_add_tail(&pt->link, &ref_list); > > Ok. > > > + > > dma_fence_signal_locked(&pt->base); > > } > > > > spin_unlock_irq(&obj->lock); > > + > > + list_for_each_entry_safe(pt, next, &ref_list, link) { > > + /* This needs to be cleared before release, otherwise the > > +* timeline_fence_release function gets confused about also > > +* removing the fence from the pt_tree. */ > > + list_del_init(&pt->link); > > + > > + dma_fence_put(&pt->base); > > + } > > How serious is the problem of one fence callback freeing another pt? > > Following the pattern here > > spin_lock(&obj->lock); > list_for_each_entry_safe(pt, next, &obj->pt_list, link) { > if (!timeline_fence_signaled(&pt->base)) > break; > > if (!dma_fence_get_rcu(&pt->base)) > continue; /* too late! */ > > rb_erase(&pt->node, &obj->pt_tree); > list_move_tail(&pt->link, &ref_list); > } > spin_unlock(&obj->lock); > > list_for_each_entry_safe(pt, next, &ref_list, link) { > list_del_init(&pt->link); > dma_fence_signal(&pt->base); Question is what the scope should be. Using this method we only take a reference and avoid releasing the fenc
Re: [PATCH v3 0/6] Generic USB Display driver
Hi Noralf, Noralf Trønnes wrote: > I would like to keep the SET_BUFFER request since it will serve as a > syncing point between the host and the device. I'm no USB expert but I > assume that a bulk transfer can fail halfway through and result in the > next update starting where the previous one failed and thus writing > beyond the end of the display buffer. Transfers either succeed completely (possibly after many retries), time out (after zero or more transfered bytes) or fail catastrophically (e.g. from device disconnect). In all cases, the driver on the host knows/has available how many bytes were successfully transfered. //Peter ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] drm: msm: a6xx: fix gpu failure after system resume
On Tue, Jul 14, 2020 at 06:55:30PM +0530, Akhil P Oommen wrote: > On targets where GMU is available, GMU takes over the ownership of GX GDSC > during its initialization. So, take a refcount on the GX PD on behalf of > GMU before we initialize it. This makes sure that nobody can collapse the > GX GDSC once GMU owns the GX GDSC. This patch fixes some weird failures > during GPU wake up during system resume. > > Signed-off-by: Akhil P Oommen I went through a few dozen suspend/resume cycles on SC7180 and didn't run into the kernel panic that typically occurs after a few iterations without this patch. Reported-by: Matthias Kaehlcke Tested-by: Matthias Kaehlcke On which tree is this patch based on? I had to apply it manually because 'git am' is unhappy when I try to apply it: error: sha1 information is lacking or useless (drivers/gpu/drm/msm/adreno/a6xx_gmu.c). error: could not build fake ancestor Both upstream and drm-msm are in my remotes and synced, so I suspect it's some private tree. Please make sure to base patches on the corresponding maintainer tree or upstream, whichs makes life easier for maintainers, testers and reviewers. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[RFC PATCH] drm/i915: g4x_get_flip_counter() can be static
Signed-off-by: kernel test robot --- i915_irq.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9812a8051c5ea..79a3118f918a1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -697,7 +697,7 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc) return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xff; } -u32 g4x_get_flip_counter(struct drm_crtc *crtc) +static u32 g4x_get_flip_counter(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); enum pipe pipe = to_intel_crtc(crtc)->pipe; ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v4 1/5] drm/i915: Add enable/disable flip done and flip done handler
Hi Karthik, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next tegra-drm/drm/tegra/for-next v5.8-rc5 next-20200714] [cannot apply to drm/drm-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Karthik-B-S/Asynchronous-flip-implementation-for-i915/20200714-095304 base: git://anongit.freedesktop.org/drm-intel for-linux-next config: x86_64-randconfig-s032-20200714 (attached as .config) compiler: gcc-9 (Debian 9.3.0-14) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.2-41-g14e84ffc-dirty # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot sparse warnings: (new ones prefixed by >>) >> drivers/gpu/drm/i915/i915_irq.c:700:5: sparse: sparse: symbol >> 'g4x_get_flip_counter' was not declared. Should it be static? Please review and possibly fold the followup patch. --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org .config.gz Description: application/gzip ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH] dma-buf/sw_sync: Avoid recursive lock during fence signal.
Quoting Bas Nieuwenhuizen (2020-07-14 16:41:02) > Calltree: > timeline_fence_release > drm_sched_entity_wakeup > dma_fence_signal_locked > sync_timeline_signal > sw_sync_ioctl > > Releasing the reference to the fence in the fence signal callback > seems reasonable to me, so this patch avoids the locking issue in > sw_sync. > > d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") > fixed the recursive locking issue but caused an use-after-free. Later > d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > fixed the use-after-free but reintroduced the recursive locking issue. > > In this attempt we avoid the use-after-free still because the release > function still always locks, and outside of the locking region in the > signal function we have properly refcounted references. > > We furthermore also avoid the recurive lock by making sure that either: > > 1) We have a properly refcounted reference, preventing the signal from >triggering the release function inside the locked region. > 2) The refcount was already zero, and hence nobody will be able to trigger >the release function from the signal function. > > Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") > Cc: Sumit Semwal > Cc: Chris Wilson > Cc: Gustavo Padovan > Cc: Christian König > Cc: > Signed-off-by: Bas Nieuwenhuizen > --- > drivers/dma-buf/sw_sync.c | 28 > 1 file changed, 20 insertions(+), 8 deletions(-) > > diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c > index 348b3a9170fa..30a482f75d56 100644 > --- a/drivers/dma-buf/sw_sync.c > +++ b/drivers/dma-buf/sw_sync.c > @@ -192,9 +192,12 @@ static const struct dma_fence_ops timeline_fence_ops = { > static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) > { > struct sync_pt *pt, *next; > + struct list_head ref_list; > > trace_sync_timeline(obj); > > + INIT_LIST_HEAD(&ref_list); > + > spin_lock_irq(&obj->lock); > > obj->value += inc; > @@ -206,18 +209,27 @@ static void sync_timeline_signal(struct sync_timeline > *obj, unsigned int inc) > list_del_init(&pt->link); > rb_erase(&pt->node, &obj->pt_tree); > > - /* > -* A signal callback may release the last reference to this > -* fence, causing it to be freed. That operation has to be > -* last to avoid a use after free inside this loop, and must > -* be after we remove the fence from the timeline in order to > -* prevent deadlocking on timeline->lock inside > -* timeline_fence_release(). > -*/ > + /* We need to take a reference to avoid a release during > +* signalling (which can cause a recursive lock of obj->lock). > +* If refcount was already zero, another thread is already > taking > +* care of destructing the fence, so the signal cannot release > +* it again and we hence will not have the recursive lock. */ /* * Block commentary style: * https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting */ > + if (dma_fence_get_rcu(&pt->base)) > + list_add_tail(&pt->link, &ref_list); Ok. > + > dma_fence_signal_locked(&pt->base); > } > > spin_unlock_irq(&obj->lock); > + > + list_for_each_entry_safe(pt, next, &ref_list, link) { > + /* This needs to be cleared before release, otherwise the > +* timeline_fence_release function gets confused about also > +* removing the fence from the pt_tree. */ > + list_del_init(&pt->link); > + > + dma_fence_put(&pt->base); > + } How serious is the problem of one fence callback freeing another pt? Following the pattern here spin_lock(&obj->lock); list_for_each_entry_safe(pt, next, &obj->pt_list, link) { if (!timeline_fence_signaled(&pt->base)) break; if (!dma_fence_get_rcu(&pt->base)) continue; /* too late! */ rb_erase(&pt->node, &obj->pt_tree); list_move_tail(&pt->link, &ref_list); } spin_unlock(&obj->lock); list_for_each_entry_safe(pt, next, &ref_list, link) { list_del_init(&pt->link); dma_fence_signal(&pt->base); dma_fence_put(&pt->base); } Marginal extra cost for signaling along the debug sw_timeline for total peace of mind. -Chris ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [v1] drm/msm/dpu: add support for clk and bw scaling for display
On Tue, Jul 14, 2020 at 04:39:47PM +0530, kalya...@codeaurora.org wrote: > On 2020-07-14 06:42, Matthias Kaehlcke wrote: > > On Thu, Jun 18, 2020 at 07:38:41PM +0530, Kalyan Thota wrote: > > > This change adds support to scale src clk and bandwidth as > > > per composition requirements. > > > > > > Interconnect registration for bw has been moved to mdp > > > device node from mdss to facilitate the scaling. > > > > > > Changes in v1: > > > - Address armv7 compilation issues with the patch (Rob) > > > > > > Signed-off-by: Kalyan Thota > > > > It seems this is an evolution of this series: > > https://patchwork.kernel.org/project/linux-arm-msm/list/?series=265351 > > > > Are the DT bits of the series still valid? If so please include them in > > the > > series, otherwise please add DT patches to allow folks to test and > > review, > > and get them landed in Bjorn's tree after the driver changes have > > landed. > > Hi, > > Yes the patch is dependent on the DT changes, should i add them with depends > tag in the commit text ? > https://patchwork.kernel.org/patch/11470785/ > https://patchwork.kernel.org/patch/11470789/ This patch doesn't really depend on the DT changes. I would suggest to make this a series of 3 patches, just like the original series linked above. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
[PATCH] drm/i915: Avoid modeset when content protection changes
From: Sean Paul Instead of doing a full modeset to enable/disable content protection, simply go through the update_pipe flow which was introduced in the related patch below. This avoids flashing the screen every time the user starts viewing protected content. Related: 634852d1f468 ("drm/i915: HDCP state handling in ddi_update_pipe") Cc: Ramalingam C Cc: Daniel Vetter Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: intel-...@lists.freedesktop.org Signed-off-by: Sean Paul --- drivers/gpu/drm/i915/display/intel_hdcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 89a4d294822d..839ce1715253 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -2191,7 +2191,7 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, return; } - crtc_state->mode_changed = true; + to_intel_crtc_state(crtc_state)->update_pipe = true; } /* Handles the CP_IRQ raised from the DP HDCP sink */ -- Sean Paul, Software Engineer, Google / Chromium OS ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [Freedreno] [v1] drm/msm/dpu: add support for clk and bw scaling for display
On Tue, Jul 14, 2020 at 4:20 AM wrote: > > On 2020-07-13 22:50, Rob Clark wrote: > > On Mon, Jul 13, 2020 at 8:59 AM wrote: > >> > >> On 2020-07-10 22:38, Rob Clark wrote: > >> > On Thu, Jun 18, 2020 at 7:09 AM Kalyan Thota > >> > wrote: > >> >> > >> >> This change adds support to scale src clk and bandwidth as > >> >> per composition requirements. > >> >> > >> >> Interconnect registration for bw has been moved to mdp > >> >> device node from mdss to facilitate the scaling. > >> >> > >> >> Changes in v1: > >> >> - Address armv7 compilation issues with the patch (Rob) > >> >> > >> >> Signed-off-by: Kalyan Thota > >> >> --- > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 109 > >> >> + > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 5 +- > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 + > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c| 37 - > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h| 4 + > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c | 9 +- > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 84 > >> >> +++ > >> >> drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 4 + > >> >> 8 files changed, 233 insertions(+), 23 deletions(-) > >> >> > >> >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > >> >> b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > >> >> index 7c230f7..e52bc44 100644 > >> >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > >> >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c > >> >> @@ -29,6 +29,74 @@ enum dpu_perf_mode { > >> >> DPU_PERF_MODE_MAX > >> >> }; > >> >> > >> >> +/** > >> >> + * @_dpu_core_perf_calc_bw() - to calculate BW per crtc > >> >> + * @kms - pointer to the dpu_kms > >> >> + * @crtc - pointer to a crtc > >> >> + * Return: returns aggregated BW for all planes in crtc. > >> >> + */ > >> >> +static u64 _dpu_core_perf_calc_bw(struct dpu_kms *kms, > >> >> + struct drm_crtc *crtc) > >> >> +{ > >> >> + struct drm_plane *plane; > >> >> + struct dpu_plane_state *pstate; > >> >> + u64 crtc_plane_bw = 0; > >> >> + u32 bw_factor; > >> >> + > >> >> + drm_atomic_crtc_for_each_plane(plane, crtc) { > >> >> + pstate = to_dpu_plane_state(plane->state); > >> >> + if (!pstate) > >> >> + continue; > >> >> + > >> >> + crtc_plane_bw += pstate->plane_fetch_bw; > >> >> + } > >> >> + > >> >> + bw_factor = kms->catalog->perf.bw_inefficiency_factor; > >> >> + if (bw_factor) { > >> >> + crtc_plane_bw *= bw_factor; > >> >> + do_div(crtc_plane_bw, 100); > >> >> + } > >> >> + > >> >> + return crtc_plane_bw; > >> >> +} > >> >> + > >> >> +/** > >> >> + * _dpu_core_perf_calc_clk() - to calculate clock per crtc > >> >> + * @kms - pointer to the dpu_kms > >> >> + * @crtc - pointer to a crtc > >> >> + * @state - pointer to a crtc state > >> >> + * Return: returns max clk for all planes in crtc. > >> >> + */ > >> >> +static u64 _dpu_core_perf_calc_clk(struct dpu_kms *kms, > >> >> + struct drm_crtc *crtc, struct drm_crtc_state *state) > >> >> +{ > >> >> + struct drm_plane *plane; > >> >> + struct dpu_plane_state *pstate; > >> >> + struct drm_display_mode *mode; > >> >> + u64 crtc_clk; > >> >> + u32 clk_factor; > >> >> + > >> >> + mode = &state->adjusted_mode; > >> >> + > >> >> + crtc_clk = mode->vtotal * mode->hdisplay * > >> >> drm_mode_vrefresh(mode); > >> >> + > >> >> + drm_atomic_crtc_for_each_plane(plane, crtc) { > >> >> + pstate = to_dpu_plane_state(plane->state); > >> >> + if (!pstate) > >> >> + continue; > >> >> + > >> >> + crtc_clk = max(pstate->plane_clk, crtc_clk); > >> >> + } > >> >> + > >> >> + clk_factor = kms->catalog->perf.clk_inefficiency_factor; > >> >> + if (clk_factor) { > >> >> + crtc_clk *= clk_factor; > >> >> + do_div(crtc_clk, 100); > >> >> + } > >> >> + > >> >> + return crtc_clk; > >> >> +} > >> >> + > >> >> static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) > >> >> { > >> >> struct msm_drm_private *priv; > >> >> @@ -51,12 +119,7 @@ static void _dpu_core_perf_calc_crtc(struct > >> >> dpu_kms *kms, > >> >> dpu_cstate = to_dpu_crtc_state(state); > >> >> memset(perf, 0, sizeof(struct dpu_core_perf_params)); > >> >> > >> >> - if (!dpu_cstate->bw_control) { > >> >> - perf->bw_ctl = kms->catalog->perf.max_bw_high * > >> >> - 1000ULL; > >> >> - perf->max_per_pipe_ib = perf->bw_ctl; > >> >> - perf->core_clk_rate = kms->perf.max_core_clk_rate; > >> >> - } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) > >> >> { > >> >> + if (kms->perf.perf_tune.m
[PATCH] dma-buf/sw_sync: Avoid recursive lock during fence signal.
Calltree: timeline_fence_release drm_sched_entity_wakeup dma_fence_signal_locked sync_timeline_signal sw_sync_ioctl Releasing the reference to the fence in the fence signal callback seems reasonable to me, so this patch avoids the locking issue in sw_sync. d3862e44daa7 ("dma-buf/sw-sync: Fix locking around sync_timeline lists") fixed the recursive locking issue but caused an use-after-free. Later d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") fixed the use-after-free but reintroduced the recursive locking issue. In this attempt we avoid the use-after-free still because the release function still always locks, and outside of the locking region in the signal function we have properly refcounted references. We furthermore also avoid the recurive lock by making sure that either: 1) We have a properly refcounted reference, preventing the signal from triggering the release function inside the locked region. 2) The refcount was already zero, and hence nobody will be able to trigger the release function from the signal function. Fixes: d3c6dd1fb30d ("dma-buf/sw_sync: Synchronize signal vs syncpt free") Cc: Sumit Semwal Cc: Chris Wilson Cc: Gustavo Padovan Cc: Christian König Cc: Signed-off-by: Bas Nieuwenhuizen --- drivers/dma-buf/sw_sync.c | 28 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 348b3a9170fa..30a482f75d56 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -192,9 +192,12 @@ static const struct dma_fence_ops timeline_fence_ops = { static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { struct sync_pt *pt, *next; + struct list_head ref_list; trace_sync_timeline(obj); + INIT_LIST_HEAD(&ref_list); + spin_lock_irq(&obj->lock); obj->value += inc; @@ -206,18 +209,27 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) list_del_init(&pt->link); rb_erase(&pt->node, &obj->pt_tree); - /* -* A signal callback may release the last reference to this -* fence, causing it to be freed. That operation has to be -* last to avoid a use after free inside this loop, and must -* be after we remove the fence from the timeline in order to -* prevent deadlocking on timeline->lock inside -* timeline_fence_release(). -*/ + /* We need to take a reference to avoid a release during +* signalling (which can cause a recursive lock of obj->lock). +* If refcount was already zero, another thread is already taking +* care of destructing the fence, so the signal cannot release +* it again and we hence will not have the recursive lock. */ + if (dma_fence_get_rcu(&pt->base)) + list_add_tail(&pt->link, &ref_list); + dma_fence_signal_locked(&pt->base); } spin_unlock_irq(&obj->lock); + + list_for_each_entry_safe(pt, next, &ref_list, link) { + /* This needs to be cleared before release, otherwise the +* timeline_fence_release function gets confused about also +* removing the fence from the pt_tree. */ + list_del_init(&pt->link); + + dma_fence_put(&pt->base); + } } /** -- 2.27.0 ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v3 6/9] drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can
Hi, On Fri, Jul 10, 2020 at 10:11 AM Steev Klimaszewski wrote: > > > On 7/10/20 9:47 AM, Doug Anderson wrote: > > Hi, > > > > > > But should I continue on this path, > > It's probably worth getting dithering working on your sdm845 anyway in > > case anyone actually does put a 6bpp panel on this SoC. > > > > > >> or should we be finding others who > >> have an N61 and see what their EDID reports? > > I have an email out to BOE, but it might take a little while to get a > > response. I'll see what they say. If they say that the panel > > actually supports 8bpp then it's a no-brainer and we should just > > switch to 8bpp and be done. > > > > ...but if they say it's a 6bpp panel that has its own dither logic > > then it gets more complicated. Initially one would think there should > > be very little downside in defining the panel as an 8bpp panel and > > calling it done. ...except that it conflicts with some other work > > that I have in progress. :-P Specifically if you treat the panel as > > 6bpp and then reduce the blanking a tiny bit you can actually save 75 > > mW of total system power on my board (probably similar on your board > > since you have the same bridge chip). You can see a patch to do that > > here: > > > > https://crrev.com/c/2276384 > > > > ...so I'm hoping to get some clarity from BOE both on the true bits > > per pixel and whether my proposed timings are valid before moving > > forward. Is that OK? > > > > > > -Doug > > > It's fine by me - testing Rob's suggestion of changing > MAX_HDISPLAY_SPLIT 1080->1920 along with the change to adding IS_SDM845 > does give me a full screen that looks nicer, I'm fine with using the > hack locally until a proper solution is found. And I'm always a fan of > using less power on a laptop. > > > I'll give the patch a spin here if you want as well. > > > Hopefully BOE gets back to you soon, and there's no rush, I'm just an > end user who is extremely appreciative of all the work everyone on the > list and the kernel in general put in to make my machines usable. Just FYI that I got confirmation that the panel is truly 6 bpp but it will do FRC dithering if given an 8 bpp input. That means that you should be getting just as good picture quality (and possibly more tunable) by using the dithering in the display pipeline and leaving the panel as 6bpp. Thus I'm going to assume that's the route we'll go down. If ever we find someone that wants to use this panel on a display controller that can't do its own dithering then I guess we'll have to figure out what to do then... In terms of the more optimal pixel clock for saving power, my proposal is still being analyzed and I'll report back when I hear more. I'm seeing if BOE can confirm that my proposal will work both for my panel (the -n62 variant) and the one you have (the -n61 variant). -Doug ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v3 4/6] drm: Add Generic USB Display driver
Den 02.06.2020 13.46, skrev Noralf Trønnes: > > > Den 02.06.2020 04.32, skrev Alan Stern: >> On Tue, Jun 02, 2020 at 12:12:07AM +, Peter Stuge wrote: >> >> ... >> >>> The way I read composite_setup() after try_fun_setup: it calls f->setup() >>> when available, and that can return < 0 to stall. >>> >>> I expect that composite_setup() and thus f->setup() run when the >>> SETUP packet has arrived, thus before the data packet arrives, and if >>> composite_setup() stalls then the device/function should never see the >>> data packet. >>> >>> For an OUT transaction I think the host controller might still send >>> the DATA packet, but the device controllers that I know don't make it >>> visible to the application in that case. >> >> ... >> >> Are you guys interested in comments from other people who know more >> about the kernel and how it works with USB? > > Absolutely, I want something thats works well in the kernel and doesn't > look odd to kernel USB people. > >> Your messages have been >> far too long to go into in any detail, but I will address this one issue. >> >> The USB protocol forbids a device from sending a STALL response to a >> SETUP packet. The only valid response is ACK. Thus, there is no way >> to prevent the host from sending its DATA packet for a control-OUT >> transfer. >> >> A gadget driver can STALL in response to a control-OUT data packet, >> but only before it has seen the packet. Once the driver knows what >> the data packet contains, the gadget API doesn't provide any way to >> STALL the status stage. There has been a proposal to change the API >> to make this possible, but so far it hasn't gone forward. >> > > This confirms what I have seen in the kernel and the reason I added a > status request so I can know the result of the operation the device has > performed. > > I have a problem that I've encountered with this status request. > In my first version the gadget would usb_ep_queue() the status value > when the operation was done and as long as this happended within the > host timeout (5s) everything worked fine. > > Then I hit a 10s timeout in the gadget when performing a display modeset > operation (wait on missing vblank). The result of this was that the host > timed out and moved on. The gadget however didn't know that the host > gave up, so it queued up the status value. The result of this was that > all further requests from the host would time out. > Do you know a solution to this? > My work around is to just poll on the status request, which returns a > value immediately, until there's a result. The udc driver I use is dwc2. > I have now tried this on a Beaglebone Black (musb udc driver) and it works just fine there (it displays an error message on the next request). So it has to be a dwc2 driver problem. I will try and chase down this problem when I get the time. This means I don't need this status request polling in my host driver. Noralf. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 04/25] drm/vkms: Annotate vblank timer
On Tue, Jul 14, 2020 at 4:56 PM Melissa Wen wrote: > > Hi, > > On 07/14, Daniel Vetter wrote: > > On Tue, Jul 14, 2020 at 11:57 AM Melissa Wen wrote: > > > > > > On 07/12, Rodrigo Siqueira wrote: > > > > Hi, > > > > > > > > Everything looks fine to me, I just noticed that the amdgpu patches did > > > > not apply smoothly, however it was trivial to fix the issues. > > > > > > > > Reviewed-by: Rodrigo Siqueira > > > > > > > > Melissa, > > > > Since you are using vkms regularly, could you test this patch and review > > > > it? Remember to add your Tested-by when you finish. > > > > > > > Hi, > > > > > > I've applied the patch series, ran some tests on vkms, and found no > > > issues. I mean, things have remained stable. > > > > > > Tested-by: Melissa Wen > > > > Did you test with CONFIG_PROVE_LOCKING enabled in the kernel .config? > > Without that enabled, there's not really any change here, but with > > that enabled there might be some lockdep splats in dmesg indicating a > > problem. > > > > Even with the lock debugging config enabled, no new issue arose in dmesg > during my tests using vkms. Excellent, thanks a lot for confirming this. -Daniel > > Melissa > > > Thanks, Daniel > > > > > > > Thanks > > > > > > > > On 07/07, Daniel Vetter wrote: > > > > > This is needed to signal the fences from page flips, annotate it > > > > > accordingly. We need to annotate entire timer callback since if we get > > > > > stuck anywhere in there, then the timer stops, and hence fences stop. > > > > > Just annotating the top part that does the vblank handling isn't > > > > > enough. > > > > > > > > > > Cc: linux-me...@vger.kernel.org > > > > > Cc: linaro-mm-...@lists.linaro.org > > > > > Cc: linux-r...@vger.kernel.org > > > > > Cc: amd-...@lists.freedesktop.org > > > > > Cc: intel-...@lists.freedesktop.org > > > > > Cc: Chris Wilson > > > > > Cc: Maarten Lankhorst > > > > > Cc: Christian König > > > > > Signed-off-by: Daniel Vetter > > > > > Cc: Rodrigo Siqueira > > > > > Cc: Haneen Mohammed > > > > > Cc: Daniel Vetter > > > > > --- > > > > > drivers/gpu/drm/vkms/vkms_crtc.c | 8 +++- > > > > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > > > > > > > diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c > > > > > b/drivers/gpu/drm/vkms/vkms_crtc.c > > > > > index ac85e17428f8..a53a40848a72 100644 > > > > > --- a/drivers/gpu/drm/vkms/vkms_crtc.c > > > > > +++ b/drivers/gpu/drm/vkms/vkms_crtc.c > > > > > @@ -1,5 +1,7 @@ > > > > > // SPDX-License-Identifier: GPL-2.0+ > > > > > > > > > > +#include > > > > > + > > > > > #include > > > > > #include > > > > > #include > > > > > @@ -14,7 +16,9 @@ static enum hrtimer_restart > > > > > vkms_vblank_simulate(struct hrtimer *timer) > > > > > struct drm_crtc *crtc = &output->crtc; > > > > > struct vkms_crtc_state *state; > > > > > u64 ret_overrun; > > > > > - bool ret; > > > > > + bool ret, fence_cookie; > > > > > + > > > > > + fence_cookie = dma_fence_begin_signalling(); > > > > > > > > > > ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, > > > > > output->period_ns); > > > > > @@ -49,6 +53,8 @@ static enum hrtimer_restart > > > > > vkms_vblank_simulate(struct hrtimer *timer) > > > > > DRM_DEBUG_DRIVER("Composer worker already > > > > > queued\n"); > > > > > } > > > > > > > > > > + dma_fence_end_signalling(fence_cookie); > > > > > + > > > > > return HRTIMER_RESTART; > > > > > } > > > > > > > > > > -- > > > > > 2.27.0 > > > > > > > > > > > > > -- > > > > Rodrigo Siqueira > > > > https://siqueira.tech > > > > > > > > > > > > -- > > Daniel Vetter > > Software Engineer, Intel Corporation > > http://blog.ffwll.ch -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v4 1/5] drm/i915: Add enable/disable flip done and flip done handler
Hi Karthik, Thank you for the patch! Yet something to improve: [auto build test ERROR on drm-intel/for-linux-next] [also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next tegra-drm/drm/tegra/for-next v5.8-rc5 next-20200713] [cannot apply to drm/drm-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Karthik-B-S/Asynchronous-flip-implementation-for-i915/20200714-095304 base: git://anongit.freedesktop.org/drm-intel for-linux-next config: i386-randconfig-a002-20200714 (attached as .config) compiler: gcc-9 (Debian 9.3.0-14) 9.3.0 reproduce (this is a W=1 build): # save the attached .config to linux build tree make W=1 ARCH=i386 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All errors (new ones prefixed by >>): >> drivers/gpu/drm/i915/i915_irq.c:700:5: error: no previous prototype for >> 'g4x_get_flip_counter' [-Werror=missing-prototypes] 700 | u32 g4x_get_flip_counter(struct drm_crtc *crtc) | ^~~~ cc1: all warnings being treated as errors vim +/g4x_get_flip_counter +700 drivers/gpu/drm/i915/i915_irq.c 699 > 700 u32 g4x_get_flip_counter(struct drm_crtc *crtc) 701 { 702 struct drm_i915_private *dev_priv = to_i915(crtc->dev); 703 enum pipe pipe = to_intel_crtc(crtc)->pipe; 704 705 return I915_READ(PIPE_FLIPCOUNT_G4X(pipe)); 706 } 707 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org .config.gz Description: application/gzip ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 0/9] drm: Add privacy-screen class and connector properties
On Thu, Jul 9, 2020 at 8:48 AM Hans de Goede wrote: > > Hi, > > On 7/8/20 11:25 PM, Alex Deucher wrote: > > On Wed, Jul 8, 2020 at 12:43 PM Hans de Goede wrote: > >> > >> Hi All, > >> > >> Here is the privacy-screen related code which we discussed a while ago. > >> This series consists of a number of different parts: > >> > >> 1. A new version of Rajat's privacy-screen connector properties patch, > >> this adds new userspace API in the form of new properties > >> > >> 2. Since on most devices the privacy screen is actually controlled by > >> some vendor specific ACPI/WMI interface which has a driver under > >> drivers/platform/x86, we need some "glue" code to make this functionality > >> available to KMS drivers. Patches 3-5 add a new privacy-screen class for > >> this, which allows non KMS drivers (and possibly KMS drivers too) to > >> register a privacy-screen device and also adds an interface for KMS drivers > >> to get access to the privacy-screen associated with a specific connector. > >> This is modelled similar to how we deal with e.g. PWMs and GPIOs in the > >> kernel, including separate includes for consumers and providers(drivers). > >> > >> 3. Some drm_connector helper functions to keep the actual changes needed > >> for this in individual KMS drivers as small as possible (patch 6). > >> > >> 4. Make the thinkpad_acpi code register a privacy-screen device on > >> ThinkPads with a privacy-screen (patches 7-8) > >> > >> 5. Make the i915 driver export the privacy-screen functionality through > >> the connector properties on the eDP connector. > > > > Care to create a patch 10 for amdgpu? Lenovo sells AMD thinkpads with > > a privacy screen as well, presumably it works > > the same way. > > Yes the AMD based Thinkpads should work the same way. > > We will need similar changes for amdgpu and very likely also for > nouveau. The problem is I don't really have hw to test this. > > Do you have access to a recent thinkpad with amdgpu ? It does not need > to have a privacy screen, as long as it is new enough that the ACPI > tables have the GSSS and methods you can test by ignoring > the presence bit for the privacy-screen, I use this little change for > that: Thanks for the hints Hans. If I can find some time, I will give it a try. Alex > > From 9438bababe77dfccbade5c2377bdc7d6a777a6c6 Mon Sep 17 00:00:00 2001 > From: Hans de Goede > Date: Wed, 27 May 2020 14:38:42 +0200 > Subject: [PATCH] platform/x86: thinkpad_acpi: Hack to allow testing > on devices without a privacy-screen > > Hack to allow testing on devices without a privacy-screen. > > Signed-off-by: Hans de Goede > --- > drivers/gpu/drm/drm_privacy_screen_x86.c | 4 > drivers/platform/x86/thinkpad_acpi.c | 4 ++-- > 2 files changed, 6 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/drm_privacy_screen_x86.c > b/drivers/gpu/drm/drm_privacy_screen_x86.c > index f486d9087819..87725766a90d 100644 > --- a/drivers/gpu/drm/drm_privacy_screen_x86.c > +++ b/drivers/gpu/drm/drm_privacy_screen_x86.c > @@ -41,7 +41,11 @@ static bool __init detect_thinkpad_privacy_screen(void) > if (ACPI_FAILURE(status)) > return false; > > +#if 1 > + return true; > +#else > return (output & 0x1) ? true : false; > +#endif > } > > static const struct arch_init_data arch_init_data[] __initconst = { > diff --git a/drivers/platform/x86/thinkpad_acpi.c > b/drivers/platform/x86/thinkpad_acpi.c > index 1583c18f7f77..92aad746d1f8 100644 > --- a/drivers/platform/x86/thinkpad_acpi.c > +++ b/drivers/platform/x86/thinkpad_acpi.c > @@ -9747,8 +9747,8 @@ static int tpacpi_lcdshadow_init(struct ibm_init_struct > *iibm) > if (!acpi_evalf(lcdshadow_get_handle, &output, NULL, "dd", 0)) > return -EIO; > > - if (!(output & 0x1)) > - return 0; > +// if (!(output & 0x1)) > +// return 0; > > lcdshadow_dev = drm_privacy_screen_register(&tpacpi_pdev->dev, > &lcdshadow_ops); > -- > 2.26.2 > > > So if you have a machine with an AMDGPU and with the mentioned ACPI methods, > then you should be able to implement this yourself. You can read/write the new > props under X11 with xrandr. And you monitor if the changes make it to the > hardware by doing: > > cat /proc/acpi/ibm/lcdshadow > > And you can simulate external changes (like through a hotkey handled by the > embedded-controller) by doing: > > echo 0 > /proc/acpi/ibm/lcdshadow > echo 1 > /proc/acpi/ibm/lcdshadow > > When you do this you should see udev change events for the properties, you > can test for those by doing: > > sudo udevadm monitor -u -p > > ### > > With all that said, I can take a shot at blindly implementing this for amdgpu > but I would greatly prefer an actually tested patch, even if it is tested in > the way described above. When the patch is ready you can just send it to me > and I'll add my s-o-b and add it as patch
Re: [PATCH] drm: msm: a6xx: fix gpu failure after system resume
On Tue, Jul 14, 2020 at 06:55:30PM +0530, Akhil P Oommen wrote: > On targets where GMU is available, GMU takes over the ownership of GX GDSC > during its initialization. So, take a refcount on the GX PD on behalf of > GMU before we initialize it. This makes sure that nobody can collapse the > GX GDSC once GMU owns the GX GDSC. This patch fixes some weird failures > during GPU wake up during system resume. The change looks fine but this explanation is confusing. When I read it I thought "oh, man, we weren't taking a reference to the GX PD during resume???" but that's not really the case. We *are* taking a reference, just not soon enough to avoid possible issues. It would be helpful if you reworded this to explain that you are moving the reference and perhaps to shine a bit more light on what the "weird" failures are. Jordan > Signed-off-by: Akhil P Oommen > --- > drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 18 ++ > 1 file changed, 10 insertions(+), 8 deletions(-) > > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > index a6f43ff..5b2df7d 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > @@ -873,10 +873,19 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) > /* Turn on the resources */ > pm_runtime_get_sync(gmu->dev); > > + /* > + * "enable" the GX power domain which won't actually do anything but it > + * will make sure that the refcounting is correct in case we need to > + * bring down the GX after a GMU failure > + */ > + if (!IS_ERR_OR_NULL(gmu->gxpd)) > + pm_runtime_get_sync(gmu->gxpd); > + > /* Use a known rate to bring up the GMU */ > clk_set_rate(gmu->core_clk, 2); > ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); > if (ret) { > + pm_runtime_put(gmu->gxpd); > pm_runtime_put(gmu->dev); > return ret; > } > @@ -919,19 +928,12 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) > /* Set the GPU to the current freq */ > a6xx_gmu_set_initial_freq(gpu, gmu); > > - /* > - * "enable" the GX power domain which won't actually do anything but it > - * will make sure that the refcounting is correct in case we need to > - * bring down the GX after a GMU failure > - */ > - if (!IS_ERR_OR_NULL(gmu->gxpd)) > - pm_runtime_get(gmu->gxpd); > - > out: > /* On failure, shut down the GMU to leave it in a good state */ > if (ret) { > disable_irq(gmu->gmu_irq); > a6xx_rpmh_stop(gmu); > + pm_runtime_put(gmu->gxpd); > pm_runtime_put(gmu->dev); > } > > -- > 2.7.4 > -- The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 04/25] drm/vkms: Annotate vblank timer
Hi, On 07/14, Daniel Vetter wrote: > On Tue, Jul 14, 2020 at 11:57 AM Melissa Wen wrote: > > > > On 07/12, Rodrigo Siqueira wrote: > > > Hi, > > > > > > Everything looks fine to me, I just noticed that the amdgpu patches did > > > not apply smoothly, however it was trivial to fix the issues. > > > > > > Reviewed-by: Rodrigo Siqueira > > > > > > Melissa, > > > Since you are using vkms regularly, could you test this patch and review > > > it? Remember to add your Tested-by when you finish. > > > > > Hi, > > > > I've applied the patch series, ran some tests on vkms, and found no > > issues. I mean, things have remained stable. > > > > Tested-by: Melissa Wen > > Did you test with CONFIG_PROVE_LOCKING enabled in the kernel .config? > Without that enabled, there's not really any change here, but with > that enabled there might be some lockdep splats in dmesg indicating a > problem. > Even with the lock debugging config enabled, no new issue arose in dmesg during my tests using vkms. Melissa > Thanks, Daniel > > > > > Thanks > > > > > > On 07/07, Daniel Vetter wrote: > > > > This is needed to signal the fences from page flips, annotate it > > > > accordingly. We need to annotate entire timer callback since if we get > > > > stuck anywhere in there, then the timer stops, and hence fences stop. > > > > Just annotating the top part that does the vblank handling isn't > > > > enough. > > > > > > > > Cc: linux-me...@vger.kernel.org > > > > Cc: linaro-mm-...@lists.linaro.org > > > > Cc: linux-r...@vger.kernel.org > > > > Cc: amd-...@lists.freedesktop.org > > > > Cc: intel-...@lists.freedesktop.org > > > > Cc: Chris Wilson > > > > Cc: Maarten Lankhorst > > > > Cc: Christian König > > > > Signed-off-by: Daniel Vetter > > > > Cc: Rodrigo Siqueira > > > > Cc: Haneen Mohammed > > > > Cc: Daniel Vetter > > > > --- > > > > drivers/gpu/drm/vkms/vkms_crtc.c | 8 +++- > > > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > > > > > diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c > > > > b/drivers/gpu/drm/vkms/vkms_crtc.c > > > > index ac85e17428f8..a53a40848a72 100644 > > > > --- a/drivers/gpu/drm/vkms/vkms_crtc.c > > > > +++ b/drivers/gpu/drm/vkms/vkms_crtc.c > > > > @@ -1,5 +1,7 @@ > > > > // SPDX-License-Identifier: GPL-2.0+ > > > > > > > > +#include > > > > + > > > > #include > > > > #include > > > > #include > > > > @@ -14,7 +16,9 @@ static enum hrtimer_restart > > > > vkms_vblank_simulate(struct hrtimer *timer) > > > > struct drm_crtc *crtc = &output->crtc; > > > > struct vkms_crtc_state *state; > > > > u64 ret_overrun; > > > > - bool ret; > > > > + bool ret, fence_cookie; > > > > + > > > > + fence_cookie = dma_fence_begin_signalling(); > > > > > > > > ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, > > > > output->period_ns); > > > > @@ -49,6 +53,8 @@ static enum hrtimer_restart > > > > vkms_vblank_simulate(struct hrtimer *timer) > > > > DRM_DEBUG_DRIVER("Composer worker already > > > > queued\n"); > > > > } > > > > > > > > + dma_fence_end_signalling(fence_cookie); > > > > + > > > > return HRTIMER_RESTART; > > > > } > > > > > > > > -- > > > > 2.27.0 > > > > > > > > > > -- > > > Rodrigo Siqueira > > > https://siqueira.tech > > > > > > > -- > Daniel Vetter > Software Engineer, Intel Corporation > http://blog.ffwll.ch ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel