iceland_smumgr.c 6.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright 2016 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Author: Huang Rui <ray.huang@amd.com>
 *
 */
25
#include "pp_debug.h"
26 27 28 29 30 31 32 33 34 35 36 37
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/gfp.h>

#include "smumgr.h"
#include "iceland_smumgr.h"
#include "smu_ucode_xfer_vi.h"
#include "ppsmc.h"
#include "smu/smu_7_1_1_d.h"
#include "smu/smu_7_1_1_sh_mask.h"
#include "cgs_common.h"
38
#include "iceland_smc.h"
39

40
#define ICELAND_SMC_SIZE               0x20000
41

42
static int iceland_start_smc(struct pp_hwmgr *hwmgr)
43
{
44
	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
45 46 47 48 49
				  SMC_SYSCON_RESET_CNTL, rst_reg, 0);

	return 0;
}

50
static void iceland_reset_smc(struct pp_hwmgr *hwmgr)
51
{
52
	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
53 54 55 56 57
				  SMC_SYSCON_RESET_CNTL,
				  rst_reg, 1);
}


58
static void iceland_stop_smc_clock(struct pp_hwmgr *hwmgr)
59
{
60
	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
61 62 63 64
				  SMC_SYSCON_CLOCK_CNTL_0,
				  ck_disable, 1);
}

65
static void iceland_start_smc_clock(struct pp_hwmgr *hwmgr)
66
{
67
	PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
68 69 70 71
				  SMC_SYSCON_CLOCK_CNTL_0,
				  ck_disable, 0);
}

72
static int iceland_smu_start_smc(struct pp_hwmgr *hwmgr)
73 74
{
	/* set smc instruct start point at 0x0 */
75
	smu7_program_jump_on_start(hwmgr);
76 77

	/* enable smc clock */
78
	iceland_start_smc_clock(hwmgr);
79 80

	/* de-assert reset */
81
	iceland_start_smc(hwmgr);
82

83
	PHM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, FIRMWARE_FLAGS,
84 85 86 87 88
				 INTERRUPTS_ENABLED, 1);

	return 0;
}

89

90
static int iceland_upload_smc_firmware_data(struct pp_hwmgr *hwmgr,
91 92
					uint32_t length, const uint8_t *src,
					uint32_t limit, uint32_t start_addr)
93
{
94
	uint32_t byte_count = length;
95
	uint32_t data;
96 97 98

	PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);

99
	cgs_write_register(hwmgr->device, mmSMC_IND_INDEX_0, start_addr);
100
	PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
101 102 103

	while (byte_count >= 4) {
		data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
104
		cgs_write_register(hwmgr->device, mmSMC_IND_DATA_0, data);
105 106 107 108
		src += 4;
		byte_count -= 4;
	}

109
	PHM_WRITE_FIELD(hwmgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
110

111
	PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be divisible by 4.", return -EINVAL);
112 113 114 115 116

	return 0;
}


117
static int iceland_smu_upload_firmware_image(struct pp_hwmgr *hwmgr)
118 119
{
	uint32_t val;
120 121
	struct cgs_firmware_info info = {0};

122
	if (hwmgr == NULL || hwmgr->device == NULL)
123 124 125
		return -EINVAL;

	/* load SMC firmware */
126
	cgs_get_firmware_info(hwmgr->device,
127
		smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
128 129 130 131 132 133 134 135 136 137 138 139

	if (info.image_size & 3) {
		pr_err("[ powerplay ] SMC ucode is not 4 bytes aligned\n");
		return -EINVAL;
	}

	if (info.image_size > ICELAND_SMC_SIZE) {
		pr_err("[ powerplay ] SMC address is beyond the SMC RAM area\n");
		return -EINVAL;
	}

	/* wait for smc boot up */
140
	PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
141 142 143
					 RCU_UC_EVENTS, boot_seq_done, 0);

	/* clear firmware interrupt enable flag */
144
	val = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
145
				    ixSMC_SYSCON_MISC_CNTL);
