-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drm/panel: add backlight support to ea8061v-ams497ee01 driver #200
base: msm8916/6.5-rc5
Are you sure you want to change the base?
drm/panel: add backlight support to ea8061v-ams497ee01 driver #200
Conversation
Oh yeah, and if someone wants to try it, remember that the device package has to be updated after building the kernel modules, or this commit reverted. |
The kernel module does not become part of the device package, the device package just says which kernel modules should be included in the initramfs. AFAICT you did not change the module name so it should still work fine with those changes in the device package? |
Right, re-building initramfs should be enough. I spent some time when I started looking at this figuring out why my changes did not have an effect when I built linux-postmarketos-qcom-msm8916 or pushed the updated module to |
This sounds like a general issue with sleep, not with panel driver. |
fea4a06
to
54d11ea
Compare
54d11ea
to
d4c06ab
Compare
recently I've tried to debug brightness on a5lte, using patches from latest commit in this branch: https://gitlab.com/minlexx/pmaports/-/commits/a5lte-debug . "Reduce dmesg spam" one helps to get a less spammy dmesg output, and 2nd one - uncommented (+slightly fixed) cmd dumper in Uncommented But the most interesting are brightness change command dumps, take a look at https://paste.sr.ht/~minlexx/8dafcf2400372cb369a14cc767b027f770c045f4. They look a bit different from what I saw for klte panel, this driver wraps every sub-command with level2-key-enable/disable pairs (f0 5a 5a, f1 5a 5a ... f0 a5 a5, f1 a5 a5). Klte panel uses single "level2-key-enable" operation at the beginning of brightness change operation, then does all the thigs, and then "level2-key-disable". This driver is special, it wraps every command in those sequences.. Feel the difference, roughly:
a5lte:
🙈 this results in much longer sequences, and if we want to mimic downstream driver behaviour fully (I think we want) - this driver will need to be adjusted, as I currently don't see |
The explanation of "level 2 test keys" from linusw:
Looks like it's important to exit from that programming mode after entering it, to avoid some display data (or other things) to be accidentally interpreted as some "MTP" command? Maybe we can do like klte's panel does, wrap the whole brightnes set operation in enter-exit pair at least, wrapping every subcommand seems like too much |
Your dump differs a bit from the one I got, will check yours and see if the colors seem better.
Mimic'ing downstream is probably the safest, but the driver for a5lte is clearly written to be as generic as possible and to handle all possible types of panels, to make samsung's life easier. Really feels like unlocking and locking again on every command is something they have added because some panel (not necessarily ea8061v ams497ee01) needed it. If we look at other ea8061v drivers (and assuming they should work similarly, which we can't be sure of I guess), they do it more like klte does it (this is the driver my first version was based on, it also worked reasonably well).
I unlock them, and leave them unlocked, in the init function. Given the level 2 testkey explanation I definitely agree that they should be locked again, preferably in the way klte does it. You had "B8 14" and "B5 21" in your dump, B8 14 probably sets some reference temperature to 20 deg C, since B8 19 seem to set reference temperature 25 degC, and B5 21 seem to be the "opposite" of B5 29. |
Nice, then we can have functions named like |
d4c06ab
to
94bf910
Compare
@minlexx I tested with the lux dump you captured but could not tell any difference from with what I have now. I guess the downstream driver can calculate a slightly different tables on different devices (since it is generated dynamically) |
94bf910
to
5ea1284
Compare
5ea1284
to
359546d
Compare
359546d
to
24c1cc5
Compare
Do you have any plans to submit the full driver upstream? If not, please keep the driver in |
a2691b6
to
c9e5f5a
Compare
Not until the remaining flickering issue has been resolved at least.
Sure, makes sense. I moved it back to msm8916-generated folder, and edited the Kconfig option in drivers/gpu/drm/panel/msm8916-generated instead. |
I think this is likely not an issue with your driver but rather in the Qualcomm/msm DSI implementation. Similar issues when changing the brightness levels via DSI commands also exist on other devices. It's not that bad there because they only need to send a single command though and not multiple like you here. In other words, I think fixing the flickering does likely not involve any changes in the panel driver, but rather in the common msm DSI code.
Thanks! |
This patch adds support for Samsung's AMOLED AMS497EE01 panel with an EA8061V controller. The driver is mostly based on the driver for s6e3fa2 and s6e63m0, with data taken from the downstream android kernel for the device with codename a500f. The panel is used in the msm8916 Samsung Galaxy A5U (EUR) devices, for which there is already partial support in the mainline kernel. Signed-off-by: Henrik Grimler <[email protected]>
c9e5f5a
to
f6949f6
Compare
BPF CI has reported the following failure: Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1506: ingress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected vsock_unix_redir_connectible:FAIL:1506 ./test_progs:vsock_unix_redir_connectible:1514: ingress: recv() err, errno=11 vsock_unix_redir_connectible:FAIL:1514 ./test_progs:vsock_unix_redir_connectible:1518: ingress: vsock socket map failed, a != b vsock_unix_redir_connectible:FAIL:1518 ./test_progs:vsock_unix_redir_connectible:1525: ingress: want pass count 1, have 0 It’s because the recv(... MSG_DONTWAIT) syscall in the test case is called before the queued work sk_psock_backlog() in the kernel finishes executing. So the data to be read is still queued in psock->ingress_skb and cannot be read by the user program. Therefore, the non-blocking recv() reads nothing and reports an EAGAIN error. So replace recv(... MSG_DONTWAIT) with xrecv_nonblock(), which calls select() to wait for data to be readable or timeout before calls recv(). Fixes: d61bd8c ("selftests/bpf: add a test case for vsock sockmap") Signed-off-by: Xu Kuohai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin KaFai Lau <[email protected]>
I tried to minimize the diff compared to the generated driver a bit more Some notable differences:
I noticed some more minor things, but I will add separate comments for these. The main code for setting the actual brightness looks good to me, thanks for trying to understand the mess Samsung did there. :) Backup of the previous version for reference// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2023 FIXME
// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME)
//
// Mostly based on s6e3fa2 and s6e63m0. Table values dumped from
// Samsung's SM-A500F android kernel
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#define EA8061V_AMS497EE01_NUM_GAMMA_LEVELS 62
#define EA8061V_AMS497EE01_GAMMA_CMD_CNT 34
#define EA8061V_AMS497EE01_MIN_BRIGHTNESS 0
#define EA8061V_AMS497EE01_MAX_BRIGHTNESS (EA8061V_AMS497EE01_NUM_GAMMA_LEVELS - 1)
#define EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS 40
/* Commands from manufacturer */
#define MCS_ACL_OFF 0x5c
#define MCS_ACL_ON 0x4c
#define MCS_ACL_CONTROL 0x55
#define MCS_AID_CONTROL 0xb2 /* Samsung AMOLED Impulsive Driving */
#define MCS_ACL_OPR_CONTROL 0xb5
#define MCS_ELVSS_CONTROL 0xb6 /* Amoled negative power supply */
#define MCS_TSET 0xb8 /* Set reference conditions */
#define MCS_GAMMA 0xca
#define MCS_GAMMA_UPDATE 0xf7
/* Which ELVSS sequence to use for which candela level.
*/
static const u8 map_candela_to_elvss[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 2, 2, 3, 4, 4, 5, 6,
7, 7, 7, 8, 9, 10,
11, 11, 11, 12, 13, 14, 15, 16, 17
};
static const u8 seq_ea8061v_ams497ee01_lux[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS][EA8061V_AMS497EE01_GAMMA_CMD_CNT] = {
{ MCS_GAMMA,
0x00, 0x92, 0x00, 0xac, 0x00, 0x7e, 0x8a, 0x8f, 0x8b,
0x8d, 0x91, 0x8d, 0x96, 0xa1, 0x99, 0x9b, 0xa5, 0x00,
0x9c, 0x95, 0xa1, 0x8d, 0x9d, 0xa3, 0xa1, 0xba, 0xbb,
0xec, 0xbd, 0xd5, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x93, 0x00, 0xac, 0x00, 0x7e, 0x8b, 0x8e, 0x8b,
0x8d, 0x90, 0x8c, 0x93, 0x9e, 0x96, 0x94, 0xa1, 0x00,
0x96, 0x96, 0xa2, 0x8d, 0x9e, 0xa2, 0xa1, 0xb9, 0xba,
0xe1, 0xb4, 0xcd, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8d, 0x8a,
0x89, 0x8e, 0x8a, 0x92, 0x9d, 0x95, 0x95, 0xa1, 0x00,
0x97, 0x97, 0xa1, 0x8e, 0x98, 0xa0, 0x9d, 0xb3, 0xb7,
0xe0, 0xb3, 0xcb, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8b, 0x8d, 0x8b,
0x89, 0x8e, 0x8a, 0x92, 0x9c, 0x94, 0x93, 0x9e, 0x00,
0x96, 0x95, 0x9f, 0x8d, 0x98, 0xa0, 0x9c, 0xb2, 0xb4,
0xe9, 0xba, 0xd2, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8c, 0x8b,
0x89, 0x8d, 0x89, 0x91, 0x9b, 0x94, 0x93, 0x9e, 0x00,
0x95, 0x94, 0x9e, 0x8c, 0x97, 0x9e, 0x9c, 0xb3, 0xb4,
0xde, 0xb1, 0xc5, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x95, 0x00, 0xac, 0x00, 0x80, 0x89, 0x8c, 0x8a,
0x8a, 0x8d, 0x8b, 0x90, 0x99, 0x92, 0x8f, 0x9a, 0x00,
0x93, 0x93, 0x9e, 0x8c, 0x99, 0x9e, 0x9c, 0xb1, 0xb3,
0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a,
0x89, 0x8b, 0x89, 0x90, 0x98, 0x92, 0x92, 0x9c, 0x00,
0x95, 0x90, 0x9b, 0x88, 0x98, 0x9e, 0x9c, 0xb1, 0xb1,
0xdd, 0xb0, 0xc3, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a,
0x8a, 0x8b, 0x8a, 0x8e, 0x96, 0x91, 0x92, 0x9b, 0x00,
0x97, 0x92, 0x9b, 0x8a, 0x92, 0x9d, 0x96, 0xae, 0xae,
0xdc, 0xb0, 0xc2, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8b, 0x88,
0x8b, 0x8c, 0x8b, 0x8f, 0x96, 0x92, 0x8f, 0x99, 0x00,
0x93, 0x91, 0x9b, 0x88, 0x93, 0x9a, 0x98, 0xaf, 0xad,
0xe0, 0xb3, 0xc6, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x8a, 0x8b, 0x89,
0x89, 0x8b, 0x87, 0x91, 0x97, 0x94, 0x8b, 0x96, 0x00,
0x91, 0x90, 0x9b, 0x89, 0x93, 0x9b, 0x95, 0xad, 0xac,
0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
0x89, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8f, 0x98, 0x00,
0x94, 0x8d, 0x98, 0x87, 0x93, 0x9a, 0x95, 0xad, 0xac,
0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
0x8a, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8c, 0x95, 0x00,
0x92, 0x8d, 0x98, 0x87, 0x92, 0x9a, 0x93, 0xae, 0xac,
0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
0x8a, 0x8b, 0x88, 0x8e, 0x93, 0x90, 0x8e, 0x97, 0x00,
0x93, 0x8d, 0x98, 0x88, 0x92, 0x9a, 0x93, 0xa7, 0xa6,
0xea, 0xbb, 0xd1, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
0x88, 0x8a, 0x87, 0x8c, 0x93, 0x90, 0x8e, 0x96, 0x00,
0x93, 0x8a, 0x95, 0x84, 0x90, 0x98, 0x8f, 0xad, 0xab,
0xdb, 0xb0, 0xc2, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8b, 0x93, 0x00,
0x91, 0x8e, 0x96, 0x88, 0x90, 0x98, 0x8e, 0xa6, 0xa5,
0xe3, 0xb7, 0xca, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8c, 0x93, 0x00,
0x92, 0x89, 0x94, 0x83, 0x8c, 0x94, 0x8b, 0xab, 0xab,
0xd2, 0xab, 0xba, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
0x88, 0x8a, 0x87, 0x8c, 0x91, 0x8e, 0x8d, 0x93, 0x00,
0x92, 0x8c, 0x96, 0x86, 0x91, 0x98, 0x8f, 0xa6, 0xa6,
0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
0x89, 0x8a, 0x88, 0x8d, 0x92, 0x8f, 0x8d, 0x93, 0x00,
0x92, 0x89, 0x93, 0x83, 0x8f, 0x97, 0x8f, 0xa4, 0xa4,
0xd7, 0xae, 0xbf, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
0x88, 0x89, 0x87, 0x8d, 0x92, 0x8f, 0x8d, 0x92, 0x00,
0x92, 0x89, 0x93, 0x83, 0x8c, 0x94, 0x8b, 0xa2, 0xa2,
0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
0x89, 0x8a, 0x88, 0x8d, 0x91, 0x90, 0x89, 0x8f, 0x00,
0x8f, 0x8c, 0x95, 0x84, 0x8b, 0x94, 0x8a, 0xa2, 0xa0,
0xe1, 0xb6, 0xc8, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
0x89, 0x8a, 0x88, 0x8e, 0x91, 0x90, 0x89, 0x8f, 0x00,
0x90, 0x88, 0x91, 0x81, 0x8c, 0x94, 0x8a, 0xa6, 0xa6,
0xd6, 0xae, 0xbe, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
0x89, 0x8a, 0x88, 0x8d, 0x90, 0x90, 0x89, 0x8f, 0x00,
0x8f, 0x88, 0x91, 0x81, 0x8c, 0x93, 0x8a, 0xa7, 0xa6,
0xd1, 0xaa, 0xb8, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
0x89, 0x8a, 0x88, 0x8e, 0x90, 0x90, 0x86, 0x8c, 0x00,
0x8e, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0,
0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x88, 0x89, 0x87, 0x8d, 0x8f, 0x8f, 0x88, 0x8d, 0x00,
0x90, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0,
0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x89, 0x87, 0x8c, 0x8f, 0x8f, 0x8a, 0x8d, 0x00,
0x91, 0x88, 0x90, 0x81, 0x8b, 0x93, 0x8a, 0xa1, 0x9e,
0xcf, 0xa9, 0xb7, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x89, 0x87, 0x8a, 0x8e, 0x8e, 0x89, 0x8c, 0x00,
0x91, 0x87, 0x8f, 0x7f, 0x90, 0x96, 0x90, 0x99, 0x97,
0xe0, 0xb5, 0xc8, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x89, 0x8c, 0x00,
0x91, 0x87, 0x8f, 0x7f, 0x89, 0x91, 0x88, 0x9f, 0x9e,
0xda, 0xb1, 0xc2, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x87, 0x89, 0x00,
0x8f, 0x87, 0x8d, 0x7e, 0x8f, 0x95, 0x8d, 0x9a, 0x97,
0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x8a, 0x89, 0x88, 0x8a, 0x8e, 0x8e, 0x88, 0x89, 0x00,
0x90, 0x81, 0x8a, 0x79, 0x93, 0x98, 0x92, 0x9b, 0x98,
0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x88, 0x87, 0x89, 0x8d, 0x8d, 0x8a, 0x8b, 0x00,
0x91, 0x81, 0x8a, 0x79, 0x93, 0x97, 0x92, 0x9b, 0x98,
0xba, 0x9d, 0xa8, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x86, 0x88, 0x00,
0x8e, 0x87, 0x8d, 0x7d, 0x8e, 0x93, 0x8e, 0x94, 0x91,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x87, 0x88, 0x00,
0x8f, 0x82, 0x89, 0x79, 0x8d, 0x92, 0x8b, 0x97, 0x95,
0xdf, 0xb5, 0xc7, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x88, 0x00,
0x8f, 0x82, 0x88, 0x79, 0x8c, 0x92, 0x8b, 0x99, 0x96,
0xd2, 0xad, 0xbc, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00,
0x8f, 0x82, 0x88, 0x79, 0x8d, 0x92, 0x8c, 0x9b, 0x97,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x89, 0x88,
0x8a, 0x89, 0x88, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00,
0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x93, 0x8f,
0xbc, 0xa1, 0xac, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0x9b, 0x00, 0xaf, 0x00, 0x87, 0x88, 0x89, 0x88,
0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x87, 0x86, 0x00,
0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x94, 0x90,
0xa1, 0x91, 0x97, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xa0, 0x00, 0xb3, 0x00, 0x8d, 0x89, 0x89, 0x88,
0x89, 0x88, 0x86, 0x8b, 0x8c, 0x8d, 0x85, 0x85, 0x00,
0x8d, 0x84, 0x89, 0x7c, 0x8a, 0x8e, 0x89, 0x93, 0x8f,
0xca, 0xa9, 0xb7, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xa4, 0x00, 0xb6, 0x00, 0x92, 0x88, 0x89, 0x89,
0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8b, 0x87, 0x86, 0x00,
0x8c, 0x81, 0x86, 0x79, 0x89, 0x8e, 0x88, 0x9b, 0x98,
0x81, 0x7d, 0x7d, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xa8, 0x00, 0xba, 0x00, 0x97, 0x88, 0x88, 0x88,
0x88, 0x87, 0x86, 0x87, 0x8b, 0x8a, 0x8a, 0x88, 0x00,
0x8f, 0x83, 0x88, 0x7d, 0x87, 0x8c, 0x87, 0x95, 0x91,
0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xad, 0x00, 0xbe, 0x00, 0x9d, 0x87, 0x88, 0x88,
0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8c, 0x86, 0x85, 0x00,
0x89, 0x82, 0x88, 0x7d, 0x87, 0x8b, 0x87, 0x96, 0x91,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xb1, 0x00, 0xc1, 0x00, 0xa2, 0x87, 0x88, 0x88,
0x88, 0x87, 0x86, 0x87, 0x89, 0x89, 0x87, 0x86, 0x00,
0x8b, 0x80, 0x85, 0x7b, 0x8c, 0x8f, 0x8c, 0x8f, 0x8c,
0xc4, 0xa5, 0xb2, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xb7, 0x00, 0xc5, 0x00, 0xa8, 0x86, 0x87, 0x87,
0x88, 0x86, 0x85, 0x88, 0x89, 0x89, 0x87, 0x86, 0x00,
0x8a, 0x81, 0x86, 0x7d, 0x8a, 0x8d, 0x88, 0x8f, 0x8c,
0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xbc, 0x00, 0xc9, 0x00, 0xae, 0x86, 0x87, 0x87,
0x87, 0x86, 0x85, 0x87, 0x88, 0x87, 0x86, 0x87, 0x00,
0x8a, 0x80, 0x84, 0x7b, 0x8a, 0x8c, 0x88, 0x90, 0x8d,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xc1, 0x00, 0xcd, 0x00, 0xb4, 0x86, 0x87, 0x87,
0x87, 0x86, 0x86, 0x86, 0x88, 0x87, 0x87, 0x86, 0x00,
0x88, 0x82, 0x84, 0x7c, 0x85, 0x89, 0x86, 0x91, 0x8e,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xc6, 0x00, 0xd1, 0x00, 0xba, 0x85, 0x86, 0x86,
0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x88, 0x87, 0x00,
0x89, 0x82, 0x86, 0x7d, 0x80, 0x86, 0x82, 0x91, 0x8e,
0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xca, 0x00, 0xd4, 0x00, 0xbf, 0x86, 0x87, 0x87,
0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x84, 0x00,
0x86, 0x82, 0x85, 0x7f, 0x80, 0x86, 0x82, 0x91, 0x8e,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xd0, 0x00, 0xd9, 0x00, 0xc6, 0x84, 0x85, 0x85,
0x85, 0x84, 0x84, 0x83, 0x85, 0x84, 0x86, 0x85, 0x00,
0x86, 0x7f, 0x82, 0x7c, 0x87, 0x8a, 0x87, 0x8e, 0x8a,
0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xd5, 0x00, 0xdd, 0x00, 0xcc, 0x85, 0x86, 0x86,
0x85, 0x84, 0x84, 0x82, 0x84, 0x83, 0x86, 0x85, 0x00,
0x85, 0x80, 0x83, 0x7e, 0x83, 0x86, 0x84, 0x8d, 0x89,
0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd3, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00,
0x85, 0x83, 0x85, 0x7f, 0x7f, 0x84, 0x81, 0x8f, 0x8b,
0x8f, 0x85, 0x88, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00,
0x85, 0x84, 0x85, 0x80, 0x7f, 0x83, 0x81, 0x8f, 0x8b,
0x74, 0x75, 0x73, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00,
0x84, 0x82, 0x83, 0x7f, 0x7f, 0x81, 0x80, 0x8e, 0x8a,
0x85, 0x81, 0x81, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00,
0x84, 0x7f, 0x80, 0x7b, 0x83, 0x85, 0x85, 0x87, 0x84,
0xa5, 0x94, 0x9c, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00,
0x83, 0x82, 0x82, 0x7e, 0x82, 0x85, 0x85, 0x89, 0x85,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x83, 0x82, 0x00,
0x84, 0x81, 0x82, 0x7d, 0x83, 0x85, 0x85, 0x86, 0x86,
0x97, 0x8c, 0x91, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
0x82, 0x82, 0x82, 0x83, 0x84, 0x84, 0x84, 0x82, 0x00,
0x84, 0x82, 0x82, 0x7e, 0x7e, 0x80, 0x80, 0x8d, 0x8b,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x83, 0x84, 0x84,
0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00,
0x85, 0x82, 0x82, 0x7e, 0x84, 0x85, 0x85, 0x8b, 0x8a,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xe0, 0x00, 0xe6, 0x00, 0xda, 0x83, 0x83, 0x83,
0x83, 0x82, 0x82, 0x83, 0x83, 0x83, 0x82, 0x81, 0x00,
0x84, 0x83, 0x83, 0x80, 0x81, 0x81, 0x81, 0x8b, 0x8a,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xe6, 0x00, 0xeb, 0x00, 0xe1, 0x82, 0x83, 0x83,
0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x00,
0x83, 0x84, 0x84, 0x82, 0x83, 0x83, 0x83, 0x86, 0x85,
0x89, 0x84, 0x86, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xec, 0x00, 0xf0, 0x00, 0xe8, 0x82, 0x83, 0x83,
0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x82, 0x00,
0x83, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85,
0x89, 0x84, 0x86, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xf1, 0x00, 0xf4, 0x00, 0xee, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x00,
0x82, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x00, 0xf6, 0x00, 0xf8, 0x00, 0xf4, 0x82, 0x82, 0x82,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0x81, 0x82, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x86, 0x85,
0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
{ MCS_GAMMA,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x00, 0x00, 0x00 }
};
/* ELVSS (Amoled negative power supply) tables */
#define EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES 18
#define ELVSS_SEQUENCE_LEN 3
static const u8 seq_ea8061v_ams497ee01_elvss[EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES][ELVSS_SEQUENCE_LEN] = {
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9b },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9a },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x99 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x98 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x97 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x96 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x95 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x94 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x93 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x92 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x91 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x90 },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8f },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8e },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8d },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8c },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8b },
{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8a }
};
#define EA8061V_AMS497EE01_NUM_AID_LEVELS 42
#define EA8061V_AMS497EE01_AID_CMD_CNT 5
/* Which AID sequence to use for each candela level.
*/
static const u8 map_candela_to_aid[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 41, 41,
41, 41
};
static const u8 seq_ea8061v_ams497ee01_aid[EA8061V_AMS497EE01_NUM_AID_LEVELS][EA8061V_AMS497EE01_AID_CMD_CNT] = {
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xdf }, /* 95.63 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xd3 }, /* 94.71 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xc7 }, /* 93.79 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xbb }, /* 92.87 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xb0 }, /* 92.02 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xa4 }, /* 91.10 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x99 }, /* 90.26 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x8d }, /* 89.34 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x82 }, /* 88.50 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x76 }, /* 87.58 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x6a }, /* 86.66 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x5f }, /* 85.81 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x52 }, /* 84.82 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x3b }, /* 83.05 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x31 }, /* 82.29 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x25 }, /* 81.37 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x18 }, /* 80.37 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x01 }, /* 78.60 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xf5 }, /* 77.68 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xdb }, /* 75.69 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xc5 }, /* 74.00 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xb7 }, /* 72.93 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x9e }, /* 71.01 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x88 }, /* 69.33 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x64 }, /* 66.56 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x4b }, /* 64.64 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x32 }, /* 62.73 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x0d }, /* 59.89 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xe7 }, /* 56.98 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xc2 }, /* 54.14 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x9d }, /* 51.30 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x79 }, /* 48.54 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x45 }, /* 44.56 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x13 }, /* 40.72 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xe7 }, /* 37.35 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xae }, /* 32.98 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x76 }, /* 28.68 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x39 }, /* 24.00 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xf8 }, /* 19.02 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xb4 }, /* 13.80 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x63 }, /* 7.59 % */
{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x0a } /* 0.77 % */
};
struct ea8061v_ams497ee01 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct backlight_device *bl_dev;
struct regulator_bulk_data supplies[2];
struct gpio_desc *reset_gpio;
bool prepared;
bool enabled;
};
static inline
struct ea8061v_ams497ee01 *to_ea8061v_ams497ee01(struct drm_panel *panel)
{
return container_of(panel, struct ea8061v_ams497ee01, panel);
}
static int ea8061v_ams497ee01_unlock(struct ea8061v_ams497ee01 *ctx, u8 lock)
{
switch (lock) {
case 0xf0:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0x5a, 0x5a);
break;
case 0xf1:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0x5a, 0x5a);
break;
case 0xfc:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0x5a, 0x5a);
break;
default:
return -EINVAL;
}
return 0;
}
static int ea8061v_ams497ee01_lock(struct ea8061v_ams497ee01 *ctx, u8 lock)
{
switch (lock) {
case 0xf0:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0xa5, 0xa5);
break;
case 0xf1:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0xa5, 0xa5);
break;
case 0xfc:
mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0xa5, 0xa5);
break;
default:
return -EINVAL;
}
return 0;
}
static int ea8061v_ams497ee01_apply_gamma(struct ea8061v_ams497ee01 *ctx)
{
mipi_dsi_dcs_write_seq(ctx->dsi, MCS_GAMMA_UPDATE, 0x01);
return 0;
}
static int ea8061v_ams497ee01_update_aid(struct ea8061v_ams497ee01 *ctx,
unsigned int brightness)
{
int ret;
int index = map_candela_to_aid[brightness];
ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
seq_ea8061v_ams497ee01_aid[index],
EA8061V_AMS497EE01_AID_CMD_CNT);
if (ret < 0)
return ret;
return 0;
}
static int ea8061v_ams497ee01_update_elvss(struct ea8061v_ams497ee01 *ctx,
unsigned int brightness)
{
int ret;
int index = map_candela_to_elvss[brightness];
ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
seq_ea8061v_ams497ee01_elvss[index],
ELVSS_SEQUENCE_LEN);
if (ret < 0)
return ret;
return 0;
}
static int ea8061v_ams497ee01_update_gamma(struct ea8061v_ams497ee01 *ctx,
unsigned int brightness)
{
int ret;
struct backlight_device *bl_dev = ctx->bl_dev;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
seq_ea8061v_ams497ee01_lux[brightness],
EA8061V_AMS497EE01_GAMMA_CMD_CNT);
if (ret < 0)
return ret;
bl_dev->props.brightness = brightness;
return 0;
}
static int ea8061v_ams497ee01_set_brightness(struct backlight_device *bl_dev)
{
struct ea8061v_ams497ee01 *ctx = bl_get_data(bl_dev);
unsigned int brightness = bl_dev->props.brightness;
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
ret = ea8061v_ams497ee01_unlock(ctx, 0xf0);
if (ret < 0) {
dev_err(dev, "Failed to unlock 0xf0: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_unlock(ctx, 0xf1);
if (ret < 0) {
dev_err(dev, "Failed to unlock 0xf1: %d\n", ret);
return ret;
}
/* aid/aor */
ret = ea8061v_ams497ee01_update_aid(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to send aid sequence: %d\n", ret);
return ret;
}
mipi_dsi_dcs_write_seq(dsi, MCS_ACL_OPR_CONTROL, 0x29);
mipi_dsi_dcs_write_seq(dsi, MCS_ACL_CONTROL, 0x00);
ret = ea8061v_ams497ee01_update_elvss(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to update elvss: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_update_gamma(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to update gamma: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_apply_gamma(ctx);
if (ret < 0) {
dev_err(dev, "Failed to apply gamma update: %d\n", ret);
return ret;
}
ea8061v_ams497ee01_lock(ctx, 0xf1);
if (ret < 0) {
dev_err(dev, "Failed to lock 0xf1: %d\n", ret);
return ret;
}
ea8061v_ams497ee01_lock(ctx, 0xf0);
if (ret < 0) {
dev_err(dev, "Failed to lock 0xf0: %d\n", ret);
return ret;
}
return 0;
}
static const struct backlight_ops ea8061v_ams497ee01_bl_ops = {
.update_status = ea8061v_ams497ee01_set_brightness,
};
static int ea8061v_ams497ee01_init(struct ea8061v_ams497ee01 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
unsigned int brightness = ctx->bl_dev->props.brightness;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = ea8061v_ams497ee01_unlock(ctx, 0xf0);
if (ret < 0) {
dev_err(dev, "Failed to unlock 0xf0: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_unlock(ctx, 0xf1);
if (ret < 0) {
dev_err(dev, "Failed to unlock 0xf1: %d\n", ret);
return ret;
}
/* Common conditions */
/* set ref temperature/voltage (0x19 = 25 degC, 0x10 = 7.6 V) */
mipi_dsi_dcs_write_seq(dsi, MCS_TSET, 0x19, 0x10);
/* ? */
mipi_dsi_dcs_write_seq(dsi, 0xba, 0x57);
ret = ea8061v_ams497ee01_unlock(ctx, 0xfc);
if (ret < 0) {
dev_err(dev, "Failed to unlock 0xfc: %d\n", ret);
return ret;
}
/* skip 11 parameters in HBM sequence? */
mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x0b);
/* ? */
mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x00, 0x85);
/* ? */
mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x70);
ret = ea8061v_ams497ee01_lock(ctx, 0xfc);
if (ret < 0) {
dev_err(dev, "Failed to lock 0xfc: %d\n", ret);
return ret;
}
/* Brightness control */
ret = ea8061v_ams497ee01_update_gamma(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to update gamma: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_update_aid(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to send aid sequence: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_update_elvss(ctx, brightness);
if (ret < 0) {
dev_err(dev, "Failed to update elvss: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_apply_gamma(ctx);
if (ret < 0) {
dev_err(dev, "Failed to apply gamma update: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(120);
ret = ea8061v_ams497ee01_lock(ctx, 0xf1);
if (ret < 0) {
dev_err(dev, "Failed to lock 0xf1: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
return 0;
}
static int ea8061v_ams497ee01_power_on(struct ea8061v_ams497ee01 *ctx)
{
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0) {
dev_err(&ctx->dsi->dev,
"Failed to enable regulators: %d\n", ret);
return ret;
}
/* send reset pulse */
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(20);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(20);
return 0;
}
static int ea8061v_ams497ee01_power_off(struct ea8061v_ams497ee01 *ctx)
{
int ret;
gpiod_set_value(ctx->reset_gpio, 1);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0)
return ret;
return 0;
}
static int ea8061v_ams497ee01_enable(struct drm_panel *panel)
{
struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
if (ctx->prepared)
return 0;
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(&dsi->dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
};
msleep(120);
backlight_enable(ctx->bl_dev);
ctx->enabled = true;
return 0;
}
static int ea8061v_ams497ee01_disable(struct drm_panel *panel)
{
struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
if (!ctx->enabled)
return 0;
backlight_disable(ctx->bl_dev);
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(&dsi->dev, "Failed to set display off: %d\n", ret);
return ret;
}
msleep(35);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(&dsi->dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(100);
ctx->enabled = false;
return 0;
}
static int ea8061v_ams497ee01_prepare(struct drm_panel *panel)
{
struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (ctx->prepared)
return 0;
ret = ea8061v_ams497ee01_power_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to power on panel: %d\n", ret);
return ret;
}
ret = ea8061v_ams497ee01_init(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
ea8061v_ams497ee01_power_off(ctx);
return ret;
}
ctx->prepared = true;
return 0;
}
static int ea8061v_ams497ee01_unprepare(struct drm_panel *panel)
{
struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (!ctx->prepared)
return 0;
ret = ea8061v_ams497ee01_power_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
ctx->prepared = false;
return 0;
}
static const struct drm_display_mode ea8061v_ams497ee01_mode = {
.clock = (720 + 80 + 96 + 128) * (1280 + 14 + 2 + 8) * 60 / 1000,
.hdisplay = 720,
.hsync_start = 720 + 80,
.hsync_end = 720 + 80 + 96,
.htotal = 720 + 80 + 96 + 128,
.vdisplay = 1280,
.vsync_start = 1280 + 14,
.vsync_end = 1280 + 14 + 2,
.vtotal = 1280 + 14 + 2 + 8,
.width_mm = 62,
.height_mm = 110,
};
static int ea8061v_ams497ee01_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, &ea8061v_ams497ee01_mode);
if (!mode)
return -ENOMEM;
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs ea8061v_ams497ee01_panel_funcs = {
.prepare = ea8061v_ams497ee01_prepare,
.enable = ea8061v_ams497ee01_enable,
.disable = ea8061v_ams497ee01_disable,
.unprepare = ea8061v_ams497ee01_unprepare,
.get_modes = ea8061v_ams497ee01_get_modes,
};
static int ea8061v_ams497ee01_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct ea8061v_ams497ee01 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
ctx->supplies[0].supply = "vdd3";
ctx->supplies[1].supply = "vci";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to get regulators\n");
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
ctx->bl_dev = backlight_device_register("panel", dev, ctx,
&ea8061v_ams497ee01_bl_ops,
NULL);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_NO_EOT_PACKET;
if (IS_ERR(ctx->bl_dev)) {
dev_err(dev, "Failed to register backlight device\n");
return PTR_ERR(ctx->bl_dev);
}
ctx->bl_dev->props.max_brightness = EA8061V_AMS497EE01_MAX_BRIGHTNESS;
ctx->bl_dev->props.brightness = EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS;
ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
drm_panel_init(&ctx->panel, dev, &ea8061v_ams497ee01_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.prepare_prev_first = true;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static void ea8061v_ams497ee01_remove(struct mipi_dsi_device *dsi)
{
struct ea8061v_ams497ee01 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev,
"Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
}
static const struct of_device_id ea8061v_ams497ee01_of_match[] = {
{ .compatible = "samsung,ea8061v-ams497ee01" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ea8061v_ams497ee01_of_match);
static struct mipi_dsi_driver ea8061v_ams497ee01_driver = {
.probe = ea8061v_ams497ee01_probe,
.remove = ea8061v_ams497ee01_remove,
.driver = {
.name = "panel-ea8061v-ams497ee01",
.of_match_table = ea8061v_ams497ee01_of_match,
},
};
module_mipi_dsi_driver(ea8061v_ams497ee01_driver);
MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); // FIXME
MODULE_DESCRIPTION("DRM driver for ss_dsi_panel_EA8061V_AMS497EE01_HD");
MODULE_LICENSE("GPL"); |
usleep_range(1000, 2000); | ||
gpiod_set_value_cansleep(ctx->reset_gpio, 0); | ||
msleep(20); | ||
switch (lock) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this switch? Can't you just do mipi_dsi_dcs_write_seq(ctx->dsi, lock, 0x5a, 0x5a);
?
struct mipi_dsi_device *dsi = ctx->dsi; | ||
struct device *dev = &dsi->dev; | ||
int ret; | ||
|
||
ret = ea8061v_ams497ee01_unlock(ctx, 0xf0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if these commands need to be sent in LPM or HPM? The generator typically produces something like
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
to make sure these commands are sent in HPM. (Now that I look at it the logic seems broken in case there is an error and return happens early but that's unrelated).
I'm not entirely sure but https://github.com/msm8916-mainline/linux-downstream/blob/3b09f23015d2f0949d49fb81ea1f43c63a8be503/drivers/video/msm/mdss/mdss_dsi_panel.c#L1041-L1044 seems to suggest you should also unset MIPI_DSI_MODE_LPM. Does that change anything for the brightness change "flickering"?
static int ea8061v_ams497ee01_set_brightness(struct backlight_device *bl_dev) | ||
{ | ||
struct ea8061v_ams497ee01 *ctx = bl_get_data(bl_dev); | ||
unsigned int brightness = bl_dev->props.brightness; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It wasn't entirely clear to me here if this can be replaced with backlight_get_brightness()
. Usually backlight_get_brightness()
is nicer because it returns 0 if the backlight has been "blanked" without changing the brightness to 0.
However, in general I'm actually unsure about the behavior when turning the screen on/off. I would expect that the backlight update_status()
is called when doing backlight_enable()
/backlight_disable()
, which happens during the enable()
/disable()
callbacks. This is because update_status()
is not just for brightness but also the blanking state ("on", "off"). This means that:
- When enabling: The initial brightness is set twice, once by
ea8061v_ams497ee01_init()
and once byea8061v_ams497ee01_set_brightness()
. Given the amount of commands that need to be sent this isn't entirely ideal for speeding up panel enabling/disabling. - When disabling: The brightness is set to 0 before the panel gets disabled. This is probably okay, but might be unneeded.
For enabling, I guess this means you could omit the brightness setting in ea8061v_ams497ee01_init()
, and expect it to be done by ea8061v_ams497ee01_set_brightness()
. The tricky part is that I'm not sure if enabling the panel without any gamma/aid/elvss is safe.
Alternatively, it might help to "cache" the last brightness that was actually set, and skip the update in ea8061v_ams497ee01_set_brightness()
if it didn't really change.
if (ret < 0) | ||
return ret; | ||
|
||
bl_dev->props.brightness = brightness; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused why this is here. When the backlight update_status()
is called, the brightness in the props was already updated. This would just write the same value that is already there.
@stephan-gh thanks for review/cleanup! Still works fine from some quick testing at least. Will test it for a day or two and go through modifications. Edit: some new dmesg errors during power on:
and when turning off the screen it goes to 100 % brightness for a short while. |
That would be the brightness setting I guess (that's exactly 10 commands). Is this only with the |
After looking at the s6e3fa2 driver I have something that is not super ugly and mostly work. Compared to previous WIP it now becomes quite dark at low brightness, and it remembers the brightness when turning off and on the screen.
The panel becomes out of sync quite a lot when changing brightness. I can try playing with sleep times and other things to improve the situation.
I also think (might be my imagination) that the screen becomes a bit green-ish at intermediate brightness levels. Perhaps because some things have been simplified compared to downstream, mainly:
Another issue (which was a problem before my updates here as well) is that the screen can become sluggish after the device comes out of sleep. If I have left the device with screen off for X minutes I sometimes have to do slow movements/touch the screen for several seconds for the touchscreen to react, so inputting the pin-code takes quite some time. After unlocking the screen usually becomes responsive again after a short time.
There is still room for improvement in the driver as well:
dsi_dcs_write_seq(dsi, 0xb5, 0x29);
->ea8061v_ams497ee01_acl_opr_on(ctx);
)Ping @minlexx as well since we discussed these panel drivers before, and you have the a5ulte.