Skip to content

Commit bd30e25

Browse files
committed
Generate panel definition for device tree
qcom,mdss-dsi-lane-map tends to be hard to get right on mainline if it differs from the default (lane_map_0123). This is because the definition on mainline is inversed (physical -> logical lanes), while downstream uses logical -> physical lanes. Let's also generate a .dtsi to make that more easy.
1 parent 109dd1b commit bd30e25

File tree

6 files changed

+100
-1
lines changed

6 files changed

+100
-1
lines changed

driver.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ def generate_driver(p: Panel, options: Options) -> None:
452452
# Unknown vendor
453453
compatible = 'mdss,' + '-'.join(compatible)
454454

455+
options.compatible = compatible
456+
455457
module = f"panel-{dash_id}"
456458
with open(f'{p.id}/{module}.c', 'w') as f:
457459
f.write(f'''\

dtsi.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from generator import Options
2+
from panel import Panel, BacklightControl
3+
4+
5+
def generate_backlight(p: Panel):
6+
if p.backlight == BacklightControl.DCS:
7+
return ""
8+
return "\t\tbacklight = <&backlight>;\n"
9+
10+
11+
def generate_supplies(options: Options):
12+
s = ""
13+
if options.regulator:
14+
for r in options.regulator:
15+
s += f"\t\t{r}-supply = <&...>;\n"
16+
return s
17+
18+
19+
def generate_gpios(options: Options):
20+
s = ""
21+
for r in options.gpios:
22+
s += f"\t\t{r}-gpios = <&msmgpio XY GPIO_ACTIVE_HIGH>;\n"
23+
return s
24+
25+
26+
def generate_panel_dtsi(p: Panel, options: Options) -> None:
27+
name = p.short_id.replace('_', '-')
28+
with open(f'{p.id}/panel-{name}.dtsi', 'w') as f:
29+
f.write(f'''\
30+
&dsi0 {{
31+
panel@0 {{
32+
compatible = "{options.compatible}";
33+
reg = <0>;
34+
35+
{generate_backlight(p)}\
36+
{generate_supplies(options)}\
37+
{generate_gpios(options)}\
38+
39+
port {{
40+
panel_in: endpoint {{
41+
remote-endpoint = <&dsi0_out>;
42+
}};
43+
}};
44+
}};
45+
}};
46+
47+
&dsi0_out {{
48+
data-lanes = <{' '.join(map(str, p.lane_map.phys2log[:p.lanes]))}>;
49+
remote-endpoint = <&panel_in>;
50+
}};
51+
''')

fdt2.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ def getprop_int32(self, nodeoffset, prop_name, default=0):
3434
return prop.as_int32()
3535

3636

37+
def property_is_str(self):
38+
return self[-1] == 0 and 0 not in self[:-1]
39+
40+
3741
def property_as_uint32_array(self):
3842
num = int(len(self) / 4)
3943
return list(struct.unpack('>' + ('L' * num), self))
4044

4145

46+
Property.is_str = property_is_str
4247
Property.as_uint32_array = property_as_uint32_array

generator.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ class Options:
1313
backlight_gpio: bool
1414
ignore_wait: int
1515
dumb_dcs: bool
16+
17+
# Added by panel driver generator
18+
compatible: str
19+
gpios: List[str]

lmdpdg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import generator
77
from driver import generate_driver
8+
from dtsi import generate_panel_dtsi
89
from fdt2 import Fdt2
910
from panel import Panel
1011
from simple import generate_panel_simple
@@ -22,6 +23,7 @@ def generate(p: Panel, options: generator.Options) -> None:
2223

2324
generate_panel_simple(p)
2425
generate_driver(p, options)
26+
generate_panel_dtsi(p, options)
2527

2628

2729
parser = argparse.ArgumentParser(

panel.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def __new__(cls, value: str, flags: List[str]) -> TrafficMode:
3838

3939
@staticmethod
4040
def parse(prop: libfdt.Property) -> Optional[TrafficMode]:
41-
if prop[-1] == 0: # Null terminated string
41+
if prop.is_str():
4242
return TrafficMode(prop.as_str())
4343

4444
print(f"WARNING: qcom,mdss-dsi-traffic-mode is not a null terminated string:", prop)
@@ -55,6 +55,40 @@ def parse(prop: libfdt.Property) -> Optional[TrafficMode]:
5555
print("Falling back to MIPI_DSI_MODE_VIDEO_SYNC_PULSE")
5656
return TrafficMode.SYNC_PULSE
5757

58+
59+
@unique
60+
class LaneMap(Enum):
61+
MAP_0123 = [0, 1, 2, 3]
62+
MAP_3012 = [3, 0, 1, 2]
63+
MAP_2301 = [2, 3, 0, 1]
64+
MAP_1230 = [1, 2, 3, 0]
65+
MAP_0321 = [0, 3, 2, 1]
66+
MAP_1032 = [1, 0, 3, 2]
67+
MAP_2103 = [2, 1, 0, 3]
68+
MAP_3210 = [3, 2, 1, 0]
69+
70+
def __new__(cls, log2phys: List[int]) -> LaneMap:
71+
obj = object.__new__(cls)
72+
obj._value_ = "lane_map_" + ''.join(map(str, log2phys))
73+
# Logical lane -> physical lane (used in downstream)
74+
obj.log2phys = log2phys
75+
# Physical lane -> logical lane (used in mainline)
76+
obj.phys2log = [0, 0, 0, 0]
77+
for i, n in enumerate(log2phys):
78+
obj.phys2log[n] = i
79+
return obj
80+
81+
@staticmethod
82+
def parse(prop: Optional[libfdt.Property]) -> LaneMap:
83+
if not prop:
84+
return LaneMap.MAP_0123
85+
if prop.is_str(): # Null terminated string
86+
return LaneMap(prop.as_str())
87+
88+
print(f"WARNING: qcom,mdss-dsi-lane-map is not a null terminated string:", prop)
89+
return LaneMap.MAP_0123
90+
91+
5892
@unique
5993
class BacklightControl(Enum):
6094
PWM = 'bl_ctrl_pwm'
@@ -171,6 +205,7 @@ def __init__(self, name: str, fdt: Fdt2, node: int) -> None:
171205
self.lanes = 0
172206
while fdt.getprop_or_none(node, f'qcom,mdss-dsi-lane-{self.lanes}-state') is not None:
173207
self.lanes += 1
208+
self.lane_map = LaneMap.parse(fdt.getprop_or_none(node, 'qcom,mdss-dsi-lane-map'))
174209

175210
self.flags = self.mode.flags + self.traffic_mode.flags
176211

0 commit comments

Comments
 (0)