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 msm8x74v1_config = { 26 .name = "msm8x74v1", 27 .mdp = { 28 .count = 1, 29 .base = { 0x00100 }, 30 .caps = MDP_CAP_SMP | 31 0, 32 }, 33 .smp = { 34 .mmb_count = 22, 35 .mmb_size = 4096, 36 .clients = { 37 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7, 38 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 39 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18, 40 }, 41 }, 42 .ctl = { 43 .count = 5, 44 .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, 45 .flush_hw_mask = 0x0003ffff, 46 }, 47 .pipe_vig = { 48 .count = 3, 49 .base = { 0x01200, 0x01600, 0x01a00 }, 50 .caps = MDP_PIPE_CAP_HFLIP | 51 MDP_PIPE_CAP_VFLIP | 52 MDP_PIPE_CAP_SCALE | 53 MDP_PIPE_CAP_CSC | 54 0, 55 }, 56 .pipe_rgb = { 57 .count = 3, 58 .base = { 0x01e00, 0x02200, 0x02600 }, 59 .caps = MDP_PIPE_CAP_HFLIP | 60 MDP_PIPE_CAP_VFLIP | 61 MDP_PIPE_CAP_SCALE | 62 0, 63 }, 64 .pipe_dma = { 65 .count = 2, 66 .base = { 0x02a00, 0x02e00 }, 67 .caps = MDP_PIPE_CAP_HFLIP | 68 MDP_PIPE_CAP_VFLIP | 69 0, 70 }, 71 .lm = { 72 .count = 5, 73 .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, 74 .nb_stages = 5, 75 }, 76 .dspp = { 77 .count = 3, 78 .base = { 0x04600, 0x04a00, 0x04e00 }, 79 }, 80 .pp = { 81 .count = 3, 82 .base = { 0x21b00, 0x21c00, 0x21d00 }, 83 }, 84 .intf = { 85 .base = { 0x21100, 0x21300, 0x21500, 0x21700 }, 86 .connect = { 87 [0] = INTF_eDP, 88 [1] = INTF_DSI, 89 [2] = INTF_DSI, 90 [3] = INTF_HDMI, 91 }, 92 }, 93 .max_clk = 200000000, 94}; 95 96const struct mdp5_cfg_hw msm8x74v2_config = { 97 .name = "msm8x74", 98 .mdp = { 99 .count = 1, 100 .base = { 0x00100 }, 101 .caps = MDP_CAP_SMP | 102 0, 103 }, 104 .smp = { 105 .mmb_count = 22, 106 .mmb_size = 4096, 107 .clients = { 108 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7, 109 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 110 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18, 111 }, 112 }, 113 .ctl = { 114 .count = 5, 115 .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, 116 .flush_hw_mask = 0x0003ffff, 117 }, 118 .pipe_vig = { 119 .count = 3, 120 .base = { 0x01200, 0x01600, 0x01a00 }, 121 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 122 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | 123 MDP_PIPE_CAP_DECIMATION, 124 }, 125 .pipe_rgb = { 126 .count = 3, 127 .base = { 0x01e00, 0x02200, 0x02600 }, 128 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 129 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, 130 }, 131 .pipe_dma = { 132 .count = 2, 133 .base = { 0x02a00, 0x02e00 }, 134 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, 135 }, 136 .lm = { 137 .count = 5, 138 .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, 139 .nb_stages = 5, 140 .max_width = 2048, 141 .max_height = 0xFFFF, 142 }, 143 .dspp = { 144 .count = 3, 145 .base = { 0x04600, 0x04a00, 0x04e00 }, 146 }, 147 .ad = { 148 .count = 2, 149 .base = { 0x13100, 0x13300 }, 150 }, 151 .pp = { 152 .count = 3, 153 .base = { 0x12d00, 0x12e00, 0x12f00 }, 154 }, 155 .intf = { 156 .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, 157 .connect = { 158 [0] = INTF_eDP, 159 [1] = INTF_DSI, 160 [2] = INTF_DSI, 161 [3] = INTF_HDMI, 162 }, 163 }, 164 .max_clk = 200000000, 165}; 166 167const struct mdp5_cfg_hw apq8084_config = { 168 .name = "apq8084", 169 .mdp = { 170 .count = 1, 171 .base = { 0x00100 }, 172 .caps = MDP_CAP_SMP | 173 0, 174 }, 175 .smp = { 176 .mmb_count = 44, 177 .mmb_size = 8192, 178 .clients = { 179 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, 180 [SSPP_VIG2] = 7, [SSPP_VIG3] = 19, 181 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 182 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, 183 [SSPP_RGB2] = 18, [SSPP_RGB3] = 22, 184 }, 185 .reserved_state[0] = GENMASK(7, 0), /* first 8 MMBs */ 186 .reserved = { 187 /* Two SMP blocks are statically tied to RGB pipes: */ 188 [16] = 2, [17] = 2, [18] = 2, [22] = 2, 189 }, 190 }, 191 .ctl = { 192 .count = 5, 193 .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, 194 .flush_hw_mask = 0x003fffff, 195 }, 196 .pipe_vig = { 197 .count = 4, 198 .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 }, 199 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 200 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | 201 MDP_PIPE_CAP_DECIMATION, 202 }, 203 .pipe_rgb = { 204 .count = 4, 205 .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 }, 206 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 207 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, 208 }, 209 .pipe_dma = { 210 .count = 2, 211 .base = { 0x03200, 0x03600 }, 212 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, 213 }, 214 .lm = { 215 .count = 6, 216 .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 }, 217 .nb_stages = 5, 218 .max_width = 2048, 219 .max_height = 0xFFFF, 220 }, 221 .dspp = { 222 .count = 4, 223 .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 }, 224 225 }, 226 .ad = { 227 .count = 3, 228 .base = { 0x13500, 0x13700, 0x13900 }, 229 }, 230 .pp = { 231 .count = 4, 232 .base = { 0x12f00, 0x13000, 0x13100, 0x13200 }, 233 }, 234 .intf = { 235 .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, 236 .connect = { 237 [0] = INTF_eDP, 238 [1] = INTF_DSI, 239 [2] = INTF_DSI, 240 [3] = INTF_HDMI, 241 }, 242 }, 243 .max_clk = 320000000, 244}; 245 246const struct mdp5_cfg_hw msm8x16_config = { 247 .name = "msm8x16", 248 .mdp = { 249 .count = 1, 250 .base = { 0x01000 }, 251 .caps = MDP_CAP_SMP | 252 0, 253 }, 254 .smp = { 255 .mmb_count = 8, 256 .mmb_size = 8192, 257 .clients = { 258 [SSPP_VIG0] = 1, [SSPP_DMA0] = 4, 259 [SSPP_RGB0] = 7, [SSPP_RGB1] = 8, 260 }, 261 }, 262 .ctl = { 263 .count = 5, 264 .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, 265 .flush_hw_mask = 0x4003ffff, 266 }, 267 .pipe_vig = { 268 .count = 1, 269 .base = { 0x05000 }, 270 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 271 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | 272 MDP_PIPE_CAP_DECIMATION, 273 }, 274 .pipe_rgb = { 275 .count = 2, 276 .base = { 0x15000, 0x17000 }, 277 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 278 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, 279 }, 280 .pipe_dma = { 281 .count = 1, 282 .base = { 0x25000 }, 283 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, 284 }, 285 .lm = { 286 .count = 2, /* LM0 and LM3 */ 287 .base = { 0x45000, 0x48000 }, 288 .nb_stages = 5, 289 .max_width = 2048, 290 .max_height = 0xFFFF, 291 }, 292 .dspp = { 293 .count = 1, 294 .base = { 0x55000 }, 295 296 }, 297 .intf = { 298 .base = { 0x00000, 0x6b800 }, 299 .connect = { 300 [0] = INTF_DISABLED, 301 [1] = INTF_DSI, 302 }, 303 }, 304 .max_clk = 320000000, 305}; 306 307const struct mdp5_cfg_hw msm8x94_config = { 308 .name = "msm8x94", 309 .mdp = { 310 .count = 1, 311 .base = { 0x01000 }, 312 .caps = MDP_CAP_SMP | 313 0, 314 }, 315 .smp = { 316 .mmb_count = 44, 317 .mmb_size = 8192, 318 .clients = { 319 [SSPP_VIG0] = 1, [SSPP_VIG1] = 4, 320 [SSPP_VIG2] = 7, [SSPP_VIG3] = 19, 321 [SSPP_DMA0] = 10, [SSPP_DMA1] = 13, 322 [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, 323 [SSPP_RGB2] = 18, [SSPP_RGB3] = 22, 324 }, 325 .reserved_state[0] = GENMASK(23, 0), /* first 24 MMBs */ 326 .reserved = { 327 [1] = 1, [4] = 1, [7] = 1, [19] = 1, 328 [16] = 5, [17] = 5, [18] = 5, [22] = 5, 329 }, 330 }, 331 .ctl = { 332 .count = 5, 333 .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, 334 .flush_hw_mask = 0xf0ffffff, 335 }, 336 .pipe_vig = { 337 .count = 4, 338 .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, 339 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 340 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | 341 MDP_PIPE_CAP_DECIMATION, 342 }, 343 .pipe_rgb = { 344 .count = 4, 345 .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, 346 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 347 MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, 348 }, 349 .pipe_dma = { 350 .count = 2, 351 .base = { 0x25000, 0x27000 }, 352 .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, 353 }, 354 .lm = { 355 .count = 6, 356 .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, 357 .nb_stages = 8, 358 .max_width = 2048, 359 .max_height = 0xFFFF, 360 }, 361 .dspp = { 362 .count = 4, 363 .base = { 0x55000, 0x57000, 0x59000, 0x5b000 }, 364 365 }, 366 .ad = { 367 .count = 3, 368 .base = { 0x79000, 0x79800, 0x7a000 }, 369 }, 370 .pp = { 371 .count = 4, 372 .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, 373 }, 374 .intf = { 375 .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, 376 .connect = { 377 [0] = INTF_DISABLED, 378 [1] = INTF_DSI, 379 [2] = INTF_DSI, 380 [3] = INTF_HDMI, 381 }, 382 }, 383 .max_clk = 400000000, 384}; 385 386const struct mdp5_cfg_hw msm8x96_config = { 387 .name = "msm8x96", 388 .mdp = { 389 .count = 1, 390 .base = { 0x01000 }, 391 .caps = MDP_CAP_DSC | 392 MDP_CAP_CDM | 393 0, 394 }, 395 .ctl = { 396 .count = 5, 397 .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, 398 .flush_hw_mask = 0xf4ffffff, 399 }, 400 .pipe_vig = { 401 .count = 4, 402 .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, 403 .caps = MDP_PIPE_CAP_HFLIP | 404 MDP_PIPE_CAP_VFLIP | 405 MDP_PIPE_CAP_SCALE | 406 MDP_PIPE_CAP_CSC | 407 MDP_PIPE_CAP_DECIMATION | 408 MDP_PIPE_CAP_SW_PIX_EXT | 409 0, 410 }, 411 .pipe_rgb = { 412 .count = 4, 413 .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, 414 .caps = MDP_PIPE_CAP_HFLIP | 415 MDP_PIPE_CAP_VFLIP | 416 MDP_PIPE_CAP_SCALE | 417 MDP_PIPE_CAP_DECIMATION | 418 MDP_PIPE_CAP_SW_PIX_EXT | 419 0, 420 }, 421 .pipe_dma = { 422 .count = 2, 423 .base = { 0x25000, 0x27000 }, 424 .caps = MDP_PIPE_CAP_HFLIP | 425 MDP_PIPE_CAP_VFLIP | 426 MDP_PIPE_CAP_SW_PIX_EXT | 427 0, 428 }, 429 .lm = { 430 .count = 6, 431 .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, 432 .nb_stages = 8, 433 .max_width = 2560, 434 .max_height = 0xFFFF, 435 }, 436 .dspp = { 437 .count = 2, 438 .base = { 0x55000, 0x57000 }, 439 }, 440 .ad = { 441 .count = 3, 442 .base = { 0x79000, 0x79800, 0x7a000 }, 443 }, 444 .pp = { 445 .count = 4, 446 .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, 447 }, 448 .cdm = { 449 .count = 1, 450 .base = { 0x7a200 }, 451 }, 452 .dsc = { 453 .count = 2, 454 .base = { 0x81000, 0x81400 }, 455 }, 456 .intf = { 457 .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, 458 .connect = { 459 [0] = INTF_DISABLED, 460 [1] = INTF_DSI, 461 [2] = INTF_DSI, 462 [3] = INTF_HDMI, 463 }, 464 }, 465 .max_clk = 412500000, 466}; 467 468static const struct mdp5_cfg_handler cfg_handlers[] = { 469 { .revision = 0, .config = { .hw = &msm8x74v1_config } }, 470 { .revision = 2, .config = { .hw = &msm8x74v2_config } }, 471 { .revision = 3, .config = { .hw = &apq8084_config } }, 472 { .revision = 6, .config = { .hw = &msm8x16_config } }, 473 { .revision = 9, .config = { .hw = &msm8x94_config } }, 474 { .revision = 7, .config = { .hw = &msm8x96_config } }, 475}; 476 477static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); 478 479const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler) 480{ 481 return cfg_handler->config.hw; 482} 483 484struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler) 485{ 486 return &cfg_handler->config; 487} 488 489int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler) 490{ 491 return cfg_handler->revision; 492} 493 494void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler) 495{ 496 kfree(cfg_handler); 497} 498 499struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, 500 uint32_t major, uint32_t minor) 501{ 502 struct drm_device *dev = mdp5_kms->dev; 503 struct platform_device *pdev = dev->platformdev; 504 struct mdp5_cfg_handler *cfg_handler; 505 struct mdp5_cfg_platform *pconfig; 506 int i, ret = 0; 507 508 cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); 509 if (unlikely(!cfg_handler)) { 510 ret = -ENOMEM; 511 goto fail; 512 } 513 514 if (major != 1) { 515 dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n", 516 major, minor); 517 ret = -ENXIO; 518 goto fail; 519 } 520 521 /* only after mdp5_cfg global pointer's init can we access the hw */ 522 for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) { 523 if (cfg_handlers[i].revision != minor) 524 continue; 525 mdp5_cfg = cfg_handlers[i].config.hw; 526 527 break; 528 } 529 if (unlikely(!mdp5_cfg)) { 530 dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n", 531 major, minor); 532 ret = -ENXIO; 533 goto fail; 534 } 535 536 cfg_handler->revision = minor; 537 cfg_handler->config.hw = mdp5_cfg; 538 539 pconfig = mdp5_get_config(pdev); 540 memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig)); 541 542 DBG("MDP5: %s hw config selected", mdp5_cfg->name); 543 544 return cfg_handler; 545 546fail: 547 if (cfg_handler) 548 mdp5_cfg_destroy(cfg_handler); 549 550 return NULL; 551} 552 553static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) 554{ 555 static struct mdp5_cfg_platform config = {}; 556#ifdef CONFIG_OF 557 /* TODO */ 558#endif 559 config.iommu = iommu_domain_alloc(&platform_bus_type); 560 561 return &config; 562} 563