573 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.4 * Copyright (C) 2013 Red Hat5 * Author: Rob Clark <robdclark@gmail.com>6 */7 8#ifndef __MSM_DRV_H__9#define __MSM_DRV_H__10 11#include <linux/kernel.h>12#include <linux/clk.h>13#include <linux/cpufreq.h>14#include <linux/devfreq.h>15#include <linux/module.h>16#include <linux/component.h>17#include <linux/platform_device.h>18#include <linux/pm.h>19#include <linux/pm_runtime.h>20#include <linux/slab.h>21#include <linux/list.h>22#include <linux/iommu.h>23#include <linux/types.h>24#include <linux/of_graph.h>25#include <linux/of_device.h>26#include <linux/sizes.h>27#include <linux/kthread.h>28 29#include <drm/drm_atomic.h>30#include <drm/drm_atomic_helper.h>31#include <drm/drm_probe_helper.h>32#include <drm/display/drm_dsc.h>33#include <drm/msm_drm.h>34#include <drm/drm_gem.h>35 36extern struct fault_attr fail_gem_alloc;37extern struct fault_attr fail_gem_iova;38 39struct msm_kms;40struct msm_gpu;41struct msm_mmu;42struct msm_mdss;43struct msm_rd_state;44struct msm_perf_state;45struct msm_gem_submit;46struct msm_fence_context;47struct msm_gem_address_space;48struct msm_gem_vma;49struct msm_disp_state;50 51#define MAX_CRTCS 852#define MAX_BRIDGES 853 54#define FRAC_16_16(mult, div) (((mult) << 16) / (div))55 56enum msm_dp_controller {57 MSM_DP_CONTROLLER_0,58 MSM_DP_CONTROLLER_1,59 MSM_DP_CONTROLLER_2,60 MSM_DP_CONTROLLER_3,61 MSM_DP_CONTROLLER_COUNT,62};63 64enum msm_dsi_controller {65 MSM_DSI_CONTROLLER_0,66 MSM_DSI_CONTROLLER_1,67 MSM_DSI_CONTROLLER_COUNT,68};69 70#define MSM_GPU_MAX_RINGS 471#define MAX_H_TILES_PER_DISPLAY 272 73/**74 * struct msm_display_topology - defines a display topology pipeline75 * @num_lm: number of layer mixers used76 * @num_intf: number of interfaces the panel is mounted on77 * @num_dspp: number of dspp blocks used78 * @num_dsc: number of Display Stream Compression (DSC) blocks used79 * @needs_cdm: indicates whether cdm block is needed for this display topology80 */81struct msm_display_topology {82 u32 num_lm;83 u32 num_intf;84 u32 num_dspp;85 u32 num_dsc;86 bool needs_cdm;87};88 89/* Commit/Event thread specific structure */90struct msm_drm_thread {91 struct drm_device *dev;92 struct kthread_worker *worker;93};94 95struct msm_drm_private {96 97 struct drm_device *dev;98 99 struct msm_kms *kms;100 int (*kms_init)(struct drm_device *dev);101 102 /* subordinate devices, if present: */103 struct platform_device *gpu_pdev;104 105 /* possibly this should be in the kms component, but it is106 * shared by both mdp4 and mdp5..107 */108 struct hdmi *hdmi;109 110 /* DSI is shared by mdp4 and mdp5 */111 struct msm_dsi *dsi[MSM_DSI_CONTROLLER_COUNT];112 113 struct msm_dp *dp[MSM_DP_CONTROLLER_COUNT];114 115 /* when we have more than one 'msm_gpu' these need to be an array: */116 struct msm_gpu *gpu;117 118 /* gpu is only set on open(), but we need this info earlier */119 bool is_a2xx;120 bool has_cached_coherent;121 122 struct msm_rd_state *rd; /* debugfs to dump all submits */123 struct msm_rd_state *hangrd; /* debugfs to dump hanging submits */124 struct msm_perf_state *perf;125 126 /**127 * total_mem: Total/global amount of memory backing GEM objects.128 */129 atomic64_t total_mem;130 131 /**132 * List of all GEM objects (mainly for debugfs, protected by obj_lock133 * (acquire before per GEM object lock)134 */135 struct list_head objects;136 struct mutex obj_lock;137 138 /**139 * lru:140 *141 * The various LRU's that a GEM object is in at various stages of142 * it's lifetime. Objects start out in the unbacked LRU. When143 * pinned (for scannout or permanently mapped GPU buffers, like144 * ringbuffer, memptr, fw, etc) it moves to the pinned LRU. When145 * unpinned, it moves into willneed or dontneed LRU depending on146 * madvise state. When backing pages are evicted (willneed) or147 * purged (dontneed) it moves back into the unbacked LRU.148 *149 * The dontneed LRU is considered by the shrinker for objects150 * that are candidate for purging, and the willneed LRU is151 * considered for objects that could be evicted.152 */153 struct {154 /**155 * unbacked:156 *157 * The LRU for GEM objects without backing pages allocated.158 * This mostly exists so that objects are always is one159 * LRU.160 */161 struct drm_gem_lru unbacked;162 163 /**164 * pinned:165 *166 * The LRU for pinned GEM objects167 */168 struct drm_gem_lru pinned;169 170 /**171 * willneed:172 *173 * The LRU for unpinned GEM objects which are in madvise174 * WILLNEED state (ie. can be evicted)175 */176 struct drm_gem_lru willneed;177 178 /**179 * dontneed:180 *181 * The LRU for unpinned GEM objects which are in madvise182 * DONTNEED state (ie. can be purged)183 */184 struct drm_gem_lru dontneed;185 186 /**187 * lock:188 *189 * Protects manipulation of all of the LRUs.190 */191 struct mutex lock;192 } lru;193 194 struct workqueue_struct *wq;195 196 unsigned int num_crtcs;197 198 struct msm_drm_thread event_thread[MAX_CRTCS];199 200 /* VRAM carveout, used when no IOMMU: */201 struct {202 unsigned long size;203 dma_addr_t paddr;204 /* NOTE: mm managed at the page level, size is in # of pages205 * and position mm_node->start is in # of pages:206 */207 struct drm_mm mm;208 spinlock_t lock; /* Protects drm_mm node allocation/removal */209 } vram;210 211 struct notifier_block vmap_notifier;212 struct shrinker *shrinker;213 214 /**215 * hangcheck_period: For hang detection, in ms216 *217 * Note that in practice, a submit/job will get at least two hangcheck218 * periods, due to checking for progress being implemented as simply219 * "have the CP position registers changed since last time?"220 */221 unsigned int hangcheck_period;222 223 /** gpu_devfreq_config: Devfreq tuning config for the GPU. */224 struct devfreq_simple_ondemand_data gpu_devfreq_config;225 226 /**227 * gpu_clamp_to_idle: Enable clamping to idle freq when inactive228 */229 bool gpu_clamp_to_idle;230 231 /**232 * disable_err_irq:233 *234 * Disable handling of GPU hw error interrupts, to force fallback to235 * sw hangcheck timer. Written (via debugfs) by igt tests to test236 * the sw hangcheck mechanism.237 */238 bool disable_err_irq;239};240 241const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format, uint64_t modifier);242 243struct msm_pending_timer;244 245int msm_atomic_init_pending_timer(struct msm_pending_timer *timer,246 struct msm_kms *kms, int crtc_idx);247void msm_atomic_destroy_pending_timer(struct msm_pending_timer *timer);248void msm_atomic_commit_tail(struct drm_atomic_state *state);249int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);250struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev);251 252int msm_crtc_enable_vblank(struct drm_crtc *crtc);253void msm_crtc_disable_vblank(struct drm_crtc *crtc);254 255int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);256void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);257 258struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev);259bool msm_use_mmu(struct drm_device *dev);260 261int msm_ioctl_gem_submit(struct drm_device *dev, void *data,262 struct drm_file *file);263 264#ifdef CONFIG_DEBUG_FS265unsigned long msm_gem_shrinker_shrink(struct drm_device *dev, unsigned long nr_to_scan);266#endif267 268int msm_gem_shrinker_init(struct drm_device *dev);269void msm_gem_shrinker_cleanup(struct drm_device *dev);270 271struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);272int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);273void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);274struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,275 struct dma_buf_attachment *attach, struct sg_table *sg);276int msm_gem_prime_pin(struct drm_gem_object *obj);277void msm_gem_prime_unpin(struct drm_gem_object *obj);278 279int msm_framebuffer_prepare(struct drm_framebuffer *fb,280 struct msm_gem_address_space *aspace, bool needs_dirtyfb);281void msm_framebuffer_cleanup(struct drm_framebuffer *fb,282 struct msm_gem_address_space *aspace, bool needed_dirtyfb);283uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,284 struct msm_gem_address_space *aspace, int plane);285struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);286const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);287struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,288 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);289struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev,290 int w, int h, int p, uint32_t format);291 292#ifdef CONFIG_DRM_FBDEV_EMULATION293void msm_fbdev_setup(struct drm_device *dev);294#else295static inline void msm_fbdev_setup(struct drm_device *dev)296{297}298#endif299 300struct hdmi;301#ifdef CONFIG_DRM_MSM_HDMI302int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,303 struct drm_encoder *encoder);304void __init msm_hdmi_register(void);305void __exit msm_hdmi_unregister(void);306#else307static inline int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,308 struct drm_encoder *encoder)309{310 return -EINVAL;311}312static inline void __init msm_hdmi_register(void) {}313static inline void __exit msm_hdmi_unregister(void) {}314#endif315 316struct msm_dsi;317#ifdef CONFIG_DRM_MSM_DSI318int dsi_dev_attach(struct platform_device *pdev);319void dsi_dev_detach(struct platform_device *pdev);320void __init msm_dsi_register(void);321void __exit msm_dsi_unregister(void);322int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,323 struct drm_encoder *encoder);324void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi);325bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi);326bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);327bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);328bool msm_dsi_wide_bus_enabled(struct msm_dsi *msm_dsi);329struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);330const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi);331#else332static inline void __init msm_dsi_register(void)333{334}335static inline void __exit msm_dsi_unregister(void)336{337}338static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,339 struct drm_device *dev,340 struct drm_encoder *encoder)341{342 return -EINVAL;343}344static inline void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi)345{346}347static inline bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)348{349 return false;350}351static inline bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi)352{353 return false;354}355static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)356{357 return false;358}359static inline bool msm_dsi_wide_bus_enabled(struct msm_dsi *msm_dsi)360{361 return false;362}363 364static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)365{366 return NULL;367}368 369static inline const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi)370{371 return NULL;372}373#endif374 375#ifdef CONFIG_DRM_MSM_DP376int __init msm_dp_register(void);377void __exit msm_dp_unregister(void);378int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,379 struct drm_encoder *encoder, bool yuv_supported);380void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display);381bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,382 const struct drm_display_mode *mode);383bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,384 const struct drm_display_mode *mode);385bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);386 387#else388static inline int __init msm_dp_register(void)389{390 return -EINVAL;391}392static inline void __exit msm_dp_unregister(void)393{394}395static inline int msm_dp_modeset_init(struct msm_dp *dp_display,396 struct drm_device *dev,397 struct drm_encoder *encoder,398 bool yuv_supported)399{400 return -EINVAL;401}402 403static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display)404{405}406 407static inline bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,408 const struct drm_display_mode *mode)409{410 return false;411}412 413static inline bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,414 const struct drm_display_mode *mode)415{416 return false;417}418 419static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)420{421 return false;422}423 424#endif425 426#ifdef CONFIG_DRM_MSM_MDP4427void msm_mdp4_register(void);428void msm_mdp4_unregister(void);429#else430static inline void msm_mdp4_register(void) {}431static inline void msm_mdp4_unregister(void) {}432#endif433 434#ifdef CONFIG_DRM_MSM_MDP5435void msm_mdp_register(void);436void msm_mdp_unregister(void);437#else438static inline void msm_mdp_register(void) {}439static inline void msm_mdp_unregister(void) {}440#endif441 442#ifdef CONFIG_DRM_MSM_DPU443void msm_dpu_register(void);444void msm_dpu_unregister(void);445#else446static inline void msm_dpu_register(void) {}447static inline void msm_dpu_unregister(void) {}448#endif449 450#ifdef CONFIG_DRM_MSM_MDSS451void msm_mdss_register(void);452void msm_mdss_unregister(void);453#else454static inline void msm_mdss_register(void) {}455static inline void msm_mdss_unregister(void) {}456#endif457 458#ifdef CONFIG_DEBUG_FS459void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);460int msm_debugfs_late_init(struct drm_device *dev);461int msm_rd_debugfs_init(struct drm_minor *minor);462void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);463__printf(3, 4)464void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,465 const char *fmt, ...);466int msm_perf_debugfs_init(struct drm_minor *minor);467void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);468#else469static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }470__printf(3, 4)471static inline void msm_rd_dump_submit(struct msm_rd_state *rd,472 struct msm_gem_submit *submit,473 const char *fmt, ...) {}474static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {}475static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {}476#endif477 478struct clk *msm_clk_get(struct platform_device *pdev, const char *name);479 480struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count,481 const char *name);482void __iomem *msm_ioremap(struct platform_device *pdev, const char *name);483void __iomem *msm_ioremap_size(struct platform_device *pdev, const char *name,484 phys_addr_t *size);485void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name);486void __iomem *msm_ioremap_mdss(struct platform_device *mdss_pdev,487 struct platform_device *dev,488 const char *name);489 490struct icc_path *msm_icc_get(struct device *dev, const char *name);491 492static inline void msm_rmw(void __iomem *addr, u32 mask, u32 or)493{494 u32 val = readl(addr);495 496 val &= ~mask;497 writel(val | or, addr);498}499 500/**501 * struct msm_hrtimer_work - a helper to combine an hrtimer with kthread_work502 *503 * @timer: hrtimer to control when the kthread work is triggered504 * @work: the kthread work505 * @worker: the kthread worker the work will be scheduled on506 */507struct msm_hrtimer_work {508 struct hrtimer timer;509 struct kthread_work work;510 struct kthread_worker *worker;511};512 513void msm_hrtimer_queue_work(struct msm_hrtimer_work *work,514 ktime_t wakeup_time,515 enum hrtimer_mode mode);516void msm_hrtimer_work_init(struct msm_hrtimer_work *work,517 struct kthread_worker *worker,518 kthread_work_func_t fn,519 clockid_t clock_id,520 enum hrtimer_mode mode);521 522#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)523#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)524 525static inline int align_pitch(int width, int bpp)526{527 int bytespp = (bpp + 7) / 8;528 /* adreno needs pitch aligned to 32 pixels: */529 return bytespp * ALIGN(width, 32);530}531 532/* for the generated headers: */533#define INVALID_IDX(idx) ({BUG(); 0;})534#define fui(x) ({BUG(); 0;})535#define _mesa_float_to_half(x) ({BUG(); 0;})536 537 538#define FIELD(val, name) (((val) & name ## __MASK) >> name ## __SHIFT)539 540/* for conditionally setting boolean flag(s): */541#define COND(bool, val) ((bool) ? (val) : 0)542 543static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)544{545 ktime_t now = ktime_get();546 s64 remaining_jiffies;547 548 if (ktime_compare(*timeout, now) < 0) {549 remaining_jiffies = 0;550 } else {551 ktime_t rem = ktime_sub(*timeout, now);552 remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ);553 }554 555 return clamp(remaining_jiffies, 1LL, (s64)INT_MAX);556}557 558/* Driver helpers */559 560extern const struct component_master_ops msm_drm_ops;561 562int msm_kms_pm_prepare(struct device *dev);563void msm_kms_pm_complete(struct device *dev);564 565int msm_drv_probe(struct device *dev,566 int (*kms_init)(struct drm_device *dev),567 struct msm_kms *kms);568void msm_kms_shutdown(struct platform_device *pdev);569 570bool msm_disp_drv_should_bind(struct device *dev, bool dpu_driver);571 572#endif /* __MSM_DRV_H__ */573