146
	cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
147 148 149
			       ixSMC_SYSCON_MISC_CNTL, val | 1);

	/* stop smc clock */
150
	iceland_stop_smc_clock(hwmgr);
151 152

	/* reset smc */
153 154
	iceland_reset_smc(hwmgr);
	iceland_upload_smc_firmware_data(hwmgr, info.image_size,
155 156
				(uint8_t *)info.kptr, ICELAND_SMC_SIZE,
				info.ucode_start_address);
157 158 159 160

	return 0;
}

161
static int iceland_request_smu_load_specific_fw(struct pp_hwmgr *hwmgr,
162 163 164 165 166
						uint32_t firmwareType)
{
	return 0;
}

167
static int iceland_start_smu(struct pp_hwmgr *hwmgr)
168 169 170
{
	int result;

171
	result = iceland_smu_upload_firmware_image(hwmgr);
172 173
	if (result)
		return result;
174
	result = iceland_smu_start_smc(hwmgr);
175 176 177
	if (result)
		return result;

178
	if (!smu7_is_smc_ram_running(hwmgr)) {
179
		pr_info("smu not running, upload firmware again \n");
180
		result = iceland_smu_upload_firmware_image(hwmgr);
181 182 183
		if (result)
			return result;

184
		result = iceland_smu_start_smc(hwmgr);
185 186 187 188
		if (result)
			return result;
	}

189
	result = smu7_request_smu_load_fw(hwmgr);
190 191 192 193 194 195 196 197 198 199 200

	return result;
}

/**
 * Write a 32bit value to the SMC SRAM space.
 * ALL PARAMETERS ARE IN HOST BYTE ORDER.
 * @param    smumgr  the address of the powerplay hardware manager.
 * @param    smcAddress the address in the SMC RAM to access.
 * @param    value to write to the SMC SRAM.
 */
201
static int iceland_smu_init(struct pp_hwmgr *hwmgr)
202
{
203
	int i;
R
Rex Zhu 已提交
204 205 206 207 208 209 210
	struct iceland_smumgr *iceland_priv = NULL;

	iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);

	if (iceland_priv == NULL)
		return -ENOMEM;

211
	hwmgr->smu_backend = iceland_priv;
R
Rex Zhu 已提交
212

213
	if (smu7_init(hwmgr))
214 215 216
		return -EINVAL;

	for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
R
Rex Zhu 已提交
217
		iceland_priv->activity_target[i] = 30;
218 219

	return 0;
220 221
}

R
Rex Zhu 已提交
222
const struct pp_smumgr_func iceland_smu_funcs = {
223
	.smu_init = &iceland_smu_init,
224
	.smu_fini = &smu7_smu_fini,
225
	.start_smu = &iceland_start_smu,
226 227
	.check_fw_load_finish = &smu7_check_fw_load_finish,
	.request_smu_load_fw = &smu7_reload_firmware,
228
	.request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw,
229 230
	.send_msg_to_smc = &smu7_send_msg_to_smc,
	.send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
231 232
	.download_pptable_settings = NULL,
	.upload_pptable_settings = NULL,
233 234 235 236 237 238 239 240 241 242
	.get_offsetof = iceland_get_offsetof,
	.process_firmware_header = iceland_process_firmware_header,
	.init_smc_table = iceland_init_smc_table,
	.update_sclk_threshold = iceland_update_sclk_threshold,
	.thermal_setup_fan_table = iceland_thermal_setup_fan_table,
	.populate_all_graphic_levels = iceland_populate_all_graphic_levels,
	.populate_all_memory_levels = iceland_populate_all_memory_levels,
	.get_mac_definition = iceland_get_mac_definition,
	.initialize_mc_reg_table = iceland_initialize_mc_reg_table,
	.is_dpm_running = iceland_is_dpm_running,
243 244
};