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

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

msm: kgsl: Get GMU version information from FW image



The GMU FW now contains version information in the block headers.
Save this data from the FW image to easily identify what GMU
FW image is being used.

Change-Id: I15ba738311ae39824a0b0a469e54865711fcd0c3
Signed-off-by: default avatarCarter Cooper <ccooper@codeaurora.org>
parent 42860985
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 */

#ifndef _A6XX_REG_H
@@ -994,6 +994,7 @@
#define A6XX_GMU_HOST2GMU_INTR_INFO_1		0x1F99C
#define A6XX_GMU_HOST2GMU_INTR_INFO_2		0x1F99D
#define A6XX_GMU_HOST2GMU_INTR_INFO_3		0x1F99E
#define A6XX_GMU_GENERAL_0			0x1F9C5
#define A6XX_GMU_GENERAL_1			0x1F9C6
#define A6XX_GMU_GENERAL_6			0x1F9CB
#define A6XX_GMU_GENERAL_7			0x1F9CC
+65 −13
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/firmware.h>
@@ -554,12 +554,6 @@ static int a6xx_gmu_oob_set(struct kgsl_device *device,
		set = BIT(30 - req * 2);
		check = BIT(31 - req);

		if ((gmu->hfi.version & 0x1F) == 0) {
			/* LEGACY for intermediate oobs */
			set = BIT(req + 16);
			check = BIT(req + 16);
		}

		if (req >= 6) {
			dev_err(&gmu->pdev->dev,
					"OOB_set(0x%x) invalid\n", set);
@@ -610,9 +604,6 @@ static inline void a6xx_gmu_oob_clear(struct kgsl_device *device,
					"OOB_clear(0x%x) invalid\n", clear);
			return;
		}
		/* LEGACY for intermediate oobs */
		if ((gmu->hfi.version & 0x1F) == 0)
			clear = BIT(req + 24);
	} else
		clear = BIT(req + 24);

@@ -1046,6 +1037,10 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device,
			return ret;
	}

	/* Read the HFI and Power version from registers */
	gmu_core_regread(device, A6XX_GMU_HFI_VERSION_INFO, &gmu->ver.hfi);
	gmu_core_regread(device, A6XX_GMU_GENERAL_0, &gmu->ver.pwr);

	ret = a6xx_gmu_hfi_start(device);
	if (ret)
		return ret;
@@ -1064,7 +1059,8 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device)
	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 ret =  -EINVAL;
	struct gmu_block_header *blk;
	int ret, offset = 0;

	/* there is no GMU */
	if (!gmu_core_isenabled(device))
@@ -1079,13 +1075,69 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device)

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

		return ret;
	}

	/*
	 * Zero payload fw blocks contain meta data and are
	 * guaranteed to precede fw load data. Parse the
	 * meta data blocks.
	 */
	while (offset < gmu->fw_image->size) {
		blk = (struct gmu_block_header *)&gmu->fw_image->data[offset];

		if (offset + sizeof(*blk) > gmu->fw_image->size) {
			dev_err(&gmu->pdev->dev, "Invalid FW Block\n");
			return -EINVAL;
		}

		/* Done with zero length blocks so return */
		if (blk->size)
			break;

		offset += sizeof(*blk);

		switch (blk->type) {
		case GMU_BLK_TYPE_CORE_VER:
			gmu->ver.core = blk->value;
			dev_dbg(&gmu->pdev->dev,
					"CORE VER: 0x%8.8x\n", blk->value);
			break;
		case GMU_BLK_TYPE_CORE_DEV_VER:
			gmu->ver.core_dev = blk->value;
			dev_dbg(&gmu->pdev->dev,
					"CORE DEV VER: 0x%8.8x\n", blk->value);
			break;
		case GMU_BLK_TYPE_PWR_VER:
			gmu->ver.pwr = blk->value;
			dev_dbg(&gmu->pdev->dev,
					"PWR VER: 0x%8.8x\n", blk->value);
			break;
		case GMU_BLK_TYPE_PWR_DEV_VER:
			gmu->ver.pwr_dev = blk->value;
			dev_dbg(&gmu->pdev->dev,
					"PWR DEV VER: 0x%8.8x\n", blk->value);
			break;
		case GMU_BLK_TYPE_HFI_VER:
			gmu->ver.hfi = blk->value;
			dev_dbg(&gmu->pdev->dev,
					"HFI VER: 0x%8.8x\n", blk->value);
			break;
		/* Skip preallocation requests for now */
		case GMU_BLK_TYPE_PREALLOC_REQ:
		case GMU_BLK_TYPE_PREALLOC_PERSIST_REQ:

		default:
			break;
		}
	}

	return 0;
}

#define A6XX_STATE_OF_CHILD             (BIT(4) | BIT(5))
#define A6XX_IDLE_FULL_LLM              BIT(0)
#define A6XX_WAKEUP_ACK                 BIT(1)
+0 −1
Original line number Diff line number Diff line
@@ -1304,7 +1304,6 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	device->gmu_core.ptr = (void *)gmu;
	hfi = &gmu->hfi;
	gmu->load_mode = TCM_BOOT;
	gmu->ver = ~0U;

	gmu->pdev = of_find_device_by_node(node);
	of_dma_configure(&gmu->pdev->dev, node, true);
+24 −2
Original line number Diff line number Diff line
@@ -14,6 +14,12 @@

#define BWMEM_SIZE	(12 + (4 * NUM_BW_LEVELS))	/*in bytes*/

#define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF)
#define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF)
#define GMU_VER_STEP(ver) ((ver) & 0xFFFF)
#define GMU_VERSION(major, minor) \
	((((major) & 0xF) << 28) | (((minor) & 0xFFF) << 16))

