Skip to content

Commit c6ed04f

Browse files
fltorobclark
authored andcommitted
drm/msm/a6xx: A640/A650 GMU firmware path
Newer GPUs have different GMU firmware path. v3: updated a6xx_gmu_fw_load based on feedback, including gmu_write_bulk, and removed extra whitespace change Signed-off-by: Jonathan Marek <[email protected]> Reviewed-by: Jordan Crouse <[email protected]> Signed-off-by: Rob Clark <[email protected]>
1 parent 8167e6f commit c6ed04f

File tree

3 files changed

+138
-16
lines changed

3 files changed

+138
-16
lines changed

drivers/gpu/drm/msm/adreno/a6xx_gmu.c

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,8 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu)
579579
{
580580
/* Disable GMU WB/RB buffer */
581581
gmu_write(gmu, REG_A6XX_GMU_SYS_BUS_CONFIG, 0x1);
582+
gmu_write(gmu, REG_A6XX_GMU_ICACHE_CONFIG, 0x1);
583+
gmu_write(gmu, REG_A6XX_GMU_DCACHE_CONFIG, 0x1);
582584

583585
gmu_write(gmu, REG_A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9c40400);
584586

@@ -608,14 +610,95 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu)
608610
A6XX_GMU_RPMH_CTRL_GFX_VOTE_ENABLE);
609611
}
610612

613+
struct block_header {
614+
u32 addr;
615+
u32 size;
616+
u32 type;
617+
u32 value;
618+
u32 data[];
619+
};
620+
621+
/* this should be a general kernel helper */
622+
static int in_range(u32 addr, u32 start, u32 size)
623+
{
624+
return addr >= start && addr < start + size;
625+
}
626+
627+
static bool fw_block_mem(struct a6xx_gmu_bo *bo, const struct block_header *blk)
628+
{
629+
if (!in_range(blk->addr, bo->iova, bo->size))
630+
return false;
631+
632+
memcpy(bo->virt + blk->addr - bo->iova, blk->data, blk->size);
633+
return true;
634+
}
635+
636+
static int a6xx_gmu_fw_load(struct a6xx_gmu *gmu)
637+
{
638+
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
639+
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
640+
const struct firmware *fw_image = adreno_gpu->fw[ADRENO_FW_GMU];
641+
const struct block_header *blk;
642+
u32 reg_offset;
643+
644+
u32 itcm_base = 0x00000000;
645+
u32 dtcm_base = 0x00040000;
646+
647+
if (adreno_is_a650(adreno_gpu))
648+
dtcm_base = 0x10004000;
649+
650+
if (gmu->legacy) {
651+
/* Sanity check the size of the firmware that was loaded */
652+
if (fw_image->size > 0x8000) {
653+
DRM_DEV_ERROR(gmu->dev,
654+
"GMU firmware is bigger than the available region\n");
655+
return -EINVAL;
656+
}
657+
658+
gmu_write_bulk(gmu, REG_A6XX_GMU_CM3_ITCM_START,
659+
(u32*) fw_image->data, fw_image->size);
660+
return 0;
661+
}
662+
663+
664+
for (blk = (const struct block_header *) fw_image->data;
665+
(const u8*) blk < fw_image->data + fw_image->size;
666+
blk = (const struct block_header *) &blk->data[blk->size >> 2]) {
667+
if (blk->size == 0)
668+
continue;
669+
670+
if (in_range(blk->addr, itcm_base, SZ_16K)) {
671+
reg_offset = (blk->addr - itcm_base) >> 2;
672+
gmu_write_bulk(gmu,
673+
REG_A6XX_GMU_CM3_ITCM_START + reg_offset,
674+
blk->data, blk->size);
675+
} else if (in_range(blk->addr, dtcm_base, SZ_16K)) {
676+
reg_offset = (blk->addr - dtcm_base) >> 2;
677+
gmu_write_bulk(gmu,
678+
REG_A6XX_GMU_CM3_DTCM_START + reg_offset,
679+
blk->data, blk->size);
680+
} else if (!fw_block_mem(&gmu->icache, blk) &&
681+
!fw_block_mem(&gmu->dcache, blk) &&
682+
!fw_block_mem(&gmu->dummy, blk)) {
683+
DRM_DEV_ERROR(gmu->dev,
684+
"failed to match fw block (addr=%.8x size=%d data[0]=%.8x)\n",
685+
blk->addr, blk->size, blk->data[0]);
686+
}
687+
}
688+
689+
return 0;
690+
}
691+
611692
static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
612693
{
613694
static bool rpmh_init;
614695
struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
615696
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
616-
int i, ret;
697+
int ret;
617698
u32 chipid;
618-
u32 *image;
699+
700+
if (adreno_is_a650(adreno_gpu))
701+
gmu_write(gmu, REG_A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF, 1);
619702

620703
if (state == GMU_WARM_BOOT) {
621704
ret = a6xx_rpmh_start(gmu);
@@ -626,13 +709,6 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
626709
"GMU firmware is not loaded\n"))
627710
return -ENOENT;
628711

