1/* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 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. 8 * 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 12 * more details. 13 * 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/>. 16 */ 17 18#ifndef __MDP5_KMS_H__ 19#define __MDP5_KMS_H__ 20 21#include "msm_drv.h" 22#include "msm_kms.h" 23#include "mdp/mdp_kms.h" 24#include "mdp5_cfg.h" /* must be included before mdp5.xml.h */ 25#include "mdp5.xml.h" 26#include "mdp5_ctl.h" 27#include "mdp5_smp.h" 28 29struct mdp5_kms { 30 struct mdp_kms base; 31 32 struct drm_device *dev; 33 34 struct mdp5_cfg_handler *cfg; 35 36 /* mapper-id used to request GEM buffer mapped for scanout: */ 37 int id; 38 struct msm_mmu *mmu; 39 40 struct mdp5_smp *smp; 41 struct mdp5_ctl_manager *ctlm; 42 43 /* io/register spaces: */ 44 void __iomem *mmio, *vbif; 45 46 struct regulator *vdd; 47 48 struct clk *axi_clk; 49 struct clk *ahb_clk; 50 struct clk *src_clk; 51 struct clk *core_clk; 52 struct clk *lut_clk; 53 struct clk *vsync_clk; 54 55 /* 56 * lock to protect access to global resources: ie., following register: 57 * - REG_MDP5_MDP_DISP_INTF_SEL 58 */ 59 spinlock_t resource_lock; 60 61 struct mdp_irq error_handler; 62 63 struct { 64 volatile unsigned long enabled_mask; 65 struct irq_domain *domain; 66 } irqcontroller; 67}; 68#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) 69 70struct mdp5_plane_state { 71 struct drm_plane_state base; 72 73 /* "virtual" zpos.. we calculate actual mixer-stage at runtime 74 * by sorting the attached planes by zpos and then assigning 75 * mixer stage lowest to highest. Private planes get default 76 * zpos of zero, and public planes a unique value that is 77 * greater than zero. This way, things work out if a naive 78 * userspace assigns planes to a crtc without setting zpos. 79 */ 80 int zpos; 81 82 /* the actual mixer stage, calculated in crtc->atomic_check() 83 * NOTE: this should move to mdp5_crtc_state, when that exists 84 */ 85 enum mdp_mixer_stage_id stage; 86 87 /* some additional transactional status to help us know in the 88 * apply path whether we need to update SMP allocation, and 89 * whether current update is still pending: 90 */ 91 bool mode_changed : 1; 92 bool pending : 1; 93}; 94#define to_mdp5_plane_state(x) \ 95 container_of(x, struct mdp5_plane_state, base) 96 97enum mdp5_intf_mode { 98 MDP5_INTF_MODE_NONE = 0, 99 100 /* Modes used for DSI interface (INTF_DSI type): */ 101 MDP5_INTF_DSI_MODE_VIDEO, 102 MDP5_INTF_DSI_MODE_COMMAND, 103 104 /* Modes used for WB interface (INTF_WB type): */ 105 MDP5_INTF_WB_MODE_BLOCK, 106 MDP5_INTF_WB_MODE_LINE, 107}; 108 109struct mdp5_interface { 110 int num; /* display interface number */ 111 enum mdp5_intf_type type; 112 enum mdp5_intf_mode mode; 113}; 114 115static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) 116{ 117 msm_writel(data, mdp5_kms->mmio + reg); 118} 119 120static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg) 121{ 122 return msm_readl(mdp5_kms->mmio + reg); 123} 124 125static inline const char *pipe2name(enum mdp5_pipe pipe) 126{ 127 static const char *names[] = { 128#define NAME(n) [SSPP_ ## n] = #n 129 NAME(VIG0), NAME(VIG1), NAME(VIG2), 130 NAME(RGB0), NAME(RGB1), NAME(RGB2), 131 NAME(DMA0), NAME(DMA1), 132 NAME(VIG3), NAME(RGB3), 133#undef NAME 134 }; 135 return names[pipe]; 136} 137 138static inline int pipe2nclients(enum mdp5_pipe pipe) 139{ 140 switch (pipe) { 141 case SSPP_RGB0: 142 case SSPP_RGB1: 143 case SSPP_RGB2: 144 case SSPP_RGB3: 145 return 1; 146 default: 147 return 3; 148 } 149} 150 151static inline uint32_t intf2err(int intf_num) 152{ 153 switch (intf_num) { 154 case 0: return MDP5_IRQ_INTF0_UNDER_RUN; 155 case 1: return MDP5_IRQ_INTF1_UNDER_RUN; 156 case 2: return MDP5_IRQ_INTF2_UNDER_RUN; 157 case 3: return MDP5_IRQ_INTF3_UNDER_RUN; 158 default: return 0; 159 } 160} 161 162#define GET_PING_PONG_ID(layer_mixer) ((layer_mixer == 5) ? 3 : layer_mixer) 163static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf) 164{ 165 /* 166 * In case of DSI Command Mode, the Ping Pong's read pointer IRQ 167 * acts as a Vblank signal. The Ping Pong buffer used is bound to 168 * layer mixer. 169 */ 170 171 if ((intf->type == INTF_DSI) && 172 (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) 173 return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm); 174 175 if (intf->type == INTF_WB) 176 return MDP5_IRQ_WB_2_DONE; 177 178 switch (intf->num) { 179 case 0: return MDP5_IRQ_INTF0_VSYNC; 180 case 1: return MDP5_IRQ_INTF1_VSYNC; 181 case 2: return MDP5_IRQ_INTF2_VSYNC; 182 case 3: return MDP5_IRQ_INTF3_VSYNC; 183 default: return 0; 184 } 185} 186 187static inline uint32_t lm2ppdone(int lm) 188{ 189 return MDP5_IRQ_PING_PONG_0_DONE << GET_PING_PONG_ID(lm); 190} 191 192int mdp5_disable(struct mdp5_kms *mdp5_kms); 193int mdp5_enable(struct mdp5_kms *mdp5_kms); 194 195void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); 196void mdp5_irq_preinstall(struct msm_kms *kms); 197int mdp5_irq_postinstall(struct msm_kms *kms); 198void mdp5_irq_uninstall(struct msm_kms *kms); 199irqreturn_t mdp5_irq(struct msm_kms *kms); 200int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); 201void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); 202int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms); 203void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms); 204 205static inline bool pipe_supports_yuv(enum mdp5_pipe pipe) 206{ 207 switch (pipe) { 208 case SSPP_VIG0: 209 case SSPP_VIG1: 210 case SSPP_VIG2: 211 case SSPP_VIG3: 212 return true; 213 default: 214 return false; 215 } 216} 217 218static inline 219uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats, 220 uint32_t max_formats) 221{ 222 return mdp_get_formats(pixel_formats, max_formats, 223 !pipe_supports_yuv(pipe)); 224} 225 226void mdp5_plane_install_properties(struct drm_plane *plane, 227 struct drm_mode_object *obj); 228uint32_t mdp5_plane_get_flush(struct drm_plane *plane); 229void mdp5_plane_complete_flip(struct drm_plane *plane); 230enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane); 231struct drm_plane *mdp5_plane_init(struct drm_device *dev, 232 enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset); 233 234uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc); 235 236int mdp5_crtc_get_lm(struct drm_crtc *crtc); 237struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc); 238void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); 239void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf); 240struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, 241 struct drm_plane *plane, int id); 242 243struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, 244 struct mdp5_interface *intf); 245int mdp5_encoder_set_split_display(struct drm_encoder *encoder, 246 struct drm_encoder *slave_encoder); 247 248#ifdef CONFIG_DRM_MSM_DSI 249struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev, 250 struct mdp5_interface *intf); 251int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, 252 struct drm_encoder *slave_encoder); 253#else 254static inline struct drm_encoder *mdp5_cmd_encoder_init( 255 struct drm_device *dev, struct mdp5_interface *intf) 256{ 257 return ERR_PTR(-EINVAL); 258} 259static inline int mdp5_cmd_encoder_set_split_display( 260 struct drm_encoder *encoder, struct drm_encoder *slave_encoder) 261{ 262 return -EINVAL; 263} 264#endif 265 266#endif /* __MDP5_KMS_H__ */ 267