diff options
author | Rex Zhu <Rex.Zhu@amd.com> | 2016-09-19 03:44:50 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2016-09-22 10:24:20 -0400 |
commit | 9487dd1548d600161485ee5528cec36ccff96edd (patch) | |
tree | fa82f7a168eeb680c2fabf3ff1558c5487e55156 | |
parent | a8ca34136453b5a570b514e466f8b0b9efd71df2 (diff) |
drm/amdgpu: use powerplay module for dgpu in Vi.
delete non-pp code and files. It was just a temporary
solution and not support dynamic power management.
Signed-off-by: Rex Zhu <Rex.Zhu@amd.com>
Acked-by: Edward O'Callaghan <funfunctor@folklore1984.net>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/Makefile | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/fiji_dpm.c | 186 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/fiji_smc.c | 863 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/fiji_smum.h | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/iceland_dpm.c | 200 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/iceland_smc.c | 677 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/iceland_smum.h | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/tonga_dpm.c | 186 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/tonga_smc.c | 862 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/tonga_smum.h | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/vi.c | 3 |
12 files changed, 6 insertions, 3114 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index dc6df075bafc..d15e9b080ce1 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile | |||
@@ -52,10 +52,7 @@ amdgpu-y += \ | |||
52 | amdgpu-y += \ | 52 | amdgpu-y += \ |
53 | amdgpu_dpm.o \ | 53 | amdgpu_dpm.o \ |
54 | amdgpu_powerplay.o \ | 54 | amdgpu_powerplay.o \ |
55 | cz_smc.o cz_dpm.o \ | 55 | cz_smc.o cz_dpm.o |
56 | tonga_smc.o tonga_dpm.o \ | ||
57 | fiji_smc.o fiji_dpm.o \ | ||
58 | iceland_smc.o iceland_dpm.o | ||
59 | 56 | ||
60 | # add DCE block | 57 | # add DCE block |
61 | amdgpu-y += \ | 58 | amdgpu-y += \ |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index 1e7f160f23d8..68ad24101a36 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | |||
@@ -80,15 +80,6 @@ static int amdgpu_powerplay_init(struct amdgpu_device *adev) | |||
80 | amd_pp->ip_funcs = &kv_dpm_ip_funcs; | 80 | amd_pp->ip_funcs = &kv_dpm_ip_funcs; |
81 | break; | 81 | break; |
82 | #endif | 82 | #endif |
83 | case CHIP_TOPAZ: | ||
84 | amd_pp->ip_funcs = &iceland_dpm_ip_funcs; | ||
85 | break; | ||
86 | case CHIP_TONGA: | ||
87 | amd_pp->ip_funcs = &tonga_dpm_ip_funcs; | ||
88 | break; | ||
89 | case CHIP_FIJI: | ||
90 | amd_pp->ip_funcs = &fiji_dpm_ip_funcs; | ||
91 | break; | ||
92 | case CHIP_CARRIZO: | 83 | case CHIP_CARRIZO: |
93 | case CHIP_STONEY: | 84 | case CHIP_STONEY: |
94 | amd_pp->ip_funcs = &cz_dpm_ip_funcs; | 85 | amd_pp->ip_funcs = &cz_dpm_ip_funcs; |
@@ -110,11 +101,11 @@ static int amdgpu_pp_early_init(void *handle) | |||
110 | switch (adev->asic_type) { | 101 | switch (adev->asic_type) { |
111 | case CHIP_POLARIS11: | 102 | case CHIP_POLARIS11: |
112 | case CHIP_POLARIS10: | 103 | case CHIP_POLARIS10: |
113 | adev->pp_enabled = true; | ||
114 | break; | ||
115 | case CHIP_TONGA: | 104 | case CHIP_TONGA: |
116 | case CHIP_FIJI: | 105 | case CHIP_FIJI: |
117 | case CHIP_TOPAZ: | 106 | case CHIP_TOPAZ: |
107 | adev->pp_enabled = true; | ||
108 | break; | ||
118 | case CHIP_CARRIZO: | 109 | case CHIP_CARRIZO: |
119 | case CHIP_STONEY: | 110 | case CHIP_STONEY: |
120 | adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true; | 111 | adev->pp_enabled = (amdgpu_powerplay == 0) ? false : true; |
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c b/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c deleted file mode 100644 index ed03b75175d4..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/fiji_dpm.c +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "fiji_smum.h" | ||
28 | |||
29 | MODULE_FIRMWARE("amdgpu/fiji_smc.bin"); | ||
30 | |||
31 | static void fiji_dpm_set_funcs(struct amdgpu_device *adev); | ||
32 | |||
33 | static int fiji_dpm_early_init(void *handle) | ||
34 | { | ||
35 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
36 | |||
37 | fiji_dpm_set_funcs(adev); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int fiji_dpm_init_microcode(struct amdgpu_device *adev) | ||
43 | { | ||
44 | char fw_name[30] = "amdgpu/fiji_smc.bin"; | ||
45 | int err; | ||
46 | |||
47 | err = request_firmware(&adev->pm.fw, fw_name, adev->dev); | ||
48 | if (err) | ||
49 | goto out; | ||
50 | err = amdgpu_ucode_validate(adev->pm.fw); | ||
51 | |||
52 | out: | ||
53 | if (err) { | ||
54 | DRM_ERROR("Failed to load firmware \"%s\"", fw_name); | ||
55 | release_firmware(adev->pm.fw); | ||
56 | adev->pm.fw = NULL; | ||
57 | } | ||
58 | return err; | ||
59 | } | ||
60 | |||
61 | static int fiji_dpm_sw_init(void *handle) | ||
62 | { | ||
63 | int ret; | ||
64 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
65 | |||
66 | ret = fiji_dpm_init_microcode(adev); | ||
67 | if (ret) | ||
68 | return ret; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int fiji_dpm_sw_fini(void *handle) | ||
74 | { | ||
75 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
76 | |||
77 | release_firmware(adev->pm.fw); | ||
78 | adev->pm.fw = NULL; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int fiji_dpm_hw_init(void *handle) | ||
84 | { | ||
85 | int ret; | ||
86 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
87 | |||
88 | mutex_lock(&adev->pm.mutex); | ||
89 | |||
90 | ret = fiji_smu_init(adev); | ||
91 | if (ret) { | ||
92 | DRM_ERROR("SMU initialization failed\n"); | ||
93 | goto fail; | ||
94 | } | ||
95 | |||
96 | ret = fiji_smu_start(adev); | ||
97 | if (ret) { | ||
98 | DRM_ERROR("SMU start failed\n"); | ||
99 | goto fail; | ||
100 | } | ||
101 | |||
102 | mutex_unlock(&adev->pm.mutex); | ||
103 | return 0; | ||
104 | |||
105 | fail: | ||
106 | adev->firmware.smu_load = false; | ||
107 | mutex_unlock(&adev->pm.mutex); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | static int fiji_dpm_hw_fini(void *handle) | ||
112 | { | ||
113 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
114 | mutex_lock(&adev->pm.mutex); | ||
115 | fiji_smu_fini(adev); | ||
116 | mutex_unlock(&adev->pm.mutex); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int fiji_dpm_suspend(void *handle) | ||
121 | { | ||
122 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
123 | |||
124 | fiji_dpm_hw_fini(adev); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int fiji_dpm_resume(void *handle) | ||
130 | { | ||
131 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
132 | |||
133 | fiji_dpm_hw_init(adev); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int fiji_dpm_set_clockgating_state(void *handle, | ||
139 | enum amd_clockgating_state state) | ||
140 | { | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int fiji_dpm_set_powergating_state(void *handle, | ||
145 | enum amd_powergating_state state) | ||
146 | { | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | const struct amd_ip_funcs fiji_dpm_ip_funcs = { | ||
151 | .name = "fiji_dpm", | ||
152 | .early_init = fiji_dpm_early_init, | ||
153 | .late_init = NULL, | ||
154 | .sw_init = fiji_dpm_sw_init, | ||
155 | .sw_fini = fiji_dpm_sw_fini, | ||
156 | .hw_init = fiji_dpm_hw_init, | ||
157 | .hw_fini = fiji_dpm_hw_fini, | ||
158 | .suspend = fiji_dpm_suspend, | ||
159 | .resume = fiji_dpm_resume, | ||
160 | .is_idle = NULL, | ||
161 | .wait_for_idle = NULL, | ||
162 | .soft_reset = NULL, | ||
163 | .set_clockgating_state = fiji_dpm_set_clockgating_state, | ||
164 | .set_powergating_state = fiji_dpm_set_powergating_state, | ||
165 | }; | ||
166 | |||
167 | static const struct amdgpu_dpm_funcs fiji_dpm_funcs = { | ||
168 | .get_temperature = NULL, | ||
169 | .pre_set_power_state = NULL, | ||
170 | .set_power_state = NULL, | ||
171 | .post_set_power_state = NULL, | ||
172 | .display_configuration_changed = NULL, | ||
173 | .get_sclk = NULL, | ||
174 | .get_mclk = NULL, | ||
175 | .print_power_state = NULL, | ||
176 | .debugfs_print_current_performance_level = NULL, | ||
177 | .force_performance_level = NULL, | ||
178 | .vblank_too_short = NULL, | ||
179 | .powergate_uvd = NULL, | ||
180 | }; | ||
181 | |||
182 | static void fiji_dpm_set_funcs(struct amdgpu_device *adev) | ||
183 | { | ||
184 | if (NULL == adev->pm.funcs) | ||
185 | adev->pm.funcs = &fiji_dpm_funcs; | ||
186 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c deleted file mode 100644 index 8cfb0a3cf725..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c +++ /dev/null | |||
@@ -1,863 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "fiji_ppsmc.h" | ||
28 | #include "fiji_smum.h" | ||
29 | #include "smu_ucode_xfer_vi.h" | ||
30 | #include "amdgpu_ucode.h" | ||
31 | |||
32 | #include "smu/smu_7_1_3_d.h" | ||
33 | #include "smu/smu_7_1_3_sh_mask.h" | ||
34 | |||
35 | #define FIJI_SMC_SIZE 0x20000 | ||
36 | |||
37 | static int fiji_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit) | ||
38 | { | ||
39 | uint32_t val; | ||
40 | |||
41 | if (smc_address & 3) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if ((smc_address + 3) > limit) | ||
45 | return -EINVAL; | ||
46 | |||
47 | WREG32(mmSMC_IND_INDEX_0, smc_address); | ||
48 | |||
49 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
50 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
51 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int fiji_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit) | ||
57 | { | ||
58 | uint32_t addr; | ||
59 | uint32_t data, orig_data; | ||
60 | int result = 0; | ||
61 | uint32_t extra_shift; | ||
62 | unsigned long flags; | ||
63 | |||
64 | if (smc_start_address & 3) | ||
65 | return -EINVAL; | ||
66 | |||
67 | if ((smc_start_address + byte_count) > limit) | ||
68 | return -EINVAL; | ||
69 | |||
70 | addr = smc_start_address; | ||
71 | |||
72 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
73 | while (byte_count >= 4) { | ||
74 | /* Bytes are written into the SMC addres space with the MSB first */ | ||
75 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
76 | |||
77 | result = fiji_set_smc_sram_address(adev, addr, limit); | ||
78 | |||
79 | if (result) | ||
80 | goto out; | ||
81 | |||
82 | WREG32(mmSMC_IND_DATA_0, data); | ||
83 | |||
84 | src += 4; | ||
85 | byte_count -= 4; | ||
86 | addr += 4; | ||
87 | } | ||
88 | |||
89 | if (0 != byte_count) { | ||
90 | /* Now write odd bytes left, do a read modify write cycle */ | ||
91 | data = 0; | ||
92 | |||
93 | result = fiji_set_smc_sram_address(adev, addr, limit); | ||
94 | if (result) | ||
95 | goto out; | ||
96 | |||
97 | orig_data = RREG32(mmSMC_IND_DATA_0); | ||
98 | extra_shift = 8 * (4 - byte_count); | ||
99 | |||
100 | while (byte_count > 0) { | ||
101 | data = (data << 8) + *src++; | ||
102 | byte_count--; | ||
103 | } | ||
104 | |||
105 | data <<= extra_shift; | ||
106 | data |= (orig_data & ~((~0UL) << extra_shift)); | ||
107 | |||
108 | result = fiji_set_smc_sram_address(adev, addr, limit); | ||
109 | if (result) | ||
110 | goto out; | ||
111 | |||
112 | WREG32(mmSMC_IND_DATA_0, data); | ||
113 | } | ||
114 | |||
115 | out: | ||
116 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
117 | return result; | ||
118 | } | ||
119 | |||
120 | static int fiji_program_jump_on_start(struct amdgpu_device *adev) | ||
121 | { | ||
122 | static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40}; | ||
123 | fiji_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static bool fiji_is_smc_ram_running(struct amdgpu_device *adev) | ||
129 | { | ||
130 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
131 | val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable); | ||
132 | |||
133 | return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C))); | ||
134 | } | ||
135 | |||
136 | static int wait_smu_response(struct amdgpu_device *adev) | ||
137 | { | ||
138 | int i; | ||
139 | uint32_t val; | ||
140 | |||
141 | for (i = 0; i < adev->usec_timeout; i++) { | ||
142 | val = RREG32(mmSMC_RESP_0); | ||
143 | if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP)) | ||
144 | break; | ||
145 | udelay(1); | ||
146 | } | ||
147 | |||
148 | if (i == adev->usec_timeout) | ||
149 | return -EINVAL; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int fiji_send_msg_to_smc_offset(struct amdgpu_device *adev) | ||
155 | { | ||
156 | if (wait_smu_response(adev)) { | ||
157 | DRM_ERROR("Failed to send previous message\n"); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | WREG32(mmSMC_MSG_ARG_0, 0x20000); | ||
162 | WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test); | ||
163 | |||
164 | if (wait_smu_response(adev)) { | ||
165 | DRM_ERROR("Failed to send message\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int fiji_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg) | ||
173 | { | ||
174 | if (!fiji_is_smc_ram_running(adev)) | ||
175 | { | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | if (wait_smu_response(adev)) { | ||
180 | DRM_ERROR("Failed to send previous message\n"); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | WREG32(mmSMC_MESSAGE_0, msg); | ||
185 | |||
186 | if (wait_smu_response(adev)) { | ||
187 | DRM_ERROR("Failed to send message\n"); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int fiji_send_msg_to_smc_without_waiting(struct amdgpu_device *adev, | ||
195 | PPSMC_Msg msg) | ||
196 | { | ||
197 | if (wait_smu_response(adev)) { | ||
198 | DRM_ERROR("Failed to send previous message\n"); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | WREG32(mmSMC_MESSAGE_0, msg); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int fiji_send_msg_to_smc_with_parameter(struct amdgpu_device *adev, | ||
208 | PPSMC_Msg msg, | ||
209 | uint32_t parameter) | ||
210 | { | ||
211 | if (!fiji_is_smc_ram_running(adev)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | if (wait_smu_response(adev)) { | ||
215 | DRM_ERROR("Failed to send previous message\n"); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
220 | |||
221 | return fiji_send_msg_to_smc(adev, msg); | ||
222 | } | ||
223 | |||
224 | static int fiji_send_msg_to_smc_with_parameter_without_waiting( | ||
225 | struct amdgpu_device *adev, | ||
226 | PPSMC_Msg msg, uint32_t parameter) | ||
227 | { | ||
228 | if (wait_smu_response(adev)) { | ||
229 | DRM_ERROR("Failed to send previous message\n"); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
234 | |||
235 | return fiji_send_msg_to_smc_without_waiting(adev, msg); | ||
236 | } | ||
237 | |||
238 | #if 0 /* not used yet */ | ||
239 | static int fiji_wait_for_smc_inactive(struct amdgpu_device *adev) | ||
240 | { | ||
241 | int i; | ||
242 | uint32_t val; | ||
243 | |||
244 | if (!fiji_is_smc_ram_running(adev)) | ||
245 | return -EINVAL; | ||
246 | |||
247 | for (i = 0; i < adev->usec_timeout; i++) { | ||
248 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
249 | if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0) | ||
250 | break; | ||
251 | udelay(1); | ||
252 | } | ||
253 | |||
254 | if (i == adev->usec_timeout) | ||
255 | return -EINVAL; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | static int fiji_smu_upload_firmware_image(struct amdgpu_device *adev) | ||
262 | { | ||
263 | const struct smc_firmware_header_v1_0 *hdr; | ||
264 | uint32_t ucode_size; | ||
265 | uint32_t ucode_start_address; | ||
266 | const uint8_t *src; | ||
267 | uint32_t val; | ||
268 | uint32_t byte_count; | ||
269 | uint32_t *data; | ||
270 | unsigned long flags; | ||
271 | |||
272 | if (!adev->pm.fw) | ||
273 | return -EINVAL; | ||
274 | |||
275 | /* Skip SMC ucode loading on SR-IOV capable boards. | ||
276 | * vbios does this for us in asic_init in that case. | ||
277 | */ | ||
278 | if (amdgpu_sriov_bios(adev)) | ||
279 | return 0; | ||
280 | |||
281 | hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data; | ||
282 | amdgpu_ucode_print_smc_hdr(&hdr->header); | ||
283 | |||
284 | adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); | ||
285 | ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); | ||
286 | ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); | ||
287 | src = (const uint8_t *) | ||
288 | (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); | ||
289 | |||
290 | if (ucode_size & 3) { | ||
291 | DRM_ERROR("SMC ucode is not 4 bytes aligned\n"); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | if (ucode_size > FIJI_SMC_SIZE) { | ||
296 | DRM_ERROR("SMC address is beyond the SMC RAM area\n"); | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
301 | WREG32(mmSMC_IND_INDEX_0, ucode_start_address); | ||
302 | |||
303 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
304 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | ||
305 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
306 | |||
307 | byte_count = ucode_size; | ||
308 | data = (uint32_t *)src; | ||
309 | for (; byte_count >= 4; data++, byte_count -= 4) | ||
310 | WREG32(mmSMC_IND_DATA_0, data[0]); | ||
311 | |||
312 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
313 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
314 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
315 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | #if 0 /* not used yet */ | ||
321 | static int fiji_read_smc_sram_dword(struct amdgpu_device *adev, | ||
322 | uint32_t smc_address, | ||
323 | uint32_t *value, | ||
324 | uint32_t limit) | ||
325 | { | ||
326 | int result; | ||
327 | unsigned long flags; | ||
328 | |||
329 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
330 | result = fiji_set_smc_sram_address(adev, smc_address, limit); | ||
331 | if (result == 0) | ||
332 | *value = RREG32(mmSMC_IND_DATA_0); | ||
333 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
334 | return result; | ||
335 | } | ||
336 | |||
337 | static int fiji_write_smc_sram_dword(struct amdgpu_device *adev, | ||
338 | uint32_t smc_address, | ||
339 | uint32_t value, | ||
340 | uint32_t limit) | ||
341 | { | ||
342 | int result; | ||
343 | unsigned long flags; | ||
344 | |||
345 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
346 | result = fiji_set_smc_sram_address(adev, smc_address, limit); | ||
347 | if (result == 0) | ||
348 | WREG32(mmSMC_IND_DATA_0, value); | ||
349 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
350 | return result; | ||
351 | } | ||
352 | |||
353 | static int fiji_smu_stop_smc(struct amdgpu_device *adev) | ||
354 | { | ||
355 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
356 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
357 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
358 | |||
359 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
360 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1); | ||
361 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | #endif | ||
366 | |||
367 | static enum AMDGPU_UCODE_ID fiji_convert_fw_type(uint32_t fw_type) | ||
368 | { | ||
369 | switch (fw_type) { | ||
370 | case UCODE_ID_SDMA0: | ||
371 | return AMDGPU_UCODE_ID_SDMA0; | ||
372 | case UCODE_ID_SDMA1: | ||
373 | return AMDGPU_UCODE_ID_SDMA1; | ||
374 | case UCODE_ID_CP_CE: | ||
375 | return AMDGPU_UCODE_ID_CP_CE; | ||
376 | case UCODE_ID_CP_PFP: | ||
377 | return AMDGPU_UCODE_ID_CP_PFP; | ||
378 | case UCODE_ID_CP_ME: | ||
379 | return AMDGPU_UCODE_ID_CP_ME; | ||
380 | case UCODE_ID_CP_MEC: | ||
381 | case UCODE_ID_CP_MEC_JT1: | ||
382 | case UCODE_ID_CP_MEC_JT2: | ||
383 | return AMDGPU_UCODE_ID_CP_MEC1; | ||
384 | case UCODE_ID_RLC_G: | ||
385 | return AMDGPU_UCODE_ID_RLC_G; | ||
386 | default: | ||
387 | DRM_ERROR("ucode type is out of range!\n"); | ||
388 | return AMDGPU_UCODE_ID_MAXIMUM; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static int fiji_smu_populate_single_firmware_entry(struct amdgpu_device *adev, | ||
393 | uint32_t fw_type, | ||
394 | struct SMU_Entry *entry) | ||
395 | { | ||
396 | enum AMDGPU_UCODE_ID id = fiji_convert_fw_type(fw_type); | ||
397 | struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id]; | ||
398 | const struct gfx_firmware_header_v1_0 *header = NULL; | ||
399 | uint64_t gpu_addr; | ||
400 | uint32_t data_size; | ||
401 | |||
402 | if (ucode->fw == NULL) | ||
403 | return -EINVAL; | ||
404 | gpu_addr = ucode->mc_addr; | ||
405 | header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; | ||
406 | data_size = le32_to_cpu(header->header.ucode_size_bytes); | ||
407 | |||
408 | if ((fw_type == UCODE_ID_CP_MEC_JT1) || | ||
409 | (fw_type == UCODE_ID_CP_MEC_JT2)) { | ||
410 | gpu_addr += le32_to_cpu(header->jt_offset) << 2; | ||
411 | data_size = le32_to_cpu(header->jt_size) << 2; | ||
412 | } | ||
413 | |||
414 | entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version); | ||
415 | entry->id = (uint16_t)fw_type; | ||
416 | entry->image_addr_high = upper_32_bits(gpu_addr); | ||
417 | entry->image_addr_low = lower_32_bits(gpu_addr); | ||
418 | entry->meta_data_addr_high = 0; | ||
419 | entry->meta_data_addr_low = 0; | ||
420 | entry->data_size_byte = data_size; | ||
421 | entry->num_register_entries = 0; | ||
422 | |||
423 | if (fw_type == UCODE_ID_RLC_G) | ||
424 | entry->flags = 1; | ||
425 | else | ||
426 | entry->flags = 0; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int fiji_smu_request_load_fw(struct amdgpu_device *adev) | ||
432 | { | ||
433 | struct fiji_smu_private_data *private = (struct fiji_smu_private_data *)adev->smu.priv; | ||
434 | struct SMU_DRAMData_TOC *toc; | ||
435 | uint32_t fw_to_load; | ||
436 | |||
437 | WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0); | ||
438 | |||
439 | fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high); | ||
440 | fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low); | ||
441 | |||
442 | toc = (struct SMU_DRAMData_TOC *)private->header; | ||
443 | toc->num_entries = 0; | ||
444 | toc->structure_version = 1; | ||
445 | |||
446 | if (!adev->firmware.smu_load) | ||
447 | return 0; | ||
448 | |||
449 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G, | ||
450 | &toc->entry[toc->num_entries++])) { | ||
451 | DRM_ERROR("Failed to get firmware entry for RLC\n"); | ||
452 | return -EINVAL; | ||
453 | } | ||
454 | |||
455 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE, | ||
456 | &toc->entry[toc->num_entries++])) { | ||
457 | DRM_ERROR("Failed to get firmware entry for CE\n"); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP, | ||
462 | &toc->entry[toc->num_entries++])) { | ||
463 | DRM_ERROR("Failed to get firmware entry for PFP\n"); | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME, | ||
468 | &toc->entry[toc->num_entries++])) { | ||
469 | DRM_ERROR("Failed to get firmware entry for ME\n"); | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC, | ||
474 | &toc->entry[toc->num_entries++])) { | ||
475 | DRM_ERROR("Failed to get firmware entry for MEC\n"); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1, | ||
480 | &toc->entry[toc->num_entries++])) { | ||
481 | DRM_ERROR("Failed to get firmware entry for MEC_JT1\n"); | ||
482 | return -EINVAL; | ||
483 | } | ||
484 | |||
485 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2, | ||
486 | &toc->entry[toc->num_entries++])) { | ||
487 | DRM_ERROR("Failed to get firmware entry for MEC_JT2\n"); | ||
488 | return -EINVAL; | ||
489 | } | ||
490 | |||
491 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0, | ||
492 | &toc->entry[toc->num_entries++])) { | ||
493 | DRM_ERROR("Failed to get firmware entry for SDMA0\n"); | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | |||
497 | if (fiji_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1, | ||
498 | &toc->entry[toc->num_entries++])) { | ||
499 | DRM_ERROR("Failed to get firmware entry for SDMA1\n"); | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high); | ||
504 | fiji_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low); | ||
505 | |||
506 | fw_to_load = UCODE_ID_RLC_G_MASK | | ||
507 | UCODE_ID_SDMA0_MASK | | ||
508 | UCODE_ID_SDMA1_MASK | | ||
509 | UCODE_ID_CP_CE_MASK | | ||
510 | UCODE_ID_CP_ME_MASK | | ||
511 | UCODE_ID_CP_PFP_MASK | | ||
512 | UCODE_ID_CP_MEC_MASK; | ||
513 | |||
514 | if (fiji_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) { | ||
515 | DRM_ERROR("Fail to request SMU load ucode\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static uint32_t fiji_smu_get_mask_for_fw_type(uint32_t fw_type) | ||
523 | { | ||
524 | switch (fw_type) { | ||
525 | case AMDGPU_UCODE_ID_SDMA0: | ||
526 | return UCODE_ID_SDMA0_MASK; | ||
527 | case AMDGPU_UCODE_ID_SDMA1: | ||
528 | return UCODE_ID_SDMA1_MASK; | ||
529 | case AMDGPU_UCODE_ID_CP_CE: | ||
530 | return UCODE_ID_CP_CE_MASK; | ||
531 | case AMDGPU_UCODE_ID_CP_PFP: | ||
532 | return UCODE_ID_CP_PFP_MASK; | ||
533 | case AMDGPU_UCODE_ID_CP_ME: | ||
534 | return UCODE_ID_CP_ME_MASK; | ||
535 | case AMDGPU_UCODE_ID_CP_MEC1: | ||
536 | return UCODE_ID_CP_MEC_MASK; | ||
537 | case AMDGPU_UCODE_ID_CP_MEC2: | ||
538 | return UCODE_ID_CP_MEC_MASK; | ||
539 | case AMDGPU_UCODE_ID_RLC_G: | ||
540 | return UCODE_ID_RLC_G_MASK; | ||
541 | default: | ||
542 | DRM_ERROR("ucode type is out of range!\n"); | ||
543 | return 0; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | static int fiji_smu_check_fw_load_finish(struct amdgpu_device *adev, | ||
548 | uint32_t fw_type) | ||
549 | { | ||
550 | uint32_t fw_mask = fiji_smu_get_mask_for_fw_type(fw_type); | ||
551 | int i; | ||
552 | |||
553 | for (i = 0; i < adev->usec_timeout; i++) { | ||
554 | if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask)) | ||
555 | break; | ||
556 | udelay(1); | ||
557 | } | ||
558 | |||
559 | if (i == adev->usec_timeout) { | ||
560 | DRM_ERROR("check firmware loading failed\n"); | ||
561 | return -EINVAL; | ||
562 | } | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int fiji_smu_start_in_protection_mode(struct amdgpu_device *adev) | ||
568 | { | ||
569 | int result; | ||
570 | uint32_t val; | ||
571 | int i; | ||
572 | |||
573 | /* Assert reset */ | ||
574 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
575 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
576 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
577 | |||
578 | result = fiji_smu_upload_firmware_image(adev); | ||
579 | if (result) | ||
580 | return result; | ||
581 | |||
582 | /* Clear status */ | ||
583 | WREG32_SMC(ixSMU_STATUS, 0); | ||
584 | |||
585 | /* Enable clock */ | ||
586 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
587 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
588 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
589 | |||
590 | /* De-assert reset */ | ||
591 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
592 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
593 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
594 | |||
595 | /* Set SMU Auto Start */ | ||
596 | val = RREG32_SMC(ixSMU_INPUT_DATA); | ||
597 | val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1); | ||
598 | WREG32_SMC(ixSMU_INPUT_DATA, val); | ||
599 | |||
600 | /* Clear firmware interrupt enable flag */ | ||
601 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
602 | |||
603 | for (i = 0; i < adev->usec_timeout; i++) { | ||
604 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
605 | if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED)) | ||
606 | break; | ||
607 | udelay(1); | ||
608 | } | ||
609 | |||
610 | if (i == adev->usec_timeout) { | ||
611 | DRM_ERROR("Interrupt is not enabled by firmware\n"); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | /* Call Test SMU message with 0x20000 offset | ||
616 | * to trigger SMU start | ||
617 | */ | ||
618 | fiji_send_msg_to_smc_offset(adev); | ||
619 | DRM_INFO("[FM]try triger smu start\n"); | ||
620 | /* Wait for done bit to be set */ | ||
621 | for (i = 0; i < adev->usec_timeout; i++) { | ||
622 | val = RREG32_SMC(ixSMU_STATUS); | ||
623 | if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE)) | ||
624 | break; | ||
625 | udelay(1); | ||
626 | } | ||
627 | |||
628 | if (i == adev->usec_timeout) { | ||
629 | DRM_ERROR("Timeout for SMU start\n"); | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | |||
633 | /* Check pass/failed indicator */ | ||
634 | val = RREG32_SMC(ixSMU_STATUS); | ||
635 | if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) { | ||
636 | DRM_ERROR("SMU Firmware start failed\n"); | ||
637 | return -EINVAL; | ||
638 | } | ||
639 | DRM_INFO("[FM]smu started\n"); | ||
640 | /* Wait for firmware to initialize */ | ||
641 | for (i = 0; i < adev->usec_timeout; i++) { | ||
642 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
643 | if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
644 | break; | ||
645 | udelay(1); | ||
646 | } | ||
647 | |||
648 | if (i == adev->usec_timeout) { | ||
649 | DRM_ERROR("SMU firmware initialization failed\n"); | ||
650 | return -EINVAL; | ||
651 | } | ||
652 | DRM_INFO("[FM]smu initialized\n"); | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int fiji_smu_start_in_non_protection_mode(struct amdgpu_device *adev) | ||
658 | { | ||
659 | int i, result; | ||
660 | uint32_t val; | ||
661 | |||
662 | /* wait for smc boot up */ | ||
663 | for (i = 0; i < adev->usec_timeout; i++) { | ||
664 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
665 | val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done); | ||
666 | if (val) | ||
667 | break; | ||
668 | udelay(1); | ||
669 | } | ||
670 | |||
671 | if (i == adev->usec_timeout) { | ||
672 | DRM_ERROR("SMC boot sequence is not completed\n"); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | |||
676 | /* Clear firmware interrupt enable flag */ | ||
677 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
678 | |||
679 | /* Assert reset */ | ||
680 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
681 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
682 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
683 | |||
684 | result = fiji_smu_upload_firmware_image(adev); | ||
685 | if (result) | ||
686 | return result; | ||
687 | |||
688 | /* Set smc instruct start point at 0x0 */ | ||
689 | fiji_program_jump_on_start(adev); | ||
690 | |||
691 | /* Enable clock */ | ||
692 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
693 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
694 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
695 | |||
696 | /* De-assert reset */ | ||
697 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
698 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
699 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
700 | |||
701 | /* Wait for firmware to initialize */ | ||
702 | for (i = 0; i < adev->usec_timeout; i++) { | ||
703 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
704 | if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
705 | break; | ||
706 | udelay(1); | ||
707 | } | ||
708 | |||
709 | if (i == adev->usec_timeout) { | ||
710 | DRM_ERROR("Timeout for SMC firmware initialization\n"); | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | int fiji_smu_start(struct amdgpu_device *adev) | ||
718 | { | ||
719 | int result; | ||
720 | uint32_t val; | ||
721 | |||
722 | if (!fiji_is_smc_ram_running(adev)) { | ||
723 | val = RREG32_SMC(ixSMU_FIRMWARE); | ||
724 | if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) { | ||
725 | DRM_INFO("[FM]start smu in nonprotection mode\n"); | ||
726 | result = fiji_smu_start_in_non_protection_mode(adev); | ||
727 | if (result) | ||
728 | return result; | ||
729 | } else { | ||
730 | DRM_INFO("[FM]start smu in protection mode\n"); | ||
731 | result = fiji_smu_start_in_protection_mode(adev); | ||
732 | if (result) | ||
733 | return result; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | return fiji_smu_request_load_fw(adev); | ||
738 | } | ||
739 | |||
740 | static const struct amdgpu_smumgr_funcs fiji_smumgr_funcs = { | ||
741 | .check_fw_load_finish = fiji_smu_check_fw_load_finish, | ||
742 | .request_smu_load_fw = NULL, | ||
743 | .request_smu_specific_fw = NULL, | ||
744 | }; | ||
745 | |||
746 | int fiji_smu_init(struct amdgpu_device *adev) | ||
747 | { | ||
748 | struct fiji_smu_private_data *private; | ||
749 | uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | ||
750 | uint32_t smu_internal_buffer_size = 200*4096; | ||
751 | struct amdgpu_bo **toc_buf = &adev->smu.toc_buf; | ||
752 | struct amdgpu_bo **smu_buf = &adev->smu.smu_buf; | ||
753 | uint64_t mc_addr; | ||
754 | void *toc_buf_ptr; | ||
755 | void *smu_buf_ptr; | ||
756 | int ret; | ||
757 | |||
758 | private = kzalloc(sizeof(struct fiji_smu_private_data), GFP_KERNEL); | ||
759 | if (NULL == private) | ||
760 | return -ENOMEM; | ||
761 | |||
762 | /* allocate firmware buffers */ | ||
763 | if (adev->firmware.smu_load) | ||
764 | amdgpu_ucode_init_bo(adev); | ||
765 | |||
766 | adev->smu.priv = private; | ||
767 | adev->smu.fw_flags = 0; | ||
768 | |||
769 | /* Allocate FW image data structure and header buffer */ | ||
770 | ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, | ||
771 | true, AMDGPU_GEM_DOMAIN_VRAM, | ||
772 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
773 | NULL, NULL, toc_buf); | ||
774 | if (ret) { | ||
775 | DRM_ERROR("Failed to allocate memory for TOC buffer\n"); | ||
776 | return -ENOMEM; | ||
777 | } | ||
778 | |||
779 | /* Allocate buffer for SMU internal buffer */ | ||
780 | ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, | ||
781 | true, AMDGPU_GEM_DOMAIN_VRAM, | ||
782 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
783 | NULL, NULL, smu_buf); | ||
784 | if (ret) { | ||
785 | DRM_ERROR("Failed to allocate memory for SMU internal buffer\n"); | ||
786 | return -ENOMEM; | ||
787 | } | ||
788 | |||
789 | /* Retrieve GPU address for header buffer and internal buffer */ | ||
790 | ret = amdgpu_bo_reserve(adev->smu.toc_buf, false); | ||
791 | if (ret) { | ||
792 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
793 | DRM_ERROR("Failed to reserve the TOC buffer\n"); | ||
794 | return -EINVAL; | ||
795 | } | ||
796 | |||
797 | ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
798 | if (ret) { | ||
799 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
800 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
801 | DRM_ERROR("Failed to pin the TOC buffer\n"); | ||
802 | return -EINVAL; | ||
803 | } | ||
804 | |||
805 | ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr); | ||
806 | if (ret) { | ||
807 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
808 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
809 | DRM_ERROR("Failed to map the TOC buffer\n"); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
814 | private->header_addr_low = lower_32_bits(mc_addr); | ||
815 | private->header_addr_high = upper_32_bits(mc_addr); | ||
816 | private->header = toc_buf_ptr; | ||
817 | |||
818 | ret = amdgpu_bo_reserve(adev->smu.smu_buf, false); | ||
819 | if (ret) { | ||
820 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
821 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
822 | DRM_ERROR("Failed to reserve the SMU internal buffer\n"); | ||
823 | return -EINVAL; | ||
824 | } | ||
825 | |||
826 | ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
827 | if (ret) { | ||
828 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
829 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
830 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
831 | DRM_ERROR("Failed to pin the SMU internal buffer\n"); | ||
832 | return -EINVAL; | ||
833 | } | ||
834 | |||
835 | ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr); | ||
836 | if (ret) { | ||
837 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
838 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
839 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
840 | DRM_ERROR("Failed to map the SMU internal buffer\n"); | ||
841 | return -EINVAL; | ||
842 | } | ||
843 | |||
844 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
845 | private->smu_buffer_addr_low = lower_32_bits(mc_addr); | ||
846 | private->smu_buffer_addr_high = upper_32_bits(mc_addr); | ||
847 | |||
848 | adev->smu.smumgr_funcs = &fiji_smumgr_funcs; | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | int fiji_smu_fini(struct amdgpu_device *adev) | ||
854 | { | ||
855 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
856 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
857 | kfree(adev->smu.priv); | ||
858 | adev->smu.priv = NULL; | ||
859 | if (adev->firmware.fw_buf) | ||
860 | amdgpu_ucode_fini_bo(adev); | ||
861 | |||
862 | return 0; | ||
863 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smum.h b/drivers/gpu/drm/amd/amdgpu/fiji_smum.h deleted file mode 100644 index 1cef03deeac3..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/fiji_smum.h +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 | #ifndef FIJI_SMUMGR_H | ||
25 | #define FIJI_SMUMGR_H | ||
26 | |||
27 | #include "fiji_ppsmc.h" | ||
28 | |||
29 | int fiji_smu_init(struct amdgpu_device *adev); | ||
30 | int fiji_smu_fini(struct amdgpu_device *adev); | ||
31 | int fiji_smu_start(struct amdgpu_device *adev); | ||
32 | |||
33 | struct fiji_smu_private_data | ||
34 | { | ||
35 | uint8_t *header; | ||
36 | uint32_t smu_buffer_addr_high; | ||
37 | uint32_t smu_buffer_addr_low; | ||
38 | uint32_t header_addr_high; | ||
39 | uint32_t header_addr_low; | ||
40 | }; | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_dpm.c b/drivers/gpu/drm/amd/amdgpu/iceland_dpm.c deleted file mode 100644 index 2f078ad6095c..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/iceland_dpm.c +++ /dev/null | |||
@@ -1,200 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "iceland_smum.h" | ||
28 | |||
29 | MODULE_FIRMWARE("amdgpu/topaz_smc.bin"); | ||
30 | |||
31 | static void iceland_dpm_set_funcs(struct amdgpu_device *adev); | ||
32 | |||
33 | static int iceland_dpm_early_init(void *handle) | ||
34 | { | ||
35 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
36 | |||
37 | iceland_dpm_set_funcs(adev); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int iceland_dpm_init_microcode(struct amdgpu_device *adev) | ||
43 | { | ||
44 | char fw_name[30] = "amdgpu/topaz_smc.bin"; | ||
45 | int err; | ||
46 | |||
47 | err = request_firmware(&adev->pm.fw, fw_name, adev->dev); | ||
48 | if (err) | ||
49 | goto out; | ||
50 | err = amdgpu_ucode_validate(adev->pm.fw); | ||
51 | |||
52 | out: | ||
53 | if (err) { | ||
54 | DRM_ERROR("Failed to load firmware \"%s\"", fw_name); | ||
55 | release_firmware(adev->pm.fw); | ||
56 | adev->pm.fw = NULL; | ||
57 | } | ||
58 | return err; | ||
59 | } | ||
60 | |||
61 | static int iceland_dpm_sw_init(void *handle) | ||
62 | { | ||
63 | int ret; | ||
64 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
65 | |||
66 | ret = iceland_dpm_init_microcode(adev); | ||
67 | if (ret) | ||
68 | return ret; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int iceland_dpm_sw_fini(void *handle) | ||
74 | { | ||
75 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
76 | |||
77 | release_firmware(adev->pm.fw); | ||
78 | adev->pm.fw = NULL; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int iceland_dpm_hw_init(void *handle) | ||
84 | { | ||
85 | int ret; | ||
86 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
87 | |||
88 | mutex_lock(&adev->pm.mutex); | ||
89 | |||
90 | /* smu init only needs to be called at startup, not resume. | ||
91 | * It should be in sw_init, but requires the fw info gathered | ||
92 | * in sw_init from other IP modules. | ||
93 | */ | ||
94 | ret = iceland_smu_init(adev); | ||
95 | if (ret) { | ||
96 | DRM_ERROR("SMU initialization failed\n"); | ||
97 | goto fail; | ||
98 | } | ||
99 | |||
100 | ret = iceland_smu_start(adev); | ||
101 | if (ret) { | ||
102 | DRM_ERROR("SMU start failed\n"); | ||
103 | goto fail; | ||
104 | } | ||
105 | |||
106 | mutex_unlock(&adev->pm.mutex); | ||
107 | return 0; | ||
108 | |||
109 | fail: | ||
110 | adev->firmware.smu_load = false; | ||
111 | mutex_unlock(&adev->pm.mutex); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | static int iceland_dpm_hw_fini(void *handle) | ||
116 | { | ||
117 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
118 | |||
119 | mutex_lock(&adev->pm.mutex); | ||
120 | /* smu fini only needs to be called at teardown, not suspend. | ||
121 | * It should be in sw_fini, but we put it here for symmetry | ||
122 | * with smu init. | ||
123 | */ | ||
124 | iceland_smu_fini(adev); | ||
125 | mutex_unlock(&adev->pm.mutex); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int iceland_dpm_suspend(void *handle) | ||
130 | { | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int iceland_dpm_resume(void *handle) | ||
135 | { | ||
136 | int ret; | ||
137 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
138 | |||
139 | mutex_lock(&adev->pm.mutex); | ||
140 | |||
141 | ret = iceland_smu_start(adev); | ||
142 | if (ret) { | ||
143 | DRM_ERROR("SMU start failed\n"); | ||
144 | goto fail; | ||
145 | } | ||
146 | |||
147 | fail: | ||
148 | mutex_unlock(&adev->pm.mutex); | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | static int iceland_dpm_set_clockgating_state(void *handle, | ||
153 | enum amd_clockgating_state state) | ||
154 | { | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int iceland_dpm_set_powergating_state(void *handle, | ||
159 | enum amd_powergating_state state) | ||
160 | { | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | const struct amd_ip_funcs iceland_dpm_ip_funcs = { | ||
165 | .name = "iceland_dpm", | ||
166 | .early_init = iceland_dpm_early_init, | ||
167 | .late_init = NULL, | ||
168 | .sw_init = iceland_dpm_sw_init, | ||
169 | .sw_fini = iceland_dpm_sw_fini, | ||
170 | .hw_init = iceland_dpm_hw_init, | ||
171 | .hw_fini = iceland_dpm_hw_fini, | ||
172 | .suspend = iceland_dpm_suspend, | ||
173 | .resume = iceland_dpm_resume, | ||
174 | .is_idle = NULL, | ||
175 | .wait_for_idle = NULL, | ||
176 | .soft_reset = NULL, | ||
177 | .set_clockgating_state = iceland_dpm_set_clockgating_state, | ||
178 | .set_powergating_state = iceland_dpm_set_powergating_state, | ||
179 | }; | ||
180 | |||
181 | static const struct amdgpu_dpm_funcs iceland_dpm_funcs = { | ||
182 | .get_temperature = NULL, | ||
183 | .pre_set_power_state = NULL, | ||
184 | .set_power_state = NULL, | ||
185 | .post_set_power_state = NULL, | ||
186 | .display_configuration_changed = NULL, | ||
187 | .get_sclk = NULL, | ||
188 | .get_mclk = NULL, | ||
189 | .print_power_state = NULL, | ||
190 | .debugfs_print_current_performance_level = NULL, | ||
191 | .force_performance_level = NULL, | ||
192 | .vblank_too_short = NULL, | ||
193 | .powergate_uvd = NULL, | ||
194 | }; | ||
195 | |||
196 | static void iceland_dpm_set_funcs(struct amdgpu_device *adev) | ||
197 | { | ||
198 | if (NULL == adev->pm.funcs) | ||
199 | adev->pm.funcs = &iceland_dpm_funcs; | ||
200 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c deleted file mode 100644 index c6e004a3f557..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c +++ /dev/null | |||
@@ -1,677 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "ppsmc.h" | ||
28 | #include "iceland_smum.h" | ||
29 | #include "smu_ucode_xfer_vi.h" | ||
30 | #include "amdgpu_ucode.h" | ||
31 | |||
32 | #include "smu/smu_7_1_1_d.h" | ||
33 | #include "smu/smu_7_1_1_sh_mask.h" | ||
34 | |||
35 | #define ICELAND_SMC_SIZE 0x20000 | ||
36 | |||
37 | static int iceland_set_smc_sram_address(struct amdgpu_device *adev, | ||
38 | uint32_t smc_address, uint32_t limit) | ||
39 | { | ||
40 | uint32_t val; | ||
41 | |||
42 | if (smc_address & 3) | ||
43 | return -EINVAL; | ||
44 | |||
45 | if ((smc_address + 3) > limit) | ||
46 | return -EINVAL; | ||
47 | |||
48 | WREG32(mmSMC_IND_INDEX_0, smc_address); | ||
49 | |||
50 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
51 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
52 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int iceland_copy_bytes_to_smc(struct amdgpu_device *adev, | ||
58 | uint32_t smc_start_address, | ||
59 | const uint8_t *src, | ||
60 | uint32_t byte_count, uint32_t limit) | ||
61 | { | ||
62 | uint32_t addr; | ||
63 | uint32_t data, orig_data; | ||
64 | int result = 0; | ||
65 | uint32_t extra_shift; | ||
66 | unsigned long flags; | ||
67 | |||
68 | if (smc_start_address & 3) | ||
69 | return -EINVAL; | ||
70 | |||
71 | if ((smc_start_address + byte_count) > limit) | ||
72 | return -EINVAL; | ||
73 | |||
74 | addr = smc_start_address; | ||
75 | |||
76 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
77 | while (byte_count >= 4) { | ||
78 | /* Bytes are written into the SMC addres space with the MSB first */ | ||
79 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
80 | |||
81 | result = iceland_set_smc_sram_address(adev, addr, limit); | ||
82 | |||
83 | if (result) | ||
84 | goto out; | ||
85 | |||
86 | WREG32(mmSMC_IND_DATA_0, data); | ||
87 | |||
88 | src += 4; | ||
89 | byte_count -= 4; | ||
90 | addr += 4; | ||
91 | } | ||
92 | |||
93 | if (0 != byte_count) { | ||
94 | /* Now write odd bytes left, do a read modify write cycle */ | ||
95 | data = 0; | ||
96 | |||
97 | result = iceland_set_smc_sram_address(adev, addr, limit); | ||
98 | if (result) | ||
99 | goto out; | ||
100 | |||
101 | orig_data = RREG32(mmSMC_IND_DATA_0); | ||
102 | extra_shift = 8 * (4 - byte_count); | ||
103 | |||
104 | while (byte_count > 0) { | ||
105 | data = (data << 8) + *src++; | ||
106 | byte_count--; | ||
107 | } | ||
108 | |||
109 | data <<= extra_shift; | ||
110 | data |= (orig_data & ~((~0UL) << extra_shift)); | ||
111 | |||
112 | result = iceland_set_smc_sram_address(adev, addr, limit); | ||
113 | if (result) | ||
114 | goto out; | ||
115 | |||
116 | WREG32(mmSMC_IND_DATA_0, data); | ||
117 | } | ||
118 | |||
119 | out: | ||
120 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
121 | return result; | ||
122 | } | ||
123 | |||
124 | static void iceland_start_smc(struct amdgpu_device *adev) | ||
125 | { | ||
126 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
127 | |||
128 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
129 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
130 | } | ||
131 | |||
132 | static void iceland_reset_smc(struct amdgpu_device *adev) | ||
133 | { | ||
134 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
135 | |||
136 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
137 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
138 | } | ||
139 | |||
140 | static int iceland_program_jump_on_start(struct amdgpu_device *adev) | ||
141 | { | ||
142 | static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40}; | ||
143 | iceland_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static void iceland_stop_smc_clock(struct amdgpu_device *adev) | ||
149 | { | ||
150 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
151 | |||
152 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1); | ||
153 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
154 | } | ||
155 | |||
156 | static void iceland_start_smc_clock(struct amdgpu_device *adev) | ||
157 | { | ||
158 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
159 | |||
160 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
161 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
162 | } | ||
163 | |||
164 | static bool iceland_is_smc_ram_running(struct amdgpu_device *adev) | ||
165 | { | ||
166 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
167 | val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable); | ||
168 | |||
169 | return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C))); | ||
170 | } | ||
171 | |||
172 | static int wait_smu_response(struct amdgpu_device *adev) | ||
173 | { | ||
174 | int i; | ||
175 | uint32_t val; | ||
176 | |||
177 | for (i = 0; i < adev->usec_timeout; i++) { | ||
178 | val = RREG32(mmSMC_RESP_0); | ||
179 | if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP)) | ||
180 | break; | ||
181 | udelay(1); | ||
182 | } | ||
183 | |||
184 | if (i == adev->usec_timeout) | ||
185 | return -EINVAL; | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int iceland_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg) | ||
191 | { | ||
192 | if (!iceland_is_smc_ram_running(adev)) | ||
193 | return -EINVAL; | ||
194 | |||
195 | if (wait_smu_response(adev)) { | ||
196 | DRM_ERROR("Failed to send previous message\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | WREG32(mmSMC_MESSAGE_0, msg); | ||
201 | |||
202 | if (wait_smu_response(adev)) { | ||
203 | DRM_ERROR("Failed to send message\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int iceland_send_msg_to_smc_without_waiting(struct amdgpu_device *adev, | ||
211 | PPSMC_Msg msg) | ||
212 | { | ||
213 | if (!iceland_is_smc_ram_running(adev)) | ||
214 | return -EINVAL; | ||
215 | |||
216 | if (wait_smu_response(adev)) { | ||
217 | DRM_ERROR("Failed to send previous message\n"); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | WREG32(mmSMC_MESSAGE_0, msg); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int iceland_send_msg_to_smc_with_parameter(struct amdgpu_device *adev, | ||
227 | PPSMC_Msg msg, | ||
228 | uint32_t parameter) | ||
229 | { | ||
230 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
231 | |||
232 | return iceland_send_msg_to_smc(adev, msg); | ||
233 | } | ||
234 | |||
235 | static int iceland_send_msg_to_smc_with_parameter_without_waiting( | ||
236 | struct amdgpu_device *adev, | ||
237 | PPSMC_Msg msg, uint32_t parameter) | ||
238 | { | ||
239 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
240 | |||
241 | return iceland_send_msg_to_smc_without_waiting(adev, msg); | ||
242 | } | ||
243 | |||
244 | #if 0 /* not used yet */ | ||
245 | static int iceland_wait_for_smc_inactive(struct amdgpu_device *adev) | ||
246 | { | ||
247 | int i; | ||
248 | uint32_t val; | ||
249 | |||
250 | if (!iceland_is_smc_ram_running(adev)) | ||
251 | return -EINVAL; | ||
252 | |||
253 | for (i = 0; i < adev->usec_timeout; i++) { | ||
254 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
255 | if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0) | ||
256 | break; | ||
257 | udelay(1); | ||
258 | } | ||
259 | |||
260 | if (i == adev->usec_timeout) | ||
261 | return -EINVAL; | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | #endif | ||
266 | |||
267 | static int iceland_smu_upload_firmware_image(struct amdgpu_device *adev) | ||
268 | { | ||
269 | const struct smc_firmware_header_v1_0 *hdr; | ||
270 | uint32_t ucode_size; | ||
271 | uint32_t ucode_start_address; | ||
272 | const uint8_t *src; | ||
273 | uint32_t val; | ||
274 | uint32_t byte_count; | ||
275 | uint32_t data; | ||
276 | unsigned long flags; | ||
277 | int i; | ||
278 | |||
279 | if (!adev->pm.fw) | ||
280 | return -EINVAL; | ||
281 | |||
282 | /* Skip SMC ucode loading on SR-IOV capable boards. | ||
283 | * vbios does this for us in asic_init in that case. | ||
284 | */ | ||
285 | if (amdgpu_sriov_bios(adev)) | ||
286 | return 0; | ||
287 | |||
288 | hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data; | ||
289 | amdgpu_ucode_print_smc_hdr(&hdr->header); | ||
290 | |||
291 | adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); | ||
292 | ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); | ||
293 | ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); | ||
294 | src = (const uint8_t *) | ||
295 | (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); | ||
296 | |||
297 | if (ucode_size & 3) { | ||
298 | DRM_ERROR("SMC ucode is not 4 bytes aligned\n"); | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | |||
302 | if (ucode_size > ICELAND_SMC_SIZE) { | ||
303 | DRM_ERROR("SMC address is beyond the SMC RAM area\n"); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | for (i = 0; i < adev->usec_timeout; i++) { | ||
308 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
309 | if (REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done) == 0) | ||
310 | break; | ||
311 | udelay(1); | ||
312 | } | ||
313 | val = RREG32_SMC(ixSMC_SYSCON_MISC_CNTL); | ||
314 | WREG32_SMC(ixSMC_SYSCON_MISC_CNTL, val | 1); | ||
315 | |||
316 | iceland_stop_smc_clock(adev); | ||
317 | iceland_reset_smc(adev); | ||
318 | |||
319 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
320 | WREG32(mmSMC_IND_INDEX_0, ucode_start_address); | ||
321 | |||
322 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
323 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | ||
324 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
325 | |||
326 | byte_count = ucode_size; | ||
327 | while (byte_count >= 4) { | ||
328 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
329 | WREG32(mmSMC_IND_DATA_0, data); | ||
330 | src += 4; | ||
331 | byte_count -= 4; | ||
332 | } | ||
333 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
334 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
335 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
336 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | #if 0 /* not used yet */ | ||
342 | static int iceland_read_smc_sram_dword(struct amdgpu_device *adev, | ||
343 | uint32_t smc_address, | ||
344 | uint32_t *value, | ||
345 | uint32_t limit) | ||
346 | { | ||
347 | int result; | ||
348 | unsigned long flags; | ||
349 | |||
350 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
351 | result = iceland_set_smc_sram_address(adev, smc_address, limit); | ||
352 | if (result == 0) | ||
353 | *value = RREG32(mmSMC_IND_DATA_0); | ||
354 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
355 | return result; | ||
356 | } | ||
357 | |||
358 | static int iceland_write_smc_sram_dword(struct amdgpu_device *adev, | ||
359 | uint32_t smc_address, | ||
360 | uint32_t value, | ||
361 | uint32_t limit) | ||
362 | { | ||
363 | int result; | ||
364 | unsigned long flags; | ||
365 | |||
366 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
367 | result = iceland_set_smc_sram_address(adev, smc_address, limit); | ||
368 | if (result == 0) | ||
369 | WREG32(mmSMC_IND_DATA_0, value); | ||
370 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
371 | return result; | ||
372 | } | ||
373 | |||
374 | static int iceland_smu_stop_smc(struct amdgpu_device *adev) | ||
375 | { | ||
376 | iceland_reset_smc(adev); | ||
377 | iceland_stop_smc_clock(adev); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | #endif | ||
382 | |||
383 | static int iceland_smu_start_smc(struct amdgpu_device *adev) | ||
384 | { | ||
385 | int i; | ||
386 | uint32_t val; | ||
387 | |||
388 | iceland_program_jump_on_start(adev); | ||
389 | iceland_start_smc_clock(adev); | ||
390 | iceland_start_smc(adev); | ||
391 | |||
392 | for (i = 0; i < adev->usec_timeout; i++) { | ||
393 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
394 | if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED) == 1) | ||
395 | break; | ||
396 | udelay(1); | ||
397 | } | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static enum AMDGPU_UCODE_ID iceland_convert_fw_type(uint32_t fw_type) | ||
402 | { | ||
403 | switch (fw_type) { | ||
404 | case UCODE_ID_SDMA0: | ||
405 | return AMDGPU_UCODE_ID_SDMA0; | ||
406 | case UCODE_ID_SDMA1: | ||
407 | return AMDGPU_UCODE_ID_SDMA1; | ||
408 | case UCODE_ID_CP_CE: | ||
409 | return AMDGPU_UCODE_ID_CP_CE; | ||
410 | case UCODE_ID_CP_PFP: | ||
411 | return AMDGPU_UCODE_ID_CP_PFP; | ||
412 | case UCODE_ID_CP_ME: | ||
413 | return AMDGPU_UCODE_ID_CP_ME; | ||
414 | case UCODE_ID_CP_MEC: | ||
415 | case UCODE_ID_CP_MEC_JT1: | ||
416 | return AMDGPU_UCODE_ID_CP_MEC1; | ||
417 | case UCODE_ID_CP_MEC_JT2: | ||
418 | return AMDGPU_UCODE_ID_CP_MEC2; | ||
419 | case UCODE_ID_RLC_G: | ||
420 | return AMDGPU_UCODE_ID_RLC_G; | ||
421 | default: | ||
422 | DRM_ERROR("ucode type is out of range!\n"); | ||
423 | return AMDGPU_UCODE_ID_MAXIMUM; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | static uint32_t iceland_smu_get_mask_for_fw_type(uint32_t fw_type) | ||
428 | { | ||
429 | switch (fw_type) { | ||
430 | case AMDGPU_UCODE_ID_SDMA0: | ||
431 | return UCODE_ID_SDMA0_MASK; | ||
432 | case AMDGPU_UCODE_ID_SDMA1: | ||
433 | return UCODE_ID_SDMA1_MASK; | ||
434 | case AMDGPU_UCODE_ID_CP_CE: | ||
435 | return UCODE_ID_CP_CE_MASK; | ||
436 | case AMDGPU_UCODE_ID_CP_PFP: | ||
437 | return UCODE_ID_CP_PFP_MASK; | ||
438 | case AMDGPU_UCODE_ID_CP_ME: | ||
439 | return UCODE_ID_CP_ME_MASK; | ||
440 | case AMDGPU_UCODE_ID_CP_MEC1: | ||
441 | return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK; | ||
442 | case AMDGPU_UCODE_ID_CP_MEC2: | ||
443 | return UCODE_ID_CP_MEC_MASK; | ||
444 | case AMDGPU_UCODE_ID_RLC_G: | ||
445 | return UCODE_ID_RLC_G_MASK; | ||
446 | default: | ||
447 | DRM_ERROR("ucode type is out of range!\n"); | ||
448 | return 0; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static int iceland_smu_populate_single_firmware_entry(struct amdgpu_device *adev, | ||
453 | uint32_t fw_type, | ||
454 | struct SMU_Entry *entry) | ||
455 | { | ||
456 | enum AMDGPU_UCODE_ID id = iceland_convert_fw_type(fw_type); | ||
457 | struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id]; | ||
458 | const struct gfx_firmware_header_v1_0 *header = NULL; | ||
459 | uint64_t gpu_addr; | ||
460 | uint32_t data_size; | ||
461 | |||
462 | if (ucode->fw == NULL) | ||
463 | return -EINVAL; | ||
464 | |||
465 | gpu_addr = ucode->mc_addr; | ||
466 | header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; | ||
467 | data_size = le32_to_cpu(header->header.ucode_size_bytes); | ||
468 | |||
469 | entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version); | ||
470 | entry->id = (uint16_t)fw_type; | ||
471 | entry->image_addr_high = upper_32_bits(gpu_addr); | ||
472 | entry->image_addr_low = lower_32_bits(gpu_addr); | ||
473 | entry->meta_data_addr_high = 0; | ||
474 | entry->meta_data_addr_low = 0; | ||
475 | entry->data_size_byte = data_size; | ||
476 | entry->num_register_entries = 0; | ||
477 | entry->flags = 0; | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int iceland_smu_request_load_fw(struct amdgpu_device *adev) | ||
483 | { | ||
484 | struct iceland_smu_private_data *private = (struct iceland_smu_private_data *)adev->smu.priv; | ||
485 | struct SMU_DRAMData_TOC *toc; | ||
486 | uint32_t fw_to_load; | ||
487 | |||
488 | toc = (struct SMU_DRAMData_TOC *)private->header; | ||
489 | toc->num_entries = 0; | ||
490 | toc->structure_version = 1; | ||
491 | |||
492 | if (!adev->firmware.smu_load) | ||
493 | return 0; | ||
494 | |||
495 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G, | ||
496 | &toc->entry[toc->num_entries++])) { | ||
497 | DRM_ERROR("Failed to get firmware entry for RLC\n"); | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | |||
501 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE, | ||
502 | &toc->entry[toc->num_entries++])) { | ||
503 | DRM_ERROR("Failed to get firmware entry for CE\n"); | ||
504 | return -EINVAL; | ||
505 | } | ||
506 | |||
507 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP, | ||
508 | &toc->entry[toc->num_entries++])) { | ||
509 | DRM_ERROR("Failed to get firmware entry for PFP\n"); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | |||
513 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME, | ||
514 | &toc->entry[toc->num_entries++])) { | ||
515 | DRM_ERROR("Failed to get firmware entry for ME\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | |||
519 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC, | ||
520 | &toc->entry[toc->num_entries++])) { | ||
521 | DRM_ERROR("Failed to get firmware entry for MEC\n"); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1, | ||
526 | &toc->entry[toc->num_entries++])) { | ||
527 | DRM_ERROR("Failed to get firmware entry for MEC_JT1\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | |||
531 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0, | ||
532 | &toc->entry[toc->num_entries++])) { | ||
533 | DRM_ERROR("Failed to get firmware entry for SDMA0\n"); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1, | ||
538 | &toc->entry[toc->num_entries++])) { | ||
539 | DRM_ERROR("Failed to get firmware entry for SDMA1\n"); | ||
540 | return -EINVAL; | ||
541 | } | ||
542 | |||
543 | iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high); | ||
544 | iceland_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low); | ||
545 | |||
546 | fw_to_load = UCODE_ID_RLC_G_MASK | | ||
547 | UCODE_ID_SDMA0_MASK | | ||
548 | UCODE_ID_SDMA1_MASK | | ||
549 | UCODE_ID_CP_CE_MASK | | ||
550 | UCODE_ID_CP_ME_MASK | | ||
551 | UCODE_ID_CP_PFP_MASK | | ||
552 | UCODE_ID_CP_MEC_MASK | | ||
553 | UCODE_ID_CP_MEC_JT1_MASK; | ||
554 | |||
555 | |||
556 | if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) { | ||
557 | DRM_ERROR("Fail to request SMU load ucode\n"); | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int iceland_smu_check_fw_load_finish(struct amdgpu_device *adev, | ||
565 | uint32_t fw_type) | ||
566 | { | ||
567 | uint32_t fw_mask = iceland_smu_get_mask_for_fw_type(fw_type); | ||
568 | int i; | ||
569 | |||
570 | for (i = 0; i < adev->usec_timeout; i++) { | ||
571 | if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_27) & fw_mask)) | ||
572 | break; | ||
573 | udelay(1); | ||
574 | } | ||
575 | |||
576 | if (i == adev->usec_timeout) { | ||
577 | DRM_ERROR("check firmware loading failed\n"); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | int iceland_smu_start(struct amdgpu_device *adev) | ||
585 | { | ||
586 | int result; | ||
587 | |||
588 | result = iceland_smu_upload_firmware_image(adev); | ||
589 | if (result) | ||
590 | return result; | ||
591 | result = iceland_smu_start_smc(adev); | ||
592 | if (result) | ||
593 | return result; | ||
594 | |||
595 | return iceland_smu_request_load_fw(adev); | ||
596 | } | ||
597 | |||
598 | static const struct amdgpu_smumgr_funcs iceland_smumgr_funcs = { | ||
599 | .check_fw_load_finish = iceland_smu_check_fw_load_finish, | ||
600 | .request_smu_load_fw = NULL, | ||
601 | .request_smu_specific_fw = NULL, | ||
602 | }; | ||
603 | |||
604 | int iceland_smu_init(struct amdgpu_device *adev) | ||
605 | { | ||
606 | struct iceland_smu_private_data *private; | ||
607 | uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | ||
608 | struct amdgpu_bo **toc_buf = &adev->smu.toc_buf; | ||
609 | uint64_t mc_addr; | ||
610 | void *toc_buf_ptr; | ||
611 | int ret; | ||
612 | |||
613 | private = kzalloc(sizeof(struct iceland_smu_private_data), GFP_KERNEL); | ||
614 | if (NULL == private) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | /* allocate firmware buffers */ | ||
618 | if (adev->firmware.smu_load) | ||
619 | amdgpu_ucode_init_bo(adev); | ||
620 | |||
621 | adev->smu.priv = private; | ||
622 | adev->smu.fw_flags = 0; | ||
623 | |||
624 | /* Allocate FW image data structure and header buffer */ | ||
625 | ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, | ||
626 | true, AMDGPU_GEM_DOMAIN_VRAM, | ||
627 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
628 | NULL, NULL, toc_buf); | ||
629 | if (ret) { | ||
630 | DRM_ERROR("Failed to allocate memory for TOC buffer\n"); | ||
631 | return -ENOMEM; | ||
632 | } | ||
633 | |||
634 | /* Retrieve GPU address for header buffer and internal buffer */ | ||
635 | ret = amdgpu_bo_reserve(adev->smu.toc_buf, false); | ||
636 | if (ret) { | ||
637 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
638 | DRM_ERROR("Failed to reserve the TOC buffer\n"); | ||
639 | return -EINVAL; | ||
640 | } | ||
641 | |||
642 | ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
643 | if (ret) { | ||
644 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
645 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
646 | DRM_ERROR("Failed to pin the TOC buffer\n"); | ||
647 | return -EINVAL; | ||
648 | } | ||
649 | |||
650 | ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr); | ||
651 | if (ret) { | ||
652 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
653 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
654 | DRM_ERROR("Failed to map the TOC buffer\n"); | ||
655 | return -EINVAL; | ||
656 | } | ||
657 | |||
658 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
659 | private->header_addr_low = lower_32_bits(mc_addr); | ||
660 | private->header_addr_high = upper_32_bits(mc_addr); | ||
661 | private->header = toc_buf_ptr; | ||
662 | |||
663 | adev->smu.smumgr_funcs = &iceland_smumgr_funcs; | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | int iceland_smu_fini(struct amdgpu_device *adev) | ||
669 | { | ||
670 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
671 | kfree(adev->smu.priv); | ||
672 | adev->smu.priv = NULL; | ||
673 | if (adev->firmware.fw_buf) | ||
674 | amdgpu_ucode_fini_bo(adev); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smum.h b/drivers/gpu/drm/amd/amdgpu/iceland_smum.h deleted file mode 100644 index 5983e3150cc5..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/iceland_smum.h +++ /dev/null | |||
@@ -1,41 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 | #ifndef ICELAND_SMUM_H | ||
25 | #define ICELAND_SMUM_H | ||
26 | |||
27 | #include "ppsmc.h" | ||
28 | |||
29 | extern int iceland_smu_init(struct amdgpu_device *adev); | ||
30 | extern int iceland_smu_fini(struct amdgpu_device *adev); | ||
31 | extern int iceland_smu_start(struct amdgpu_device *adev); | ||
32 | |||
33 | struct iceland_smu_private_data | ||
34 | { | ||
35 | uint8_t *header; | ||
36 | uint8_t *mec_image; | ||
37 | uint32_t header_addr_high; | ||
38 | uint32_t header_addr_low; | ||
39 | }; | ||
40 | |||
41 | #endif | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c deleted file mode 100644 index f06f6f4dc3a8..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "tonga_smum.h" | ||
28 | |||
29 | MODULE_FIRMWARE("amdgpu/tonga_smc.bin"); | ||
30 | |||
31 | static void tonga_dpm_set_funcs(struct amdgpu_device *adev); | ||
32 | |||
33 | static int tonga_dpm_early_init(void *handle) | ||
34 | { | ||
35 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
36 | |||
37 | tonga_dpm_set_funcs(adev); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int tonga_dpm_init_microcode(struct amdgpu_device *adev) | ||
43 | { | ||
44 | char fw_name[30] = "amdgpu/tonga_smc.bin"; | ||
45 | int err; | ||
46 | err = request_firmware(&adev->pm.fw, fw_name, adev->dev); | ||
47 | if (err) | ||
48 | goto out; | ||
49 | err = amdgpu_ucode_validate(adev->pm.fw); | ||
50 | |||
51 | out: | ||
52 | if (err) { | ||
53 | DRM_ERROR("Failed to load firmware \"%s\"", fw_name); | ||
54 | release_firmware(adev->pm.fw); | ||
55 | adev->pm.fw = NULL; | ||
56 | } | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | static int tonga_dpm_sw_init(void *handle) | ||
61 | { | ||
62 | int ret; | ||
63 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
64 | |||
65 | ret = tonga_dpm_init_microcode(adev); | ||
66 | if (ret) | ||
67 | return ret; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int tonga_dpm_sw_fini(void *handle) | ||
73 | { | ||
74 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
75 | |||
76 | release_firmware(adev->pm.fw); | ||
77 | adev->pm.fw = NULL; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int tonga_dpm_hw_init(void *handle) | ||
83 | { | ||
84 | int ret; | ||
85 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
86 | |||
87 | mutex_lock(&adev->pm.mutex); | ||
88 | |||
89 | /* smu init only needs to be called at startup, not resume. | ||
90 | * It should be in sw_init, but requires the fw info gathered | ||
91 | * in sw_init from other IP modules. | ||
92 | */ | ||
93 | ret = tonga_smu_init(adev); | ||
94 | if (ret) { | ||
95 | DRM_ERROR("SMU initialization failed\n"); | ||
96 | goto fail; | ||
97 | } | ||
98 | |||
99 | ret = tonga_smu_start(adev); | ||
100 | if (ret) { | ||
101 | DRM_ERROR("SMU start failed\n"); | ||
102 | goto fail; | ||
103 | } | ||
104 | |||
105 | mutex_unlock(&adev->pm.mutex); | ||
106 | return 0; | ||
107 | |||
108 | fail: | ||
109 | adev->firmware.smu_load = false; | ||
110 | mutex_unlock(&adev->pm.mutex); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | |||
114 | static int tonga_dpm_hw_fini(void *handle) | ||
115 | { | ||
116 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
117 | |||
118 | mutex_lock(&adev->pm.mutex); | ||
119 | /* smu fini only needs to be called at teardown, not suspend. | ||
120 | * It should be in sw_fini, but we put it here for symmetry | ||
121 | * with smu init. | ||
122 | */ | ||
123 | tonga_smu_fini(adev); | ||
124 | mutex_unlock(&adev->pm.mutex); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int tonga_dpm_suspend(void *handle) | ||
129 | { | ||
130 | return tonga_dpm_hw_fini(handle); | ||
131 | } | ||
132 | |||
133 | static int tonga_dpm_resume(void *handle) | ||
134 | { | ||
135 | return tonga_dpm_hw_init(handle); | ||
136 | } | ||
137 | |||
138 | static int tonga_dpm_set_clockgating_state(void *handle, | ||
139 | enum amd_clockgating_state state) | ||
140 | { | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int tonga_dpm_set_powergating_state(void *handle, | ||
145 | enum amd_powergating_state state) | ||
146 | { | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | const struct amd_ip_funcs tonga_dpm_ip_funcs = { | ||
151 | .name = "tonga_dpm", | ||
152 | .early_init = tonga_dpm_early_init, | ||
153 | .late_init = NULL, | ||
154 | .sw_init = tonga_dpm_sw_init, | ||
155 | .sw_fini = tonga_dpm_sw_fini, | ||
156 | .hw_init = tonga_dpm_hw_init, | ||
157 | .hw_fini = tonga_dpm_hw_fini, | ||
158 | .suspend = tonga_dpm_suspend, | ||
159 | .resume = tonga_dpm_resume, | ||
160 | .is_idle = NULL, | ||
161 | .wait_for_idle = NULL, | ||
162 | .soft_reset = NULL, | ||
163 | .set_clockgating_state = tonga_dpm_set_clockgating_state, | ||
164 | .set_powergating_state = tonga_dpm_set_powergating_state, | ||
165 | }; | ||
166 | |||
167 | static const struct amdgpu_dpm_funcs tonga_dpm_funcs = { | ||
168 | .get_temperature = NULL, | ||
169 | .pre_set_power_state = NULL, | ||
170 | .set_power_state = NULL, | ||
171 | .post_set_power_state = NULL, | ||
172 | .display_configuration_changed = NULL, | ||
173 | .get_sclk = NULL, | ||
174 | .get_mclk = NULL, | ||
175 | .print_power_state = NULL, | ||
176 | .debugfs_print_current_performance_level = NULL, | ||
177 | .force_performance_level = NULL, | ||
178 | .vblank_too_short = NULL, | ||
179 | .powergate_uvd = NULL, | ||
180 | }; | ||
181 | |||
182 | static void tonga_dpm_set_funcs(struct amdgpu_device *adev) | ||
183 | { | ||
184 | if (NULL == adev->pm.funcs) | ||
185 | adev->pm.funcs = &tonga_dpm_funcs; | ||
186 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c deleted file mode 100644 index 1e71e819468b..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c +++ /dev/null | |||
@@ -1,862 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 <linux/firmware.h> | ||
25 | #include "drmP.h" | ||
26 | #include "amdgpu.h" | ||
27 | #include "tonga_ppsmc.h" | ||
28 | #include "tonga_smum.h" | ||
29 | #include "smu_ucode_xfer_vi.h" | ||
30 | #include "amdgpu_ucode.h" | ||
31 | |||
32 | #include "smu/smu_7_1_2_d.h" | ||
33 | #include "smu/smu_7_1_2_sh_mask.h" | ||
34 | |||
35 | #define TONGA_SMC_SIZE 0x20000 | ||
36 | |||
37 | static int tonga_set_smc_sram_address(struct amdgpu_device *adev, uint32_t smc_address, uint32_t limit) | ||
38 | { | ||
39 | uint32_t val; | ||
40 | |||
41 | if (smc_address & 3) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if ((smc_address + 3) > limit) | ||
45 | return -EINVAL; | ||
46 | |||
47 | WREG32(mmSMC_IND_INDEX_0, smc_address); | ||
48 | |||
49 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
50 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
51 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int tonga_copy_bytes_to_smc(struct amdgpu_device *adev, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit) | ||
57 | { | ||
58 | uint32_t addr; | ||
59 | uint32_t data, orig_data; | ||
60 | int result = 0; | ||
61 | uint32_t extra_shift; | ||
62 | unsigned long flags; | ||
63 | |||
64 | if (smc_start_address & 3) | ||
65 | return -EINVAL; | ||
66 | |||
67 | if ((smc_start_address + byte_count) > limit) | ||
68 | return -EINVAL; | ||
69 | |||
70 | addr = smc_start_address; | ||
71 | |||
72 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
73 | while (byte_count >= 4) { | ||
74 | /* Bytes are written into the SMC addres space with the MSB first */ | ||
75 | data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; | ||
76 | |||
77 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
78 | |||
79 | if (result) | ||
80 | goto out; | ||
81 | |||
82 | WREG32(mmSMC_IND_DATA_0, data); | ||
83 | |||
84 | src += 4; | ||
85 | byte_count -= 4; | ||
86 | addr += 4; | ||
87 | } | ||
88 | |||
89 | if (0 != byte_count) { | ||
90 | /* Now write odd bytes left, do a read modify write cycle */ | ||
91 | data = 0; | ||
92 | |||
93 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
94 | if (result) | ||
95 | goto out; | ||
96 | |||
97 | orig_data = RREG32(mmSMC_IND_DATA_0); | ||
98 | extra_shift = 8 * (4 - byte_count); | ||
99 | |||
100 | while (byte_count > 0) { | ||
101 | data = (data << 8) + *src++; | ||
102 | byte_count--; | ||
103 | } | ||
104 | |||
105 | data <<= extra_shift; | ||
106 | data |= (orig_data & ~((~0UL) << extra_shift)); | ||
107 | |||
108 | result = tonga_set_smc_sram_address(adev, addr, limit); | ||
109 | if (result) | ||
110 | goto out; | ||
111 | |||
112 | WREG32(mmSMC_IND_DATA_0, data); | ||
113 | } | ||
114 | |||
115 | out: | ||
116 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
117 | return result; | ||
118 | } | ||
119 | |||
120 | static int tonga_program_jump_on_start(struct amdgpu_device *adev) | ||
121 | { | ||
122 | static unsigned char data[] = {0xE0, 0x00, 0x80, 0x40}; | ||
123 | tonga_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static bool tonga_is_smc_ram_running(struct amdgpu_device *adev) | ||
129 | { | ||
130 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
131 | val = REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable); | ||
132 | |||
133 | return ((0 == val) && (0x20100 <= RREG32_SMC(ixSMC_PC_C))); | ||
134 | } | ||
135 | |||
136 | static int wait_smu_response(struct amdgpu_device *adev) | ||
137 | { | ||
138 | int i; | ||
139 | uint32_t val; | ||
140 | |||
141 | for (i = 0; i < adev->usec_timeout; i++) { | ||
142 | val = RREG32(mmSMC_RESP_0); | ||
143 | if (REG_GET_FIELD(val, SMC_RESP_0, SMC_RESP)) | ||
144 | break; | ||
145 | udelay(1); | ||
146 | } | ||
147 | |||
148 | if (i == adev->usec_timeout) | ||
149 | return -EINVAL; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int tonga_send_msg_to_smc_offset(struct amdgpu_device *adev) | ||
155 | { | ||
156 | if (wait_smu_response(adev)) { | ||
157 | DRM_ERROR("Failed to send previous message\n"); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | WREG32(mmSMC_MSG_ARG_0, 0x20000); | ||
162 | WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_Test); | ||
163 | |||
164 | if (wait_smu_response(adev)) { | ||
165 | DRM_ERROR("Failed to send message\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int tonga_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg) | ||
173 | { | ||
174 | if (!tonga_is_smc_ram_running(adev)) | ||
175 | { | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | if (wait_smu_response(adev)) { | ||
180 | DRM_ERROR("Failed to send previous message\n"); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | WREG32(mmSMC_MESSAGE_0, msg); | ||
185 | |||
186 | if (wait_smu_response(adev)) { | ||
187 | DRM_ERROR("Failed to send message\n"); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int tonga_send_msg_to_smc_without_waiting(struct amdgpu_device *adev, | ||
195 | PPSMC_Msg msg) | ||
196 | { | ||
197 | if (wait_smu_response(adev)) { | ||
198 | DRM_ERROR("Failed to send previous message\n"); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | WREG32(mmSMC_MESSAGE_0, msg); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int tonga_send_msg_to_smc_with_parameter(struct amdgpu_device *adev, | ||
208 | PPSMC_Msg msg, | ||
209 | uint32_t parameter) | ||
210 | { | ||
211 | if (!tonga_is_smc_ram_running(adev)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | if (wait_smu_response(adev)) { | ||
215 | DRM_ERROR("Failed to send previous message\n"); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
220 | |||
221 | return tonga_send_msg_to_smc(adev, msg); | ||
222 | } | ||
223 | |||
224 | static int tonga_send_msg_to_smc_with_parameter_without_waiting( | ||
225 | struct amdgpu_device *adev, | ||
226 | PPSMC_Msg msg, uint32_t parameter) | ||
227 | { | ||
228 | if (wait_smu_response(adev)) { | ||
229 | DRM_ERROR("Failed to send previous message\n"); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | WREG32(mmSMC_MSG_ARG_0, parameter); | ||
234 | |||
235 | return tonga_send_msg_to_smc_without_waiting(adev, msg); | ||
236 | } | ||
237 | |||
238 | #if 0 /* not used yet */ | ||
239 | static int tonga_wait_for_smc_inactive(struct amdgpu_device *adev) | ||
240 | { | ||
241 | int i; | ||
242 | uint32_t val; | ||
243 | |||
244 | if (!tonga_is_smc_ram_running(adev)) | ||
245 | return -EINVAL; | ||
246 | |||
247 | for (i = 0; i < adev->usec_timeout; i++) { | ||
248 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
249 | if (REG_GET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, cken) == 0) | ||
250 | break; | ||
251 | udelay(1); | ||
252 | } | ||
253 | |||
254 | if (i == adev->usec_timeout) | ||
255 | return -EINVAL; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | static int tonga_smu_upload_firmware_image(struct amdgpu_device *adev) | ||
262 | { | ||
263 | const struct smc_firmware_header_v1_0 *hdr; | ||
264 | uint32_t ucode_size; | ||
265 | uint32_t ucode_start_address; | ||
266 | const uint8_t *src; | ||
267 | uint32_t val; | ||
268 | uint32_t byte_count; | ||
269 | uint32_t *data; | ||
270 | unsigned long flags; | ||
271 | |||
272 | if (!adev->pm.fw) | ||
273 | return -EINVAL; | ||
274 | |||
275 | /* Skip SMC ucode loading on SR-IOV capable boards. | ||
276 | * vbios does this for us in asic_init in that case. | ||
277 | */ | ||
278 | if (amdgpu_sriov_bios(adev)) | ||
279 | return 0; | ||
280 | |||
281 | hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data; | ||
282 | amdgpu_ucode_print_smc_hdr(&hdr->header); | ||
283 | |||
284 | adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); | ||
285 | ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); | ||
286 | ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); | ||
287 | src = (const uint8_t *) | ||
288 | (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); | ||
289 | |||
290 | if (ucode_size & 3) { | ||
291 | DRM_ERROR("SMC ucode is not 4 bytes aligned\n"); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | if (ucode_size > TONGA_SMC_SIZE) { | ||
296 | DRM_ERROR("SMC address is beyond the SMC RAM area\n"); | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
301 | WREG32(mmSMC_IND_INDEX_0, ucode_start_address); | ||
302 | |||
303 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
304 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1); | ||
305 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
306 | |||
307 | byte_count = ucode_size; | ||
308 | data = (uint32_t *)src; | ||
309 | for (; byte_count >= 4; data++, byte_count -= 4) | ||
310 | WREG32(mmSMC_IND_DATA_0, data[0]); | ||
311 | |||
312 | val = RREG32(mmSMC_IND_ACCESS_CNTL); | ||
313 | val = REG_SET_FIELD(val, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0); | ||
314 | WREG32(mmSMC_IND_ACCESS_CNTL, val); | ||
315 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | #if 0 /* not used yet */ | ||
321 | static int tonga_read_smc_sram_dword(struct amdgpu_device *adev, | ||
322 | uint32_t smc_address, | ||
323 | uint32_t *value, | ||
324 | uint32_t limit) | ||
325 | { | ||
326 | int result; | ||
327 | unsigned long flags; | ||
328 | |||
329 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
330 | result = tonga_set_smc_sram_address(adev, smc_address, limit); | ||
331 | if (result == 0) | ||
332 | *value = RREG32(mmSMC_IND_DATA_0); | ||
333 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
334 | return result; | ||
335 | } | ||
336 | |||
337 | static int tonga_write_smc_sram_dword(struct amdgpu_device *adev, | ||
338 | uint32_t smc_address, | ||
339 | uint32_t value, | ||
340 | uint32_t limit) | ||
341 | { | ||
342 | int result; | ||
343 | unsigned long flags; | ||
344 | |||
345 | spin_lock_irqsave(&adev->smc_idx_lock, flags); | ||
346 | result = tonga_set_smc_sram_address(adev, smc_address, limit); | ||
347 | if (result == 0) | ||
348 | WREG32(mmSMC_IND_DATA_0, value); | ||
349 | spin_unlock_irqrestore(&adev->smc_idx_lock, flags); | ||
350 | return result; | ||
351 | } | ||
352 | |||
353 | static int tonga_smu_stop_smc(struct amdgpu_device *adev) | ||
354 | { | ||
355 | uint32_t val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
356 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
357 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
358 | |||
359 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
360 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 1); | ||
361 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | #endif | ||
366 | |||
367 | static enum AMDGPU_UCODE_ID tonga_convert_fw_type(uint32_t fw_type) | ||
368 | { | ||
369 | switch (fw_type) { | ||
370 | case UCODE_ID_SDMA0: | ||
371 | return AMDGPU_UCODE_ID_SDMA0; | ||
372 | case UCODE_ID_SDMA1: | ||
373 | return AMDGPU_UCODE_ID_SDMA1; | ||
374 | case UCODE_ID_CP_CE: | ||
375 | return AMDGPU_UCODE_ID_CP_CE; | ||
376 | case UCODE_ID_CP_PFP: | ||
377 | return AMDGPU_UCODE_ID_CP_PFP; | ||
378 | case UCODE_ID_CP_ME: | ||
379 | return AMDGPU_UCODE_ID_CP_ME; | ||
380 | case UCODE_ID_CP_MEC: | ||
381 | case UCODE_ID_CP_MEC_JT1: | ||
382 | return AMDGPU_UCODE_ID_CP_MEC1; | ||
383 | case UCODE_ID_CP_MEC_JT2: | ||
384 | return AMDGPU_UCODE_ID_CP_MEC2; | ||
385 | case UCODE_ID_RLC_G: | ||
386 | return AMDGPU_UCODE_ID_RLC_G; | ||
387 | default: | ||
388 | DRM_ERROR("ucode type is out of range!\n"); | ||
389 | return AMDGPU_UCODE_ID_MAXIMUM; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | static int tonga_smu_populate_single_firmware_entry(struct amdgpu_device *adev, | ||
394 | uint32_t fw_type, | ||
395 | struct SMU_Entry *entry) | ||
396 | { | ||
397 | enum AMDGPU_UCODE_ID id = tonga_convert_fw_type(fw_type); | ||
398 | struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id]; | ||
399 | const struct gfx_firmware_header_v1_0 *header = NULL; | ||
400 | uint64_t gpu_addr; | ||
401 | uint32_t data_size; | ||
402 | |||
403 | if (ucode->fw == NULL) | ||
404 | return -EINVAL; | ||
405 | |||
406 | gpu_addr = ucode->mc_addr; | ||
407 | header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; | ||
408 | data_size = le32_to_cpu(header->header.ucode_size_bytes); | ||
409 | |||
410 | if ((fw_type == UCODE_ID_CP_MEC_JT1) || | ||
411 | (fw_type == UCODE_ID_CP_MEC_JT2)) { | ||
412 | gpu_addr += le32_to_cpu(header->jt_offset) << 2; | ||
413 | data_size = le32_to_cpu(header->jt_size) << 2; | ||
414 | } | ||
415 | |||
416 | entry->version = (uint16_t)le32_to_cpu(header->header.ucode_version); | ||
417 | entry->id = (uint16_t)fw_type; | ||
418 | entry->image_addr_high = upper_32_bits(gpu_addr); | ||
419 | entry->image_addr_low = lower_32_bits(gpu_addr); | ||
420 | entry->meta_data_addr_high = 0; | ||
421 | entry->meta_data_addr_low = 0; | ||
422 | entry->data_size_byte = data_size; | ||
423 | entry->num_register_entries = 0; | ||
424 | |||
425 | if (fw_type == UCODE_ID_RLC_G) | ||
426 | entry->flags = 1; | ||
427 | else | ||
428 | entry->flags = 0; | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int tonga_smu_request_load_fw(struct amdgpu_device *adev) | ||
434 | { | ||
435 | struct tonga_smu_private_data *private = (struct tonga_smu_private_data *)adev->smu.priv; | ||
436 | struct SMU_DRAMData_TOC *toc; | ||
437 | uint32_t fw_to_load; | ||
438 | |||
439 | WREG32_SMC(ixSOFT_REGISTERS_TABLE_28, 0); | ||
440 | |||
441 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_HI, private->smu_buffer_addr_high); | ||
442 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SMU_DRAM_ADDR_LO, private->smu_buffer_addr_low); | ||
443 | |||
444 | toc = (struct SMU_DRAMData_TOC *)private->header; | ||
445 | toc->num_entries = 0; | ||
446 | toc->structure_version = 1; | ||
447 | |||
448 | if (!adev->firmware.smu_load) | ||
449 | return 0; | ||
450 | |||
451 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_RLC_G, | ||
452 | &toc->entry[toc->num_entries++])) { | ||
453 | DRM_ERROR("Failed to get firmware entry for RLC\n"); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_CE, | ||
458 | &toc->entry[toc->num_entries++])) { | ||
459 | DRM_ERROR("Failed to get firmware entry for CE\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_PFP, | ||
464 | &toc->entry[toc->num_entries++])) { | ||
465 | DRM_ERROR("Failed to get firmware entry for PFP\n"); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | |||
469 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_ME, | ||
470 | &toc->entry[toc->num_entries++])) { | ||
471 | DRM_ERROR("Failed to get firmware entry for ME\n"); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC, | ||
476 | &toc->entry[toc->num_entries++])) { | ||
477 | DRM_ERROR("Failed to get firmware entry for MEC\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | |||
481 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT1, | ||
482 | &toc->entry[toc->num_entries++])) { | ||
483 | DRM_ERROR("Failed to get firmware entry for MEC_JT1\n"); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2, | ||
488 | &toc->entry[toc->num_entries++])) { | ||
489 | DRM_ERROR("Failed to get firmware entry for MEC_JT2\n"); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | |||
493 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0, | ||
494 | &toc->entry[toc->num_entries++])) { | ||
495 | DRM_ERROR("Failed to get firmware entry for SDMA0\n"); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | if (tonga_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA1, | ||
500 | &toc->entry[toc->num_entries++])) { | ||
501 | DRM_ERROR("Failed to get firmware entry for SDMA1\n"); | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | |||
505 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_HI, private->header_addr_high); | ||
506 | tonga_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_DRV_DRAM_ADDR_LO, private->header_addr_low); | ||
507 | |||
508 | fw_to_load = UCODE_ID_RLC_G_MASK | | ||
509 | UCODE_ID_SDMA0_MASK | | ||
510 | UCODE_ID_SDMA1_MASK | | ||
511 | UCODE_ID_CP_CE_MASK | | ||
512 | UCODE_ID_CP_ME_MASK | | ||
513 | UCODE_ID_CP_PFP_MASK | | ||
514 | UCODE_ID_CP_MEC_MASK; | ||
515 | |||
516 | if (tonga_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) { | ||
517 | DRM_ERROR("Fail to request SMU load ucode\n"); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static uint32_t tonga_smu_get_mask_for_fw_type(uint32_t fw_type) | ||
525 | { | ||
526 | switch (fw_type) { | ||
527 | case AMDGPU_UCODE_ID_SDMA0: | ||
528 | return UCODE_ID_SDMA0_MASK; | ||
529 | case AMDGPU_UCODE_ID_SDMA1: | ||
530 | return UCODE_ID_SDMA1_MASK; | ||
531 | case AMDGPU_UCODE_ID_CP_CE: | ||
532 | return UCODE_ID_CP_CE_MASK; | ||
533 | case AMDGPU_UCODE_ID_CP_PFP: | ||
534 | return UCODE_ID_CP_PFP_MASK; | ||
535 | case AMDGPU_UCODE_ID_CP_ME: | ||
536 | return UCODE_ID_CP_ME_MASK; | ||
537 | case AMDGPU_UCODE_ID_CP_MEC1: | ||
538 | return UCODE_ID_CP_MEC_MASK; | ||
539 | case AMDGPU_UCODE_ID_CP_MEC2: | ||
540 | return UCODE_ID_CP_MEC_MASK; | ||
541 | case AMDGPU_UCODE_ID_RLC_G: | ||
542 | return UCODE_ID_RLC_G_MASK; | ||
543 | default: | ||
544 | DRM_ERROR("ucode type is out of range!\n"); | ||
545 | return 0; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | static int tonga_smu_check_fw_load_finish(struct amdgpu_device *adev, | ||
550 | uint32_t fw_type) | ||
551 | { | ||
552 | uint32_t fw_mask = tonga_smu_get_mask_for_fw_type(fw_type); | ||
553 | int i; | ||
554 | |||
555 | for (i = 0; i < adev->usec_timeout; i++) { | ||
556 | if (fw_mask == (RREG32_SMC(ixSOFT_REGISTERS_TABLE_28) & fw_mask)) | ||
557 | break; | ||
558 | udelay(1); | ||
559 | } | ||
560 | |||
561 | if (i == adev->usec_timeout) { | ||
562 | DRM_ERROR("check firmware loading failed\n"); | ||
563 | return -EINVAL; | ||
564 | } | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static int tonga_smu_start_in_protection_mode(struct amdgpu_device *adev) | ||
570 | { | ||
571 | int result; | ||
572 | uint32_t val; | ||
573 | int i; | ||
574 | |||
575 | /* Assert reset */ | ||
576 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
577 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
578 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
579 | |||
580 | result = tonga_smu_upload_firmware_image(adev); | ||
581 | if (result) | ||
582 | return result; | ||
583 | |||
584 | /* Clear status */ | ||
585 | WREG32_SMC(ixSMU_STATUS, 0); | ||
586 | |||
587 | /* Enable clock */ | ||
588 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
589 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
590 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
591 | |||
592 | /* De-assert reset */ | ||
593 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
594 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
595 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
596 | |||
597 | /* Set SMU Auto Start */ | ||
598 | val = RREG32_SMC(ixSMU_INPUT_DATA); | ||
599 | val = REG_SET_FIELD(val, SMU_INPUT_DATA, AUTO_START, 1); | ||
600 | WREG32_SMC(ixSMU_INPUT_DATA, val); | ||
601 | |||
602 | /* Clear firmware interrupt enable flag */ | ||
603 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
604 | |||
605 | for (i = 0; i < adev->usec_timeout; i++) { | ||
606 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
607 | if (REG_GET_FIELD(val, RCU_UC_EVENTS, INTERRUPTS_ENABLED)) | ||
608 | break; | ||
609 | udelay(1); | ||
610 | } | ||
611 | |||
612 | if (i == adev->usec_timeout) { | ||
613 | DRM_ERROR("Interrupt is not enabled by firmware\n"); | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | |||
617 | /* Call Test SMU message with 0x20000 offset | ||
618 | * to trigger SMU start | ||
619 | */ | ||
620 | tonga_send_msg_to_smc_offset(adev); | ||
621 | |||
622 | /* Wait for done bit to be set */ | ||
623 | for (i = 0; i < adev->usec_timeout; i++) { | ||
624 | val = RREG32_SMC(ixSMU_STATUS); | ||
625 | if (REG_GET_FIELD(val, SMU_STATUS, SMU_DONE)) | ||
626 | break; | ||
627 | udelay(1); | ||
628 | } | ||
629 | |||
630 | if (i == adev->usec_timeout) { | ||
631 | DRM_ERROR("Timeout for SMU start\n"); | ||
632 | return -EINVAL; | ||
633 | } | ||
634 | |||
635 | /* Check pass/failed indicator */ | ||
636 | val = RREG32_SMC(ixSMU_STATUS); | ||
637 | if (!REG_GET_FIELD(val, SMU_STATUS, SMU_PASS)) { | ||
638 | DRM_ERROR("SMU Firmware start failed\n"); | ||
639 | return -EINVAL; | ||
640 | } | ||
641 | |||
642 | /* Wait for firmware to initialize */ | ||
643 | for (i = 0; i < adev->usec_timeout; i++) { | ||
644 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
645 | if(REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
646 | break; | ||
647 | udelay(1); | ||
648 | } | ||
649 | |||
650 | if (i == adev->usec_timeout) { | ||
651 | DRM_ERROR("SMU firmware initialization failed\n"); | ||
652 | return -EINVAL; | ||
653 | } | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int tonga_smu_start_in_non_protection_mode(struct amdgpu_device *adev) | ||
659 | { | ||
660 | int i, result; | ||
661 | uint32_t val; | ||
662 | |||
663 | /* wait for smc boot up */ | ||
664 | for (i = 0; i < adev->usec_timeout; i++) { | ||
665 | val = RREG32_SMC(ixRCU_UC_EVENTS); | ||
666 | val = REG_GET_FIELD(val, RCU_UC_EVENTS, boot_seq_done); | ||
667 | if (val) | ||
668 | break; | ||
669 | udelay(1); | ||
670 | } | ||
671 | |||
672 | if (i == adev->usec_timeout) { | ||
673 | DRM_ERROR("SMC boot sequence is not completed\n"); | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | |||
677 | /* Clear firmware interrupt enable flag */ | ||
678 | WREG32_SMC(ixFIRMWARE_FLAGS, 0); | ||
679 | |||
680 | /* Assert reset */ | ||
681 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
682 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 1); | ||
683 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
684 | |||
685 | result = tonga_smu_upload_firmware_image(adev); | ||
686 | if (result) | ||
687 | return result; | ||
688 | |||
689 | /* Set smc instruct start point at 0x0 */ | ||
690 | tonga_program_jump_on_start(adev); | ||
691 | |||
692 | /* Enable clock */ | ||
693 | val = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0); | ||
694 | val = REG_SET_FIELD(val, SMC_SYSCON_CLOCK_CNTL_0, ck_disable, 0); | ||
695 | WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, val); | ||
696 | |||
697 | /* De-assert reset */ | ||
698 | val = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL); | ||
699 | val = REG_SET_FIELD(val, SMC_SYSCON_RESET_CNTL, rst_reg, 0); | ||
700 | WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, val); | ||
701 | |||
702 | /* Wait for firmware to initialize */ | ||
703 | for (i = 0; i < adev->usec_timeout; i++) { | ||
704 | val = RREG32_SMC(ixFIRMWARE_FLAGS); | ||
705 | if (REG_GET_FIELD(val, FIRMWARE_FLAGS, INTERRUPTS_ENABLED)) | ||
706 | break; | ||
707 | udelay(1); | ||
708 | } | ||
709 | |||
710 | if (i == adev->usec_timeout) { | ||
711 | DRM_ERROR("Timeout for SMC firmware initialization\n"); | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | int tonga_smu_start(struct amdgpu_device *adev) | ||
719 | { | ||
720 | int result; | ||
721 | uint32_t val; | ||
722 | |||
723 | if (!tonga_is_smc_ram_running(adev)) { | ||
724 | val = RREG32_SMC(ixSMU_FIRMWARE); | ||
725 | if (!REG_GET_FIELD(val, SMU_FIRMWARE, SMU_MODE)) { | ||
726 | result = tonga_smu_start_in_non_protection_mode(adev); | ||
727 | if (result) | ||
728 | return result; | ||
729 | } else { | ||
730 | result = tonga_smu_start_in_protection_mode(adev); | ||
731 | if (result) | ||
732 | return result; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | return tonga_smu_request_load_fw(adev); | ||
737 | } | ||
738 | |||
739 | static const struct amdgpu_smumgr_funcs tonga_smumgr_funcs = { | ||
740 | .check_fw_load_finish = tonga_smu_check_fw_load_finish, | ||
741 | .request_smu_load_fw = NULL, | ||
742 | .request_smu_specific_fw = NULL, | ||
743 | }; | ||
744 | |||
745 | int tonga_smu_init(struct amdgpu_device *adev) | ||
746 | { | ||
747 | struct tonga_smu_private_data *private; | ||
748 | uint32_t image_size = ((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096; | ||
749 | uint32_t smu_internal_buffer_size = 200*4096; | ||
750 | struct amdgpu_bo **toc_buf = &adev->smu.toc_buf; | ||
751 | struct amdgpu_bo **smu_buf = &adev->smu.smu_buf; | ||
752 | uint64_t mc_addr; | ||
753 | void *toc_buf_ptr; | ||
754 | void *smu_buf_ptr; | ||
755 | int ret; | ||
756 | |||
757 | private = kzalloc(sizeof(struct tonga_smu_private_data), GFP_KERNEL); | ||
758 | if (NULL == private) | ||
759 | return -ENOMEM; | ||
760 | |||
761 | /* allocate firmware buffers */ | ||
762 | if (adev->firmware.smu_load) | ||
763 | amdgpu_ucode_init_bo(adev); | ||
764 | |||
765 | adev->smu.priv = private; | ||
766 | adev->smu.fw_flags = 0; | ||
767 | |||
768 | /* Allocate FW image data structure and header buffer */ | ||
769 | ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, | ||
770 | true, AMDGPU_GEM_DOMAIN_VRAM, | ||
771 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
772 | NULL, NULL, toc_buf); | ||
773 | if (ret) { | ||
774 | DRM_ERROR("Failed to allocate memory for TOC buffer\n"); | ||
775 | return -ENOMEM; | ||
776 | } | ||
777 | |||
778 | /* Allocate buffer for SMU internal buffer */ | ||
779 | ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, | ||
780 | true, AMDGPU_GEM_DOMAIN_VRAM, | ||
781 | AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, | ||
782 | NULL, NULL, smu_buf); | ||
783 | if (ret) { | ||
784 | DRM_ERROR("Failed to allocate memory for SMU internal buffer\n"); | ||
785 | return -ENOMEM; | ||
786 | } | ||
787 | |||
788 | /* Retrieve GPU address for header buffer and internal buffer */ | ||
789 | ret = amdgpu_bo_reserve(adev->smu.toc_buf, false); | ||
790 | if (ret) { | ||
791 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
792 | DRM_ERROR("Failed to reserve the TOC buffer\n"); | ||
793 | return -EINVAL; | ||
794 | } | ||
795 | |||
796 | ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
797 | if (ret) { | ||
798 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
799 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
800 | DRM_ERROR("Failed to pin the TOC buffer\n"); | ||
801 | return -EINVAL; | ||
802 | } | ||
803 | |||
804 | ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr); | ||
805 | if (ret) { | ||
806 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
807 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
808 | DRM_ERROR("Failed to map the TOC buffer\n"); | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | amdgpu_bo_unreserve(adev->smu.toc_buf); | ||
813 | private->header_addr_low = lower_32_bits(mc_addr); | ||
814 | private->header_addr_high = upper_32_bits(mc_addr); | ||
815 | private->header = toc_buf_ptr; | ||
816 | |||
817 | ret = amdgpu_bo_reserve(adev->smu.smu_buf, false); | ||
818 | if (ret) { | ||
819 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
820 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
821 | DRM_ERROR("Failed to reserve the SMU internal buffer\n"); | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_VRAM, &mc_addr); | ||
826 | if (ret) { | ||
827 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
828 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
829 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
830 | DRM_ERROR("Failed to pin the SMU internal buffer\n"); | ||
831 | return -EINVAL; | ||
832 | } | ||
833 | |||
834 | ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr); | ||
835 | if (ret) { | ||
836 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
837 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
838 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
839 | DRM_ERROR("Failed to map the SMU internal buffer\n"); | ||
840 | return -EINVAL; | ||
841 | } | ||
842 | |||
843 | amdgpu_bo_unreserve(adev->smu.smu_buf); | ||
844 | private->smu_buffer_addr_low = lower_32_bits(mc_addr); | ||
845 | private->smu_buffer_addr_high = upper_32_bits(mc_addr); | ||
846 | |||
847 | adev->smu.smumgr_funcs = &tonga_smumgr_funcs; | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | int tonga_smu_fini(struct amdgpu_device *adev) | ||
853 | { | ||
854 | amdgpu_bo_unref(&adev->smu.toc_buf); | ||
855 | amdgpu_bo_unref(&adev->smu.smu_buf); | ||
856 | kfree(adev->smu.priv); | ||
857 | adev->smu.priv = NULL; | ||
858 | if (adev->firmware.fw_buf) | ||
859 | amdgpu_ucode_fini_bo(adev); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smum.h b/drivers/gpu/drm/amd/amdgpu/tonga_smum.h deleted file mode 100644 index c031ff99fe3e..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/tonga_smum.h +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2014 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 | #ifndef TONGA_SMUMGR_H | ||
25 | #define TONGA_SMUMGR_H | ||
26 | |||
27 | #include "tonga_ppsmc.h" | ||
28 | |||
29 | int tonga_smu_init(struct amdgpu_device *adev); | ||
30 | int tonga_smu_fini(struct amdgpu_device *adev); | ||
31 | int tonga_smu_start(struct amdgpu_device *adev); | ||
32 | |||
33 | struct tonga_smu_private_data | ||
34 | { | ||
35 | uint8_t *header; | ||
36 | uint32_t smu_buffer_addr_high; | ||
37 | uint32_t smu_buffer_addr_low; | ||
38 | uint32_t header_addr_high; | ||
39 | uint32_t header_addr_low; | ||
40 | }; | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 63ce7f08d1d5..c0d9aad7126f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c | |||
@@ -79,6 +79,9 @@ | |||
79 | #endif | 79 | #endif |
80 | #include "dce_virtual.h" | 80 | #include "dce_virtual.h" |
81 | 81 | ||
82 | MODULE_FIRMWARE("amdgpu/topaz_smc.bin"); | ||
83 | MODULE_FIRMWARE("amdgpu/tonga_smc.bin"); | ||
84 | MODULE_FIRMWARE("amdgpu/fiji_smc.bin"); | ||
82 | MODULE_FIRMWARE("amdgpu/polaris10_smc.bin"); | 85 | MODULE_FIRMWARE("amdgpu/polaris10_smc.bin"); |
83 | MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); | 86 | MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); |
84 | MODULE_FIRMWARE("amdgpu/polaris11_smc.bin"); | 87 | MODULE_FIRMWARE("amdgpu/polaris11_smc.bin"); |