Reimplement dsi85 as DRM bridge (squashed). (#1)
* Reimplement dsi85 as DRM bridge (squashed). - blunt import of preliminary bridge driver - make dsi85 a kernel extension instead of a module to circumvent problems with DRM init order - make i2c matchstring match our DTS - find and use associated drm_panel - add hardcoded DSI85 init in bridge-enable - Do not drm_connector_register yet at bridge_attach time (unlike other bridge drivers) - Add a mipi_dsi_device to configure #lanes The DSI host wants to know the number of lanes, and guesses 1 lane if not given. The old attempt using just panel-simple was easy; a panel declared as DSI panel in panel-simple gets a mipi_dsi_device which it can configure. This driver follows the example of the adv7533 driver and creates its own mipi_dsi_device, where it places a hard-coded number of lanes. - cleanup * Compute DSI85 register values from Panel At bridge_mode_set time, fill all logical DSI85 registers from panel parameters and constant assumptions, then write logical registers to physical registers. Still needs override for a few logical registers: related to DSI clock, and related to horizontal parameters which our panel_simple contains with factor 2 to force proper DSI timings. * compute DSI input clock from DT attributes and mode * add debugging mode_fixup handler to bridge * add DT attrs for more DSI85 registers sync delay, DSI clock divider. And cleanup. * remove bridge_mode_fixup debug helper * use DRM logging macros uniformly * Derive sync polarity from panel's flags but make sure that DSI always uses standard polarity; fix that in the mode_fixup callback. * fix computation of dsi_clk_divider Code assumed wrong bit position in 0x0B, but with the right bit position, the divider is trivial to compute from existing params. There goes one DT attribute. * make LVDS regs 0x19..0x1B configurable by DT * add documentation
This commit is contained in:
parent
241f587f41
commit
59616c830f
7
Kconfig
Normal file
7
Kconfig
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
config DRM_BRIDGE_DSI85
|
||||||
|
tristate "DSI85 DSI-to-LVDS bridge"
|
||||||
|
depends on OF
|
||||||
|
select DRM_KMS_HELPER
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
Support for the DSI85 DSI-to-LVDS-bridge.
|
13
Makefile
13
Makefile
|
@ -1,11 +1,2 @@
|
||||||
ifneq ($(KERNELRELEASE),)
|
obj-$(CONFIG_DRM_BRIDGE_DSI85) := dsi85.o
|
||||||
# kbuild part of makefile
|
dsi85-y := dsi85_main.o
|
||||||
include Kbuild
|
|
||||||
else
|
|
||||||
# normal makefile
|
|
||||||
KDIR ?= /lib/modules/`uname -r`/build
|
|
||||||
|
|
||||||
default:
|
|
||||||
$(MAKE) -C $(KDIR) M=$$PWD
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
269
dsi85.txt
Normal file
269
dsi85.txt
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
dsi85 DSI-to-LVDS bridge driver
|
||||||
|
###############################
|
||||||
|
|
||||||
|
This driver integrates the TI SN65DSI85 DSI-to-LVDS converter into a
|
||||||
|
DRM-based graphics setup.
|
||||||
|
|
||||||
|
Author: Konrad Anton <konrad.anton@awinia.de>
|
||||||
|
for Hella-Gutmann Solutions GmbH.
|
||||||
|
|
||||||
|
Setup
|
||||||
|
=====
|
||||||
|
|
||||||
|
In order to use dsi85 in a project, copy the dsi85 tree to
|
||||||
|
drivers/gpu/drm/bridge/dsi85 (the "dsi85" buildroot package does that)
|
||||||
|
and set CONFIG_DSI85=y.
|
||||||
|
|
||||||
|
The dsi85 driver implements a DRM Bridge which sits between a DSI
|
||||||
|
output and a Panel. The Panel knows panel timings and how to switch
|
||||||
|
the backlight. Usually, the panel-simple driver is a good choice.
|
||||||
|
|
||||||
|
|
||||||
|
Configuration by DT
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Dsi85 needs three nodes in the Device Tree: the dsi85 node, the Panel
|
||||||
|
node and the DSI node. As an I2C client, the dsi85 node wants to be
|
||||||
|
nested in the node of the I2C bus::
|
||||||
|
|
||||||
|
i2c@12460000 {
|
||||||
|
//...
|
||||||
|
|
||||||
|
dsi85@2d {
|
||||||
|
compatible = "ti,dsi85"; /* instantiate the dsi85 driver */
|
||||||
|
reg = <0x2d>; /* i2c slave id */
|
||||||
|
|
||||||
|
dsi-lanes = <4>; /* tuning parameters -- see below */
|
||||||
|
lvds-channels = <2>;
|
||||||
|
sync-delay = <33>;
|
||||||
|
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
dsi85_in: endpoint {
|
||||||
|
remote-endpoint = <&dsi0_out>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
dsi85_out: endpoint {
|
||||||
|
remote-endpoint = <&panel_in>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
The dsi85 node must have exactly two ports. Port 0 points toward the
|
||||||
|
DSI output, Port 1 toward the Panel. The DSI output needs a port wired
|
||||||
|
to dsi85_in. In the Qualcomm MSM example::
|
||||||
|
|
||||||
|
dsi0: mdss_dsi@4700000 {
|
||||||
|
status = "okay";
|
||||||
|
vdda-supply = <&pm8921_l2>;/*VDD_MIPI1 to 4*/
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
ports {
|
||||||
|
port@0 {
|
||||||
|
reg = <0> ;
|
||||||
|
dsi0_in: endpoint {
|
||||||
|
remote-endpoint = <&mdp_dsi1_out>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <1> ;
|
||||||
|
dsi0_out: endpoint {
|
||||||
|
remote-endpoint = <&dsi85_in>;
|
||||||
|
data-lanes = <0 1 2 3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
On the other side, the panel needs a port wired to dsi85_out::
|
||||||
|
|
||||||
|
dsi_lvds_panel: panel {
|
||||||
|
reg = <0>;
|
||||||
|
compatible = "nlt,192108AC18"; /* one of panel-simple's
|
||||||
|
match strings */
|
||||||
|
|
||||||
|
backlight = <&backlight>;
|
||||||
|
|
||||||
|
vddp-supply = <&pm8921_l17>;
|
||||||
|
iovcc-supply = <&pm8921_lvs7>;
|
||||||
|
|
||||||
|
enable-gpios = <&tlmm_pinmux 80 GPIO_ACTIVE_HIGH>;
|
||||||
|
reset-gpios = <&tlmm_pinmux 32 GPIO_ACTIVE_HIGH>;
|
||||||
|
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&display_pins>;
|
||||||
|
|
||||||
|
port {
|
||||||
|
panel_in: endpoint {
|
||||||
|
remote-endpoint = <&dsi85_out>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Tuning parameters
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Some of the configuration details of a DSI85 can be controlled by
|
||||||
|
setting properties inside the dsi85 DT node. See DSI85 datasheet for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
dsi-lanes = N
|
||||||
|
number of DSI lanes to use. Only tested with 4.
|
||||||
|
|
||||||
|
lvds-channels = N
|
||||||
|
number of LVDS channels to use. (Only tested with 2).
|
||||||
|
|
||||||
|
sync-delay = N
|
||||||
|
Additional delay to insert when translating a DSI HSync or VSync to
|
||||||
|
a LVDS Hsync or VSync. Becomes DSI85 registers CHA_SYNC_DELAY_LOW/HIGH,
|
||||||
|
see there. Default 0.
|
||||||
|
|
||||||
|
de-neg-polarity = 0 or 1
|
||||||
|
default 0; when 1, set DE_NEG_POLARITY=1 in 0x18.7
|
||||||
|
|
||||||
|
force-24bpp-mode = 0 or 1
|
||||||
|
Default 0. Controls CHA_24BPP_MODE and
|
||||||
|
CHB_24BPP_MODE: If 1, force 24bpp; if 0, force 18bpp.
|
||||||
|
|
||||||
|
force-24bpp-format1 = 0 or 1
|
||||||
|
Default 0. Controls CHA_24BPP_FORMAT1 and CHB_24BPP_FORMAT1, see there.
|
||||||
|
|
||||||
|
lvds-vocm = 0..3
|
||||||
|
Default 0. Bit 1 controls CHA_LVDS_VOCM and Bit 0 controls CHB_LVDS_VOCM, see there.
|
||||||
|
false means 1.2V, true means 0.9V.
|
||||||
|
|
||||||
|
lvds-vod-swing-cha = 0..3
|
||||||
|
Default 0. Controls the CHA_LVDS_VOD_SWING field.
|
||||||
|
|
||||||
|
lvds-vod-swing-chb = 0..3
|
||||||
|
Default 0. Controls the CHB_LVDS_VOD_SWING field.
|
||||||
|
|
||||||
|
lvds-even-odd-swap = 0 or 1
|
||||||
|
Default 0. Controls EVEN_ODD_SWAP.
|
||||||
|
|
||||||
|
lvds-reverse = 0..3
|
||||||
|
Default 0. Bit 0 controls CHB_REVERSE_LVDS, and Bit 1 controls CHA_REVERSE_LVDS.
|
||||||
|
|
||||||
|
lvds-term = 0..3
|
||||||
|
Default 3. Bit 0 controls CHB_LVDS_TERM (true means termination on),
|
||||||
|
and Bit 1 controls CHA_LVDS_TERM.
|
||||||
|
|
||||||
|
lvds-cm-adjust-cha = 0..3
|
||||||
|
Default 0. Adjust common mode voltage for channel A, 0 means don't adjust.
|
||||||
|
See CHA_LVDS_CM_ADJUST.
|
||||||
|
|
||||||
|
lvds-cm-adjust-chb = 0..3
|
||||||
|
Default 0. Adjust common mode voltage for channel B, 0 means don't adjust.
|
||||||
|
See CHB_LVDS_CM_ADJUST.
|
||||||
|
|
||||||
|
|
||||||
|
Other parameters
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The Panel will require a certain polarity of HSYNC and VSYNC
|
||||||
|
signals. These are configured in the drm_display_mode instance of the
|
||||||
|
panel-simple panel object, along with the display timings::
|
||||||
|
|
||||||
|
static const struct drm_display_mode nlt_192108AC18_mode = {
|
||||||
|
.clock = 74175 * 2,
|
||||||
|
.hdisplay = 960 * 2,
|
||||||
|
.hsync_start = (960 + 48) * 2,
|
||||||
|
.hsync_end = (960 + 48 + 44) * 2,
|
||||||
|
.htotal = (960 + 48 + 44 + 48) * 2,
|
||||||
|
.vdisplay = 1080,
|
||||||
|
.vsync_start = 1080 + 15,
|
||||||
|
.vsync_end = 1080 + 15 + 15,
|
||||||
|
.vtotal = 1080 + 15 + 15 + 15,
|
||||||
|
.vrefresh = 60,
|
||||||
|
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||||
|
};
|
||||||
|
|
||||||
|
The flags bit DRM_MODE_FLAG_NVSYNC causes VS_NEG_POLARITY=1 in DSI85
|
||||||
|
reg 0x18, i.e. VS is negative polarity driven 0 during corresponding
|
||||||
|
sync. Analogously, DRM_MODE_FLAG_NHSYNC causes HS_NEG_POLARITY=1 in
|
||||||
|
reg 0x18 for HSync. Default is VS_NEG_POLARITY=HS_NEG_POLARITY=0.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Notes for dual-channel LVDS
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The NL192108AC18 panel's datasheet requests a clock of 74MHz and a
|
||||||
|
width of 960 double-pixel clocks. However, dsi85 expects the panel to
|
||||||
|
contain pixel timings, i.e. 148MHz and 1920 pixels width, because then
|
||||||
|
the DSI output can be configured directly from the panel parameters.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Debug messages
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The dsi85 driver uses the DRM logging facility which can be controlled
|
||||||
|
by kernel parameter drm.debug=N, where N=0x3f enables all output.
|
||||||
|
|
||||||
|
Especially errors in the Device Tree configuration can be discovered
|
||||||
|
that way; grep for "dsi85".
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Design and Implementation
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Implementation follows the example of other bridge drivers in the
|
||||||
|
mainline kernel, especially nxp-ptn3460.
|
||||||
|
|
||||||
|
The dsi85 driver is implemented as an I2C client driver whose probe
|
||||||
|
method tries to locate panel and DSI drivers. Depending on
|
||||||
|
circumstances, this will fail if some of the other drivers (e.g. the
|
||||||
|
panel) are not yet ready. In that case, the probe callback uses the
|
||||||
|
EPROBE_DEFER mechanism to request a retry. Otherwise, the probe
|
||||||
|
callback installs the DRM bridge represented by sn65dsi85_bridge_funcs.
|
||||||
|
|
||||||
|
The first bridge callback is the attach callback, which assembles a
|
||||||
|
driver graph out of:
|
||||||
|
|
||||||
|
- a DRM Connector, implemented using drm_connector_helper, that helps
|
||||||
|
choose display modes by delegating to the Panel.
|
||||||
|
|
||||||
|
- the DRM Encoder supplied by the DRM framework
|
||||||
|
|
||||||
|
- a DSI client device to configure DSI parameters (number of lanes...)
|
||||||
|
|
||||||
|
The other callbacks deal with a proper sequence of initialization:
|
||||||
|
|
||||||
|
- mode_fixup adjusts a display mode and decides whether it can be
|
||||||
|
activated. The dsi85 implementation does not attempt to validate
|
||||||
|
whether the timings are possible -- in the intended setting, the
|
||||||
|
panel does not change that often -- but it normalizes the
|
||||||
|
sync-polarity flags so that DSI always uses the same sync polarity,
|
||||||
|
regardless of the panel's choice.
|
||||||
|
|
||||||
|
- mode_set is the place where the DSI85 register values are computed
|
||||||
|
according to the adjusted display mode and the DT settings, then
|
||||||
|
written to DSI85.
|
||||||
|
|
||||||
|
- pre_enable tells the panel to power itself up
|
||||||
|
|
||||||
|
- enable enables the DSI85 PLL and tells the panel to activate its backlight
|
||||||
|
|
||||||
|
- disable undoes enable
|
||||||
|
|
||||||
|
- post_disable undoes pre_enable
|
||||||
|
|
||||||
|
|
||||||
|
Caveats
|
||||||
|
-------
|
||||||
|
|
||||||
|
The dsi85 driver has only been tested in a Qualcomm MSM kernel, and
|
||||||
|
only with the panel NL192108AC18, dual-channel LVDS, four-lane DSI.
|
||||||
|
|
972
dsi85_main.c
972
dsi85_main.c
File diff suppressed because it is too large
Load diff
46
dsi85_registers.h
Normal file
46
dsi85_registers.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef DSI85_REGISTERS_H_INCLUDED
|
||||||
|
#define DSI85_REGISTERS_H_INCLUDED
|
||||||
|
|
||||||
|
/* Register addresses */
|
||||||
|
#define DSI85_SOFT_RESET 0x09
|
||||||
|
#define DSI85_CORE_PLL 0x0A
|
||||||
|
#define DSI85_PLL_DIV 0x0B
|
||||||
|
#define DSI85_PLL_EN 0x0D
|
||||||
|
#define DSI85_DSI_CFG 0x10
|
||||||
|
#define DSI85_DSI_EQ 0x11
|
||||||
|
#define DSI85_CHA_DSI_CLK_RNG 0x12
|
||||||
|
#define DSI85_CHB_DSI_CLK_RNG 0x13
|
||||||
|
#define DSI85_LVDS_MODE 0x18
|
||||||
|
#define DSI85_LVDS_SIGN 0x19
|
||||||
|
#define DSI85_LVDS_TERM 0x1A
|
||||||
|
#define DSI85_LVDS_ADJUST 0x1B
|
||||||
|
#define DSI85_CHA_LINE_LEN_LO 0x20
|
||||||
|
#define DSI85_CHA_LINE_LEN_HI 0x21
|
||||||
|
#define DSI85_CHB_LINE_LEN_LO 0x22
|
||||||
|
#define DSI85_CHB_LINE_LEN_HI 0x23
|
||||||
|
#define DSI85_CHA_VERT_LINES_LO 0x24
|
||||||
|
#define DSI85_CHA_VERT_LINES_HI 0x25
|
||||||
|
#define DSI85_CHB_VERT_LINES_LO 0x26
|
||||||
|
#define DSI85_CHB_VERT_LINES_HI 0x27
|
||||||
|
#define DSI85_CHA_SYNC_DELAY_LO 0x28
|
||||||
|
#define DSI85_CHA_SYNC_DELAY_HI 0x29
|
||||||
|
#define DSI85_CHB_SYNC_DELAY_LO 0x2A
|
||||||
|
#define DSI85_CHB_SYNC_DELAY_HI 0x2B
|
||||||
|
#define DSI85_CHA_HSYNC_WIDTH_LO 0x2C
|
||||||
|
#define DSI85_CHA_HSYNC_WIDTH_HI 0x2D
|
||||||
|
#define DSI85_CHB_HSYNC_WIDTH_LO 0x2E
|
||||||
|
#define DSI85_CHB_HSYNC_WIDTH_HI 0x2F
|
||||||
|
#define DSI85_CHA_VSYNC_WIDTH_LO 0x30
|
||||||
|
#define DSI85_CHA_VSYNC_WIDTH_HI 0x31
|
||||||
|
#define DSI85_CHB_VSYNC_WIDTH_LO 0x32
|
||||||
|
#define DSI85_CHB_VSYNC_WIDTH_HI 0x33
|
||||||
|
#define DSI85_CHA_HORZ_BACKPORCH 0x34
|
||||||
|
#define DSI85_CHB_HORZ_BACKPORCH 0x35
|
||||||
|
#define DSI85_CHA_VERT_BACKPORCH 0x36
|
||||||
|
#define DSI85_CHB_VERT_BACKPORCH 0x37
|
||||||
|
#define DSI85_CHA_HORZ_FRONTPORCH 0x38
|
||||||
|
#define DSI85_CHB_HORZ_FRONTPORCH 0x39
|
||||||
|
#define DSI85_CHA_VERT_FRONTPORCH 0x3A
|
||||||
|
#define DSI85_CHB_VERT_FRONTPORCH 0x3B
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue