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

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

msm: kgsl: Add support for PDC register subsections



KGSL is required to program two subsections inside the PDC register
block. Map and write only the subsections that KGSL needs to program.
Use the GPU subsections definitions if they are present in the DT.
Otherwise try to determine the GPU subsections from the base
of the PDC register block.

Change-Id: I0ddc8748e497b74da5554ed70dd3179f5f11b4b3
Signed-off-by: default avatarCarter Cooper <ccooper@codeaurora.org>
parent cecc0b27
Loading
Loading
Loading
Loading
+33 −27
Original line number Diff line number Diff line
@@ -1058,33 +1058,39 @@
#define A6XX_RSCC_TCS3_DRV0_STATUS                      0x23B7E

/* GPU PDC sequencer registers in AOSS.RPMh domain */
#define	PDC_GPU_ENABLE_PDC			0x21140
#define PDC_GPU_SEQ_START_ADDR			0x21148
#define PDC_GPU_TCS0_CONTROL			0x21540
#define PDC_GPU_TCS0_CMD_ENABLE_BANK		0x21541
#define PDC_GPU_TCS0_CMD_WAIT_FOR_CMPL_BANK	0x21542
#define PDC_GPU_TCS0_CMD0_MSGID			0x21543
#define PDC_GPU_TCS0_CMD0_ADDR			0x21544
#define PDC_GPU_TCS0_CMD0_DATA			0x21545
#define PDC_GPU_TCS1_CONTROL			0x21572
#define PDC_GPU_TCS1_CMD_ENABLE_BANK		0x21573
#define PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK	0x21574
#define PDC_GPU_TCS1_CMD0_MSGID			0x21575
#define PDC_GPU_TCS1_CMD0_ADDR			0x21576
#define PDC_GPU_TCS1_CMD0_DATA			0x21577
#define PDC_GPU_TCS2_CONTROL			0x215A4
#define PDC_GPU_TCS2_CMD_ENABLE_BANK		0x215A5
#define PDC_GPU_TCS2_CMD_WAIT_FOR_CMPL_BANK	0x215A6
#define PDC_GPU_TCS2_CMD0_MSGID			0x215A7
#define PDC_GPU_TCS2_CMD0_ADDR			0x215A8
#define PDC_GPU_TCS2_CMD0_DATA			0x215A9
#define PDC_GPU_TCS3_CONTROL			0x215D6
#define PDC_GPU_TCS3_CMD_ENABLE_BANK		0x215D7
#define PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK	0x215D8
#define PDC_GPU_TCS3_CMD0_MSGID			0x215D9
#define PDC_GPU_TCS3_CMD0_ADDR			0x215DA
#define PDC_GPU_TCS3_CMD0_DATA			0x215DB
#define PDC_GPU_SEQ_MEM_0			0xA0000
#define PDC_GPU_ENABLE_PDC			0x1140
#define PDC_GPU_SEQ_START_ADDR			0x1148
#define PDC_GPU_TCS0_CONTROL			0x1540
#define PDC_GPU_TCS0_CMD_ENABLE_BANK		0x1541
#define PDC_GPU_TCS0_CMD_WAIT_FOR_CMPL_BANK	0x1542
#define PDC_GPU_TCS0_CMD0_MSGID			0x1543
#define PDC_GPU_TCS0_CMD0_ADDR			0x1544
#define PDC_GPU_TCS0_CMD0_DATA			0x1545
#define PDC_GPU_TCS1_CONTROL			0x1572
#define PDC_GPU_TCS1_CMD_ENABLE_BANK		0x1573
#define PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK	0x1574
#define PDC_GPU_TCS1_CMD0_MSGID			0x1575
#define PDC_GPU_TCS1_CMD0_ADDR			0x1576
#define PDC_GPU_TCS1_CMD0_DATA			0x1577
#define PDC_GPU_TCS2_CONTROL			0x15A4
#define PDC_GPU_TCS2_CMD_ENABLE_BANK		0x15A5
#define PDC_GPU_TCS2_CMD_WAIT_FOR_CMPL_BANK	0x15A6
#define PDC_GPU_TCS2_CMD0_MSGID			0x15A7
#define PDC_GPU_TCS2_CMD0_ADDR			0x15A8
#define PDC_GPU_TCS2_CMD0_DATA			0x15A9
#define PDC_GPU_TCS3_CONTROL			0x15D6
#define PDC_GPU_TCS3_CMD_ENABLE_BANK		0x15D7
#define PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK	0x15D8
#define PDC_GPU_TCS3_CMD0_MSGID			0x15D9
#define PDC_GPU_TCS3_CMD0_ADDR			0x15DA
#define PDC_GPU_TCS3_CMD0_DATA			0x15DB

/*
 * Legacy DTSI used an offset from the start of the PDC resource
 * for PDC SEQ programming. We are now using PDC subsections so
 * start the PDC SEQ offset at zero.
 */
#define PDC_GPU_SEQ_MEM_0			0x0