629-
/* Sanity check the size of the firmware that was loaded */
630-
if (adreno_gpu->fw[ADRENO_FW_GMU]->size > 0x8000) {
631-
DRM_DEV_ERROR(gmu->dev,
632-
"GMU firmware is bigger than the available region\n");
633-
return -EINVAL;
634-
}
635-
636712
/* Turn on register retention */
637713
gmu_write(gmu, REG_A6XX_GMU_GENERAL_7, 1);
638714

@@ -646,11 +722,9 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
646722
return ret;
647723
}
648724

649-
image = (u32 *) adreno_gpu->fw[ADRENO_FW_GMU]->data;
650-
651-
for (i = 0; i < adreno_gpu->fw[ADRENO_FW_GMU]->size >> 2; i++)
652-
gmu_write(gmu, REG_A6XX_GMU_CM3_ITCM_START + i,
653-
image[i]);
725+
ret = a6xx_gmu_fw_load(gmu);
726+
if (ret)
727+
return ret;
654728
}
655729

656730
gmu_write(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, 0);
@@ -783,6 +857,13 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
783857
status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ?
784858
GMU_WARM_BOOT : GMU_COLD_BOOT;
785859

860+
/*
861+
* Warm boot path does not work on newer GPUs
862+
* Presumably this is because icache/dcache regions must be restored
863+
*/
864+
if (!gmu->legacy)
865+
status = GMU_COLD_BOOT;
866+
786867
ret = a6xx_gmu_fw_start(gmu, status);
787868
if (ret)
788869
goto out;
@@ -965,6 +1046,9 @@ static void a6xx_gmu_memory_free(struct a6xx_gmu *gmu)
9651046
{
9661047
msm_gem_kernel_put(gmu->hfi.obj, gmu->aspace, false);
9671048
msm_gem_kernel_put(gmu->debug.obj, gmu->aspace, false);
1049+
msm_gem_kernel_put(gmu->icache.obj, gmu->aspace, false);
1050+
msm_gem_kernel_put(gmu->dcache.obj, gmu->aspace, false);
1051+
msm_gem_kernel_put(gmu->dummy.obj, gmu->aspace, false);
9681052

9691053
gmu->aspace->mmu->funcs->detach(gmu->aspace->mmu);
9701054
msm_gem_address_space_put(gmu->aspace);
@@ -982,12 +1066,14 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo,
9821066
size = PAGE_ALIGN(size);
9831067
if (!iova) {
9841068
/* no fixed address - use GMU's uncached range */
985-
range_start = 0x60000000;
1069+
range_start = 0x60000000 + PAGE_SIZE; /* skip dummy page */
9861070
range_end = 0x80000000;
9871071
} else {
9881072
/* range for fixed address */
9891073
range_start = iova;
9901074
range_end = iova + size;
1075+
/* use IOMMU_PRIV for icache/dcache */
1076+
flags |= MSM_BO_MAP_PRIV;
9911077
}
9921078

9931079
bo->obj = msm_gem_new(dev, size, flags);
@@ -1328,7 +1414,27 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
13281414
if (ret)
13291415
goto err_put_device;
13301416

1331-
if (!adreno_is_a640(adreno_gpu) && !adreno_is_a650(adreno_gpu)) {
1417+
/* Allocate memory for the GMU dummy page */
1418+
ret = a6xx_gmu_memory_alloc(gmu, &gmu->dummy, SZ_4K, 0x60000000);
1419+
if (ret)
1420+
goto err_memory;
1421+
1422+
if (adreno_is_a650(adreno_gpu)) {
1423+
ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache,
1424+
SZ_16M - SZ_16K, 0x04000);
1425+
if (ret)
1426+
goto err_memory;
1427+
} else if (adreno_is_a640(adreno_gpu)) {
1428+
ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache,
1429+
SZ_256K - SZ_16K, 0x04000);
1430+
if (ret)
1431+
goto err_memory;
1432+
1433+
ret = a6xx_gmu_memory_alloc(gmu, &gmu->dcache,
1434+
SZ_256K - SZ_16K, 0x44000);
1435+
if (ret)
1436+
goto err_memory;
1437+
} else {
13321438
/* HFI v1, has sptprac */
13331439
gmu->legacy = true;
13341440

drivers/gpu/drm/msm/adreno/a6xx_gmu.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ struct a6xx_gmu {
5757

5858
struct a6xx_gmu_bo hfi;
5959
struct a6xx_gmu_bo debug;
60+
struct a6xx_gmu_bo icache;
61+
struct a6xx_gmu_bo dcache;
62+
struct a6xx_gmu_bo dummy;
6063

6164
int nr_clocks;
6265
struct clk_bulk_data *clocks;
@@ -92,6 +95,13 @@ static inline void gmu_write(struct a6xx_gmu *gmu, u32 offset, u32 value)
9295
return msm_writel(value, gmu->mmio + (offset << 2));
9396
}
9497

98+
static inline void
99+
gmu_write_bulk(struct a6xx_gmu *gmu, u32 offset, const u32 *data, u32 size)
100+
{
101+
memcpy_toio(gmu->mmio + (offset << 2), data, size);
102+
wmb();
103+
}
104+
95105
static inline void gmu_rmw(struct a6xx_gmu *gmu, u32 reg, u32 mask, u32 or)
96106
{
97107
u32 val = gmu_read(gmu, reg);

drivers/gpu/drm/msm/adreno/a6xx_gmu.xml.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ static inline uint32_t A6XX_HFI_IRQ_OOB_MASK(uint32_t val)
101101

102102
#define REG_A6XX_GMU_DCVS_RETURN 0x000023ff
103103

104+
#define REG_A6XX_GMU_ICACHE_CONFIG 0x00004c00
105+
106+
#define REG_A6XX_GMU_DCACHE_CONFIG 0x00004c01
107+
104108
#define REG_A6XX_GMU_SYS_BUS_CONFIG 0x00004c0f
105109

106110
#define REG_A6XX_GMU_CM3_SYSRESET 0x00005000
@@ -199,6 +203,8 @@ static inline uint32_t A6XX_GMU_GPU_NAP_CTRL_SID(uint32_t val)
199203

200204
#define REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE 0x000050ec
201205

206+
#define REG_A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF 0x000050f0
207+
202208
#define REG_A6XX_GMU_BOOT_KMD_LM_HANDSHAKE 0x000051f0
203209

204210
#define REG_A6XX_GMU_LLM_GLM_SLEEP_CTRL 0x00005157

0 commit comments

Comments
 (0)