Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b20e9b05 authored by Carter Cooper's avatar Carter Cooper
Browse files

msm: kgsl: Store GMU firmware image in the GMU device structure



Use the struct firmware structure for storing the GMU firmware image.
Parse the firmware until out of data rather than reading the number
of blocks present in the firmware.

Change-Id: I6d8aef7a088f26be7fd6f092eedbbe021bf76f77
Signed-off-by: default avatarCarter Cooper <ccooper@codeaurora.org>
parent a84db540
Loading
Loading
Loading
Loading
+34 −50
Original line number Diff line number Diff line
@@ -472,12 +472,6 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
	return 0;
}

/*
 * Gmu FW header format:
 * <32-bit start addr> <32-bit size> <32-bit pad0> <32-bit pad1> <Payload>
 */
#define GMU_FW_HEADER_SIZE 4

#define GMU_ITCM_VA_START 0x0
#define GMU_ITCM_VA_END   (GMU_ITCM_VA_START + 0x4000) /* 16 KB */

@@ -490,50 +484,52 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
static int load_gmu_fw(struct kgsl_device *device)
{
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	uint32_t *fwptr = gmu->fw_image->hostptr;
	int i, j;
	int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records;
	uint8_t *fw = (uint8_t *)gmu->fw_image->data;
	struct gmu_block_header *blk;
	uint32_t *fwptr;
	int j;
	int tcm_slot;

	while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) {
		blk = (struct gmu_block_header *)fw;
		fw += sizeof(*blk);

		/* Don't deal with zero size blocks */
		if (blk->size == 0)
			continue;

		if ((blk->addr >= GMU_ITCM_VA_START) &&
				(blk->addr < GMU_ITCM_VA_END)) {
			fwptr = (uint32_t *)fw;
			tcm_slot = (blk->addr - GMU_ITCM_VA_START)
				/ sizeof(uint32_t);

	/*
	 * Read first record. pad0 field of first record contains
	 * number of records in the image.
	 */
	num_records = fwptr[2];
	for (i = 0; i < num_records; i++) {
		start_addr = fwptr[0];
		size_in_bytes = fwptr[1];
		num_dwords = size_in_bytes / sizeof(uint32_t);
		fwptr += GMU_FW_HEADER_SIZE;

		if ((start_addr >= GMU_ITCM_VA_START) &&
				(start_addr < GMU_ITCM_VA_END)) {
			tcm_slot = start_addr / sizeof(uint32_t);

			for (j = 0; j < num_dwords; j++)
			for (j = 0; j < blk->size / sizeof(uint32_t); j++)
				gmu_core_regwrite(device,
					A6XX_GMU_CM3_ITCM_START + tcm_slot + j,
					fwptr[j]);
		} else if ((start_addr >= GMU_DTCM_VA_START) &&
				(start_addr < GMU_DTCM_VA_END)) {
			tcm_slot = (start_addr - GMU_DTCM_VA_START)
		} else if ((blk->addr >= GMU_DTCM_VA_START) &&
				(blk->addr < GMU_DTCM_VA_END)) {
			fwptr = (uint32_t *)fw;
			tcm_slot = (blk->addr - GMU_DTCM_VA_START)
				/ sizeof(uint32_t);

			for (j = 0; j < num_dwords; j++)
			for (j = 0; j < blk->size / sizeof(uint32_t); j++)
				gmu_core_regwrite(device,
					A6XX_GMU_CM3_DTCM_START + tcm_slot + j,
					fwptr[j]);
		} else if ((start_addr >= GMU_ICACHE_VA_START) &&
				(start_addr < GMU_ICACHE_VA_END)) {
			if (!is_cached_fw_size_valid(size_in_bytes)) {
		} else if ((blk->addr >= GMU_ICACHE_VA_START) &&
				(blk->addr < GMU_ICACHE_VA_END)) {
			if (!is_cached_fw_size_valid(blk->size)) {
				dev_err(&gmu->pdev->dev,
						"GMU firmware size too big\n");
				return -EINVAL;

			}
			memcpy(gmu->icache_mem->hostptr, fwptr, size_in_bytes);
			memcpy(gmu->icache_mem->hostptr, fw, blk->size);
		}

		fwptr += num_dwords;
		fw += blk->size;
	}

	/* Proceed only after the FW is written */
@@ -1044,11 +1040,10 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device,
 */
static int a6xx_gmu_load_firmware(struct kgsl_device *device)
{
	const struct firmware *fw = NULL;
	const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	const struct adreno_gpu_core *gpucore = adreno_dev->gpucore;
	int image_size, ret =  -EINVAL;
	int ret =  -EINVAL;

	/* there is no GMU */
	if (!gmu_core_isenabled(device))
@@ -1061,22 +1056,11 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device)
	if (gpucore->gpmufw_name == NULL)
		return -EINVAL;

	ret = request_firmware(&fw, gpucore->gpmufw_name, device->dev);
	if (ret || fw == NULL) {
	ret = request_firmware(&gmu->fw_image, gpucore->gpmufw_name,
			device->dev);
	if (ret || gmu->fw_image == NULL)
		KGSL_CORE_ERR("request_firmware (%s) failed: %d\n",
				gpucore->gpmufw_name, ret);
		return ret;
	}

	image_size = PAGE_ALIGN(fw->size);

	ret = allocate_gmu_image(gmu, image_size);

	/* load into shared memory with GMU */
	if (!ret)
		memcpy(gmu->fw_image->hostptr, fw->data, fw->size);

	release_firmware(fw);

	return ret;
}
+5 −21
Original line number Diff line number Diff line
@@ -235,26 +235,6 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu,
	return md;
}

/*
 * allocate_gmu_image() - allocates & maps memory for FW image, the size
 * shall come from the loaded f/w file.
 * @gmu: Pointer to GMU device
 * @size: Requested allocation size
 */
int allocate_gmu_image(struct gmu_device *gmu, unsigned int size)
{
	/* Allocates & maps memory for GMU FW */
	gmu->fw_image = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, size,
				(IOMMU_READ | IOMMU_PRIV));
	if (IS_ERR(gmu->fw_image)) {
		dev_err(&gmu->pdev->dev,
				"GMU firmware image allocation failed\n");
		return -EINVAL;
	}

	return 0;
}

