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 __MDP4_KMS_H__ 19#define __MDP4_KMS_H__ 20 21#include "msm_drv.h" 22#include "msm_kms.h" 23#include "mdp/mdp_kms.h" 24#include "mdp4.xml.h" 25 26#include "drm_panel.h" 27 28struct mdp4_kms { 29 struct mdp_kms base; 30 31 struct drm_device *dev; 32 33 int rev; 34 35 /* mapper-id used to request GEM buffer mapped for scanout: */ 36 int id; 37 38 void __iomem *mmio; 39 40 struct regulator *dsi_pll_vdda; 41 struct regulator *dsi_pll_vddio; 42 struct regulator *vdd; 43 44 struct clk *clk; 45 struct clk *pclk; 46 struct clk *lut_clk; 47 struct clk *axi_clk; 48 49 struct mdp_irq error_handler; 50 51 /* empty/blank cursor bo to use when cursor is "disabled" */ 52 struct drm_gem_object *blank_cursor_bo; 53 uint32_t blank_cursor_iova; 54}; 55#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) 56 57/* platform config data (ie. from DT, or pdata) */ 58struct mdp4_platform_config { 59 struct iommu_domain *iommu; 60 uint32_t max_clk; 61}; 62 63static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data) 64{ 65 msm_writel(data, mdp4_kms->mmio + reg); 66} 67 68static inline u32 mdp4_read(struct mdp4_kms *mdp4_kms, u32 reg) 69{ 70 return msm_readl(mdp4_kms->mmio + reg); 71} 72 73static inline uint32_t pipe2flush(enum mdp4_pipe pipe) 74{ 75 switch (pipe) { 76 case VG1: return MDP4_OVERLAY_FLUSH_VG1; 77 case VG2: return MDP4_OVERLAY_FLUSH_VG2; 78 case RGB1: return MDP4_OVERLAY_FLUSH_RGB1; 79 case RGB2: return MDP4_OVERLAY_FLUSH_RGB2; 80 default: return 0; 81 } 82} 83 84static inline uint32_t ovlp2flush(int ovlp) 85{ 86 switch (ovlp) { 87 case 0: return MDP4_OVERLAY_FLUSH_OVLP0; 88 case 1: return MDP4_OVERLAY_FLUSH_OVLP1; 89 default: return 0; 90 } 91} 92 93static inline uint32_t dma2irq(enum mdp4_dma dma) 94{ 95 switch (dma) { 96 case DMA_P: return MDP4_IRQ_DMA_P_DONE; 97 case DMA_S: return MDP4_IRQ_DMA_S_DONE; 98 case DMA_E: return MDP4_IRQ_DMA_E_DONE; 99 default: return 0; 100 } 101} 102 103static inline uint32_t dma2err(enum mdp4_dma dma) 104{ 105 switch (dma) { 106 case DMA_P: return MDP4_IRQ_PRIMARY_INTF_UDERRUN; 107 case DMA_S: return 0; // ??? 108 case DMA_E: return MDP4_IRQ_EXTERNAL_INTF_UDERRUN; 109 default: return 0; 110 } 111} 112 113static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer, 114 enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage) 115{ 116 switch (pipe) { 117 case VG1: 118 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK | 119 MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1); 120 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) | 121 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1); 122 break; 123 case VG2: 124 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK | 125 MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1); 126 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) | 127 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1); 128 break; 129 case RGB1: 130 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK | 131 MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1); 132 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) | 133 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1); 134 break; 135 case RGB2: 136 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK | 137 MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1); 138 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) | 139 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1); 140 break; 141 case RGB3: 142 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK | 143 MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1); 144 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) | 145 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1); 146 break; 147 case VG3: 148 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK | 149 MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1); 150 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) | 151 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1); 152 break; 153 case VG4: 154 mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK | 155 MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); 156 mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) | 157 COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); 158 break; 159 default: 160 WARN_ON("invalid pipe"); 161 break; 162 } 163 164 return mixer_cfg; 165} 166 167int mdp4_disable(struct mdp4_kms *mdp4_kms); 168int mdp4_enable(struct mdp4_kms *mdp4_kms); 169 170void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); 171void mdp4_irq_preinstall(struct msm_kms *kms); 172int mdp4_irq_postinstall(struct msm_kms *kms); 173void mdp4_irq_uninstall(struct msm_kms *kms); 174irqreturn_t mdp4_irq(struct msm_kms *kms); 175int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); 176void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); 177 178static inline bool pipe_supports_yuv(enum mdp4_pipe pipe) 179{ 180 switch (pipe) { 181 case VG1: 182 case VG2: 183 case VG3: 184 case VG4: 185 return true; 186 default: 187 return false; 188 } 189} 190 191static inline 192uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, 193 uint32_t max_formats) 194{ 195 return mdp_get_formats(pixel_formats, max_formats, 196 !pipe_supports_yuv(pipe_id)); 197} 198 199void mdp4_plane_install_properties(struct drm_plane *plane, 200 struct drm_mode_object *obj); 201enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane); 202struct drm_plane *mdp4_plane_init(struct drm_device *dev, 203 enum mdp4_pipe pipe_id, bool private_plane); 204 205uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); 206void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); 207void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); 208void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer); 209struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, 210 struct drm_plane *plane, int id, int ovlp_id, 211 enum mdp4_dma dma_id); 212 213long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate); 214struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev); 215 216long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate); 217struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, 218 struct drm_panel *panel); 219 220struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, 221 struct drm_panel *panel, struct drm_encoder *encoder); 222 223#ifdef CONFIG_COMMON_CLK 224struct clk *mpd4_lvds_pll_init(struct drm_device *dev); 225#else 226static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev) 227{ 228 return ERR_PTR(-ENODEV); 229} 230#endif 231 232#ifdef CONFIG_MSM_BUS_SCALING 233static inline int match_dev_name(struct device *dev, void *data) 234{ 235 return !strcmp(dev_name(dev), data); 236} 237/* bus scaling data is associated with extra pointless platform devices, 238 * "dtv", etc.. this is a bit of a hack, but we need a way for encoders 239 * to find their pdata to make the bus-scaling stuff work. 240 */ 241static inline void *mdp4_find_pdata(const char *devname) 242{ 243 struct device *dev; 244 dev = bus_find_device(&platform_bus_type, NULL, 245 (void *)devname, match_dev_name); 246 return dev ? dev->platform_data : NULL; 247} 248#endif 249 250#endif /* __MDP4_KMS_H__ */ 251