* 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 | disp/dpu1/dpu_hw_lm.o \ | 65 | disp/dpu1/dpu_hw_lm.o \ |
| 66 | disp/dpu1/dpu_hw_pingpong.o \ | 66 | disp/dpu1/dpu_hw_pingpong.o \ |
| 67 | disp/dpu1/dpu_hw_sspp.o \ | 67 | disp/dpu1/dpu_hw_sspp.o \ |
| 68 | disp/dpu1/dpu_hw_dspp.o \ | ||
| 68 | disp/dpu1/dpu_hw_top.o \ | 69 | disp/dpu1/dpu_hw_top.o \ |
| 69 | disp/dpu1/dpu_hw_util.o \ | 70 | disp/dpu1/dpu_hw_util.o \ |
| 70 | disp/dpu1/dpu_hw_vbif.o \ | 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 | return state; | 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 | /* Register offset defines for A2XX - copy of A3XX */ | 419 | /* Register offset defines for A2XX - copy of A3XX */ |
| 405 | static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { | 420 | static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { |
| 406 | REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE), | 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 | #endif | 444 | #endif |
| 430 | .gpu_state_get = a2xx_gpu_state_get, | 445 | .gpu_state_get = a2xx_gpu_state_get, |
| 431 | .gpu_state_put = adreno_gpu_state_put, | 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 | #endif | 441 | #endif |
| 442 | .gpu_state_get = a3xx_gpu_state_get, | 442 | .gpu_state_get = a3xx_gpu_state_get, |
| 443 | .gpu_state_put = adreno_gpu_state_put, | 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++) { | 69 | /* No CCU for A405 */ |
| 70 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i), | 70 | if (!adreno_is_a405(adreno_gpu)) { |
| 71 | 0x00000922); | 71 | for (i = 0; i < 4; i++) { |
| 72 | } | 72 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i), |
| 73 | 0x00000922); | ||
| 74 | } | ||
| 73 | 75 | ||
| 74 | for (i = 0; i < 4; i++) { | 76 | for (i = 0; i < 4; i++) { |
| 75 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i), | 77 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i), |
| 76 | 0x00000000); | 78 | 0x00000000); |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 79 | for (i = 0; i < 4; i++) { | 81 | for (i = 0; i < 4; i++) { |
| 80 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i), | 82 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i), |
| 81 | 0x00000001); | 83 | 0x00000001); |
| 84 | } | ||
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | gpu_write(gpu, REG_A4XX_RBBM_CLOCK_MODE_GPC, 0x02222222); | 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 | uint32_t *ptr, len; | 140 | uint32_t *ptr, len; |
| 138 | int i, ret; | 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 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F); | 146 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F); |
| 142 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4); | 147 | gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4); |
| 143 | gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001); | 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 | ~0 /* sentinel */ | 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 | static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) | 494 | static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) |
| 444 | { | 495 | { |
| 445 | struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); | 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 | #endif | 583 | #endif |
| 533 | .gpu_state_get = a4xx_gpu_state_get, | 584 | .gpu_state_get = a4xx_gpu_state_get, |
| 534 | .gpu_state_put = adreno_gpu_state_put, | 585 | .gpu_state_put = adreno_gpu_state_put, |
| 586 | .create_address_space = adreno_iommu_create_address_space, | ||
| 535 | }, | 587 | }, |
| 536 | .get_timestamp = a4xx_get_timestamp, | 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 | gpu->perfcntrs = NULL; | 615 | gpu->perfcntrs = NULL; |
| 564 | gpu->num_perfcntrs = 0; | 616 | gpu->num_perfcntrs = 0; |
| 565 | 617 | ||
| 566 | adreno_gpu->registers = a4xx_registers; | ||
| 567 | adreno_gpu->reg_offsets = a4xx_register_offsets; | ||
| 568 | |||
| 569 | ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); | 618 | ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); |
| 570 | if (ret) | 619 | if (ret) |
| 571 | goto fail; | 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 | /* if needed, allocate gmem: */ | 626 | /* if needed, allocate gmem: */ |
| 574 | if (adreno_is_a4xx(adreno_gpu)) { | 627 | if (adreno_is_a4xx(adreno_gpu)) { |
| 575 | ret = adreno_gpu_ocmem_init(dev->dev, adreno_gpu, | 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 | u64 busy_cycles, busy_time; | 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 | busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, | 1411 | busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, |
| 1408 | REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); | 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 | gpu->devfreq.busy_cycles = busy_cycles; | 1417 | gpu->devfreq.busy_cycles = busy_cycles; |
| 1414 | 1418 | ||
| 1419 | pm_runtime_put(&gpu->pdev->dev); | ||
| 1420 | |||
| 1415 | if (WARN_ON(busy_time > ~0LU)) | 1421 | if (WARN_ON(busy_time > ~0LU)) |
| 1416 | return ~0LU; | 1422 | return ~0LU; |
| 1417 | 1423 | ||
| @@ -1439,6 +1445,7 @@ static const struct adreno_gpu_funcs funcs = { · 21 unmodified lines | |||
| 1439 | .gpu_busy = a5xx_gpu_busy, | 1445 | .gpu_busy = a5xx_gpu_busy, |
| 1440 | .gpu_state_get = a5xx_gpu_state_get, | 1446 | .gpu_state_get = a5xx_gpu_state_get, |
| 1441 | .gpu_state_put = a5xx_gpu_state_put, | 1447 | .gpu_state_put = a5xx_gpu_state_put, |
| 1448 | .create_address_space = adreno_iommu_create_address_space, | ||
| 1442 | }, | 1449 | }, |
| 1443 | .get_timestamp = a5xx_get_timestamp, | 1450 | .get_timestamp = a5xx_get_timestamp, |
| 1444 | }; | 1451 | }; |
| @@ -1047,6 +1047,8 @@ enum a6xx_tex_type { · 1046 unmodified lines | |||
| 1047 | 1047 | ||
| 1048 | #define REG_A6XX_CP_MISC_CNTL 0x00000840 | 1048 | #define REG_A6XX_CP_MISC_CNTL 0x00000840 |
| 1049 | 1049 | ||
| 1050 | #define REG_A6XX_CP_APRIV_CNTL 0x00000844 | ||
| 1051 | |||
| 1050 | #define REG_A6XX_CP_ROQ_THRESHOLDS_1 0x000008c1 | 1052 | #define REG_A6XX_CP_ROQ_THRESHOLDS_1 0x000008c1 |
| 1051 | 1053 | ||
| 1052 | #define REG_A6XX_CP_ROQ_THRESHOLDS_2 0x000008c2 | 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 | #define REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL 0x00000010 | 1767 | #define REG_A6XX_RBBM_VBIF_CLIENT_QOS_CNTL 0x00000010 |
| 1766 | 1768 | ||
| 1769 | #define REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL 0x00000011 | ||
| 1770 | |||
| 1767 | #define REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0000001f | 1771 | #define REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0000001f |
| 1768 | 1772 | ||
| 1769 | #define REG_A6XX_RBBM_INT_CLEAR_CMD 0x00000037 | 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 | #define REG_A6XX_TPL1_NC_MODE_CNTL 0x0000b604 | 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 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_0 0x0000b610 | 2435 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_0 0x0000b610 |
| 2422 | 2436 | ||
| 2423 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_1 0x0000b611 | 2437 | #define REG_A6XX_TPL1_PERFCTR_TP_SEL_1 0x0000b611 |
| @@ -2,14 +2,16 @@ · 1 unmodified line | |||
| 2 | /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */ | 2 | /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */ |
| 3 | 3 | ||
| 4 | #include <linux/clk.h> | 4 | #include <linux/clk.h> |
| 5 | #include <linux/dma-mapping.h> | ||
| 6 | #include <linux/interconnect.h> | 5 | #include <linux/interconnect.h> |
| 7 | #include <linux/pm_domain.h> | 6 | #include <linux/pm_domain.h> |
| 8 | #include <linux/pm_opp.h> | 7 | #include <linux/pm_opp.h> |
| 9 | #include <soc/qcom/cmd-db.h> | 8 | #include <soc/qcom/cmd-db.h> |
| 9 | #include <drm/drm_gem.h> | ||
| 10 | 10 | ||
| 11 | #include "a6xx_gpu.h" | 11 | #include "a6xx_gpu.h" |
| 12 | #include "a6xx_gmu.xml.h" | 12 | #include "a6xx_gmu.xml.h" |
| 13 | #include "msm_gem.h" | ||
| 14 | #include "msm_mmu.h" | ||
| 13 | 15 | ||
| 14 | static void a6xx_gmu_fault(struct a6xx_gmu *gmu) | 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 | if (ret) | 129 | if (ret) |
| 128 | dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); | 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 | * Eventually we will want to scale the path vote with the frequency but | 133 | * Eventually we will want to scale the path vote with the frequency but |
| 134 | * for now leave it at max so that the performance is nominal. | 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 | break; | 151 | break; |
| 152 | 152 | ||
| 153 | gmu->current_perf_index = perf_index; | 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 | unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu) | 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 | u32 val; | 209 | u32 val; |
| 197 | 210 | ||
| 198 | gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1); | 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 | gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0); | 218 | gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0); |
| 200 | 219 | ||
| 201 | ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val, | 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 | switch (state) { | 252 | switch (state) { |
| 234 | case GMU_OOB_GPU_SET: | 253 | case GMU_OOB_GPU_SET: |
| 235 | request = GMU_OOB_GPU_SET_REQUEST; | 254 | if (gmu->legacy) { |
| 236 | ack = GMU_OOB_GPU_SET_ACK; | 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 | name = "GPU_SET"; | 261 | name = "GPU_SET"; |
| 238 | break; | 262 | break; |
| 239 | case GMU_OOB_BOOT_SLUMBER: | 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 | /* Clear a pending OOB state in the GMU */ | 296 | /* Clear a pending OOB state in the GMU */ |
| 273 | void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) | 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 | switch (state) { | 306 | switch (state) { |
| 276 | case GMU_OOB_GPU_SET: | 307 | case GMU_OOB_GPU_SET: |
| 277 | gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, | 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 | int ret; | 325 | int ret; |
| 295 | u32 val; | 326 | u32 val; |
| 296 | 327 | ||
| 328 | if (!gmu->legacy) | ||
| 329 | return 0; | ||
| 330 | |||
| 297 | gmu_write(gmu, REG_A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, 0x778000); | 331 | gmu_write(gmu, REG_A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, 0x778000); |
| 298 | 332 | ||
| 299 | ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, val, | 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 | u32 val; | 347 | u32 val; |
| 314 | int ret; | 348 | int ret; |
| 315 | 349 | ||
| 350 | if (!gmu->legacy) | ||
| 351 | return; | ||
| 352 | |||
| 316 | /* Make sure retention is on */ | 353 | /* Make sure retention is on */ |
| 317 | gmu_rmw(gmu, REG_A6XX_GPU_CC_GX_GDSCR, 0, (1 << 11)); | 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 | if (gmu->idle_level < GMU_IDLE_STATE_SPTP) | 393 | if (gmu->idle_level < GMU_IDLE_STATE_SPTP) |
| 357 | a6xx_sptprac_disable(gmu); | 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 | /* Tell the GMU to get ready to slumber */ | 401 | /* Tell the GMU to get ready to slumber */ |
| 360 | gmu_write(gmu, REG_A6XX_GMU_BOOT_SLUMBER_OPTION, 1); | 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 | /* Put fence into allow mode */ | 417 | /* Put fence into allow mode */ |
| 375 | gmu_write(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); | 418 | gmu_write(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, 0); |
| 376 | return ret; | 419 | return ret; |
| @@ -392,7 +435,7 @@ static int a6xx_rpmh_start(struct a6xx_gmu *gmu) · 15 unmodified lines | |||
| 392 | return ret; | 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 | !val, 100, 10000); | 439 | !val, 100, 10000); |
| 397 | 440 | ||
| 398 | if (ret) { | 441 | if (ret) { |
| @@ -418,7 +461,7 @@ static void a6xx_rpmh_stop(struct a6xx_gmu *gmu) · 19 unmodified lines | |||
| 418 | 461 | ||
| 419 | gmu_write(gmu, REG_A6XX_GMU_RSCC_CONTROL_REQ, 1); | 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 | val, val & (1 << 16), 100, 10000); | 465 | val, val & (1 << 16), 100, 10000); |
| 423 | if (ret) | 466 | if (ret) |
| 424 | DRM_DEV_ERROR(gmu->dev, "Unable to power off the GPU RSC\n"); | 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 | struct platform_device *pdev = to_platform_device(gmu->dev); | 484 | struct platform_device *pdev = to_platform_device(gmu->dev); |
| 442 | void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); | 485 | void __iomem *pdcptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc"); |
| 443 | void __iomem *seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); | 486 | void __iomem *seqptr = a6xx_gmu_get_mmio(pdev, "gmu_pdc_seq"); |
| 487 | uint32_t pdc_address_offset; | ||
| 444 | 488 | ||
| 445 | if (!pdcptr || !seqptr) | 489 | if (!pdcptr || !seqptr) |
| 446 | goto err; | 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 | /* Disable SDE clock gating */ | 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 | /* Setup RSC PDC handshake for sleep and wakeup */ | 502 | /* Setup RSC PDC handshake for sleep and wakeup */ |
| 452 | gmu_write(gmu, REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); | 503 | gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); |
| 453 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); | 504 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); |
| 454 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); | 505 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); |
| 455 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0); | 506 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 2, 0); |
| 456 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0); | 507 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 2, 0); |
| 457 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4, 0x80000000); | 508 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + 4, 0x80000000); |
| 458 | gmu_write(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0); | 509 | gmu_write_rscc(gmu, REG_A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + 4, 0); |
| 459 | gmu_write(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0); | 510 | gmu_write_rscc(gmu, REG_A6XX_RSCC_OVERRIDE_START_ADDR, 0); |
| 460 | gmu_write(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); | 511 | gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); |
| 461 | gmu_write(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); | 512 | gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); |
| 462 | gmu_write(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); | 513 | gmu_write_rscc(gmu, REG_A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); |
| 463 | 514 | ||
| 464 | /* Load RSC sequencer uCode for sleep and wakeup */ | 515 | /* Load RSC sequencer uCode for sleep and wakeup */ |
| 465 | gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xa7a506a0); | 516 | if (adreno_is_a650(adreno_gpu)) { |
| 466 | gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xa1e6a6e7); | 517 | gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0, 0xeaaae5a0); |
| 467 | gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e081e1); | 518 | gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xe1a1ebab); |
| 468 | gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xe9a982e2); | 519 | gmu_write_rscc(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xa2e0a581); |
| 469 | gmu_write(gmu, REG_A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020e8a8); | 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 | /* Load PDC sequencer uCode for power up and power down sequence */ | 530 | /* Load PDC sequencer uCode for power up and power down sequence */ |
| 472 | pdc_write(seqptr, REG_A6XX_PDC_GPU_SEQ_MEM_0, 0xfebea1e1); | 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 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 4, 0x0); | 546 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 4, 0x0); |
| 488 | 547 | ||
| 489 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_MSGID + 8, 0x10108); | 548 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_MSGID + 8, 0x10108); |
| 490 | if (adreno_is_a618(adreno_gpu)) | 549 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_ADDR + 8, pdc_address_offset); |
| 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); | ||
| 494 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 8, 0x0); | 550 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS1_CMD0_DATA + 8, 0x0); |
| 495 | 551 | ||
| 496 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD_ENABLE_BANK, 7); | 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 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 4, 0x10108); | 559 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 4, 0x10108); |
| 504 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 4, 0x30000); | 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 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x2); | 562 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x2); |
| 507 | else | 563 | else |
| 508 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3); | 564 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 4, 0x3); |
| 509 | |||
| 510 | |||
| 511 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 8, 0x10108); | 565 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_MSGID + 8, 0x10108); |
| 512 | if (adreno_is_a618(adreno_gpu)) | 566 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_ADDR + 8, pdc_address_offset); |
| 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); | ||
| 516 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 8, 0x3); | 567 | pdc_write(pdcptr, REG_A6XX_PDC_GPU_TCS3_CMD0_DATA + 8, 0x3); |
| 517 | 568 | ||
| 518 | /* Setup GPU PDC */ | 569 | /* Setup GPU PDC */ |
| @@ -542,6 +593,8 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu) · 23 unmodified lines | |||
| 542 | { | 593 | { |
| 543 | /* Disable GMU WB/RB buffer */ | 594 | /* Disable GMU WB/RB buffer */ |
| 544 | gmu_write(gmu, REG_A6XX_GMU_SYS_BUS_CONFIG, 0x1); | 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 | gmu_write(gmu, REG_A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9c40400); | 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 | A6XX_GMU_RPMH_CTRL_GFX_VOTE_ENABLE); | 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 | static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) | 706 | static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state) |
| 575 | { | 707 | { |
| 576 | static bool rpmh_init; | 708 | static bool rpmh_init; |
| 577 | struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); | 709 | struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); |
| 578 | struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; | 710 | struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; |
| 579 | int i, ret; | 711 | int ret; |
| 580 | u32 chipid; | 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 | if (state == GMU_WARM_BOOT) { | 717 | if (state == GMU_WARM_BOOT) { |
| 584 | ret = a6xx_rpmh_start(gmu); | 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 | "GMU firmware is not loaded\n")) | 723 | "GMU firmware is not loaded\n")) |
| 590 | return -ENOENT; | 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 | /* Turn on register retention */ | 726 | /* Turn on register retention */ |
| 600 | gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1); | 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 | return ret; | 736 | return ret; |
| 610 | } | 737 | } |
| 611 | 738 | ||
| 612 | image = (u32 *) adreno_gpu->fw[ADRENO_FW_GMU]->data; | 739 | ret = a6xx_gmu_fw_load(gmu); |
| 613 | 740 | if (ret) | |
| 614 | for (i = 0; i < adreno_gpu->fw[ADRENO_FW_GMU]->size >> 2; i++) | 741 | return ret; |
| 615 | gmu_write(gmu, REG_A6XX_GMU_CM3_ITCM_START + i, | ||
| 616 | image[i]); | ||
| 617 | } | 742 | } |
| 618 | 743 | ||
| 619 | gmu_write(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, 0); | 744 | gmu_write(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, 0); |
| 620 | gmu_write(gmu, REG_A6XX_GMU_CM3_BOOT_CONFIG, 0x02); | 745 | gmu_write(gmu, REG_A6XX_GMU_CM3_BOOT_CONFIG, 0x02); |
| 621 | 746 | ||
| 622 | /* Write the iova of the HFI table */ | 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 | gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_INFO, 1); | 749 | gmu_write(gmu, REG_A6XX_GMU_HFI_QTBL_INFO, 1); |
| 625 | 750 | ||
| 626 | gmu_write(gmu, REG_A6XX_GMU_AHB_FENCE_RANGE_0, | 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 | gmu_write(gmu, REG_A6XX_GMU_HFI_SFR_ADDR, chipid); | 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 | /* Set up the lowest idle level on the GMU */ | 764 | /* Set up the lowest idle level on the GMU */ |
| 637 | a6xx_gmu_power_config(gmu); | 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 | if (ret) | 768 | if (ret) |
| 641 | return ret; | 769 | return ret; |
| 642 | 770 | ||
| 643 | ret = a6xx_gmu_gfx_rail_on(gmu); | 771 | if (gmu->legacy) { |
| 644 | if (ret) | 772 | ret = a6xx_gmu_gfx_rail_on(gmu); |
| 645 | return ret; | 773 | if (ret) |
| 774 | return ret; | ||
| 775 | } | ||
| 646 | 776 | ||
| 647 | /* Enable SPTP_PC if the CPU is responsible for it */ | 777 | /* Enable SPTP_PC if the CPU is responsible for it */ |
| 648 | if (gmu->idle_level < GMU_IDLE_STATE_SPTP) { | 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 | u32 val; | 813 | u32 val; |
| 684 | 814 | ||
| 685 | /* Make sure there are no outstanding RPMh votes */ | 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 | (val & 1), 100, 10000); | 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 | (val & 1), 100, 10000); | 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 | (val & 1), 100, 10000); | 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 | (val & 1), 100, 1000); | 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 | status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ? | 874 | status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ? |
| 745 | GMU_WARM_BOOT : GMU_COLD_BOOT; | 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 | ret = a6xx_gmu_fw_start(gmu, status); | 884 | ret = a6xx_gmu_fw_start(gmu, status); |
| 748 | if (ret) | 885 | if (ret) |
| 749 | goto out; | 886 | goto out; |
| @@ -761,7 +898,10 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) · 11 unmodified lines | |||
| 761 | enable_irq(gmu->hfi_irq); | 898 | enable_irq(gmu->hfi_irq); |
| 762 | 899 | ||
| 763 | /* Set the GPU to the current freq */ | 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 | * "enable" the GX power domain which won't actually do anything but it | 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 | return 0; | 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)) | 1064 | msm_gem_kernel_put(gmu->hfi.obj, gmu->aspace, false); |
| 925 | return; | 1065 | msm_gem_kernel_put(gmu->debug.obj, gmu->aspace, false); |
| 926 | 1066 | msm_gem_kernel_put(gmu->icache.obj, gmu->aspace, false); | |
| 927 | dma_free_wc(gmu->dev, bo->size, bo->virt, bo->iova); | 1067 | msm_gem_kernel_put(gmu->dcache.obj, gmu->aspace, false); |
| 928 | kfree(bo); | 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, | 1075 | static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, |
| 932 | size_t size) | 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); | 1084 | size = PAGE_ALIGN(size); |
| 937 | if (!bo) | 1085 | if (!iova) { |
| 938 | return ERR_PTR(-ENOMEM); | 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) { | 1119 | domain = iommu_domain_alloc(&platform_bus_type); |
| 945 | kfree(bo); | 1120 | if (!domain) |
| 946 | return ERR_PTR(-ENOMEM); | 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 | /* Return the 'arc-level' for the given frequency */ | 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 | if (j == pri_count) { | 1193 | if (j == pri_count) { |
| 1013 | DRM_DEV_ERROR(dev, | 1194 | DRM_DEV_ERROR(dev, |
| 1014 | "Level %u not found in in the RPMh list\n", | 1195 | "Level %u not found in the RPMh list\n", |
| 1015 | level); | 1196 | level); |
| 1016 | DRM_DEV_ERROR(dev, "Available levels:\n"); | 1197 | DRM_DEV_ERROR(dev, "Available levels:\n"); |
| 1017 | for (j = 0; j < pri_count; j++) | 1198 | for (j = 0; j < pri_count; j++) |
| 1018 | DRM_DEV_ERROR(dev, " %u\n", pri[j]); | 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 | void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) | 1371 | void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) |
| 1191 | { | 1372 | { |
| 1192 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; | 1373 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; |
| 1374 | struct platform_device *pdev = to_platform_device(gmu->dev); | ||
| 1193 | 1375 | ||
| 1194 | if (!gmu->initialized) | 1376 | if (!gmu->initialized) |
| 1195 | return; | 1377 | return; |
| @@ -1202,9 +1384,12 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) · 6 unmodified lines | |||
| 1202 | } | 1384 | } |
| 1203 | 1385 | ||
| 1204 | iounmap(gmu->mmio); | 1386 | iounmap(gmu->mmio); |
| 1387 | if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) | ||
| 1388 | iounmap(gmu->rscc); | ||
| 1205 | gmu->mmio = NULL; | 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 | free_irq(gmu->gmu_irq, gmu); | 1394 | free_irq(gmu->gmu_irq, gmu); |
| 1210 | free_irq(gmu->hfi_irq, gmu); | 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 | int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) | 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 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; | 1406 | struct a6xx_gmu *gmu = &a6xx_gpu->gmu; |
| 1221 | struct platform_device *pdev = of_find_device_by_node(node); | 1407 | struct platform_device *pdev = of_find_device_by_node(node); |
| 1222 | int ret; | 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 | gmu->dev = &pdev->dev; | 1413 | gmu->dev = &pdev->dev; |
| 1228 | 1414 | ||
| 1229 | /* Pass force_dma false to require the DT to set the dma region */ | 1415 | of_dma_configure(gmu->dev, node, true); |
| 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; | ||
| 1238 | 1416 | ||
| 1239 | /* Fow now, don't do anything fancy until we get our feet under us */ | 1417 | /* Fow now, don't do anything fancy until we get our feet under us */ |
| 1240 | gmu->idle_level = GMU_IDLE_STATE_ACTIVE; | 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 | if (ret) | 1424 | if (ret) |
| 1247 | goto err_put_device; | 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 | /* Allocate memory for for the HFI queues */ | 1461 | /* Allocate memory for for the HFI queues */ |
| 1250 | gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K); | 1462 | ret = a6xx_gmu_memory_alloc(gmu, &gmu->hfi, SZ_16K, 0); |
| 1251 | if (IS_ERR(gmu->hfi)) | 1463 | if (ret) |
| 1252 | goto err_memory; | 1464 | goto err_memory; |
| 1253 | 1465 | ||
| 1254 | /* Allocate memory for the GMU debug region */ | 1466 | /* Allocate memory for the GMU log region */ |
| 1255 | gmu->debug = a6xx_gmu_memory_alloc(gmu, SZ_16K); | 1467 | ret = a6xx_gmu_memory_alloc(gmu, &gmu->log, SZ_4K, 0); |
| 1256 | if (IS_ERR(gmu->debug)) | 1468 | if (ret) |
| 1257 | goto err_memory; | 1469 | goto err_memory; |
| 1258 | 1470 | ||
| 1259 | /* Map the GMU registers */ | 1471 | /* Map the GMU registers */ |
| 1260 | gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu"); | 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 | goto err_memory; | 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 | /* Get the HFI and GMU interrupts */ | 1486 | /* Get the HFI and GMU interrupts */ |
| 1265 | gmu->hfi_irq = a6xx_gmu_get_irq(gmu, pdev, "hfi", a6xx_hfi_irq); | 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 | err_mmio: | 1509 | err_mmio: |
| 1288 | iounmap(gmu->mmio); | 1510 | iounmap(gmu->mmio); |
| 1511 | if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "rscc")) | ||
| 1512 | iounmap(gmu->rscc); | ||
| 1289 | free_irq(gmu->gmu_irq, gmu); | 1513 | free_irq(gmu->gmu_irq, gmu); |
| 1290 | free_irq(gmu->hfi_irq, gmu); | 1514 | free_irq(gmu->hfi_irq, gmu); |
| 1291 | err_memory: | ||
| 1292 | a6xx_gmu_memory_free(gmu, gmu->hfi); | ||
| 1293 | 1515 | ||
| 1294 | ret = -ENODEV; | 1516 | ret = -ENODEV; |
| 1295 | 1517 | ||
| 1518 | err_memory: | ||
| 1519 | a6xx_gmu_memory_free(gmu); | ||
| 1296 | err_put_device: | 1520 | err_put_device: |
| 1297 | /* Drop reference taken in of_find_device_by_node */ | 1521 | /* Drop reference taken in of_find_device_by_node */ |
| 1298 | put_device(gmu->dev); | 1522 | put_device(gmu->dev); |
| @@ -10,9 +10,10 @@ · 9 unmodified lines | |||
| 10 | #include "a6xx_hfi.h" | 10 | #include "a6xx_hfi.h" |
| 11 | 11 | ||
| 12 | struct a6xx_gmu_bo { | 12 | struct a6xx_gmu_bo { |
| 13 | struct drm_gem_object *obj; | ||
| 13 | void *virt; | 14 | void *virt; |
| 14 | size_t size; | 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 | struct a6xx_gmu { | 44 | struct a6xx_gmu { |
| 44 | struct device *dev; | 45 | struct device *dev; |
| 45 | 46 | ||
| 47 | struct msm_gem_address_space *aspace; | ||
| 48 | |||
| 46 | void * __iomem mmio; | 49 | void * __iomem mmio; |
| 50 | void * __iomem rscc; | ||
| 47 | 51 | ||
| 48 | int hfi_irq; | 52 | int hfi_irq; |
| 49 | int gmu_irq; | 53 | int gmu_irq; |
| @@ -52,8 +56,12 @@ struct a6xx_gmu { · 2 unmodified lines | |||
| 52 | 56 | ||
| 53 | int idle_level; | 57 | int idle_level; |
| 54 | 58 | ||
| 55 | struct a6xx_gmu_bo *hfi; | 59 | struct a6xx_gmu_bo hfi; |
| 56 | struct a6xx_gmu_bo *debug; | 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 | int nr_clocks; | 66 | int nr_clocks; |
| 59 | struct clk_bulk_data *clocks; | 67 | struct clk_bulk_data *clocks; |
| @@ -76,6 +84,7 @@ struct a6xx_gmu { · 16 unmodified lines | |||
| 76 | 84 | ||
| 77 | bool initialized; | 85 | bool initialized; |
| 78 | bool hung; | 86 | bool hung; |
| 87 | bool legacy; /* a618 or a630 */ | ||
| 79 | }; | 88 | }; |
| 80 | 89 | ||
| 81 | static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset) | 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 | return msm_writel(value, gmu->mmio + (offset << 2)); | 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 | static inline void gmu_rmw(struct a6xx_gmu *gmu, u32 reg, u32 mask, u32 or) | 107 | static inline void gmu_rmw(struct a6xx_gmu *gmu, u32 reg, u32 mask, u32 or) |
| 92 | { | 108 | { |
| 93 | u32 val = gmu_read(gmu, reg); | 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 | readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \ | 127 | readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \ |
| 112 | interval, timeout) | 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 | * These are the available OOB (out of band requests) to the GMU where "out of | 140 | * These are the available OOB (out of band requests) to the GMU where "out of |
| 116 | * band" means that the CPU talks to the GMU directly and not through HFI. | 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 | #define GMU_OOB_GPU_SET_ACK 24 | 181 | #define GMU_OOB_GPU_SET_ACK 24 |
| 157 | #define GMU_OOB_GPU_SET_CLEAR 24 | 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 | void a6xx_hfi_init(struct a6xx_gmu *gmu); | 189 | void a6xx_hfi_init(struct a6xx_gmu *gmu); |
| 161 | int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state); | 190 | int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state); |
| 162 | void a6xx_hfi_stop(struct a6xx_gmu *gmu); | 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 | bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu); | 195 | bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu); |
| 165 | bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu); | 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 | #define REG_A6XX_GMU_DCVS_RETURN 0x000023ff | 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 | #define REG_A6XX_GMU_SYS_BUS_CONFIG 0x00004c0f | 108 | #define REG_A6XX_GMU_SYS_BUS_CONFIG 0x00004c0f |
| 105 | 109 | ||
| 106 | #define REG_A6XX_GMU_CM3_SYSRESET 0x00005000 | 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 | #define REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE 0x000050ec | 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 | #define REG_A6XX_GMU_BOOT_KMD_LM_HANDSHAKE 0x000051f0 | 212 | #define REG_A6XX_GMU_BOOT_KMD_LM_HANDSHAKE 0x000051f0 |
| 203 | 213 | ||
| 204 | #define REG_A6XX_GMU_LLM_GLM_SLEEP_CTRL 0x00005157 | 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 | #define REG_A6XX_GMU_AO_SPARE_CNTL 0x00009316 | 341 | #define REG_A6XX_GMU_AO_SPARE_CNTL 0x00009316 |
| 332 | 342 | ||
| 333 | #define REG_A6XX_GPU_RSCC_RSC_STATUS0_DRV0 0x00008c04 | ||
| 334 | |||
| 335 | #define REG_A6XX_GMU_RSCC_CONTROL_REQ 0x00009307 | 343 | #define REG_A6XX_GMU_RSCC_CONTROL_REQ 0x00009307 |
| 336 | 344 | ||
| 337 | #define REG_A6XX_GMU_RSCC_CONTROL_ACK 0x00009308 | 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 | #define REG_A6XX_GPU_CC_GX_DOMAIN_MISC 0x00009d42 | 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 | #endif /* A6XX_GMU_XML */ | 392 | #endif /* A6XX_GMU_XML */ |
| @@ -414,7 +414,17 @@ static int a6xx_hw_init(struct msm_gpu *gpu) · 413 unmodified lines | |||
| 414 | a6xx_set_hwcg(gpu, true); | 414 | a6xx_set_hwcg(gpu, true); |
| 415 | 415 | ||
| 416 | /* VBIF/GBIF start*/ | 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 | if (adreno_is_a630(adreno_gpu)) | 428 | if (adreno_is_a630(adreno_gpu)) |
| 419 | gpu_write(gpu, REG_A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); | 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 | gpu_write(gpu, REG_A6XX_UCHE_WRITE_THRU_BASE_LO, 0xfffff000); | 439 | gpu_write(gpu, REG_A6XX_UCHE_WRITE_THRU_BASE_LO, 0xfffff000); |
| 430 | gpu_write(gpu, REG_A6XX_UCHE_WRITE_THRU_BASE_HI, 0x0001ffff); | 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] */ | 442 | if (!adreno_is_a650(adreno_gpu)) { |
| 433 | gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MIN_LO, | 443 | /* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */ |
| 434 | REG_A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000); | 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, | 447 | gpu_write64(gpu, REG_A6XX_UCHE_GMEM_RANGE_MAX_LO, |
| 437 | REG_A6XX_UCHE_GMEM_RANGE_MAX_HI, | 448 | REG_A6XX_UCHE_GMEM_RANGE_MAX_HI, |
| 438 | 0x00100000 + adreno_gpu->gmem - 1); | 449 | 0x00100000 + adreno_gpu->gmem - 1); |
| 450 | } | ||
| 439 | 451 | ||
| 440 | gpu_write(gpu, REG_A6XX_UCHE_FILTER_CNTL, 0x804); | 452 | gpu_write(gpu, REG_A6XX_UCHE_FILTER_CNTL, 0x804); |
| 441 | gpu_write(gpu, REG_A6XX_UCHE_CACHE_WAYS, 0x4); | 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 | gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_1, 0x8040362c); | 459 | gpu_write(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_1, 0x8040362c); |
| 445 | 460 | ||
| 446 | /* Setting the mem pool size */ | 461 | /* Setting the mem pool size */ |
| 447 | gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 128); | 462 | gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 128); |
| 448 | 463 | ||
| 449 | /* Setting the primFifo thresholds default values */ | 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 | /* Set the AHB default slave response to "ERROR" */ | 472 | /* Set the AHB default slave response to "ERROR" */ |
| 453 | gpu_write(gpu, REG_A6XX_CP_AHB_CNTL, 0x1); | 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 | gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, 1); | 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 | /* Protect registers from the CP */ | 507 | /* Protect registers from the CP */ |
| 475 | gpu_write(gpu, REG_A6XX_CP_PROTECT_CNTL, 0x00000003); | 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 | A6XX_PROTECT_RDONLY(0x980, 0x4)); | 541 | A6XX_PROTECT_RDONLY(0x980, 0x4)); |
| 509 | gpu_write(gpu, REG_A6XX_CP_PROTECT(25), A6XX_PROTECT_RW(0xa630, 0x0)); | 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 | /* Enable interrupts */ | 549 | /* Enable interrupts */ |
| 512 | gpu_write(gpu, REG_A6XX_RBBM_INT_0_MASK, A6XX_INT_MASK); | 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 | a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); | 605 | a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); |
| 568 | 606 | ||
| 569 | /* Take the GMU out of its special boot mode */ | 607 | if (a6xx_gpu->gmu.legacy) { |
| 570 | a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER); | 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 | return ret; | 612 | return ret; |
| 573 | } | 613 | } |
| @@ -810,6 +850,11 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) · 236 unmodified lines | |||
| 810 | struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); | 850 | struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); |
| 811 | u64 busy_cycles, busy_time; | 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 | busy_cycles = gmu_read64(&a6xx_gpu->gmu, | 858 | busy_cycles = gmu_read64(&a6xx_gpu->gmu, |
| 814 | REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, | 859 | REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, |
| 815 | REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H); | 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 | gpu->devfreq.busy_cycles = busy_cycles; | 865 | gpu->devfreq.busy_cycles = busy_cycles; |
| 821 | 866 | ||
| 867 | pm_runtime_put(a6xx_gpu->gmu.dev); | ||
| 868 | |||
| 822 | if (WARN_ON(busy_time > ~0LU)) | 869 | if (WARN_ON(busy_time > ~0LU)) |
| 823 | return ~0LU; | 870 | return ~0LU; |
| 824 | 871 | ||
| @@ -846,6 +893,7 @@ static const struct adreno_gpu_funcs funcs = { · 21 unmodified lines | |||
| 846 | #if defined(CONFIG_DRM_MSM_GPU_STATE) | 893 | #if defined(CONFIG_DRM_MSM_GPU_STATE) |
| 847 | .gpu_state_get = a6xx_gpu_state_get, | 894 | .gpu_state_get = a6xx_gpu_state_get, |
| 848 | .gpu_state_put = a6xx_gpu_state_put, | 895 | .gpu_state_put = a6xx_gpu_state_put, |
| 896 | .create_address_space = adreno_iommu_create_address_space, | ||
| 849 | #endif | 897 | #endif |
| 850 | }, | 898 | }, |
| 851 | .get_timestamp = a6xx_get_timestamp, | 899 | .get_timestamp = a6xx_get_timestamp, |
| @@ -17,10 +17,14 @@ static const char * const a6xx_hfi_msg_id[] = { · 16 unmodified lines | |||
| 17 | HFI_MSG_ID(HFI_H2F_MSG_BW_TABLE), | 17 | HFI_MSG_ID(HFI_H2F_MSG_BW_TABLE), |
| 18 | HFI_MSG_ID(HFI_H2F_MSG_PERF_TABLE), | 18 | HFI_MSG_ID(HFI_H2F_MSG_PERF_TABLE), |
| 19 | HFI_MSG_ID(HFI_H2F_MSG_TEST), | 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, | 26 | static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, |
| 23 | u32 dwords) | 27 | struct a6xx_hfi_queue *queue, u32 *data, u32 dwords) |
| 24 | { | 28 | { |
| 25 | struct a6xx_hfi_queue_header *header = queue->header; | 29 | struct a6xx_hfi_queue_header *header = queue->header; |
| 26 | u32 i, hdr, index = header->read_index; | 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 | index = (index + 1) % header->size; | 52 | index = (index + 1) % header->size; |
| 49 | } | 53 | } |
| 50 | 54 | ||
| 55 | if (!gmu->legacy) | ||
| 56 | index = ALIGN(index, 4) % header->size; | ||
| 57 | |||
| 51 | header->read_index = index; | 58 | header->read_index = index; |
| 52 | return HFI_HEADER_SIZE(hdr); | 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 | index = (index + 1) % header->size; | 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 | header->write_index = index; | 89 | header->write_index = index; |
| 77 | spin_unlock(&queue->lock); | 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 | struct a6xx_hfi_msg_response resp; | 119 | struct a6xx_hfi_msg_response resp; |
| 107 | 120 | ||
| 108 | /* Get the next packet */ | 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 | sizeof(resp) >> 2); | 123 | sizeof(resp) >> 2); |
| 111 | 124 | ||
| 112 | /* If the queue is empty our response never made it */ | 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 | struct a6xx_hfi_msg_gmu_init_cmd msg = { 0 }; | 190 | struct a6xx_hfi_msg_gmu_init_cmd msg = { 0 }; |
| 178 | 191 | ||
| 179 | msg.dbg_buffer_addr = (u32) gmu->debug->iova; | 192 | msg.dbg_buffer_addr = (u32) gmu->debug.iova; |
| 180 | msg.dbg_buffer_size = (u32) gmu->debug->size; | 193 | msg.dbg_buffer_size = (u32) gmu->debug.size; |
| 181 | msg.boot_state = boot_state; | 194 | msg.boot_state = boot_state; |
| 182 | 195 | ||
| 183 | return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_INIT, &msg, sizeof(msg), | 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 | version, sizeof(*version)); | 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 | static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu) | 233 | static int a6xx_hfi_send_perf_table(struct a6xx_gmu *gmu) |
| 199 | { | 234 | { |
| 200 | struct a6xx_hfi_msg_perf_table msg = { 0 }; | 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 | for (i = 0; i < gmu->nr_gpu_freqs; i++) { | 241 | for (i = 0; i < gmu->nr_gpu_freqs; i++) { |
| 207 | msg.gx_votes[i].vote = gmu->gx_arc_votes[i]; | 242 | msg.gx_votes[i].vote = gmu->gx_arc_votes[i]; |
| 243 | msg.gx_votes[i].acd = 0xffffffff; | ||
| 208 | msg.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; | 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 | NULL, 0); | 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 | int ret; | 385 | int ret; |
| 312 | 386 | ||
| @@ -324,7 +398,7 @@ int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) · 11 unmodified lines | |||
| 324 | * the GMU firmware | 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 | if (ret) | 402 | if (ret) |
| 329 | return ret; | 403 | return ret; |
| 330 | 404 | ||
| @@ -341,6 +415,37 @@ int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state) · 10 unmodified lines | |||
| 341 | return 0; | 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 | void a6xx_hfi_stop(struct a6xx_gmu *gmu) | 449 | void a6xx_hfi_stop(struct a6xx_gmu *gmu) |
| 345 | { | 450 | { |
| 346 | int i; | 451 | int i; |
| @@ -385,7 +490,7 @@ static void a6xx_hfi_queue_init(struct a6xx_hfi_queue *queue, · 38 unmodified lines | |||
| 385 | 490 | ||
| 386 | void a6xx_hfi_init(struct a6xx_gmu *gmu) | 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 | struct a6xx_hfi_queue_table_header *table = hfi->virt; | 494 | struct a6xx_hfi_queue_table_header *table = hfi->virt; |
| 390 | struct a6xx_hfi_queue_header *headers = hfi->virt + sizeof(*table); | 495 | struct a6xx_hfi_queue_header *headers = hfi->virt + sizeof(*table); |
| 391 | u64 offset; | 496 | u64 offset; |
| @@ -415,5 +520,5 @@ void a6xx_hfi_init(struct a6xx_gmu *gmu) · 23 unmodified lines | |||
| 415 | /* GMU response queue */ | 520 | /* GMU response queue */ |
| 416 | offset += SZ_4K; | 521 | offset += SZ_4K; |
| 417 | a6xx_hfi_queue_init(&gmu->queues[1], &headers[1], hfi->virt + offset, | 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 | /* HFI message types */ | 51 | /* HFI message types */ |
| 52 | 52 | ||
| 53 | #define HFI_MSG_CMD 0 | 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 | #define HFI_F2H_MSG_ACK 126 | 57 | #define HFI_F2H_MSG_ACK 126 |
| 57 | 58 | ||
| @@ -94,7 +95,13 @@ struct perf_level { · 36 unmodified lines | |||
| 94 | u32 freq; | 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 | u32 header; | 105 | u32 header; |
| 99 | u32 num_gpu_levels; | 106 | u32 num_gpu_levels; |
| 100 | u32 num_gmu_levels; | 107 | u32 num_gmu_levels; |
| @@ -103,6 +110,15 @@ struct a6xx_hfi_msg_perf_table { · 2 unmodified lines | |||
| 103 | struct perf_level cx_votes[4]; | 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 | #define HFI_H2F_MSG_BW_TABLE 3 | 122 | #define HFI_H2F_MSG_BW_TABLE 3 |
| 107 | 123 | ||
| 108 | struct a6xx_hfi_msg_bw_table { | 124 | struct a6xx_hfi_msg_bw_table { |
| @@ -124,4 +140,34 @@ struct a6xx_hfi_msg_test { · 15 unmodified lines | |||
| 124 | u32 header; | 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 | #endif | 173 | #endif |
| @@ -92,6 +92,17 @@ static const struct adreno_info gpulist[] = { · 91 unmodified lines | |||
| 92 | .gmem = SZ_1M, | 92 | .gmem = SZ_1M, |
| 93 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, | 93 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, |
| 94 | .init = a3xx_gpu_init, | 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 | .rev = ADRENO_REV(4, 2, 0, ANY_ID), | 107 | .rev = ADRENO_REV(4, 2, 0, ANY_ID), |
| 97 | .revn = 420, | 108 | .revn = 420, |
| @@ -189,6 +200,30 @@ static const struct adreno_info gpulist[] = { · 91 unmodified lines | |||
| 189 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, | 200 | .inactive_period = DRM_MSM_INACTIVE_PERIOD, |
| 190 | .init = a6xx_gpu_init, | 201 | .init = a6xx_gpu_init, |
| 191 | .zapfw = "a630_zap.mdt", | 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 | return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); | 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 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) | 205 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) |
| 189 | { | 206 | { |
| 190 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | 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 | *value = adreno_gpu->gmem; | 214 | *value = adreno_gpu->gmem; |
| 198 | return 0; | 215 | return 0; |
| 199 | case MSM_PARAM_GMEM_BASE: | 216 | case MSM_PARAM_GMEM_BASE: |
| 200 | *value = 0x100000; | 217 | *value = !adreno_is_a650(adreno_gpu) ? 0x100000 : 0; |
| 201 | return 0; | 218 | return 0; |
| 202 | case MSM_PARAM_CHIP_ID: | 219 | case MSM_PARAM_CHIP_ID: |
| 203 | *value = adreno_gpu->rev.patchid | | 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 | break; | 476 | break; |
| 460 | /* fall-thru */ | 477 | /* fall-thru */ |
| 461 | case MSM_SUBMIT_CMD_BUF: | 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 | CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); | 480 | CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); |
| 464 | OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); | 481 | OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); |
| 465 | OUT_RING(ring, submit->cmd[i].size); | 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 | adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; | 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 | adreno_gpu_config.nr_rings = nr_rings; | 1008 | adreno_gpu_config.nr_rings = nr_rings; |
| 998 | 1009 | ||
| 999 | adreno_get_pwrlevels(&pdev->dev, gpu); | 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 | return (gpu->revn >= 400) && (gpu->revn < 500); | 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 | static inline int adreno_is_a420(struct adreno_gpu *gpu) | 210 | static inline int adreno_is_a420(struct adreno_gpu *gpu) |
| 206 | { | 211 | { |
| 207 | return gpu->revn == 420; | 212 | return gpu->revn == 420; |
| @@ -237,6 +242,16 @@ static inline int adreno_is_a630(struct adreno_gpu *gpu) · 29 unmodified lines | |||
| 237 | return gpu->revn == 630; | 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 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); | 255 | int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); |
| 241 | const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, | 256 | const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, |
| 242 | const char *fwname); | 257 | const char *fwname); |
| @@ -272,6 +287,14 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state); · 29 unmodified lines | |||
| 272 | int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); | 287 | int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); |
| 273 | int adreno_gpu_state_put(struct msm_gpu_state *state); | 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 | * For a5xx and a6xx targets load the zap shader that is used to pull the GPU | 299 | * For a5xx and a6xx targets load the zap shader that is used to pull the GPU |
| 277 | * out of secure mode | 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 | return to_dpu_kms(priv->kms); | 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 | static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, | 39 | static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, |
| 56 | struct drm_crtc *crtc, | 40 | struct drm_crtc *crtc, |
| 57 | struct drm_crtc_state *state, | 41 | struct drm_crtc_state *state, |
| @@ -94,7 +78,6 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, · 36 unmodified lines | |||
| 94 | u32 bw, threshold; | 78 | u32 bw, threshold; |
| 95 | u64 bw_sum_of_intfs = 0; | 79 | u64 bw_sum_of_intfs = 0; |
| 96 | enum dpu_crtc_client_type curr_client_type; | 80 | enum dpu_crtc_client_type curr_client_type; |
| 97 | bool is_video_mode; | ||
| 98 | struct dpu_crtc_state *dpu_cstate; | 81 | struct dpu_crtc_state *dpu_cstate; |
| 99 | struct drm_crtc *tmp_crtc; | 82 | struct drm_crtc *tmp_crtc; |
| 100 | struct dpu_kms *kms; | 83 | struct dpu_kms *kms; |
| @@ -144,11 +127,7 @@ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, · 43 unmodified lines | |||
| 144 | bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); | 127 | bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); |
| 145 | DPU_DEBUG("calculated bandwidth=%uk\n", bw); | 128 | DPU_DEBUG("calculated bandwidth=%uk\n", bw); |
| 146 | 129 | ||
| 147 | is_video_mode = dpu_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO; | 130 | threshold = kms->catalog->perf.max_bw_high; |
| 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; | ||
| 152 | 131 | ||
| 153 | DPU_DEBUG("final threshold bw limit = %d\n", threshold); | 132 | DPU_DEBUG("final threshold bw limit = %d\n", threshold); |
| 154 | 133 | ||
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/sort.h> | 9 | #include <linux/sort.h> |
| 10 | #include <linux/debugfs.h> | 10 | #include <linux/debugfs.h> |
| 11 | #include <linux/ktime.h> | 11 | #include <linux/ktime.h> |
| 12 | #include <linux/bits.h> | ||
| 12 | 13 | ||
| 13 | #include <drm/drm_crtc.h> | 14 | #include <drm/drm_crtc.h> |
| 14 | #include <drm/drm_flip_work.h> | 15 | #include <drm/drm_flip_work.h> |
| @@ -20,6 +21,7 @@ · 5 unmodified lines | |||
| 20 | #include "dpu_kms.h" | 21 | #include "dpu_kms.h" |
| 21 | #include "dpu_hw_lm.h" | 22 | #include "dpu_hw_lm.h" |
| 22 | #include "dpu_hw_ctl.h" | 23 | #include "dpu_hw_ctl.h" |
| 24 | #include "dpu_hw_dspp.h" | ||
| 23 | #include "dpu_crtc.h" | 25 | #include "dpu_crtc.h" |
| 24 | #include "dpu_plane.h" | 26 | #include "dpu_plane.h" |
| 25 | #include "dpu_encoder.h" | 27 | #include "dpu_encoder.h" |
| @@ -40,6 +42,9 @@ · 14 unmodified lines | |||
| 40 | /* timeout in ms waiting for frame done */ | 42 | /* timeout in ms waiting for frame done */ |
| 41 | #define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 | 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 | static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) | 48 | static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
| 44 | { | 49 | { |
| 45 | struct msm_drm_private *priv = crtc->dev->dev_private; | 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 | static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) | 94 | static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) |
| 90 | { | 95 | { |
| 91 | struct dpu_crtc *dpu_crtc; | ||
| 92 | struct dpu_crtc_state *crtc_state; | 96 | struct dpu_crtc_state *crtc_state; |
| 93 | int lm_idx, lm_horiz_position; | 97 | int lm_idx, lm_horiz_position; |
| 94 | 98 | ||
| 95 | dpu_crtc = to_dpu_crtc(crtc); | ||
| 96 | crtc_state = to_dpu_crtc_state(crtc->state); | 99 | crtc_state = to_dpu_crtc_state(crtc->state); |
| 97 | 100 | ||
| 98 | lm_horiz_position = 0; | 101 | lm_horiz_position = 0; |
| @@ -422,6 +425,74 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, · 323 unmodified lines | |||
| 422 | drm_mode_debug_printmodeline(adj_mode); | 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 | static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, | 496 | static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, |
| 426 | struct drm_crtc_state *old_state) | 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 | struct drm_encoder *encoder; | 501 | struct drm_encoder *encoder; |
| 431 | struct drm_device *dev; | 502 | struct drm_device *dev; |
| 432 | unsigned long flags; | 503 | unsigned long flags; |
| 433 | struct dpu_crtc_smmu_state_data *smmu_state; | ||
| 434 | 504 | ||
| 435 | if (!crtc) { | 505 | if (!crtc) { |
| 436 | DPU_ERROR("invalid crtc\n"); | 506 | DPU_ERROR("invalid crtc\n"); |
| @@ -448,7 +518,6 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, · 11 unmodified lines | |||
| 448 | dpu_crtc = to_dpu_crtc(crtc); | 518 | dpu_crtc = to_dpu_crtc(crtc); |
| 449 | cstate = to_dpu_crtc_state(crtc->state); | 519 | cstate = to_dpu_crtc_state(crtc->state); |
| 450 | dev = crtc->dev; | 520 | dev = crtc->dev; |
| 451 | smmu_state = &dpu_crtc->smmu_state; | ||
| 452 | 521 | ||
| 453 | _dpu_crtc_setup_lm_bounds(crtc, crtc->state); | 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 | _dpu_crtc_blend_setup(crtc); | 545 | _dpu_crtc_blend_setup(crtc); |
| 477 | 546 | ||
| 547 | _dpu_crtc_setup_cp_blocks(crtc); | ||
| 548 | |||
| 478 | /* | 549 | /* |
| 479 | * PP_DONE irq is only used by command mode for now. | 550 | * PP_DONE irq is only used by command mode for now. |
| 480 | * It is better to request pending before FLUSH and START trigger | 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 | struct drm_device *dev; | 562 | struct drm_device *dev; |
| 492 | struct drm_plane *plane; | 563 | struct drm_plane *plane; |
| 493 | struct msm_drm_private *priv; | 564 | struct msm_drm_private *priv; |
| 494 | struct msm_drm_thread *event_thread; | ||
| 495 | unsigned long flags; | 565 | unsigned long flags; |
| 496 | struct dpu_crtc_state *cstate; | 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 | return; | 583 | return; |
| 514 | } | 584 | } |
| 515 | 585 | ||
| 516 | event_thread = &priv->event_thread[crtc->index]; | ||
| 517 | |||
| 518 | if (dpu_crtc->event) { | 586 | if (dpu_crtc->event) { |
| 519 | DPU_DEBUG("already received dpu_crtc->event\n"); | 587 | DPU_DEBUG("already received dpu_crtc->event\n"); |
| 520 | } else { | 588 | } else { |
| @@ -567,7 +635,6 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, · 46 unmodified lines | |||
| 567 | static void dpu_crtc_destroy_state(struct drm_crtc *crtc, | 635 | static void dpu_crtc_destroy_state(struct drm_crtc *crtc, |
| 568 | struct drm_crtc_state *state) | 636 | struct drm_crtc_state *state) |
| 569 | { | 637 | { |
| 570 | struct dpu_crtc *dpu_crtc; | ||
| 571 | struct dpu_crtc_state *cstate; | 638 | struct dpu_crtc_state *cstate; |
| 572 | 639 | ||
| 573 | if (!crtc || !state) { | 640 | if (!crtc || !state) { |
| @@ -575,7 +642,6 @@ static void dpu_crtc_destroy_state(struct drm_crtc *crtc, · 1 unmodified line | |||
| 575 | return; | 642 | return; |
| 576 | } | 643 | } |
| 577 | 644 | ||
| 578 | dpu_crtc = to_dpu_crtc(crtc); | ||
| 579 | cstate = to_dpu_crtc_state(state); | 645 | cstate = to_dpu_crtc_state(state); |
| 580 | 646 | ||
| 581 | DPU_DEBUG("crtc%d\n", crtc->base.id); | 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 | * dpu_crtc_duplicate_state - state duplicate hook | 729 | * dpu_crtc_duplicate_state - state duplicate hook |
| 664 | * @crtc: Pointer to drm crtc structure | 730 | * @crtc: Pointer to drm crtc structure |
| 665 | * @Returns: Pointer to new drm_crtc_state structure | ||
| 666 | */ | 731 | */ |
| 667 | static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) | 732 | static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) |
| 668 | { | 733 | { |
| 669 | struct dpu_crtc *dpu_crtc; | ||
| 670 | struct dpu_crtc_state *cstate, *old_cstate; | 734 | struct dpu_crtc_state *cstate, *old_cstate; |
| 671 | 735 | ||
| 672 | if (!crtc || !crtc->state) { | 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 | return NULL; | 738 | return NULL; |
| 675 | } | 739 | } |
| 676 | 740 | ||
| 677 | dpu_crtc = to_dpu_crtc(crtc); | ||
| 678 | old_cstate = to_dpu_crtc_state(crtc->state); | 741 | old_cstate = to_dpu_crtc_state(crtc->state); |
| 679 | cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); | 742 | cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); |
| 680 | if (!cstate) { | 743 | if (!cstate) { |
| @@ -693,9 +756,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, · 12 unmodified lines | |||
| 693 | { | 756 | { |
| 694 | struct dpu_crtc *dpu_crtc; | 757 | struct dpu_crtc *dpu_crtc; |
| 695 | struct dpu_crtc_state *cstate; | 758 | struct dpu_crtc_state *cstate; |
| 696 | struct drm_display_mode *mode; | ||
| 697 | struct drm_encoder *encoder; | 759 | struct drm_encoder *encoder; |
| 698 | struct msm_drm_private *priv; | ||
| 699 | unsigned long flags; | 760 | unsigned long flags; |
| 700 | bool release_bandwidth = false; | 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 | dpu_crtc = to_dpu_crtc(crtc); | 767 | dpu_crtc = to_dpu_crtc(crtc); |
| 707 | cstate = to_dpu_crtc_state(crtc->state); | 768 | cstate = to_dpu_crtc_state(crtc->state); |
| 708 | mode = &cstate->base.adjusted_mode; | ||
| 709 | priv = crtc->dev->dev_private; | ||
| 710 | 769 | ||
| 711 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); | 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 | struct dpu_crtc *dpu_crtc; | 828 | struct dpu_crtc *dpu_crtc; |
| 770 | struct drm_encoder *encoder; | 829 | struct drm_encoder *encoder; |
| 771 | struct msm_drm_private *priv; | ||
| 772 | bool request_bandwidth; | 830 | bool request_bandwidth; |
| 773 | 831 | ||
| 774 | if (!crtc) { | 832 | if (!crtc) { |
| 775 | DPU_ERROR("invalid crtc\n"); | 833 | DPU_ERROR("invalid crtc\n"); |
| 776 | return; | 834 | return; |
| 777 | } | 835 | } |
| 778 | priv = crtc->dev->dev_private; | ||
| 779 | 836 | ||
| 780 | pm_runtime_get_sync(crtc->dev->dev); | 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 | drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); | 1377 | drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); |
| 1321 | 1378 | ||
| 1379 | drm_crtc_enable_color_mgmt(crtc, 0, true, 0); | ||
| 1380 | |||
| 1322 | /* save user friendly CRTC name for later */ | 1381 | /* save user friendly CRTC name for later */ |
| 1323 | snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); | 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 | * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC | 73 | * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC |
| 74 | * @hw_lm: LM HW Driver context | 74 | * @hw_lm: LM HW Driver context |
| 75 | * @lm_ctl: CTL Path HW driver context | 75 | * @lm_ctl: CTL Path HW driver context |
| 76 | * @lm_dspp: DSPP HW driver context | ||
| 76 | * @mixer_op_mode: mixer blending operation mode | 77 | * @mixer_op_mode: mixer blending operation mode |
| 77 | * @flush_mask: mixer flush mask for ctl, mixer and pipe | 78 | * @flush_mask: mixer flush mask for ctl, mixer and pipe |
| 78 | */ | 79 | */ |
| 79 | struct dpu_crtc_mixer { | 80 | struct dpu_crtc_mixer { |
| 80 | struct dpu_hw_mixer *hw_lm; | 81 | struct dpu_hw_mixer *hw_lm; |
| 81 | struct dpu_hw_ctl *lm_ctl; | 82 | struct dpu_hw_ctl *lm_ctl; |
| 83 | struct dpu_hw_dspp *hw_dspp; | ||
| 82 | u32 mixer_op_mode; | 84 | u32 mixer_op_mode; |
| 83 | u32 flush_mask; | 85 | u32 flush_mask; |
| 84 | }; | 86 | }; |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include "dpu_hw_catalog.h" | 20 | #include "dpu_hw_catalog.h" |
| 21 | #include "dpu_hw_intf.h" | 21 | #include "dpu_hw_intf.h" |
| 22 | #include "dpu_hw_ctl.h" | 22 | #include "dpu_hw_ctl.h" |
| 23 | #include "dpu_hw_dspp.h" | ||
| 23 | #include "dpu_formats.h" | 24 | #include "dpu_formats.h" |
| 24 | #include "dpu_encoder_phys.h" | 25 | #include "dpu_encoder_phys.h" |
| 25 | #include "dpu_crtc.h" | 26 | #include "dpu_crtc.h" |
| @@ -536,6 +537,7 @@ static struct msm_display_topology dpu_encoder_get_topology( · 510 unmodified lines | |||
| 536 | * 1 LM, 1 INTF | 537 | * 1 LM, 1 INTF |
| 537 | * 2 LM, 1 INTF (stream merge to support high resolution interfaces) | 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 | if (intf_count == 2) | 542 | if (intf_count == 2) |
| 541 | topology.num_lm = 2; | 543 | topology.num_lm = 2; |
| @@ -544,6 +546,9 @@ static struct msm_display_topology dpu_encoder_get_topology( · 2 unmodified lines | |||
| 544 | else | 546 | else |
| 545 | topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; | 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 | topology.num_enc = 0; | 552 | topology.num_enc = 0; |
| 548 | topology.num_intf = intf_count; | 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 | struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC]; | 964 | struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC]; |
| 960 | struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; | 965 | struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; |
| 961 | struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; | 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 | int i, j; | 969 | int i, j; |
| 964 | 970 | ||
| 965 | if (!drm_enc) { | 971 | if (!drm_enc) { |
| @@ -1008,6 +1014,9 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, · 42 unmodified lines | |||
| 1008 | drm_enc->base.id, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl)); | 1014 | drm_enc->base.id, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl)); |
| 1009 | num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, | 1015 | num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, |
| 1010 | drm_enc->base.id, DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm)); | 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 | for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) | 1021 | for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) |
| 1013 | dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) | 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 | cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]); | 1030 | cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]); |
| 1022 | cstate->mixers[i].lm_ctl = to_dpu_hw_ctl(hw_ctl[ctl_idx]); | 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 | cstate->num_mixers = num_lm; | 1035 | cstate->num_mixers = num_lm; |
| @@ -41,6 +41,8 @@ · 40 unmodified lines | |||
| 41 | #define PINGPONG_SDM845_SPLIT_MASK \ | 41 | #define PINGPONG_SDM845_SPLIT_MASK \ |
| 42 | (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) | 42 | (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) |
| 43 | 43 | ||
| 44 | #define DSPP_SC7180_MASK BIT(DPU_DSPP_PCC) | ||
| 45 | |||
| 44 | #define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) | 46 | #define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) |
| 45 | #define DEFAULT_DPU_LINE_WIDTH 2048 | 47 | #define DEFAULT_DPU_LINE_WIDTH 2048 |
| 46 | #define DEFAULT_DPU_OUTPUT_LINE_WIDTH 2560 | 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 | .name = _name, .id = _id, \ | 298 | .name = _name, .id = _id, \ |
| 297 | .base = _base, .len = 0x320, \ | 299 | .base = _base, .len = 0x320, \ |
| 298 | .features = _fmask, \ | 300 | .features = _fmask, \ |
| 299 | .sblk = _sblk, \ | 301 | .sblk = _sblk, \ |
| 300 | .pingpong = _pp, \ | 302 | .pingpong = _pp, \ |
| 301 | .lm_pair_mask = (1 << _lmpair) \ | 303 | .lm_pair_mask = (1 << _lmpair), \ |
| 304 | .dspp = _dspp \ | ||
| 302 | } | 305 | } |
| 303 | 306 | ||
| 304 | static const struct dpu_lm_cfg sdm845_lm[] = { | 307 | static const struct dpu_lm_cfg sdm845_lm[] = { |
| 305 | LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, | 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 | LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, | 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 | LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, | 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 | LM_BLK("lm_3", LM_3, 0x0, MIXER_SDM845_MASK, | 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 | LM_BLK("lm_4", LM_4, 0x0, MIXER_SDM845_MASK, | 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 | LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK, | 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 | /* SC7180 */ | 322 | /* SC7180 */ |
| @@ -328,11 +331,30 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = { · 8 unmodified lines | |||
| 328 | 331 | ||
| 329 | static const struct dpu_lm_cfg sc7180_lm[] = { | 332 | static const struct dpu_lm_cfg sc7180_lm[] = { |
| 330 | LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK, | 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 | LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK, | 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 | * PINGPONG sub blocks config | 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 | static const struct dpu_perf_cfg sc7180_perf_data = { | 539 | static const struct dpu_perf_cfg sc7180_perf_data = { |
| 518 | .max_bw_low = 3900000, | 540 | .max_bw_low = 6800000, |
| 519 | .max_bw_high = 5500000, | 541 | .max_bw_high = 6800000, |
| 520 | .min_core_ib = 2400000, | 542 | .min_core_ib = 2400000, |
| 521 | .min_llcc_ib = 800000, | 543 | .min_llcc_ib = 800000, |
| 522 | .min_dram_ib = 800000, | 544 | .min_dram_ib = 800000, |
| @@ -587,6 +609,8 @@ static void sc7180_cfg_init(struct dpu_mdss_cfg *dpu_cfg) · 64 unmodified lines | |||
| 587 | .sspp = sc7180_sspp, | 609 | .sspp = sc7180_sspp, |
| 588 | .mixer_count = ARRAY_SIZE(sc7180_lm), | 610 | .mixer_count = ARRAY_SIZE(sc7180_lm), |
| 589 | .mixer = sc7180_lm, | 611 | .mixer = sc7180_lm, |
| 612 | .dspp_count = ARRAY_SIZE(sc7180_dspp), | ||
| 613 | .dspp = sc7180_dspp, | ||
| 590 | .pingpong_count = ARRAY_SIZE(sc7180_pp), | 614 | .pingpong_count = ARRAY_SIZE(sc7180_pp), |
| 591 | .pingpong = sc7180_pp, | 615 | .pingpong = sc7180_pp, |
| 592 | .intf_count = ARRAY_SIZE(sc7180_intf), | 616 | .intf_count = ARRAY_SIZE(sc7180_intf), |
| @@ -145,6 +145,17 @@ enum { · 144 unmodified lines | |||
| 145 | DPU_MIXER_MAX | 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 | * PINGPONG sub-blocks | 160 | * PINGPONG sub-blocks |
| 150 | * @DPU_PINGPONG_TE Tear check block | 161 | * @DPU_PINGPONG_TE Tear check block |
| @@ -377,6 +388,16 @@ struct dpu_lm_sub_blks { · 226 unmodified lines | |||
| 377 | struct dpu_pp_blk gc; | 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 | struct dpu_pingpong_sub_blks { | 401 | struct dpu_pingpong_sub_blks { |
| 381 | struct dpu_pp_blk te; | 402 | struct dpu_pp_blk te; |
| 382 | struct dpu_pp_blk te2; | 403 | struct dpu_pp_blk te2; |
| @@ -471,9 +492,23 @@ struct dpu_lm_cfg { · 88 unmodified lines | |||
| 471 | DPU_HW_BLK_INFO; | 492 | DPU_HW_BLK_INFO; |
| 472 | const struct dpu_lm_sub_blks *sblk; | 493 | const struct dpu_lm_sub_blks *sblk; |
| 473 | u32 pingpong; | 494 | u32 pingpong; |
| 495 | u32 dspp; | ||
| 474 | unsigned long lm_pair_mask; | 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 | * struct dpu_pingpong_cfg - information of PING-PONG blocks | 513 | * struct dpu_pingpong_cfg - information of PING-PONG blocks |
| 479 | * @id enum identifying this block | 514 | * @id enum identifying this block |
| @@ -688,6 +723,9 @@ struct dpu_mdss_cfg { · 208 unmodified lines | |||
| 688 | 723 | ||
| 689 | u32 ad_count; | 724 | u32 ad_count; |
| 690 | 725 | ||
| 726 | u32 dspp_count; | ||
| 727 | const struct dpu_dspp_cfg *dspp; | ||
| 728 | |||
| 691 | /* Add additional block data structures here */ | 729 | /* Add additional block data structures here */ |
| 692 | 730 | ||
| 693 | struct dpu_perf_cfg perf; | 731 | struct dpu_perf_cfg perf; |
| @@ -716,6 +754,7 @@ struct dpu_mdss_hw_cfg_handler { · 22 unmodified lines | |||
| 716 | #define BLK_PINGPONG(s) ((s)->pingpong) | 754 | #define BLK_PINGPONG(s) ((s)->pingpong) |
| 717 | #define BLK_INTF(s) ((s)->intf) | 755 | #define BLK_INTF(s) ((s)->intf) |
| 718 | #define BLK_AD(s) ((s)->ad) | 756 | #define BLK_AD(s) ((s)->ad) |
| 757 | #define BLK_DSPP(s) ((s)->dspp) | ||
| 719 | 758 | ||
| 720 | /** | 759 | /** |
| 721 | * dpu_hw_catalog_init - dpu hardware catalog init API retrieves | 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 | return 0; | 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 | static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) | 300 | static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) |
| 276 | { | 301 | { |
| 277 | struct dpu_hw_blk_reg_map *c = &ctx->hw; | 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 | ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; | 573 | ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; |
| 549 | ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; | 574 | ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; |
| 550 | ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; | 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 | static struct dpu_hw_blk_ops dpu_hw_ops; | 579 | static struct dpu_hw_blk_ops dpu_hw_ops; |
| @@ -139,6 +139,9 @@ struct dpu_hw_ctl_ops { · 138 unmodified lines | |||
| 139 | uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, | 139 | uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, |
| 140 | enum dpu_lm blk); | 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 | * Query the value of the intf flush mask | 146 | * Query the value of the intf flush mask |
| 144 | * No effect on hardware | 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 | DPU_HW_BLK_PINGPONG, | 95 | DPU_HW_BLK_PINGPONG, |
| 96 | DPU_HW_BLK_INTF, | 96 | DPU_HW_BLK_INTF, |
| 97 | DPU_HW_BLK_WB, | 97 | DPU_HW_BLK_WB, |
| 98 | DPU_HW_BLK_DSPP, | ||
| 98 | DPU_HW_BLK_MAX, | 99 | DPU_HW_BLK_MAX, |
| 99 | }; | 100 | }; |
| 100 | 101 | ||
| @@ -425,5 +426,6 @@ struct dpu_mdss_color { · 324 unmodified lines | |||
| 425 | #define DPU_DBG_MASK_TOP (1 << 7) | 426 | #define DPU_DBG_MASK_TOP (1 << 7) |
| 426 | #define DPU_DBG_MASK_VBIF (1 << 8) | 427 | #define DPU_DBG_MASK_VBIF (1 << 8) |
| 427 | #define DPU_DBG_MASK_ROT (1 << 9) | 428 | #define DPU_DBG_MASK_ROT (1 << 9) |
| 429 | #define DPU_DBG_MASK_DSPP (1 << 10) | ||
| 428 | 430 | ||
| 429 | #endif /* _DPU_HW_MDSS_H */ | 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 | struct iommu_domain *domain; | 773 | struct iommu_domain *domain; |
| 774 | struct msm_gem_address_space *aspace; | 774 | struct msm_gem_address_space *aspace; |
| 775 | int ret; | 775 | struct msm_mmu *mmu; |
| 776 | 776 | ||
| 777 | domain = iommu_domain_alloc(&platform_bus_type); | 777 | domain = iommu_domain_alloc(&platform_bus_type); |
| 778 | if (!domain) | 778 | if (!domain) |
| 779 | return 0; | 779 | return 0; |
| 780 | 780 | ||
| 781 | domain->geometry.aperture_start = 0x1000; | 781 | mmu = msm_iommu_new(dpu_kms->dev->dev, domain); |
| 782 | domain->geometry.aperture_end = 0xffffffff; | 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 | if (IS_ERR(aspace)) { | 785 | if (IS_ERR(aspace)) { |
| 787 | iommu_domain_free(domain); | 786 | mmu->funcs->destroy(mmu); |
| 788 | return PTR_ERR(aspace); | 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 | dpu_kms->base.aspace = aspace; | 790 | dpu_kms->base.aspace = aspace; |
| 799 | return 0; | 791 | return 0; |
| 800 | } | 792 | } |
| @@ -158,6 +158,7 @@ struct dpu_global_state { · 157 unmodified lines | |||
| 158 | uint32_t mixer_to_enc_id[LM_MAX - LM_0]; | 158 | uint32_t mixer_to_enc_id[LM_MAX - LM_0]; |
| 159 | uint32_t ctl_to_enc_id[CTL_MAX - CTL_0]; | 159 | uint32_t ctl_to_enc_id[CTL_MAX - CTL_0]; |
| 160 | uint32_t intf_to_enc_id[INTF_MAX - INTF_0]; | 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 | struct dpu_global_state | 164 | struct dpu_global_state |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include "dpu_hw_ctl.h" | 9 | #include "dpu_hw_ctl.h" |
| 10 | #include "dpu_hw_pingpong.h" | 10 | #include "dpu_hw_pingpong.h" |
| 11 | #include "dpu_hw_intf.h" | 11 | #include "dpu_hw_intf.h" |
| 12 | #include "dpu_hw_dspp.h" | ||
| 12 | #include "dpu_encoder.h" | 13 | #include "dpu_encoder.h" |
| 13 | #include "dpu_trace.h" | 14 | #include "dpu_trace.h" |
| 14 | 15 | ||
| @@ -174,6 +175,23 @@ int dpu_rm_init(struct dpu_rm *rm, · 159 unmodified lines | |||
| 174 | rm->ctl_blks[ctl->id - CTL_0] = &hw->base; | 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 | return 0; | 195 | return 0; |
| 178 | 196 | ||
| 179 | fail: | 197 | fail: |
| @@ -222,12 +240,17 @@ static bool _dpu_rm_check_lm_peer(struct dpu_rm *rm, int primary_idx, · 42 unmodified lines | |||
| 222 | * if lm, and all other hardwired blocks connected to the lm (pp) is | 240 | * if lm, and all other hardwired blocks connected to the lm (pp) is |
| 223 | * available and appropriate | 241 | * available and appropriate |
| 224 | * @pp_idx: output parameter, index of pingpong block attached to the layer | 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 | * @Return: true if lm matches all requirements, false otherwise | 248 | * @Return: true if lm matches all requirements, false otherwise |
| 227 | */ | 249 | */ |
| 228 | static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, | 250 | static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, |
| 229 | struct dpu_global_state *global_state, | 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 | const struct dpu_lm_cfg *lm_cfg; | 255 | const struct dpu_lm_cfg *lm_cfg; |
| 233 | int idx; | 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 | return false; | 274 | return false; |
| 252 | } | 275 | } |
| 253 | *pp_idx = idx; | 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 | return true; | 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 | int lm_idx[MAX_BLOCKS]; | 303 | int lm_idx[MAX_BLOCKS]; |
| 264 | int pp_idx[MAX_BLOCKS]; | 304 | int pp_idx[MAX_BLOCKS]; |
| 305 | int dspp_idx[MAX_BLOCKS] = {0}; | ||
| 265 | int i, j, lm_count = 0; | 306 | int i, j, lm_count = 0; |
| 266 | 307 | ||
| 267 | if (!reqs->topology.num_lm) { | 308 | if (!reqs->topology.num_lm) { |
| @@ -279,7 +320,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 11 unmodified lines | |||
| 279 | lm_idx[lm_count] = i; | 320 | lm_idx[lm_count] = i; |
| 280 | 321 | ||
| 281 | if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state, | 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 | continue; | 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 | if (!_dpu_rm_check_lm_and_get_connected_blks(rm, | 342 | if (!_dpu_rm_check_lm_and_get_connected_blks(rm, |
| 301 | global_state, enc_id, j, | 343 | global_state, enc_id, j, |
| 302 | &pp_idx[lm_count])) { | 344 | &pp_idx[lm_count], &dspp_idx[lm_count], |
| 345 | reqs)) { | ||
| 303 | continue; | 346 | continue; |
| 304 | } | 347 | } |
| 305 | 348 | ||
| @@ -316,6 +359,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, · 10 unmodified lines | |||
| 316 | for (i = 0; i < lm_count; i++) { | 359 | for (i = 0; i < lm_count; i++) { |
| 317 | global_state->mixer_to_enc_id[lm_idx[i]] = enc_id; | 360 | global_state->mixer_to_enc_id[lm_idx[i]] = enc_id; |
| 318 | global_state->pingpong_to_enc_id[pp_idx[i]] = enc_id; | 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 | trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id, | 365 | trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id, |
| 321 | pp_idx[i] + PINGPONG_0); | 366 | pp_idx[i] + PINGPONG_0); |
| @@ -560,6 +605,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, · 238 unmodified lines | |||
| 560 | hw_to_enc_id = global_state->intf_to_enc_id; | 605 | hw_to_enc_id = global_state->intf_to_enc_id; |
| 561 | max_blks = ARRAY_SIZE(rm->intf_blks); | 606 | max_blks = ARRAY_SIZE(rm->intf_blks); |
| 562 | break; | 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 | default: | 613 | default: |
| 564 | DPU_ERROR("blk type %d not managed by rm\n", type); | 614 | DPU_ERROR("blk type %d not managed by rm\n", type); |
| 565 | return 0; | 615 | return 0; |
| @@ -19,6 +19,7 @@ struct dpu_global_state; · 18 unmodified lines | |||
| 19 | * @mixer_blks: array of layer mixer hardware resources | 19 | * @mixer_blks: array of layer mixer hardware resources |
| 20 | * @ctl_blks: array of ctl hardware resources | 20 | * @ctl_blks: array of ctl hardware resources |
| 21 | * @intf_blks: array of intf hardware resources | 21 | * @intf_blks: array of intf hardware resources |
| 22 | * @dspp_blks: array of dspp hardware resources | ||
| 22 | * @lm_max_width: cached layer mixer maximum width | 23 | * @lm_max_width: cached layer mixer maximum width |
| 23 | * @rm_lock: resource manager mutex | 24 | * @rm_lock: resource manager mutex |
| 24 | */ | 25 | */ |
| @@ -27,6 +28,7 @@ struct dpu_rm { · 2 unmodified lines | |||
| 27 | struct dpu_hw_blk *mixer_blks[LM_MAX - LM_0]; | 28 | struct dpu_hw_blk *mixer_blks[LM_MAX - LM_0]; |
| 28 | struct dpu_hw_blk *ctl_blks[CTL_MAX - CTL_0]; | 29 | struct dpu_hw_blk *ctl_blks[CTL_MAX - CTL_0]; |
| 29 | struct dpu_hw_blk *intf_blks[INTF_MAX - INTF_0]; | 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 | uint32_t lm_max_width; | 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 | mdelay(16); | 510 | mdelay(16); |
| 511 | 511 | ||
| 512 | if (config->iommu) { | 512 | if (config->iommu) { |
| 513 | aspace = msm_gem_address_space_create(&pdev->dev, | 513 | struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, |
| 514 | config->iommu, "mdp4"); | 514 | config->iommu); |
| 515 | |||
| 516 | aspace = msm_gem_address_space_create(mmu, | ||
| 517 | "mdp4", 0x1000, 0xffffffff); | ||
| 518 | |||
| 515 | if (IS_ERR(aspace)) { | 519 | if (IS_ERR(aspace)) { |
| 520 | if (!IS_ERR(mmu)) | ||
| 521 | mmu->funcs->destroy(mmu); | ||
| 516 | ret = PTR_ERR(aspace); | 522 | ret = PTR_ERR(aspace); |
| 517 | goto fail; | 523 | goto fail; |
| 518 | } | 524 | } |
| 519 | 525 | ||
| 520 | kms->aspace = aspace; | 526 | kms->aspace = aspace; |
| 521 | |||
| 522 | ret = aspace->mmu->funcs->attach(aspace->mmu); | ||
| 523 | if (ret) | ||
| 524 | goto fail; | ||
| 525 | } else { | 527 | } else { |
| 526 | DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " | 528 | DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " |
| 527 | "contig buffers for scanout\n"); | 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 | /* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */ | 571 | /* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */ |
| 570 | config.max_clk = 266667000; | 572 | config.max_clk = 266667000; |
| 571 | config.iommu = iommu_domain_alloc(&platform_bus_type); | 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 | return &config; | 575 | return &config; |
| 578 | } | 576 | } |
| @@ -342,6 +342,81 @@ static const struct mdp5_cfg_hw msm8x16_config = { · 341 unmodified lines | |||
| 342 | .max_clk = 320000000, | 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 | static const struct mdp5_cfg_hw msm8x94_config = { | 420 | static const struct mdp5_cfg_hw msm8x94_config = { |
| 346 | .name = "msm8x94", | 421 | .name = "msm8x94", |
| 347 | .mdp = { | 422 | .mdp = { |
| @@ -840,6 +915,7 @@ static const struct mdp5_cfg_handler cfg_handlers_v1[] = { · 492 unmodified lines | |||
| 840 | { .revision = 2, .config = { .hw = &msm8x74v2_config } }, | 915 | { .revision = 2, .config = { .hw = &msm8x74v2_config } }, |
| 841 | { .revision = 3, .config = { .hw = &apq8084_config } }, | 916 | { .revision = 3, .config = { .hw = &apq8084_config } }, |
| 842 | { .revision = 6, .config = { .hw = &msm8x16_config } }, | 917 | { .revision = 6, .config = { .hw = &msm8x16_config } }, |
| 918 | { .revision = 8, .config = { .hw = &msm8x36_config } }, | ||
| 843 | { .revision = 9, .config = { .hw = &msm8x94_config } }, | 919 | { .revision = 9, .config = { .hw = &msm8x94_config } }, |
| 844 | { .revision = 7, .config = { .hw = &msm8x96_config } }, | 920 | { .revision = 7, .config = { .hw = &msm8x96_config } }, |
| 845 | { .revision = 11, .config = { .hw = &msm8x76_config } }, | 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 | static struct mdp5_cfg_platform config = {}; | 1017 | static struct mdp5_cfg_platform config = {}; |
| 942 | 1018 | ||
| 943 | config.iommu = iommu_domain_alloc(&platform_bus_type); | 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 | return &config; | 1021 | return &config; |
| 950 | } | 1022 | } |
| @@ -959,7 +959,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, · 958 unmodified lines | |||
| 959 | if (!ctl) | 959 | if (!ctl) |
| 960 | return -EINVAL; | 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 | if (mdp5_cstate->pipeline.r_mixer) | 963 | if (mdp5_cstate->pipeline.r_mixer) |
| 964 | return -EINVAL; | 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 | return -EINVAL; | 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 | if (mdp5_cstate->pipeline.r_mixer) | 1034 | if (mdp5_cstate->pipeline.r_mixer) |
| 1035 | return -EINVAL; | 1035 | return -EINVAL; |
| 1036 | 1036 | ||
| @@ -632,25 +632,25 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) · 631 unmodified lines | |||
| 632 | mdelay(16); | 632 | mdelay(16); |
| 633 | 633 | ||
| 634 | if (config->platform.iommu) { | 634 | if (config->platform.iommu) { |
| 635 | struct msm_mmu *mmu; | ||
| 636 | |||
| 635 | iommu_dev = &pdev->dev; | 637 | iommu_dev = &pdev->dev; |
| 636 | if (!dev_iommu_fwspec_get(iommu_dev)) | 638 | if (!dev_iommu_fwspec_get(iommu_dev)) |
| 637 | iommu_dev = iommu_dev->parent; | 639 | iommu_dev = iommu_dev->parent; |
| 638 | 640 | ||
| 639 | aspace = msm_gem_address_space_create(iommu_dev, | 641 | mmu = msm_iommu_new(iommu_dev, config->platform.iommu); |
| 640 | config->platform.iommu, "mdp5"); | 642 | |
| 643 | aspace = msm_gem_address_space_create(mmu, "mdp5", | ||
| 644 | 0x1000, 0xffffffff); | ||
| 645 | |||
| 641 | if (IS_ERR(aspace)) { | 646 | if (IS_ERR(aspace)) { |
| 647 | if (!IS_ERR(mmu)) | ||
| 648 | mmu->funcs->destroy(mmu); | ||
| 642 | ret = PTR_ERR(aspace); | 649 | ret = PTR_ERR(aspace); |
| 643 | goto fail; | 650 | goto fail; |
| 644 | } | 651 | } |
| 645 | 652 | ||
| 646 | kms->aspace = aspace; | 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 | } else { | 654 | } else { |
| 655 | DRM_DEV_INFO(&pdev->dev, | 655 | DRM_DEV_INFO(&pdev->dev, |
| 656 | "no iommu, fallback to phys contig buffers for scanout\n"); | 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 | return 0; | 944 | return 0; |
| 945 | fail: | 945 | fail: |
| 946 | mdp5_destroy(pdev); | 946 | if (mdp5_kms) |
| 947 | mdp5_destroy(pdev); | ||
| 947 | return ret; | 948 | return ret; |
| 948 | } | 949 | } |
| 949 | 950 | ||
| @@ -37,9 +37,10 @@ · 36 unmodified lines | |||
| 37 | * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get | 37 | * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get |
| 38 | * GEM object's debug name | 38 | * GEM object's debug name |
| 39 | * - 1.5.0 - Add SUBMITQUERY_QUERY ioctl | 39 | * - 1.5.0 - Add SUBMITQUERY_QUERY ioctl |
| 40 | * - 1.6.0 - Syncobj support | ||
| 40 | */ | 41 | */ |
| 41 | #define MSM_VERSION_MAJOR 1 | 42 | #define MSM_VERSION_MAJOR 1 |
| 42 | #define MSM_VERSION_MINOR 5 | 43 | #define MSM_VERSION_MINOR 6 |
| 43 | #define MSM_VERSION_PATCHLEVEL 0 | 44 | #define MSM_VERSION_PATCHLEVEL 0 |
| 44 | 45 | ||
| 45 | static const struct drm_mode_config_funcs mode_config_funcs = { | 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 | .driver_features = DRIVER_GEM | | 1003 | .driver_features = DRIVER_GEM | |
| 1003 | DRIVER_RENDER | | 1004 | DRIVER_RENDER | |
| 1004 | DRIVER_ATOMIC | | 1005 | DRIVER_ATOMIC | |
| 1005 | DRIVER_MODESET, | 1006 | DRIVER_MODESET | |
| 1007 | DRIVER_SYNCOBJ, | ||
| 1006 | .open = msm_open, | 1008 | .open = msm_open, |
| 1007 | .postclose = msm_postclose, | 1009 | .postclose = msm_postclose, |
| 1008 | .lastclose = drm_fb_helper_lastclose, | 1010 | .lastclose = drm_fb_helper_lastclose, |
| @@ -105,6 +105,7 @@ struct msm_display_topology { · 104 unmodified lines | |||
| 105 | u32 num_lm; | 105 | u32 num_lm; |
| 106 | u32 num_enc; | 106 | u32 num_enc; |
| 107 | u32 num_intf; | 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 | void msm_crtc_disable_vblank(struct drm_crtc *crtc); | 237 | void msm_crtc_disable_vblank(struct drm_crtc *crtc); |
| 237 | 238 | ||
| 238 | int msm_gem_init_vma(struct msm_gem_address_space *aspace, | 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 | void msm_gem_purge_vma(struct msm_gem_address_space *aspace, | 242 | void msm_gem_purge_vma(struct msm_gem_address_space *aspace, |
| 241 | struct msm_gem_vma *vma); | 243 | struct msm_gem_vma *vma); |
| 242 | void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, | 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 | void msm_gem_address_space_put(struct msm_gem_address_space *aspace); | 252 | void msm_gem_address_space_put(struct msm_gem_address_space *aspace); |
| 251 | 253 | ||
| 252 | struct msm_gem_address_space * | 254 | struct msm_gem_address_space * |
| 253 | msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | 255 | msm_gem_address_space_create(struct msm_mmu *mmu, const char *name, |
| 254 | const char *name); | 256 | u64 va_start, u64 size); |
| 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); | ||
| 259 | 257 | ||
| 260 | int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); | 258 | int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); |
| 261 | void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); | 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 | uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); | 274 | uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); |
| 277 | int msm_gem_get_iova(struct drm_gem_object *obj, | 275 | int msm_gem_get_iova(struct drm_gem_object *obj, |
| 278 | struct msm_gem_address_space *aspace, uint64_t *iova); | 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 | int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, | 280 | int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, |
| 280 | struct msm_gem_address_space *aspace, uint64_t *iova); | 281 | struct msm_gem_address_space *aspace, uint64_t *iova); |
| 281 | uint64_t msm_gem_iova(struct drm_gem_object *obj, | 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 | static int msm_gem_get_iova_locked(struct drm_gem_object *obj, | 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 | struct msm_gem_object *msm_obj = to_msm_bo(obj); | 395 | struct msm_gem_object *msm_obj = to_msm_bo(obj); |
| 395 | struct msm_gem_vma *vma; | 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 | if (IS_ERR(vma)) | 405 | if (IS_ERR(vma)) |
| 405 | return PTR_ERR(vma); | 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 | if (ret) { | 410 | if (ret) { |
| 409 | del_vma(vma); | 411 | del_vma(vma); |
| 410 | return ret; | 412 | return ret; |
| @@ -426,6 +428,9 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj, · 15 unmodified lines | |||
| 426 | if (!(msm_obj->flags & MSM_BO_GPU_READONLY)) | 428 | if (!(msm_obj->flags & MSM_BO_GPU_READONLY)) |
| 427 | prot |= IOMMU_WRITE; | 429 | prot |= IOMMU_WRITE; |
| 428 | 430 | ||
| 431 | if (msm_obj->flags & MSM_BO_MAP_PRIV) | ||
| 432 | prot |= IOMMU_PRIV; | ||
| 433 | |||
| 429 | WARN_ON(!mutex_is_locked(&msm_obj->lock)); | 434 | WARN_ON(!mutex_is_locked(&msm_obj->lock)); |
| 430 | 435 | ||
| 431 | if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) | 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 | msm_obj->sgt, obj->size >> PAGE_SHIFT); | 448 | msm_obj->sgt, obj->size >> PAGE_SHIFT); |
| 444 | } | 449 | } |
| 445 | 450 | ||
| 446 | /* get iova and pin it. Should have a matching put */ | 451 | /* |
| 447 | int msm_gem_get_and_pin_iova(struct drm_gem_object *obj, | 452 | * get iova and pin it. Should have a matching put |
| 448 | struct msm_gem_address_space *aspace, uint64_t *iova) | 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 | struct msm_gem_object *msm_obj = to_msm_bo(obj); | 459 | struct msm_gem_object *msm_obj = to_msm_bo(obj); |
| 451 | u64 local; | 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 | mutex_lock(&msm_obj->lock); | 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 | if (!ret) | 468 | if (!ret) |
| 459 | ret = msm_gem_pin_iova(obj, aspace); | 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 | return ret; | 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 | * Get an iova but don't pin it. Doesn't need a put because iovas are currently | 486 | * Get an iova but don't pin it. Doesn't need a put because iovas are currently |
| 470 | * valid for the life of the object | 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 | int ret; | 493 | int ret; |
| 477 | 494 | ||
| 478 | mutex_lock(&msm_obj->lock); | 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 | mutex_unlock(&msm_obj->lock); | 497 | mutex_unlock(&msm_obj->lock); |
| 481 | 498 | ||
| 482 | return ret; | 499 | return ret; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | /* Additional internal-use only BO flags: */ | 14 | /* Additional internal-use only BO flags: */ |
| 15 | #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ | 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 | struct msm_gem_address_space { | 18 | struct msm_gem_address_space { |
| 18 | const char *name; | 19 | const char *name; |
| @@ -8,7 +8,9 @@ · 7 unmodified lines | |||
| 8 | #include <linux/sync_file.h> | 8 | #include <linux/sync_file.h> |
| 9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
| 10 | 10 | ||
| 11 | #include <drm/drm_drv.h> | ||
| 11 | #include <drm/drm_file.h> | 12 | #include <drm/drm_file.h> |
| 13 | #include <drm/drm_syncobj.h> | ||
| 12 | 14 | ||
| 13 | #include "msm_drv.h" | 15 | #include "msm_drv.h" |
| 14 | #include "msm_gpu.h" | 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 | int msm_ioctl_gem_submit(struct drm_device *dev, void *data, | 576 | int msm_ioctl_gem_submit(struct drm_device *dev, void *data, |
| 395 | struct drm_file *file) | 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 | struct sync_file *sync_file = NULL; | 585 | struct sync_file *sync_file = NULL; |
| 404 | struct msm_gpu_submitqueue *queue; | 586 | struct msm_gpu_submitqueue *queue; |
| 405 | struct msm_ringbuffer *ring; | 587 | struct msm_ringbuffer *ring; |
| 588 | struct msm_submit_post_dep *post_deps = NULL; | ||
| 589 | struct drm_syncobj **syncobjs_to_reset = NULL; | ||
| 406 | int out_fence_fd = -1; | 590 | int out_fence_fd = -1; |
| 407 | struct pid *pid = get_pid(task_pid(current)); | 591 | struct pid *pid = get_pid(task_pid(current)); |
| 408 | bool has_ww_ticket = false; | 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 | if (!gpu) | 595 | if (!gpu) |
| 412 | return -ENXIO; | 596 | return -ENXIO; |
| 413 | 597 | ||
| 598 | if (args->pad) | ||
| 599 | return -EINVAL; | ||
| 600 | |||
| 414 | /* for now, we just have 3d pipe.. eventually this would need to | 601 | /* for now, we just have 3d pipe.. eventually this would need to |
| 415 | * be more clever to dispatch to appropriate gpu module: | 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 | return ret; | 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 | ret = mutex_lock_interruptible(&dev->struct_mutex); | 668 | ret = mutex_lock_interruptible(&dev->struct_mutex); |
| 462 | if (ret) | 669 | if (ret) |
| 463 | return ret; | 670 | goto out_post_unlock; |
| 464 | 671 | ||
| 465 | if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) { | 672 | if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) { |
| 466 | out_fence_fd = get_unused_fd_flags(O_CLOEXEC); | 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 | args->fence_fd = out_fence_fd; | 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 | out: | 802 | out: |
| 591 | submit_cleanup(submit); | 803 | submit_cleanup(submit); |
| 592 | if (has_ww_ticket) | 804 | if (has_ww_ticket) |
| @@ -597,5 +809,23 @@ out_unlock: · 4 unmodified lines | |||
| 597 | if (ret && (out_fence_fd >= 0)) | 809 | if (ret && (out_fence_fd >= 0)) |
| 598 | put_unused_fd(out_fence_fd); | 810 | put_unused_fd(out_fence_fd); |
| 599 | mutex_unlock(&dev->struct_mutex); | 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 | return ret; | 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 | /* Initialize a new vma and allocate an iova for it */ | 104 | /* Initialize a new vma and allocate an iova for it */ |
| 105 | int msm_gem_init_vma(struct msm_gem_address_space *aspace, | 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 | int ret; | 109 | int ret; |
| 109 | 110 | ||
| @@ -111,7 +112,8 @@ int msm_gem_init_vma(struct msm_gem_address_space *aspace, · 1 unmodified line | |||
| 111 | return -EBUSY; | 112 | return -EBUSY; |
| 112 | 113 | ||
| 113 | spin_lock(&aspace->lock); | 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 | spin_unlock(&aspace->lock); | 117 | spin_unlock(&aspace->lock); |
| 116 | 118 | ||
| 117 | if (ret) | 119 | if (ret) |
| @@ -125,37 +127,14 @@ int msm_gem_init_vma(struct msm_gem_address_space *aspace, · 7 unmodified lines | |||
| 125 | return 0; | 127 | return 0; |
| 126 | } | 128 | } |
| 127 | 129 | ||
| 128 | |||
| 129 | struct msm_gem_address_space * | 130 | struct msm_gem_address_space * |
| 130 | msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | 131 | msm_gem_address_space_create(struct msm_mmu *mmu, const char *name, |
| 131 | const char *name) | 132 | u64 va_start, u64 size) |
| 132 | { | 133 | { |
| 133 | struct msm_gem_address_space *aspace; | 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); | 136 | if (IS_ERR(mmu)) |
| 149 | 137 | return ERR_CAST(mmu); | |
| 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; | ||
| 159 | 138 | ||
| 160 | aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); | 139 | aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); |
| 161 | if (!aspace) | 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 | spin_lock_init(&aspace->lock); | 143 | spin_lock_init(&aspace->lock); |
| 165 | aspace->name = name; | 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), | 147 | drm_mm_init(&aspace->mm, va_start >> PAGE_SHIFT, size >> PAGE_SHIFT); |
| 169 | size >> PAGE_SHIFT); | ||
| 170 | 148 | ||
| 171 | kref_init(&aspace->kref); | 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 | return 0; | 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 | int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, | 824 | int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, |
| 870 | struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, | 825 | struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, |
| 871 | const char *name, struct msm_gpu_config *config) | 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 | msm_devfreq_init(gpu); | 894 | msm_devfreq_init(gpu); |
| 940 | 895 | ||
| 941 | gpu->aspace = msm_gpu_create_address_space(gpu, pdev, | 896 | |
| 942 | config->va_start, config->va_end); | 897 | gpu->aspace = gpu->funcs->create_address_space(gpu, pdev); |
| 943 | 898 | ||
| 944 | if (gpu->aspace == NULL) | 899 | if (gpu->aspace == NULL) |
| 945 | DRM_DEV_INFO(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); | 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 | struct msm_gpu_config { | 22 | struct msm_gpu_config { |
| 23 | const char *ioname; | 23 | const char *ioname; |
| 24 | uint64_t va_start; | ||
| 25 | uint64_t va_end; | ||
| 26 | unsigned int nr_rings; | 24 | unsigned int nr_rings; |
| 27 | }; | 25 | }; |
| 28 | 26 | ||
| @@ -64,6 +62,8 @@ struct msm_gpu_funcs { · 35 unmodified lines | |||
| 64 | int (*gpu_state_put)(struct msm_gpu_state *state); | 62 | int (*gpu_state_put)(struct msm_gpu_state *state); |
| 65 | unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); | 63 | unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); |
| 66 | void (*gpu_set_freq)(struct msm_gpu *gpu, unsigned long freq); | 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 | struct msm_gpu { | 69 | struct msm_gpu { |
| @@ -21,17 +21,12 @@ struct msm_gpummu { · 20 unmodified lines | |||
| 21 | #define GPUMMU_PAGE_SIZE SZ_4K | 21 | #define GPUMMU_PAGE_SIZE SZ_4K |
| 22 | #define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE) | 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 | static void msm_gpummu_detach(struct msm_mmu *mmu) | 24 | static void msm_gpummu_detach(struct msm_mmu *mmu) |
| 30 | { | 25 | { |
| 31 | } | 26 | } |
| 32 | 27 | ||
| 33 | static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova, | 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 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); | 31 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); |
| 37 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; | 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 | return 0; | 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 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); | 59 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); |
| 65 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; | 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 | static const struct msm_mmu_funcs funcs = { | 82 | static const struct msm_mmu_funcs funcs = { |
| 88 | .attach = msm_gpummu_attach, | ||
| 89 | .detach = msm_gpummu_detach, | 83 | .detach = msm_gpummu_detach, |
| 90 | .map = msm_gpummu_map, | 84 | .map = msm_gpummu_map, |
| 91 | .unmap = msm_gpummu_unmap, | 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 | return 0; | 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 | static void msm_iommu_detach(struct msm_mmu *mmu) | 26 | static void msm_iommu_detach(struct msm_mmu *mmu) |
| 34 | { | 27 | { |
| 35 | struct msm_iommu *iommu = to_msm_iommu(mmu); | 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 | static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, | 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 | struct msm_iommu *iommu = to_msm_iommu(mmu); | 36 | struct msm_iommu *iommu = to_msm_iommu(mmu); |
| 44 | size_t ret; | 37 | size_t ret; |
| @@ -49,7 +42,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, · 4 unmodified lines | |||
| 49 | return (ret == len) ? 0 : -EINVAL; | 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 | struct msm_iommu *iommu = to_msm_iommu(mmu); | 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 | static const struct msm_mmu_funcs funcs = { | 61 | static const struct msm_mmu_funcs funcs = { |
| 69 | .attach = msm_iommu_attach, | ||
| 70 | .detach = msm_iommu_detach, | 62 | .detach = msm_iommu_detach, |
| 71 | .map = msm_iommu_map, | 63 | .map = msm_iommu_map, |
| 72 | .unmap = msm_iommu_unmap, | 64 | .unmap = msm_iommu_unmap, |
| @@ -76,6 +68,10 @@ static const struct msm_mmu_funcs funcs = { · 3 unmodified lines | |||
| 76 | struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) | 68 | struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) |
| 77 | { | 69 | { |
| 78 | struct msm_iommu *iommu; | 70 | struct msm_iommu *iommu; |
| 71 | int ret; | ||
| 72 | |||
| 73 | if (!domain) | ||
| 74 | return ERR_PTR(-ENODEV); | ||
| 79 | 75 | ||
| 80 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 76 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
| 81 | if (!iommu) | 77 | if (!iommu) |
| @@ -85,5 +81,11 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) · 3 unmodified lines | |||
| 85 | msm_mmu_init(&iommu->base, dev, &funcs); | 81 | msm_mmu_init(&iommu->base, dev, &funcs); |
| 86 | iommu_set_fault_handler(domain, msm_fault_handler, iommu); | 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 | return &iommu->base; | 90 | return &iommu->base; |
| 89 | } | 91 | } |
| @@ -10,11 +10,10 @@ · 9 unmodified lines | |||
| 10 | #include <linux/iommu.h> | 10 | #include <linux/iommu.h> |
| 11 | 11 | ||
| 12 | struct msm_mmu_funcs { | 12 | struct msm_mmu_funcs { |
| 13 | int (*attach)(struct msm_mmu *mmu); | ||
| 14 | void (*detach)(struct msm_mmu *mmu); | 13 | void (*detach)(struct msm_mmu *mmu); |
| 15 | int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, | 14 | int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, |
| 16 | unsigned len, int prot); | 15 | size_t len, int prot); |
| 17 | int (*unmap)(struct msm_mmu *mmu, uint64_t iova, unsigned len); | 16 | int (*unmap)(struct msm_mmu *mmu, uint64_t iova, size_t len); |
| 18 | void (*destroy)(struct msm_mmu *mmu); | 17 | void (*destroy)(struct msm_mmu *mmu); |
| 19 | }; | 18 | }; |
| 20 | 19 | ||
| @@ -29,8 +29,6 @@ · 28 unmodified lines | |||
| 29 | * or shader programs (if not emitted inline in cmdstream). | 29 | * or shader programs (if not emitted inline in cmdstream). |
| 30 | */ | 30 | */ |
| 31 | 31 | ||
| 32 | #ifdef CONFIG_DEBUG_FS | ||
| 33 | |||
| 34 | #include <linux/circ_buf.h> | 32 | #include <linux/circ_buf.h> |
| 35 | #include <linux/debugfs.h> | 33 | #include <linux/debugfs.h> |
| 36 | #include <linux/kfifo.h> | 34 | #include <linux/kfifo.h> |
| @@ -47,6 +45,8 @@ bool rd_full = false; · 10 unmodified lines | |||
| 47 | MODULE_PARM_DESC(rd_full, "If true, $debugfs/.../rd will snapshot all buffer contents"); | 45 | MODULE_PARM_DESC(rd_full, "If true, $debugfs/.../rd will snapshot all buffer contents"); |
| 48 | module_param_named(rd_full, rd_full, bool, 0600); | 46 | module_param_named(rd_full, rd_full, bool, 0600); |
| 49 | 47 | ||
| 48 | #ifdef CONFIG_DEBUG_FS | ||
| 49 | |||
| 50 | enum rd_sect_type { | 50 | enum rd_sect_type { |
| 51 | RD_NONE, | 51 | RD_NONE, |
| 52 | RD_TEST, /* ascii text */ | 52 | RD_TEST, /* ascii text */ |
| @@ -217,13 +217,28 @@ struct drm_msm_gem_submit_bo { · 216 unmodified lines | |||
| 217 | #define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ | 217 | #define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ |
| 218 | #define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ | 218 | #define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ |
| 219 | #define MSM_SUBMIT_SUDO 0x10000000 /* run submitted cmds from RB */ | 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 | #define MSM_SUBMIT_FLAGS ( \ | 222 | #define MSM_SUBMIT_FLAGS ( \ |
| 221 | MSM_SUBMIT_NO_IMPLICIT | \ | 223 | MSM_SUBMIT_NO_IMPLICIT | \ |
| 222 | MSM_SUBMIT_FENCE_FD_IN | \ | 224 | MSM_SUBMIT_FENCE_FD_IN | \ |
| 223 | MSM_SUBMIT_FENCE_FD_OUT | \ | 225 | MSM_SUBMIT_FENCE_FD_OUT | \ |
| 224 | MSM_SUBMIT_SUDO | \ | 226 | MSM_SUBMIT_SUDO | \ |
| 227 | MSM_SUBMIT_SYNCOBJ_IN | \ | ||
| 228 | MSM_SUBMIT_SYNCOBJ_OUT | \ | ||
| 225 | 0) | 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 | /* Each cmdstream submit consists of a table of buffers involved, and | 242 | /* Each cmdstream submit consists of a table of buffers involved, and |
| 228 | * one or more cmdstream buffers. This allows for conditional execution | 243 | * one or more cmdstream buffers. This allows for conditional execution |
| 229 | * (context-restore), and IB buffers needed for per tile/bin draw cmds. | 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 | __u64 bos; /* in, ptr to array of submit_bo's */ | 251 | __u64 bos; /* in, ptr to array of submit_bo's */ |
| 237 | __u64 cmds; /* in, ptr to array of submit_cmd's */ | 252 | __u64 cmds; /* in, ptr to array of submit_cmd's */ |
| 238 | __s32 fence_fd; /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */ | 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 | /* The normal way to synchronize with the GPU is just to CPU_PREP on | 264 | /* The normal way to synchronize with the GPU is just to CPU_PREP on |