* new gpu support: a405, a640, a650 * dpu: color processing support * mdp5: support for msm8x36 (the thing with a405) * some prep work for per-context pagetables (ie the part that does not depend on in-flight iommu patches) * last but not least, UABI update for submit ioctl to support syncobj (from Bas)
Unified · Split
| @@ -65,6 +65,7 @@ msm-y := \ · 64 unmodified lines | ||
| 65 | 65 | disp/dpu1/dpu_hw_lm.o \ |
| 66 | 66 | disp/dpu1/dpu_hw_pingpong.o \ |
| 67 | 67 | disp/dpu1/dpu_hw_sspp.o \ |
| 68 | + disp/dpu1/dpu_hw_dspp.o \ | |
| 68 | 69 | disp/dpu1/dpu_hw_top.o \ |
| 69 | 70 | disp/dpu1/dpu_hw_util.o \ |
| 70 | 71 | disp/dpu1/dpu_hw_vbif.o \ |
| @@ -401,6 +401,21 @@ static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu) · 400 unmodified lines | ||
| 401 | 401 | return state; |
| 402 | 402 | } |
| 403 | 403 | |
| 404 | +static struct msm_gem_address_space * | |
| 405 | +a2xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) | |
| 406 | +{ | |
| 407 | + struct msm_mmu *mmu = msm_gpummu_new(&pdev->dev, gpu); | |
| 408 | + struct msm_gem_address_space *aspace; | |
| 409 | + | |
| 410 | + aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M, | |
| 411 | + SZ_16M + 0xfff * SZ_64K); | |
| 412 | + | |
| 413 | + if (IS_ERR(aspace) && !IS_ERR(mmu)) | |
| 414 | + mmu->funcs->destroy(mmu); | |
| 415 | + | |
| 416 | + return aspace; | |
| 417 | +} | |
| 418 | + | |
| 404 | 419 | /* Register offset defines for A2XX - copy of A3XX */ |
| 405 | 420 | static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { |
| 406 | 421 | REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE), |
| @@ -429,6 +444,7 @@ static const struct adreno_gpu_funcs funcs = { · 22 unmodified lines | ||
| 429 | 444 | #endif |
| 430 | 445 | .gpu_state_get = a2xx_gpu_state_get, |
| 431 | 446 | .gpu_state_put = adreno_gpu_state_put, |
| 447 | + .create_address_space = a2xx_create_address_space, | |
| 432 | 448 | }, |
| 433 | 449 | }; |
| 434 | 450 | |
| @@ -441,6 +441,7 @@ static const struct adreno_gpu_funcs funcs = { · 440 unmodified lines | ||
| 441 | 441 | #endif |
| 442 | 442 | .gpu_state_get = a3xx_gpu_state_get, |
| 443 | 443 | .gpu_state_put = adreno_gpu_state_put, |
| 444 | + .create_address_space = adreno_iommu_create_address_space, | |
| 444 | 445 | }, |
| 445 | 446 | }; |
| 446 | 447 | |
| @@ -66,19 +66,22 @@ static void a4xx_enable_hwcg(struct msm_gpu *gpu) · 65 unmodified lines | ||
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | − for (i = 0; i < 4; i++) { | |
| 70 | − gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i), | |
| 71 | − 0x00000922); | |
| 72 | − } | |
| 69 | + /* No CCU for A405 */ | |
| 70 | + if (!adreno_is_a405(adreno_gpu)) { | |
| 71 | + for (i = 0; i < 4; i++) { | |
| 72 | + gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i), | |
| 73 | + 0x00000922); | |
| 74 | + } | |
| 73 | 75 | |
| 74 | − for (i = 0; i < 4; i++) { | |
| 75 | − gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i), | |
| 76 | − 0x00000000); | |
| 77 | − } | |
| 76 | + for (i = 0; i < 4; i++) { | |
| 77 | + gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i), | |
| 78 | + 0x00000000); | |
| 79 | + } | |
| 78 | 80 | |
| 79 | − for (i = 0; i < 4; i++) { | |
| 80 | − gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i), | |
| 81 | − 0x00000001); | |
| 81 | + for (i = 0; i < 4; i++) { | |
| 82 | + gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i), | |
| 83 | + 0x00000001); | |
| 84 | + } | |
| 82 | 85 | } |
| 83 | 86 | |
| 84 | 87 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_MODE_GPC, 0x02222222); |
| @@ -137,7 +140,9 @@ static int a4xx_hw_init(struct msm_gpu *gpu) · 52 unmodified lines | ||
| 137 | 140 | uint32_t *ptr, len; |
| 138 | 141 | int i, ret; |
| 139 | 142 | |
| 140 | − if (adreno_is_a420(adreno_gpu)) { | |
| 143 | + if (adreno_is_a405(adreno_gpu)) { | |
| 144 | + gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); | |
| 145 | + } else if (adreno_is_a420(adreno_gpu)) { | |
| 141 | 146 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F); |
| 142 | 147 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4); |
| 143 | 148 | gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001); |
| @@ -440,6 +445,52 @@ static const unsigned int a4xx_registers[] = { · 296 unmodified lines | ||
| 440 | 445 | ~0 /* sentinel */ |
| 441 | 446 | }; |
| 442 | 447 | |
| 448 | +static const unsigned int a405_registers[] = { | |
| 449 | + /* RBBM */ | |
| 450 | + 0x0000, 0x0002, 0x0004, 0x0021, 0x0023, 0x0024, 0x0026, 0x0026, | |
| 451 | + 0x0028, 0x002B, 0x002E, 0x0034, 0x0037, 0x0044, 0x0047, 0x0066, | |
| 452 | + 0x0068, 0x0095, 0x009C, 0x0170, 0x0174, 0x01AF, | |
| 453 | + /* CP */ | |
| 454 | + 0x0200, 0x0233, 0x0240, 0x0250, 0x04C0, 0x04DD, 0x0500, 0x050B, | |
| 455 | + 0x0578, 0x058F, | |
| 456 | + /* VSC */ | |
| 457 | + 0x0C00, 0x0C03, 0x0C08, 0x0C41, 0x0C50, 0x0C51, | |
| 458 | + /* GRAS */ | |
| 459 | + 0x0C80, 0x0C81, 0x0C88, 0x0C8F, | |
| 460 | + /* RB */ | |
| 461 | + 0x0CC0, 0x0CC0, 0x0CC4, 0x0CD2, | |
| 462 | + /* PC */ | |
| 463 | + 0x0D00, 0x0D0C, 0x0D10, 0x0D17, 0x0D20, 0x0D23, | |
| 464 | + /* VFD */ | |
| 465 | + 0x0E40, 0x0E4A, | |
| 466 | + /* VPC */ | |
| 467 | + 0x0E60, 0x0E61, 0x0E63, 0x0E68, | |
| 468 | + /* UCHE */ | |
| 469 | + 0x0E80, 0x0E84, 0x0E88, 0x0E95, | |
| 470 | + /* GRAS CTX 0 */ | |
| 471 | + 0x2000, 0x2004, 0x2008, 0x2067, 0x2070, 0x2078, 0x207B, 0x216E, | |
| 472 | + /* PC CTX 0 */ | |
| 473 | + 0x21C0, 0x21C6, 0x21D0, 0x21D0, 0x21D9, 0x21D9, 0x21E5, 0x21E7, | |
| 474 | + /* VFD CTX 0 */ | |
| 475 | + 0x2200, 0x2204, 0x2208, 0x22A9, | |
| 476 | + /* GRAS CTX 1 */ | |
| 477 | + 0x2400, 0x2404, 0x2408, 0x2467, 0x2470, 0x2478, 0x247B, 0x256E, | |
| 478 | + /* PC CTX 1 */ | |
| 479 | + 0x25C0, 0x25C6, 0x25D0, 0x25D0, 0x25D9, 0x25D9, 0x25E5, 0x25E7, | |
| 480 | + /* VFD CTX 1 */ | |
| 481 | + 0x2600, 0x2604, 0x2608, 0x26A9, | |
| 482 | + /* VBIF version 0x20050000*/ | |
| 483 | + 0x3000, 0x3007, 0x302C, 0x302C, 0x3030, 0x3030, 0x3034, 0x3036, | |
| 484 | + 0x3038, 0x3038, 0x303C, 0x303D, 0x3040, 0x3040, 0x3049, 0x3049, | |
| 485 | + 0x3058, 0x3058, 0x305B, 0x3061, 0x3064, 0x3068, 0x306C, 0x306D, | |
| 486 | + 0x3080, 0x3088, 0x308B, 0x308C, 0x3090, 0x3094, 0x3098, 0x3098, | |
| 487 | + 0x309C, 0x309C, 0x30C0, 0x30C0, 0x30C8, 0x30C8, 0x30D0, 0x30D0, | |
| 488 | + 0x30D8, 0x30D8, 0x30E0, 0x30E0, 0x3100, 0x3100, 0x3108, 0x3108, | |
| 489 | + 0x3110, 0x3110, 0x3118, 0x3118, 0x3120, 0x3120, 0x3124, 0x3125, | |
| 490 | + 0x3129, 0x3129, 0x340C, 0x340C, 0x3410, 0x3410, | |
| 491 | + ~0 /* sentinel */ | |
| 492 | +}; | |
| 493 | + | |
| 443 | 494 | static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) |
| 444 | 495 | { |
| 445 | 496 | struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); |
| @@ -532,6 +583,7 @@ static const struct adreno_gpu_funcs funcs = { · 86 unmodified lines | ||
| 532 | 583 | #endif |
| 533 | 584 | .gpu_state_get = a4xx_gpu_state_get, |
| 534 | 585 | .gpu_state_put = adreno_gpu_state_put, |
| 586 | + .create_address_space = adreno_iommu_create_address_space, | |
| 535 | 587 | }, |
| 536 | 588 | .get_timestamp = a4xx_get_timestamp, |
| 537 | 589 | }; |
| @@ -563,13 +615,14 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) · 25 unmodified lines | ||
| 563 | 615 | gpu->perfcntrs = NULL; |
| 564 | 616 | gpu->num_perfcntrs = 0; |
| 565 | 617 | |
| 566 | − adreno_gpu->registers = a4xx_registers; | |
| 567 | − adreno_gpu->reg_offsets = a4xx_register_offsets; | |
| 568 | − | |
| 569 | 618 | ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); |
| 570 | 619 | if (ret) |
| 571 | 620 | goto fail; |
| 572 | 621 | |
| 622 | + adreno_gpu->registers = adreno_is_a405(adreno_gpu) ? a405_registers : | |
| 623 | + a4xx_registers; | |
| 624 | + adreno_gpu->reg_offsets = a4xx_register_offsets; | |
| 625 | + | |
| 573 | 626 | /* if needed, allocate gmem: */ |
| 574 | 627 | if (adreno_is_a4xx(adreno_gpu)) { |
| 575 | 628 | ret = adreno_gpu_ocmem_init(dev->dev, adreno_gpu, |
| @@ -1404,6 +1404,10 @@ static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu) · 1403 unmodified lines | ||
| 1404 | 1404 | { |
| 1405 | 1405 | u64 busy_cycles, busy_time; |
| 1406 | 1406 | |
| 1407 | + /* Only read the gpu busy if the hardware is already active */ | |
| 1408 | + if (pm_runtime_get_if_in_use(&gpu->pdev->dev) == 0) | |
| 1409 | + return 0; | |
| 1410 | + | |
| 1407 | 1411 | busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, |
| 1408 | 1412 | REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); |
| 1409 | 1413 | |
| @@ -1412,6 +1416,8 @@ static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu) · 2 unmodified lines | ||
| 1412 | 1416 | |
| 1413 | 1417 | gpu->devfreq.busy_cycles = busy_cycles; |
| 1414 | 1418 | |
| 1419 | + pm_runtime_put(&gpu->pdev->dev); | |
| 1420 | + | |
| 1415 | 1421 | if (WARN_ON(busy_time > ~0LU)) |
| 1416 | 1422 | return ~0LU; |
| 1417 | 1423 | |
| @@ -1439,6 +1445,7 @@ static const struct adreno_gpu_funcs funcs = { · 21 unmodified lines | ||
| 1439 | 1445 | .gpu_busy = a5xx_gpu_busy, |
| 1440 | 1446 | .gpu_state_get = a5xx_gpu_state_get, |
| 1441 | 1447 | .gpu_state_put = a5xx_gpu_state_put, |
| 1448 | + .create_address_space = adreno_iommu_create_address_space, | |
| 1442 | 1449 | }, |
| 1443 | 1450 | .get_timestamp = a5xx_get_timestamp, |
| 1444 | 1451 | }; |
| @@ -1047,6 +1047,8 @@ enum a6xx_tex_type { · 1046 unmodified lines | ||
| 1047 | 1047 | |
| 1048 | 1048 | #define REG_A6XX_CP_MISC_CNTL 0x00000840 |
| 1049 | 1049 | |
| 1050 | +#define REG_A6XX_CP_APRIV_CNTL 0x00000844 | |
| 1051 | + | |
| 1050 | 1052 | #define REG_A6XX_CP_ROQ_THRESHOLDS_1 0x000008c1 |
| 1051 | 1053 | |
| 1052 | 1054 | #define REG_A6XX_CP_ROQ_THRESHOLDS_2 0x000008c2 |
| @@ -1764,6 +1766,8 @@ static inline uint32_t A6XX_CP_PROTECT_REG_MASK_LEN(uint32_t val) · 711 unmodified lines | ||
| 1764 | 1766 | |
| 1765 | 1767 | #define REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL 0x00000010 |
| 1766 | 1768 | |
| 1769 | +#define REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL 0x00000011 | |
| 1770 | + | |
| 1767 | 1771 | #define REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0000001f |
| 1768 | 1772 | |
| 1769 | 1773 | #define REG_A6XX_RBBM_INT_CLEAR_CMD 0x00000037 |
| @@ -2418,6 +2422,16 @@ static inline uint32_t A6XX_UCHE_CLIENT_PF_PERFSEL(uint32_t val) · 648 unmodified lines | ||
| 2418 | 2422 | |
| 2419 | 2423 | #define REG_A6XX_TPL1_NC_MODE_CNTL 0x0000b604 |
| 2420 | 2424 | |
| 2425 | +#define REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_0 0x0000b608 | |
| 2426 | + | |
| 2427 | +#define REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_1 0x0000b609 | |
| 2428 | + | |
| 2429 | +#define REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_2 0x0000b60a | |
| 2430 | + | |
| 2431 | +#define REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_3 0x0000b60b | |
| 2432 | + | |
| 2433 | +#define REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_4 0x0000b60c | |
| 2434 | + | |
| 2421 | 2435 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_0 0x0000b610 |
| 2422 | 2436 | |
| 2423 | 2437 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_1 0x0000b611 |
| @@ -2,14 +2,16 @@ · 1 unmodified line | ||
| 2 | 2 | /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */ |
| 3 | 3 | |
| 4 | 4 | #include <linux/clk.h> |
| 5 | −#include <linux/dma-mapping.h> | |
| 6 | 5 | #include <linux/interconnect.h> |
| 7 | 6 | #include <linux/pm_domain.h> |
| 8 | 7 | #include <linux/pm_opp.h> |
| 9 | 8 | #include <soc/qcom/cmd-db.h> |
| 9 | +#include <drm/drm_gem.h> | |
| 10 | 10 | |
| 11 | 11 | #include "a6xx_gpu.h" |
| 12 | 12 | #include "a6xx_gmu.xml.h" |
| 13 | +#include "msm_gem.h" | |
| 14 | +#include "msm_mmu.h" | |
| 13 | 15 | |
| 14 | 16 | static void a6xx_gmu_fault(struct a6xx_gmu *gmu) |
| 15 | 17 | { |
| @@ -127,8 +129,6 @@ static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) · 111 unmodified lines | ||
| 127 | 129 | if (ret) |
| 128 | 130 | dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); |
| 129 | 131 | |
| 130 | − gmu->freq = gmu->gpu_freqs[index]; | |
| 131 | − | |
| 132 | 132 | /* |
| 133 | 133 | * Eventually we will want to scale the path vote with the frequency but |
| 134 | 134 | * for now leave it at max so that the performance is nominal. |
| @@ -151,8 +151,21 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq) · 16 unmodified lines | ||
| 151 | 151 | break; |
| 152 | 152 | |
| 153 | 153 | gmu->current_perf_index = perf_index; |
| 154 | + gmu->freq = gmu->gpu_freqs[perf_index]; | |
| 155 | + | |
| 156 | + /* | |
| 157 | + * This can get called from devfreq while the hardware is idle. Don't | |
| 158 | + * bring up the power if it isn't already active | |
| 159 | + */ | |
| 160 | + if (pm_runtime_get_if_in_use(gmu->dev) == 0) | |
| 161 | + return; | |
| 154 | 162 | |
| 155 | − __a6xx_gmu_set_freq(gmu, perf_index); | |
| 163 | + if (gmu->legacy) | |
| 164 | + __a6xx_gmu_set_freq(gmu, perf_index); | |
| 165 | + else | |
| 166 | + a6xx_hfi_set_freq(gmu, perf_index); | |
| 167 | + | |
| 168 | + pm_runtime_put(gmu->dev); | |
| 156 | 169 | } |
| 157 | 170 | |
| 158 | 171 | unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu) |
| @@ -196,6 +209,12 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu) · 37 unmodified lines | ||
| 196 | 209 | u32 val; |
| 197 | 210 | |
| 198 | 211 | gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1); |
| 212 | + | |
| 213 | + /* Set the log wptr index | |
| 214 | + * note: downstream saves the value in poweroff and restores it here | |
| 215 | + */ | |
| 216 | + gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_RESP, 0); | |
| 217 | + | |
| 199 | 218 | gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0); |
| 200 | 219 | |
| 201 | 220 | ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val, |
| @@ -232,8 +251,13 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) · 30 unmodified lines | ||
| 232 | 251 | |
| 233 | 252 | switch (state) { |
| 234 | 253 | case GMU_OOB_GPU_SET: |
| 235 | − request = GMU_OOB_GPU_SET_REQUEST; | |
| 236 | − ack = GMU_OOB_GPU_SET_ACK; | |
| 254 | + if (gmu->legacy) { | |
| 255 | + request = GMU_OOB_GPU_SET_REQUEST; | |
| 256 | + ack = GMU_OOB_GPU_SET_ACK; | |
| 257 | + } else { | |
| 258 | + request = GMU_OOB_GPU_SET_REQUEST_NEW; | |
| 259 | + ack = GMU_OOB_GPU_SET_ACK_NEW; | |
| 260 | + } | |
| 237 | 261 | name = "GPU_SET"; |
| 238 | 262 | break; |
| 239 | 263 | case GMU_OOB_BOOT_SLUMBER: |
| @@ -272,6 +296,13 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) · 32 unmodified lines | ||
| 272 | 296 | /* Clear a pending OOB state in the GMU */ |
| 273 | 297 | void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) |
| 274 | 298 | { |
| 299 | + if (!gmu->legacy) { | |
| 300 | + WARN_ON(state != GMU_OOB_GPU_SET); | |
| 301 | + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, | |
| 302 | + 1 << GMU_OOB_GPU_SET_CLEAR_NEW); | |
| 303 | + return; | |
| 304 | + } | |
| 305 | + | |
| 275 | 306 | switch (state) { |
| 276 | 307 | case GMU_OOB_GPU_SET: |
| 277 | 308 | gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, |
| @@ -294,6 +325,9 @@ static int a6xx_sptprac_enable(struct a6xx_gmu *gmu) · 16 unmodified lines | ||
| 294 | 325 | int ret; |
| 295 | 326 | u32 val; |
| 296 | 327 | |
| 328 | + if (!gmu->legacy) | |
| 329 | + return 0; | |
| 330 | + | |
| 297 | 331 | gmu_write(gmu, REG_A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, 0x778000); |
| 298 | 332 | |
| 299 | 333 | ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, val, |
| @@ -313,6 +347,9 @@ static void a6xx_sptprac_disable(struct a6xx_gmu *gmu) · 13 unmodified lines | ||
| 313 | 347 | u32 val; |
| 314 | 348 | int ret; |
| 315 | 349 | |
| 350 | + if (!gmu->legacy) | |
| 351 | + return; | |
| 352 | + | |
| 316 | 353 | /* Make sure retention is on */ |
| 317 | 354 | gmu_rmw(gmu, REG_A6XX_GPU_CC_GX_GDSCR, 0, (1 << 11)); |
| 318 | 355 | |
| @@ -356,6 +393,11 @@ static int a6xx_gmu_notify_slumber(struct a6xx_gmu *gmu) · 37 unmodified lines | ||
| 356 | 393 | if (gmu->idle_level < GMU_IDLE_STATE_SPTP) |
| 357 | 394 | a6xx_sptprac_disable(gmu); |
| 358 | 395 | |
| 396 | + if (!gmu->legacy) { | |
| 397 | + ret = a6xx_hfi_send_prep_slumber(gmu); | |
| 398 | + goto out; | |
| 399 | + } | |
| 400 | + | |
| 359 | 401 | /* Tell the GMU to get ready to slumber */ |
| 360 | 402 | gmu_write(gmu, REG_A6XX_GMU_BOOT_SLUMBER_OPTION, 1); |
| 361 | 403 | |
| @@ -371,6 +413,7 @@ static int a6xx_gmu_notify_slumber(struct a6xx_gmu *gmu) · 9 unmodified lines | ||
| 371 | 413 | } |
| 372 | 414 | } |
| 373 | 415 | |
| 416 | +out: | |
| 374 | 417 | /* Put fence into allow mode */ |
| 375 | 418 | gmu_write(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); |
| 376 | 419 | return ret; |
| @@ -392,7 +435,7 @@ static int a6xx_rpmh_start(struct a6xx_gmu *gmu) · 15 unmodified lines | ||
| 392 | 435 | return ret; |
| 393 | 436 | } |
| 394 | 437 | |
| 395 | − ret = gmu_poll_timeout(gmu, REG_A6XX_RSCC_SEQ_BUSY_DRV0, val, | |
| 438 | + ret = gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_SEQ_BUSY_DRV0, val, | |
| 396 | 439 | !val, 100, 10000); |
| 397 | 440 | |
| 398 | 441 | if (ret) { |
| @@ -418,7 +461,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu) · 19 unmodified lines | ||
| 418 | 461 | |
| 419 | 462 | gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 1); |
| 420 | 463 | |
| 421 | − ret = gmu_poll_timeout(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0, | |
| 464 | + ret = gmu_poll_timeout_rscc(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0, | |
| 422 | 465 | val, val & (1 << 16), 100, 10000); |
| 423 | 466 | if (ret) |
| 424 | 467 | DRM_DEV_ERROR(gmu->dev, "Unable to power off the GPU RSC\n"); |
| @@ -441,32 +484,48 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) · 16 unmodified lines | ||
| 441 | 484 | struct platform_device *pdev = to_platform_device(gmu->dev); |
| 442 | 485 | void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); |
| 443 | 486 | void __iomem *seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); |
| 487 | + uint32_t pdc_address_offset; | |
| 444 | 488 | |
| 445 | 489 | if (!pdcptr || !seqptr) |
| 446 | 490 | goto err; |
| 447 | 491 | |
| 492 | + if (adreno_is_a618(adreno_gpu) || adreno_is_a640(adreno_gpu)) | |
| 493 | + pdc_address_offset = 0x30090; | |
| 494 | + else if (adreno_is_a650(adreno_gpu)) | |
| 495 | + pdc_address_offset = 0x300a0; | |
| 496 | + else | |
| 497 | + pdc_address_offset = 0x30080; | |
| 498 | + | |
| 448 | 499 | /* Disable SDE clock gating */ |
| 449 | − gmu_write(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); | |
| 500 | + gmu_write_rscc(gmu, REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); | |
| 450 | 501 | |
| 451 | 502 | /* Setup RSC PDC handshake for sleep and wakeup */ |
| 452 | − gmu_write(gmu, REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); | |
| 453 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); | |
| 454 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); | |
| 455 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0); | |
| 456 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0); | |
| 457 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4, 0x80000000); | |
| 458 | − gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0); | |
| 459 | − gmu_write(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0); | |
| 460 | − gmu_write(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); | |
| 461 | − gmu_write(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); | |
| 462 | − gmu_write(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); | |
| 503 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); | |
| 504 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); | |
| 505 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); | |
| 506 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0); | |
| 507 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0); | |
| 508 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4, 0x80000000); | |
| 509 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0); | |
| 510 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0); | |
| 511 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); | |
| 512 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); | |
| 513 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); | |
| 463 | 514 | |
| 464 | 515 | /* Load RSC sequencer uCode for sleep and wakeup */ |
| 465 | − gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xa7a506a0); | |
| 466 | − gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xa1e6a6e7); | |
| 467 | − gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e081e1); | |
| 468 | − gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xe9a982e2); | |
| 469 | − gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020e8a8); | |
| 516 | + if (adreno_is_a650(adreno_gpu)) { | |
| 517 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xeaaae5a0); | |
| 518 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xe1a1ebab); | |
| 519 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e0a581); | |
| 520 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xecac82e2); | |
| 521 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020edad); | |
| 522 | + } else { | |
| 523 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xa7a506a0); | |
| 524 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xa1e6a6e7); | |
| 525 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e081e1); | |
| 526 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xe9a982e2); | |
| 527 | + gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020e8a8); | |
| 528 | + } | |
| 470 | 529 | |
| 471 | 530 | /* Load PDC sequencer uCode for power up and power down sequence */ |
| 472 | 531 | pdc_write(seqptr, REG_A6XX_PDC_GPU_SEQ_MEM_0, 0xfebea1e1); |
| @@ -487,10 +546,7 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) · 14 unmodified lines | ||
| 487 | 546 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 4, 0x0); |
| 488 | 547 | |
| 489 | 548 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_MSGID + 8, 0x10108); |
| 490 | − if (adreno_is_a618(adreno_gpu)) | |
| 491 | − pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, 0x30090); | |
| 492 | − else | |
| 493 | − pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, 0x30080); | |
| 549 | + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, pdc_address_offset); | |
| 494 | 550 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 8, 0x0); |
| 495 | 551 | |
| 496 | 552 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD_ENABLE_BANK, 7); |
| @@ -502,17 +558,12 @@ static void a6xx_gmu_rpmh_init(struct a6xx_gmu *gmu) · 5 unmodified lines | ||
| 502 | 558 | |
| 503 | 559 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 4, 0x10108); |
| 504 | 560 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 4, 0x30000); |
| 505 | − if (adreno_is_a618(adreno_gpu)) | |
| 561 | + if (adreno_is_a618(adreno_gpu) || adreno_is_a650(adreno_gpu)) | |
| 506 | 562 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x2); |
| 507 | 563 | else |
| 508 | 564 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3); |
| 509 | − | |
| 510 | − | |
| 511 | 565 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 8, 0x10108); |
| 512 | − if (adreno_is_a618(adreno_gpu)) | |
| 513 | − pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, 0x30090); | |
| 514 | − else | |
| 515 | − pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, 0x30080); | |
| 566 | + pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, pdc_address_offset); | |
| 516 | 567 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 8, 0x3); |
| 517 | 568 | |
| 518 | 569 | /* Setup GPU PDC */ |
| @@ -542,6 +593,8 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu) · 23 unmodified lines | ||
| 542 | 593 | { |
| 543 | 594 | /* Disable GMU WB/RB buffer */ |
| 544 | 595 | gmu_write(gmu, REG_A6XX_GMU_SYS_BUS_CONFIG, 0x1); |
| 596 | + gmu_write(gmu, REG_A6XX_GMU_ICACHE_CONFIG, 0x1); | |
| 597 | + gmu_write(gmu, REG_A6XX_GMU_DCACHE_CONFIG, 0x1); | |
| 545 | 598 | |
| 546 | 599 | gmu_write(gmu, REG_A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9c40400); |
| 547 | 600 | |
| @@ -571,14 +624,95 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu) · 23 unmodified lines | ||
| 571 | 624 | A6XX_GMU_RPMH_CTRL_GFX_VOTE_ENABLE); |
| 572 | 625 | } |
| 573 | 626 | |
| 627 | +struct block_header { | |
| 628 | + u32 addr; | |
| 629 | + u32 size; | |
| 630 | + u32 type; | |
| 631 | + u32 value; | |
| 632 | + u32 data[]; | |
| 633 | +}; | |
| 634 | + | |
| 635 | +/* this should be a general kernel helper */ | |
| 636 | +static int in_range(u32 addr, u32 start, u32 size) | |
| 637 | +{ | |
| 638 | + return addr >= start && addr < start + size; | |
| 639 | +} | |
| 640 | + | |
| 641 | +static bool fw_block_mem(struct a6xx_gmu_bo *bo, const struct block_header *blk) | |
| 642 | +{ | |
| 643 | + if (!in_range(blk->addr, bo->iova, bo->size)) | |
| 644 | + return false; | |
| 645 | + | |
| 646 | + memcpy(bo->virt + blk->addr - bo->iova, blk->data, blk->size); | |
| 647 | + return true; | |
| 648 | +} | |
| 649 | + | |
| 650 | +static int a6xx_gmu_fw_load(struct a6xx_gmu *gmu) | |
| 651 | +{ | |
| 652 | + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); | |
| 653 | + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; | |
| 654 | + const struct firmware *fw_image = adreno_gpu->fw[ADRENO_FW_GMU]; | |
| 655 | + const struct block_header *blk; | |
| 656 | + u32 reg_offset; | |
| 657 | + | |
| 658 | + u32 itcm_base = 0x00000000; | |
| 659 | + u32 dtcm_base = 0x00040000; | |
| 660 | + | |
| 661 | + if (adreno_is_a650(adreno_gpu)) | |
| 662 | + dtcm_base = 0x10004000; | |
| 663 | + | |
| 664 | + if (gmu->legacy) { | |
| 665 | + /* Sanity check the size of the firmware that was loaded */ | |
| 666 | + if (fw_image->size > 0x8000) { | |
| 667 | + DRM_DEV_ERROR(gmu->dev, | |
| 668 | + "GMU firmware is bigger than the available region\n"); | |
| 669 | + return -EINVAL; | |
| 670 | + } | |
| 671 | + | |
| 672 | + gmu_write_bulk(gmu, REG_A6XX_GMU_CM3_ITCM_START, | |
| 673 | + (u32*) fw_image->data, fw_image->size); | |
| 674 | + return 0; | |
| 675 | + } | |
| 676 | + | |
| 677 | + | |
| 678 | + for (blk = (const struct block_header *) fw_image->data; | |
| 679 | + (const u8*) blk < fw_image->data + fw_image->size; | |
| 680 | + blk = (const struct block_header *) &blk->data[blk->size >> 2]) { | |
| 681 | + if (blk->size == 0) | |
| 682 | + continue; | |
| 683 | + | |
| 684 | + if (in_range(blk->addr, itcm_base, SZ_16K)) { | |
| 685 | + reg_offset = (blk->addr - itcm_base) >> 2; | |
| 686 | + gmu_write_bulk(gmu, | |
| 687 | + REG_A6XX_GMU_CM3_ITCM_START + reg_offset, | |
| 688 | + blk->data, blk->size); | |
| 689 | + } else if (in_range(blk->addr, dtcm_base, SZ_16K)) { | |
| 690 | + reg_offset = (blk->addr - dtcm_base) >> 2; | |
| 691 | + gmu_write_bulk(gmu, | |
| 692 | + REG_A6XX_GMU_CM3_DTCM_START + reg_offset, | |
| 693 | + blk->data, blk->size); | |
| 694 | + } else if (!fw_block_mem(&gmu->icache, blk) && | |
| 695 | + !fw_block_mem(&gmu->dcache, blk) && | |
| 696 | + !fw_block_mem(&gmu->dummy, blk)) { | |
| 697 | + DRM_DEV_ERROR(gmu->dev, | |
| 698 | + "failed to match fw block (addr=%.8x size=%d data[0]=%.8x)\n", | |
| 699 | + blk->addr, blk->size, blk->data[0]); | |
| 700 | + } | |
| 701 | + } | |
| 702 | + | |
| 703 | + return 0; | |
| 704 | +} | |
| 705 | + | |
| 574 | 706 | static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) |
| 575 | 707 | { |
| 576 | 708 | static bool rpmh_init; |
| 577 | 709 | struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); |
| 578 | 710 | struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; |
| 579 | − int i, ret; | |
| 711 | + int ret; | |
| 580 | 712 | u32 chipid; |
| 581 | − u32 *image; | |
| 713 | + | |
| 714 | + if (adreno_is_a650(adreno_gpu)) | |
| 715 | + gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF, 1); | |
| 582 | 716 | |
| 583 | 717 | if (state == GMU_WARM_BOOT) { |
| 584 | 718 | ret = a6xx_rpmh_start(gmu); |
| @@ -589,13 +723,6 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) · 4 unmodified lines | ||
| 589 | 723 | "GMU firmware is not loaded\n")) |
| 590 | 724 | return -ENOENT; |
| 591 | 725 | |
| 592 | − /* Sanity check the size of the firmware that was loaded */ | |
| 593 | − if (adreno_gpu->fw[ADRENO_FW_GMU]->size > 0x8000) { | |
| 594 | − DRM_DEV_ERROR(gmu->dev, | |
| 595 | − "GMU firmware is bigger than the available region\n"); | |
| 596 | − return -EINVAL; | |
| 597 | − } | |
| 598 | − | |
| 599 | 726 | /* Turn on register retention */ |
| 600 | 727 | gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1); |
| 601 | 728 | |
| @@ -609,18 +736,16 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) · 7 unmodified lines | ||
| 609 | 736 | return ret; |
| 610 | 737 | } |
| 611 | 738 | |
| 612 | − image = (u32 *) adreno_gpu->fw[ADRENO_FW_GMU]->data; | |
| 613 | − | |
| 614 | − for (i = 0; i < adreno_gpu->fw[ADRENO_FW_GMU]->size >> 2; i++) | |
| 615 | − gmu_write(gmu, REG_A6XX_GMU_CM3_ITCM_START + i, | |
| 616 | − image[i]); | |
| 739 | + ret = a6xx_gmu_fw_load(gmu); | |
| 740 | + if (ret) | |
| 741 | + return ret; | |
| 617 | 742 | } |
| 618 | 743 | |
| 619 | 744 | gmu_write(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, 0); |
| 620 | 745 | gmu_write(gmu, REG_A6XX_GMU_CM3_BOOT_CONFIG, 0x02); |
| 621 | 746 | |
| 622 | 747 | /* Write the iova of the HFI table */ |
| 623 | − gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_ADDR, gmu->hfi->iova); | |
| 748 | + gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_ADDR, gmu->hfi.iova); | |
| 624 | 749 | gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_INFO, 1); |
| 625 | 750 | |
| 626 | 751 | gmu_write(gmu, REG_A6XX_GMU_AHB_FENCE_RANGE_0, |
| @@ -633,6 +758,9 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) · 6 unmodified lines | ||
| 633 | 758 | |
| 634 | 759 | gmu_write(gmu, REG_A6XX_GMU_HFI_SFR_ADDR, chipid); |
| 635 | 760 | |
| 761 | + gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_MSG, | |
| 762 | + gmu->log.iova | (gmu->log.size / SZ_4K - 1)); | |
| 763 | + | |
| 636 | 764 | /* Set up the lowest idle level on the GMU */ |
| 637 | 765 | a6xx_gmu_power_config(gmu); |
| 638 | 766 | |
| @@ -640,9 +768,11 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) · 1 unmodified line | ||
| 640 | 768 | if (ret) |
| 641 | 769 | return ret; |
| 642 | 770 | |
| 643 | − ret = a6xx_gmu_gfx_rail_on(gmu); | |
| 644 | − if (ret) | |
| 645 | − return ret; | |
| 771 | + if (gmu->legacy) { | |
| 772 | + ret = a6xx_gmu_gfx_rail_on(gmu); | |
| 773 | + if (ret) | |
| 774 | + return ret; | |
| 775 | + } | |
| 646 | 776 | |
| 647 | 777 | /* Enable SPTP_PC if the CPU is responsible for it */ |
| 648 | 778 | if (gmu->idle_level < GMU_IDLE_STATE_SPTP) { |
| @@ -683,13 +813,13 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu) · 34 unmodified lines | ||
| 683 | 813 | u32 val; |
| 684 | 814 | |
| 685 | 815 | /* Make sure there are no outstanding RPMh votes */ |
| 686 | − gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val, | |
| 816 | + gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val, | |
| 687 | 817 | (val & 1), 100, 10000); |
| 688 | − gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val, | |
| 818 | + gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val, | |
| 689 | 819 | (val & 1), 100, 10000); |
| 690 | − gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val, | |
| 820 | + gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val, | |
| 691 | 821 | (val & 1), 100, 10000); |
| 692 | − gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val, | |
| 822 | + gmu_poll_timeout_rscc(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val, | |
| 693 | 823 | (val & 1), 100, 1000); |
| 694 | 824 | } |
| 695 | 825 | |
| @@ -744,6 +874,13 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) · 48 unmodified lines | ||
| 744 | 874 | status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ? |
| 745 | 875 | GMU_WARM_BOOT : GMU_COLD_BOOT; |
| 746 | 876 | |
| 877 | + /* | |
| 878 | + * Warm boot path does not work on newer GPUs | |
| 879 | + * Presumably this is because icache/dcache regions must be restored | |
| 880 | + */ | |
| 881 | + if (!gmu->legacy) | |
| 882 | + status = GMU_COLD_BOOT; | |
| 883 | + | |
| 747 | 884 | ret = a6xx_gmu_fw_start(gmu, status); |
| 748 | 885 | if (ret) |
| 749 | 886 | goto out; |
| @@ -761,7 +898,10 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) · 11 unmodified lines | ||
| 761 | 898 | enable_irq(gmu->hfi_irq); |
| 762 | 899 | |
| 763 | 900 | /* Set the GPU to the current freq */ |
| 764 | − __a6xx_gmu_set_freq(gmu, gmu->current_perf_index); | |
| 901 | + if (gmu->legacy) | |
| 902 | + __a6xx_gmu_set_freq(gmu, gmu->current_perf_index); | |
| 903 | + else | |
| 904 | + a6xx_hfi_set_freq(gmu, gmu->current_perf_index); | |
| 765 | 905 | |
| 766 | 906 | /* |
| 767 | 907 | * "enable" the GX power domain which won't actually do anything but it |
| @@ -919,34 +1059,75 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) · 151 unmodified lines | ||
| 919 | 1059 | return 0; |
| 920 | 1060 | } |
| 921 | 1061 | |
| 922 | −static void a6xx_gmu_memory_free(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo) | |
| 1062 | +static void a6xx_gmu_memory_free(struct a6xx_gmu *gmu) | |
| 923 | 1063 | { |
| 924 | − if (IS_ERR_OR_NULL(bo)) | |
| 925 | − return; | |
| 926 | − | |
| 927 | − dma_free_wc(gmu->dev, bo->size, bo->virt, bo->iova); | |
| 928 | − kfree(bo); | |
| 1064 | + msm_gem_kernel_put(gmu->hfi.obj, gmu->aspace, false); | |
| 1065 | + msm_gem_kernel_put(gmu->debug.obj, gmu->aspace, false); | |
| 1066 | + msm_gem_kernel_put(gmu->icache.obj, gmu->aspace, false); | |
| 1067 | + msm_gem_kernel_put(gmu->dcache.obj, gmu->aspace, false); | |
| 1068 | + msm_gem_kernel_put(gmu->dummy.obj, gmu->aspace, false); | |
| 1069 | + msm_gem_kernel_put(gmu->log.obj, gmu->aspace, false); | |
| 1070 | + | |
| 1071 | + gmu->aspace->mmu->funcs->detach(gmu->aspace->mmu); | |
| 1072 | + msm_gem_address_space_put(gmu->aspace); | |
| 929 | 1073 | } |
| 930 | 1074 | |
| 931 | −static struct a6xx_gmu_bo *a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, | |
| 932 | − size_t size) | |
| 1075 | +static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, | |
| 1076 | + size_t size, u64 iova) | |
| 933 | 1077 | { |
| 934 | − struct a6xx_gmu_bo *bo; | |
| 1078 | + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); | |
| 1079 | + struct drm_device *dev = a6xx_gpu->base.base.dev; | |
| 1080 | + uint32_t flags = MSM_BO_WC; | |
| 1081 | + u64 range_start, range_end; | |
| 1082 | + int ret; | |
| 935 | 1083 | |
| 936 | − bo = kzalloc(sizeof(*bo), GFP_KERNEL); | |
| 937 | − if (!bo) | |
| 938 | − return ERR_PTR(-ENOMEM); | |
| 1084 | + size = PAGE_ALIGN(size); | |
| 1085 | + if (!iova) { | |
| 1086 | + /* no fixed address - use GMU's uncached range */ | |
| 1087 | + range_start = 0x60000000 + PAGE_SIZE; /* skip dummy page */ | |
| 1088 | + range_end = 0x80000000; | |
| 1089 | + } else { | |
| 1090 | + /* range for fixed address */ | |
| 1091 | + range_start = iova; | |
| 1092 | + range_end = iova + size; | |
| 1093 | + /* use IOMMU_PRIV for icache/dcache */ | |
| 1094 | + flags |= MSM_BO_MAP_PRIV; | |
| 1095 | + } | |
| 939 | 1096 | |
| 940 | − bo->size = PAGE_ALIGN(size); | |
| 1097 | + bo->obj = msm_gem_new(dev, size, flags); | |
| 1098 | + if (IS_ERR(bo->obj)) | |
| 1099 | + return PTR_ERR(bo->obj); | |
| 941 | 1100 | |
| 942 | − bo->virt = dma_alloc_wc(gmu->dev, bo->size, &bo->iova, GFP_KERNEL); | |
| 1101 | + ret = msm_gem_get_and_pin_iova_range(bo->obj, gmu->aspace, &bo->iova, | |
| 1102 | + range_start >> PAGE_SHIFT, range_end >> PAGE_SHIFT); | |
| 1103 | + if (ret) { | |
| 1104 | + drm_gem_object_put(bo->obj); | |
| 1105 | + return ret; | |
| 1106 | + } | |
| 1107 | + | |
| 1108 | + bo->virt = msm_gem_get_vaddr(bo->obj); | |
| 1109 | + bo->size = size; | |
| 1110 | + | |
| 1111 | + return 0; | |
| 1112 | +} | |
| 1113 | + | |
| 1114 | +static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) | |
| 1115 | +{ | |
| 1116 | + struct iommu_domain *domain; | |
| 1117 | + struct msm_mmu *mmu; | |
| 943 | 1118 | |
| 944 | − if (!bo->virt) { | |
| 945 | − kfree(bo); | |
| 946 | − return ERR_PTR(-ENOMEM); | |
| 1119 | + domain = iommu_domain_alloc(&platform_bus_type); | |
| 1120 | + if (!domain) | |
| 1121 | + return -ENODEV; | |
| 1122 | + | |
| 1123 | + mmu = msm_iommu_new(gmu->dev, domain); | |
| 1124 | + gmu->aspace = msm_gem_address_space_create(mmu, "gmu", 0x0, 0x7fffffff); | |
| 1125 | + if (IS_ERR(gmu->aspace)) { | |
| 1126 | + iommu_domain_free(domain); | |
| 1127 | + return PTR_ERR(gmu->aspace); | |
| 947 | 1128 | } |
| 948 | 1129 | |
| 949 | − return bo; | |
| 1130 | + return 0; | |
| 950 | 1131 | } |
| 951 | 1132 | |
| 952 | 1133 | /* Return the 'arc-level' for the given frequency */ |
| @@ -1011,8 +1192,8 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, · 58 unmodified lines | ||
| 1011 | 1192 | |
| 1012 | 1193 | if (j == pri_count) { |
| 1013 | 1194 | DRM_DEV_ERROR(dev, |
| 1014 | − "Level %u not found in in the RPMh list\n", | |
| 1015 | − level); | |
| 1195 | + "Level %u not found in the RPMh list\n", | |
| 1196 | + level); | |
| 1016 | 1197 | DRM_DEV_ERROR(dev, "Available levels:\n"); |
| 1017 | 1198 | for (j = 0; j < pri_count; j++) |
| 1018 | 1199 | DRM_DEV_ERROR(dev, " %u\n", pri[j]); |
| @@ -1190,6 +1371,7 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev, · 171 unmodified lines | ||
| 1190 | 1371 | void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) |
| 1191 | 1372 | { |
| 1192 | 1373 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; |
| 1374 | + struct platform_device *pdev = to_platform_device(gmu->dev); | |
| 1193 | 1375 | |
| 1194 | 1376 | if (!gmu->initialized) |
| 1195 | 1377 | return; |
| @@ -1202,9 +1384,12 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) · 6 unmodified lines | ||
| 1202 | 1384 | } |
| 1203 | 1385 | |
| 1204 | 1386 | iounmap(gmu->mmio); |
| 1387 | + if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) | |
| 1388 | + iounmap(gmu->rscc); | |
| 1205 | 1389 | gmu->mmio = NULL; |
| 1390 | + gmu->rscc = NULL; | |
| 1206 | 1391 | |
| 1207 | − a6xx_gmu_memory_free(gmu, gmu->hfi); | |
| 1392 | + a6xx_gmu_memory_free(gmu); | |
| 1208 | 1393 | |
| 1209 | 1394 | free_irq(gmu->gmu_irq, gmu); |
| 1210 | 1395 | free_irq(gmu->hfi_irq, gmu); |
| @@ -1217,6 +1402,7 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) · 6 unmodified lines | ||
| 1217 | 1402 | |
| 1218 | 1403 | int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) |
| 1219 | 1404 | { |
| 1405 | + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; | |
| 1220 | 1406 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; |
| 1221 | 1407 | struct platform_device *pdev = of_find_device_by_node(node); |
| 1222 | 1408 | int ret; |
| @@ -1226,15 +1412,7 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) · 3 unmodified lines | ||
| 1226 | 1412 | |
| 1227 | 1413 | gmu->dev = &pdev->dev; |
| 1228 | 1414 | |
| 1229 | − /* Pass force_dma false to require the DT to set the dma region */ | |
| 1230 | − ret = of_dma_configure(gmu->dev, node, false); | |
| 1231 | − if (ret) | |
| 1232 | − return ret; | |
| 1233 | − | |
| 1234 | − /* Set the mask after the of_dma_configure() */ | |
| 1235 | − ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(31)); | |
| 1236 | − if (ret) | |
| 1237 | − return ret; | |
| 1415 | + of_dma_configure(gmu->dev, node, true); | |
| 1238 | 1416 | |
| 1239 | 1417 | /* Fow now, don't do anything fancy until we get our feet under us */ |
| 1240 | 1418 | gmu->idle_level = GMU_IDLE_STATE_ACTIVE; |
| @@ -1246,20 +1424,64 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) · 5 unmodified lines | ||
| 1246 | 1424 | if (ret) |
| 1247 | 1425 | goto err_put_device; |
| 1248 | 1426 | |
| 1427 | + ret = a6xx_gmu_memory_probe(gmu); | |
| 1428 | + if (ret) | |
| 1429 | + goto err_put_device; | |
| 1430 | + | |
| 1431 | + /* Allocate memory for the GMU dummy page */ | |
| 1432 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->dummy, SZ_4K, 0x60000000); | |
| 1433 | + if (ret) | |
| 1434 | + goto err_memory; | |
| 1435 | + | |
| 1436 | + if (adreno_is_a650(adreno_gpu)) { | |
| 1437 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache, | |
| 1438 | + SZ_16M - SZ_16K, 0x04000); | |
| 1439 | + if (ret) | |
| 1440 | + goto err_memory; | |
| 1441 | + } else if (adreno_is_a640(adreno_gpu)) { | |
| 1442 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache, | |
| 1443 | + SZ_256K - SZ_16K, 0x04000); | |
| 1444 | + if (ret) | |
| 1445 | + goto err_memory; | |
| 1446 | + | |
| 1447 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->dcache, | |
| 1448 | + SZ_256K - SZ_16K, 0x44000); | |
| 1449 | + if (ret) | |
| 1450 | + goto err_memory; | |
| 1451 | + } else { | |
| 1452 | + /* HFI v1, has sptprac */ | |
| 1453 | + gmu->legacy = true; | |
| 1454 | + | |
| 1455 | + /* Allocate memory for the GMU debug region */ | |
| 1456 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_16K, 0); | |
| 1457 | + if (ret) | |
| 1458 | + goto err_memory; | |
| 1459 | + } | |
| 1460 | + | |
| 1249 | 1461 | /* Allocate memory for for the HFI queues */ |
| 1250 | − gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K); | |
| 1251 | − if (IS_ERR(gmu->hfi)) | |
| 1462 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->hfi, SZ_16K, 0); | |
| 1463 | + if (ret) | |
| 1252 | 1464 | goto err_memory; |
| 1253 | 1465 | |
| 1254 | − /* Allocate memory for the GMU debug region */ | |
| 1255 | − gmu->debug = a6xx_gmu_memory_alloc(gmu, SZ_16K); | |
| 1256 | − if (IS_ERR(gmu->debug)) | |
| 1466 | + /* Allocate memory for the GMU log region */ | |
| 1467 | + ret = a6xx_gmu_memory_alloc(gmu, &gmu->log, SZ_4K, 0); | |
| 1468 | + if (ret) | |
| 1257 | 1469 | goto err_memory; |
| 1258 | 1470 | |
| 1259 | 1471 | /* Map the GMU registers */ |
| 1260 | 1472 | gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); |
| 1261 | − if (IS_ERR(gmu->mmio)) | |
| 1473 | + if (IS_ERR(gmu->mmio)) { | |
| 1474 | + ret = PTR_ERR(gmu->mmio); | |
| 1262 | 1475 | goto err_memory; |
| 1476 | + } | |
| 1477 | + | |
| 1478 | + if (adreno_is_a650(adreno_gpu)) { | |
| 1479 | + gmu->rscc = a6xx_gmu_get_mmio(pdev, "rscc"); | |
| 1480 | + if (IS_ERR(gmu->rscc)) | |
| 1481 | + goto err_mmio; | |
| 1482 | + } else { | |
| 1483 | + gmu->rscc = gmu->mmio + 0x23000; | |
| 1484 | + } | |
| 1263 | 1485 | |
| 1264 | 1486 | /* Get the HFI and GMU interrupts */ |
| 1265 | 1487 | gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq); |
| @@ -1286,13 +1508,15 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) · 20 unmodified lines | ||
| 1286 | 1508 | |
| 1287 | 1509 | err_mmio: |
| 1288 | 1510 | iounmap(gmu->mmio); |
| 1511 | + if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) | |
| 1512 | + iounmap(gmu->rscc); | |
| 1289 | 1513 | free_irq(gmu->gmu_irq, gmu); |
| 1290 | 1514 | free_irq(gmu->hfi_irq, gmu); |
| 1291 | −err_memory: | |
| 1292 | − a6xx_gmu_memory_free(gmu, gmu->hfi); | |
| 1293 | 1515 | |
| 1294 | 1516 | ret = -ENODEV; |
| 1295 | 1517 | |
| 1518 | +err_memory: | |
| 1519 | + a6xx_gmu_memory_free(gmu); | |
| 1296 | 1520 | err_put_device: |
| 1297 | 1521 | /* Drop reference taken in of_find_device_by_node */ |
| 1298 | 1522 | put_device(gmu->dev); |
| @@ -10,9 +10,10 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "a6xx_hfi.h" |
| 11 | 11 | |
| 12 | 12 | struct a6xx_gmu_bo { |
| 13 | + struct drm_gem_object *obj; | |
| 13 | 14 | void *virt; |
| 14 | 15 | size_t size; |
| 15 | − dma_addr_t iova; | |
| 16 | + u64 iova; | |
| 16 | 17 | }; |
| 17 | 18 | |
| 18 | 19 | /* |
| @@ -43,7 +44,10 @@ struct a6xx_gmu_bo { · 24 unmodified lines | ||
| 43 | 44 | struct a6xx_gmu { |
| 44 | 45 | struct device *dev; |
| 45 | 46 | |
| 47 | + struct msm_gem_address_space *aspace; | |
| 48 | + | |
| 46 | 49 | void * __iomem mmio; |
| 50 | + void * __iomem rscc; | |
| 47 | 51 | |
| 48 | 52 | int hfi_irq; |
| 49 | 53 | int gmu_irq; |
| @@ -52,8 +56,12 @@ struct a6xx_gmu { · 2 unmodified lines | ||
| 52 | 56 | |
| 53 | 57 | int idle_level; |
| 54 | 58 | |
| 55 | − struct a6xx_gmu_bo *hfi; | |
| 56 | − struct a6xx_gmu_bo *debug; | |
| 59 | + struct a6xx_gmu_bo hfi; | |
| 60 | + struct a6xx_gmu_bo debug; | |
| 61 | + struct a6xx_gmu_bo icache; | |
| 62 | + struct a6xx_gmu_bo dcache; | |
| 63 | + struct a6xx_gmu_bo dummy; | |
| 64 | + struct a6xx_gmu_bo log; | |
| 57 | 65 | |
| 58 | 66 | int nr_clocks; |
| 59 | 67 | struct clk_bulk_data *clocks; |
| @@ -76,6 +84,7 @@ struct a6xx_gmu { · 16 unmodified lines | ||
| 76 | 84 | |
| 77 | 85 | bool initialized; |
| 78 | 86 | bool hung; |
| 87 | + bool legacy; /* a618 or a630 */ | |
| 79 | 88 | }; |
| 80 | 89 | |
| 81 | 90 | static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset) |
| @@ -88,6 +97,13 @@ static inline void gmu_write(struct a6xx_gmu *gmu, u32 offset, u32 value) · 6 unmodified lines | ||
| 88 | 97 | return msm_writel(value, gmu->mmio + (offset << 2)); |
| 89 | 98 | } |
| 90 | 99 | |
| 100 | +static inline void | |
| 101 | +gmu_write_bulk(struct a6xx_gmu *gmu, u32 offset, const u32 *data, u32 size) | |
| 102 | +{ | |
| 103 | + memcpy_toio(gmu->mmio + (offset << 2), data, size); | |
| 104 | + wmb(); | |
| 105 | +} | |
| 106 | + | |
| 91 | 107 | static inline void gmu_rmw(struct a6xx_gmu *gmu, u32 reg, u32 mask, u32 or) |
| 92 | 108 | { |
| 93 | 109 | u32 val = gmu_read(gmu, reg); |
| @@ -111,6 +127,15 @@ static inline u64 gmu_read64(struct a6xx_gmu *gmu, u32 lo, u32 hi) · 17 unmodified lines | ||
| 111 | 127 | readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \ |
| 112 | 128 | interval, timeout) |
| 113 | 129 | |
| 130 | +static inline void gmu_write_rscc(struct a6xx_gmu *gmu, u32 offset, u32 value) | |
| 131 | +{ | |
| 132 | + return msm_writel(value, gmu->rscc + (offset << 2)); | |
| 133 | +} | |
| 134 | + | |
| 135 | +#define gmu_poll_timeout_rscc(gmu, addr, val, cond, interval, timeout) \ | |
| 136 | + readl_poll_timeout((gmu)->rscc + ((addr) << 2), val, cond, \ | |
| 137 | + interval, timeout) | |
| 138 | + | |
| 114 | 139 | /* |
| 115 | 140 | * These are the available OOB (out of band requests) to the GMU where "out of |
| 116 | 141 | * band" means that the CPU talks to the GMU directly and not through HFI. |
| @@ -156,10 +181,16 @@ enum a6xx_gmu_oob_state { · 39 unmodified lines | ||
| 156 | 181 | #define GMU_OOB_GPU_SET_ACK 24 |
| 157 | 182 | #define GMU_OOB_GPU_SET_CLEAR 24 |
| 158 | 183 | |
| 184 | +#define GMU_OOB_GPU_SET_REQUEST_NEW 30 | |
| 185 | +#define GMU_OOB_GPU_SET_ACK_NEW 31 | |
| 186 | +#define GMU_OOB_GPU_SET_CLEAR_NEW 31 | |
| 187 | + | |
| 159 | 188 | |
| 160 | 189 | void a6xx_hfi_init(struct a6xx_gmu *gmu); |
| 161 | 190 | int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state); |
| 162 | 191 | void a6xx_hfi_stop(struct a6xx_gmu *gmu); |
| 192 | +int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu); | |
| 193 | +int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, int index); | |
| 163 | 194 | |
| 164 | 195 | bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu); |
| 165 | 196 | bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu); |
| @@ -101,6 +101,10 @@ static inline uint32_t A6XX_HFI_IRQ_OOB_MASK(uint32_t val) · 100 unmodified lines | ||
| 101 | 101 | |
| 102 | 102 | #define REG_A6XX_GMU_DCVS_RETURN 0x000023ff |
| 103 | 103 | |
| 104 | +#define REG_A6XX_GMU_ICACHE_CONFIG 0x00004c00 | |
| 105 | + | |
| 106 | +#define REG_A6XX_GMU_DCACHE_CONFIG 0x00004c01 | |
| 107 | + | |
| 104 | 108 | #define REG_A6XX_GMU_SYS_BUS_CONFIG 0x00004c0f |
| 105 | 109 | |
| 106 | 110 | #define REG_A6XX_GMU_CM3_SYSRESET 0x00005000 |
| @@ -199,6 +203,12 @@ static inline uint32_t A6XX_GMU_GPU_NAP_CTRL_SID(uint32_t val) · 92 unmodified lines | ||
| 199 | 203 | |
| 200 | 204 | #define REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE 0x000050ec |
| 201 | 205 | |
| 206 | +#define REG_A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF 0x000050f0 | |
| 207 | + | |
| 208 | +#define REG_A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_MSG 0x00005100 | |
| 209 | + | |
| 210 | +#define REG_A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_RESP 0x00005101 | |
| 211 | + | |
| 202 | 212 | #define REG_A6XX_GMU_BOOT_KMD_LM_HANDSHAKE 0x000051f0 |
| 203 | 213 | |
| 204 | 214 | #define REG_A6XX_GMU_LLM_GLM_SLEEP_CTRL 0x00005157 |
| @@ -330,8 +340,6 @@ static inline uint32_t A6XX_GMU_GPU_NAP_CTRL_SID(uint32_t val) · 125 unmodified lines | ||
| 330 | 340 | |
| 331 | 341 | #define REG_A6XX_GMU_AO_SPARE_CNTL 0x00009316 |
| 332 | 342 | |
| 333 | −#define REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0 0x00008c04 | |
| 334 | − | |
| 335 | 343 | #define REG_A6XX_GMU_RSCC_CONTROL_REQ 0x00009307 |
| 336 | 344 | |
| 337 | 345 | #define REG_A6XX_GMU_RSCC_CONTROL_ACK 0x00009308 |
| @@ -344,39 +352,41 @@ static inline uint32_t A6XX_GMU_GPU_NAP_CTRL_SID(uint32_t val) · 6 unmodified lines | ||
| 344 | 352 | |
| 345 | 353 | #define REG_A6XX_GPU_CC_GX_DOMAIN_MISC 0x00009d42 |
| 346 | 354 | |
| 347 | −#define REG_A6XX_RSCC_PDC_SEQ_START_ADDR 0x00008c08 | |
| 355 | +#define REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0 0x00000004 | |
| 356 | + | |
| 357 | +#define REG_A6XX_RSCC_PDC_SEQ_START_ADDR 0x00000008 | |
| 348 | 358 | |
| 349 | −#define REG_A6XX_RSCC_PDC_MATCH_VALUE_LO 0x00008c09 | |
| 359 | +#define REG_A6XX_RSCC_PDC_MATCH_VALUE_LO 0x00000009 | |
| 350 | 360 | |
| 351 | −#define REG_A6XX_RSCC_PDC_MATCH_VALUE_HI 0x00008c0a | |
| 361 | +#define REG_A6XX_RSCC_PDC_MATCH_VALUE_HI 0x0000000a | |
| 352 | 362 | |
| 353 | −#define REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0 0x00008c0b | |
| 363 | +#define REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0 0x0000000b | |
| 354 | 364 | |
| 355 | −#define REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR 0x00008c0d | |
| 365 | +#define REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR 0x0000000d | |
| 356 | 366 | |
| 357 | −#define REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA 0x00008c0e | |
| 367 | +#define REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA 0x0000000e | |
| 358 | 368 | |
| 359 | −#define REG_A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0 0x00008c82 | |
| 369 | +#define REG_A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0 0x00000082 | |
| 360 | 370 | |
| 361 | −#define REG_A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0 0x00008c83 | |
| 371 | +#define REG_A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0 0x00000083 | |
| 362 | 372 | |
| 363 | −#define REG_A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0 0x00008c89 | |
| 373 | +#define REG_A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0 0x00000089 | |
| 364 | 374 | |
| 365 | −#define REG_A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0 0x00008c8c | |
| 375 | +#define REG_A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0 0x0000008c | |
| 366 | 376 | |
| 367 | −#define REG_A6XX_RSCC_OVERRIDE_START_ADDR 0x00008d00 | |
| 377 | +#define REG_A6XX_RSCC_OVERRIDE_START_ADDR 0x00000100 | |
| 368 | 378 | |
| 369 | −#define REG_A6XX_RSCC_SEQ_BUSY_DRV0 0x00008d01 | |
| 379 | +#define REG_A6XX_RSCC_SEQ_BUSY_DRV0 0x00000101 | |
| 370 | 380 | |
| 371 | −#define REG_A6XX_RSCC_SEQ_MEM_0_DRV0 0x00008d80 | |
| 381 | +#define REG_A6XX_RSCC_SEQ_MEM_0_DRV0 0x00000180 | |
| 372 | 382 | |
| 373 | −#define REG_A6XX_RSCC_TCS0_DRV0_STATUS 0x00008f46 | |
| 383 | +#define REG_A6XX_RSCC_TCS0_DRV0_STATUS 0x00000346 | |
| 374 | 384 | |
| 375 | −#define REG_A6XX_RSCC_TCS1_DRV0_STATUS 0x000090ae | |
| 385 | +#define REG_A6XX_RSCC_TCS1_DRV0_STATUS 0x000003ee | |
| 376 | 386 | |
| 377 | −#define REG_A6XX_RSCC_TCS2_DRV0_STATUS 0x00009216 | |
| 387 | +#define REG_A6XX_RSCC_TCS2_DRV0_STATUS 0x00000496 | |
| 378 | 388 | |
| 379 | −#define REG_A6XX_RSCC_TCS3_DRV0_STATUS 0x0000937e | |
| 389 | +#define REG_A6XX_RSCC_TCS3_DRV0_STATUS 0x0000053e | |
| 380 | 390 | |
| 381 | 391 | |
| 382 | 392 | #endif /* A6XX_GMU_XML */ |
| @@ -414,7 +414,17 @@ static int a6xx_hw_init(struct msm_gpu *gpu) · 413 unmodified lines | ||
| 414 | 414 | a6xx_set_hwcg(gpu, true); |
| 415 | 415 | |
| 416 | 416 | /* VBIF/GBIF start*/ |
| 417 | − gpu_write(gpu, REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3); | |
| 417 | + if (adreno_is_a640(adreno_gpu) || adreno_is_a650(adreno_gpu)) { | |
| 418 | + gpu_write(gpu, REG_A6XX_GBIF_QSB_SIDE0, 0x00071620); | |
| 419 | + gpu_write(gpu, REG_A6XX_GBIF_QSB_SIDE1, 0x00071620); | |
| 420 | + gpu_write(gpu, REG_A6XX_GBIF_QSB_SIDE2, 0x00071620); | |
| 421 | + gpu_write(gpu, REG_A6XX_GBIF_QSB_SIDE3, 0x00071620); | |
| 422 | + gpu_write(gpu, REG_A6XX_GBIF_QSB_SIDE3, 0x00071620); | |
| 423 | + gpu_write(gpu, REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x3); | |
| 424 | + } else { | |
| 425 | + gpu_write(gpu, REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3); | |
| 426 | + } | |
| 427 | + | |
| 418 | 428 | if (adreno_is_a630(adreno_gpu)) |
| 419 | 429 | gpu_write(gpu, REG_A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); |
| 420 | 430 | |
| @@ -429,25 +439,35 @@ static int a6xx_hw_init(struct msm_gpu *gpu) · 8 unmodified lines | ||
| 429 | 439 | gpu_write(gpu, REG_A6XX_UCHE_WRITE_THRU_BASE_LO, 0xfffff000); |
| 430 | 440 | gpu_write(gpu, REG_A6XX_UCHE_WRITE_THRU_BASE_HI, 0x0001ffff); |
| 431 | 441 | |
| 432 | − /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ | |
| 433 | − gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, | |
| 434 | − REG_A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000); | |
| 442 | + if (!adreno_is_a650(adreno_gpu)) { | |
| 443 | + /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ | |
| 444 | + gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, | |
| 445 | + REG_A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000); | |
| 435 | 446 | |
| 436 | − gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX_LO, | |
| 437 | − REG_A6XX_UCHE_GMEM_RANGE_MAX_HI, | |
| 438 | − 0x00100000 + adreno_gpu->gmem - 1); | |
| 447 | + gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX_LO, | |
| 448 | + REG_A6XX_UCHE_GMEM_RANGE_MAX_HI, | |
| 449 | + 0x00100000 + adreno_gpu->gmem - 1); | |
| 450 | + } | |
| 439 | 451 | |
| 440 | 452 | gpu_write(gpu, REG_A6XX_UCHE_FILTER_CNTL, 0x804); |
| 441 | 453 | gpu_write(gpu, REG_A6XX_UCHE_CACHE_WAYS, 0x4); |
| 442 | 454 | |
| 443 | − gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2, 0x010000c0); | |
| 455 | + if (adreno_is_a640(adreno_gpu) || adreno_is_a650(adreno_gpu)) | |
| 456 | + gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2, 0x02000140); | |
| 457 | + else | |
| 458 | + gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2, 0x010000c0); | |
| 444 | 459 | gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_1, 0x8040362c); |
| 445 | 460 | |
| 446 | 461 | /* Setting the mem pool size */ |
| 447 | 462 | gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 128); |
| 448 | 463 | |
| 449 | 464 | /* Setting the primFifo thresholds default values */ |
| 450 | − gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, (0x300 << 11)); | |
| 465 | + if (adreno_is_a650(adreno_gpu)) | |
| 466 | + gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00300000); | |
| 467 | + else if (adreno_is_a640(adreno_gpu)) | |
| 468 | + gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00200000); | |
| 469 | + else | |
| 470 | + gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, (0x300 << 11)); | |
| 451 | 471 | |
| 452 | 472 | /* Set the AHB default slave response to "ERROR" */ |
| 453 | 473 | gpu_write(gpu, REG_A6XX_CP_AHB_CNTL, 0x1); |
| @@ -471,6 +491,19 @@ static int a6xx_hw_init(struct msm_gpu *gpu) · 17 unmodified lines | ||
| 471 | 491 | |
| 472 | 492 | gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, 1); |
| 473 | 493 | |
| 494 | + /* Set weights for bicubic filtering */ | |
| 495 | + if (adreno_is_a650(adreno_gpu)) { | |
| 496 | + gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_0, 0); | |
| 497 | + gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_1, | |
| 498 | + 0x3fe05ff4); | |
| 499 | + gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_2, | |
| 500 | + 0x3fa0ebee); | |
| 501 | + gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_3, | |
| 502 | + 0x3f5193ed); | |
| 503 | + gpu_write(gpu, REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE_4, | |
| 504 | + 0x3f0243f0); | |
| 505 | + } | |
| 506 | + | |
| 474 | 507 | /* Protect registers from the CP */ |
| 475 | 508 | gpu_write(gpu, REG_A6XX_CP_PROTECT_CNTL, 0x00000003); |
| 476 | 509 | |
| @@ -508,6 +541,11 @@ static int a6xx_hw_init(struct msm_gpu *gpu) · 31 unmodified lines | ||
| 508 | 541 | A6XX_PROTECT_RDONLY(0x980, 0x4)); |
| 509 | 542 | gpu_write(gpu, REG_A6XX_CP_PROTECT(25), A6XX_PROTECT_RW(0xa630, 0x0)); |
| 510 | 543 | |
| 544 | + if (adreno_is_a650(adreno_gpu)) { | |
| 545 | + gpu_write(gpu, REG_A6XX_CP_APRIV_CNTL, | |
| 546 | + (1 << 6) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1)); | |
| 547 | + } | |
| 548 | + | |
| 511 | 549 | /* Enable interrupts */ |
| 512 | 550 | gpu_write(gpu, REG_A6XX_RBBM_INT_0_MASK, A6XX_INT_MASK); |
| 513 | 551 | |
| @@ -566,8 +604,10 @@ out: · 52 unmodified lines | ||
| 566 | 604 | */ |
| 567 | 605 | a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); |
| 568 | 606 | |
| 569 | − /* Take the GMU out of its special boot mode */ | |
| 570 | − a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER); | |
| 607 | + if (a6xx_gpu->gmu.legacy) { | |
| 608 | + /* Take the GMU out of its special boot mode */ | |
| 609 | + a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER); | |
| 610 | + } | |
| 571 | 611 | |
| 572 | 612 | return ret; |
| 573 | 613 | } |
| @@ -810,6 +850,11 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) · 236 unmodified lines | ||
| 810 | 850 | struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); |
| 811 | 851 | u64 busy_cycles, busy_time; |
| 812 | 852 | |
| 853 | + | |
| 854 | + /* Only read the gpu busy if the hardware is already active */ | |
| 855 | + if (pm_runtime_get_if_in_use(a6xx_gpu->gmu.dev) == 0) | |
| 856 | + return 0; | |
| 857 | + | |
| 813 | 858 | busy_cycles = gmu_read64(&a6xx_gpu->gmu, |
| 814 | 859 | REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, |
| 815 | 860 | REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H); |
| @@ -819,6 +864,8 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) · 3 unmodified lines | ||
| 819 | 864 | |
| 820 | 865 | gpu->devfreq.busy_cycles = busy_cycles; |
| 821 | 866 | |
| 867 | + pm_runtime_put(a6xx_gpu->gmu.dev); | |
| 868 | + | |
| 822 | 869 | if (WARN_ON(busy_time > ~0LU)) |
| 823 | 870 | return ~0LU; |
| 824 | 871 | |
| @@ -846,6 +893,7 @@ static const struct adreno_gpu_funcs funcs = { · 21 unmodified lines | ||
| 846 | 893 | #if defined(CONFIG_DRM_MSM_GPU_STATE) |
| 847 | 894 | .gpu_state_get = a6xx_gpu_state_get, |
| 848 | 895 | .gpu_state_put = a6xx_gpu_state_put, |
| 896 | + .create_address_space = adreno_iommu_create_address_space, | |
| 849 | 897 | #endif |
| 850 | 898 | }, |
| 851 | 899 | .get_timestamp = a6xx_get_timestamp, |
| @@ -17,10 +17,14 @@ static const char * const a6xx_hfi_msg_id[] = { · 16 unmodified lines | ||
| 17 | 17 | HFI_MSG_ID(HFI_H2F_MSG_BW_TABLE), |
| 18 | 18 | HFI_MSG_ID(HFI_H2F_MSG_PERF_TABLE), |
| 19 | 19 | HFI_MSG_ID(HFI_H2F_MSG_TEST), |
| 20 | + HFI_MSG_ID(HFI_H2F_MSG_START), | |
| 21 | + HFI_MSG_ID(HFI_H2F_MSG_CORE_FW_START), | |
| 22 | + HFI_MSG_ID(HFI_H2F_MSG_GX_BW_PERF_VOTE), | |
| 23 | + HFI_MSG_ID(HFI_H2F_MSG_PREPARE_SLUMBER), | |
| 20 | 24 | }; |
| 21 | 25 | |
| 22 | −static int a6xx_hfi_queue_read(struct a6xx_hfi_queue *queue, u32 *data, | |
| 23 | − u32 dwords) | |
| 26 | +static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, | |
| 27 | + struct a6xx_hfi_queue *queue, u32 *data, u32 dwords) | |
| 24 | 28 | { |
| 25 | 29 | struct a6xx_hfi_queue_header *header = queue->header; |
| 26 | 30 | u32 i, hdr, index = header->read_index; |
| @@ -48,6 +52,9 @@ static int a6xx_hfi_queue_read(struct a6xx_hfi_queue *queue, u32 *data, · 21 unmodified lines | ||
| 48 | 52 | index = (index + 1) % header->size; |
| 49 | 53 | } |
| 50 | 54 | |
| 55 | + if (!gmu->legacy) | |
| 56 | + index = ALIGN(index, 4) % header->size; | |
| 57 | + | |
| 51 | 58 | header->read_index = index; |
| 52 | 59 | return HFI_HEADER_SIZE(hdr); |
| 53 | 60 | } |
| @@ -73,6 +80,12 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, · 19 unmodified lines | ||
| 73 | 80 | index = (index + 1) % header->size; |
| 74 | 81 | } |
| 75 | 82 | |
| 83 | + /* Cookify any non used data at the end of the write buffer */ | |
| 84 | + if (!gmu->legacy) { | |
| 85 | + for (; index % 4; index = (index + 1) % header->size) | |
| 86 | + queue->data[index] = 0xfafafafa; | |
| 87 | + } | |
| 88 | + | |
| 76 | 89 | header->write_index = index; |
| 77 | 90 | spin_unlock(&queue->lock); |
| 78 | 91 | |
| @@ -106,7 +119,7 @@ static int a6xx_hfi_wait_for_ack(struct a6xx_gmu *gmu, u32 id, u32 seqnum, · 27 unmodified lines | ||
| 106 | 119 | struct a6xx_hfi_msg_response resp; |
| 107 | 120 | |
| 108 | 121 | /* Get the next packet */ |
| 109 | − ret = a6xx_hfi_queue_read(queue, (u32 *) &resp, | |
| 122 | + ret = a6xx_hfi_queue_read(gmu, queue, (u32 *) &resp, | |
| 110 | 123 | sizeof(resp) >> 2); |
| 111 | 124 | |
| 112 | 125 | /* If the queue is empty our response never made it */ |
| @@ -176,8 +189,8 @@ static int a6xx_hfi_send_gmu_init(struct a6xx_gmu *gmu, int boot_state) · 63 unmodified lines | ||
| 176 | 189 | { |
| 177 | 190 | struct a6xx_hfi_msg_gmu_init_cmd msg = { 0 }; |
| 178 | 191 | |
| 179 | − msg.dbg_buffer_addr = (u32) gmu->debug->iova; | |
| 180 | − msg.dbg_buffer_size = (u32) gmu->debug->size; | |
| 192 | + msg.dbg_buffer_addr = (u32) gmu->debug.iova; | |
| 193 | + msg.dbg_buffer_size = (u32) gmu->debug.size; | |
| 181 | 194 | msg.boot_state = boot_state; |
| 182 | 195 | |
| 183 | 196 | return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_INIT, &msg, sizeof(msg), |
| @@ -195,6 +208,28 @@ static int a6xx_hfi_get_fw_version(struct a6xx_gmu *gmu, u32 *version) · 11 unmodified lines | ||
| 195 | 208 | version, sizeof(*version)); |
| 196 | 209 | } |
| 197 | 210 | |
| 211 | +static int a6xx_hfi_send_perf_table_v1(struct a6xx_gmu *gmu) | |
| 212 | +{ | |
| 213 | + struct a6xx_hfi_msg_perf_table_v1 msg = { 0 }; | |
| 214 | + int i; | |
| 215 | + | |
| 216 | + msg.num_gpu_levels = gmu->nr_gpu_freqs; | |
| 217 | + msg.num_gmu_levels = gmu->nr_gmu_freqs; | |
| 218 | + | |
| 219 | + for (i = 0; i < gmu->nr_gpu_freqs; i++) { | |
| 220 | + msg.gx_votes[i].vote = gmu->gx_arc_votes[i]; | |
| 221 | + msg.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; | |
| 222 | + } | |
| 223 | + | |
| 224 | + for (i = 0; i < gmu->nr_gmu_freqs; i++) { | |
| 225 | + msg.cx_votes[i].vote = gmu->cx_arc_votes[i]; | |
| 226 | + msg.cx_votes[i].freq = gmu->gmu_freqs[i] / 1000; | |
| 227 | + } | |
| 228 | + | |
| 229 | + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_PERF_TABLE, &msg, sizeof(msg), | |
| 230 | + NULL, 0); | |
| 231 | +} | |
| 232 | + | |
| 198 | 233 | static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu) |
| 199 | 234 | { |
| 200 | 235 | struct a6xx_hfi_msg_perf_table msg = { 0 }; |
| @@ -205,6 +240,7 @@ static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu) · 4 unmodified lines | ||
| 205 | 240 | |
| 206 | 241 | for (i = 0; i < gmu->nr_gpu_freqs; i++) { |
| 207 | 242 | msg.gx_votes[i].vote = gmu->gx_arc_votes[i]; |
| 243 | + msg.gx_votes[i].acd = 0xffffffff; | |
| 208 | 244 | msg.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; |
| 209 | 245 | } |
| 210 | 246 | |
| @@ -306,7 +342,45 @@ static int a6xx_hfi_send_test(struct a6xx_gmu *gmu) · 95 unmodified lines | ||
| 306 | 342 | NULL, 0); |
| 307 | 343 | } |
| 308 | 344 | |
| 309 | −int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) | |
| 345 | +static int a6xx_hfi_send_start(struct a6xx_gmu *gmu) | |
| 346 | +{ | |
| 347 | + struct a6xx_hfi_msg_start msg = { 0 }; | |
| 348 | + | |
| 349 | + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_START, &msg, sizeof(msg), | |
| 350 | + NULL, 0); | |
| 351 | +} | |
| 352 | + | |
| 353 | +static int a6xx_hfi_send_core_fw_start(struct a6xx_gmu *gmu) | |
| 354 | +{ | |
| 355 | + struct a6xx_hfi_msg_core_fw_start msg = { 0 }; | |
| 356 | + | |
| 357 | + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_CORE_FW_START, &msg, | |
| 358 | + sizeof(msg), NULL, 0); | |
| 359 | +} | |
| 360 | + | |
| 361 | +int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, int index) | |
| 362 | +{ | |
| 363 | + struct a6xx_hfi_gx_bw_perf_vote_cmd msg = { 0 }; | |
| 364 | + | |
| 365 | + msg.ack_type = 1; /* blocking */ | |
| 366 | + msg.freq = index; | |
| 367 | + msg.bw = 0; /* TODO: bus scaling */ | |
| 368 | + | |
| 369 | + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_GX_BW_PERF_VOTE, &msg, | |
| 370 | + sizeof(msg), NULL, 0); | |
| 371 | +} | |
| 372 | + | |
| 373 | +int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu) | |
| 374 | +{ | |
| 375 | + struct a6xx_hfi_prep_slumber_cmd msg = { 0 }; | |
| 376 | + | |
| 377 | + /* TODO: should freq and bw fields be non-zero ? */ | |
| 378 | + | |
| 379 | + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_PREPARE_SLUMBER, &msg, | |
| 380 | + sizeof(msg), NULL, 0); | |
| 381 | +} | |
| 382 | + | |
| 383 | +static int a6xx_hfi_start_v1(struct a6xx_gmu *gmu, int boot_state) | |
| 310 | 384 | { |
| 311 | 385 | int ret; |
| 312 | 386 | |
| @@ -324,7 +398,7 @@ int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) · 11 unmodified lines | ||
| 324 | 398 | * the GMU firmware |
| 325 | 399 | */ |
| 326 | 400 | |
| 327 | − ret = a6xx_hfi_send_perf_table(gmu); | |
| 401 | + ret = a6xx_hfi_send_perf_table_v1(gmu); | |
| 328 | 402 | if (ret) |
| 329 | 403 | return ret; |
| 330 | 404 | |
| @@ -341,6 +415,37 @@ int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) · 10 unmodified lines | ||
| 341 | 415 | return 0; |
| 342 | 416 | } |
| 343 | 417 | |
| 418 | +int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) | |
| 419 | +{ | |
| 420 | + int ret; | |
| 421 | + | |
| 422 | + if (gmu->legacy) | |
| 423 | + return a6xx_hfi_start_v1(gmu, boot_state); | |
| 424 | + | |
| 425 | + | |
| 426 | + ret = a6xx_hfi_send_perf_table(gmu); | |
| 427 | + if (ret) | |
| 428 | + return ret; | |
| 429 | + | |
| 430 | + ret = a6xx_hfi_send_bw_table(gmu); | |
| 431 | + if (ret) | |
| 432 | + return ret; | |
| 433 | + | |
| 434 | + ret = a6xx_hfi_send_core_fw_start(gmu); | |
| 435 | + if (ret) | |
| 436 | + return ret; | |
| 437 | + | |
| 438 | + /* | |
| 439 | + * Downstream driver sends this in its "a6xx_hw_init" equivalent, | |
| 440 | + * but seems to be no harm in sending it here | |
| 441 | + */ | |
| 442 | + ret = a6xx_hfi_send_start(gmu); | |
| 443 | + if (ret) | |
| 444 | + return ret; | |
| 445 | + | |
| 446 | + return 0; | |
| 447 | +} | |
| 448 | + | |
| 344 | 449 | void a6xx_hfi_stop(struct a6xx_gmu *gmu) |
| 345 | 450 | { |
| 346 | 451 | int i; |
| @@ -385,7 +490,7 @@ static void a6xx_hfi_queue_init(struct a6xx_hfi_queue *queue, · 38 unmodified lines | ||
| 385 | 490 | |
| 386 | 491 | void a6xx_hfi_init(struct a6xx_gmu *gmu) |
| 387 | 492 | { |
| 388 | − struct a6xx_gmu_bo *hfi = gmu->hfi; | |
| 493 | + struct a6xx_gmu_bo *hfi = &gmu->hfi; | |
| 389 | 494 | struct a6xx_hfi_queue_table_header *table = hfi->virt; |
| 390 | 495 | struct a6xx_hfi_queue_header *headers = hfi->virt + sizeof(*table); |
| 391 | 496 | u64 offset; |
| @@ -415,5 +520,5 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu) · 23 unmodified lines | ||
| 415 | 520 | /* GMU response queue */ |
| 416 | 521 | offset += SZ_4K; |
| 417 | 522 | a6xx_hfi_queue_init(&gmu->queues[1], &headers[1], hfi->virt + offset, |
| 418 | − hfi->iova + offset, 4); | |
| 523 | + hfi->iova + offset, gmu->legacy ? 4 : 1); | |
| 419 | 524 | } |
| @@ -51,7 +51,8 @@ struct a6xx_hfi_queue { · 50 unmodified lines | ||
| 51 | 51 | /* HFI message types */ |
| 52 | 52 | |
| 53 | 53 | #define HFI_MSG_CMD 0 |
| 54 | −#define HFI_MSG_ACK 2 | |
| 54 | +#define HFI_MSG_ACK 1 | |
| 55 | +#define HFI_MSG_ACK_V1 2 | |
| 55 | 56 | |
| 56 | 57 | #define HFI_F2H_MSG_ACK 126 |
| 57 | 58 | |
| @@ -94,7 +95,13 @@ struct perf_level { · 36 unmodified lines | ||
| 94 | 95 | u32 freq; |
| 95 | 96 | }; |
| 96 | 97 | |
| 97 | −struct a6xx_hfi_msg_perf_table { | |
| 98 | +struct perf_gx_level { | |
| 99 | + u32 vote; | |
| 100 | + u32 acd; | |
| 101 | + u32 freq; | |
| 102 | +}; | |
| 103 | + | |
| 104 | +struct a6xx_hfi_msg_perf_table_v1 { | |
| 98 | 105 | u32 header; |
| 99 | 106 | u32 num_gpu_levels; |
| 100 | 107 | u32 num_gmu_levels; |
| @@ -103,6 +110,15 @@ struct a6xx_hfi_msg_perf_table { · 2 unmodified lines | ||
| 103 | 110 | struct perf_level cx_votes[4]; |
| 104 | 111 | }; |
| 105 | 112 | |
| 113 | +struct a6xx_hfi_msg_perf_table { | |
| 114 | + u32 header; | |
| 115 | + u32 num_gpu_levels; | |
| 116 | + u32 num_gmu_levels; | |
| 117 | + | |
| 118 | + struct perf_gx_level gx_votes[16]; | |
| 119 | + struct perf_level cx_votes[4]; | |
| 120 | +}; | |
| 121 | + | |
| 106 | 122 | #define HFI_H2F_MSG_BW_TABLE 3 |
| 107 | 123 | |
| 108 | 124 | struct a6xx_hfi_msg_bw_table { |
| @@ -124,4 +140,34 @@ struct a6xx_hfi_msg_test { · 15 unmodified lines | ||
| 124 | 140 | u32 header; |
| 125 | 141 | }; |
| 126 | 142 | |
| 143 | +#define HFI_H2F_MSG_START 10 | |
| 144 | + | |
| 145 | +struct a6xx_hfi_msg_start { | |
| 146 | + u32 header; | |
| 147 | +}; | |
| 148 | + | |
| 149 | +#define HFI_H2F_MSG_CORE_FW_START 14 | |
| 150 | + | |
| 151 | +struct a6xx_hfi_msg_core_fw_start { | |
| 152 | + u32 header; | |
| 153 | + u32 handle; | |
| 154 | +}; | |
| 155 | + | |
| 156 | +#define HFI_H2F_MSG_GX_BW_PERF_VOTE 30 | |
| 157 | + | |
| 158 | +struct a6xx_hfi_gx_bw_perf_vote_cmd { | |
| 159 | + u32 header; | |
| 160 | + u32 ack_type; | |
| 161 | + u32 freq; | |
| 162 | + u32 bw; | |
| 163 | +}; | |
| 164 | + | |
| 165 | +#define HFI_H2F_MSG_PREPARE_SLUMBER 33 | |
| 166 | + | |
| 167 | +struct a6xx_hfi_prep_slumber_cmd { | |
| 168 | + u32 header; | |
| 169 | + u32 bw; | |
| 170 | + u32 freq; | |
| 171 | +}; | |
| 172 | + | |
| 127 | 173 | #endif |
| @@ -92,6 +92,17 @@ static const struct adreno_info gpulist[] = { · 91 unmodified lines | ||
| 92 | 92 | .gmem = SZ_1M, |
| 93 | 93 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, |
| 94 | 94 | .init = a3xx_gpu_init, |
| 95 | + }, { | |
| 96 | + .rev = ADRENO_REV(4, 0, 5, ANY_ID), | |
| 97 | + .revn = 405, | |
| 98 | + .name = "A405", | |
| 99 | + .fw = { | |
| 100 | + [ADRENO_FW_PM4] = "a420_pm4.fw", | |
| 101 | + [ADRENO_FW_PFP] = "a420_pfp.fw", | |
| 102 | + }, | |
| 103 | + .gmem = SZ_256K, | |
| 104 | + .inactive_period = DRM_MSM_INACTIVE_PERIOD, | |
| 105 | + .init = a4xx_gpu_init, | |
| 95 | 106 | }, { |
| 96 | 107 | .rev = ADRENO_REV(4, 2, 0, ANY_ID), |
| 97 | 108 | .revn = 420, |
| @@ -189,6 +200,30 @@ static const struct adreno_info gpulist[] = { · 91 unmodified lines | ||
| 189 | 200 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, |
| 190 | 201 | .init = a6xx_gpu_init, |
| 191 | 202 | .zapfw = "a630_zap.mdt", |
| 203 | + }, { | |
| 204 | + .rev = ADRENO_REV(6, 4, 0, ANY_ID), | |
| 205 | + .revn = 640, | |
| 206 | + .name = "A640", | |
| 207 | + .fw = { | |
| 208 | + [ADRENO_FW_SQE] = "a630_sqe.fw", | |
| 209 | + [ADRENO_FW_GMU] = "a640_gmu.bin", | |
| 210 | + }, | |
| 211 | + .gmem = SZ_1M, | |
| 212 | + .inactive_period = DRM_MSM_INACTIVE_PERIOD, | |
| 213 | + .init = a6xx_gpu_init, | |
| 214 | + .zapfw = "a640_zap.mdt", | |
| 215 | + }, { | |
| 216 | + .rev = ADRENO_REV(6, 5, 0, ANY_ID), | |
| 217 | + .revn = 650, | |
| 218 | + .name = "A650", | |
| 219 | + .fw = { | |
| 220 | + [ADRENO_FW_SQE] = "a650_sqe.fw", | |
| 221 | + [ADRENO_FW_GMU] = "a650_gmu.bin", | |
| 222 | + }, | |
| 223 | + .gmem = SZ_1M + SZ_128K, | |
| 224 | + .inactive_period = DRM_MSM_INACTIVE_PERIOD, | |
| 225 | + .init = a6xx_gpu_init, | |
| 226 | + .zapfw = "a650_zap.mdt", | |
| 192 | 227 | }, |
| 193 | 228 | }; |
| 194 | 229 | |
| @@ -185,6 +185,23 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) · 184 unmodified lines | ||
| 185 | 185 | return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | +struct msm_gem_address_space * | |
| 189 | +adreno_iommu_create_address_space(struct msm_gpu *gpu, | |
| 190 | + struct platform_device *pdev) | |
| 191 | +{ | |
| 192 | + struct iommu_domain *iommu = iommu_domain_alloc(&platform_bus_type); | |
| 193 | + struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu); | |
| 194 | + struct msm_gem_address_space *aspace; | |
| 195 | + | |
| 196 | + aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M, | |
| 197 | + 0xfffffff); | |
| 198 | + | |
| 199 | + if (IS_ERR(aspace) && !IS_ERR(mmu)) | |
| 200 | + mmu->funcs->destroy(mmu); | |
| 201 | + | |
| 202 | + return aspace; | |
| 203 | +} | |
| 204 | + | |
| 188 | 205 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) |
| 189 | 206 | { |
| 190 | 207 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
| @@ -197,7 +214,7 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) · 6 unmodified lines | ||
| 197 | 214 | *value = adreno_gpu->gmem; |
| 198 | 215 | return 0; |
| 199 | 216 | case MSM_PARAM_GMEM_BASE: |
| 200 | − *value = 0x100000; | |
| 217 | + *value = !adreno_is_a650(adreno_gpu) ? 0x100000 : 0; | |
| 201 | 218 | return 0; |
| 202 | 219 | case MSM_PARAM_CHIP_ID: |
| 203 | 220 | *value = adreno_gpu->rev.patchid | |
| @@ -459,7 +476,7 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, · 255 unmodified lines | ||
| 459 | 476 | break; |
| 460 | 477 | /* fall-thru */ |
| 461 | 478 | case MSM_SUBMIT_CMD_BUF: |
| 462 | − OUT_PKT3(ring, adreno_is_a430(adreno_gpu) ? | |
| 479 | + OUT_PKT3(ring, adreno_is_a4xx(adreno_gpu) ? | |
| 463 | 480 | CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); |
| 464 | 481 | OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); |
| 465 | 482 | OUT_RING(ring, submit->cmd[i].size); |
| @@ -988,12 +1005,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, · 522 unmodified lines | ||
| 988 | 1005 | |
| 989 | 1006 | adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; |
| 990 | 1007 | |
| 991 | − adreno_gpu_config.va_start = SZ_16M; | |
| 992 | − adreno_gpu_config.va_end = 0xffffffff; | |
| 993 | − /* maximum range of a2xx mmu */ | |
| 994 | − if (adreno_is_a2xx(adreno_gpu)) | |
| 995 | − adreno_gpu_config.va_end = SZ_16M + 0xfff * SZ_64K; | |
| 996 | − | |
| 997 | 1008 | adreno_gpu_config.nr_rings = nr_rings; |
| 998 | 1009 | |
| 999 | 1010 | adreno_get_pwrlevels(&pdev->dev, gpu); |
| @@ -202,6 +202,11 @@ static inline bool adreno_is_a4xx(struct adreno_gpu *gpu) · 201 unmodified lines | ||
| 202 | 202 | return (gpu->revn >= 400) && (gpu->revn < 500); |
| 203 | 203 | } |
| 204 | 204 | |
| 205 | +static inline int adreno_is_a405(struct adreno_gpu *gpu) | |
| 206 | +{ | |
| 207 | + return gpu->revn == 405; | |
| 208 | +} | |
| 209 | + | |
| 205 | 210 | static inline int adreno_is_a420(struct adreno_gpu *gpu) |
| 206 | 211 | { |
| 207 | 212 | return gpu->revn == 420; |
| @@ -237,6 +242,16 @@ static inline int adreno_is_a630(struct adreno_gpu *gpu) · 29 unmodified lines | ||
| 237 | 242 | return gpu->revn == 630; |
| 238 | 243 | } |
| 239 | 244 | |
| 245 | +static inline int adreno_is_a640(struct adreno_gpu *gpu) | |
| 246 | +{ | |
| 247 | + return gpu->revn == 640; | |
| 248 | +} | |
| 249 | + | |
| 250 | +static inline int adreno_is_a650(struct adreno_gpu *gpu) | |
| 251 | +{ | |
| 252 | + return gpu->revn == 650; | |
| 253 | +} | |
| 254 | + | |
| 240 | 255 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); |
| 241 | 256 | const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, |
| 242 | 257 | const char *fwname); |
| @@ -272,6 +287,14 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state); · 29 unmodified lines | ||
| 272 | 287 | int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); |
| 273 | 288 | int adreno_gpu_state_put(struct msm_gpu_state *state); |
| 274 | 289 | |
| 290 | +/* | |
| 291 | + * Common helper function to initialize the default address space for arm-smmu | |
| 292 | + * attached targets | |
| 293 | + */ | |
| 294 | +struct msm_gem_address_space * | |
| 295 | +adreno_iommu_create_address_space(struct msm_gpu *gpu, | |
| 296 | + struct platform_device *pdev); | |
| 297 | + | |
| 275 | 298 | /* |
| 276 | 299 | * For a5xx and a6xx targets load the zap shader that is used to pull the GPU |
| 277 | 300 | * out of secure mode |
| @@ -36,22 +36,6 @@ static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) · 35 unmodified lines | ||
| 36 | 36 | return to_dpu_kms(priv->kms); |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | −static bool _dpu_core_video_mode_intf_connected(struct drm_crtc *crtc) | |
| 40 | −{ | |
| 41 | − struct drm_crtc *tmp_crtc; | |
| 42 | − | |
| 43 | − drm_for_each_crtc(tmp_crtc, crtc->dev) { | |
| 44 | − if ((dpu_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) && | |
| 45 | − tmp_crtc->enabled) { | |
| 46 | − DPU_DEBUG("video interface connected crtc:%d\n", | |
| 47 | − tmp_crtc->base.id); | |
| 48 | − return true; | |
| 49 | − } | |
| 50 | − } | |
| 51 | − | |
| 52 | − return false; | |
| 53 | −} | |
| 54 | − | |
| 55 | 39 | static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, |
| 56 | 40 | struct drm_crtc *crtc, |
| 57 | 41 | struct drm_crtc_state *state, |
| @@ -94,7 +78,6 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, · 36 unmodified lines | ||
| 94 | 78 | u32 bw, threshold; |
| 95 | 79 | u64 bw_sum_of_intfs = 0; |
| 96 | 80 | enum dpu_crtc_client_type curr_client_type; |
| 97 | − bool is_video_mode; | |
| 98 | 81 | struct dpu_crtc_state *dpu_cstate; |
| 99 | 82 | struct drm_crtc *tmp_crtc; |
| 100 | 83 | struct dpu_kms *kms; |
| @@ -144,11 +127,7 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, · 43 unmodified lines | ||
| 144 | 127 | bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); |
| 145 | 128 | DPU_DEBUG("calculated bandwidth=%uk\n", bw); |
| 146 | 129 | |
| 147 | − is_video_mode = dpu_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO; | |
| 148 | − threshold = (is_video_mode || | |
| 149 | − _dpu_core_video_mode_intf_connected(crtc)) ? | |
| 150 | − kms->catalog->perf.max_bw_low : | |
| 151 | − kms->catalog->perf.max_bw_high; | |
| 130 | + threshold = kms->catalog->perf.max_bw_high; | |
| 152 | 131 | |
| 153 | 132 | DPU_DEBUG("final threshold bw limit = %d\n", threshold); |
| 154 | 133 | |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/sort.h> |
| 10 | 10 | #include <linux/debugfs.h> |
| 11 | 11 | #include <linux/ktime.h> |
| 12 | +#include <linux/bits.h> | |
| 12 | 13 | |
| 13 | 14 | #include <drm/drm_crtc.h> |
| 14 | 15 | #include <drm/drm_flip_work.h> |
| @@ -20,6 +21,7 @@ · 5 unmodified lines | ||
| 20 | 21 | #include "dpu_kms.h" |
| 21 | 22 | #include "dpu_hw_lm.h" |
| 22 | 23 | #include "dpu_hw_ctl.h" |
| 24 | +#include "dpu_hw_dspp.h" | |
| 23 | 25 | #include "dpu_crtc.h" |
| 24 | 26 | #include "dpu_plane.h" |
| 25 | 27 | #include "dpu_encoder.h" |
| @@ -40,6 +42,9 @@ · 14 unmodified lines | ||
| 40 | 42 | /* timeout in ms waiting for frame done */ |
| 41 | 43 | #define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 |
| 42 | 44 | |
| 45 | +#define CONVERT_S3_15(val) \ | |
| 46 | + (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) | |
| 47 | + | |
| 43 | 48 | static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
| 44 | 49 | { |
| 45 | 50 | struct msm_drm_private *priv = crtc->dev->dev_private; |
| @@ -88,11 +93,9 @@ static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, · 42 unmodified lines | ||
| 88 | 93 | |
| 89 | 94 | static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) |
| 90 | 95 | { |
| 91 | − struct dpu_crtc *dpu_crtc; | |
| 92 | 96 | struct dpu_crtc_state *crtc_state; |
| 93 | 97 | int lm_idx, lm_horiz_position; |
| 94 | 98 | |
| 95 | − dpu_crtc = to_dpu_crtc(crtc); | |
| 96 | 99 | crtc_state = to_dpu_crtc_state(crtc->state); |
| 97 | 100 | |
| 98 | 101 | lm_horiz_position = 0; |
| @@ -422,6 +425,74 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, · 323 unmodified lines | ||
| 422 | 425 | drm_mode_debug_printmodeline(adj_mode); |
| 423 | 426 | } |
| 424 | 427 | |
| 428 | +static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, | |
| 429 | + struct dpu_hw_pcc_cfg *cfg) | |
| 430 | +{ | |
| 431 | + struct drm_color_ctm *ctm; | |
| 432 | + | |
| 433 | + memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); | |
| 434 | + | |
| 435 | + ctm = (struct drm_color_ctm *)state->ctm->data; | |
| 436 | + | |
| 437 | + if (!ctm) | |
| 438 | + return; | |
| 439 | + | |
| 440 | + cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); | |
| 441 | + cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); | |
| 442 | + cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); | |
| 443 | + | |
| 444 | + cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); | |
| 445 | + cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); | |
| 446 | + cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); | |
| 447 | + | |
| 448 | + cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); | |
| 449 | + cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); | |
| 450 | + cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); | |
| 451 | +} | |
| 452 | + | |
| 453 | +static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) | |
| 454 | +{ | |
| 455 | + struct drm_crtc_state *state = crtc->state; | |
| 456 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); | |
| 457 | + struct dpu_crtc_mixer *mixer = cstate->mixers; | |
| 458 | + struct dpu_hw_pcc_cfg cfg; | |
| 459 | + struct dpu_hw_ctl *ctl; | |
| 460 | + struct dpu_hw_mixer *lm; | |
| 461 | + struct dpu_hw_dspp *dspp; | |
| 462 | + int i; | |
| 463 | + | |
| 464 | + | |
| 465 | + if (!state->color_mgmt_changed) | |
| 466 | + return; | |
| 467 | + | |
| 468 | + for (i = 0; i < cstate->num_mixers; i++) { | |
| 469 | + ctl = mixer[i].lm_ctl; | |
| 470 | + lm = mixer[i].hw_lm; | |
| 471 | + dspp = mixer[i].hw_dspp; | |
| 472 | + | |
| 473 | + if (!dspp || !dspp->ops.setup_pcc) | |
| 474 | + continue; | |
| 475 | + | |
| 476 | + if (!state->ctm) { | |
| 477 | + dspp->ops.setup_pcc(dspp, NULL); | |
| 478 | + } else { | |
| 479 | + _dpu_crtc_get_pcc_coeff(state, &cfg); | |
| 480 | + dspp->ops.setup_pcc(dspp, &cfg); | |
| 481 | + } | |
| 482 | + | |
| 483 | + mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, | |
| 484 | + mixer[i].hw_dspp->idx); | |
| 485 | + | |
| 486 | + /* stage config flush mask */ | |
| 487 | + ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); | |
| 488 | + | |
| 489 | + DPU_DEBUG("lm %d, ctl %d, flush mask 0x%x\n", | |
| 490 | + mixer[i].hw_lm->idx - DSPP_0, | |
| 491 | + ctl->idx - CTL_0, | |
| 492 | + mixer[i].flush_mask); | |
| 493 | + } | |
| 494 | +} | |
| 495 | + | |
| 425 | 496 | static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, |
| 426 | 497 | struct drm_crtc_state *old_state) |
| 427 | 498 | { |
| @@ -430,7 +501,6 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, · 2 unmodified lines | ||
| 430 | 501 | struct drm_encoder *encoder; |
| 431 | 502 | struct drm_device *dev; |
| 432 | 503 | unsigned long flags; |
| 433 | − struct dpu_crtc_smmu_state_data *smmu_state; | |
| 434 | 504 | |
| 435 | 505 | if (!crtc) { |
| 436 | 506 | DPU_ERROR("invalid crtc\n"); |
| @@ -448,7 +518,6 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, · 11 unmodified lines | ||
| 448 | 518 | dpu_crtc = to_dpu_crtc(crtc); |
| 449 | 519 | cstate = to_dpu_crtc_state(crtc->state); |
| 450 | 520 | dev = crtc->dev; |
| 451 | − smmu_state = &dpu_crtc->smmu_state; | |
| 452 | 521 | |
| 453 | 522 | _dpu_crtc_setup_lm_bounds(crtc, crtc->state); |
| 454 | 523 | |
| @@ -475,6 +544,8 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, · 20 unmodified lines | ||
| 475 | 544 | |
| 476 | 545 | _dpu_crtc_blend_setup(crtc); |
| 477 | 546 | |
| 547 | + _dpu_crtc_setup_cp_blocks(crtc); | |
| 548 | + | |
| 478 | 549 | /* |
| 479 | 550 | * PP_DONE irq is only used by command mode for now. |
| 480 | 551 | * It is better to request pending before FLUSH and START trigger |
| @@ -491,7 +562,6 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, · 10 unmodified lines | ||
| 491 | 562 | struct drm_device *dev; |
| 492 | 563 | struct drm_plane *plane; |
| 493 | 564 | struct msm_drm_private *priv; |
| 494 | − struct msm_drm_thread *event_thread; | |
| 495 | 565 | unsigned long flags; |
| 496 | 566 | struct dpu_crtc_state *cstate; |
| 497 | 567 | |
| @@ -513,8 +583,6 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, · 15 unmodified lines | ||
| 513 | 583 | return; |
| 514 | 584 | } |
| 515 | 585 | |
| 516 | − event_thread = &priv->event_thread[crtc->index]; | |
| 517 | − | |
| 518 | 586 | if (dpu_crtc->event) { |
| 519 | 587 | DPU_DEBUG("already received dpu_crtc->event\n"); |
| 520 | 588 | } else { |
| @@ -567,7 +635,6 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, · 46 unmodified lines | ||
| 567 | 635 | static void dpu_crtc_destroy_state(struct drm_crtc *crtc, |
| 568 | 636 | struct drm_crtc_state *state) |
| 569 | 637 | { |
| 570 | − struct dpu_crtc *dpu_crtc; | |
| 571 | 638 | struct dpu_crtc_state *cstate; |
| 572 | 639 | |
| 573 | 640 | if (!crtc || !state) { |
| @@ -575,7 +642,6 @@ static void dpu_crtc_destroy_state(struct drm_crtc *crtc, · 1 unmodified line | ||
| 575 | 642 | return; |
| 576 | 643 | } |
| 577 | 644 | |
| 578 | − dpu_crtc = to_dpu_crtc(crtc); | |
| 579 | 645 | cstate = to_dpu_crtc_state(state); |
| 580 | 646 | |
| 581 | 647 | DPU_DEBUG("crtc%d\n", crtc->base.id); |
| @@ -662,11 +728,9 @@ static void dpu_crtc_reset(struct drm_crtc *crtc) · 80 unmodified lines | ||
| 662 | 728 | /** |
| 663 | 729 | * dpu_crtc_duplicate_state - state duplicate hook |
| 664 | 730 | * @crtc: Pointer to drm crtc structure |
| 665 | − * @Returns: Pointer to new drm_crtc_state structure | |
| 666 | 731 | */ |
| 667 | 732 | static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) |
| 668 | 733 | { |
| 669 | − struct dpu_crtc *dpu_crtc; | |
| 670 | 734 | struct dpu_crtc_state *cstate, *old_cstate; |
| 671 | 735 | |
| 672 | 736 | if (!crtc || !crtc->state) { |
| @@ -674,7 +738,6 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) · 1 unmodified line | ||
| 674 | 738 | return NULL; |
| 675 | 739 | } |
| 676 | 740 | |
| 677 | − dpu_crtc = to_dpu_crtc(crtc); | |
| 678 | 741 | old_cstate = to_dpu_crtc_state(crtc->state); |
| 679 | 742 | cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); |
| 680 | 743 | if (!cstate) { |
| @@ -693,9 +756,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, · 12 unmodified lines | ||
| 693 | 756 | { |
| 694 | 757 | struct dpu_crtc *dpu_crtc; |
| 695 | 758 | struct dpu_crtc_state *cstate; |
| 696 | − struct drm_display_mode *mode; | |
| 697 | 759 | struct drm_encoder *encoder; |
| 698 | − struct msm_drm_private *priv; | |
| 699 | 760 | unsigned long flags; |
| 700 | 761 | bool release_bandwidth = false; |
| 701 | 762 | |
| @@ -705,8 +766,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, · 3 unmodified lines | ||
| 705 | 766 | } |
| 706 | 767 | dpu_crtc = to_dpu_crtc(crtc); |
| 707 | 768 | cstate = to_dpu_crtc_state(crtc->state); |
| 708 | − mode = &cstate->base.adjusted_mode; | |
| 709 | − priv = crtc->dev->dev_private; | |
| 710 | 769 | |
| 711 | 770 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); |
| 712 | 771 | |
| @@ -768,14 +827,12 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, · 55 unmodified lines | ||
| 768 | 827 | { |
| 769 | 828 | struct dpu_crtc *dpu_crtc; |
| 770 | 829 | struct drm_encoder *encoder; |
| 771 | − struct msm_drm_private *priv; | |
| 772 | 830 | bool request_bandwidth; |
| 773 | 831 | |
| 774 | 832 | if (!crtc) { |
| 775 | 833 | DPU_ERROR("invalid crtc\n"); |
| 776 | 834 | return; |
| 777 | 835 | } |
| 778 | − priv = crtc->dev->dev_private; | |
| 779 | 836 | |
| 780 | 837 | pm_runtime_get_sync(crtc->dev->dev); |
| 781 | 838 | |
| @@ -1319,6 +1376,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, · 537 unmodified lines | ||
| 1319 | 1376 | |
| 1320 | 1377 | drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); |
| 1321 | 1378 | |
| 1379 | + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); | |
| 1380 | + | |
| 1322 | 1381 | /* save user friendly CRTC name for later */ |
| 1323 | 1382 | snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); |
| 1324 | 1383 | |
| @@ -73,12 +73,14 @@ struct dpu_crtc_smmu_state_data { · 72 unmodified lines | ||
| 73 | 73 | * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC |
| 74 | 74 | * @hw_lm: LM HW Driver context |
| 75 | 75 | * @lm_ctl: CTL Path HW driver context |
| 76 | + * @lm_dspp: DSPP HW driver context | |
| 76 | 77 | * @mixer_op_mode: mixer blending operation mode |
| 77 | 78 | * @flush_mask: mixer flush mask for ctl, mixer and pipe |
| 78 | 79 | */ |
| 79 | 80 | struct dpu_crtc_mixer { |
| 80 | 81 | struct dpu_hw_mixer *hw_lm; |
| 81 | 82 | struct dpu_hw_ctl *lm_ctl; |
| 83 | + struct dpu_hw_dspp *hw_dspp; | |
| 82 | 84 | u32 mixer_op_mode; |
| 83 | 85 | u32 flush_mask; |
| 84 | 86 | }; |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "dpu_hw_catalog.h" |
| 21 | 21 | #include "dpu_hw_intf.h" |
| 22 | 22 | #include "dpu_hw_ctl.h" |
| 23 | +#include "dpu_hw_dspp.h" | |
| 23 | 24 | #include "dpu_formats.h" |
| 24 | 25 | #include "dpu_encoder_phys.h" |
| 25 | 26 | #include "dpu_crtc.h" |
| @@ -536,6 +537,7 @@ static struct msm_display_topology dpu_encoder_get_topology( · 510 unmodified lines | ||
| 536 | 537 | * 1 LM, 1 INTF |
| 537 | 538 | * 2 LM, 1 INTF (stream merge to support high resolution interfaces) |
| 538 | 539 | * |
| 540 | + * Adding color blocks only to primary interface | |
| 539 | 541 | */ |
| 540 | 542 | if (intf_count == 2) |
| 541 | 543 | topology.num_lm = 2; |
| @@ -544,6 +546,9 @@ static struct msm_display_topology dpu_encoder_get_topology( · 2 unmodified lines | ||
| 544 | 546 | else |
| 545 | 547 | topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; |
| 546 | 548 | |
| 549 | + if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) | |
| 550 | + topology.num_dspp = topology.num_lm; | |
| 551 | + | |
| 547 | 552 | topology.num_enc = 0; |
| 548 | 553 | topology.num_intf = intf_count; |
| 549 | 554 | |
| @@ -959,7 +964,8 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, · 409 unmodified lines | ||
| 959 | 964 | struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC]; |
| 960 | 965 | struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; |
| 961 | 966 | struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; |
| 962 | − int num_lm, num_ctl, num_pp; | |
| 967 | + struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL }; | |
| 968 | + int num_lm, num_ctl, num_pp, num_dspp; | |
| 963 | 969 | int i, j; |
| 964 | 970 | |
| 965 | 971 | if (!drm_enc) { |
| @@ -1008,6 +1014,9 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, · 42 unmodified lines | ||
| 1008 | 1014 | drm_enc->base.id, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl)); |
| 1009 | 1015 | num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, |
| 1010 | 1016 | drm_enc->base.id, DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm)); |
| 1017 | + num_dspp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, | |
| 1018 | + drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp, | |
| 1019 | + ARRAY_SIZE(hw_dspp)); | |
| 1011 | 1020 | |
| 1012 | 1021 | for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) |
| 1013 | 1022 | dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) |
| @@ -1020,6 +1029,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, · 6 unmodified lines | ||
| 1020 | 1029 | |
| 1021 | 1030 | cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]); |
| 1022 | 1031 | cstate->mixers[i].lm_ctl = to_dpu_hw_ctl(hw_ctl[ctl_idx]); |
| 1032 | + cstate->mixers[i].hw_dspp = to_dpu_hw_dspp(hw_dspp[i]); | |
| 1023 | 1033 | } |
| 1024 | 1034 | |
| 1025 | 1035 | cstate->num_mixers = num_lm; |
| @@ -41,6 +41,8 @@ · 40 unmodified lines | ||
| 41 | 41 | #define PINGPONG_SDM845_SPLIT_MASK \ |
| 42 | 42 | (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) |
| 43 | 43 | |
| 44 | +#define DSPP_SC7180_MASK BIT(DPU_DSPP_PCC) | |
| 45 | + | |
| 44 | 46 | #define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) |
| 45 | 47 | #define DEFAULT_DPU_LINE_WIDTH 2048 |
| 46 | 48 | #define DEFAULT_DPU_OUTPUT_LINE_WIDTH 2560 |
| @@ -291,29 +293,30 @@ static const struct dpu_lm_sub_blks sdm845_lm_sblk = { · 244 unmodified lines | ||
| 291 | 293 | }, |
| 292 | 294 | }; |
| 293 | 295 | |
| 294 | −#define LM_BLK(_name, _id, _base, _fmask, _sblk, _pp, _lmpair) \ | |
| 296 | +#define LM_BLK(_name, _id, _base, _fmask, _sblk, _pp, _lmpair, _dspp) \ | |
| 295 | 297 | { \ |
| 296 | 298 | .name = _name, .id = _id, \ |
| 297 | 299 | .base = _base, .len = 0x320, \ |
| 298 | 300 | .features = _fmask, \ |
| 299 | 301 | .sblk = _sblk, \ |
| 300 | 302 | .pingpong = _pp, \ |
| 301 | − .lm_pair_mask = (1 << _lmpair) \ | |
| 303 | + .lm_pair_mask = (1 << _lmpair), \ | |
| 304 | + .dspp = _dspp \ | |
| 302 | 305 | } |
| 303 | 306 | |
| 304 | 307 | static const struct dpu_lm_cfg sdm845_lm[] = { |
| 305 | 308 | LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, |
| 306 | − &sdm845_lm_sblk, PINGPONG_0, LM_1), | |
| 309 | + &sdm845_lm_sblk, PINGPONG_0, LM_1, 0), | |
| 307 | 310 | LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, |
| 308 | − &sdm845_lm_sblk, PINGPONG_1, LM_0), | |
| 311 | + &sdm845_lm_sblk, PINGPONG_1, LM_0, 0), | |
| 309 | 312 | LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, |
| 310 | − &sdm845_lm_sblk, PINGPONG_2, LM_5), | |
| 313 | + &sdm845_lm_sblk, PINGPONG_2, LM_5, 0), | |
| 311 | 314 | LM_BLK("lm_3", LM_3, 0x0, MIXER_SDM845_MASK, |
| 312 | − &sdm845_lm_sblk, PINGPONG_MAX, 0), | |
| 315 | + &sdm845_lm_sblk, PINGPONG_MAX, 0, 0), | |
| 313 | 316 | LM_BLK("lm_4", LM_4, 0x0, MIXER_SDM845_MASK, |
| 314 | − &sdm845_lm_sblk, PINGPONG_MAX, 0), | |
| 317 | + &sdm845_lm_sblk, PINGPONG_MAX, 0, 0), | |
| 315 | 318 | LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK, |
| 316 | − &sdm845_lm_sblk, PINGPONG_3, LM_2), | |
| 319 | + &sdm845_lm_sblk, PINGPONG_3, LM_2, 0), | |
| 317 | 320 | }; |
| 318 | 321 | |
| 319 | 322 | /* SC7180 */ |
| @@ -328,11 +331,30 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = { · 8 unmodified lines | ||
| 328 | 331 | |
| 329 | 332 | static const struct dpu_lm_cfg sc7180_lm[] = { |
| 330 | 333 | LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, |
| 331 | − &sc7180_lm_sblk, PINGPONG_0, LM_1), | |
| 334 | + &sc7180_lm_sblk, PINGPONG_0, LM_1, DSPP_0), | |
| 332 | 335 | LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK, |
| 333 | − &sc7180_lm_sblk, PINGPONG_1, LM_0), | |
| 336 | + &sc7180_lm_sblk, PINGPONG_1, LM_0, 0), | |
| 337 | +}; | |
| 338 | + | |
| 339 | +/************************************************************* | |
| 340 | + * DSPP sub blocks config | |
| 341 | + *************************************************************/ | |
| 342 | +static const struct dpu_dspp_sub_blks sc7180_dspp_sblk = { | |
| 343 | + .pcc = {.id = DPU_DSPP_PCC, .base = 0x1700, | |
| 344 | + .len = 0x90, .version = 0x10000}, | |
| 334 | 345 | }; |
| 335 | 346 | |
| 347 | +#define DSPP_BLK(_name, _id, _base) \ | |
| 348 | + {\ | |
| 349 | + .name = _name, .id = _id, \ | |
| 350 | + .base = _base, .len = 0x1800, \ | |
| 351 | + .features = DSPP_SC7180_MASK, \ | |
| 352 | + .sblk = &sc7180_dspp_sblk \ | |
| 353 | + } | |
| 354 | + | |
| 355 | +static const struct dpu_dspp_cfg sc7180_dspp[] = { | |
| 356 | + DSPP_BLK("dspp_0", DSPP_0, 0x54000), | |
| 357 | +}; | |
| 336 | 358 | /************************************************************* |
| 337 | 359 | * PINGPONG sub blocks config |
| 338 | 360 | *************************************************************/ |
| @@ -515,8 +537,8 @@ static const struct dpu_perf_cfg sdm845_perf_data = { · 176 unmodified lines | ||
| 515 | 537 | }; |
| 516 | 538 | |
| 517 | 539 | static const struct dpu_perf_cfg sc7180_perf_data = { |
| 518 | − .max_bw_low = 3900000, | |
| 519 | − .max_bw_high = 5500000, | |
| 540 | + .max_bw_low = 6800000, | |
| 541 | + .max_bw_high = 6800000, | |
| 520 | 542 | .min_core_ib = 2400000, |
| 521 | 543 | .min_llcc_ib = 800000, |
| 522 | 544 | .min_dram_ib = 800000, |
| @@ -587,6 +609,8 @@ static void sc7180_cfg_init(struct dpu_mdss_cfg *dpu_cfg) · 64 unmodified lines | ||
| 587 | 609 | .sspp = sc7180_sspp, |
| 588 | 610 | .mixer_count = ARRAY_SIZE(sc7180_lm), |
| 589 | 611 | .mixer = sc7180_lm, |
| 612 | + .dspp_count = ARRAY_SIZE(sc7180_dspp), | |
| 613 | + .dspp = sc7180_dspp, | |
| 590 | 614 | .pingpong_count = ARRAY_SIZE(sc7180_pp), |
| 591 | 615 | .pingpong = sc7180_pp, |
| 592 | 616 | .intf_count = ARRAY_SIZE(sc7180_intf), |
| @@ -145,6 +145,17 @@ enum { · 144 unmodified lines | ||
| 145 | 145 | DPU_MIXER_MAX |
| 146 | 146 | }; |
| 147 | 147 | |
| 148 | +/** | |
| 149 | + * DSPP sub-blocks | |
| 150 | + * @DPU_DSPP_PCC Panel color correction block | |
| 151 | + * @DPU_DSPP_GC Gamma correction block | |
| 152 | + */ | |
| 153 | +enum { | |
| 154 | + DPU_DSPP_PCC = 0x1, | |
| 155 | + DPU_DSPP_GC, | |
| 156 | + DPU_DSPP_MAX | |
| 157 | +}; | |
| 158 | + | |
| 148 | 159 | /** |
| 149 | 160 | * PINGPONG sub-blocks |
| 150 | 161 | * @DPU_PINGPONG_TE Tear check block |
| @@ -377,6 +388,16 @@ struct dpu_lm_sub_blks { · 226 unmodified lines | ||
| 377 | 388 | struct dpu_pp_blk gc; |
| 378 | 389 | }; |
| 379 | 390 | |
| 391 | +/** | |
| 392 | + * struct dpu_dspp_sub_blks: Information of DSPP block | |
| 393 | + * @gc : gamma correction block | |
| 394 | + * @pcc: pixel color correction block | |
| 395 | + */ | |
| 396 | +struct dpu_dspp_sub_blks { | |
| 397 | + struct dpu_pp_blk gc; | |
| 398 | + struct dpu_pp_blk pcc; | |
| 399 | +}; | |
| 400 | + | |
| 380 | 401 | struct dpu_pingpong_sub_blks { |
| 381 | 402 | struct dpu_pp_blk te; |
| 382 | 403 | struct dpu_pp_blk te2; |
| @@ -471,9 +492,23 @@ struct dpu_lm_cfg { · 88 unmodified lines | ||
| 471 | 492 | DPU_HW_BLK_INFO; |
| 472 | 493 | const struct dpu_lm_sub_blks *sblk; |
| 473 | 494 | u32 pingpong; |
| 495 | + u32 dspp; | |
| 474 | 496 | unsigned long lm_pair_mask; |
| 475 | 497 | }; |
| 476 | 498 | |
| 499 | +/** | |
| 500 | + * struct dpu_dspp_cfg - information of DSPP blocks | |
| 501 | + * @id enum identifying this block | |
| 502 | + * @base register offset of this block | |
| 503 | + * @features bit mask identifying sub-blocks/features | |
| 504 | + * supported by this block | |
| 505 | + * @sblk sub-blocks information | |
| 506 | + */ | |
| 507 | +struct dpu_dspp_cfg { | |
| 508 | + DPU_HW_BLK_INFO; | |
| 509 | + const struct dpu_dspp_sub_blks *sblk; | |
| 510 | +}; | |
| 511 | + | |
| 477 | 512 | /** |
| 478 | 513 | * struct dpu_pingpong_cfg - information of PING-PONG blocks |
| 479 | 514 | * @id enum identifying this block |
| @@ -688,6 +723,9 @@ struct dpu_mdss_cfg { · 208 unmodified lines | ||
| 688 | 723 | |
| 689 | 724 | u32 ad_count; |
| 690 | 725 | |
| 726 | + u32 dspp_count; | |
| 727 | + const struct dpu_dspp_cfg *dspp; | |
| 728 | + | |
| 691 | 729 | /* Add additional block data structures here */ |
| 692 | 730 | |
| 693 | 731 | struct dpu_perf_cfg perf; |
| @@ -716,6 +754,7 @@ struct dpu_mdss_hw_cfg_handler { · 22 unmodified lines | ||
| 716 | 754 | #define BLK_PINGPONG(s) ((s)->pingpong) |
| 717 | 755 | #define BLK_INTF(s) ((s)->intf) |
| 718 | 756 | #define BLK_AD(s) ((s)->ad) |
| 757 | +#define BLK_DSPP(s) ((s)->dspp) | |
| 719 | 758 | |
| 720 | 759 | /** |
| 721 | 760 | * dpu_hw_catalog_init - dpu hardware catalog init API retrieves |
| @@ -272,6 +272,31 @@ static int dpu_hw_ctl_active_get_bitmask_intf(struct dpu_hw_ctl *ctx, · 271 unmodified lines | ||
| 272 | 272 | return 0; |
| 273 | 273 | } |
| 274 | 274 | |
| 275 | +static uint32_t dpu_hw_ctl_get_bitmask_dspp(struct dpu_hw_ctl *ctx, | |
| 276 | + enum dpu_dspp dspp) | |
| 277 | +{ | |
| 278 | + uint32_t flushbits = 0; | |
| 279 | + | |
| 280 | + switch (dspp) { | |
| 281 | + case DSPP_0: | |
| 282 | + flushbits = BIT(13); | |
| 283 | + break; | |
| 284 | + case DSPP_1: | |
| 285 | + flushbits = BIT(14); | |
| 286 | + break; | |
| 287 | + case DSPP_2: | |
| 288 | + flushbits = BIT(15); | |
| 289 | + break; | |
| 290 | + case DSPP_3: | |
| 291 | + flushbits = BIT(21); | |
| 292 | + break; | |
| 293 | + default: | |
| 294 | + return 0; | |
| 295 | + } | |
| 296 | + | |
| 297 | + return flushbits; | |
| 298 | +} | |
| 299 | + | |
| 275 | 300 | static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) |
| 276 | 301 | { |
| 277 | 302 | struct dpu_hw_blk_reg_map *c = &ctx->hw; |
| @@ -548,6 +573,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, · 270 unmodified lines | ||
| 548 | 573 | ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; |
| 549 | 574 | ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; |
| 550 | 575 | ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; |
| 576 | + ops->get_bitmask_dspp = dpu_hw_ctl_get_bitmask_dspp; | |
| 551 | 577 | }; |
| 552 | 578 | |
| 553 | 579 | static struct dpu_hw_blk_ops dpu_hw_ops; |
| @@ -139,6 +139,9 @@ struct dpu_hw_ctl_ops { · 138 unmodified lines | ||
| 139 | 139 | uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, |
| 140 | 140 | enum dpu_lm blk); |
| 141 | 141 | |
| 142 | + uint32_t (*get_bitmask_dspp)(struct dpu_hw_ctl *ctx, | |
| 143 | + enum dpu_dspp blk); | |
| 144 | + | |
| 142 | 145 | /** |
| 143 | 146 | * Query the value of the intf flush mask |
| 144 | 147 | * No effect on hardware |
| @@ -0,0 +1,129 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#include "dpu_hwio.h" | |
| 6 | +#include "dpu_hw_catalog.h" | |
| 7 | +#include "dpu_hw_lm.h" | |
| 8 | +#include "dpu_hw_dspp.h" | |
| 9 | +#include "dpu_kms.h" | |
| 10 | + | |
| 11 | + | |
| 12 | +/* DSPP_PCC */ | |
| 13 | +#define PCC_EN BIT(0) | |
| 14 | +#define PCC_DIS 0 | |
| 15 | +#define PCC_RED_R_OFF 0x10 | |
| 16 | +#define PCC_RED_G_OFF 0x1C | |
| 17 | +#define PCC_RED_B_OFF 0x28 | |
| 18 | +#define PCC_GREEN_R_OFF 0x14 | |
| 19 | +#define PCC_GREEN_G_OFF 0x20 | |
| 20 | +#define PCC_GREEN_B_OFF 0x2C | |
| 21 | +#define PCC_BLUE_R_OFF 0x18 | |
| 22 | +#define PCC_BLUE_G_OFF 0x24 | |
| 23 | +#define PCC_BLUE_B_OFF 0x30 | |
| 24 | + | |
| 25 | +static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, | |
| 26 | + struct dpu_hw_pcc_cfg *cfg) | |
| 27 | +{ | |
| 28 | + | |
| 29 | + u32 base = ctx->cap->sblk->pcc.base; | |
| 30 | + | |
| 31 | + if (!ctx || !base) { | |
| 32 | + DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base); | |
| 33 | + return; | |
| 34 | + } | |
| 35 | + | |
| 36 | + if (!cfg) { | |
| 37 | + DRM_DEBUG_DRIVER("disable pcc feature\n"); | |
| 38 | + DPU_REG_WRITE(&ctx->hw, base, PCC_DIS); | |
| 39 | + return; | |
| 40 | + } | |
| 41 | + | |
| 42 | + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_R_OFF, cfg->r.r); | |
| 43 | + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_G_OFF, cfg->r.g); | |
| 44 | + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_B_OFF, cfg->r.b); | |
| 45 | + | |
| 46 | + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_R_OFF, cfg->g.r); | |
| 47 | + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_G_OFF, cfg->g.g); | |
| 48 | + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_B_OFF, cfg->g.b); | |
| 49 | + | |
| 50 | + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_R_OFF, cfg->b.r); | |
| 51 | + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_G_OFF, cfg->b.g); | |
| 52 | + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_B_OFF, cfg->b.b); | |
| 53 | + | |
| 54 | + DPU_REG_WRITE(&ctx->hw, base, PCC_EN); | |
| 55 | +} | |
| 56 | + | |
| 57 | +static void _setup_dspp_ops(struct dpu_hw_dspp *c, | |
| 58 | + unsigned long features) | |
| 59 | +{ | |
| 60 | + if (test_bit(DPU_DSPP_PCC, &features) && | |
| 61 | + IS_SC7180_TARGET(c->hw.hwversion)) | |
| 62 | + c->ops.setup_pcc = dpu_setup_dspp_pcc; | |
| 63 | +} | |
| 64 | + | |
| 65 | +static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp, | |
| 66 | + const struct dpu_mdss_cfg *m, | |
| 67 | + void __iomem *addr, | |
| 68 | + struct dpu_hw_blk_reg_map *b) | |
| 69 | +{ | |
| 70 | + int i; | |
| 71 | + | |
| 72 | + if (!m || !addr || !b) | |
| 73 | + return ERR_PTR(-EINVAL); | |
| 74 | + | |
| 75 | + for (i = 0; i < m->dspp_count; i++) { | |
| 76 | + if (dspp == m->dspp[i].id) { | |
| 77 | + b->base_off = addr; | |
| 78 | + b->blk_off = m->dspp[i].base; | |
| 79 | + b->length = m->dspp[i].len; | |
| 80 | + b->hwversion = m->hwversion; | |
| 81 | + b->log_mask = DPU_DBG_MASK_DSPP; | |
| 82 | + return &m->dspp[i]; | |
| 83 | + } | |
| 84 | + } | |
| 85 | + | |
| 86 | + return ERR_PTR(-EINVAL); | |
| 87 | +} | |
| 88 | + | |
| 89 | +static struct dpu_hw_blk_ops dpu_hw_ops; | |
| 90 | + | |
| 91 | +struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx, | |
| 92 | + void __iomem *addr, | |
| 93 | + const struct dpu_mdss_cfg *m) | |
| 94 | +{ | |
| 95 | + struct dpu_hw_dspp *c; | |
| 96 | + const struct dpu_dspp_cfg *cfg; | |
| 97 | + | |
| 98 | + if (!addr || !m) | |
| 99 | + return ERR_PTR(-EINVAL); | |
| 100 | + | |
| 101 | + c = kzalloc(sizeof(*c), GFP_KERNEL); | |
| 102 | + if (!c) | |
| 103 | + return ERR_PTR(-ENOMEM); | |
| 104 | + | |
| 105 | + cfg = _dspp_offset(idx, m, addr, &c->hw); | |
| 106 | + if (IS_ERR_OR_NULL(cfg)) { | |
| 107 | + kfree(c); | |
| 108 | + return ERR_PTR(-EINVAL); | |
| 109 | + } | |
| 110 | + | |
| 111 | + /* Assign ops */ | |
| 112 | + c->idx = idx; | |
| 113 | + c->cap = cfg; | |
| 114 | + _setup_dspp_ops(c, c->cap->features); | |
| 115 | + | |
| 116 | + dpu_hw_blk_init(&c->base, DPU_HW_BLK_DSPP, idx, &dpu_hw_ops); | |
| 117 | + | |
| 118 | + return c; | |
| 119 | +} | |
| 120 | + | |
| 121 | +void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp) | |
| 122 | +{ | |
| 123 | + if (dspp) | |
| 124 | + dpu_hw_blk_destroy(&dspp->base); | |
| 125 | + | |
| 126 | + kfree(dspp); | |
| 127 | +} | |
| 128 | + | |
| 129 | + | |
| @@ -0,0 +1,100 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#ifndef _DPU_HW_DSPP_H | |
| 6 | +#define _DPU_HW_DSPP_H | |
| 7 | + | |
| 8 | +#include "dpu_hw_blk.h" | |
| 9 | + | |
| 10 | +struct dpu_hw_dspp; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * struct dpu_hw_pcc_coeff - PCC coefficient structure for each color | |
| 14 | + * component. | |
| 15 | + * @r: red coefficient. | |
| 16 | + * @g: green coefficient. | |
| 17 | + * @b: blue coefficient. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +struct dpu_hw_pcc_coeff { | |
| 21 | + __u32 r; | |
| 22 | + __u32 g; | |
| 23 | + __u32 b; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * struct dpu_hw_pcc - pcc feature structure | |
| 28 | + * @r: red coefficients. | |
| 29 | + * @g: green coefficients. | |
| 30 | + * @b: blue coefficients. | |
| 31 | + */ | |
| 32 | +struct dpu_hw_pcc_cfg { | |
| 33 | + struct dpu_hw_pcc_coeff r; | |
| 34 | + struct dpu_hw_pcc_coeff g; | |
| 35 | + struct dpu_hw_pcc_coeff b; | |
| 36 | +}; | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * struct dpu_hw_dspp_ops - interface to the dspp hardware driver functions | |
| 40 | + * Caller must call the init function to get the dspp context for each dspp | |
| 41 | + * Assumption is these functions will be called after clocks are enabled | |
| 42 | + */ | |
| 43 | +struct dpu_hw_dspp_ops { | |
| 44 | + /** | |
| 45 | + * setup_pcc - setup dspp pcc | |
| 46 | + * @ctx: Pointer to dspp context | |
| 47 | + * @cfg: Pointer to configuration | |
| 48 | + */ | |
| 49 | + void (*setup_pcc)(struct dpu_hw_dspp *ctx, struct dpu_hw_pcc_cfg *cfg); | |
| 50 | + | |
| 51 | +}; | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * struct dpu_hw_dspp - dspp description | |
| 55 | + * @base: Hardware block base structure | |
| 56 | + * @hw: Block hardware details | |
| 57 | + * @idx: DSPP index | |
| 58 | + * @cap: Pointer to layer_cfg | |
| 59 | + * @ops: Pointer to operations possible for this DSPP | |
| 60 | + */ | |
| 61 | +struct dpu_hw_dspp { | |
| 62 | + struct dpu_hw_blk base; | |
| 63 | + struct dpu_hw_blk_reg_map hw; | |
| 64 | + | |
| 65 | + /* dspp */ | |
| 66 | + int idx; | |
| 67 | + const struct dpu_dspp_cfg *cap; | |
| 68 | + | |
| 69 | + /* Ops */ | |
| 70 | + struct dpu_hw_dspp_ops ops; | |
| 71 | +}; | |
| 72 | + | |
| 73 | +/** | |
| 74 | + * dpu_hw_dspp - convert base object dpu_hw_base to container | |
| 75 | + * @hw: Pointer to base hardware block | |
| 76 | + * return: Pointer to hardware block container | |
| 77 | + */ | |
| 78 | +static inline struct dpu_hw_dspp *to_dpu_hw_dspp(struct dpu_hw_blk *hw) | |
| 79 | +{ | |
| 80 | + return container_of(hw, struct dpu_hw_dspp, base); | |
| 81 | +} | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * dpu_hw_dspp_init - initializes the dspp hw driver object. | |
| 85 | + * should be called once before accessing every dspp. | |
| 86 | + * @idx: DSPP index for which driver object is required | |
| 87 | + * @addr: Mapped register io address of MDP | |
| 88 | + * @Return: pointer to structure or ERR_PTR | |
| 89 | + */ | |
| 90 | +struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx, | |
| 91 | + void __iomem *addr, const struct dpu_mdss_cfg *m); | |
| 92 | + | |
| 93 | +/** | |
| 94 | + * dpu_hw_dspp_destroy(): Destroys DSPP driver context | |
| 95 | + * @dspp: Pointer to DSPP driver context | |
| 96 | + */ | |
| 97 | +void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp); | |
| 98 | + | |
| 99 | +#endif /*_DPU_HW_DSPP_H */ | |
| 100 | + | |
| @@ -95,6 +95,7 @@ enum dpu_hw_blk_type { · 94 unmodified lines | ||
| 95 | 95 | DPU_HW_BLK_PINGPONG, |
| 96 | 96 | DPU_HW_BLK_INTF, |
| 97 | 97 | DPU_HW_BLK_WB, |
| 98 | + DPU_HW_BLK_DSPP, | |
| 98 | 99 | DPU_HW_BLK_MAX, |
| 99 | 100 | }; |
| 100 | 101 | |
| @@ -425,5 +426,6 @@ struct dpu_mdss_color { · 324 unmodified lines | ||
| 425 | 426 | #define DPU_DBG_MASK_TOP (1 << 7) |
| 426 | 427 | #define DPU_DBG_MASK_VBIF (1 << 8) |
| 427 | 428 | #define DPU_DBG_MASK_ROT (1 << 9) |
| 429 | +#define DPU_DBG_MASK_DSPP (1 << 10) | |
| 428 | 430 | |
| 429 | 431 | #endif /* _DPU_HW_MDSS_H */ |
| @@ -772,29 +772,21 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) · 771 unmodified lines | ||
| 772 | 772 | { |
| 773 | 773 | struct iommu_domain *domain; |
| 774 | 774 | struct msm_gem_address_space *aspace; |
| 775 | − int ret; | |
| 775 | + struct msm_mmu *mmu; | |
| 776 | 776 | |
| 777 | 777 | domain = iommu_domain_alloc(&platform_bus_type); |
| 778 | 778 | if (!domain) |
| 779 | 779 | return 0; |
| 780 | 780 | |
| 781 | − domain->geometry.aperture_start = 0x1000; | |
| 782 | − domain->geometry.aperture_end = 0xffffffff; | |
| 781 | + mmu = msm_iommu_new(dpu_kms->dev->dev, domain); | |
| 782 | + aspace = msm_gem_address_space_create(mmu, "dpu1", | |
| 783 | + 0x1000, 0xfffffff); | |
| 783 | 784 | |
| 784 | − aspace = msm_gem_address_space_create(dpu_kms->dev->dev, | |
| 785 | − domain, "dpu1"); | |
| 786 | 785 | if (IS_ERR(aspace)) { |
| 787 | − iommu_domain_free(domain); | |
| 786 | + mmu->funcs->destroy(mmu); | |
| 788 | 787 | return PTR_ERR(aspace); |
| 789 | 788 | } |
| 790 | 789 | |
| 791 | − ret = aspace->mmu->funcs->attach(aspace->mmu); | |
| 792 | − if (ret) { | |
| 793 | − DPU_ERROR("failed to attach iommu %d\n", ret); | |
| 794 | − msm_gem_address_space_put(aspace); | |
| 795 | − return ret; | |
| 796 | − } | |
| 797 | − | |
| 798 | 790 | dpu_kms->base.aspace = aspace; |
| 799 | 791 | return 0; |
| 800 | 792 | } |
| @@ -158,6 +158,7 @@ struct dpu_global_state { · 157 unmodified lines | ||
| 158 | 158 | uint32_t mixer_to_enc_id[LM_MAX - LM_0]; |
| 159 | 159 | uint32_t ctl_to_enc_id[CTL_MAX - CTL_0]; |
| 160 | 160 | uint32_t intf_to_enc_id[INTF_MAX - INTF_0]; |
| 161 | + uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0]; | |
| 161 | 162 | }; |
| 162 | 163 | |
| 163 | 164 | struct dpu_global_state |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "dpu_hw_ctl.h" |
| 10 | 10 | #include "dpu_hw_pingpong.h" |
| 11 | 11 | #include "dpu_hw_intf.h" |
| 12 | +#include "dpu_hw_dspp.h" | |
| 12 | 13 | #include "dpu_encoder.h" |
| 13 | 14 | #include "dpu_trace.h" |
| 14 | 15 | |
| @@ -174,6 +175,23 @@ int dpu_rm_init(struct dpu_rm *rm, · 159 unmodified lines | ||
| 174 | 175 | rm->ctl_blks[ctl->id - CTL_0] = &hw->base; |
| 175 | 176 | } |
| 176 | 177 | |
| 178 | + for (i = 0; i < cat->dspp_count; i++) { | |
| 179 | + struct dpu_hw_dspp *hw; | |
| 180 | + const struct dpu_dspp_cfg *dspp = &cat->dspp[i]; | |
| 181 | + | |
| 182 | + if (dspp->id < DSPP_0 || dspp->id >= DSPP_MAX) { | |
| 183 | + DPU_ERROR("skip dspp %d with invalid id\n", dspp->id); | |
| 184 | + continue; | |
| 185 | + } | |
| 186 | + hw = dpu_hw_dspp_init(dspp->id, mmio, cat); | |
| 187 | + if (IS_ERR_OR_NULL(hw)) { | |
| 188 | + rc = PTR_ERR(hw); | |
| 189 | + DPU_ERROR("failed dspp object creation: err %d\n", rc); | |
| 190 | + goto fail; | |
| 191 | + } | |
| 192 | + rm->dspp_blks[dspp->id - DSPP_0] = &hw->base; | |
| 193 | + } | |
| 194 | + | |
| 177 | 195 | return 0; |
| 178 | 196 | |
| 179 | 197 | fail: |
| @@ -222,12 +240,17 @@ static bool _dpu_rm_check_lm_peer(struct dpu_rm *rm, int primary_idx, · 42 unmodified lines | ||
| 222 | 240 | * if lm, and all other hardwired blocks connected to the lm (pp) is |
| 223 | 241 | * available and appropriate |
| 224 | 242 | * @pp_idx: output parameter, index of pingpong block attached to the layer |
| 225 | − * mixer in rm->pongpong_blks[]. | |
| 243 | + * mixer in rm->pingpong_blks[]. | |
| 244 | + * @dspp_idx: output parameter, index of dspp block attached to the layer | |
| 245 | + * mixer in rm->dspp_blks[]. | |
| 246 | + * @reqs: input parameter, rm requirements for HW blocks needed in the | |
| 247 | + * datapath. | |
| 226 | 248 | * @Return: true if lm matches all requirements, false otherwise |
| 227 | 249 | */ |
| 228 | 250 | static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, |
| 229 | 251 | struct dpu_global_state *global_state, |
| 230 | − uint32_t enc_id, int lm_idx, int *pp_idx) | |
| 252 | + uint32_t enc_id, int lm_idx, int *pp_idx, int *dspp_idx, | |
| 253 | + struct dpu_rm_requirements *reqs) | |
| 231 | 254 | { |
| 232 | 255 | const struct dpu_lm_cfg *lm_cfg; |
| 233 | 256 | int idx; |
| @@ -251,6 +274,23 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, · 17 unmodified lines | ||
| 251 | 274 | return false; |
| 252 | 275 | } |
| 253 | 276 | *pp_idx = idx; |
| 277 | + | |
| 278 | + if (!reqs->topology.num_dspp) | |
| 279 | + return true; | |
| 280 | + | |
| 281 | + idx = lm_cfg->dspp - DSPP_0; | |
| 282 | + if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks)) { | |
| 283 | + DPU_ERROR("failed to get dspp on lm %d\n", lm_cfg->dspp); | |
| 284 | + return false; | |
| 285 | + } | |
| 286 | + | |
| 287 | + if (reserved_by_other(global_state->dspp_to_enc_id, idx, enc_id)) { | |
| 288 | + DPU_DEBUG("lm %d dspp %d already reserved\n", lm_cfg->id, | |
| 289 | + lm_cfg->dspp); | |
| 290 | + return false; | |
| 291 | + } | |
| 292 | + *dspp_idx = idx; | |
| 293 | + | |
| 254 | 294 | return true; |
| 255 | 295 | } |
| 256 | 296 | |
| @@ -262,6 +302,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 5 unmodified lines | ||
| 262 | 302 | { |
| 263 | 303 | int lm_idx[MAX_BLOCKS]; |
| 264 | 304 | int pp_idx[MAX_BLOCKS]; |
| 305 | + int dspp_idx[MAX_BLOCKS] = {0}; | |
| 265 | 306 | int i, j, lm_count = 0; |
| 266 | 307 | |
| 267 | 308 | if (!reqs->topology.num_lm) { |
| @@ -279,7 +320,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 11 unmodified lines | ||
| 279 | 320 | lm_idx[lm_count] = i; |
| 280 | 321 | |
| 281 | 322 | if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state, |
| 282 | − enc_id, i, &pp_idx[lm_count])) { | |
| 323 | + enc_id, i, &pp_idx[lm_count], | |
| 324 | + &dspp_idx[lm_count], reqs)) { | |
| 283 | 325 | continue; |
| 284 | 326 | } |
| 285 | 327 | |
| @@ -299,7 +341,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 13 unmodified lines | ||
| 299 | 341 | |
| 300 | 342 | if (!_dpu_rm_check_lm_and_get_connected_blks(rm, |
| 301 | 343 | global_state, enc_id, j, |
| 302 | − &pp_idx[lm_count])) { | |
| 344 | + &pp_idx[lm_count], &dspp_idx[lm_count], | |
| 345 | + reqs)) { | |
| 303 | 346 | continue; |
| 304 | 347 | } |
| 305 | 348 | |
| @@ -316,6 +359,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 10 unmodified lines | ||
| 316 | 359 | for (i = 0; i < lm_count; i++) { |
| 317 | 360 | global_state->mixer_to_enc_id[lm_idx[i]] = enc_id; |
| 318 | 361 | global_state->pingpong_to_enc_id[pp_idx[i]] = enc_id; |
| 362 | + global_state->dspp_to_enc_id[dspp_idx[i]] = | |
| 363 | + reqs->topology.num_dspp ? enc_id : 0; | |
| 319 | 364 | |
| 320 | 365 | trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id, |
| 321 | 366 | pp_idx[i] + PINGPONG_0); |
| @@ -560,6 +605,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, · 238 unmodified lines | ||
| 560 | 605 | hw_to_enc_id = global_state->intf_to_enc_id; |
| 561 | 606 | max_blks = ARRAY_SIZE(rm->intf_blks); |
| 562 | 607 | break; |
| 608 | + case DPU_HW_BLK_DSPP: | |
| 609 | + hw_blks = rm->dspp_blks; | |
| 610 | + hw_to_enc_id = global_state->dspp_to_enc_id; | |
| 611 | + max_blks = ARRAY_SIZE(rm->dspp_blks); | |
| 612 | + break; | |
| 563 | 613 | default: |
| 564 | 614 | DPU_ERROR("blk type %d not managed by rm\n", type); |
| 565 | 615 | return 0; |
| @@ -19,6 +19,7 @@ struct dpu_global_state; · 18 unmodified lines | ||
| 19 | 19 | * @mixer_blks: array of layer mixer hardware resources |
| 20 | 20 | * @ctl_blks: array of ctl hardware resources |
| 21 | 21 | * @intf_blks: array of intf hardware resources |
| 22 | + * @dspp_blks: array of dspp hardware resources | |
| 22 | 23 | * @lm_max_width: cached layer mixer maximum width |
| 23 | 24 | * @rm_lock: resource manager mutex |
| 24 | 25 | */ |
| @@ -27,6 +28,7 @@ struct dpu_rm { · 2 unmodified lines | ||
| 27 | 28 | struct dpu_hw_blk *mixer_blks[LM_MAX - LM_0]; |
| 28 | 29 | struct dpu_hw_blk *ctl_blks[CTL_MAX - CTL_0]; |
| 29 | 30 | struct dpu_hw_blk *intf_blks[INTF_MAX - INTF_0]; |
| 31 | + struct dpu_hw_blk *dspp_blks[DSPP_MAX - DSPP_0]; | |
| 30 | 32 | |
| 31 | 33 | uint32_t lm_max_width; |
| 32 | 34 | }; |
| @@ -510,18 +510,20 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) · 509 unmodified lines | ||
| 510 | 510 | mdelay(16); |
| 511 | 511 | |
| 512 | 512 | if (config->iommu) { |
| 513 | − aspace = msm_gem_address_space_create(&pdev->dev, | |
| 514 | − config->iommu, "mdp4"); | |
| 513 | + struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, | |
| 514 | + config->iommu); | |
| 515 | + | |
| 516 | + aspace = msm_gem_address_space_create(mmu, | |
| 517 | + "mdp4", 0x1000, 0xffffffff); | |
| 518 | + | |
| 515 | 519 | if (IS_ERR(aspace)) { |
| 520 | + if (!IS_ERR(mmu)) | |
| 521 | + mmu->funcs->destroy(mmu); | |
| 516 | 522 | ret = PTR_ERR(aspace); |
| 517 | 523 | goto fail; |
| 518 | 524 | } |
| 519 | 525 | |
| 520 | 526 | kms->aspace = aspace; |
| 521 | − | |
| 522 | − ret = aspace->mmu->funcs->attach(aspace->mmu); | |
| 523 | − if (ret) | |
| 524 | − goto fail; | |
| 525 | 527 | } else { |
| 526 | 528 | DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " |
| 527 | 529 | "contig buffers for scanout\n"); |
| @@ -569,10 +571,6 @@ static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev) · 41 unmodified lines | ||
| 569 | 571 | /* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */ |
| 570 | 572 | config.max_clk = 266667000; |
| 571 | 573 | config.iommu = iommu_domain_alloc(&platform_bus_type); |
| 572 | − if (config.iommu) { | |
| 573 | − config.iommu->geometry.aperture_start = 0x1000; | |
| 574 | − config.iommu->geometry.aperture_end = 0xffffffff; | |
| 575 | − } | |
| 576 | 574 | |
| 577 | 575 | return &config; |
| 578 | 576 | } |
| @@ -342,6 +342,81 @@ static const struct mdp5_cfg_hw msm8x16_config = { · 341 unmodified lines | ||
| 342 | 342 | .max_clk = 320000000, |
| 343 | 343 | }; |
| 344 | 344 | |
| 345 | +static const struct mdp5_cfg_hw msm8x36_config = { | |
| 346 | + .name = "msm8x36", | |
| 347 | + .mdp = { | |
| 348 | + .count = 1, | |
| 349 | + .base = { 0x0 }, | |
| 350 | + .caps = MDP_CAP_SMP | | |
| 351 | + 0, | |
| 352 | + }, | |
| 353 | + .smp = { | |
| 354 | + .mmb_count = 8, | |
| 355 | + .mmb_size = 10240, | |
| 356 | + .clients = { | |
| 357 | + [SSPP_VIG0] = 1, [SSPP_DMA0] = 4, | |
| 358 | + [SSPP_RGB0] = 7, [SSPP_RGB1] = 8, | |
| 359 | + }, | |
| 360 | + }, | |
| 361 | + .ctl = { | |
| 362 | + .count = 3, | |
| 363 | + .base = { 0x01000, 0x01200, 0x01400 }, | |
| 364 | + .flush_hw_mask = 0x4003ffff, | |
| 365 | + }, | |
| 366 | + .pipe_vig = { | |
| 367 | + .count = 1, | |
| 368 | + .base = { 0x04000 }, | |
| 369 | + .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | | |
| 370 | + MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | | |
| 371 | + MDP_PIPE_CAP_DECIMATION, | |
| 372 | + }, | |
| 373 | + .pipe_rgb = { | |
| 374 | + .count = 2, | |
| 375 | + .base = { 0x14000, 0x16000 }, | |
| 376 | + .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | | |
| 377 | + MDP_PIPE_CAP_DECIMATION, | |
| 378 | + }, | |
| 379 | + .pipe_dma = { | |
| 380 | + .count = 1, | |
| 381 | + .base = { 0x24000 }, | |
| 382 | + .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, | |
| 383 | + }, | |
| 384 | + .lm = { | |
| 385 | + .count = 2, | |
| 386 | + .base = { 0x44000, 0x47000 }, | |
| 387 | + .instances = { | |
| 388 | + { .id = 0, .pp = 0, .dspp = 0, | |
| 389 | + .caps = MDP_LM_CAP_DISPLAY, }, | |
| 390 | + { .id = 1, .pp = -1, .dspp = -1, | |
| 391 | + .caps = MDP_LM_CAP_WB, }, | |
| 392 | + }, | |
| 393 | + .nb_stages = 8, | |
| 394 | + .max_width = 2560, | |
| 395 | + .max_height = 0xFFFF, | |
| 396 | + }, | |
| 397 | + .pp = { | |
| 398 | + .count = 1, | |
| 399 | + .base = { 0x70000 }, | |
| 400 | + }, | |
| 401 | + .ad = { | |
| 402 | + .count = 1, | |
| 403 | + .base = { 0x78000 }, | |
| 404 | + }, | |
| 405 | + .dspp = { | |
| 406 | + .count = 1, | |
| 407 | + .base = { 0x54000 }, | |
| 408 | + }, | |
| 409 | + .intf = { | |
| 410 | + .base = { 0x00000, 0x6a800, 0x6b000 }, | |
| 411 | + .connect = { | |
| 412 | + [0] = INTF_DISABLED, | |
| 413 | + [1] = INTF_DSI, | |
| 414 | + [2] = INTF_DSI, | |
| 415 | + }, | |
| 416 | + }, | |
| 417 | + .max_clk = 366670000, | |
| 418 | +}; | |
| 419 | + | |
| 345 | 420 | static const struct mdp5_cfg_hw msm8x94_config = { |
| 346 | 421 | .name = "msm8x94", |
| 347 | 422 | .mdp = { |
| @@ -840,6 +915,7 @@ static const struct mdp5_cfg_handler cfg_handlers_v1[] = { · 492 unmodified lines | ||
| 840 | 915 | { .revision = 2, .config = { .hw = &msm8x74v2_config } }, |
| 841 | 916 | { .revision = 3, .config = { .hw = &apq8084_config } }, |
| 842 | 917 | { .revision = 6, .config = { .hw = &msm8x16_config } }, |
| 918 | + { .revision = 8, .config = { .hw = &msm8x36_config } }, | |
| 843 | 919 | { .revision = 9, .config = { .hw = &msm8x94_config } }, |
| 844 | 920 | { .revision = 7, .config = { .hw = &msm8x96_config } }, |
| 845 | 921 | { .revision = 11, .config = { .hw = &msm8x76_config } }, |
| @@ -941,10 +1017,6 @@ static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) · 95 unmodified lines | ||
| 941 | 1017 | static struct mdp5_cfg_platform config = {}; |
| 942 | 1018 | |
| 943 | 1019 | config.iommu = iommu_domain_alloc(&platform_bus_type); |
| 944 | − if (config.iommu) { | |
| 945 | − config.iommu->geometry.aperture_start = 0x1000; | |
| 946 | − config.iommu->geometry.aperture_end = 0xffffffff; | |
| 947 | − } | |
| 948 | 1020 | |
| 949 | 1021 | return &config; |
| 950 | 1022 | } |
| @@ -959,7 +959,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, · 958 unmodified lines | ||
| 959 | 959 | if (!ctl) |
| 960 | 960 | return -EINVAL; |
| 961 | 961 | |
| 962 | − /* don't support LM cursors when we we have source split enabled */ | |
| 962 | + /* don't support LM cursors when we have source split enabled */ | |
| 963 | 963 | if (mdp5_cstate->pipeline.r_mixer) |
| 964 | 964 | return -EINVAL; |
| 965 | 965 | |
| @@ -1030,7 +1030,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) · 64 unmodified lines | ||
| 1030 | 1030 | return -EINVAL; |
| 1031 | 1031 | } |
| 1032 | 1032 | |
| 1033 | − /* don't support LM cursors when we we have source split enabled */ | |
| 1033 | + /* don't support LM cursors when we have source split enabled */ | |
| 1034 | 1034 | if (mdp5_cstate->pipeline.r_mixer) |
| 1035 | 1035 | return -EINVAL; |
| 1036 | 1036 | |
| @@ -632,25 +632,25 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) · 631 unmodified lines | ||
| 632 | 632 | mdelay(16); |
| 633 | 633 | |
| 634 | 634 | if (config->platform.iommu) { |
| 635 | + struct msm_mmu *mmu; | |
| 636 | + | |
| 635 | 637 | iommu_dev = &pdev->dev; |
| 636 | 638 | if (!dev_iommu_fwspec_get(iommu_dev)) |
| 637 | 639 | iommu_dev = iommu_dev->parent; |
| 638 | 640 | |
| 639 | − aspace = msm_gem_address_space_create(iommu_dev, | |
| 640 | − config->platform.iommu, "mdp5"); | |
| 641 | + mmu = msm_iommu_new(iommu_dev, config->platform.iommu); | |
| 642 | + | |
| 643 | + aspace = msm_gem_address_space_create(mmu, "mdp5", | |
| 644 | + 0x1000, 0xffffffff); | |
| 645 | + | |
| 641 | 646 | if (IS_ERR(aspace)) { |
| 647 | + if (!IS_ERR(mmu)) | |
| 648 | + mmu->funcs->destroy(mmu); | |
| 642 | 649 | ret = PTR_ERR(aspace); |
| 643 | 650 | goto fail; |
| 644 | 651 | } |
| 645 | 652 | |
| 646 | 653 | kms->aspace = aspace; |
| 647 | − | |
| 648 | − ret = aspace->mmu->funcs->attach(aspace->mmu); | |
| 649 | − if (ret) { | |
| 650 | − DRM_DEV_ERROR(&pdev->dev, "failed to attach iommu: %d\n", | |
| 651 | − ret); | |
| 652 | − goto fail; | |
| 653 | − } | |
| 654 | 654 | } else { |
| 655 | 655 | DRM_DEV_INFO(&pdev->dev, |
| 656 | 656 | "no iommu, fallback to phys contig buffers for scanout\n"); |
| @@ -943,7 +943,8 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) · 286 unmodified lines | ||
| 943 | 943 | |
| 944 | 944 | return 0; |
| 945 | 945 | fail: |
| 946 | − mdp5_destroy(pdev); | |
| 946 | + if (mdp5_kms) | |
| 947 | + mdp5_destroy(pdev); | |
| 947 | 948 | return ret; |
| 948 | 949 | } |
| 949 | 950 | |
| @@ -37,9 +37,10 @@ · 36 unmodified lines | ||
| 37 | 37 | * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get |
| 38 | 38 | * GEM object's debug name |
| 39 | 39 | * - 1.5.0 - Add SUBMITQUERY_QUERY ioctl |
| 40 | + * - 1.6.0 - Syncobj support | |
| 40 | 41 | */ |
| 41 | 42 | #define MSM_VERSION_MAJOR 1 |
| 42 | −#define MSM_VERSION_MINOR 5 | |
| 43 | +#define MSM_VERSION_MINOR 6 | |
| 43 | 44 | #define MSM_VERSION_PATCHLEVEL 0 |
| 44 | 45 | |
| 45 | 46 | static const struct drm_mode_config_funcs mode_config_funcs = { |
| @@ -1002,7 +1003,8 @@ static struct drm_driver msm_driver = { · 956 unmodified lines | ||
| 1002 | 1003 | .driver_features = DRIVER_GEM | |
| 1003 | 1004 | DRIVER_RENDER | |
| 1004 | 1005 | DRIVER_ATOMIC | |
| 1005 | − DRIVER_MODESET, | |
| 1006 | + DRIVER_MODESET | | |
| 1007 | + DRIVER_SYNCOBJ, | |
| 1006 | 1008 | .open = msm_open, |
| 1007 | 1009 | .postclose = msm_postclose, |
| 1008 | 1010 | .lastclose = drm_fb_helper_lastclose, |
| @@ -105,6 +105,7 @@ struct msm_display_topology { · 104 unmodified lines | ||
| 105 | 105 | u32 num_lm; |
| 106 | 106 | u32 num_enc; |
| 107 | 107 | u32 num_intf; |
| 108 | + u32 num_dspp; | |
| 108 | 109 | }; |
| 109 | 110 | |
| 110 | 111 | /** |
| @@ -236,7 +237,8 @@ int msm_crtc_enable_vblank(struct drm_crtc *crtc); · 125 unmodified lines | ||
| 236 | 237 | void msm_crtc_disable_vblank(struct drm_crtc *crtc); |
| 237 | 238 | |
| 238 | 239 | int msm_gem_init_vma(struct msm_gem_address_space *aspace, |
| 239 | − struct msm_gem_vma *vma, int npages); | |
| 240 | + struct msm_gem_vma *vma, int npages, | |
| 241 | + u64 range_start, u64 range_end); | |
| 240 | 242 | void msm_gem_purge_vma(struct msm_gem_address_space *aspace, |
| 241 | 243 | struct msm_gem_vma *vma); |
| 242 | 244 | void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, |
| @@ -250,12 +252,8 @@ void msm_gem_close_vma(struct msm_gem_address_space *aspace, · 7 unmodified lines | ||
| 250 | 252 | void msm_gem_address_space_put(struct msm_gem_address_space *aspace); |
| 251 | 253 | |
| 252 | 254 | struct msm_gem_address_space * |
| 253 | −msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | |
| 254 | − const char *name); | |
| 255 | − | |
| 256 | −struct msm_gem_address_space * | |
| 257 | −msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, | |
| 258 | − const char *name, uint64_t va_start, uint64_t va_end); | |
| 255 | +msm_gem_address_space_create(struct msm_mmu *mmu, const char *name, | |
| 256 | + u64 va_start, u64 size); | |
| 259 | 257 | |
| 260 | 258 | int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); |
| 261 | 259 | void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); |
| @@ -276,6 +274,9 @@ vm_fault_t msm_gem_fault(struct vm_fault *vmf); · 14 unmodified lines | ||
| 276 | 274 | uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); |
| 277 | 275 | int msm_gem_get_iova(struct drm_gem_object *obj, |
| 278 | 276 | struct msm_gem_address_space *aspace, uint64_t *iova); |
| 277 | +int msm_gem_get_and_pin_iova_range(struct drm_gem_object *obj, | |
| 278 | + struct msm_gem_address_space *aspace, uint64_t *iova, | |
| 279 | + u64 range_start, u64 range_end); | |
| 279 | 280 | int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, |
| 280 | 281 | struct msm_gem_address_space *aspace, uint64_t *iova); |
| 281 | 282 | uint64_t msm_gem_iova(struct drm_gem_object *obj, |
| @@ -389,7 +389,8 @@ put_iova(struct drm_gem_object *obj) · 388 unmodified lines | ||
| 389 | 389 | } |
| 390 | 390 | |
| 391 | 391 | static int msm_gem_get_iova_locked(struct drm_gem_object *obj, |
| 392 | − struct msm_gem_address_space *aspace, uint64_t *iova) | |
| 392 | + struct msm_gem_address_space *aspace, uint64_t *iova, | |
| 393 | + u64 range_start, u64 range_end) | |
| 393 | 394 | { |
| 394 | 395 | struct msm_gem_object *msm_obj = to_msm_bo(obj); |
| 395 | 396 | struct msm_gem_vma *vma; |
| @@ -404,7 +405,8 @@ static int msm_gem_get_iova_locked(struct drm_gem_object *obj, · 8 unmodified lines | ||
| 404 | 405 | if (IS_ERR(vma)) |
| 405 | 406 | return PTR_ERR(vma); |
| 406 | 407 | |
| 407 | − ret = msm_gem_init_vma(aspace, vma, obj->size >> PAGE_SHIFT); | |
| 408 | + ret = msm_gem_init_vma(aspace, vma, obj->size >> PAGE_SHIFT, | |
| 409 | + range_start, range_end); | |
| 408 | 410 | if (ret) { |
| 409 | 411 | del_vma(vma); |
| 410 | 412 | return ret; |
| @@ -426,6 +428,9 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj, · 15 unmodified lines | ||
| 426 | 428 | if (!(msm_obj->flags & MSM_BO_GPU_READONLY)) |
| 427 | 429 | prot |= IOMMU_WRITE; |
| 428 | 430 | |
| 431 | + if (msm_obj->flags & MSM_BO_MAP_PRIV) | |
| 432 | + prot |= IOMMU_PRIV; | |
| 433 | + | |
| 429 | 434 | WARN_ON(!mutex_is_locked(&msm_obj->lock)); |
| 430 | 435 | |
| 431 | 436 | if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) |
| @@ -443,9 +448,13 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj, · 11 unmodified lines | ||
| 443 | 448 | msm_obj->sgt, obj->size >> PAGE_SHIFT); |
| 444 | 449 | } |
| 445 | 450 | |
| 446 | −/* get iova and pin it. Should have a matching put */ | |
| 447 | −int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, | |
| 448 | − struct msm_gem_address_space *aspace, uint64_t *iova) | |
| 451 | +/* | |
| 452 | + * get iova and pin it. Should have a matching put | |
| 453 | + * limits iova to specified range (in pages) | |
| 454 | + */ | |
| 455 | +int msm_gem_get_and_pin_iova_range(struct drm_gem_object *obj, | |
| 456 | + struct msm_gem_address_space *aspace, uint64_t *iova, | |
| 457 | + u64 range_start, u64 range_end) | |
| 449 | 458 | { |
| 450 | 459 | struct msm_gem_object *msm_obj = to_msm_bo(obj); |
| 451 | 460 | u64 local; |
| @@ -453,7 +462,8 @@ int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, · 1 unmodified line | ||
| 453 | 462 | |
| 454 | 463 | mutex_lock(&msm_obj->lock); |
| 455 | 464 | |
| 456 | − ret = msm_gem_get_iova_locked(obj, aspace, &local); | |
| 465 | + ret = msm_gem_get_iova_locked(obj, aspace, &local, | |
| 466 | + range_start, range_end); | |
| 457 | 467 | |
| 458 | 468 | if (!ret) |
| 459 | 469 | ret = msm_gem_pin_iova(obj, aspace); |
| @@ -465,6 +475,13 @@ int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, · 5 unmodified lines | ||
| 465 | 475 | return ret; |
| 466 | 476 | } |
| 467 | 477 | |
| 478 | +/* get iova and pin it. Should have a matching put */ | |
| 479 | +int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, | |
| 480 | + struct msm_gem_address_space *aspace, uint64_t *iova) | |
| 481 | +{ | |
| 482 | + return msm_gem_get_and_pin_iova_range(obj, aspace, iova, 0, U64_MAX); | |
| 483 | +} | |
| 484 | + | |
| 468 | 485 | /* |
| 469 | 486 | * Get an iova but don't pin it. Doesn't need a put because iovas are currently |
| 470 | 487 | * valid for the life of the object |
| @@ -476,7 +493,7 @@ int msm_gem_get_iova(struct drm_gem_object *obj, · 5 unmodified lines | ||
| 476 | 493 | int ret; |
| 477 | 494 | |
| 478 | 495 | mutex_lock(&msm_obj->lock); |
| 479 | − ret = msm_gem_get_iova_locked(obj, aspace, iova); | |
| 496 | + ret = msm_gem_get_iova_locked(obj, aspace, iova, 0, U64_MAX); | |
| 480 | 497 | mutex_unlock(&msm_obj->lock); |
| 481 | 498 | |
| 482 | 499 | return ret; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | /* Additional internal-use only BO flags: */ |
| 15 | 15 | #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ |
| 16 | +#define MSM_BO_MAP_PRIV 0x20000000 /* use IOMMU_PRIV when mapping */ | |
| 16 | 17 | |
| 17 | 18 | struct msm_gem_address_space { |
| 18 | 19 | const char *name; |
| @@ -8,7 +8,9 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <linux/sync_file.h> |
| 9 | 9 | #include <linux/uaccess.h> |
| 10 | 10 | |
| 11 | +#include <drm/drm_drv.h> | |
| 11 | 12 | #include <drm/drm_file.h> |
| 13 | +#include <drm/drm_syncobj.h> | |
| 12 | 14 | |
| 13 | 15 | #include "msm_drv.h" |
| 14 | 16 | #include "msm_gpu.h" |
| @@ -391,6 +393,186 @@ static void submit_cleanup(struct msm_gem_submit *submit) · 376 unmodified lines | ||
| 391 | 393 | } |
| 392 | 394 | } |
| 393 | 395 | |
| 396 | + | |
| 397 | +struct msm_submit_post_dep { | |
| 398 | + struct drm_syncobj *syncobj; | |
| 399 | + uint64_t point; | |
| 400 | + struct dma_fence_chain *chain; | |
| 401 | +}; | |
| 402 | + | |
| 403 | +static struct drm_syncobj **msm_wait_deps(struct drm_device *dev, | |
| 404 | + struct drm_file *file, | |
| 405 | + uint64_t in_syncobjs_addr, | |
| 406 | + uint32_t nr_in_syncobjs, | |
| 407 | + size_t syncobj_stride, | |
| 408 | + struct msm_ringbuffer *ring) | |
| 409 | +{ | |
| 410 | + struct drm_syncobj **syncobjs = NULL; | |
| 411 | + struct drm_msm_gem_submit_syncobj syncobj_desc = {0}; | |
| 412 | + int ret = 0; | |
| 413 | + uint32_t i, j; | |
| 414 | + | |
| 415 | + syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs), | |
| 416 | + GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); | |
| 417 | + if (!syncobjs) | |
| 418 | + return ERR_PTR(-ENOMEM); | |
| 419 | + | |
| 420 | + for (i = 0; i < nr_in_syncobjs; ++i) { | |
| 421 | + uint64_t address = in_syncobjs_addr + i * syncobj_stride; | |
| 422 | + struct dma_fence *fence; | |
| 423 | + | |
| 424 | + if (copy_from_user(&syncobj_desc, | |
| 425 | + u64_to_user_ptr(address), | |
| 426 | + min(syncobj_stride, sizeof(syncobj_desc)))) { | |
| 427 | + ret = -EFAULT; | |
| 428 | + break; | |
| 429 | + } | |
| 430 | + | |
| 431 | + if (syncobj_desc.point && | |
| 432 | + !drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) { | |
| 433 | + ret = -EOPNOTSUPP; | |
| 434 | + break; | |
| 435 | + } | |
| 436 | + | |
| 437 | + if (syncobj_desc.flags & ~MSM_SUBMIT_SYNCOBJ_FLAGS) { | |
| 438 | + ret = -EINVAL; | |
| 439 | + break; | |
| 440 | + } | |
| 441 | + | |
| 442 | + ret = drm_syncobj_find_fence(file, syncobj_desc.handle, | |
| 443 | + syncobj_desc.point, 0, &fence); | |
| 444 | + if (ret) | |
| 445 | + break; | |
| 446 | + | |
| 447 | + if (!dma_fence_match_context(fence, ring->fctx->context)) | |
| 448 | + ret = dma_fence_wait(fence, true); | |
| 449 | + | |
| 450 | + dma_fence_put(fence); | |
| 451 | + if (ret) | |
| 452 | + break; | |
| 453 | + | |
| 454 | + if (syncobj_desc.flags & MSM_SUBMIT_SYNCOBJ_RESET) { | |
| 455 | + syncobjs[i] = | |
| 456 | + drm_syncobj_find(file, syncobj_desc.handle); | |
| 457 | + if (!syncobjs[i]) { | |
| 458 | + ret = -EINVAL; | |
| 459 | + break; | |
| 460 | + } | |
| 461 | + } | |
| 462 | + } | |
| 463 | + | |
| 464 | + if (ret) { | |
| 465 | + for (j = 0; j <= i; ++j) { | |
| 466 | + if (syncobjs[j]) | |
| 467 | + drm_syncobj_put(syncobjs[j]); | |
| 468 | + } | |
| 469 | + kfree(syncobjs); | |
| 470 | + return ERR_PTR(ret); | |
| 471 | + } | |
| 472 | + return syncobjs; | |
| 473 | +} | |
| 474 | + | |
| 475 | +static void msm_reset_syncobjs(struct drm_syncobj **syncobjs, | |
| 476 | + uint32_t nr_syncobjs) | |
| 477 | +{ | |
| 478 | + uint32_t i; | |
| 479 | + | |
| 480 | + for (i = 0; syncobjs && i < nr_syncobjs; ++i) { | |
| 481 | + if (syncobjs[i]) | |
| 482 | + drm_syncobj_replace_fence(syncobjs[i], NULL); | |
| 483 | + } | |
| 484 | +} | |
| 485 | + | |
| 486 | +static struct msm_submit_post_dep *msm_parse_post_deps(struct drm_device *dev, | |
| 487 | + struct drm_file *file, | |
| 488 | + uint64_t syncobjs_addr, | |
| 489 | + uint32_t nr_syncobjs, | |
| 490 | + size_t syncobj_stride) | |
| 491 | +{ | |
| 492 | + struct msm_submit_post_dep *post_deps; | |
| 493 | + struct drm_msm_gem_submit_syncobj syncobj_desc = {0}; | |
| 494 | + int ret = 0; | |
| 495 | + uint32_t i, j; | |
| 496 | + | |
| 497 | + post_deps = kmalloc_array(nr_syncobjs, sizeof(*post_deps), | |
| 498 | + GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); | |
| 499 | + if (!post_deps) | |
| 500 | + return ERR_PTR(-ENOMEM); | |
| 501 | + | |
| 502 | + for (i = 0; i < nr_syncobjs; ++i) { | |
| 503 | + uint64_t address = syncobjs_addr + i * syncobj_stride; | |
| 504 | + | |
| 505 | + if (copy_from_user(&syncobj_desc, | |
| 506 | + u64_to_user_ptr(address), | |
| 507 | + min(syncobj_stride, sizeof(syncobj_desc)))) { | |
| 508 | + ret = -EFAULT; | |
| 509 | + break; | |
| 510 | + } | |
| 511 | + | |
| 512 | + post_deps[i].point = syncobj_desc.point; | |
| 513 | + post_deps[i].chain = NULL; | |
| 514 | + | |
| 515 | + if (syncobj_desc.flags) { | |
| 516 | + ret = -EINVAL; | |
| 517 | + break; | |
| 518 | + } | |
| 519 | + | |
| 520 | + if (syncobj_desc.point) { | |
| 521 | + if (!drm_core_check_feature(dev, | |
| 522 | + DRIVER_SYNCOBJ_TIMELINE)) { | |
| 523 | + ret = -EOPNOTSUPP; | |
| 524 | + break; | |
| 525 | + } | |
| 526 | + | |
| 527 | + post_deps[i].chain = | |
| 528 | + kmalloc(sizeof(*post_deps[i].chain), | |
| 529 | + GFP_KERNEL); | |
| 530 | + if (!post_deps[i].chain) { | |
| 531 | + ret = -ENOMEM; | |
| 532 | + break; | |
| 533 | + } | |
| 534 | + } | |
| 535 | + | |
| 536 | + post_deps[i].syncobj = | |
| 537 | + drm_syncobj_find(file, syncobj_desc.handle); | |
| 538 | + if (!post_deps[i].syncobj) { | |
| 539 | + ret = -EINVAL; | |
| 540 | + break; | |
| 541 | + } | |
| 542 | + } | |
| 543 | + | |
| 544 | + if (ret) { | |
| 545 | + for (j = 0; j <= i; ++j) { | |
| 546 | + kfree(post_deps[j].chain); | |
| 547 | + if (post_deps[j].syncobj) | |
| 548 | + drm_syncobj_put(post_deps[j].syncobj); | |
| 549 | + } | |
| 550 | + | |
| 551 | + kfree(post_deps); | |
| 552 | + return ERR_PTR(ret); | |
| 553 | + } | |
| 554 | + | |
| 555 | + return post_deps; | |
| 556 | +} | |
| 557 | + | |
| 558 | +static void msm_process_post_deps(struct msm_submit_post_dep *post_deps, | |
| 559 | + uint32_t count, struct dma_fence *fence) | |
| 560 | +{ | |
| 561 | + uint32_t i; | |
| 562 | + | |
| 563 | + for (i = 0; post_deps && i < count; ++i) { | |
| 564 | + if (post_deps[i].chain) { | |
| 565 | + drm_syncobj_add_point(post_deps[i].syncobj, | |
| 566 | + post_deps[i].chain, | |
| 567 | + fence, post_deps[i].point); | |
| 568 | + post_deps[i].chain = NULL; | |
| 569 | + } else { | |
| 570 | + drm_syncobj_replace_fence(post_deps[i].syncobj, | |
| 571 | + fence); | |
| 572 | + } | |
| 573 | + } | |
| 574 | +} | |
| 575 | + | |
| 394 | 576 | int msm_ioctl_gem_submit(struct drm_device *dev, void *data, |
| 395 | 577 | struct drm_file *file) |
| 396 | 578 | { |
| @@ -403,6 +585,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, · 6 unmodified lines | ||
| 403 | 585 | struct sync_file *sync_file = NULL; |
| 404 | 586 | struct msm_gpu_submitqueue *queue; |
| 405 | 587 | struct msm_ringbuffer *ring; |
| 588 | + struct msm_submit_post_dep *post_deps = NULL; | |
| 589 | + struct drm_syncobj **syncobjs_to_reset = NULL; | |
| 406 | 590 | int out_fence_fd = -1; |
| 407 | 591 | struct pid *pid = get_pid(task_pid(current)); |
| 408 | 592 | bool has_ww_ticket = false; |
| @@ -411,6 +595,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, · 2 unmodified lines | ||
| 411 | 595 | if (!gpu) |
| 412 | 596 | return -ENXIO; |
| 413 | 597 | |
| 598 | + if (args->pad) | |
| 599 | + return -EINVAL; | |
| 600 | + | |
| 414 | 601 | /* for now, we just have 3d pipe.. eventually this would need to |
| 415 | 602 | * be more clever to dispatch to appropriate gpu module: |
| 416 | 603 | */ |
| @@ -458,9 +645,29 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, · 41 unmodified lines | ||
| 458 | 645 | return ret; |
| 459 | 646 | } |
| 460 | 647 | |
| 648 | + if (args->flags & MSM_SUBMIT_SYNCOBJ_IN) { | |
| 649 | + syncobjs_to_reset = msm_wait_deps(dev, file, | |
| 650 | + args->in_syncobjs, | |
| 651 | + args->nr_in_syncobjs, | |
| 652 | + args->syncobj_stride, ring); | |
| 653 | + if (IS_ERR(syncobjs_to_reset)) | |
| 654 | + return PTR_ERR(syncobjs_to_reset); | |
| 655 | + } | |
| 656 | + | |
| 657 | + if (args->flags & MSM_SUBMIT_SYNCOBJ_OUT) { | |
| 658 | + post_deps = msm_parse_post_deps(dev, file, | |
| 659 | + args->out_syncobjs, | |
| 660 | + args->nr_out_syncobjs, | |
| 661 | + args->syncobj_stride); | |
| 662 | + if (IS_ERR(post_deps)) { | |
| 663 | + ret = PTR_ERR(post_deps); | |
| 664 | + goto out_post_unlock; | |
| 665 | + } | |
| 666 | + } | |
| 667 | + | |
| 461 | 668 | ret = mutex_lock_interruptible(&dev->struct_mutex); |
| 462 | 669 | if (ret) |
| 463 | − return ret; | |
| 670 | + goto out_post_unlock; | |
| 464 | 671 | |
| 465 | 672 | if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) { |
| 466 | 673 | out_fence_fd = get_unused_fd_flags(O_CLOEXEC); |
| @@ -587,6 +794,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, · 120 unmodified lines | ||
| 587 | 794 | args->fence_fd = out_fence_fd; |
| 588 | 795 | } |
| 589 | 796 | |
| 797 | + msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs); | |
| 798 | + msm_process_post_deps(post_deps, args->nr_out_syncobjs, | |
| 799 | + submit->fence); | |
| 800 | + | |
| 801 | + | |
| 590 | 802 | out: |
| 591 | 803 | submit_cleanup(submit); |
| 592 | 804 | if (has_ww_ticket) |
| @@ -597,5 +809,23 @@ out_unlock: · 4 unmodified lines | ||
| 597 | 809 | if (ret && (out_fence_fd >= 0)) |
| 598 | 810 | put_unused_fd(out_fence_fd); |
| 599 | 811 | mutex_unlock(&dev->struct_mutex); |
| 812 | + | |
| 813 | +out_post_unlock: | |
| 814 | + if (!IS_ERR_OR_NULL(post_deps)) { | |
| 815 | + for (i = 0; i < args->nr_out_syncobjs; ++i) { | |
| 816 | + kfree(post_deps[i].chain); | |
| 817 | + drm_syncobj_put(post_deps[i].syncobj); | |
| 818 | + } | |
| 819 | + kfree(post_deps); | |
| 820 | + } | |
| 821 | + | |
| 822 | + if (!IS_ERR_OR_NULL(syncobjs_to_reset)) { | |
| 823 | + for (i = 0; i < args->nr_in_syncobjs; ++i) { | |
| 824 | + if (syncobjs_to_reset[i]) | |
| 825 | + drm_syncobj_put(syncobjs_to_reset[i]); | |
| 826 | + } | |
| 827 | + kfree(syncobjs_to_reset); | |
| 828 | + } | |
| 829 | + | |
| 600 | 830 | return ret; |
| 601 | 831 | } |
| @@ -103,7 +103,8 @@ void msm_gem_close_vma(struct msm_gem_address_space *aspace, · 102 unmodified lines | ||
| 103 | 103 | |
| 104 | 104 | /* Initialize a new vma and allocate an iova for it */ |
| 105 | 105 | int msm_gem_init_vma(struct msm_gem_address_space *aspace, |
| 106 | − struct msm_gem_vma *vma, int npages) | |
| 106 | + struct msm_gem_vma *vma, int npages, | |
| 107 | + u64 range_start, u64 range_end) | |
| 107 | 108 | { |
| 108 | 109 | int ret; |
| 109 | 110 | |
| @@ -111,7 +112,8 @@ int msm_gem_init_vma(struct msm_gem_address_space *aspace, · 1 unmodified line | ||
| 111 | 112 | return -EBUSY; |
| 112 | 113 | |
| 113 | 114 | spin_lock(&aspace->lock); |
| 114 | − ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); | |
| 115 | + ret = drm_mm_insert_node_in_range(&aspace->mm, &vma->node, npages, 0, | |
| 116 | + 0, range_start, range_end, 0); | |
| 115 | 117 | spin_unlock(&aspace->lock); |
| 116 | 118 | |
| 117 | 119 | if (ret) |
| @@ -125,37 +127,14 @@ int msm_gem_init_vma(struct msm_gem_address_space *aspace, · 7 unmodified lines | ||
| 125 | 127 | return 0; |
| 126 | 128 | } |
| 127 | 129 | |
| 128 | − | |
| 129 | 130 | struct msm_gem_address_space * |
| 130 | −msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | |
| 131 | − const char *name) | |
| 131 | +msm_gem_address_space_create(struct msm_mmu *mmu, const char *name, | |
| 132 | + u64 va_start, u64 size) | |
| 132 | 133 | { |
| 133 | 134 | struct msm_gem_address_space *aspace; |
| 134 | − u64 size = domain->geometry.aperture_end - | |
| 135 | − domain->geometry.aperture_start; | |
| 136 | − | |
| 137 | − aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); | |
| 138 | − if (!aspace) | |
| 139 | − return ERR_PTR(-ENOMEM); | |
| 140 | − | |
| 141 | − spin_lock_init(&aspace->lock); | |
| 142 | − aspace->name = name; | |
| 143 | − aspace->mmu = msm_iommu_new(dev, domain); | |
| 144 | − | |
| 145 | − drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), | |
| 146 | − size >> PAGE_SHIFT); | |
| 147 | 135 | |
| 148 | − kref_init(&aspace->kref); | |
| 149 | − | |
| 150 | − return aspace; | |
| 151 | −} | |
| 152 | − | |
| 153 | −struct msm_gem_address_space * | |
| 154 | −msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, | |
| 155 | − const char *name, uint64_t va_start, uint64_t va_end) | |
| 156 | −{ | |
| 157 | − struct msm_gem_address_space *aspace; | |
| 158 | − u64 size = va_end - va_start; | |
| 136 | + if (IS_ERR(mmu)) | |
| 137 | + return ERR_CAST(mmu); | |
| 159 | 138 | |
| 160 | 139 | aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); |
| 161 | 140 | if (!aspace) |
| @@ -163,10 +142,9 @@ msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, · 1 unmodified line | ||
| 163 | 142 | |
| 164 | 143 | spin_lock_init(&aspace->lock); |
| 165 | 144 | aspace->name = name; |
| 166 | − aspace->mmu = msm_gpummu_new(dev, gpu); | |
| 145 | + aspace->mmu = mmu; | |
| 167 | 146 | |
| 168 | − drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT), | |
| 169 | − size >> PAGE_SHIFT); | |
| 147 | + drm_mm_init(&aspace->mm, va_start >> PAGE_SHIFT, size >> PAGE_SHIFT); | |
| 170 | 148 | |
| 171 | 149 | kref_init(&aspace->kref); |
| 172 | 150 | |
| @@ -821,51 +821,6 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) · 820 unmodified lines | ||
| 821 | 821 | return 0; |
| 822 | 822 | } |
| 823 | 823 | |
| 824 | −static struct msm_gem_address_space * | |
| 825 | −msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev, | |
| 826 | − uint64_t va_start, uint64_t va_end) | |
| 827 | −{ | |
| 828 | − struct msm_gem_address_space *aspace; | |
| 829 | − int ret; | |
| 830 | − | |
| 831 | − /* | |
| 832 | − * Setup IOMMU.. eventually we will (I think) do this once per context | |
| 833 | − * and have separate page tables per context. For now, to keep things | |
| 834 | − * simple and to get something working, just use a single address space: | |
| 835 | − */ | |
| 836 | − if (!adreno_is_a2xx(to_adreno_gpu(gpu))) { | |
| 837 | − struct iommu_domain *iommu = iommu_domain_alloc(&platform_bus_type); | |
| 838 | − if (!iommu) | |
| 839 | − return NULL; | |
| 840 | − | |
| 841 | − iommu->geometry.aperture_start = va_start; | |
| 842 | − iommu->geometry.aperture_end = va_end; | |
| 843 | − | |
| 844 | − DRM_DEV_INFO(gpu->dev->dev, "%s: using IOMMU\n", gpu->name); | |
| 845 | − | |
| 846 | − aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu"); | |
| 847 | − if (IS_ERR(aspace)) | |
| 848 | − iommu_domain_free(iommu); | |
| 849 | − } else { | |
| 850 | − aspace = msm_gem_address_space_create_a2xx(&pdev->dev, gpu, "gpu", | |
| 851 | − va_start, va_end); | |
| 852 | − } | |
| 853 | − | |
| 854 | − if (IS_ERR(aspace)) { | |
| 855 | − DRM_DEV_ERROR(gpu->dev->dev, "failed to init mmu: %ld\n", | |
| 856 | − PTR_ERR(aspace)); | |
| 857 | − return ERR_CAST(aspace); | |
| 858 | − } | |
| 859 | − | |
| 860 | − ret = aspace->mmu->funcs->attach(aspace->mmu); | |
| 861 | − if (ret) { | |
| 862 | − msm_gem_address_space_put(aspace); | |
| 863 | − return ERR_PTR(ret); | |
| 864 | − } | |
| 865 | − | |
| 866 | − return aspace; | |
| 867 | −} | |
| 868 | − | |
| 869 | 824 | int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, |
| 870 | 825 | struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, |
| 871 | 826 | const char *name, struct msm_gpu_config *config) |
| @@ -938,8 +893,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, · 66 unmodified lines | ||
| 938 | 893 | |
| 939 | 894 | msm_devfreq_init(gpu); |
| 940 | 895 | |
| 941 | − gpu->aspace = msm_gpu_create_address_space(gpu, pdev, | |
| 942 | − config->va_start, config->va_end); | |
| 896 | + | |
| 897 | + gpu->aspace = gpu->funcs->create_address_space(gpu, pdev); | |
| 943 | 898 | |
| 944 | 899 | if (gpu->aspace == NULL) |
| 945 | 900 | DRM_DEV_INFO(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); |
| @@ -21,8 +21,6 @@ struct msm_gpu_state; · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | struct msm_gpu_config { |
| 23 | 23 | const char *ioname; |
| 24 | − uint64_t va_start; | |
| 25 | − uint64_t va_end; | |
| 26 | 24 | unsigned int nr_rings; |
| 27 | 25 | }; |
| 28 | 26 | |
| @@ -64,6 +62,8 @@ struct msm_gpu_funcs { · 35 unmodified lines | ||
| 64 | 62 | int (*gpu_state_put)(struct msm_gpu_state *state); |
| 65 | 63 | unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); |
| 66 | 64 | void (*gpu_set_freq)(struct msm_gpu *gpu, unsigned long freq); |
| 65 | + struct msm_gem_address_space *(*create_address_space) | |
| 66 | + (struct msm_gpu *gpu, struct platform_device *pdev); | |
| 67 | 67 | }; |
| 68 | 68 | |
| 69 | 69 | struct msm_gpu { |
| @@ -21,17 +21,12 @@ struct msm_gpummu { · 20 unmodified lines | ||
| 21 | 21 | #define GPUMMU_PAGE_SIZE SZ_4K |
| 22 | 22 | #define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE) |
| 23 | 23 | |
| 24 | −static int msm_gpummu_attach(struct msm_mmu *mmu) | |
| 25 | −{ | |
| 26 | − return 0; | |
| 27 | −} | |
| 28 | − | |
| 29 | 24 | static void msm_gpummu_detach(struct msm_mmu *mmu) |
| 30 | 25 | { |
| 31 | 26 | } |
| 32 | 27 | |
| 33 | 28 | static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova, |
| 34 | − struct sg_table *sgt, unsigned len, int prot) | |
| 29 | + struct sg_table *sgt, size_t len, int prot) | |
| 35 | 30 | { |
| 36 | 31 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); |
| 37 | 32 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; |
| @@ -59,7 +54,7 @@ static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova, · 21 unmodified lines | ||
| 59 | 54 | return 0; |
| 60 | 55 | } |
| 61 | 56 | |
| 62 | −static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len) | |
| 57 | +static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova, size_t len) | |
| 63 | 58 | { |
| 64 | 59 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); |
| 65 | 60 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; |
| @@ -85,7 +80,6 @@ static void msm_gpummu_destroy(struct msm_mmu *mmu) · 19 unmodified lines | ||
| 85 | 80 | } |
| 86 | 81 | |
| 87 | 82 | static const struct msm_mmu_funcs funcs = { |
| 88 | − .attach = msm_gpummu_attach, | |
| 89 | 83 | .detach = msm_gpummu_detach, |
| 90 | 84 | .map = msm_gpummu_map, |
| 91 | 85 | .unmap = msm_gpummu_unmap, |
| @@ -23,13 +23,6 @@ static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, · 22 unmodified lines | ||
| 23 | 23 | return 0; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | −static int msm_iommu_attach(struct msm_mmu *mmu) | |
| 27 | −{ | |
| 28 | − struct msm_iommu *iommu = to_msm_iommu(mmu); | |
| 29 | − | |
| 30 | − return iommu_attach_device(iommu->domain, mmu->dev); | |
| 31 | −} | |
| 32 | − | |
| 33 | 26 | static void msm_iommu_detach(struct msm_mmu *mmu) |
| 34 | 27 | { |
| 35 | 28 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| @@ -38,7 +31,7 @@ static void msm_iommu_detach(struct msm_mmu *mmu) · 2 unmodified lines | ||
| 38 | 31 | } |
| 39 | 32 | |
| 40 | 33 | static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, |
| 41 | − struct sg_table *sgt, unsigned len, int prot) | |
| 34 | + struct sg_table *sgt, size_t len, int prot) | |
| 42 | 35 | { |
| 43 | 36 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 44 | 37 | size_t ret; |
| @@ -49,7 +42,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, · 4 unmodified lines | ||
| 49 | 42 | return (ret == len) ? 0 : -EINVAL; |
| 50 | 43 | } |
| 51 | 44 | |
| 52 | −static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len) | |
| 45 | +static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, size_t len) | |
| 53 | 46 | { |
| 54 | 47 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 55 | 48 | |
| @@ -66,7 +59,6 @@ static void msm_iommu_destroy(struct msm_mmu *mmu) · 10 unmodified lines | ||
| 66 | 59 | } |
| 67 | 60 | |
| 68 | 61 | static const struct msm_mmu_funcs funcs = { |
| 69 | − .attach = msm_iommu_attach, | |
| 70 | 62 | .detach = msm_iommu_detach, |
| 71 | 63 | .map = msm_iommu_map, |
| 72 | 64 | .unmap = msm_iommu_unmap, |
| @@ -76,6 +68,10 @@ static const struct msm_mmu_funcs funcs = { · 3 unmodified lines | ||
| 76 | 68 | struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) |
| 77 | 69 | { |
| 78 | 70 | struct msm_iommu *iommu; |
| 71 | + int ret; | |
| 72 | + | |
| 73 | + if (!domain) | |
| 74 | + return ERR_PTR(-ENODEV); | |
| 79 | 75 | |
| 80 | 76 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
| 81 | 77 | if (!iommu) |
| @@ -85,5 +81,11 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) · 3 unmodified lines | ||
| 85 | 81 | msm_mmu_init(&iommu->base, dev, &funcs); |
| 86 | 82 | iommu_set_fault_handler(domain, msm_fault_handler, iommu); |
| 87 | 83 | |
| 84 | + ret = iommu_attach_device(iommu->domain, dev); | |
| 85 | + if (ret) { | |
| 86 | + kfree(iommu); | |
| 87 | + return ERR_PTR(ret); | |
| 88 | + } | |
| 89 | + | |
| 88 | 90 | return &iommu->base; |
| 89 | 91 | } |
| @@ -10,11 +10,10 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/iommu.h> |
| 11 | 11 | |
| 12 | 12 | struct msm_mmu_funcs { |
| 13 | − int (*attach)(struct msm_mmu *mmu); | |
| 14 | 13 | void (*detach)(struct msm_mmu *mmu); |
| 15 | 14 | int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, |
| 16 | − unsigned len, int prot); | |
| 17 | − int (*unmap)(struct msm_mmu *mmu, uint64_t iova, unsigned len); | |
| 15 | + size_t len, int prot); | |
| 16 | + int (*unmap)(struct msm_mmu *mmu, uint64_t iova, size_t len); | |
| 18 | 17 | void (*destroy)(struct msm_mmu *mmu); |
| 19 | 18 | }; |
| 20 | 19 | |
| @@ -29,8 +29,6 @@ · 28 unmodified lines | ||
| 29 | 29 | * or shader programs (if not emitted inline in cmdstream). |
| 30 | 30 | */ |
| 31 | 31 | |
| 32 | −#ifdef CONFIG_DEBUG_FS | |
| 33 | − | |
| 34 | 32 | #include <linux/circ_buf.h> |
| 35 | 33 | #include <linux/debugfs.h> |
| 36 | 34 | #include <linux/kfifo.h> |
| @@ -47,6 +45,8 @@ bool rd_full = false; · 10 unmodified lines | ||
| 47 | 45 | MODULE_PARM_DESC(rd_full, "If true, $debugfs/.../rd will snapshot all buffer contents"); |
| 48 | 46 | module_param_named(rd_full, rd_full, bool, 0600); |
| 49 | 47 | |
| 48 | +#ifdef CONFIG_DEBUG_FS | |
| 49 | + | |
| 50 | 50 | enum rd_sect_type { |
| 51 | 51 | RD_NONE, |
| 52 | 52 | RD_TEST, /* ascii text */ |
| @@ -217,13 +217,28 @@ struct drm_msm_gem_submit_bo { · 216 unmodified lines | ||
| 217 | 217 | #define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ |
| 218 | 218 | #define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ |
| 219 | 219 | #define MSM_SUBMIT_SUDO 0x10000000 /* run submitted cmds from RB */ |
| 220 | +#define MSM_SUBMIT_SYNCOBJ_IN 0x08000000 /* enable input syncobj */ | |
| 221 | +#define MSM_SUBMIT_SYNCOBJ_OUT 0x04000000 /* enable output syncobj */ | |
| 220 | 222 | #define MSM_SUBMIT_FLAGS ( \ |
| 221 | 223 | MSM_SUBMIT_NO_IMPLICIT | \ |
| 222 | 224 | MSM_SUBMIT_FENCE_FD_IN | \ |
| 223 | 225 | MSM_SUBMIT_FENCE_FD_OUT | \ |
| 224 | 226 | MSM_SUBMIT_SUDO | \ |
| 227 | + MSM_SUBMIT_SYNCOBJ_IN | \ | |
| 228 | + MSM_SUBMIT_SYNCOBJ_OUT | \ | |
| 225 | 229 | 0) |
| 226 | 230 | |
| 231 | +#define MSM_SUBMIT_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */ | |
| 232 | +#define MSM_SUBMIT_SYNCOBJ_FLAGS ( \ | |
| 233 | + MSM_SUBMIT_SYNCOBJ_RESET | \ | |
| 234 | + 0) | |
| 235 | + | |
| 236 | +struct drm_msm_gem_submit_syncobj { | |
| 237 | + __u32 handle; /* in, syncobj handle. */ | |
| 238 | + __u32 flags; /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */ | |
| 239 | + __u64 point; /* in, timepoint for timeline syncobjs. */ | |
| 240 | +}; | |
| 241 | + | |
| 227 | 242 | /* Each cmdstream submit consists of a table of buffers involved, and |
| 228 | 243 | * one or more cmdstream buffers. This allows for conditional execution |
| 229 | 244 | * (context-restore), and IB buffers needed for per tile/bin draw cmds. |
| @@ -236,7 +251,14 @@ struct drm_msm_gem_submit { · 6 unmodified lines | ||
| 236 | 251 | __u64 bos; /* in, ptr to array of submit_bo's */ |
| 237 | 252 | __u64 cmds; /* in, ptr to array of submit_cmd's */ |
| 238 | 253 | __s32 fence_fd; /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */ |
| 239 | − __u32 queueid; /* in, submitqueue id */ | |
| 254 | + __u32 queueid; /* in, submitqueue id */ | |
| 255 | + __u64 in_syncobjs; /* in, ptr to to array of drm_msm_gem_submit_syncobj */ | |
| 256 | + __u64 out_syncobjs; /* in, ptr to to array of drm_msm_gem_submit_syncobj */ | |
| 257 | + __u32 nr_in_syncobjs; /* in, number of entries in in_syncobj */ | |
| 258 | + __u32 nr_out_syncobjs; /* in, number of entries in out_syncobj. */ | |
| 259 | + __u32 syncobj_stride; /* in, stride of syncobj arrays. */ | |
| 260 | + __u32 pad; /*in, reserved for future use, always 0. */ | |
| 261 | + | |
| 240 | 262 | }; |
| 241 | 263 | |
| 242 | 264 | /* The normal way to synchronize with the GPU is just to CPU_PREP on |