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

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

msm: kgsl: Add GMU feature flag support



There are many different flavors of GMU/GPMU out there
and more coming in the near future. Split and define
what these features are. These feature flags come in very
handy when trying to figure out what the device is capable
of and what the device is configured to do (ie device tree
and adreno flag combinations).

Change-Id: I8d11029ca0c85e855ed6c3de911481ee79928387
Signed-off-by: default avatarCarter Cooper <ccooper@codeaurora.org>
parent 1cedbaf9
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -1118,6 +1118,7 @@ static int adreno_probe(struct platform_device *pdev)
	struct kgsl_device *device;
	struct adreno_device *adreno_dev;
	int status;
	unsigned long flags;

	adreno_dev = adreno_get_dev(pdev);

@@ -1148,8 +1149,10 @@ static int adreno_probe(struct platform_device *pdev)
	 * Another part of GPU power probe in platform_probe
	 * needs GMU initialized.
	 */
	status = gmu_probe(device);
	if (status != 0 && status != -ENXIO) {
	flags = ADRENO_FEATURE(adreno_dev, ADRENO_GPMU) ? BIT(GMU_GPMU) : 0;

	status = gmu_probe(device, flags);
	if (status) {
		device->pdev = NULL;
		return status;
	}
@@ -1484,7 +1487,7 @@ static bool regulators_left_on(struct kgsl_device *device)
{
	int i;

	if (kgsl_gmu_isenabled(device))
	if (kgsl_gmu_gpmu_isenabled(device))
		return false;

	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
+8 −6
Original line number Diff line number Diff line
@@ -1674,10 +1674,10 @@ static inline void a6xx_gpu_keepalive(struct adreno_device *adreno_dev,
static int a6xx_sptprac_enable(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct gmu_device *gmu = &device->gmu;

	if (!gmu->pdev)
	if (!kgsl_gmu_gpmu_isenabled(device))
		return -EINVAL;

	if (!adreno_has_sptprac_gdsc(adreno_dev))
		return 0;

@@ -1689,7 +1689,7 @@ static int a6xx_sptprac_enable(struct adreno_device *adreno_dev)
			SPTPRAC_POWERON_STATUS_MASK,
			SPTPRAC_CTRL_TIMEOUT,
			SPTPRAC_POWERON_STATUS_MASK)) {
		dev_err(&gmu->pdev->dev, "power on SPTPRAC fail\n");
		dev_err(&device->gmu.pdev->dev, "power on SPTPRAC fail\n");
		return -EINVAL;
	}

@@ -1703,9 +1703,11 @@ static int a6xx_sptprac_enable(struct adreno_device *adreno_dev)
static void a6xx_sptprac_disable(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct gmu_device *gmu = &device->gmu;

	if (!gmu->pdev || !adreno_has_sptprac_gdsc(adreno_dev))
	if (!adreno_has_sptprac_gdsc(adreno_dev))
		return;

	if (!kgsl_gmu_gpmu_isenabled(device))
		return;

	/* Ensure that retention is on */
@@ -1720,7 +1722,7 @@ static void a6xx_sptprac_disable(struct adreno_device *adreno_dev)
			SPTPRAC_POWEROFF_STATUS_MASK,
			SPTPRAC_CTRL_TIMEOUT,
			SPTPRAC_POWEROFF_STATUS_MASK))
		dev_err(&gmu->pdev->dev, "power off SPTPRAC fail\n");
		dev_err(&device->gmu.pdev->dev, "power off SPTPRAC fail\n");
}

#define SPTPRAC_POWER_OFF	BIT(2)
+29 −22
Original line number Diff line number Diff line
@@ -104,25 +104,6 @@ struct gmu_iommu_context gmu_ctx[] = {
static struct gmu_memdesc gmu_kmem_entries[GMU_KERNEL_ENTRIES];
static unsigned long gmu_kmem_bitmap;

/*
 * kgsl_gmu_isenabled() - Check if there is a GMU and it is enabled
 * @device: Pointer to the KGSL device that owns the GMU
 *
 * Check if a GMU has been found and successfully probed. Also
 * check that the feature flag to use a GMU is enabled. Returns
 * true if both of these conditions are met, otherwise false.
 */
bool kgsl_gmu_isenabled(struct kgsl_device *device)
{
	struct gmu_device *gmu = &device->gmu;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	if (!nogmu && gmu->pdev &&
		ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
		return true;
	return false;
}

static int _gmu_iommu_fault_handler(struct device *dev,
		unsigned long addr, int flags, const char *name)
{
@@ -1177,7 +1158,7 @@ static void gmu_irq_disable(struct kgsl_device *device)
}

/* Do not access any GMU registers in GMU probe function */
int gmu_probe(struct kgsl_device *device)
int gmu_probe(struct kgsl_device *device, unsigned long flags)
{
	struct device_node *node;
	struct gmu_device *gmu = &device->gmu;
@@ -1191,11 +1172,22 @@ int gmu_probe(struct kgsl_device *device)
	gmu->flags = 0;
	gmu->ver = ~0U;

	/* Normalize flags for input feature requests */
	flags &= BIT(GMU_GPMU);

	node = of_find_compatible_node(device->pdev->dev.of_node,
			NULL, "qcom,gpu-gmu");
	/* No GMU in dt, no worries...hopefully */
	if (node == NULL) {
		/* If we are trying to use GPMU and no GMU, that's bad */
		if (flags & BIT(GMU_GPMU))
			return -ENXIO;
		/* Otherwise it's ok and nothing to do */
		return 0;
	}

	if (node == NULL)
		return ret;
	/* Ok, now say the flags are enabled */
	gmu->flags = flags;

	device->gmu.pdev = of_find_device_by_node(node);

@@ -1284,6 +1276,8 @@ int gmu_probe(struct kgsl_device *device)

	/* disable LM during boot time */
	clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag);
	set_bit(GMU_ENABLED, &gmu->flags);

	return 0;

error:
@@ -1690,9 +1684,22 @@ void gmu_remove(struct kgsl_device *device)
		gmu->cx_gdsc = NULL;
	}

	device->gmu.flags = 0;
	device->gmu.pdev = NULL;
}

