aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2016-11-28 14:28:34 -0500
committerRob Clark <robdclark@gmail.com>2016-11-28 15:14:16 -0500
commit2401a008461481387741bacf7318d13af2c2055f (patch)
tree265b4b900cf83397cffb0385c68650e28a1760fc
parentb5f103ab98c77ca5998b39533c2b46959fbd37d9 (diff)
drm/msm: gpu: Add support for the GPMU
Most 5XX targets have GPMU (Graphics Power Management Unit) that handles a lot of the heavy lifting for power management including thermal and limits management and dynamic power collapse. While the GPMU itself is optional, it is usually nessesary to hit aggressive power targets. The GPMU firmware needs to be loaded into the GPMU at init time via a shared hardware block of registers. Using the GPU to write the microcode is more efficient than using the CPU so at first load create an indirect buffer that can be executed during subsequent initalization sequences. After loading the GPMU gets initalized through a shared register interface and then we mostly get out of its way and let it do its thing. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c64
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.h23
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_power.c344
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c1
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h1
6 files changed, 431 insertions, 3 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 3c9f0ccc8abb..028c24df2291 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -7,6 +7,7 @@ msm-y := \
7 adreno/a3xx_gpu.o \ 7 adreno/a3xx_gpu.o \
8 adreno/a4xx_gpu.o \ 8 adreno/a4xx_gpu.o \
9 adreno/a5xx_gpu.o \ 9 adreno/a5xx_gpu.o \
10 adreno/a5xx_power.o \
10 hdmi/hdmi.o \ 11 hdmi/hdmi.o \
11 hdmi/hdmi_audio.o \ 12 hdmi/hdmi_audio.o \
12 hdmi/hdmi_bridge.o \ 13 hdmi/hdmi_bridge.o \
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index bf0a93038554..b8647198c11c 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -450,6 +450,9 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
450 REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); 450 REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000);
451 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); 451 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000);
452 452
453 /* Load the GPMU firmware before starting the HW init */
454 a5xx_gpmu_ucode_init(gpu);
455
453 ret = adreno_hw_init(gpu); 456 ret = adreno_hw_init(gpu);
454 if (ret) 457 if (ret)
455 return ret; 458 return ret;
@@ -467,8 +470,9 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
467 if (ret) 470 if (ret)
468 return ret; 471 return ret;
469 472
470 /* Put the GPU into insecure mode */ 473 ret = a5xx_power_init(gpu);
471 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); 474 if (ret)
475 return ret;
472 476
473 /* 477 /*
474 * Send a pipeline event stat to get misbehaving counters to start 478 * Send a pipeline event stat to get misbehaving counters to start
@@ -483,6 +487,9 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
483 return -EINVAL; 487 return -EINVAL;
484 } 488 }
485 489
490 /* Put the GPU into unsecure mode */
491 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
492
486 return 0; 493 return 0;
487} 494}
488 495
@@ -525,6 +532,12 @@ static void a5xx_destroy(struct msm_gpu *gpu)
525 drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo); 532 drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo);
526 } 533 }
527 534
535 if (a5xx_gpu->gpmu_bo) {
536 if (a5xx_gpu->gpmu_bo)
537 msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->id);
538 drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo);
539 }
540
528 adreno_gpu_cleanup(adreno_gpu); 541 adreno_gpu_cleanup(adreno_gpu);
529 kfree(a5xx_gpu); 542 kfree(a5xx_gpu);
530} 543}
@@ -748,11 +761,54 @@ static void a5xx_dump(struct msm_gpu *gpu)
748 761
749static int a5xx_pm_resume(struct msm_gpu *gpu) 762static int a5xx_pm_resume(struct msm_gpu *gpu)
750{ 763{
751 return msm_gpu_pm_resume(gpu); 764 int ret;
765
766 /* Turn on the core power */
767 ret = msm_gpu_pm_resume(gpu);
768 if (ret)
769 return ret;
770
771 /* Turn the RBCCU domain first to limit the chances of voltage droop */
772 gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000);
773
774 /* Wait 3 usecs before polling */
775 udelay(3);
776
777 ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS,
778 (1 << 20), (1 << 20));
779 if (ret) {
780 DRM_ERROR("%s: timeout waiting for RBCCU GDSC enable: %X\n",
781 gpu->name,
782 gpu_read(gpu, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS));
783 return ret;
784 }
785
786 /* Turn on the SP domain */
787 gpu_write(gpu, REG_A5XX_GPMU_SP_POWER_CNTL, 0x778000);
788 ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_SP_PWR_CLK_STATUS,
789 (1 << 20), (1 << 20));
790 if (ret)
791 DRM_ERROR("%s: timeout waiting for SP GDSC enable\n",
792 gpu->name);
793
794 return ret;
752} 795}
753 796
754static int a5xx_pm_suspend(struct msm_gpu *gpu) 797static int a5xx_pm_suspend(struct msm_gpu *gpu)
755{ 798{
799 /* Clear the VBIF pipe before shutting down */
800 gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF);
801 spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF);
802
803 gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0);
804
805 /*
806 * Reset the VBIF before power collapse to avoid issue with FIFO
807 * entries
808 */
809 gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000);
810 gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000);
811
756 return msm_gpu_pm_suspend(gpu); 812 return msm_gpu_pm_suspend(gpu);
757} 813}
758 814
@@ -820,6 +876,8 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
820 adreno_gpu->registers = a5xx_registers; 876 adreno_gpu->registers = a5xx_registers;
821 adreno_gpu->reg_offsets = a5xx_register_offsets; 877 adreno_gpu->reg_offsets = a5xx_register_offsets;
822 878
879 a5xx_gpu->lm_leakage = 0x4E001A;
880
823 ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs); 881 ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
824 if (ret) { 882 if (ret) {
825 a5xx_destroy(&(a5xx_gpu->base.base)); 883 a5xx_destroy(&(a5xx_gpu->base.base));
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index 39a07f400b35..1590f845d554 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -30,8 +30,31 @@ struct a5xx_gpu {
30 30
31 struct drm_gem_object *pfp_bo; 31 struct drm_gem_object *pfp_bo;
32 uint64_t pfp_iova; 32 uint64_t pfp_iova;
33
34 struct drm_gem_object *gpmu_bo;
35 uint64_t gpmu_iova;
36 uint32_t gpmu_dwords;
37
38 uint32_t lm_leakage;
33}; 39};
34 40
35#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) 41#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
36 42
43int a5xx_power_init(struct msm_gpu *gpu);
44void a5xx_gpmu_ucode_init(struct msm_gpu *gpu);
45
46static inline int spin_usecs(struct msm_gpu *gpu, uint32_t usecs,
47 uint32_t reg, uint32_t mask, uint32_t value)
48{
49 while (usecs--) {
50 udelay(1);
51 if ((gpu_read(gpu, reg) & mask) == value)
52 return 0;
53 cpu_relax();
54 }
55
56 return -ETIMEDOUT;
57}
58
59
37#endif /* __A5XX_GPU_H__ */ 60#endif /* __A5XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c
new file mode 100644
index 000000000000..72d52c71f769
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c
@@ -0,0 +1,344 @@
1/* Copyright (c) 2016 The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/pm_opp.h>
15#include "a5xx_gpu.h"
16
17/*
18 * The GPMU data block is a block of shared registers that can be used to
19 * communicate back and forth. These "registers" are by convention with the GPMU
20 * firwmare and not bound to any specific hardware design
21 */
22
23#define AGC_INIT_BASE REG_A5XX_GPMU_DATA_RAM_BASE
24#define AGC_INIT_MSG_MAGIC (AGC_INIT_BASE + 5)
25#define AGC_MSG_BASE (AGC_INIT_BASE + 7)
26
27#define AGC_MSG_STATE (AGC_MSG_BASE + 0)
28#define AGC_MSG_COMMAND (AGC_MSG_BASE + 1)
29#define AGC_MSG_PAYLOAD_SIZE (AGC_MSG_BASE + 3)
30#define AGC_MSG_PAYLOAD(_o) ((AGC_MSG_BASE + 5) + (_o))
31
32#define AGC_POWER_CONFIG_PRODUCTION_ID 1
33#define AGC_INIT_MSG_VALUE 0xBABEFACE
34
35static struct {
36 uint32_t reg;
37 uint32_t value;
38} a5xx_sequence_regs[] = {
39 { 0xB9A1, 0x00010303 },
40 { 0xB9A2, 0x13000000 },
41 { 0xB9A3, 0x00460020 },
42 { 0xB9A4, 0x10000000 },
43 { 0xB9A5, 0x040A1707 },
44 { 0xB9A6, 0x00010000 },
45 { 0xB9A7, 0x0E000904 },
46 { 0xB9A8, 0x10000000 },
47 { 0xB9A9, 0x01165000 },
48 { 0xB9AA, 0x000E0002 },
49 { 0xB9AB, 0x03884141 },
50 { 0xB9AC, 0x10000840 },
51 { 0xB9AD, 0x572A5000 },
52 { 0xB9AE, 0x00000003 },
53 { 0xB9AF, 0x00000000 },
54 { 0xB9B0, 0x10000000 },
55 { 0xB828, 0x6C204010 },
56 { 0xB829, 0x6C204011 },
57 { 0xB82A, 0x6C204012 },
58 { 0xB82B, 0x6C204013 },
59 { 0xB82C, 0x6C204014 },
60 { 0xB90F, 0x00000004 },
61 { 0xB910, 0x00000002 },
62 { 0xB911, 0x00000002 },
63 { 0xB912, 0x00000002 },
64 { 0xB913, 0x00000002 },
65 { 0xB92F, 0x00000004 },
66 { 0xB930, 0x00000005 },
67 { 0xB931, 0x00000005 },
68 { 0xB932, 0x00000005 },
69 { 0xB933, 0x00000005 },
70 { 0xB96F, 0x00000001 },
71 { 0xB970, 0x00000003 },
72 { 0xB94F, 0x00000004 },
73 { 0xB950, 0x0000000B },
74 { 0xB951, 0x0000000B },
75 { 0xB952, 0x0000000B },
76 { 0xB953, 0x0000000B },
77 { 0xB907, 0x00000019 },
78 { 0xB927, 0x00000019 },
79 { 0xB947, 0x00000019 },
80 { 0xB967, 0x00000019 },
81 { 0xB987, 0x00000019 },
82 { 0xB906, 0x00220001 },
83 { 0xB926, 0x00220001 },
84 { 0xB946, 0x00220001 },
85 { 0xB966, 0x00220001 },
86 { 0xB986, 0x00300000 },
87 { 0xAC40, 0x0340FF41 },
88 { 0xAC41, 0x03BEFED0 },
89 { 0xAC42, 0x00331FED },
90 { 0xAC43, 0x021FFDD3 },
91 { 0xAC44, 0x5555AAAA },
92 { 0xAC45, 0x5555AAAA },
93 { 0xB9BA, 0x00000008 },
94};
95
96/*
97 * Get the actual voltage value for the operating point at the specified
98 * frequency
99 */
100static inline uint32_t _get_mvolts(struct msm_gpu *gpu, uint32_t freq)
101{
102 struct drm_device *dev = gpu->dev;
103 struct msm_drm_private *priv = dev->dev_private;
104 struct platform_device *pdev = priv->gpu_pdev;
105 struct dev_pm_opp *opp;
106
107 opp = dev_pm_opp_find_freq_exact(&pdev->dev, freq, true);
108
109 return (!IS_ERR(opp)) ? dev_pm_opp_get_voltage(opp) / 1000 : 0;
110}
111
112/* Setup thermal limit management */
113static void a5xx_lm_setup(struct msm_gpu *gpu)
114{
115 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
116 struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
117 unsigned int i;
118
119 /* Write the block of sequence registers */
120 for (i = 0; i < ARRAY_SIZE(a5xx_sequence_regs); i++)
121 gpu_write(gpu, a5xx_sequence_regs[i].reg,
122 a5xx_sequence_regs[i].value);
123
124 /* Hard code the A530 GPU thermal sensor ID for the GPMU */
125 gpu_write(gpu, REG_A5XX_GPMU_TEMP_SENSOR_ID, 0x60007);
126 gpu_write(gpu, REG_A5XX_GPMU_DELTA_TEMP_THRESHOLD, 0x01);
127 gpu_write(gpu, REG_A5XX_GPMU_TEMP_SENSOR_CONFIG, 0x01);
128
129 /* Until we get clock scaling 0 is always the active power level */
130 gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE, 0x80000000 | 0);
131
132 gpu_write(gpu, REG_A5XX_GPMU_BASE_LEAKAGE, a5xx_gpu->lm_leakage);
133
134 /* The threshold is fixed at 6000 for A530 */
135 gpu_write(gpu, REG_A5XX_GPMU_GPMU_PWR_THRESHOLD, 0x80000000 | 6000);
136
137 gpu_write(gpu, REG_A5XX_GPMU_BEC_ENABLE, 0x10001FFF);
138 gpu_write(gpu, REG_A5XX_GDPM_CONFIG1, 0x00201FF1);
139
140 /* Write the voltage table */
141 gpu_write(gpu, REG_A5XX_GPMU_BEC_ENABLE, 0x10001FFF);
142 gpu_write(gpu, REG_A5XX_GDPM_CONFIG1, 0x201FF1);
143
144 gpu_write(gpu, AGC_MSG_STATE, 1);
145 gpu_write(gpu, AGC_MSG_COMMAND, AGC_POWER_CONFIG_PRODUCTION_ID);
146
147 /* Write the max power - hard coded to 5448 for A530 */
148 gpu_write(gpu, AGC_MSG_PAYLOAD(0), 5448);
149 gpu_write(gpu, AGC_MSG_PAYLOAD(1), 1);
150
151 /*
152 * For now just write the one voltage level - we will do more when we
153 * can do scaling
154 */
155 gpu_write(gpu, AGC_MSG_PAYLOAD(2), _get_mvolts(gpu, gpu->fast_rate));
156 gpu_write(gpu, AGC_MSG_PAYLOAD(3), gpu->fast_rate / 1000000);
157
158 gpu_write(gpu, AGC_MSG_PAYLOAD_SIZE, 4 * sizeof(uint32_t));
159 gpu_write(gpu, AGC_INIT_MSG_MAGIC, AGC_INIT_MSG_VALUE);
160}
161
162/* Enable SP/TP cpower collapse */
163static void a5xx_pc_init(struct msm_gpu *gpu)
164{
165 gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_INTER_FRAME_CTRL, 0x7F);
166 gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_BINNING_CTRL, 0);
167 gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_INTER_FRAME_HYST, 0xA0080);
168 gpu_write(gpu, REG_A5XX_GPMU_PWR_COL_STAGGER_DELAY, 0x600040);
169}
170
171/* Enable the GPMU microcontroller */
172static int a5xx_gpmu_init(struct msm_gpu *gpu)
173{
174 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
175 struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
176 struct msm_ringbuffer *ring = gpu->rb;
177
178 if (!a5xx_gpu->gpmu_dwords)
179 return 0;
180
181 /* Turn off protected mode for this operation */
182 OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1);
183 OUT_RING(ring, 0);
184
185 /* Kick off the IB to load the GPMU microcode */
186 OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3);
187 OUT_RING(ring, lower_32_bits(a5xx_gpu->gpmu_iova));
188 OUT_RING(ring, upper_32_bits(a5xx_gpu->gpmu_iova));
189 OUT_RING(ring, a5xx_gpu->gpmu_dwords);
190
191 /* Turn back on protected mode */
192 OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1);
193 OUT_RING(ring, 1);
194
195 gpu->funcs->flush(gpu);
196
197 if (!gpu->funcs->idle(gpu)) {
198 DRM_ERROR("%s: Unable to load GPMU firmware. GPMU will not be active\n",
199 gpu->name);
200 return -EINVAL;
201 }
202
203 gpu_write(gpu, REG_A5XX_GPMU_WFI_CONFIG, 0x4014);
204
205 /* Kick off the GPMU */
206 gpu_write(gpu, REG_A5XX_GPMU_CM3_SYSRESET, 0x0);
207
208 /*
209 * Wait for the GPMU to respond. It isn't fatal if it doesn't, we just
210 * won't have advanced power collapse.
211 */
212 if (spin_usecs(gpu, 25, REG_A5XX_GPMU_GENERAL_0, 0xFFFFFFFF,
213 0xBABEFACE))
214 DRM_ERROR("%s: GPMU firmware initialization timed out\n",
215 gpu->name);
216
217 return 0;
218}
219
220/* Enable limits management */
221static void a5xx_lm_enable(struct msm_gpu *gpu)
222{
223 gpu_write(gpu, REG_A5XX_GDPM_INT_MASK, 0x0);
224 gpu_write(gpu, REG_A5XX_GDPM_INT_EN, 0x0A);
225 gpu_write(gpu, REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_EN_MASK, 0x01);
226 gpu_write(gpu, REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_EN_MASK, 0x50000);
227 gpu_write(gpu, REG_A5XX_GPMU_THROTTLE_UNMASK_FORCE_CTRL, 0x30000);
228
229 gpu_write(gpu, REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL, 0x011);
230}
231
232int a5xx_power_init(struct msm_gpu *gpu)
233{
234 int ret;
235
236 /* Set up the limits management */
237 a5xx_lm_setup(gpu);
238
239 /* Set up SP/TP power collpase */
240 a5xx_pc_init(gpu);
241
242 /* Start the GPMU */
243 ret = a5xx_gpmu_init(gpu);
244 if (ret)
245 return ret;
246
247 /* Start the limits management */
248 a5xx_lm_enable(gpu);
249
250 return 0;
251}
252
253void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
254{
255 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
256 struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
257 struct drm_device *drm = gpu->dev;
258 const struct firmware *fw;
259 uint32_t dwords = 0, offset = 0, bosize;
260 unsigned int *data, *ptr, *cmds;
261 unsigned int cmds_size;
262
263 if (a5xx_gpu->gpmu_bo)
264 return;
265
266 /* Get the firmware */
267 if (request_firmware(&fw, adreno_gpu->info->gpmufw, drm->dev)) {
268 DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n",
269 gpu->name);
270 return;
271 }
272
273 data = (unsigned int *) fw->data;
274
275 /*
276 * The first dword is the size of the remaining data in dwords. Use it
277 * as a checksum of sorts and make sure it matches the actual size of
278 * the firmware that we read
279 */
280
281 if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2)))
282 goto out;
283
284 /* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */
285 if (data[1] != 2)
286 goto out;
287
288 cmds = data + data[2] + 3;
289 cmds_size = data[0] - data[2] - 2;
290
291 /*
292 * A single type4 opcode can only have so many values attached so
293 * add enough opcodes to load the all the commands
294 */
295 bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2;
296
297 mutex_lock(&drm->struct_mutex);
298 a5xx_gpu->gpmu_bo = msm_gem_new(drm, bosize, MSM_BO_UNCACHED);
299 mutex_unlock(&drm->struct_mutex);
300
301 if (IS_ERR(a5xx_gpu->gpmu_bo))
302 goto err;
303
304 if (msm_gem_get_iova(a5xx_gpu->gpmu_bo, gpu->id, &a5xx_gpu->gpmu_iova))
305 goto err;
306
307 ptr = msm_gem_get_vaddr(a5xx_gpu->gpmu_bo);
308 if (!ptr)
309 goto err;
310
311 while (cmds_size > 0) {
312 int i;
313 uint32_t _size = cmds_size > TYPE4_MAX_PAYLOAD ?
314 TYPE4_MAX_PAYLOAD : cmds_size;
315
316 ptr[dwords++] = PKT4(REG_A5XX_GPMU_INST_RAM_BASE + offset,
317 _size);
318
319 for (i = 0; i < _size; i++)
320 ptr[dwords++] = *cmds++;
321
322 offset += _size;
323 cmds_size -= _size;
324 }
325
326 msm_gem_put_vaddr(a5xx_gpu->gpmu_bo);
327 a5xx_gpu->gpmu_dwords = dwords;
328
329 goto out;
330
331err:
332 if (a5xx_gpu->gpmu_iova)
333 msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->id);
334 if (a5xx_gpu->gpmu_bo)
335 drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo);
336
337 a5xx_gpu->gpmu_bo = NULL;
338 a5xx_gpu->gpmu_iova = 0;
339 a5xx_gpu->gpmu_dwords = 0;
340
341out:
342 /* No need to keep that firmware laying around anymore */
343 release_firmware(fw);
344}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 985d95fbb726..893eb2b2531b 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -82,6 +82,7 @@ static const struct adreno_info gpulist[] = {
82 .pfpfw = "a530_pfp.fw", 82 .pfpfw = "a530_pfp.fw",
83 .gmem = SZ_1M, 83 .gmem = SZ_1M,
84 .init = a5xx_gpu_init, 84 .init = a5xx_gpu_init,
85 .gpmufw = "a530v3_gpmu.fw2",
85 }, 86 },
86}; 87};
87 88
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 0d1f4e757f59..e8d55b0306ed 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -73,6 +73,7 @@ struct adreno_info {
73 uint32_t revn; 73 uint32_t revn;
74 const char *name; 74 const char *name;
75 const char *pm4fw, *pfpfw; 75 const char *pm4fw, *pfpfw;
76 const char *gpmufw;
76 uint32_t gmem; 77 uint32_t gmem;
77 struct msm_gpu *(*init)(struct drm_device *dev); 78 struct msm_gpu *(*init)(struct drm_device *dev);
78}; 79};