#define GMU_INT_WDOG_BITE		BIT(0)
#define GMU_INT_RSCC_COMP		BIT(1)
#define GMU_INT_FENCE_ERR		BIT(3)
@@ -57,6 +63,16 @@ struct gmu_block_header {
	uint32_t value;
};

/* GMU Block types */
#define GMU_BLK_TYPE_DATA 0
#define GMU_BLK_TYPE_PREALLOC_REQ 1
#define GMU_BLK_TYPE_CORE_VER 2
#define GMU_BLK_TYPE_CORE_DEV_VER 3
#define GMU_BLK_TYPE_PWR_VER 4
#define GMU_BLK_TYPE_PWR_DEV_VER 5
#define GMU_BLK_TYPE_HFI_VER 6
#define GMU_BLK_TYPE_PREALLOC_PERSIST_REQ 7

/* For GMU Logs*/
#define LOGMEM_SIZE  SZ_4K

@@ -120,7 +136,7 @@ struct kgsl_mailbox {

/**
 * struct gmu_device - GMU device structure
 * @ver: GMU FW version, read from GMU
 * @ver: GMU Version information
 * @reg_phys: GMU CSR physical address
 * @reg_len: GMU CSR range
 * @gmu_interrupt_num: GMU interrupt number
@@ -154,7 +170,13 @@ struct kgsl_mailbox {
 * @mailbox: Messages to AOP for ACD enable/disable go through this
 */
struct gmu_device {
	unsigned int ver;
	struct {
		u32 core;
		u32 core_dev;
		u32 pwr;
		u32 pwr_dev;
		u32 hfi;
	} ver;
	struct platform_device *pdev;
	unsigned long reg_phys;
	unsigned int reg_len;
+7 −24
Original line number Diff line number Diff line
@@ -31,14 +31,6 @@
#define CMD_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_CMD)
#define ACK_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_ACK)

#define HFI_VER_MAJOR(hfi) (((hfi)->version >> 28) & 0xF)
#define HFI_VER_MINOR(hfi) (((hfi)->version >> 5) & 0x7FFFFF)
#define HFI_VER_BRANCH(hfi) ((hfi)->version & 0x1F)
#define HFI_VERSION(major, minor, branch) \
	((((major) & 0xF) << 28) | \
	 (((minor) & 0x7FFFFF) << 5) | \
	 ((branch) & 0x1F))

static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx,
	struct pending_cmd *ret_cmd);

@@ -95,7 +87,7 @@ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx,
		result = -ENODATA;
	}

	if (HFI_VER_MAJOR(&gmu->hfi) >= 2)
	if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2)
		read = ALIGN(read, SZ_4) % hdr->queue_size;

	hdr->read_index = read;
@@ -154,7 +146,7 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
	}

	/* Cookify any non used data at the end of the write buffer */
	if (HFI_VER_MAJOR(&gmu->hfi) >= 2) {
	if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2) {
		for (; write % 4; write = (write + 1) % hdr->queue_size)
			queue[write] = 0xFAFAFAFA;
	}
@@ -586,7 +578,7 @@ static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx,

	while (hfi_queue_read(gmu, queue_idx, rcvd, sizeof(rcvd)) > 0) {
		/* Special case if we're v1 */
		if (HFI_VER_MAJOR(&gmu->hfi) < 2) {
		if (GMU_VER_MAJOR(gmu->ver.hfi) < 2) {
			hfi_v1_receiver(gmu, rcvd, ret_cmd);
			continue;
		}
@@ -620,11 +612,6 @@ void hfi_receiver(unsigned long data)
	hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL);
}

#define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF)
#define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF)
#define GMU_VERSION(major, minor) \
	((((major) & 0xF) << 28) | (((minor) & 0xFFF) << 16))

static int hfi_verify_fw_version(struct kgsl_device *device,
		struct gmu_device *gmu)
{
@@ -633,13 +620,9 @@ static int hfi_verify_fw_version(struct kgsl_device *device,
	unsigned int ver, major, minor;

	/* GMU version is already known, so don't waste time finding again */
	if (gmu->ver != ~0U)
	if (gmu->ver.core != 0)
		return 0;

	/* Read the HFI version from the register */
	adreno_read_gmureg(adreno_dev,
		ADRENO_REG_GMU_HFI_VERSION_INFO, &gmu->hfi.version);

	major = adreno_dev->gpucore->gpmu_major;
	minor = adreno_dev->gpucore->gpmu_minor;

@@ -662,7 +645,7 @@ static int hfi_verify_fw_version(struct kgsl_device *device,
				GMU_VER_MINOR(ver), minor);

	/* Save the gmu version information */
	gmu->ver = ver;
	gmu->ver.core = ver;

	return 0;
}
@@ -717,7 +700,7 @@ int hfi_start(struct kgsl_device *device,
	if (result)
		return result;

	if (HFI_VER_MAJOR(&gmu->hfi) < 2)
	if (GMU_VER_MAJOR(gmu->ver.hfi) < 2)
		result = hfi_send_dcvstbl_v1(gmu);
	else
		result = hfi_send_dcvstbl(gmu);
@@ -733,7 +716,7 @@ int hfi_start(struct kgsl_device *device,
	 * we are sending no more HFIs until the next boot otherwise
	 * send H2F_MSG_CORE_FW_START and features for A640 devices
	 */
	if (HFI_VER_MAJOR(&gmu->hfi) >= 2) {
	if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2) {
		if (ADRENO_FEATURE(adreno_dev, ADRENO_ECP)) {
			result = hfi_send_feature_ctrl(gmu,
					HFI_FEATURE_ECP, 1, 0);
Loading