|
| 1 | +# SPDX-License-Identifier: GPL-2.0-only |
| 2 | +from __future__ import annotations |
| 3 | + |
| 4 | +import datetime |
| 5 | + |
| 6 | +import wrap |
| 7 | +from panel import Panel, Mode, CommandSequence, LaneMap, TrafficMode |
| 8 | + |
| 9 | + |
| 10 | +def generate_commands(p: Panel, cmd_name: str) -> str: |
| 11 | + cmd: CommandSequence = p.cmds[cmd_name] |
| 12 | + |
| 13 | + cmds = "" |
| 14 | + struct = f"static struct mipi_dsi_cmd {p.id}_{cmd_name}_command[] = {{\n" |
| 15 | + |
| 16 | + s = "" |
| 17 | + i = 0 |
| 18 | + for c in cmd.seq: |
| 19 | + b = bytearray() |
| 20 | + long = c.type.is_long |
| 21 | + if long: |
| 22 | + b += int.to_bytes(len(c.payload), 2, 'little') # Word count (WC) |
| 23 | + else: |
| 24 | + assert len(c.payload) <= 2, f"Payload too long: {len(c.payload)}" |
| 25 | + itr = iter(c.payload) |
| 26 | + b.append(next(itr, 0)) |
| 27 | + b.append(next(itr, 0)) |
| 28 | + |
| 29 | + b.append(c.type.value | c.vc << 6) |
| 30 | + b.append(int(c.ack) << 5 | int(long) << 6 | int(c.last) << 7) |
| 31 | + |
| 32 | + if long: |
| 33 | + b += bytes(c.payload) |
| 34 | + |
| 35 | + # DMA command size must be multiple of 4 |
| 36 | + mod = len(b) % 4 |
| 37 | + if mod != 0: |
| 38 | + b += bytes([0xff] * (4 - mod)) |
| 39 | + |
| 40 | + name = f'{p.id}_{cmd_name}_cmd_{i}' |
| 41 | + cmds += f'static char {name}[] = {{\n' |
| 42 | + cmds += wrap.join('\t', ',', '', [f'{byte:#04x}' for byte in b], wrap=54) |
| 43 | + cmds += '\n};\n' |
| 44 | + |
| 45 | + struct += f'\t{{ sizeof({name}), {name}, {c.wait} }},\n' |
| 46 | + i += 1 |
| 47 | + |
| 48 | + struct += '};' |
| 49 | + |
| 50 | + return cmds + '\n' + struct |
| 51 | + |
| 52 | + |
| 53 | +def generate_cmd_info(p: Panel) -> str: |
| 54 | + s = f'static struct commandpanel_info {p.id}_command_panel = {{\n' |
| 55 | + if p.mode != Mode.CMD_MODE: |
| 56 | + return s + '\t/* Unused, this is a video mode panel */\n};' |
| 57 | + |
| 58 | + s += '\t/* FIXME: This is a command mode panel */\n' |
| 59 | + return s + '};' |
| 60 | + |
| 61 | + |
| 62 | +def generate_video_info(p: Panel) -> str: |
| 63 | + s = f'static struct videopanel_info {p.id}_video_panel = {{\n' |
| 64 | + |
| 65 | + s += f'''\ |
| 66 | + .hsync_pulse = {int('MIPI_DSI_MODE_VIDEO_HSE' in p.flags)}, |
| 67 | + .hfp_power_mode = {int(p.hfp_power_mode)}, |
| 68 | + .hbp_power_mode = {int(p.hbp_power_mode)}, |
| 69 | + .hsa_power_mode = {int(p.hsa_power_mode)}, |
| 70 | + .bllp_eof_power_mode = {int(p.bllp_eof_power_mode)}, |
| 71 | + .bllp_power_mode = {int(p.bllp_power_mode)}, |
| 72 | + .traffic_mode = {list(TrafficMode.__members__.values()).index(p.traffic_mode)}, |
| 73 | + /* This is bllp_eof_power_mode and bllp_power_mode combined */ |
| 74 | + .bllp_eof_power = {int(p.bllp_eof_power_mode)} << 3 | {int(p.bllp_power_mode)} << 0, |
| 75 | +''' |
| 76 | + return s + '};' |
| 77 | + |
| 78 | + |
| 79 | +def generate_reset_seq(p: Panel) -> str: |
| 80 | + if not p.reset_seq: |
| 81 | + return '' |
| 82 | + |
| 83 | + return f''' |
| 84 | +static struct panel_reset_sequence {p.id}_reset_seq = {{ |
| 85 | + .pin_state = {{ {', '.join(str(res[0]) for res in p.reset_seq)} }}, |
| 86 | + .sleep = {{ {', '.join(str(res[1]) for res in p.reset_seq)} }}, |
| 87 | + .pin_direction = 2, |
| 88 | +}}; |
| 89 | +''' |
| 90 | + |
| 91 | + |
| 92 | +def generate_backlight(p: Panel) -> str: |
| 93 | + if not p.backlight: |
| 94 | + return '' |
| 95 | + |
| 96 | + return f''' |
| 97 | +static struct backlight {p.id}_backlight = {{ |
| 98 | + .bl_interface_type = BL_{p.backlight.name}, |
| 99 | + .bl_min_level = 1, |
| 100 | + .bl_max_level = {p.max_brightness}, |
| 101 | +}}; |
| 102 | +''' |
| 103 | + |
| 104 | + |
| 105 | +def generate_lk_driver(p: Panel) -> None: |
| 106 | + if 'sim' in p.id: |
| 107 | + return |
| 108 | + |
| 109 | + define = f'_PANEL_{p.id.upper()}_H_' |
| 110 | + |
| 111 | + with open(f'{p.id}/lk_panel_{p.id}.h', 'w') as f: |
| 112 | + f.write(f'''\ |
| 113 | +// SPDX-License-Identifier: GPL-2.0-only |
| 114 | +// Copyright (c) {datetime.date.today().year} FIXME |
| 115 | +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: |
| 116 | +// Copyright (c) 2014, The Linux Foundation. All rights reserved. (FIXME) |
| 117 | +
|
| 118 | +#ifndef {define} |
| 119 | +#define {define} |
| 120 | +
|
| 121 | +#include <mipi_dsi.h> |
| 122 | +#include <panel_display.h> |
| 123 | +#include <panel.h> |
| 124 | +#include <string.h> |
| 125 | +
|
| 126 | +static struct panel_config {p.id}_panel_data = {{ |
| 127 | + .panel_node_id = "{p.node_name}", |
| 128 | + .panel_controller = "dsi:0", |
| 129 | + .panel_compatible = "qcom,mdss-dsi-panel", |
| 130 | + .panel_type = {int(p.mode == Mode.CMD_MODE)}, |
| 131 | + .panel_destination = "DISPLAY_1", |
| 132 | + /* .panel_orientation not supported yet */ |
| 133 | + .panel_framerate = {p.framerate}, |
| 134 | + .panel_lp11_init = {int(p.lp11_init)}, |
| 135 | + .panel_init_delay = {p.init_delay}, |
| 136 | +}}; |
| 137 | +
|
| 138 | +static struct panel_resolution {p.id}_panel_res = {{ |
| 139 | + .panel_width = {p.h.px}, |
| 140 | + .panel_height = {p.v.px}, |
| 141 | + .hfront_porch = {p.h.fp}, |
| 142 | + .hback_porch = {p.h.bp}, |
| 143 | + .hpulse_width = {p.h.pw}, |
| 144 | + .hsync_skew = {p.hsync_skew}, |
| 145 | + .vfront_porch = {p.v.fp}, |
| 146 | + .vback_porch = {p.v.bp}, |
| 147 | + .vpulse_width = {p.v.pw}, |
| 148 | + /* Borders not supported yet */ |
| 149 | +}}; |
| 150 | +
|
| 151 | +static struct color_info {p.id}_color = {{ |
| 152 | + .color_format = {p.bpp}, |
| 153 | + .color_order = DSI_RGB_SWAP_RGB, |
| 154 | + .underflow_color = 0xff, |
| 155 | + /* Borders and pixel packing not supported yet */ |
| 156 | +}}; |
| 157 | +
|
| 158 | +{generate_commands(p, 'on')} |
| 159 | +
|
| 160 | +{generate_commands(p, 'off')} |
| 161 | +
|
| 162 | +static struct command_state {p.id}_state = {{ |
| 163 | + .oncommand_state = {int(p.cmds['on'].state == CommandSequence.State.HS_MODE)}, |
| 164 | + .offcommand_state = {int(p.cmds['off'].state == CommandSequence.State.HS_MODE)}, |
| 165 | +}}; |
| 166 | +
|
| 167 | +{generate_cmd_info(p)} |
| 168 | +
|
| 169 | +{generate_video_info(p)} |
| 170 | +
|
| 171 | +static struct lane_configuration {p.id}_lane_config = {{ |
| 172 | + .dsi_lanes = {p.lanes}, |
| 173 | + .dsi_lanemap = {list(LaneMap.__members__.values()).index(p.lane_map)}, |
| 174 | + .lane0_state = {int(p.lanes > 0)}, |
| 175 | + .lane1_state = {int(p.lanes > 1)}, |
| 176 | + .lane2_state = {int(p.lanes > 2)}, |
| 177 | + .lane3_state = {int(p.lanes > 3)}, |
| 178 | + .force_clk_lane_hs = {int('MIPI_DSI_CLOCK_NON_CONTINUOUS' not in p.flags)}, |
| 179 | +}}; |
| 180 | +
|
| 181 | +static const uint32_t {p.id}_timings[] = {{ |
| 182 | + {', '.join(f'{byte:#04x}' for byte in p.timings)} |
| 183 | +}}; |
| 184 | +
|
| 185 | +static struct panel_timing {p.id}_timing_info = {{ |
| 186 | + .tclk_post = {p.tclk_post:#04x}, |
| 187 | + .tclk_pre = {p.tclk_pre:#04x}, |
| 188 | +}}; |
| 189 | +{generate_reset_seq(p)}{generate_backlight(p)} |
| 190 | +{wrap.join(f'static inline void panel_{p.id}_select(', ',', ')', |
| 191 | + ['struct panel_struct *panel', 'struct msm_panel_info *pinfo', |
| 192 | + 'struct mdss_dsi_phy_ctrl *phy_db'])} |
| 193 | +{{ |
| 194 | + panel->paneldata = &{p.id}_panel_data; |
| 195 | + panel->panelres = &{p.id}_panel_res; |
| 196 | + panel->color = &{p.id}_color; |
| 197 | + panel->videopanel = &{p.id}_video_panel; |
| 198 | + panel->commandpanel = &{p.id}_command_panel; |
| 199 | + panel->state = &{p.id}_state; |
| 200 | + panel->laneconfig = &{p.id}_lane_config; |
| 201 | + panel->paneltiminginfo = &{p.id}_timing_info; |
| 202 | + panel->panelresetseq = {f'&{p.id}_reset_seq' if p.reset_seq else 'NULL'}; |
| 203 | + panel->backlightinfo = {f'&{p.id}_backlight' if p.backlight else 'NULL'}; |
| 204 | + pinfo->mipi.panel_cmds = {p.id}_on_command; |
| 205 | + pinfo->mipi.num_of_panel_cmds = ARRAY_SIZE({p.id}_on_command); |
| 206 | + memcpy(phy_db->timing, {p.id}_timings, TIMING_SIZE); |
| 207 | + phy_db->regulator_mode = {'DSI_PHY_REGULATOR_LDO_MODE' if p.ldo_mode else 'DSI_PHY_REGULATOR_DCDC_MODE'}; |
| 208 | +}} |
| 209 | +
|
| 210 | +#endif /* {define} */ |
| 211 | +''') |
0 commit comments