1 | /* |
2 | * Copyright 2021 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | #include "reg_helper.h" |
27 | #include "core_types.h" |
28 | #include "dc_dmub_srv.h" |
29 | #include "dcn31_panel_cntl.h" |
30 | #include "atom.h" |
31 | |
32 | #define TO_DCN31_PANEL_CNTL(panel_cntl)\ |
33 | container_of(panel_cntl, struct dcn31_panel_cntl, base) |
34 | |
35 | #define CTX \ |
36 | dcn31_panel_cntl->base.ctx |
37 | |
38 | #define DC_LOGGER \ |
39 | dcn31_panel_cntl->base.ctx->logger |
40 | |
41 | static bool dcn31_query_backlight_info(struct panel_cntl *panel_cntl, union dmub_rb_cmd *cmd) |
42 | { |
43 | struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(panel_cntl); |
44 | struct dc_dmub_srv *dc_dmub_srv = panel_cntl->ctx->dmub_srv; |
45 | |
46 | if (!dc_dmub_srv) |
47 | return false; |
48 | |
49 | memset(cmd, 0, sizeof(*cmd)); |
50 | cmd->panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; |
51 | cmd->panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO; |
52 | cmd->panel_cntl.header.payload_bytes = sizeof(cmd->panel_cntl.data); |
53 | cmd->panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; |
54 | |
55 | return dc_wake_and_execute_dmub_cmd(ctx: dc_dmub_srv->ctx, cmd, wait_type: DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); |
56 | } |
57 | |
58 | static uint32_t dcn31_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl) |
59 | { |
60 | union dmub_rb_cmd cmd; |
61 | |
62 | if (!dcn31_query_backlight_info(panel_cntl, cmd: &cmd)) |
63 | return 0; |
64 | |
65 | return cmd.panel_cntl.data.current_backlight; |
66 | } |
67 | |
68 | static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl) |
69 | { |
70 | struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(panel_cntl); |
71 | struct dc_dmub_srv *dc_dmub_srv = panel_cntl->ctx->dmub_srv; |
72 | union dmub_rb_cmd cmd; |
73 | |
74 | if (!dc_dmub_srv) |
75 | return 0; |
76 | |
77 | memset(&cmd, 0, sizeof(cmd)); |
78 | cmd.panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; |
79 | cmd.panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_HW_INIT; |
80 | cmd.panel_cntl.header.payload_bytes = sizeof(cmd.panel_cntl.data); |
81 | cmd.panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; |
82 | cmd.panel_cntl.data.bl_pwm_cntl = panel_cntl->stored_backlight_registers.BL_PWM_CNTL; |
83 | cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL; |
84 | cmd.panel_cntl.data.bl_pwm_ref_div1 = |
85 | panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV; |
86 | cmd.panel_cntl.data.bl_pwm_ref_div2 = |
87 | panel_cntl->stored_backlight_registers.PANEL_PWRSEQ_REF_DIV2; |
88 | if (!dc_wake_and_execute_dmub_cmd(ctx: dc_dmub_srv->ctx, cmd: &cmd, wait_type: DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) |
89 | return 0; |
90 | |
91 | panel_cntl->stored_backlight_registers.BL_PWM_CNTL = cmd.panel_cntl.data.bl_pwm_cntl; |
92 | panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 = 0; /* unused */ |
93 | panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL = cmd.panel_cntl.data.bl_pwm_period_cntl; |
94 | panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = |
95 | cmd.panel_cntl.data.bl_pwm_ref_div1; |
96 | panel_cntl->stored_backlight_registers.PANEL_PWRSEQ_REF_DIV2 = |
97 | cmd.panel_cntl.data.bl_pwm_ref_div2; |
98 | |
99 | return cmd.panel_cntl.data.current_backlight; |
100 | } |
101 | |
102 | static void dcn31_panel_cntl_destroy(struct panel_cntl **panel_cntl) |
103 | { |
104 | struct dcn31_panel_cntl *dcn31_panel_cntl = TO_DCN31_PANEL_CNTL(*panel_cntl); |
105 | |
106 | kfree(objp: dcn31_panel_cntl); |
107 | *panel_cntl = NULL; |
108 | } |
109 | |
110 | static bool dcn31_is_panel_backlight_on(struct panel_cntl *panel_cntl) |
111 | { |
112 | union dmub_rb_cmd cmd; |
113 | |
114 | if (!dcn31_query_backlight_info(panel_cntl, cmd: &cmd)) |
115 | return false; |
116 | |
117 | return cmd.panel_cntl.data.is_backlight_on; |
118 | } |
119 | |
120 | static bool dcn31_is_panel_powered_on(struct panel_cntl *panel_cntl) |
121 | { |
122 | union dmub_rb_cmd cmd; |
123 | |
124 | if (!dcn31_query_backlight_info(panel_cntl, cmd: &cmd)) |
125 | return false; |
126 | |
127 | return cmd.panel_cntl.data.is_powered_on; |
128 | } |
129 | |
130 | static void dcn31_store_backlight_level(struct panel_cntl *panel_cntl) |
131 | { |
132 | union dmub_rb_cmd cmd; |
133 | |
134 | if (!dcn31_query_backlight_info(panel_cntl, cmd: &cmd)) |
135 | return; |
136 | |
137 | panel_cntl->stored_backlight_registers.BL_PWM_CNTL = cmd.panel_cntl.data.bl_pwm_cntl; |
138 | panel_cntl->stored_backlight_registers.BL_PWM_CNTL2 = 0; /* unused */ |
139 | panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL = cmd.panel_cntl.data.bl_pwm_period_cntl; |
140 | panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = |
141 | cmd.panel_cntl.data.bl_pwm_ref_div1; |
142 | } |
143 | |
144 | static const struct panel_cntl_funcs dcn31_link_panel_cntl_funcs = { |
145 | .destroy = dcn31_panel_cntl_destroy, |
146 | .hw_init = dcn31_panel_cntl_hw_init, |
147 | .is_panel_backlight_on = dcn31_is_panel_backlight_on, |
148 | .is_panel_powered_on = dcn31_is_panel_powered_on, |
149 | .store_backlight_level = dcn31_store_backlight_level, |
150 | .get_current_backlight = dcn31_get_16_bit_backlight_from_pwm, |
151 | }; |
152 | |
153 | void dcn31_panel_cntl_construct( |
154 | struct dcn31_panel_cntl *dcn31_panel_cntl, |
155 | const struct panel_cntl_init_data *init_data) |
156 | { |
157 | uint8_t pwrseq_inst = 0xF; |
158 | |
159 | dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs; |
160 | dcn31_panel_cntl->base.ctx = init_data->ctx; |
161 | dcn31_panel_cntl->base.inst = init_data->inst; |
162 | |
163 | switch (init_data->eng_id) { |
164 | case ENGINE_ID_DIGA: |
165 | pwrseq_inst = 0; |
166 | break; |
167 | case ENGINE_ID_DIGB: |
168 | pwrseq_inst = 1; |
169 | break; |
170 | default: |
171 | DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n" , init_data->eng_id); |
172 | ASSERT(false); |
173 | break; |
174 | } |
175 | |
176 | dcn31_panel_cntl->base.pwrseq_inst = pwrseq_inst; |
177 | } |
178 | |