/* Check if GPMU is in charge of power features */
bool kgsl_gmu_gpmu_isenabled(struct kgsl_device *device)
{
	return test_bit(GMU_GPMU, &(device->gmu.flags));
}

/* Check if GMU is enabled. Only set once GMU is fully initialized */
bool kgsl_gmu_isenabled(struct kgsl_device *device)
{
	return !nogmu && test_bit(GMU_ENABLED, &device->gmu.flags);
}

/*
 * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled
 * @adreno_dev: Pointer to the Adreno device device that owns the GMU
+12 −6
Original line number Diff line number Diff line
@@ -93,10 +93,12 @@ enum oob_request {
/* Bits for the flags field in the gmu structure */
enum gmu_flags {
	GMU_BOOT_INIT_DONE = 0,
	GMU_CLK_ON = 1,
	GMU_HFI_ON = 2,
	GMU_FAULT = 3,
	GMU_DCVS_REPLAY = 4,
	GMU_CLK_ON,
	GMU_HFI_ON,
	GMU_FAULT,
	GMU_DCVS_REPLAY,
	GMU_GPMU,
	GMU_ENABLED,
};

/**
@@ -202,7 +204,7 @@ enum gpu_idle_level {
 * @gx_gdsc: GX headswitch that controls power of GPU subsystem
 * @clks: GPU subsystem clocks required for GMU functionality
 * @load_mode: GMU FW load/boot mode
 * @flags: GMU power control flags
 * @flags: GMU flags
 * @wakeup_pwrlevel: GPU wake up power/DCVS level in case different
 *		than default power level
 * @pcl: GPU BW scaling client
@@ -246,9 +248,13 @@ struct gmu_device {
	unsigned int fault_count;
};

struct kgsl_device;
void gmu_snapshot(struct kgsl_device *device);

bool kgsl_gmu_gpmu_isenabled(struct kgsl_device *device);
bool kgsl_gmu_isenabled(struct kgsl_device *device);
int gmu_probe(struct kgsl_device *device);

int gmu_probe(struct kgsl_device *device, unsigned long flags);
void gmu_remove(struct kgsl_device *device);
int allocate_gmu_image(struct gmu_device *gmu, unsigned int size);
int gmu_start(struct kgsl_device *device);
+14 −7
Original line number Diff line number Diff line
@@ -225,6 +225,10 @@ static int kgsl_bus_scale_request(struct kgsl_device *device,
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int ret = 0;

	/* GMU scales BW */
	if (kgsl_gmu_gpmu_isenabled(device))
		return 0;

	if (pwr->pcl) {
		/* Linux bus driver scales BW */
		ret = msm_bus_scale_client_update_request(pwr->pcl, buslevel);
@@ -250,7 +254,7 @@ int kgsl_clk_set_rate(struct kgsl_device *device,
	int ret = 0;

	/* GMU scales GPU freq */
	if (kgsl_gmu_isenabled(device)) {
	if (kgsl_gmu_gpmu_isenabled(device)) {
		/* If GMU has not been started, save it */
		if (!test_bit(GMU_HFI_ON, &gmu->flags)) {
			/* store clock change request */
@@ -1697,7 +1701,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int i = 0;

	if (kgsl_gmu_isenabled(device))
	if (kgsl_gmu_gpmu_isenabled(device))
		return;
	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->ctrl_flags))
		return;
@@ -1807,6 +1811,9 @@ static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
{
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;

	if (kgsl_gmu_gpmu_isenabled(device))
		return;

	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags))
		return;

@@ -1873,7 +1880,7 @@ static int kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	int status = 0;

	if (kgsl_gmu_isenabled(device))
	if (kgsl_gmu_gpmu_isenabled(device))
		return 0;
	/*
	 * Disabling the regulator means also disabling dependent clocks.
@@ -2573,7 +2580,7 @@ void kgsl_pre_hwaccess(struct kgsl_device *device)
	 * A register access without device power will cause a fatal timeout.
	 * This is not valid for targets with a GMU.
	 */
	if (!kgsl_gmu_isenabled(device))
	if (!kgsl_gmu_gpmu_isenabled(device))
		WARN_ON(!kgsl_pwrctrl_isenabled(device));
}
EXPORT_SYMBOL(kgsl_pre_hwaccess);
@@ -2594,7 +2601,7 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device)

	kgsl_pwrctrl_pwrlevel_change(device, level);

	if (kgsl_gmu_isenabled(device)) {
	if (kgsl_gmu_gpmu_isenabled(device)) {
		int ret = gmu_start(device);

		if (!ret)
@@ -2613,7 +2620,7 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device)

static void kgsl_pwrctrl_disable(struct kgsl_device *device)
{
	if (kgsl_gmu_isenabled(device)) {
	if (kgsl_gmu_gpmu_isenabled(device)) {
		kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
		return gmu_stop(device);
	}
@@ -2762,7 +2769,7 @@ _aware(struct kgsl_device *device)

	switch (device->state) {
	case KGSL_STATE_RESET:
		if (!kgsl_gmu_isenabled(device))
		if (!kgsl_gmu_gpmu_isenabled(device))
			break;
		status = gmu_start(device);
		break;