1/* 2 * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include "mdp5_kms.h" 15#include "mdp5_cfg.h" 16 17struct mdp5_cfg_handler { 18 int revision; 19 struct mdp5_cfg config; 20}; 21 22/* mdp5_cfg must be exposed (used in mdp5.xml.h) */ 23const struct mdp5_cfg_hw *mdp5_cfg = NULL; 24 25const struct mdp5_cfg_hw msm8x74_config = { 26 .name = "msm8x74", 27 .mdp = { 28 .count = 1, 29 .base = { 0x00100 }, 30 }, 31 .smp = { 32 .mmb_count = 22, 33 .mmb_size = 4096, 34 .clients = { 35 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7, 36 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 37 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18, 38 }, 39 }, 40 .ctl = { 41 .count = 5, 42 .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, 43 .flush_hw_mask = 0x0003ffff, 44 }, 45 .pipe_vig = { 46 .count = 3, 47 .base = { 0x01200, 0x01600, 0x01a00 }, 48 }, 49 .pipe_rgb = { 50 .count = 3, 51 .base = { 0x01e00, 0x02200, 0x02600 }, 52 }, 53 .pipe_dma = { 54 .count = 2, 55 .base = { 0x02a00, 0x02e00 }, 56 }, 57 .lm = { 58 .count = 5, 59 .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, 60 .nb_stages = 5, 61 }, 62 .dspp = { 63 .count = 3, 64 .base = { 0x04600, 0x04a00, 0x04e00 }, 65 }, 66 .ad = { 67 .count = 2, 68 .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */ 69 }, 70 .pp = { 71 .count = 3, 72 .base = { 0x12d00, 0x12e00, 0x12f00 }, 73 }, 74 .intf = { 75 .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, 76 .connect = { 77 [0] = INTF_eDP, 78 [1] = INTF_DSI, 79 [2] = INTF_DSI, 80 [3] = INTF_HDMI, 81 }, 82 }, 83 .max_clk = 200000000, 84}; 85 86const struct mdp5_cfg_hw apq8084_config = { 87 .name = "apq8084", 88 .mdp = { 89 .count = 1, 90 .base = { 0x00100 }, 91 }, 92 .smp = { 93 .mmb_count = 44, 94 .mmb_size = 8192, 95 .clients = { 96 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, 97 [SSPP_VIG2] = 7, [SSPP_VIG3] = 19, 98 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 99 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, 100 [SSPP_RGB2] = 18, [SSPP_RGB3] = 22, 101 }, 102 .reserved_state[0] = GENMASK(7, 0), /* first 8 MMBs */ 103 .reserved = { 104 /* Two SMP blocks are statically tied to RGB pipes: */ 105 [16] = 2, [17] = 2, [18] = 2, [22] = 2, 106 }, 107 }, 108 .ctl = { 109 .count = 5, 110 .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, 111 .flush_hw_mask = 0x003fffff, 112 }, 113 .pipe_vig = { 114 .count = 4, 115 .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 }, 116 }, 117 .pipe_rgb = { 118 .count = 4, 119 .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 }, 120 }, 121 .pipe_dma = { 122 .count = 2, 123 .base = { 0x03200, 0x03600 }, 124 }, 125 .lm = { 126 .count = 6, 127 .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 }, 128 .nb_stages = 5, 129 }, 130 .dspp = { 131 .count = 4, 132 .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 }, 133 134 }, 135 .ad = { 136 .count = 3, 137 .base = { 0x13500, 0x13700, 0x13900 }, 138 }, 139 .pp = { 140 .count = 4, 141 .base = { 0x12f00, 0x13000, 0x13100, 0x13200 }, 142 }, 143 .intf = { 144 .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, 145 .connect = { 146 [0] = INTF_eDP, 147 [1] = INTF_DSI, 148 [2] = INTF_DSI, 149 [3] = INTF_HDMI, 150 }, 151 }, 152 .max_clk = 320000000, 153}; 154 155const struct mdp5_cfg_hw msm8x16_config = { 156 .name = "msm8x16", 157 .mdp = { 158 .count = 1, 159 .base = { 0x01000 }, 160 }, 161 .smp = { 162 .mmb_count = 8, 163 .mmb_size = 8192, 164 .clients = { 165 [SSPP_VIG0] = 1, [SSPP_DMA0] = 4, 166 [SSPP_RGB0] = 7, [SSPP_RGB1] = 8, 167 }, 168 }, 169 .ctl = { 170 .count = 5, 171 .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, 172 .flush_hw_mask = 0x4003ffff, 173 }, 174 .pipe_vig = { 175 .count = 1, 176 .base = { 0x05000 }, 177 }, 178 .pipe_rgb = { 179 .count = 2, 180 .base = { 0x15000, 0x17000 }, 181 }, 182 .pipe_dma = { 183 .count = 1, 184 .base = { 0x25000 }, 185 }, 186 .lm = { 187 .count = 2, /* LM0 and LM3 */ 188 .base = { 0x45000, 0x48000 }, 189 .nb_stages = 5, 190 }, 191 .dspp = { 192 .count = 1, 193 .base = { 0x55000 }, 194 195 }, 196 .intf = { 197 .base = { 0x00000, 0x6b800 }, 198 .connect = { 199 [0] = INTF_DISABLED, 200 [1] = INTF_DSI, 201 }, 202 }, 203 .max_clk = 320000000, 204}; 205 206static const struct mdp5_cfg_handler cfg_handlers[] = { 207 { .revision = 0, .config = { .hw = &msm8x74_config } }, 208 { .revision = 2, .config = { .hw = &msm8x74_config } }, 209 { .revision = 3, .config = { .hw = &apq8084_config } }, 210 { .revision = 6, .config = { .hw = &msm8x16_config } }, 211}; 212 213 214static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); 215 216const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler) 217{ 218 return cfg_handler->config.hw; 219} 220 221struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler) 222{ 223 return &cfg_handler->config; 224} 225 226int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler) 227{ 228 return cfg_handler->revision; 229} 230 231void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler) 232{ 233 kfree(cfg_handler); 234} 235 236struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, 237 uint32_t major, uint32_t minor) 238{ 239 struct drm_device *dev = mdp5_kms->dev; 240 struct platform_device *pdev = dev->platformdev; 241 struct mdp5_cfg_handler *cfg_handler; 242 struct mdp5_cfg_platform *pconfig; 243 int i, ret = 0; 244 245 cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); 246 if (unlikely(!cfg_handler)) { 247 ret = -ENOMEM; 248 goto fail; 249 } 250 251 if (major != 1) { 252 dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n", 253 major, minor); 254 ret = -ENXIO; 255 goto fail; 256 } 257 258 /* only after mdp5_cfg global pointer's init can we access the hw */ 259 for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) { 260 if (cfg_handlers[i].revision != minor) 261 continue; 262 mdp5_cfg = cfg_handlers[i].config.hw; 263 264 break; 265 } 266 if (unlikely(!mdp5_cfg)) { 267 dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n", 268 major, minor); 269 ret = -ENXIO; 270 goto fail; 271 } 272 273 cfg_handler->revision = minor; 274 cfg_handler->config.hw = mdp5_cfg; 275 276 pconfig = mdp5_get_config(pdev); 277 memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig)); 278 279 DBG("MDP5: %s hw config selected", mdp5_cfg->name); 280 281 return cfg_handler; 282 283fail: 284 if (cfg_handler) 285 mdp5_cfg_destroy(cfg_handler); 286 287 return NULL; 288} 289 290static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) 291{ 292 static struct mdp5_cfg_platform config = {}; 293#ifdef CONFIG_OF 294 /* TODO */ 295#endif 296 config.iommu = iommu_domain_alloc(&platform_bus_type); 297 298 return &config; 299} 300