Difference between revisions of "RK3566 EBC Reverse-Engineering"

Jump to navigation Jump to search
(fixes)
 
Line 3: Line 3:
Unfortunately, the driver published for this eInk interface within the BSP kernel is an assembly dump produced by gcc. Fortunately, it contains quite a bit of debug information, which we can use to reverse engineer it.
Unfortunately, the driver published for this eInk interface within the BSP kernel is an assembly dump produced by gcc. Fortunately, it contains quite a bit of debug information, which we can use to reverse engineer it.


= Sources =
== Sources ==


== Downstream ==
=== Downstream ===


The ebc driver source is [https://gitlab.com/pine64-org/quartz-bsp/rockchip-linux/-/tree/quartz64/drivers/gpu/drm/rockchip/ebc-dev available from the quartz-bsp repository].
The ebc driver source is [https://gitlab.com/pine64-org/quartz-bsp/rockchip-linux/-/tree/quartz64/drivers/gpu/drm/rockchip/ebc-dev available from the quartz-bsp repository].
Line 17: Line 17:
Some reversing of the downstream Linux driver has been done here: https://github.com/Ralim/ebc-dev-reverse-engineering
Some reversing of the downstream Linux driver has been done here: https://github.com/Ralim/ebc-dev-reverse-engineering


== Reimplementation ==
=== Reimplementation ===


A human-readable C reimplementation of the LUT and pixel data path [https://gitlab.com/smaeul/ebc-dev is available from smaeul here]. This provides everything needed to convert a framebuffer and a waveform data file into a series of "frames" for the panel. The new implementation includes a test suite to verify its output matches the output from the BSP assembly code. It is based on the downstream Linux driver.
A human-readable C reimplementation of the LUT and pixel data path [https://gitlab.com/smaeul/ebc-dev is available from smaeul here]. This provides everything needed to convert a framebuffer and a waveform data file into a series of "frames" for the panel. The new implementation includes a test suite to verify its output matches the output from the BSP assembly code. It is based on the downstream Linux driver.


== In-Development Driver ==
=== In-Development Driver ===


[https://github.com/smaeul/linux/commits/rk356x-ebc-dev rk356x-ebc-dev] is the branch used for developing an upstreamable DRM driver based on mainline kernel sources. The driver currently functions well enough to get a virtual console and Xorg running, but it does not support features like multiple waveforms.
[https://github.com/smaeul/linux/commits/rk356x-ebc-dev rk356x-ebc-dev] is the branch used for developing an upstreamable DRM driver based on mainline kernel sources. The driver currently functions well enough to get a virtual console and Xorg running, but it does not support features like multiple waveforms.


= Documentation =
== Documentation ==


== Datasheets ==
=== Datasheets ===


=== EBC ===
==== EBC ====


The EBC TCON is documented in part 2 of the RK356x TRM.
The EBC TCON is documented in part 2 of the RK356x TRM.


=== TI TPS65185x ===
==== TI TPS65185x ====


This is the PMIC used to drive the e-Ink panel, for which the downstream sources also implement a driver.
This is the PMIC used to drive the e-Ink panel, for which the downstream sources also implement a driver.
Line 39: Line 39:
https://www.ti.com/lit/ds/symlink/tps65185.pdf
https://www.ti.com/lit/ds/symlink/tps65185.pdf


=== Waveform ===
==== Waveform ====


The format of the waveform file is documented here:
The format of the waveform file is documented here:
Line 47: Line 47:
https://www.waveshare.net/w/upload/archive/c/c4/20190611032540!E-paper-mode-declaration.pdf
https://www.waveshare.net/w/upload/archive/c/c4/20190611032540!E-paper-mode-declaration.pdf


== Utilities ==
=== Utilities ===


The [https://github.com/fread-ink/inkwave <tt>inkwave</tt>] program is designed to parse waveform files. Currently it cannot fully handle the waveform files shipped with the PineNote. Adding support for this to the tool would be helpful.
The [https://github.com/fread-ink/inkwave <tt>inkwave</tt>] program is designed to parse waveform files. Currently it cannot fully handle the waveform files shipped with the PineNote. Adding support for this to the tool would be helpful.


== Assembly Syntax and Semantics ==
=== Assembly Syntax and Semantics ===


The Syntax is GNU Assembler (GAS) syntax. [https://modexp.wordpress.com/2018/10/30/arm64-assembly/ This modexp article] provides a good introduction to the syntax, calling convention, semantics and some often used instructions.
The Syntax is GNU Assembler (GAS) syntax. [https://modexp.wordpress.com/2018/10/30/arm64-assembly/ This modexp article] provides a good introduction to the syntax, calling convention, semantics and some often used instructions.
Line 59: Line 59:
At the very least, you should read up on the registers and calling convention used.
At the very least, you should read up on the registers and calling convention used.


= Various Findings =
== Various Findings ==


The driver isn't really something that can be mainlined as-is once reversed, as it makes a number of questionable design decisions.
The driver isn't really something that can be mainlined as-is once reversed, as it makes a number of questionable design decisions.
Line 69: Line 69:
However, reverse engineering to know how it works provides a good baseline from which we can rewrite it in a more sensible manner.
However, reverse engineering to know how it works provides a good baseline from which we can rewrite it in a more sensible manner.


= Debug Information =
== Debug Information ==


Quite a bit of debug info is left in the assembly dump, including function names, file names and line numbers. We can take this to our advantage.
Quite a bit of debug info is left in the assembly dump, including function names, file names and line numbers. We can take this to our advantage.


== <code>.file ''file-number'' ''file-path''</code> ==
=== <code>.file ''file-number'' ''file-path''</code> ===


Specifies a number to reference a file by, and its path. All following code until the next <code>.file</code> or <code>.loc</code> statement are to be understood as originating from this file. This is particularly useful to understand which code has been inlined from other files, for which the source is available.
Specifies a number to reference a file by, and its path. All following code until the next <code>.file</code> or <code>.loc</code> statement are to be understood as originating from this file. This is particularly useful to understand which code has been inlined from other files, for which the source is available.


== <code>.loc ''file-number'' ''line-number'' 0</code> ==
=== <code>.loc ''file-number'' ''line-number'' 0</code> ===


Specifies that the following code is generated from <code>''line-number''</code> stemming from file number <code>''file-number''</code>. See the <code>.file</code> directive for this file number to understand which source file it came from.
Specifies that the following code is generated from <code>''line-number''</code> stemming from file number <code>''file-number''</code>. See the <code>.file</code> directive for this file number to understand which source file it came from.


== <code>.type ''function-name'', %function</code> ==
=== <code>.type ''function-name'', %function</code> ===


This tells us that the following code belongs to function <code>''function-name''</code>. You'll usually see a <code>.cfi_startproc</code>, which signifies the start of the function code, until the matching <code>.cfi_endproc</code>.
This tells us that the following code belongs to function <code>''function-name''</code>. You'll usually see a <code>.cfi_startproc</code>, which signifies the start of the function code, until the matching <code>.cfi_endproc</code>.
Line 87: Line 87:
A quick grep for <code>%function</code> shows that we are dealing with 30 functions in this file.
A quick grep for <code>%function</code> shows that we are dealing with 30 functions in this file.


== <code>.type ''struct-name'', %object</code> ==
=== <code>.type ''struct-name'', %object</code> ===


This seems to signify a definition of a C struct named <code>''struct-name''</code>.
This seems to signify a definition of a C struct named <code>''struct-name''</code>.
Line 93: Line 93:
A quick grep for <code>%object</code> shows that we are dealing with around 27 structs in this file.
A quick grep for <code>%object</code> shows that we are dealing with around 27 structs in this file.


== <code>.Ldebug_info0:</code> ==
=== <code>.Ldebug_info0:</code> ===


'''TODO:''' This seems to contain the main bulk of the DWARF debug information, including enough info to reverse full structs and function signatures.
'''TODO:''' This seems to contain the main bulk of the DWARF debug information, including enough info to reverse full structs and function signatures.


= Finding Structs and Function Signatures =
== Finding Structs and Function Signatures ==


First, we'll need to assemble the file:
First, we'll need to assemble the file:
Line 109: Line 109:
Also make sure that if you are looking up known struct accesses, that you use struct definitions from the BSP kernel, not from mainline. The kernel has no internal ABI for drivers!
Also make sure that if you are looking up known struct accesses, that you use struct definitions from the BSP kernel, not from mainline. The kernel has no internal ABI for drivers!


== Faster and Easier - Ghidra ==
=== Faster and Easier - Ghidra ===


Import the file into Ghidra, open the code browser. After analysis, you should be able to find structs in the "Data Type Manager" marked with an S icon. You'll also find functions in the symbol tree.
Import the file into Ghidra, open the code browser. After analysis, you should be able to find structs in the "Data Type Manager" marked with an S icon. You'll also find functions in the symbol tree.


== Slow and Painful - readelf/objdump ==
=== Slow and Painful - readelf/objdump ===


Use this if you want to manually look up dwarf symbols for some reason.
Use this if you want to manually look up dwarf symbols for some reason.
Line 170: Line 170:
[etc etc...]</nowiki>
[etc etc...]</nowiki>


= Reverse-Engineered Stuff =
== Reverse-Engineered Stuff ==


== Structs ==
=== Structs ===


=== ebc_info ===
==== ebc_info ====


<!-- I don't know why mediawiki scuffs the formatting here -->
<!-- I don't know why mediawiki scuffs the formatting here -->
Line 180: Line 180:
See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L124, which is based on [https://gitlab.com/pine64-org/quartz-bsp/linux-next/-/commits/2de5fb11a888c37f366642544e5a53ec2faae32d the v1.04 BSP Linux driver].
See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L124, which is based on [https://gitlab.com/pine64-org/quartz-bsp/linux-next/-/commits/2de5fb11a888c37f366642544e5a53ec2faae32d the v1.04 BSP Linux driver].


=== ebc ===
==== ebc ====


See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L200, which is based on [https://gitlab.com/pine64-org/quartz-bsp/linux-next/-/commits/2de5fb11a888c37f366642544e5a53ec2faae32d the v1.04 BSP Linux driver].
See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L200, which is based on [https://gitlab.com/pine64-org/quartz-bsp/linux-next/-/commits/2de5fb11a888c37f366642544e5a53ec2faae32d the v1.04 BSP Linux driver].


=== rkf_waveform ===
==== rkf_waveform ====


Note: all known waveform data files are the "PVI" variant, not the "RKF" variant.
Note: all known waveform data files are the "PVI" variant, not the "RKF" variant.
Line 214: Line 214:
</source>
</source>


== Enums ==
=== Enums ===


=== rkf_waveform_type ===
==== rkf_waveform_type ====
<source lang="c">
<source lang="c">
enum rkf_waveform_type {
enum rkf_waveform_type {