1/*
2 * Copyright 2018 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 */
23
24#include "smumgr.h"
25#include "smu9_smumgr.h"
26#include "vega10_inc.h"
27#include "soc15_common.h"
28#include "pp_debug.h"
29
30
31/* MP Apertures */
32#define MP0_Public                  0x03800000
33#define MP0_SRAM                    0x03900000
34#define MP1_Public                  0x03b00000
35#define MP1_SRAM                    0x03c00004
36
37#define smnMP1_FIRMWARE_FLAGS                                                                           0x3010028
38
39bool smu9_is_smc_ram_running(struct pp_hwmgr *hwmgr)
40{
41	struct amdgpu_device *adev = hwmgr->adev;
42	uint32_t mp1_fw_flags;
43
44	mp1_fw_flags = RREG32_PCIE(MP1_Public |
45				   (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
46
47	if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK)
48		return true;
49
50	return false;
51}
52
53/*
54 * Check if SMC has responded to previous message.
55 *
56 * @param    smumgr  the address of the powerplay hardware manager.
57 * @return   TRUE    SMC has responded, FALSE otherwise.
58 */
59static uint32_t smu9_wait_for_response(struct pp_hwmgr *hwmgr)
60{
61	struct amdgpu_device *adev = hwmgr->adev;
62	uint32_t reg;
63	uint32_t ret;
64
65	if (hwmgr->pp_one_vf) {
66		reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_103);
67
68		ret = phm_wait_for_register_unequal(hwmgr, reg,
69				0, MP1_C2PMSG_103__CONTENT_MASK);
70
71		if (ret)
72			pr_err("No response from smu\n");
73
74		return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103);
75	} else {
76		reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
77
78		ret = phm_wait_for_register_unequal(hwmgr, reg,
79				0, MP1_C2PMSG_90__CONTENT_MASK);
80
81		if (ret)
82			pr_err("No response from smu\n");
83		return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
84	}
85}
86
87/*
88 * Send a message to the SMC, and do not wait for its response.
89 * @param    smumgr  the address of the powerplay hardware manager.
90 * @param    msg the message to send.
91 * @return   Always return 0.
92 */
93static int smu9_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr,
94						uint16_t msg)
95{
96	struct amdgpu_device *adev = hwmgr->adev;
97
98	if (hwmgr->pp_one_vf) {
99		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_101, msg);
100	} else {
101		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg);
102	}
103
104	return 0;
105}
106
107/*
108 * Send a message to the SMC, and wait for its response.
109 * @param    hwmgr  the address of the powerplay hardware manager.
110 * @param    msg the message to send.
111 * @return   Always return 0.
112 */
113int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
114{
115	struct amdgpu_device *adev = hwmgr->adev;
116	uint32_t ret;
117
118	smu9_wait_for_response(hwmgr);
119
120	if (hwmgr->pp_one_vf)
121		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0);
122	else
123		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
124
125	smu9_send_msg_to_smc_without_waiting(hwmgr, msg);
126
127	ret = smu9_wait_for_response(hwmgr);
128	if (ret != 1)
129		dev_err(adev->dev, "Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret);
130
131	return 0;
132}
133
134/*
135 * Send a message to the SMC with parameter
136 * @param    hwmgr:  the address of the powerplay hardware manager.
137 * @param    msg: the message to send.
138 * @param    parameter: the parameter to send
139 * @return   Always return 0.
140 */
141int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
142					uint16_t msg, uint32_t parameter)
143{
144	struct amdgpu_device *adev = hwmgr->adev;
145	uint32_t ret;
146
147	smu9_wait_for_response(hwmgr);
148
149	if (hwmgr->pp_one_vf) {
150		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0);
151		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102, parameter);
152	} else {
153		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
154		WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter);
155	}
156
157	smu9_send_msg_to_smc_without_waiting(hwmgr, msg);
158
159	ret = smu9_wait_for_response(hwmgr);
160	if (ret != 1)
161		pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret);
162
163	return 0;
164}
165
166uint32_t smu9_get_argument(struct pp_hwmgr *hwmgr)
167{
168	struct amdgpu_device *adev = hwmgr->adev;
169
170	if (hwmgr->pp_one_vf)
171		return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102);
172	else
173		return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82);
174}
175