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 __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')