2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
27 #ifdef CONFIG_MSM_BUS_SCALING
28 #include <mach/board.h>
29 static void bs_init(struct msm_gpu
*gpu
)
31 if (gpu
->bus_scale_table
) {
32 gpu
->bsc
= msm_bus_scale_register_client(gpu
->bus_scale_table
);
33 DBG("bus scale client: %08x", gpu
->bsc
);
37 static void bs_fini(struct msm_gpu
*gpu
)
40 msm_bus_scale_unregister_client(gpu
->bsc
);
45 static void bs_set(struct msm_gpu
*gpu
, int idx
)
48 DBG("set bus scaling: %d", idx
);
49 msm_bus_scale_client_update_request(gpu
->bsc
, idx
);
53 static void bs_init(struct msm_gpu
*gpu
) {}
54 static void bs_fini(struct msm_gpu
*gpu
) {}
55 static void bs_set(struct msm_gpu
*gpu
, int idx
) {}
58 static int enable_pwrrail(struct msm_gpu
*gpu
)
60 struct drm_device
*dev
= gpu
->dev
;
64 ret
= regulator_enable(gpu
->gpu_reg
);
66 dev_err(dev
->dev
, "failed to enable 'gpu_reg': %d\n", ret
);
72 ret
= regulator_enable(gpu
->gpu_cx
);
74 dev_err(dev
->dev
, "failed to enable 'gpu_cx': %d\n", ret
);
82 static int disable_pwrrail(struct msm_gpu
*gpu
)
85 regulator_disable(gpu
->gpu_cx
);
87 regulator_disable(gpu
->gpu_reg
);
91 static int enable_clk(struct msm_gpu
*gpu
)
93 struct clk
*rate_clk
= NULL
;
96 /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */
97 for (i
= ARRAY_SIZE(gpu
->grp_clks
) - 1; i
> 0; i
--) {
98 if (gpu
->grp_clks
[i
]) {
99 clk_prepare(gpu
->grp_clks
[i
]);
100 rate_clk
= gpu
->grp_clks
[i
];
104 if (rate_clk
&& gpu
->fast_rate
)
105 clk_set_rate(rate_clk
, gpu
->fast_rate
);
107 for (i
= ARRAY_SIZE(gpu
->grp_clks
) - 1; i
> 0; i
--)
108 if (gpu
->grp_clks
[i
])
109 clk_enable(gpu
->grp_clks
[i
]);
114 static int disable_clk(struct msm_gpu
*gpu
)
116 struct clk
*rate_clk
= NULL
;
119 /* NOTE: kgsl_pwrctrl_clk() ignores grp_clks[0].. */
120 for (i
= ARRAY_SIZE(gpu
->grp_clks
) - 1; i
> 0; i
--) {
121 if (gpu
->grp_clks
[i
]) {
122 clk_disable(gpu
->grp_clks
[i
]);
123 rate_clk
= gpu
->grp_clks
[i
];
127 if (rate_clk
&& gpu
->slow_rate
)
128 clk_set_rate(rate_clk
, gpu
->slow_rate
);
130 for (i
= ARRAY_SIZE(gpu
->grp_clks
) - 1; i
> 0; i
--)
131 if (gpu
->grp_clks
[i
])
132 clk_unprepare(gpu
->grp_clks
[i
]);
137 static int enable_axi(struct msm_gpu
*gpu
)
140 clk_prepare_enable(gpu
->ebi1_clk
);
142 bs_set(gpu
, gpu
->bus_freq
);
146 static int disable_axi(struct msm_gpu
*gpu
)
149 clk_disable_unprepare(gpu
->ebi1_clk
);
155 int msm_gpu_pm_resume(struct msm_gpu
*gpu
)
159 DBG("%s", gpu
->name
);
161 ret
= enable_pwrrail(gpu
);
165 ret
= enable_clk(gpu
);
169 ret
= enable_axi(gpu
);
176 int msm_gpu_pm_suspend(struct msm_gpu
*gpu
)
180 DBG("%s", gpu
->name
);
182 ret
= disable_axi(gpu
);
186 ret
= disable_clk(gpu
);
190 ret
= disable_pwrrail(gpu
);
198 * Hangcheck detection for locked gpu:
201 static void recover_worker(struct work_struct
*work
)
203 struct msm_gpu
*gpu
= container_of(work
, struct msm_gpu
, recover_work
);
204 struct drm_device
*dev
= gpu
->dev
;
206 dev_err(dev
->dev
, "%s: hangcheck recover!\n", gpu
->name
);
208 mutex_lock(&dev
->struct_mutex
);
209 gpu
->funcs
->recover(gpu
);
210 mutex_unlock(&dev
->struct_mutex
);
215 static void hangcheck_timer_reset(struct msm_gpu
*gpu
)
217 DBG("%s", gpu
->name
);
218 mod_timer(&gpu
->hangcheck_timer
,
219 round_jiffies_up(jiffies
+ DRM_MSM_HANGCHECK_JIFFIES
));
222 static void hangcheck_handler(unsigned long data
)
224 struct msm_gpu
*gpu
= (struct msm_gpu
*)data
;
225 struct drm_device
*dev
= gpu
->dev
;
226 struct msm_drm_private
*priv
= dev
->dev_private
;
227 uint32_t fence
= gpu
->funcs
->last_fence(gpu
);
229 if (fence
!= gpu
->hangcheck_fence
) {
230 /* some progress has been made.. ya! */
231 gpu
->hangcheck_fence
= fence
;
232 } else if (fence
< gpu
->submitted_fence
) {
233 /* no progress and not done.. hung! */
234 gpu
->hangcheck_fence
= fence
;
235 dev_err(dev
->dev
, "%s: hangcheck detected gpu lockup!\n",
237 dev_err(dev
->dev
, "%s: completed fence: %u\n",
239 dev_err(dev
->dev
, "%s: submitted fence: %u\n",
240 gpu
->name
, gpu
->submitted_fence
);
241 queue_work(priv
->wq
, &gpu
->recover_work
);
244 /* if still more pending work, reset the hangcheck timer: */
245 if (gpu
->submitted_fence
> gpu
->hangcheck_fence
)
246 hangcheck_timer_reset(gpu
);
248 /* workaround for missing irq: */
249 queue_work(priv
->wq
, &gpu
->retire_work
);
253 * Cmdstream submission/retirement:
256 static void retire_worker(struct work_struct
*work
)
258 struct msm_gpu
*gpu
= container_of(work
, struct msm_gpu
, retire_work
);
259 struct drm_device
*dev
= gpu
->dev
;
260 uint32_t fence
= gpu
->funcs
->last_fence(gpu
);
262 msm_update_fence(gpu
->dev
, fence
);
264 mutex_lock(&dev
->struct_mutex
);
266 while (!list_empty(&gpu
->active_list
)) {
267 struct msm_gem_object
*obj
;
269 obj
= list_first_entry(&gpu
->active_list
,
270 struct msm_gem_object
, mm_list
);
272 if ((obj
->read_fence
<= fence
) &&
273 (obj
->write_fence
<= fence
)) {
274 /* move to inactive: */
275 msm_gem_move_to_inactive(&obj
->base
);
276 msm_gem_put_iova(&obj
->base
, gpu
->id
);
277 drm_gem_object_unreference(&obj
->base
);
283 mutex_unlock(&dev
->struct_mutex
);
286 /* call from irq handler to schedule work to retire bo's */
287 void msm_gpu_retire(struct msm_gpu
*gpu
)
289 struct msm_drm_private
*priv
= gpu
->dev
->dev_private
;
290 queue_work(priv
->wq
, &gpu
->retire_work
);
293 /* add bo's to gpu's ring, and kick gpu: */
294 int msm_gpu_submit(struct msm_gpu
*gpu
, struct msm_gem_submit
*submit
,
295 struct msm_file_private
*ctx
)
297 struct drm_device
*dev
= gpu
->dev
;
298 struct msm_drm_private
*priv
= dev
->dev_private
;
301 submit
->fence
= ++priv
->next_fence
;
303 gpu
->submitted_fence
= submit
->fence
;
305 ret
= gpu
->funcs
->submit(gpu
, submit
, ctx
);
308 for (i
= 0; i
< submit
->nr_bos
; i
++) {
309 struct msm_gem_object
*msm_obj
= submit
->bos
[i
].obj
;
311 /* can't happen yet.. but when we add 2d support we'll have
312 * to deal w/ cross-ring synchronization:
314 WARN_ON(is_active(msm_obj
) && (msm_obj
->gpu
!= gpu
));
316 if (!is_active(msm_obj
)) {
319 /* ring takes a reference to the bo and iova: */
320 drm_gem_object_reference(&msm_obj
->base
);
321 msm_gem_get_iova_locked(&msm_obj
->base
,
322 submit
->gpu
->id
, &iova
);
325 if (submit
->bos
[i
].flags
& MSM_SUBMIT_BO_READ
)
326 msm_gem_move_to_active(&msm_obj
->base
, gpu
, false, submit
->fence
);
328 if (submit
->bos
[i
].flags
& MSM_SUBMIT_BO_WRITE
)
329 msm_gem_move_to_active(&msm_obj
->base
, gpu
, true, submit
->fence
);
331 hangcheck_timer_reset(gpu
);
340 static irqreturn_t
irq_handler(int irq
, void *data
)
342 struct msm_gpu
*gpu
= data
;
343 return gpu
->funcs
->irq(gpu
);
346 static const char *clk_names
[] = {
347 "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
350 int msm_gpu_init(struct drm_device
*drm
, struct platform_device
*pdev
,
351 struct msm_gpu
*gpu
, const struct msm_gpu_funcs
*funcs
,
352 const char *name
, const char *ioname
, const char *irqname
, int ringsz
)
354 struct iommu_domain
*iommu
;
361 INIT_LIST_HEAD(&gpu
->active_list
);
362 INIT_WORK(&gpu
->retire_work
, retire_worker
);
363 INIT_WORK(&gpu
->recover_work
, recover_worker
);
365 setup_timer(&gpu
->hangcheck_timer
, hangcheck_handler
,
368 BUG_ON(ARRAY_SIZE(clk_names
) != ARRAY_SIZE(gpu
->grp_clks
));
371 gpu
->mmio
= msm_ioremap(pdev
, ioname
, name
);
372 if (IS_ERR(gpu
->mmio
)) {
373 ret
= PTR_ERR(gpu
->mmio
);
378 gpu
->irq
= platform_get_irq_byname(pdev
, irqname
);
381 dev_err(drm
->dev
, "failed to get irq: %d\n", ret
);
385 ret
= devm_request_irq(&pdev
->dev
, gpu
->irq
, irq_handler
,
386 IRQF_TRIGGER_HIGH
, gpu
->name
, gpu
);
388 dev_err(drm
->dev
, "failed to request IRQ%u: %d\n", gpu
->irq
, ret
);
392 /* Acquire clocks: */
393 for (i
= 0; i
< ARRAY_SIZE(clk_names
); i
++) {
394 gpu
->grp_clks
[i
] = devm_clk_get(&pdev
->dev
, clk_names
[i
]);
395 DBG("grp_clks[%s]: %p", clk_names
[i
], gpu
->grp_clks
[i
]);
396 if (IS_ERR(gpu
->grp_clks
[i
]))
397 gpu
->grp_clks
[i
] = NULL
;
400 gpu
->ebi1_clk
= devm_clk_get(&pdev
->dev
, "bus_clk");
401 DBG("ebi1_clk: %p", gpu
->ebi1_clk
);
402 if (IS_ERR(gpu
->ebi1_clk
))
403 gpu
->ebi1_clk
= NULL
;
405 /* Acquire regulators: */
406 gpu
->gpu_reg
= devm_regulator_get(&pdev
->dev
, "vdd");
407 DBG("gpu_reg: %p", gpu
->gpu_reg
);
408 if (IS_ERR(gpu
->gpu_reg
))
411 gpu
->gpu_cx
= devm_regulator_get(&pdev
->dev
, "vddcx");
412 DBG("gpu_cx: %p", gpu
->gpu_cx
);
413 if (IS_ERR(gpu
->gpu_cx
))
416 /* Setup IOMMU.. eventually we will (I think) do this once per context
417 * and have separate page tables per context. For now, to keep things
418 * simple and to get something working, just use a single address space:
420 iommu
= iommu_domain_alloc(&platform_bus_type
);
422 dev_info(drm
->dev
, "%s: using IOMMU\n", name
);
423 gpu
->mmu
= msm_iommu_new(drm
, iommu
);
425 dev_info(drm
->dev
, "%s: no IOMMU, fallback to VRAM carveout!\n", name
);
427 gpu
->id
= msm_register_mmu(drm
, gpu
->mmu
);
429 /* Create ringbuffer: */
430 gpu
->rb
= msm_ringbuffer_new(gpu
, ringsz
);
431 if (IS_ERR(gpu
->rb
)) {
432 ret
= PTR_ERR(gpu
->rb
);
434 dev_err(drm
->dev
, "could not create ringbuffer: %d\n", ret
);
438 ret
= msm_gem_get_iova_locked(gpu
->rb
->bo
, gpu
->id
, &gpu
->rb_iova
);
441 dev_err(drm
->dev
, "could not map ringbuffer: %d\n", ret
);
453 void msm_gpu_cleanup(struct msm_gpu
*gpu
)
455 DBG("%s", gpu
->name
);
457 WARN_ON(!list_empty(&gpu
->active_list
));
463 msm_gem_put_iova(gpu
->rb
->bo
, gpu
->id
);
464 msm_ringbuffer_destroy(gpu
->rb
);
468 gpu
->mmu
->funcs
->destroy(gpu
->mmu
);