#endif /* _A6XX_REG_H */
+111 −56
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include <linux/firmware.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_platform.h>

#include "kgsl_gmu_core.h"
#include "kgsl_gmu.h"
@@ -79,10 +81,70 @@ static void _regwrite(void __iomem *regbase,
 * PDC and RSC execute GPU power on/off RPMh sequence
 * @device: Pointer to KGSL device
 */
static void _load_gmu_rpmh_ucode(struct kgsl_device *device)
static int _load_gmu_rpmh_ucode(struct kgsl_device *device)
{
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct resource *res_pdc, *res_cfg, *res_seq;
	void __iomem *cfg = NULL, *seq = NULL;
	unsigned int cfg_offset, seq_offset;

	/* Offsets from the base PDC (if no PDC subsections in the DTSI) */
	if (adreno_is_a640v2(adreno_dev)) {
		cfg_offset = 0x90000;
		seq_offset = 0x290000;
	} else {
		cfg_offset = 0x80000;
		seq_offset = 0x280000;
	}

	/*
	 * Older A6x platforms specified PDC registers in the DT using a
	 * single base pointer that encompassed the entire PDC range. Current
	 * targets specify the individual GPU-owned PDC register blocks
	 * (sequence and config).
	 *
	 * This code handles both possibilities and generates individual
	 * pointers to the GPU PDC blocks, either as offsets from the single
	 * base, or as directly specified ranges.
	 */

	/* Get pointers to each of the possible PDC resources */
	res_pdc = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
			"kgsl_gmu_pdc_reg");
	res_cfg = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
			"kgsl_gmu_pdc_cfg");
	res_seq = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
			"kgsl_gmu_pdc_seq");

	/*
	 * Map the starting address for pdc_cfg programming. If the pdc_cfg
	 * resource is not available use an offset from the base PDC resource.
	 */
	if (res_cfg)
		cfg = ioremap(res_cfg->start, resource_size(res_cfg));
	else if (res_pdc)
		cfg = ioremap(res_pdc->start + cfg_offset, 0x10000);

	if (!cfg) {
		dev_err(&gmu->pdev->dev, "Failed to map PDC CFG\n");
		return -ENODEV;
	}

	/*
	 * Map the starting address for pdc_seq programming. If the pdc_seq
	 * resource is not available use an offset from the base PDC resource.
	 */
	if (res_seq)
		seq = ioremap(res_seq->start, resource_size(res_seq));
	else if (res_pdc)
		seq = ioremap(res_pdc->start + seq_offset, 0x10000);

	if (!seq) {
		dev_err(&gmu->pdev->dev, "Failed to map PDC SEQ\n");
		iounmap(cfg);
		return -ENODEV;
	}

	/* Disable SDE clock gating */
	gmu_core_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24));
@@ -118,68 +180,62 @@ static void _load_gmu_rpmh_ucode(struct kgsl_device *device)
	gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8);

	/* Load PDC sequencer uCode for power up and power down sequence */
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 1, 0xA5A4A3A2);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 2, 0x8382A6E0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 3, 0xBCE3E284);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 4, 0x002081FC);
	_regwrite(seq, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1);
	_regwrite(seq, PDC_GPU_SEQ_MEM_0 + 1, 0xA5A4A3A2);
	_regwrite(seq, PDC_GPU_SEQ_MEM_0 + 2, 0x8382A6E0);
	_regwrite(seq, PDC_GPU_SEQ_MEM_0 + 3, 0xBCE3E284);
	_regwrite(seq, PDC_GPU_SEQ_MEM_0 + 4, 0x002081FC);

	/* Set TCS commands used by PDC sequence for low power modes */
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_ENABLE_BANK, 7);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK, 0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CONTROL, 0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_MSGID, 0x10108);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_ADDR, 0x30010);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_DATA, 1);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET, 0x0);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108);
	_regwrite(cfg, PDC_GPU_TCS1_CMD_ENABLE_BANK, 7);
	_regwrite(cfg, PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK, 0);
	_regwrite(cfg, PDC_GPU_TCS1_CONTROL, 0);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_MSGID, 0x10108);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_ADDR, 0x30010);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_DATA, 1);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET, 0x0);
	_regwrite(cfg, PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108);

	if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev))
		_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30090);
		_regwrite(cfg, PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2,
				0x30090);
	else
		_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080);

	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_ENABLE_BANK, 7);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK, 0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CONTROL, 0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_MSGID, 0x10108);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_ADDR, 0x30010);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_DATA, 2);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3);
	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108);
		_regwrite(cfg, PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2,
				0x30080);

	_regwrite(cfg, PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x0);
	_regwrite(cfg, PDC_GPU_TCS3_CMD_ENABLE_BANK, 7);
	_regwrite(cfg, PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK, 0);
	_regwrite(cfg, PDC_GPU_TCS3_CONTROL, 0);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_MSGID, 0x10108);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_ADDR, 0x30010);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_DATA, 2);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108);

	if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev))
		_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30090);
		_regwrite(cfg, PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2,
				0x30090);
	else
		_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080);

	_regwrite(gmu->pdc_reg_virt,
			PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x3);
		_regwrite(cfg, PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2,
				0x30080);
	_regwrite(cfg, PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x3);

	/* Setup GPU PDC */
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_START_ADDR, 0);
	_regwrite(gmu->pdc_reg_virt, PDC_GPU_ENABLE_PDC, 0x80000001);
	_regwrite(cfg, PDC_GPU_SEQ_START_ADDR, 0);
	_regwrite(cfg, PDC_GPU_ENABLE_PDC, 0x80000001);

	/* ensure no writes happen before the uCode is fully written */
	wmb();

	iounmap(seq);
	iounmap(cfg);

	return 0;
}

