def __init__(self, fdt: Fdt2, node: int, t: Type) -> None: self.type = type self.px = fdt.getprop(node, f'qcom,mdss-dsi-panel-{t.size}').as_int32() self.fp = fdt.getprop(node, f'qcom,mdss-dsi-{t.prefix}-front-porch').as_int32() self.bp = fdt.getprop(node, f'qcom,mdss-dsi-{t.prefix}-back-porch').as_int32() self.pw = fdt.getprop(node, f'qcom,mdss-dsi-{t.prefix}-pulse-width').as_int32() self.size = fdt.getprop_int32(node, f'qcom,mdss-pan-physical-{t.size}-dimension')
def __init__(self, fdt: Fdt2, node: int, cmd: str) -> None: self.state = CommandSequence.State(fdt.getprop(node, f'qcom,mdss-dsi-{cmd}-command-state').as_str()) self.seq = [] prop = fdt.getprop_or_none(node, f'qcom,mdss-dsi-{cmd}-command') if prop is None: print(f'Warning: qcom,mdss-dsi-{cmd}-command does not exist') return # No commands itr = iter(prop) if cmd == 'on': # WHY SONY, WHY?????? Just put it in on-command... init = fdt.getprop_or_none(node, 'somc,mdss-dsi-init-command') if init: itr = itertools.chain(init, itr) for dtype in itr: last, vc, ack, wait = next(itr), next(itr), next(itr), next(itr) dlen = next(itr) << 8 | next(itr) payload = bytes(next(itr) for _ in range(0, dlen)) t = mipi.Transaction(dtype) # Very often there are too many arguments encoded in the command stream. # These are redundant, because they would be never sent anyway. max_dlen = t.max_args + 1 if 0 < max_dlen < dlen: payload = payload[:max_dlen] self.seq.append(Command(t, last, vc, ack, wait, payload))
def __init__(self, fdt: Fdt2, panel_node: int, mode_node: int, t: Type) -> None: self.type = type if t.size == "width": self.px = fdt.getprop(mode_node, f'qcom,mdss-pan-res').as_uint32_array()[1] self.fp = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[5] self.bp = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[3] self.pw = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[4] self.size = fdt.getprop(panel_node, f'qcom,mdss-pan-size').as_uint32_array()[0] elif t.size == "height": self.px = fdt.getprop(mode_node, f'qcom,mdss-pan-res').as_uint32_array()[0] self.fp = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[2] self.bp = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[0] self.pw = fdt.getprop( mode_node, f'qcom,mdss-pan-porch-values').as_uint32_array()[1] self.size = fdt.getprop(panel_node, f'qcom,mdss-pan-size').as_uint32_array()[1] else: raise ValueError(f'Unknown dimension {t.size}')
def find(fdt: Fdt2) -> Iterator[Panel]: for mdp in fdt.find_by_compatible('qcom,mdss_mdp'): for sub in fdt.subnodes(mdp): panel = Panel.parse(fdt, sub) if panel: yield panel # Newer device trees do not necessarily have panels below MDP, # search for qcom,dsi-display node instead panel_phandles = set() for display in fdt.find_by_compatible('qcom,dsi-display'): # On even newer SoCs there is another node with qcom,dsi-display-list displays = fdt.getprop_or_none(display, 'qcom,dsi-display-list') if displays is None: panel_phandles.add( fdt.getprop(display, 'qcom,dsi-panel').as_uint32()) else: for display_phandle in displays.as_uint32_array(): display = fdt.node_offset_by_phandle(display_phandle) panel_phandles.add( fdt.getprop(display, 'qcom,dsi-panel').as_uint32()) for phandle in panel_phandles: offset = fdt.node_offset_by_phandle(phandle) panel = Panel.parse(fdt, offset) if panel: yield panel
def _find_mode_node(fdt: Fdt2, node: int) -> int: timings_node = fdt.subnode_or_none(node, "qcom,mdss-dsi-display-timings") if timings_node is None: return node mode_node = None for timing in fdt.subnodes(timings_node): if mode_node: print("WARNING: Multiple display timings are not supported yet, using first!") break mode_node = timing assert mode_node, "No display timings found" return mode_node
default=0, help=""" Ignore wait in command sequences that is smaller that the specified value. Some device trees add a useless 1ms wait after each command, making the driver unnecessarily verbose. """) parser.add_argument('--dumb-dcs', dest='dumb_dcs', action='store_true', help=""" Do not attempt to interpret DCS commands. Some panels use arbitrary DCS commands to write to registers, which conflict with commands specified in the MIPI DCS specification. This option stops interpretation of DCS commands, except for enter/exit_sleep_mode and set_display_on/off (which should be supported by any panel ideally). """) args = parser.parse_args(namespace=generator.Options()) for f in args.dtb: with f: print(f"Parsing: {f.name}") fdt = Fdt2(f.read()) found = False for panel in Panel.find(fdt): found = True generate(panel, args) if not found: print(f"{f.name} does not contain any panel specifications")
def find(fdt: Fdt2) -> Iterator[Panel]: for mdp in fdt.find_by_compatible('qcom,mdss_mdp'): for sub in fdt.subnodes(mdp): panel = Panel.parse(fdt, sub) if panel: yield panel
def parse(fdt: Fdt2, node: int) -> Panel: name = fdt.getprop_or_none(node, 'qcom,mdss-dsi-panel-name') return name and Panel(name.as_str(), fdt, node)
def __init__(self, name: str, fdt: Fdt2, node: int) -> None: self.name = name self.id = _remove_before(_remove_prefixes(fdt.get_name(node), 'qcom,mdss_dsi_', 'ss_dsi_panel_', 'mot_').lower(), ',') print(f'Parsing: {self.id} ({name})') self.short_id = _replace_all(self.id, '_panel', '_video', '_vid', '_cmd', '_hd', '_qhd', '_720p', '_1080p', '_wvga', '_fwvga', '_qvga', '_xga', '_wxga') self.h = Dimension(fdt, node, Dimension.Type.HORIZONTAL) self.v = Dimension(fdt, node, Dimension.Type.VERTICAL) self.framerate = fdt.getprop(node, 'qcom,mdss-dsi-panel-framerate').as_int32() self.bpp = fdt.getprop(node, 'qcom,mdss-dsi-bpp').as_int32() self.mode = Mode(fdt.getprop(node, 'qcom,mdss-dsi-panel-type').as_str()) self.traffic_mode = TrafficMode.parse(fdt.getprop(node, 'qcom,mdss-dsi-traffic-mode')) backlight = fdt.getprop_or_none(node, 'qcom,mdss-dsi-bl-pmic-control-type') self.backlight = BacklightControl(backlight.as_str()) if backlight else None self.max_brightness = fdt.getprop_int32(node, 'qcom,mdss-dsi-bl-max-level', None) self.lanes = 0 while fdt.getprop_or_none(node, f'qcom,mdss-dsi-lane-{self.lanes}-state') is not None: self.lanes += 1 self.flags = self.mode.flags + self.traffic_mode.flags if fdt.getprop_int32(node, 'qcom,mdss-dsi-h-sync-pulse') != 0: self.flags.append('MIPI_DSI_MODE_VIDEO_HSE') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-tx-eot-append') is None: self.flags.append('MIPI_DSI_MODE_EOT_PACKET') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clock-lane-hs') is None \ and fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clk-lane-hs') is None: self.flags.append('MIPI_DSI_CLOCK_NON_CONTINUOUS') reset_seq = fdt.getprop_or_none(node, 'qcom,mdss-dsi-reset-sequence') if reset_seq is not None: itr = iter(reset_seq.as_uint32_array()) self.reset_seq = list(zip(itr, itr)) else: self.reset_seq = None self.cmds = { 'on': CommandSequence(fdt, node, 'on'), 'off': CommandSequence(fdt, node, 'off') } # If all commands are sent in LPM, add flag globally if self.cmds['on'].state == CommandSequence.State.LP_MODE == self.cmds['off'].state: self.flags.append('MIPI_DSI_MODE_LPM') if self.bpp == 24: self.format = 'MIPI_DSI_FMT_RGB888' else: raise ValueError(f'Unsupported bpp: {self.bpp} (TODO)') # Sony </3 prop = fdt.getprop_or_none(node, 'somc,mdss-phy-size-mm') if prop: phy_size_mm = prop.as_uint32_array() self.h.size = phy_size_mm[0] self.v.size = phy_size_mm[1]
def __init__(self, name: str, fdt: Fdt2, node: int) -> None: self.name = name self.id = _remove_before( _remove_prefixes(fdt.get_name(node), 'qcom,mdss_dsi_', 'ss_dsi_panel_', 'mot_').lower(), ',') print(f'Parsing: {self.id} ({name})') self.short_id = _replace_all(self.id, '_panel', '_video', '_vid', '_cmd', '_hd', '_qhd', '_720p', '_1080p', '_wvga', '_fwvga', '_qvga', '_xga', '_wxga') # Newer SoCs can use panels in different modes (resolution, refresh rate etc). # We don't support this properly yet but many panels just have a single mode # ("timing") defined, so let's try to support this here. mode_node = _find_mode_node(fdt, node) self.h = Dimension(fdt, node, mode_node, Dimension.Type.HORIZONTAL) self.v = Dimension(fdt, node, mode_node, Dimension.Type.VERTICAL) self.framerate = fdt.getprop( mode_node, 'qcom,mdss-pan-dsi-frame-rate').as_int32() self.bpp = fdt.getprop(node, 'qcom,mdss-pan-bpp').as_int32() self.mode = Mode( 'dsi_cmd_mode') # FIXME, what do to with missing dsi_cmd_mode? self.traffic_mode = TrafficMode.parse( fdt.getprop(node, 'qcom,mdss-pan-dsi-traffic-mode')) backlight = fdt.getprop_or_none(node, 'qcom,mdss-dsi-bl-pmic-control-type') self.backlight = BacklightControl( backlight.as_str()) if backlight else None self.max_brightness = fdt.getprop_int32(node, 'qcom,mdss-dsi-bl-max-level', None) if self.backlight == BacklightControl.DCS and self.max_brightness is None: print( "WARNING: DCS backlight without maximum brightness, ignoring..." ) self.backlight = None self.lanes = 0 while fdt.getprop_or_none( node, f'qcom,mdss-dsi-lane-{self.lanes}-state') is not None: self.lanes += 1 self.lane_map = LaneMap.parse( fdt.getprop_or_none(node, 'qcom,mdss-dsi-lane-map')) self.flags = self.mode.flags + self.traffic_mode.flags if fdt.getprop_int32(node, 'qcom,mdss-dsi-h-sync-pulse') != 0: self.flags.append('MIPI_DSI_MODE_VIDEO_HSE') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-tx-eot-append') is None: self.flags.append('MIPI_DSI_MODE_EOT_PACKET') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clock-lane-hs') is None \ and fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clk-lane-hs') is None: self.flags.append('MIPI_DSI_CLOCK_NON_CONTINUOUS') reset_seq = fdt.getprop_or_none(node, 'qcom,mdss-dsi-reset-sequence') if reset_seq is not None: itr = iter(reset_seq.as_uint32_array()) self.reset_seq = list(zip(itr, itr)) else: self.reset_seq = None self.cmds = { 'on': CommandSequence(fdt, mode_node, 'on'), 'off': CommandSequence(fdt, mode_node, 'off') } # If all commands are sent in LPM, add flag globally if self.cmds['on'].state == CommandSequence.State.LP_MODE == self.cmds[ 'off'].state: self.flags.append('MIPI_DSI_MODE_LPM') if self.bpp == 24: self.format = 'MIPI_DSI_FMT_RGB888' else: raise ValueError(f'Unsupported bpp: {self.bpp} (TODO)') # Sony </3 prop = fdt.getprop_or_none(node, 'somc,mdss-phy-size-mm') if prop: phy_size_mm = prop.as_uint32_array() self.h.size = phy_size_mm[0] self.v.size = phy_size_mm[1]
def __init__(self, name: str, fdt: Fdt2, node: int) -> None: self.name = name self.node_name = fdt.get_name(node) self.id = _remove_before(_remove_prefixes(self.node_name, 'qcom,mdss_dsi_', 'ss_dsi_panel_', 'mot_').lower(), ',') print(f'Parsing: {self.id} ({name})') self.short_id = _replace_all(self.id, '_panel', '_video', '_vid', '_cmd', '_hd', '_qhd', '_720p', '_1080p', '_wvga', '_fwvga', '_qvga', '_xga', '_wxga') # Newer SoCs can use panels in different modes (resolution, refresh rate etc). # We don't support this properly yet but many panels just have a single mode # ("timing") defined, so let's try to support this here. mode_node = _find_mode_node(fdt, node) self.h = Dimension(fdt, node, mode_node, Dimension.Type.HORIZONTAL) self.v = Dimension(fdt, node, mode_node, Dimension.Type.VERTICAL) self.framerate = fdt.getprop(mode_node, 'qcom,mdss-dsi-panel-framerate').as_int32() self.bpp = fdt.getprop(node, 'qcom,mdss-dsi-bpp').as_int32() self.mode = Mode(fdt.getprop(node, 'qcom,mdss-dsi-panel-type').as_str()) self.traffic_mode = TrafficMode.parse(fdt.getprop(node, 'qcom,mdss-dsi-traffic-mode')) backlight = fdt.getprop_or_none(node, 'qcom,mdss-dsi-bl-pmic-control-type') self.backlight = BacklightControl(backlight.as_str()) if backlight else None self.max_brightness = fdt.getprop_int32(node, 'qcom,mdss-dsi-bl-max-level', None) if self.backlight == BacklightControl.DCS and self.max_brightness is None: print("WARNING: DCS backlight without maximum brightness, ignoring...") self.backlight = None self.lanes = 0 while fdt.getprop_or_none(node, f'qcom,mdss-dsi-lane-{self.lanes}-state') is not None: self.lanes += 1 self.lane_map = LaneMap.parse(fdt.getprop_or_none(node, 'qcom,mdss-dsi-lane-map')) self.flags = self.mode.flags + self.traffic_mode.flags if fdt.getprop_int32(node, 'qcom,mdss-dsi-h-sync-pulse') != 0: self.flags.append('MIPI_DSI_MODE_VIDEO_HSE') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-tx-eot-append') is None: self.flags.append('MIPI_DSI_MODE_NO_EOT_PACKET') if fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clock-lane-hs') is None \ and fdt.getprop_or_none(node, 'qcom,mdss-dsi-force-clk-lane-hs') is None \ and fdt.getprop_or_none(node, 'qcom,mdss-force-clk-lane-hs') is None: self.flags.append('MIPI_DSI_CLOCK_NON_CONTINUOUS') reset_seq = fdt.getprop_or_none(node, 'qcom,mdss-dsi-reset-sequence') if reset_seq is not None: itr = iter(reset_seq.as_uint32_array()) self.reset_seq = list(zip(itr, itr)) else: self.reset_seq = None self.cmds = { 'on': CommandSequence(fdt, mode_node, 'on'), 'off': CommandSequence(fdt, mode_node, 'off') } # If all commands are sent in LPM, add flag globally if self.cmds['on'].state == CommandSequence.State.LP_MODE == self.cmds['off'].state: self.flags.append('MIPI_DSI_MODE_LPM') if self.bpp == 24: self.format = 'MIPI_DSI_FMT_RGB888' else: raise ValueError(f'Unsupported bpp: {self.bpp} (TODO)') # Sony </3 prop = fdt.getprop_or_none(node, 'somc,mdss-phy-size-mm') if prop: phy_size_mm = prop.as_uint32_array() self.h.size = phy_size_mm[0] self.v.size = phy_size_mm[1] # Check DSI controller if LDO mode is needed self.ldo_mode = False dsi_ctrl = fdt.getprop_or_none(node, 'qcom,mdss-dsi-panel-controller') if dsi_ctrl is not None: dsi_ctrl = fdt.node_offset_by_phandle(dsi_ctrl.as_uint32()) self.ldo_mode = fdt.getprop_or_none(dsi_ctrl, 'qcom,regulator-ldo-mode') is not None # Timings are usually calculated by the driver except for downstream and LK p = fdt.getprop_or_none(node, 'qcom,mdss-dsi-panel-timings') self.timings = bytes(p) if p else bytes() self.tclk_post = fdt.getprop_int32(node, 'qcom,mdss-dsi-t-clk-post') self.tclk_pre = fdt.getprop_int32(node, 'qcom,mdss-dsi-t-clk-pre') # Additional weird values used by downstream and LK self.hsync_skew = fdt.getprop_int32(node, 'qcom,mdss-dsi-h-sync-skew') self.hfp_power_mode = fdt.getprop_or_none(node, 'qcom,mdss-dsi-hfp-power-mode') is not None self.hsa_power_mode = fdt.getprop_or_none(node, 'qcom,mdss-dsi-hsa-power-mode') is not None self.hbp_power_mode = fdt.getprop_or_none(node, 'qcom,mdss-dsi-hbp-power-mode') is not None self.bllp_power_mode = fdt.getprop_or_none(node, 'qcom,mdss-dsi-bllp-power-mode') is not None self.bllp_eof_power_mode = fdt.getprop_or_none(node, 'qcom,mdss-dsi-bllp-eof-power-mode') is not None self.lp11_init = fdt.getprop_or_none(node, 'qcom,mdss-dsi-lp11-init') is not None self.init_delay = fdt.getprop_int32(node, 'qcom,mdss-dsi-init-delay-us')