/* Checks if cached fw code size falls within the cached code segment range */
bool is_cached_fw_size_valid(uint32_t size_in_bytes)
{
@@ -360,7 +340,6 @@ static void gmu_kmem_close(struct gmu_device *gmu)
	gmu->hfi_mem = NULL;
	gmu->bw_mem = NULL;
	gmu->dump_mem = NULL;
	gmu->fw_image = NULL;
	gmu->gmu_log = NULL;

	/* Unmap all memories in GMU kernel memory pool */
@@ -1629,6 +1608,11 @@ static void gmu_remove(struct kgsl_device *device)
		gmu->pcl = 0;
	}

	if (gmu->fw_image) {
		release_firmware(gmu->fw_image);
		gmu->fw_image = NULL;
	}

	gmu_memory_close(gmu);

	for (i = 0; i < MAX_GMU_CLKS; i++) {
+11 −3
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#define __KGSL_GMU_H

#include "kgsl_gmu_core.h"
#include <linux/firmware.h>
#include "kgsl_hfi.h"

#define MAX_GMUFW_SIZE	0x2000	/* in bytes */
@@ -55,6 +56,14 @@
#define OOB_BOOT_OPTION         0
#define OOB_SLUMBER_OPTION      1

/* Gmu FW block header format */
struct gmu_block_header {
	uint32_t addr;
	uint32_t size;
	uint32_t type;
	uint32_t value;
};

/* For GMU Logs*/
#define LOGMEM_SIZE  SZ_4K

@@ -112,7 +121,7 @@ enum gmu_load_mode {
 * @reg_phys: GMU CSR physical address
 * @reg_len: GMU CSR range
 * @gmu_interrupt_num: GMU interrupt number
 * @fw_image: descriptor of GMU memory that has GMU image in it
 * @fw_image: GMU FW image
 * @hfi_mem: pointer to HFI shared memory
 * @bw_mem: pointer to BW data indirect buffer memory
 * @dump_mem: pointer to GMU debug dump memory
@@ -148,7 +157,7 @@ struct gmu_device {
	unsigned long reg_phys;
	unsigned int reg_len;
	unsigned int gmu_interrupt_num;
	struct gmu_memdesc *fw_image;
	const struct firmware *fw_image;
	struct gmu_memdesc *hfi_mem;
	struct gmu_memdesc *bw_mem;
	struct gmu_memdesc *dump_mem;
@@ -177,6 +186,5 @@ struct gmu_device {
};

bool is_cached_fw_size_valid(uint32_t size_in_bytes);
int allocate_gmu_image(struct gmu_device *gmu, unsigned int size);

#endif /* __KGSL_GMU_H */