/* GMU timeouts */
@@ -900,12 +956,11 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device,
		gmu_core_regwrite(device, A6XX_GMU_GENERAL_7, 1);

		if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags))
			_load_gmu_rpmh_ucode(device);
		else {
			ret = _load_gmu_rpmh_ucode(device);
		else
			ret = a6xx_rpmh_power_on_gpu(device);
		if (ret)
			return ret;
		}

		if (gmu->load_mode == TCM_BOOT) {
			/* Load GMU image via AHB bus */
+14 −32
Original line number Diff line number Diff line
@@ -1076,44 +1076,35 @@ static int gmu_pwrlevel_probe(struct gmu_device *gmu, struct device_node *node)
	return 0;
}

static int gmu_reg_probe(struct gmu_device *gmu, const char *name, bool is_gmu)
static int gmu_reg_probe(struct gmu_device *gmu)
{
	struct resource *res;

	res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM, name);
	res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
			"kgsl_gmu_reg");
	if (res == NULL) {
		dev_err(&gmu->pdev->dev,
				"platform_get_resource %s failed\n", name);
			"platform_get_resource kgsl_gmu_reg failed\n");
		return -EINVAL;
	}

	if (res->start == 0 || resource_size(res) == 0) {
		dev_err(&gmu->pdev->dev,
				"dev %d %s invalid register region\n",
				gmu->pdev->dev.id, name);
				"dev %d kgsl_gmu_reg invalid register region\n",
				gmu->pdev->dev.id);
		return -EINVAL;
	}

	if (is_gmu) {
	gmu->reg_phys = res->start;
	gmu->reg_len = resource_size(res);

	gmu->reg_virt = devm_ioremap(&gmu->pdev->dev, res->start,
			resource_size(res));

	if (gmu->reg_virt == NULL) {
			dev_err(&gmu->pdev->dev, "GMU regs ioremap failed\n");
		dev_err(&gmu->pdev->dev, "kgsl_gmu_reg ioremap failed\n");
		return -ENODEV;
	}

	} else {
		gmu->pdc_reg_virt = devm_ioremap(&gmu->pdev->dev, res->start,
				resource_size(res));
		if (gmu->pdc_reg_virt == NULL) {
			dev_err(&gmu->pdev->dev, "PDC regs ioremap failed\n");
			return -ENODEV;
		}
	}

	return 0;
}

@@ -1314,11 +1305,7 @@ static int gmu_probe(struct kgsl_device *device,
	mem_addr = gmu->hfi_mem;

	/* Map and reserve GMU CSRs registers */
	ret = gmu_reg_probe(gmu, "kgsl_gmu_reg", true);
	if (ret)
		goto error;

	ret = gmu_reg_probe(gmu, "kgsl_gmu_pdc_reg", false);
	ret = gmu_reg_probe(gmu);
	if (ret)
		goto error;

@@ -1740,11 +1727,6 @@ static void gmu_remove(struct kgsl_device *device)
		gmu->pcl = 0;
	}

	if (gmu->pdc_reg_virt) {
		devm_iounmap(&gmu->pdev->dev, gmu->pdc_reg_virt);
		gmu->pdc_reg_virt = NULL;
	}

	if (gmu->reg_virt) {
		devm_iounmap(&gmu->pdev->dev, gmu->reg_virt);
		gmu->reg_virt = NULL;
+0 −2
Original line number Diff line number Diff line
@@ -105,7 +105,6 @@ enum gmu_load_mode {
 * @reg_phys: GMU CSR physical address
 * @reg_virt: GMU CSR virtual address
 * @reg_len: GMU CSR range
 * @pdc_reg_virt: starting kernel virtual address for RPMh PDC registers
 * @gmu_interrupt_num: GMU interrupt number
 * @fw_image: descriptor of GMU memory that has GMU image in it
 * @hfi_mem: pointer to HFI shared memory
@@ -142,7 +141,6 @@ struct gmu_device {
	unsigned long reg_phys;
	void __iomem *reg_virt;
	unsigned int reg_len;
	void __iomem *pdc_reg_virt;
	unsigned int gmu_interrupt_num;
	struct gmu_memdesc cached_fw_image;
	struct gmu_memdesc *fw_image;