1c349dbc7Sjsg /*
2c349dbc7Sjsg * Copyright 2019 Advanced Micro Devices, Inc.
3c349dbc7Sjsg *
4c349dbc7Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg *
11c349dbc7Sjsg * The above copyright notice and this permission notice shall be included in
12c349dbc7Sjsg * all copies or substantial portions of the Software.
13c349dbc7Sjsg *
14c349dbc7Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c349dbc7Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c349dbc7Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17c349dbc7Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c349dbc7Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c349dbc7Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c349dbc7Sjsg * OTHER DEALINGS IN THE SOFTWARE.
21c349dbc7Sjsg *
22c349dbc7Sjsg * Authors: AMD
23c349dbc7Sjsg *
24c349dbc7Sjsg */
25c349dbc7Sjsg
26ad8b1aafSjsg #include "../dmub_srv.h"
27c349dbc7Sjsg #include "dmub_dcn20.h"
28c349dbc7Sjsg #include "dmub_dcn21.h"
29ad8b1aafSjsg #include "dmub_cmd.h"
30ad8b1aafSjsg #include "dmub_dcn30.h"
315ca02815Sjsg #include "dmub_dcn301.h"
325ca02815Sjsg #include "dmub_dcn302.h"
335ca02815Sjsg #include "dmub_dcn303.h"
345ca02815Sjsg #include "dmub_dcn31.h"
353f3e4deaSjsg #include "dmub_dcn314.h"
361bb76ff1Sjsg #include "dmub_dcn315.h"
371bb76ff1Sjsg #include "dmub_dcn316.h"
381bb76ff1Sjsg #include "dmub_dcn32.h"
39c349dbc7Sjsg #include "os_types.h"
40c349dbc7Sjsg /*
41c349dbc7Sjsg * Note: the DMUB service is standalone. No additional headers should be
42c349dbc7Sjsg * added below or above this line unless they reside within the DMUB
43c349dbc7Sjsg * folder.
44c349dbc7Sjsg */
45c349dbc7Sjsg
46c349dbc7Sjsg /* Alignment for framebuffer memory. */
47c349dbc7Sjsg #define DMUB_FB_ALIGNMENT (1024 * 1024)
48c349dbc7Sjsg
49c349dbc7Sjsg /* Stack size. */
50c349dbc7Sjsg #define DMUB_STACK_SIZE (128 * 1024)
51c349dbc7Sjsg
52c349dbc7Sjsg /* Context size. */
53c349dbc7Sjsg #define DMUB_CONTEXT_SIZE (512 * 1024)
54c349dbc7Sjsg
555ca02815Sjsg /* Mailbox size : Ring buffers are required for both inbox and outbox */
565ca02815Sjsg #define DMUB_MAILBOX_SIZE ((2 * DMUB_RB_SIZE))
57c349dbc7Sjsg
58c349dbc7Sjsg /* Default state size if meta is absent. */
59ad8b1aafSjsg #define DMUB_FW_STATE_SIZE (64 * 1024)
60c349dbc7Sjsg
61c349dbc7Sjsg /* Default tracebuffer size if meta is absent. */
62ad8b1aafSjsg #define DMUB_TRACE_BUFFER_SIZE (64 * 1024)
63c349dbc7Sjsg
645ca02815Sjsg
65c349dbc7Sjsg /* Default scratch mem size. */
66c349dbc7Sjsg #define DMUB_SCRATCH_MEM_SIZE (256)
67c349dbc7Sjsg
68c349dbc7Sjsg /* Number of windows in use. */
69c349dbc7Sjsg #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL)
70c349dbc7Sjsg /* Base addresses. */
71c349dbc7Sjsg
72c349dbc7Sjsg #define DMUB_CW0_BASE (0x60000000)
73c349dbc7Sjsg #define DMUB_CW1_BASE (0x61000000)
74c349dbc7Sjsg #define DMUB_CW3_BASE (0x63000000)
75ad8b1aafSjsg #define DMUB_CW4_BASE (0x64000000)
76c349dbc7Sjsg #define DMUB_CW5_BASE (0x65000000)
77c349dbc7Sjsg #define DMUB_CW6_BASE (0x66000000)
78c349dbc7Sjsg
795ca02815Sjsg #define DMUB_REGION5_BASE (0xA0000000)
805ca02815Sjsg
dmub_align(uint32_t val,uint32_t factor)81c349dbc7Sjsg static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
82c349dbc7Sjsg {
83c349dbc7Sjsg return (val + factor - 1) / factor * factor;
84c349dbc7Sjsg }
85c349dbc7Sjsg
dmub_flush_buffer_mem(const struct dmub_fb * fb)86ad8b1aafSjsg void dmub_flush_buffer_mem(const struct dmub_fb *fb)
87c349dbc7Sjsg {
88c349dbc7Sjsg const uint8_t *base = (const uint8_t *)fb->cpu_addr;
89c349dbc7Sjsg uint8_t buf[64];
90c349dbc7Sjsg uint32_t pos, end;
91c349dbc7Sjsg
92c349dbc7Sjsg /**
93c349dbc7Sjsg * Read 64-byte chunks since we don't want to store a
94c349dbc7Sjsg * large temporary buffer for this purpose.
95c349dbc7Sjsg */
96c349dbc7Sjsg end = fb->size / sizeof(buf) * sizeof(buf);
97c349dbc7Sjsg
98c349dbc7Sjsg for (pos = 0; pos < end; pos += sizeof(buf))
99c349dbc7Sjsg dmub_memcpy(buf, base + pos, sizeof(buf));
100c349dbc7Sjsg
101c349dbc7Sjsg /* Read anything leftover into the buffer. */
102c349dbc7Sjsg if (end < fb->size)
103c349dbc7Sjsg dmub_memcpy(buf, base + pos, fb->size - end);
104c349dbc7Sjsg }
105c349dbc7Sjsg
106c349dbc7Sjsg static const struct dmub_fw_meta_info *
dmub_get_fw_meta_info_from_blob(const uint8_t * blob,uint32_t blob_size,uint32_t meta_offset)1071bb76ff1Sjsg dmub_get_fw_meta_info_from_blob(const uint8_t *blob, uint32_t blob_size, uint32_t meta_offset)
108c349dbc7Sjsg {
109c349dbc7Sjsg const union dmub_fw_meta *meta;
110ad8b1aafSjsg
111ad8b1aafSjsg if (!blob || !blob_size)
112c349dbc7Sjsg return NULL;
113c349dbc7Sjsg
114ad8b1aafSjsg if (blob_size < sizeof(union dmub_fw_meta) + meta_offset)
115c349dbc7Sjsg return NULL;
116c349dbc7Sjsg
117ad8b1aafSjsg meta = (const union dmub_fw_meta *)(blob + blob_size - meta_offset -
118c349dbc7Sjsg sizeof(union dmub_fw_meta));
119c349dbc7Sjsg
120c349dbc7Sjsg if (meta->info.magic_value != DMUB_FW_META_MAGIC)
121c349dbc7Sjsg return NULL;
122c349dbc7Sjsg
123c349dbc7Sjsg return &meta->info;
124c349dbc7Sjsg }
125c349dbc7Sjsg
1261bb76ff1Sjsg static const struct dmub_fw_meta_info *
dmub_get_fw_meta_info(const struct dmub_srv_region_params * params)1271bb76ff1Sjsg dmub_get_fw_meta_info(const struct dmub_srv_region_params *params)
1281bb76ff1Sjsg {
1291bb76ff1Sjsg const struct dmub_fw_meta_info *info = NULL;
1301bb76ff1Sjsg
1311bb76ff1Sjsg if (params->fw_bss_data && params->bss_data_size) {
1321bb76ff1Sjsg /* Legacy metadata region. */
1331bb76ff1Sjsg info = dmub_get_fw_meta_info_from_blob(params->fw_bss_data,
1341bb76ff1Sjsg params->bss_data_size,
1351bb76ff1Sjsg DMUB_FW_META_OFFSET);
1361bb76ff1Sjsg } else if (params->fw_inst_const && params->inst_const_size) {
1371bb76ff1Sjsg /* Combined metadata region - can be aligned to 16-bytes. */
1381bb76ff1Sjsg uint32_t i;
1391bb76ff1Sjsg
1401bb76ff1Sjsg for (i = 0; i < 16; ++i) {
1411bb76ff1Sjsg info = dmub_get_fw_meta_info_from_blob(
1421bb76ff1Sjsg params->fw_inst_const, params->inst_const_size, i);
1431bb76ff1Sjsg
1441bb76ff1Sjsg if (info)
1451bb76ff1Sjsg break;
1461bb76ff1Sjsg }
1471bb76ff1Sjsg }
1481bb76ff1Sjsg
1491bb76ff1Sjsg return info;
1501bb76ff1Sjsg }
1511bb76ff1Sjsg
dmub_srv_hw_setup(struct dmub_srv * dmub,enum dmub_asic asic)152c349dbc7Sjsg static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
153c349dbc7Sjsg {
154c349dbc7Sjsg struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
155c349dbc7Sjsg
156c349dbc7Sjsg switch (asic) {
157c349dbc7Sjsg case DMUB_ASIC_DCN20:
158c349dbc7Sjsg case DMUB_ASIC_DCN21:
159ad8b1aafSjsg case DMUB_ASIC_DCN30:
1605ca02815Sjsg case DMUB_ASIC_DCN301:
1615ca02815Sjsg case DMUB_ASIC_DCN302:
1625ca02815Sjsg case DMUB_ASIC_DCN303:
163c349dbc7Sjsg dmub->regs = &dmub_srv_dcn20_regs;
164c349dbc7Sjsg
165c349dbc7Sjsg funcs->reset = dmub_dcn20_reset;
166c349dbc7Sjsg funcs->reset_release = dmub_dcn20_reset_release;
167c349dbc7Sjsg funcs->backdoor_load = dmub_dcn20_backdoor_load;
168c349dbc7Sjsg funcs->setup_windows = dmub_dcn20_setup_windows;
169c349dbc7Sjsg funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
17069703a93Sjsg funcs->get_inbox1_wptr = dmub_dcn20_get_inbox1_wptr;
171c349dbc7Sjsg funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
172c349dbc7Sjsg funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
173c349dbc7Sjsg funcs->is_supported = dmub_dcn20_is_supported;
174c349dbc7Sjsg funcs->is_hw_init = dmub_dcn20_is_hw_init;
175c349dbc7Sjsg funcs->set_gpint = dmub_dcn20_set_gpint;
176c349dbc7Sjsg funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked;
177c349dbc7Sjsg funcs->get_gpint_response = dmub_dcn20_get_gpint_response;
1785ca02815Sjsg funcs->get_fw_status = dmub_dcn20_get_fw_boot_status;
1795ca02815Sjsg funcs->enable_dmub_boot_options = dmub_dcn20_enable_dmub_boot_options;
1805ca02815Sjsg funcs->skip_dmub_panel_power_sequence = dmub_dcn20_skip_dmub_panel_power_sequence;
1815ca02815Sjsg funcs->get_current_time = dmub_dcn20_get_current_time;
1825ca02815Sjsg
1835ca02815Sjsg // Out mailbox register access functions for RN and above
1845ca02815Sjsg funcs->setup_out_mailbox = dmub_dcn20_setup_out_mailbox;
1855ca02815Sjsg funcs->get_outbox1_wptr = dmub_dcn20_get_outbox1_wptr;
1865ca02815Sjsg funcs->set_outbox1_rptr = dmub_dcn20_set_outbox1_rptr;
1875ca02815Sjsg
1885ca02815Sjsg //outbox0 call stacks
1895ca02815Sjsg funcs->setup_outbox0 = dmub_dcn20_setup_outbox0;
1905ca02815Sjsg funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr;
1915ca02815Sjsg funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr;
1925ca02815Sjsg
1935ca02815Sjsg funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data;
194c349dbc7Sjsg
195*f005ef32Sjsg if (asic == DMUB_ASIC_DCN21)
196c349dbc7Sjsg dmub->regs = &dmub_srv_dcn21_regs;
197c349dbc7Sjsg
198ad8b1aafSjsg if (asic == DMUB_ASIC_DCN30) {
199ad8b1aafSjsg dmub->regs = &dmub_srv_dcn30_regs;
200ad8b1aafSjsg
201ad8b1aafSjsg funcs->backdoor_load = dmub_dcn30_backdoor_load;
202ad8b1aafSjsg funcs->setup_windows = dmub_dcn30_setup_windows;
203ad8b1aafSjsg }
2045ca02815Sjsg if (asic == DMUB_ASIC_DCN301) {
2055ca02815Sjsg dmub->regs = &dmub_srv_dcn301_regs;
2065ca02815Sjsg
2075ca02815Sjsg funcs->backdoor_load = dmub_dcn30_backdoor_load;
2085ca02815Sjsg funcs->setup_windows = dmub_dcn30_setup_windows;
2095ca02815Sjsg }
2105ca02815Sjsg if (asic == DMUB_ASIC_DCN302) {
2115ca02815Sjsg dmub->regs = &dmub_srv_dcn302_regs;
2125ca02815Sjsg
2135ca02815Sjsg funcs->backdoor_load = dmub_dcn30_backdoor_load;
2145ca02815Sjsg funcs->setup_windows = dmub_dcn30_setup_windows;
2155ca02815Sjsg }
2165ca02815Sjsg if (asic == DMUB_ASIC_DCN303) {
2175ca02815Sjsg dmub->regs = &dmub_srv_dcn303_regs;
2185ca02815Sjsg
2195ca02815Sjsg funcs->backdoor_load = dmub_dcn30_backdoor_load;
2205ca02815Sjsg funcs->setup_windows = dmub_dcn30_setup_windows;
2215ca02815Sjsg }
2225ca02815Sjsg break;
2235ca02815Sjsg
2245ca02815Sjsg case DMUB_ASIC_DCN31:
2251bb76ff1Sjsg case DMUB_ASIC_DCN31B:
2261bb76ff1Sjsg case DMUB_ASIC_DCN314:
2271bb76ff1Sjsg case DMUB_ASIC_DCN315:
2281bb76ff1Sjsg case DMUB_ASIC_DCN316:
2295dce7169Sjsg if (asic == DMUB_ASIC_DCN314) {
2303f3e4deaSjsg dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
231a7a3e763Sjsg funcs->is_psrsu_supported = dmub_dcn314_is_psrsu_supported;
2325dce7169Sjsg } else if (asic == DMUB_ASIC_DCN315) {
2331bb76ff1Sjsg dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
2345dce7169Sjsg } else if (asic == DMUB_ASIC_DCN316) {
2351bb76ff1Sjsg dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
2365dce7169Sjsg } else {
2375ca02815Sjsg dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
2385dce7169Sjsg funcs->is_psrsu_supported = dmub_dcn31_is_psrsu_supported;
2395dce7169Sjsg }
2405ca02815Sjsg funcs->reset = dmub_dcn31_reset;
2415ca02815Sjsg funcs->reset_release = dmub_dcn31_reset_release;
2425ca02815Sjsg funcs->backdoor_load = dmub_dcn31_backdoor_load;
2435ca02815Sjsg funcs->setup_windows = dmub_dcn31_setup_windows;
2445ca02815Sjsg funcs->setup_mailbox = dmub_dcn31_setup_mailbox;
24569703a93Sjsg funcs->get_inbox1_wptr = dmub_dcn31_get_inbox1_wptr;
2465ca02815Sjsg funcs->get_inbox1_rptr = dmub_dcn31_get_inbox1_rptr;
2475ca02815Sjsg funcs->set_inbox1_wptr = dmub_dcn31_set_inbox1_wptr;
2485ca02815Sjsg funcs->setup_out_mailbox = dmub_dcn31_setup_out_mailbox;
2495ca02815Sjsg funcs->get_outbox1_wptr = dmub_dcn31_get_outbox1_wptr;
2505ca02815Sjsg funcs->set_outbox1_rptr = dmub_dcn31_set_outbox1_rptr;
2515ca02815Sjsg funcs->is_supported = dmub_dcn31_is_supported;
2525ca02815Sjsg funcs->is_hw_init = dmub_dcn31_is_hw_init;
2535ca02815Sjsg funcs->set_gpint = dmub_dcn31_set_gpint;
2545ca02815Sjsg funcs->is_gpint_acked = dmub_dcn31_is_gpint_acked;
2555ca02815Sjsg funcs->get_gpint_response = dmub_dcn31_get_gpint_response;
2565ca02815Sjsg funcs->get_gpint_dataout = dmub_dcn31_get_gpint_dataout;
2575ca02815Sjsg funcs->get_fw_status = dmub_dcn31_get_fw_boot_status;
258*f005ef32Sjsg funcs->get_fw_boot_option = dmub_dcn31_get_fw_boot_option;
2595ca02815Sjsg funcs->enable_dmub_boot_options = dmub_dcn31_enable_dmub_boot_options;
2605ca02815Sjsg funcs->skip_dmub_panel_power_sequence = dmub_dcn31_skip_dmub_panel_power_sequence;
2615ca02815Sjsg //outbox0 call stacks
2625ca02815Sjsg funcs->setup_outbox0 = dmub_dcn31_setup_outbox0;
2635ca02815Sjsg funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr;
2645ca02815Sjsg funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr;
2655ca02815Sjsg
2665ca02815Sjsg funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data;
2671bb76ff1Sjsg funcs->should_detect = dmub_dcn31_should_detect;
2685ca02815Sjsg funcs->get_current_time = dmub_dcn31_get_current_time;
2695ca02815Sjsg
270c349dbc7Sjsg break;
271c349dbc7Sjsg
2721bb76ff1Sjsg case DMUB_ASIC_DCN32:
2731bb76ff1Sjsg case DMUB_ASIC_DCN321:
2741bb76ff1Sjsg dmub->regs_dcn32 = &dmub_srv_dcn32_regs;
2751bb76ff1Sjsg funcs->configure_dmub_in_system_memory = dmub_dcn32_configure_dmub_in_system_memory;
2761bb76ff1Sjsg funcs->send_inbox0_cmd = dmub_dcn32_send_inbox0_cmd;
2771bb76ff1Sjsg funcs->clear_inbox0_ack_register = dmub_dcn32_clear_inbox0_ack_register;
2781bb76ff1Sjsg funcs->read_inbox0_ack_register = dmub_dcn32_read_inbox0_ack_register;
2791bb76ff1Sjsg funcs->reset = dmub_dcn32_reset;
2801bb76ff1Sjsg funcs->reset_release = dmub_dcn32_reset_release;
2811bb76ff1Sjsg funcs->backdoor_load = dmub_dcn32_backdoor_load;
2821bb76ff1Sjsg funcs->backdoor_load_zfb_mode = dmub_dcn32_backdoor_load_zfb_mode;
2831bb76ff1Sjsg funcs->setup_windows = dmub_dcn32_setup_windows;
2841bb76ff1Sjsg funcs->setup_mailbox = dmub_dcn32_setup_mailbox;
28569703a93Sjsg funcs->get_inbox1_wptr = dmub_dcn32_get_inbox1_wptr;
2861bb76ff1Sjsg funcs->get_inbox1_rptr = dmub_dcn32_get_inbox1_rptr;
2871bb76ff1Sjsg funcs->set_inbox1_wptr = dmub_dcn32_set_inbox1_wptr;
2881bb76ff1Sjsg funcs->setup_out_mailbox = dmub_dcn32_setup_out_mailbox;
2891bb76ff1Sjsg funcs->get_outbox1_wptr = dmub_dcn32_get_outbox1_wptr;
2901bb76ff1Sjsg funcs->set_outbox1_rptr = dmub_dcn32_set_outbox1_rptr;
2911bb76ff1Sjsg funcs->is_supported = dmub_dcn32_is_supported;
2921bb76ff1Sjsg funcs->is_hw_init = dmub_dcn32_is_hw_init;
2931bb76ff1Sjsg funcs->set_gpint = dmub_dcn32_set_gpint;
2941bb76ff1Sjsg funcs->is_gpint_acked = dmub_dcn32_is_gpint_acked;
2951bb76ff1Sjsg funcs->get_gpint_response = dmub_dcn32_get_gpint_response;
2961bb76ff1Sjsg funcs->get_gpint_dataout = dmub_dcn32_get_gpint_dataout;
2971bb76ff1Sjsg funcs->get_fw_status = dmub_dcn32_get_fw_boot_status;
2981bb76ff1Sjsg funcs->enable_dmub_boot_options = dmub_dcn32_enable_dmub_boot_options;
2991bb76ff1Sjsg funcs->skip_dmub_panel_power_sequence = dmub_dcn32_skip_dmub_panel_power_sequence;
3001bb76ff1Sjsg
3011bb76ff1Sjsg /* outbox0 call stacks */
3021bb76ff1Sjsg funcs->setup_outbox0 = dmub_dcn32_setup_outbox0;
3031bb76ff1Sjsg funcs->get_outbox0_wptr = dmub_dcn32_get_outbox0_wptr;
3041bb76ff1Sjsg funcs->set_outbox0_rptr = dmub_dcn32_set_outbox0_rptr;
3051bb76ff1Sjsg funcs->get_current_time = dmub_dcn32_get_current_time;
3061bb76ff1Sjsg funcs->get_diagnostic_data = dmub_dcn32_get_diagnostic_data;
3071bb76ff1Sjsg
3081bb76ff1Sjsg break;
3091bb76ff1Sjsg
310c349dbc7Sjsg default:
311c349dbc7Sjsg return false;
312c349dbc7Sjsg }
313c349dbc7Sjsg
314c349dbc7Sjsg return true;
315c349dbc7Sjsg }
316c349dbc7Sjsg
dmub_srv_create(struct dmub_srv * dmub,const struct dmub_srv_create_params * params)317c349dbc7Sjsg enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
318c349dbc7Sjsg const struct dmub_srv_create_params *params)
319c349dbc7Sjsg {
320c349dbc7Sjsg enum dmub_status status = DMUB_STATUS_OK;
321c349dbc7Sjsg
322c349dbc7Sjsg dmub_memset(dmub, 0, sizeof(*dmub));
323c349dbc7Sjsg
324c349dbc7Sjsg dmub->funcs = params->funcs;
325c349dbc7Sjsg dmub->user_ctx = params->user_ctx;
326c349dbc7Sjsg dmub->asic = params->asic;
327ad8b1aafSjsg dmub->fw_version = params->fw_version;
328c349dbc7Sjsg dmub->is_virtual = params->is_virtual;
329c349dbc7Sjsg
330c349dbc7Sjsg /* Setup asic dependent hardware funcs. */
331c349dbc7Sjsg if (!dmub_srv_hw_setup(dmub, params->asic)) {
332c349dbc7Sjsg status = DMUB_STATUS_INVALID;
333c349dbc7Sjsg goto cleanup;
334c349dbc7Sjsg }
335c349dbc7Sjsg
336c349dbc7Sjsg /* Override (some) hardware funcs based on user params. */
337c349dbc7Sjsg if (params->hw_funcs) {
338ad8b1aafSjsg if (params->hw_funcs->emul_get_inbox1_rptr)
339ad8b1aafSjsg dmub->hw_funcs.emul_get_inbox1_rptr =
340ad8b1aafSjsg params->hw_funcs->emul_get_inbox1_rptr;
341c349dbc7Sjsg
342ad8b1aafSjsg if (params->hw_funcs->emul_set_inbox1_wptr)
343ad8b1aafSjsg dmub->hw_funcs.emul_set_inbox1_wptr =
344ad8b1aafSjsg params->hw_funcs->emul_set_inbox1_wptr;
345c349dbc7Sjsg
346c349dbc7Sjsg if (params->hw_funcs->is_supported)
347c349dbc7Sjsg dmub->hw_funcs.is_supported =
348c349dbc7Sjsg params->hw_funcs->is_supported;
349c349dbc7Sjsg }
350c349dbc7Sjsg
351c349dbc7Sjsg /* Sanity checks for required hw func pointers. */
352c349dbc7Sjsg if (!dmub->hw_funcs.get_inbox1_rptr ||
353c349dbc7Sjsg !dmub->hw_funcs.set_inbox1_wptr) {
354c349dbc7Sjsg status = DMUB_STATUS_INVALID;
355c349dbc7Sjsg goto cleanup;
356c349dbc7Sjsg }
357c349dbc7Sjsg
358c349dbc7Sjsg cleanup:
359c349dbc7Sjsg if (status == DMUB_STATUS_OK)
360c349dbc7Sjsg dmub->sw_init = true;
361c349dbc7Sjsg else
362c349dbc7Sjsg dmub_srv_destroy(dmub);
363c349dbc7Sjsg
364c349dbc7Sjsg return status;
365c349dbc7Sjsg }
366c349dbc7Sjsg
dmub_srv_destroy(struct dmub_srv * dmub)367c349dbc7Sjsg void dmub_srv_destroy(struct dmub_srv *dmub)
368c349dbc7Sjsg {
369c349dbc7Sjsg dmub_memset(dmub, 0, sizeof(*dmub));
370c349dbc7Sjsg }
371c349dbc7Sjsg
372c349dbc7Sjsg enum dmub_status
dmub_srv_calc_region_info(struct dmub_srv * dmub,const struct dmub_srv_region_params * params,struct dmub_srv_region_info * out)373c349dbc7Sjsg dmub_srv_calc_region_info(struct dmub_srv *dmub,
374c349dbc7Sjsg const struct dmub_srv_region_params *params,
375c349dbc7Sjsg struct dmub_srv_region_info *out)
376c349dbc7Sjsg {
377c349dbc7Sjsg struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST];
378c349dbc7Sjsg struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK];
379c349dbc7Sjsg struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA];
380c349dbc7Sjsg struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS];
381c349dbc7Sjsg struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX];
382c349dbc7Sjsg struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF];
383c349dbc7Sjsg struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE];
384c349dbc7Sjsg struct dmub_region *scratch_mem = &out->regions[DMUB_WINDOW_7_SCRATCH_MEM];
385c349dbc7Sjsg const struct dmub_fw_meta_info *fw_info;
386c349dbc7Sjsg uint32_t fw_state_size = DMUB_FW_STATE_SIZE;
387c349dbc7Sjsg uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE;
388c349dbc7Sjsg uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE;
389cf95312aSjsg uint32_t previous_top = 0;
390c349dbc7Sjsg if (!dmub->sw_init)
391c349dbc7Sjsg return DMUB_STATUS_INVALID;
392c349dbc7Sjsg
393c349dbc7Sjsg memset(out, 0, sizeof(*out));
394c349dbc7Sjsg
395c349dbc7Sjsg out->num_regions = DMUB_NUM_WINDOWS;
396c349dbc7Sjsg
397c349dbc7Sjsg inst->base = 0x0;
398c349dbc7Sjsg inst->top = inst->base + params->inst_const_size;
399c349dbc7Sjsg
400c349dbc7Sjsg data->base = dmub_align(inst->top, 256);
401c349dbc7Sjsg data->top = data->base + params->bss_data_size;
402c349dbc7Sjsg
403c349dbc7Sjsg /*
404c349dbc7Sjsg * All cache windows below should be aligned to the size
405c349dbc7Sjsg * of the DMCUB cache line, 64 bytes.
406c349dbc7Sjsg */
407c349dbc7Sjsg
408c349dbc7Sjsg stack->base = dmub_align(data->top, 256);
409c349dbc7Sjsg stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
410c349dbc7Sjsg
411c349dbc7Sjsg bios->base = dmub_align(stack->top, 256);
412c349dbc7Sjsg bios->top = bios->base + params->vbios_size;
413c349dbc7Sjsg
414cf95312aSjsg if (params->is_mailbox_in_inbox) {
415cf95312aSjsg mail->base = 0;
416cf95312aSjsg mail->top = mail->base + DMUB_MAILBOX_SIZE;
417cf95312aSjsg previous_top = bios->top;
418cf95312aSjsg } else {
419c349dbc7Sjsg mail->base = dmub_align(bios->top, 256);
420c349dbc7Sjsg mail->top = mail->base + DMUB_MAILBOX_SIZE;
421cf95312aSjsg previous_top = mail->top;
422cf95312aSjsg }
423c349dbc7Sjsg
424ad8b1aafSjsg fw_info = dmub_get_fw_meta_info(params);
425c349dbc7Sjsg
426c349dbc7Sjsg if (fw_info) {
427c349dbc7Sjsg fw_state_size = fw_info->fw_region_size;
428c349dbc7Sjsg trace_buffer_size = fw_info->trace_buffer_size;
429ad8b1aafSjsg
430ad8b1aafSjsg /**
431ad8b1aafSjsg * If DM didn't fill in a version, then fill it in based on
432ad8b1aafSjsg * the firmware meta now that we have it.
433ad8b1aafSjsg *
434ad8b1aafSjsg * TODO: Make it easier for driver to extract this out to
435ad8b1aafSjsg * pass during creation.
436ad8b1aafSjsg */
437ad8b1aafSjsg if (dmub->fw_version == 0)
438ad8b1aafSjsg dmub->fw_version = fw_info->fw_version;
439c349dbc7Sjsg }
440c349dbc7Sjsg
441cf95312aSjsg trace_buff->base = dmub_align(previous_top, 256);
442c349dbc7Sjsg trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64);
443c349dbc7Sjsg
444c349dbc7Sjsg fw_state->base = dmub_align(trace_buff->top, 256);
445c349dbc7Sjsg fw_state->top = fw_state->base + dmub_align(fw_state_size, 64);
446c349dbc7Sjsg
447c349dbc7Sjsg scratch_mem->base = dmub_align(fw_state->top, 256);
448c349dbc7Sjsg scratch_mem->top = scratch_mem->base + dmub_align(scratch_mem_size, 64);
449c349dbc7Sjsg
450c349dbc7Sjsg out->fb_size = dmub_align(scratch_mem->top, 4096);
451c349dbc7Sjsg
452cf95312aSjsg if (params->is_mailbox_in_inbox)
453cf95312aSjsg out->inbox_size = dmub_align(mail->top, 4096);
454cf95312aSjsg
455c349dbc7Sjsg return DMUB_STATUS_OK;
456c349dbc7Sjsg }
457c349dbc7Sjsg
dmub_srv_calc_mem_info(struct dmub_srv * dmub,const struct dmub_srv_memory_params * params,struct dmub_srv_fb_info * out)458cf95312aSjsg enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub,
459cf95312aSjsg const struct dmub_srv_memory_params *params,
460c349dbc7Sjsg struct dmub_srv_fb_info *out)
461c349dbc7Sjsg {
462c349dbc7Sjsg uint8_t *cpu_base;
463c349dbc7Sjsg uint64_t gpu_base;
464c349dbc7Sjsg uint32_t i;
465c349dbc7Sjsg
466c349dbc7Sjsg if (!dmub->sw_init)
467c349dbc7Sjsg return DMUB_STATUS_INVALID;
468c349dbc7Sjsg
469c349dbc7Sjsg memset(out, 0, sizeof(*out));
470c349dbc7Sjsg
471c349dbc7Sjsg if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
472c349dbc7Sjsg return DMUB_STATUS_INVALID;
473c349dbc7Sjsg
474cf95312aSjsg cpu_base = (uint8_t *)params->cpu_fb_addr;
475cf95312aSjsg gpu_base = params->gpu_fb_addr;
476c349dbc7Sjsg
477c349dbc7Sjsg for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
478c349dbc7Sjsg const struct dmub_region *reg =
479c349dbc7Sjsg ¶ms->region_info->regions[i];
480c349dbc7Sjsg
481c349dbc7Sjsg out->fb[i].cpu_addr = cpu_base + reg->base;
482c349dbc7Sjsg out->fb[i].gpu_addr = gpu_base + reg->base;
483cf95312aSjsg
484cf95312aSjsg if (i == DMUB_WINDOW_4_MAILBOX && params->cpu_inbox_addr != 0) {
485cf95312aSjsg out->fb[i].cpu_addr = (uint8_t *)params->cpu_inbox_addr + reg->base;
486cf95312aSjsg out->fb[i].gpu_addr = params->gpu_inbox_addr + reg->base;
487cf95312aSjsg }
488cf95312aSjsg
489c349dbc7Sjsg out->fb[i].size = reg->top - reg->base;
490c349dbc7Sjsg }
491c349dbc7Sjsg
492c349dbc7Sjsg out->num_fb = DMUB_NUM_WINDOWS;
493c349dbc7Sjsg
494c349dbc7Sjsg return DMUB_STATUS_OK;
495c349dbc7Sjsg }
496c349dbc7Sjsg
dmub_srv_has_hw_support(struct dmub_srv * dmub,bool * is_supported)497c349dbc7Sjsg enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
498c349dbc7Sjsg bool *is_supported)
499c349dbc7Sjsg {
500c349dbc7Sjsg *is_supported = false;
501c349dbc7Sjsg
502c349dbc7Sjsg if (!dmub->sw_init)
503c349dbc7Sjsg return DMUB_STATUS_INVALID;
504c349dbc7Sjsg
505c349dbc7Sjsg if (dmub->hw_funcs.is_supported)
506c349dbc7Sjsg *is_supported = dmub->hw_funcs.is_supported(dmub);
507c349dbc7Sjsg
508c349dbc7Sjsg return DMUB_STATUS_OK;
509c349dbc7Sjsg }
510c349dbc7Sjsg
dmub_srv_is_hw_init(struct dmub_srv * dmub,bool * is_hw_init)511c349dbc7Sjsg enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
512c349dbc7Sjsg {
513c349dbc7Sjsg *is_hw_init = false;
514c349dbc7Sjsg
515c349dbc7Sjsg if (!dmub->sw_init)
516c349dbc7Sjsg return DMUB_STATUS_INVALID;
517c349dbc7Sjsg
518c349dbc7Sjsg if (!dmub->hw_init)
519c349dbc7Sjsg return DMUB_STATUS_OK;
520c349dbc7Sjsg
521c349dbc7Sjsg if (dmub->hw_funcs.is_hw_init)
522c349dbc7Sjsg *is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
523c349dbc7Sjsg
524c349dbc7Sjsg return DMUB_STATUS_OK;
525c349dbc7Sjsg }
526c349dbc7Sjsg
dmub_srv_hw_init(struct dmub_srv * dmub,const struct dmub_srv_hw_params * params)527c349dbc7Sjsg enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
528c349dbc7Sjsg const struct dmub_srv_hw_params *params)
529c349dbc7Sjsg {
530c349dbc7Sjsg struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
531c349dbc7Sjsg struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
532c349dbc7Sjsg struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
533c349dbc7Sjsg struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
534c349dbc7Sjsg struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
535c349dbc7Sjsg struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
536c349dbc7Sjsg struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
537c349dbc7Sjsg struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
538c349dbc7Sjsg
5395ca02815Sjsg struct dmub_rb_init_params rb_params, outbox0_rb_params;
540c349dbc7Sjsg struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6;
5415ca02815Sjsg struct dmub_region inbox1, outbox1, outbox0;
542c349dbc7Sjsg
543c349dbc7Sjsg if (!dmub->sw_init)
544c349dbc7Sjsg return DMUB_STATUS_INVALID;
545c349dbc7Sjsg
5465ca02815Sjsg if (!inst_fb || !stack_fb || !data_fb || !bios_fb || !mail_fb ||
5475ca02815Sjsg !tracebuff_fb || !fw_state_fb || !scratch_mem_fb) {
5485ca02815Sjsg ASSERT(0);
5495ca02815Sjsg return DMUB_STATUS_INVALID;
5505ca02815Sjsg }
5515ca02815Sjsg
552c349dbc7Sjsg dmub->fb_base = params->fb_base;
553c349dbc7Sjsg dmub->fb_offset = params->fb_offset;
554c349dbc7Sjsg dmub->psp_version = params->psp_version;
555c349dbc7Sjsg
5565ca02815Sjsg if (dmub->hw_funcs.reset)
5575ca02815Sjsg dmub->hw_funcs.reset(dmub);
5585ca02815Sjsg
5596150e708Sjsg /* reset the cache of the last wptr as well now that hw is reset */
5606150e708Sjsg dmub->inbox1_last_wptr = 0;
5616150e708Sjsg
562c349dbc7Sjsg cw0.offset.quad_part = inst_fb->gpu_addr;
563c349dbc7Sjsg cw0.region.base = DMUB_CW0_BASE;
564c349dbc7Sjsg cw0.region.top = cw0.region.base + inst_fb->size - 1;
565c349dbc7Sjsg
566c349dbc7Sjsg cw1.offset.quad_part = stack_fb->gpu_addr;
567c349dbc7Sjsg cw1.region.base = DMUB_CW1_BASE;
568c349dbc7Sjsg cw1.region.top = cw1.region.base + stack_fb->size - 1;
569c349dbc7Sjsg
5701bb76ff1Sjsg if (params->fw_in_system_memory && dmub->hw_funcs.configure_dmub_in_system_memory)
5711bb76ff1Sjsg dmub->hw_funcs.configure_dmub_in_system_memory(dmub);
5721bb76ff1Sjsg
5735ca02815Sjsg if (params->load_inst_const && dmub->hw_funcs.backdoor_load) {
574c349dbc7Sjsg /**
575c349dbc7Sjsg * Read back all the instruction memory so we don't hang the
576c349dbc7Sjsg * DMCUB when backdoor loading if the write from x86 hasn't been
577c349dbc7Sjsg * flushed yet. This only occurs in backdoor loading.
578c349dbc7Sjsg */
579c349dbc7Sjsg dmub_flush_buffer_mem(inst_fb);
5801bb76ff1Sjsg
5811bb76ff1Sjsg if (params->fw_in_system_memory && dmub->hw_funcs.backdoor_load_zfb_mode)
5821bb76ff1Sjsg dmub->hw_funcs.backdoor_load_zfb_mode(dmub, &cw0, &cw1);
5831bb76ff1Sjsg else
584c349dbc7Sjsg dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
585c349dbc7Sjsg }
586c349dbc7Sjsg
587c349dbc7Sjsg cw2.offset.quad_part = data_fb->gpu_addr;
588c349dbc7Sjsg cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
589c349dbc7Sjsg cw2.region.top = cw2.region.base + data_fb->size;
590c349dbc7Sjsg
591c349dbc7Sjsg cw3.offset.quad_part = bios_fb->gpu_addr;
592c349dbc7Sjsg cw3.region.base = DMUB_CW3_BASE;
593c349dbc7Sjsg cw3.region.top = cw3.region.base + bios_fb->size;
594c349dbc7Sjsg
595c349dbc7Sjsg cw4.offset.quad_part = mail_fb->gpu_addr;
596ad8b1aafSjsg cw4.region.base = DMUB_CW4_BASE;
597c349dbc7Sjsg cw4.region.top = cw4.region.base + mail_fb->size;
598c349dbc7Sjsg
5995ca02815Sjsg /**
6005ca02815Sjsg * Doubled the mailbox region to accomodate inbox and outbox.
6015ca02815Sjsg * Note: Currently, currently total mailbox size is 16KB. It is split
6025ca02815Sjsg * equally into 8KB between inbox and outbox. If this config is
6035ca02815Sjsg * changed, then uncached base address configuration of outbox1
6045ca02815Sjsg * has to be updated in funcs->setup_out_mailbox.
6055ca02815Sjsg */
606c349dbc7Sjsg inbox1.base = cw4.region.base;
6075ca02815Sjsg inbox1.top = cw4.region.base + DMUB_RB_SIZE;
6085ca02815Sjsg outbox1.base = inbox1.top;
6095ca02815Sjsg outbox1.top = cw4.region.top;
610c349dbc7Sjsg
611c349dbc7Sjsg cw5.offset.quad_part = tracebuff_fb->gpu_addr;
612c349dbc7Sjsg cw5.region.base = DMUB_CW5_BASE;
613c349dbc7Sjsg cw5.region.top = cw5.region.base + tracebuff_fb->size;
614c349dbc7Sjsg
6155ca02815Sjsg outbox0.base = DMUB_REGION5_BASE + TRACE_BUFFER_ENTRY_OFFSET;
6165ca02815Sjsg outbox0.top = outbox0.base + tracebuff_fb->size - TRACE_BUFFER_ENTRY_OFFSET;
6175ca02815Sjsg
618c349dbc7Sjsg cw6.offset.quad_part = fw_state_fb->gpu_addr;
619c349dbc7Sjsg cw6.region.base = DMUB_CW6_BASE;
620c349dbc7Sjsg cw6.region.top = cw6.region.base + fw_state_fb->size;
621c349dbc7Sjsg
622c349dbc7Sjsg dmub->fw_state = fw_state_fb->cpu_addr;
623c349dbc7Sjsg
624c349dbc7Sjsg dmub->scratch_mem_fb = *scratch_mem_fb;
625c349dbc7Sjsg
626c349dbc7Sjsg if (dmub->hw_funcs.setup_windows)
6275ca02815Sjsg dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5, &cw6);
6285ca02815Sjsg
6295ca02815Sjsg if (dmub->hw_funcs.setup_outbox0)
6305ca02815Sjsg dmub->hw_funcs.setup_outbox0(dmub, &outbox0);
631c349dbc7Sjsg
632c349dbc7Sjsg if (dmub->hw_funcs.setup_mailbox)
633c349dbc7Sjsg dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
6345ca02815Sjsg if (dmub->hw_funcs.setup_out_mailbox)
6355ca02815Sjsg dmub->hw_funcs.setup_out_mailbox(dmub, &outbox1);
636c349dbc7Sjsg
637c349dbc7Sjsg dmub_memset(&rb_params, 0, sizeof(rb_params));
638c349dbc7Sjsg rb_params.ctx = dmub;
639c349dbc7Sjsg rb_params.base_address = mail_fb->cpu_addr;
640c349dbc7Sjsg rb_params.capacity = DMUB_RB_SIZE;
641c349dbc7Sjsg dmub_rb_init(&dmub->inbox1_rb, &rb_params);
6425ca02815Sjsg
6435ca02815Sjsg // Initialize outbox1 ring buffer
6445ca02815Sjsg rb_params.ctx = dmub;
6455ca02815Sjsg rb_params.base_address = (void *) ((uint8_t *) (mail_fb->cpu_addr) + DMUB_RB_SIZE);
6465ca02815Sjsg rb_params.capacity = DMUB_RB_SIZE;
6475ca02815Sjsg dmub_rb_init(&dmub->outbox1_rb, &rb_params);
6485ca02815Sjsg
6495ca02815Sjsg dmub_memset(&outbox0_rb_params, 0, sizeof(outbox0_rb_params));
6505ca02815Sjsg outbox0_rb_params.ctx = dmub;
6515ca02815Sjsg outbox0_rb_params.base_address = (void *)((uintptr_t)(tracebuff_fb->cpu_addr) + TRACE_BUFFER_ENTRY_OFFSET);
6525ca02815Sjsg outbox0_rb_params.capacity = tracebuff_fb->size - dmub_align(TRACE_BUFFER_ENTRY_OFFSET, 64);
6535ca02815Sjsg dmub_rb_init(&dmub->outbox0_rb, &outbox0_rb_params);
6545ca02815Sjsg
6555ca02815Sjsg /* Report to DMUB what features are supported by current driver */
6565ca02815Sjsg if (dmub->hw_funcs.enable_dmub_boot_options)
6575ca02815Sjsg dmub->hw_funcs.enable_dmub_boot_options(dmub, params);
658c349dbc7Sjsg
659*f005ef32Sjsg if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
6601bb76ff1Sjsg dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub,
6611bb76ff1Sjsg params->skip_panel_power_sequence);
6621bb76ff1Sjsg
663*f005ef32Sjsg if (dmub->hw_funcs.reset_release && !dmub->is_virtual)
664c349dbc7Sjsg dmub->hw_funcs.reset_release(dmub);
665c349dbc7Sjsg
666c349dbc7Sjsg dmub->hw_init = true;
667c349dbc7Sjsg
668c349dbc7Sjsg return DMUB_STATUS_OK;
669c349dbc7Sjsg }
670c349dbc7Sjsg
dmub_srv_sync_inbox1(struct dmub_srv * dmub)67169703a93Sjsg enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub)
67269703a93Sjsg {
67369703a93Sjsg if (!dmub->sw_init)
67469703a93Sjsg return DMUB_STATUS_INVALID;
67569703a93Sjsg
67669703a93Sjsg if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) {
6771c155a16Sjsg uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
6781c155a16Sjsg uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub);
6791c155a16Sjsg
6801c155a16Sjsg if (rptr > dmub->inbox1_rb.capacity || wptr > dmub->inbox1_rb.capacity) {
6811c155a16Sjsg return DMUB_STATUS_HW_FAILURE;
6821c155a16Sjsg } else {
6831c155a16Sjsg dmub->inbox1_rb.rptr = rptr;
6841c155a16Sjsg dmub->inbox1_rb.wrpt = wptr;
68569703a93Sjsg dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
68669703a93Sjsg }
6871c155a16Sjsg }
68869703a93Sjsg
68969703a93Sjsg return DMUB_STATUS_OK;
69069703a93Sjsg }
69169703a93Sjsg
dmub_srv_hw_reset(struct dmub_srv * dmub)692c349dbc7Sjsg enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
693c349dbc7Sjsg {
694c349dbc7Sjsg if (!dmub->sw_init)
695c349dbc7Sjsg return DMUB_STATUS_INVALID;
696c349dbc7Sjsg
697c349dbc7Sjsg if (dmub->hw_funcs.reset)
698c349dbc7Sjsg dmub->hw_funcs.reset(dmub);
699c349dbc7Sjsg
7006150e708Sjsg /* mailboxes have been reset in hw, so reset the sw state as well */
7016150e708Sjsg dmub->inbox1_last_wptr = 0;
7026150e708Sjsg dmub->inbox1_rb.wrpt = 0;
7036150e708Sjsg dmub->inbox1_rb.rptr = 0;
7046150e708Sjsg dmub->outbox0_rb.wrpt = 0;
7056150e708Sjsg dmub->outbox0_rb.rptr = 0;
7066150e708Sjsg dmub->outbox1_rb.wrpt = 0;
7076150e708Sjsg dmub->outbox1_rb.rptr = 0;
7086150e708Sjsg
709c349dbc7Sjsg dmub->hw_init = false;
710c349dbc7Sjsg
711c349dbc7Sjsg return DMUB_STATUS_OK;
712c349dbc7Sjsg }
713c349dbc7Sjsg
dmub_srv_cmd_queue(struct dmub_srv * dmub,const union dmub_rb_cmd * cmd)714c349dbc7Sjsg enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
715ad8b1aafSjsg const union dmub_rb_cmd *cmd)
716c349dbc7Sjsg {
717c349dbc7Sjsg if (!dmub->hw_init)
718c349dbc7Sjsg return DMUB_STATUS_INVALID;
719c349dbc7Sjsg
7201c155a16Sjsg if (dmub->inbox1_rb.rptr > dmub->inbox1_rb.capacity ||
7211c155a16Sjsg dmub->inbox1_rb.wrpt > dmub->inbox1_rb.capacity) {
7221c155a16Sjsg return DMUB_STATUS_HW_FAILURE;
7231c155a16Sjsg }
7241c155a16Sjsg
725c349dbc7Sjsg if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
726c349dbc7Sjsg return DMUB_STATUS_OK;
727c349dbc7Sjsg
728c349dbc7Sjsg return DMUB_STATUS_QUEUE_FULL;
729c349dbc7Sjsg }
730c349dbc7Sjsg
dmub_srv_cmd_execute(struct dmub_srv * dmub)731c349dbc7Sjsg enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
732c349dbc7Sjsg {
7331bb76ff1Sjsg struct dmub_rb flush_rb;
7341bb76ff1Sjsg
735c349dbc7Sjsg if (!dmub->hw_init)
736c349dbc7Sjsg return DMUB_STATUS_INVALID;
737c349dbc7Sjsg
738c349dbc7Sjsg /**
739c349dbc7Sjsg * Read back all the queued commands to ensure that they've
740c349dbc7Sjsg * been flushed to framebuffer memory. Otherwise DMCUB might
741c349dbc7Sjsg * read back stale, fully invalid or partially invalid data.
742c349dbc7Sjsg */
7431bb76ff1Sjsg flush_rb = dmub->inbox1_rb;
7441bb76ff1Sjsg flush_rb.rptr = dmub->inbox1_last_wptr;
7451bb76ff1Sjsg dmub_rb_flush_pending(&flush_rb);
746c349dbc7Sjsg
747c349dbc7Sjsg dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
7481bb76ff1Sjsg
7491bb76ff1Sjsg dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
7501bb76ff1Sjsg
751c349dbc7Sjsg return DMUB_STATUS_OK;
752c349dbc7Sjsg }
753c349dbc7Sjsg
dmub_srv_wait_for_auto_load(struct dmub_srv * dmub,uint32_t timeout_us)754c349dbc7Sjsg enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
755c349dbc7Sjsg uint32_t timeout_us)
756c349dbc7Sjsg {
757c349dbc7Sjsg uint32_t i;
758c349dbc7Sjsg
759c349dbc7Sjsg if (!dmub->hw_init)
760c349dbc7Sjsg return DMUB_STATUS_INVALID;
761c349dbc7Sjsg
762c349dbc7Sjsg for (i = 0; i <= timeout_us; i += 100) {
7635ca02815Sjsg union dmub_fw_boot_status status = dmub->hw_funcs.get_fw_status(dmub);
7645ca02815Sjsg
7655ca02815Sjsg if (status.bits.dal_fw && status.bits.mailbox_rdy)
766c349dbc7Sjsg return DMUB_STATUS_OK;
767c349dbc7Sjsg
768c349dbc7Sjsg udelay(100);
769c349dbc7Sjsg }
770c349dbc7Sjsg
771c349dbc7Sjsg return DMUB_STATUS_TIMEOUT;
772c349dbc7Sjsg }
773c349dbc7Sjsg
dmub_srv_wait_for_idle(struct dmub_srv * dmub,uint32_t timeout_us)774c349dbc7Sjsg enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
775c349dbc7Sjsg uint32_t timeout_us)
776c349dbc7Sjsg {
7771bb76ff1Sjsg uint32_t i, rptr;
778c349dbc7Sjsg
779c349dbc7Sjsg if (!dmub->hw_init)
780c349dbc7Sjsg return DMUB_STATUS_INVALID;
781c349dbc7Sjsg
782c349dbc7Sjsg for (i = 0; i <= timeout_us; ++i) {
7831bb76ff1Sjsg rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
7841bb76ff1Sjsg
7851bb76ff1Sjsg if (rptr > dmub->inbox1_rb.capacity)
7861bb76ff1Sjsg return DMUB_STATUS_HW_FAILURE;
7871bb76ff1Sjsg
7881bb76ff1Sjsg dmub->inbox1_rb.rptr = rptr;
7891bb76ff1Sjsg
790c349dbc7Sjsg if (dmub_rb_empty(&dmub->inbox1_rb))
791c349dbc7Sjsg return DMUB_STATUS_OK;
792c349dbc7Sjsg
793c349dbc7Sjsg udelay(1);
794c349dbc7Sjsg }
795c349dbc7Sjsg
796c349dbc7Sjsg return DMUB_STATUS_TIMEOUT;
797c349dbc7Sjsg }
798c349dbc7Sjsg
799c349dbc7Sjsg enum dmub_status
dmub_srv_send_gpint_command(struct dmub_srv * dmub,enum dmub_gpint_command command_code,uint16_t param,uint32_t timeout_us)800c349dbc7Sjsg dmub_srv_send_gpint_command(struct dmub_srv *dmub,
801c349dbc7Sjsg enum dmub_gpint_command command_code,
802c349dbc7Sjsg uint16_t param, uint32_t timeout_us)
803c349dbc7Sjsg {
804c349dbc7Sjsg union dmub_gpint_data_register reg;
805c349dbc7Sjsg uint32_t i;
806c349dbc7Sjsg
807c349dbc7Sjsg if (!dmub->sw_init)
808c349dbc7Sjsg return DMUB_STATUS_INVALID;
809c349dbc7Sjsg
810c349dbc7Sjsg if (!dmub->hw_funcs.set_gpint)
811c349dbc7Sjsg return DMUB_STATUS_INVALID;
812c349dbc7Sjsg
813c349dbc7Sjsg if (!dmub->hw_funcs.is_gpint_acked)
814c349dbc7Sjsg return DMUB_STATUS_INVALID;
815c349dbc7Sjsg
816c349dbc7Sjsg reg.bits.status = 1;
817c349dbc7Sjsg reg.bits.command_code = command_code;
818c349dbc7Sjsg reg.bits.param = param;
819c349dbc7Sjsg
820c349dbc7Sjsg dmub->hw_funcs.set_gpint(dmub, reg);
821c349dbc7Sjsg
822c349dbc7Sjsg for (i = 0; i < timeout_us; ++i) {
8235ca02815Sjsg udelay(1);
8245ca02815Sjsg
825c349dbc7Sjsg if (dmub->hw_funcs.is_gpint_acked(dmub, reg))
826c349dbc7Sjsg return DMUB_STATUS_OK;
827c349dbc7Sjsg }
828c349dbc7Sjsg
829c349dbc7Sjsg return DMUB_STATUS_TIMEOUT;
830c349dbc7Sjsg }
831c349dbc7Sjsg
dmub_srv_get_gpint_response(struct dmub_srv * dmub,uint32_t * response)832c349dbc7Sjsg enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub,
833c349dbc7Sjsg uint32_t *response)
834c349dbc7Sjsg {
835c349dbc7Sjsg *response = 0;
836c349dbc7Sjsg
837c349dbc7Sjsg if (!dmub->sw_init)
838c349dbc7Sjsg return DMUB_STATUS_INVALID;
839c349dbc7Sjsg
840c349dbc7Sjsg if (!dmub->hw_funcs.get_gpint_response)
841c349dbc7Sjsg return DMUB_STATUS_INVALID;
842c349dbc7Sjsg
843c349dbc7Sjsg *response = dmub->hw_funcs.get_gpint_response(dmub);
844c349dbc7Sjsg
845c349dbc7Sjsg return DMUB_STATUS_OK;
846c349dbc7Sjsg }
8475ca02815Sjsg
dmub_srv_get_gpint_dataout(struct dmub_srv * dmub,uint32_t * dataout)8485ca02815Sjsg enum dmub_status dmub_srv_get_gpint_dataout(struct dmub_srv *dmub,
8495ca02815Sjsg uint32_t *dataout)
8505ca02815Sjsg {
8515ca02815Sjsg *dataout = 0;
8525ca02815Sjsg
8535ca02815Sjsg if (!dmub->sw_init)
8545ca02815Sjsg return DMUB_STATUS_INVALID;
8555ca02815Sjsg
8565ca02815Sjsg if (!dmub->hw_funcs.get_gpint_dataout)
8575ca02815Sjsg return DMUB_STATUS_INVALID;
8585ca02815Sjsg
8595ca02815Sjsg *dataout = dmub->hw_funcs.get_gpint_dataout(dmub);
8605ca02815Sjsg
8615ca02815Sjsg return DMUB_STATUS_OK;
8625ca02815Sjsg }
8635ca02815Sjsg
dmub_srv_get_fw_boot_status(struct dmub_srv * dmub,union dmub_fw_boot_status * status)8645ca02815Sjsg enum dmub_status dmub_srv_get_fw_boot_status(struct dmub_srv *dmub,
8655ca02815Sjsg union dmub_fw_boot_status *status)
8665ca02815Sjsg {
8675ca02815Sjsg status->all = 0;
8685ca02815Sjsg
8695ca02815Sjsg if (!dmub->sw_init)
8705ca02815Sjsg return DMUB_STATUS_INVALID;
8715ca02815Sjsg
8725ca02815Sjsg if (dmub->hw_funcs.get_fw_status)
8735ca02815Sjsg *status = dmub->hw_funcs.get_fw_status(dmub);
8745ca02815Sjsg
8755ca02815Sjsg return DMUB_STATUS_OK;
8765ca02815Sjsg }
8775ca02815Sjsg
dmub_srv_get_fw_boot_option(struct dmub_srv * dmub,union dmub_fw_boot_options * option)878*f005ef32Sjsg enum dmub_status dmub_srv_get_fw_boot_option(struct dmub_srv *dmub,
879*f005ef32Sjsg union dmub_fw_boot_options *option)
880*f005ef32Sjsg {
881*f005ef32Sjsg option->all = 0;
882*f005ef32Sjsg
883*f005ef32Sjsg if (!dmub->sw_init)
884*f005ef32Sjsg return DMUB_STATUS_INVALID;
885*f005ef32Sjsg
886*f005ef32Sjsg if (dmub->hw_funcs.get_fw_boot_option)
887*f005ef32Sjsg *option = dmub->hw_funcs.get_fw_boot_option(dmub);
888*f005ef32Sjsg
889*f005ef32Sjsg return DMUB_STATUS_OK;
890*f005ef32Sjsg }
891*f005ef32Sjsg
dmub_srv_set_skip_panel_power_sequence(struct dmub_srv * dmub,bool skip)892*f005ef32Sjsg enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub,
893*f005ef32Sjsg bool skip)
894*f005ef32Sjsg {
895*f005ef32Sjsg if (!dmub->sw_init)
896*f005ef32Sjsg return DMUB_STATUS_INVALID;
897*f005ef32Sjsg
898*f005ef32Sjsg if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
899*f005ef32Sjsg dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub, skip);
900*f005ef32Sjsg
901*f005ef32Sjsg return DMUB_STATUS_OK;
902*f005ef32Sjsg }
903*f005ef32Sjsg
dmub_srv_cmd_with_reply_data(struct dmub_srv * dmub,union dmub_rb_cmd * cmd)9045ca02815Sjsg enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
9055ca02815Sjsg union dmub_rb_cmd *cmd)
9065ca02815Sjsg {
9075ca02815Sjsg enum dmub_status status = DMUB_STATUS_OK;
9085ca02815Sjsg
9095ca02815Sjsg // Queue command
9105ca02815Sjsg status = dmub_srv_cmd_queue(dmub, cmd);
9115ca02815Sjsg
9125ca02815Sjsg if (status != DMUB_STATUS_OK)
9135ca02815Sjsg return status;
9145ca02815Sjsg
9155ca02815Sjsg // Execute command
9165ca02815Sjsg status = dmub_srv_cmd_execute(dmub);
9175ca02815Sjsg
9185ca02815Sjsg if (status != DMUB_STATUS_OK)
9195ca02815Sjsg return status;
9205ca02815Sjsg
9215ca02815Sjsg // Wait for DMUB to process command
9225ca02815Sjsg status = dmub_srv_wait_for_idle(dmub, 100000);
9235ca02815Sjsg
9245ca02815Sjsg if (status != DMUB_STATUS_OK)
9255ca02815Sjsg return status;
9265ca02815Sjsg
9275ca02815Sjsg // Copy data back from ring buffer into command
9285ca02815Sjsg dmub_rb_get_return_data(&dmub->inbox1_rb, cmd);
9295ca02815Sjsg
9305ca02815Sjsg return status;
9315ca02815Sjsg }
9325ca02815Sjsg
dmub_rb_out_trace_buffer_front(struct dmub_rb * rb,void * entry)9335ca02815Sjsg static inline bool dmub_rb_out_trace_buffer_front(struct dmub_rb *rb,
9345ca02815Sjsg void *entry)
9355ca02815Sjsg {
9365ca02815Sjsg const uint64_t *src = (const uint64_t *)(rb->base_address) + rb->rptr / sizeof(uint64_t);
9375ca02815Sjsg uint64_t *dst = (uint64_t *)entry;
9385ca02815Sjsg uint8_t i;
9395ca02815Sjsg uint8_t loop_count;
9405ca02815Sjsg
9415ca02815Sjsg if (rb->rptr == rb->wrpt)
9425ca02815Sjsg return false;
9435ca02815Sjsg
9445ca02815Sjsg loop_count = sizeof(struct dmcub_trace_buf_entry) / sizeof(uint64_t);
9455ca02815Sjsg // copying data
9465ca02815Sjsg for (i = 0; i < loop_count; i++)
9475ca02815Sjsg *dst++ = *src++;
9485ca02815Sjsg
9495ca02815Sjsg rb->rptr += sizeof(struct dmcub_trace_buf_entry);
9505ca02815Sjsg
9515ca02815Sjsg rb->rptr %= rb->capacity;
9525ca02815Sjsg
9535ca02815Sjsg return true;
9545ca02815Sjsg }
9555ca02815Sjsg
dmub_srv_get_outbox0_msg(struct dmub_srv * dmub,struct dmcub_trace_buf_entry * entry)9565ca02815Sjsg bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry)
9575ca02815Sjsg {
9585ca02815Sjsg dmub->outbox0_rb.wrpt = dmub->hw_funcs.get_outbox0_wptr(dmub);
9595ca02815Sjsg
9605ca02815Sjsg return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry);
9615ca02815Sjsg }
9625ca02815Sjsg
dmub_srv_get_diagnostic_data(struct dmub_srv * dmub,struct dmub_diagnostic_data * diag_data)9635ca02815Sjsg bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
9645ca02815Sjsg {
9655ca02815Sjsg if (!dmub || !dmub->hw_funcs.get_diagnostic_data || !diag_data)
9665ca02815Sjsg return false;
9675ca02815Sjsg dmub->hw_funcs.get_diagnostic_data(dmub, diag_data);
9685ca02815Sjsg return true;
9695ca02815Sjsg }
9701bb76ff1Sjsg
dmub_srv_should_detect(struct dmub_srv * dmub)9711bb76ff1Sjsg bool dmub_srv_should_detect(struct dmub_srv *dmub)
9721bb76ff1Sjsg {
9731bb76ff1Sjsg if (!dmub->hw_init || !dmub->hw_funcs.should_detect)
9741bb76ff1Sjsg return false;
9751bb76ff1Sjsg
9761bb76ff1Sjsg return dmub->hw_funcs.should_detect(dmub);
9771bb76ff1Sjsg }
9781bb76ff1Sjsg
dmub_srv_clear_inbox0_ack(struct dmub_srv * dmub)9791bb76ff1Sjsg enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub)
9801bb76ff1Sjsg {
9811bb76ff1Sjsg if (!dmub->hw_init || !dmub->hw_funcs.clear_inbox0_ack_register)
9821bb76ff1Sjsg return DMUB_STATUS_INVALID;
9831bb76ff1Sjsg
9841bb76ff1Sjsg dmub->hw_funcs.clear_inbox0_ack_register(dmub);
9851bb76ff1Sjsg return DMUB_STATUS_OK;
9861bb76ff1Sjsg }
9871bb76ff1Sjsg
dmub_srv_wait_for_inbox0_ack(struct dmub_srv * dmub,uint32_t timeout_us)9881bb76ff1Sjsg enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t timeout_us)
9891bb76ff1Sjsg {
9901bb76ff1Sjsg uint32_t i = 0;
9911bb76ff1Sjsg uint32_t ack = 0;
9921bb76ff1Sjsg
9931bb76ff1Sjsg if (!dmub->hw_init || !dmub->hw_funcs.read_inbox0_ack_register)
9941bb76ff1Sjsg return DMUB_STATUS_INVALID;
9951bb76ff1Sjsg
9961bb76ff1Sjsg for (i = 0; i <= timeout_us; i++) {
9971bb76ff1Sjsg ack = dmub->hw_funcs.read_inbox0_ack_register(dmub);
9981bb76ff1Sjsg if (ack)
9991bb76ff1Sjsg return DMUB_STATUS_OK;
100022b9dc14Sjsg udelay(1);
10011bb76ff1Sjsg }
10021bb76ff1Sjsg return DMUB_STATUS_TIMEOUT;
10031bb76ff1Sjsg }
10041bb76ff1Sjsg
dmub_srv_send_inbox0_cmd(struct dmub_srv * dmub,union dmub_inbox0_data_register data)10051bb76ff1Sjsg enum dmub_status dmub_srv_send_inbox0_cmd(struct dmub_srv *dmub,
10061bb76ff1Sjsg union dmub_inbox0_data_register data)
10071bb76ff1Sjsg {
10081bb76ff1Sjsg if (!dmub->hw_init || !dmub->hw_funcs.send_inbox0_cmd)
10091bb76ff1Sjsg return DMUB_STATUS_INVALID;
10101bb76ff1Sjsg
10111bb76ff1Sjsg dmub->hw_funcs.send_inbox0_cmd(dmub, data);
10121bb76ff1Sjsg return DMUB_STATUS_OK;
10131bb76ff1Sjsg }
1014