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

Commit 0c46c9a3 authored by Jordan Crouse's avatar Jordan Crouse
Browse files

msm: kgsl: Move GMU to a component device



Traditionally the GMU/RGMU device has been a child of the adreno device
and probed manually. That has worked despite the fact that the GMU/RGMU
device has resources of its own and it really should be a top level
platform device.

Finally do the right thing, make GMU a top level platform device and
driver and bind it to Adreno as a component. This will make sure we
get the advantages of all of the platform level initialization without
having to code in half a dozen hacks to make everything work and then
break again next kernel version.

Change-Id: Ic0dedbadf6776e1a4f5e0eb1e093241e5103b3ff
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent c7ae2394
Loading
Loading
Loading
Loading
+73 −13
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
/*
 * Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved.
 */
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/input.h>
@@ -1415,8 +1416,9 @@ static void adreno_setup_device(struct adreno_device *adreno_dev)
	}
}

static int adreno_probe(struct platform_device *pdev)
static int adreno_bind(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	const struct of_device_id *of_id;
	struct adreno_device *adreno_dev;
	struct kgsl_device *device;
@@ -1435,6 +1437,8 @@ static int adreno_probe(struct platform_device *pdev)

	device = KGSL_DEVICE(adreno_dev);

	dev_set_drvdata(dev, device);

	device->pdev = pdev;

	if (adreno_is_gpu_disabled(adreno_dev)) {
@@ -1466,13 +1470,14 @@ static int adreno_probe(struct platform_device *pdev)
		goto err;

	/*
	 * Probe/init GMU after initial gpu power probe
	 * Another part of GPU power probe in platform_probe
	 * needs GMU initialized.
	 * Bind the GMU components (if applicable) before doing the KGSL
	 * platform probe
	 */
	status = gmu_core_probe(device);
	if (status)
		goto err;
	status = component_bind_all(dev, NULL);
	if (status) {
		kgsl_bus_close(device);
		return status;
	}

	/*
	 * The SMMU APIs use unsigned long for virtual addresses which means
@@ -1576,7 +1581,7 @@ static int adreno_probe(struct platform_device *pdev)
err:
	device->pdev = NULL;

	gmu_core_remove(device);
	component_unbind_all(dev, NULL);
	kgsl_bus_close(device);

	return status;
@@ -1598,8 +1603,9 @@ static void _adreno_free_memories(struct adreno_device *adreno_dev)
	adreno_dev->gpmu_cmds = NULL;
}

static int adreno_remove(struct platform_device *pdev)
static void adreno_unbind(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	const struct of_device_id *of_id;
	struct adreno_device *adreno_dev;
	struct kgsl_device *device;
@@ -1607,7 +1613,7 @@ static int adreno_remove(struct platform_device *pdev)

	of_id = of_match_device(adreno_match_table, &pdev->dev);
	if (!of_id)
		return -EINVAL;
		return;

	adreno_dev = (struct adreno_device *) of_id->data;
	device = KGSL_DEVICE(adreno_dev);
@@ -1653,12 +1659,10 @@ static int adreno_remove(struct platform_device *pdev)

	kgsl_device_platform_remove(device);

	gmu_core_remove(device);
	component_unbind_all(dev, NULL);

	clear_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv);
	clear_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv);

	return 0;
}

static int adreno_pm_resume(struct device *dev)
@@ -3882,6 +3886,60 @@ static const struct kgsl_functable adreno_functable = {
	.is_hwcg_on = adreno_is_hwcg_on,
};

static const struct component_master_ops adreno_ops = {
	.bind = adreno_bind,
	.unbind = adreno_unbind,
};

static const struct of_device_id adreno_gmu_match[] = {
	{ .compatible = "qcom,gpu-gmu" },
	{ .compatible = "qcom,gpu-rgmu" },
	{},
};

static int _compare_of(struct device *dev, void *data)
{
	return (dev->of_node == data);
}

static void _release_of(struct device *dev, void *data)
{
	of_node_put(data);
}

static void adreno_add_gmu_components(struct device *dev,
		struct component_match **match)
{
	struct device_node *node;

	node = of_find_matching_node(NULL, adreno_gmu_match);
	if (!node)
		return;

	if (!of_device_is_available(node)) {
		of_node_put(node);
		return;
	}

	component_match_add_release(dev, match, _release_of,
		_compare_of, node);
}

static int adreno_probe(struct platform_device *pdev)
{
	struct component_match *match = NULL;

	adreno_add_gmu_components(&pdev->dev, &match);

	return component_master_add_with_match(&pdev->dev, &adreno_ops, match);
}

static int adreno_remove(struct platform_device *pdev)
{
	component_master_del(&pdev->dev, &adreno_ops);
	return 0;
}

static const struct dev_pm_ops adreno_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(adreno_pm_suspend, adreno_pm_resume)
};
@@ -3905,6 +3963,7 @@ static int __init kgsl_3d_init(void)
	if (ret)
		return ret;

	gmu_core_register();
	ret = platform_driver_register(&adreno_platform_driver);
	if (ret)
		kgsl_core_exit();
@@ -3915,6 +3974,7 @@ static int __init kgsl_3d_init(void)
static void __exit kgsl_3d_exit(void)
{
	platform_driver_unregister(&adreno_platform_driver);
	gmu_core_unregister();
	kgsl_core_exit();
}

+0 −2
Original line number Diff line number Diff line
@@ -4776,8 +4776,6 @@ static int _register_device(struct kgsl_device *device)

	device->dev->dma_mask = &dma_mask;
	set_dma_ops(device->dev, NULL);

	dev_set_drvdata(&device->pdev->dev, device);
	return 0;
}

+62 −38
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/interconnect.h>
@@ -1296,8 +1297,9 @@ static int gmu_bus_set(struct kgsl_device *device, int buslevel,
	return ret;
}

/* Do not access any GMU registers in GMU probe function */
static int gmu_probe(struct kgsl_device *device, struct device_node *node)
static struct gmu_core_ops gmu_ops;

static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
{
	struct gmu_device *gmu;
	struct kgsl_hfi *hfi;
@@ -1305,35 +1307,28 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int i = 0, ret = -ENXIO, index;

	gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL);

	if (gmu == NULL)
	gmu = devm_kzalloc(&pdev->dev, sizeof(*gmu), GFP_KERNEL);
	if (!gmu)
		return -ENOMEM;

	gmu->pdev = of_find_device_by_node(node);
	if (!gmu->pdev) {
		kfree(gmu);
		return -EINVAL;
	}
	gmu->pdev = pdev;

	device->gmu_core.ptr = (void *)gmu;
	hfi = &gmu->hfi;
	gmu->load_mode = TCM_BOOT;

	of_dma_configure(&gmu->pdev->dev, node, true);

	dma_set_coherent_mask(&gmu->pdev->dev, DMA_BIT_MASK(64));
	gmu->pdev->dev.dma_mask = &gmu->pdev->dev.coherent_dma_mask;
	set_dma_ops(&gmu->pdev->dev, NULL);

	/* Set up GMU regulators */
	ret = gmu_regulators_probe(gmu, node);
	ret = gmu_regulators_probe(gmu, pdev->dev.of_node);
	if (ret)
		goto error;
		return ret;

	ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
	if (ret < 0)
		goto error;
		return ret;

	gmu->num_clks = ret;

@@ -1341,12 +1336,11 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	gmu->gmu_clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, "gmu_clk");
	if (!gmu->gmu_clk) {
		dev_err(&gmu->pdev->dev, "Couldn't get gmu_clk\n");
		ret = -ENODEV;
		goto error;
		return -ENODEV;
	}

	/* Set up GMU IOMMU and shared memory with GMU */
	ret = gmu_iommu_init(gmu, node);
	ret = gmu_iommu_init(gmu, pdev->dev.of_node);
	if (ret)
		goto error;

@@ -1421,12 +1415,14 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
	else
		gmu->idle_level = GPU_HW_ACTIVE;

	gmu_acd_probe(device, gmu, node);
	gmu_acd_probe(device, gmu, pdev->dev.of_node);

	if (gmu_core_scales_bandwidth(device))
		pwr->bus_set = gmu_bus_set;

	set_bit(GMU_ENABLED, &device->gmu_core.flags);

	device->gmu_core.core_ops = &gmu_ops;
	device->gmu_core.dev_ops = &adreno_a6xx_gmudev;

	return 0;
@@ -1729,27 +1725,12 @@ static void gmu_remove(struct kgsl_device *device)

	clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);

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

	gmu_memory_close(gmu);

	if (gmu->gx_gdsc) {
		devm_regulator_put(gmu->gx_gdsc);
		gmu->gx_gdsc = NULL;
	}

	if (gmu->cx_gdsc) {
		devm_regulator_put(gmu->cx_gdsc);
		gmu->cx_gdsc = NULL;
	}

	memset(&device->gmu_core, 0, sizeof(device->gmu_core));

	gmu->pdev = NULL;
	kfree(gmu);
}

static bool gmu_regulator_isenabled(struct kgsl_device *device)
@@ -1759,9 +1740,7 @@ static bool gmu_regulator_isenabled(struct kgsl_device *device)
	return (gmu->gx_gdsc && regulator_is_enabled(gmu->gx_gdsc));
}

struct gmu_core_ops gmu_ops = {
	.probe = gmu_probe,
	.remove = gmu_remove,
static struct gmu_core_ops gmu_ops = {
	.init = gmu_init,
	.start = gmu_start,
	.stop = gmu_stop,
@@ -1771,3 +1750,48 @@ struct gmu_core_ops gmu_ops = {
	.suspend = gmu_suspend,
	.acd_set = gmu_acd_set,
};

static int kgsl_gmu_bind(struct device *dev, struct device *master, void *data)
{
	struct kgsl_device *device = dev_get_drvdata(master);

	return gmu_probe(device, to_platform_device(dev));
}

static void kgsl_gmu_unbind(struct device *dev, struct device *master,
		void *data)
{
	struct kgsl_device *device = dev_get_drvdata(master);

	gmu_remove(device);
}

static const struct component_ops kgsl_gmu_ops = {
	.bind = kgsl_gmu_bind,
	.unbind = kgsl_gmu_unbind,
};

static int kgsl_gmu_probe(struct platform_device *pdev)
{
	return component_add(&pdev->dev, &kgsl_gmu_ops);
}

static int kgsl_gmu_remove(struct platform_device *pdev)
{
	component_del(&pdev->dev, &kgsl_gmu_ops);
	return 0;
}

static const struct of_device_id kgsl_gmu_match_table[] = {
	{ .compatible = "qcom,gpu-gmu" },
	{ },
};

struct platform_driver kgsl_gmu_driver = {
	.probe = kgsl_gmu_probe,
	.remove = kgsl_gmu_remove,
	.driver = {
		.name = "kgsl-gmu",
		.of_match_table = kgsl_gmu_match_table,
	},
};
+25 −46
Original line number Diff line number Diff line
@@ -10,13 +10,10 @@
#include "kgsl_gmu_core.h"
#include "kgsl_trace.h"

static const struct {
	char *compat;
	struct gmu_core_ops *core_ops;
	enum gmu_coretype type;
} gmu_subtypes[] = {
		{"qcom,gpu-gmu", &gmu_ops, GMU_CORE_TYPE_CM3},
		{"qcom,gpu-rgmu", &rgmu_ops, GMU_CORE_TYPE_PCC},
static const struct of_device_id gmu_match_table[] = {
	{ .compatible = "qcom,gpu-gmu", .data = &kgsl_gmu_driver },
	{ .compatible = "qcom,gpu-rgmu", .data = &kgsl_rgmu_driver },
	{},
};

struct oob_entry {
@@ -40,50 +37,32 @@ const char *gmu_core_oob_type_str(enum oob_request req)
	return "UNKNOWN";
}

int gmu_core_probe(struct kgsl_device *device)
void __init gmu_core_register(void)
{
	const struct of_device_id *match;
	struct device_node *node;
	struct gmu_core_ops *gmu_core_ops;
	int i = 0, ret = -ENXIO;

	device->gmu_core.flags = ADRENO_FEATURE(ADRENO_DEVICE(device),
			ADRENO_GPMU) ? BIT(GMU_GPMU) : 0;

	for (i = 0; i < ARRAY_SIZE(gmu_subtypes); i++) {
		node = of_find_compatible_node(device->pdev->dev.of_node,
				NULL, gmu_subtypes[i].compat);

		if (node != NULL) {
			gmu_core_ops = gmu_subtypes[i].core_ops;
			device->gmu_core.type = gmu_subtypes[i].type;
			break;
		}
	}

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

	if (gmu_core_ops && gmu_core_ops->probe) {
		ret = gmu_core_ops->probe(device, node);
		if (ret == 0)
			device->gmu_core.core_ops = gmu_core_ops;
	}
	node = of_find_matching_node_and_match(NULL, gmu_match_table,
		&match);
	if (!node)
		return;

	return ret;
	platform_driver_register((struct platform_driver *) match->data);
	of_node_put(node);
}

void gmu_core_remove(struct kgsl_device *device)
void __exit gmu_core_unregister(void)
{
	struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
	const struct of_device_id *match;
	struct device_node *node;

	node = of_find_matching_node_and_match(NULL, gmu_match_table,
		&match);
	if (!node)
		return;

	if (gmu_core_ops && gmu_core_ops->remove)
		gmu_core_ops->remove(device);
	platform_driver_unregister((struct platform_driver *) match->data);
	of_node_put(node);
}

bool gmu_core_isenabled(struct kgsl_device *device)
@@ -93,7 +72,7 @@ bool gmu_core_isenabled(struct kgsl_device *device)

bool gmu_core_gpmu_isenabled(struct kgsl_device *device)
{
	return test_bit(GMU_GPMU, &device->gmu_core.flags);
	return (device->gmu_core.core_ops != NULL);
}

bool gmu_core_scales_bandwidth(struct kgsl_device *device)
+6 −15
Original line number Diff line number Diff line
@@ -39,18 +39,10 @@ enum gmu_core_flags {
	GMU_HFI_ON,
	GMU_FAULT,
	GMU_DCVS_REPLAY,
	GMU_GPMU,
	GMU_ENABLED,
	GMU_RSCC_SLEEP_SEQ_DONE,
};

/* GMU Types */
enum gmu_coretype {
	GMU_CORE_TYPE_CM3 = 1, /* Cortex M3 core */
	GMU_CORE_TYPE_PCC = 2, /* Power collapsible controller */
	GMU_CORE_TYPE_NONE, /* No GMU */
};

/*
 * OOB requests values. These range from 0 to 7 and then
 * the BIT() offset into the actual value is calculated
@@ -109,8 +101,6 @@ struct kgsl_device;
struct kgsl_snapshot;

struct gmu_core_ops {
	int (*probe)(struct kgsl_device *device, struct device_node *node);
	void (*remove)(struct kgsl_device *device);
	int (*dcvs_set)(struct kgsl_device *device,
			int gpu_pwrlevel, int bus_level);
	int (*init)(struct kgsl_device *device);
@@ -169,15 +159,16 @@ struct gmu_core_device {
	struct gmu_core_ops *core_ops;
	struct gmu_dev_ops *dev_ops;
	unsigned long flags;
	enum gmu_coretype type;
};

extern struct gmu_core_ops gmu_ops;
extern struct gmu_core_ops rgmu_ops;
extern struct platform_driver kgsl_gmu_driver;
extern struct platform_driver kgsl_rgmu_driver;

/* GMU core functions */
int gmu_core_probe(struct kgsl_device *device);
void gmu_core_remove(struct kgsl_device *device);

void __init gmu_core_register(void);
void __exit gmu_core_unregister(void);

int gmu_core_init(struct kgsl_device *device);
int gmu_core_start(struct kgsl_device *device);
void gmu_core_stop(struct kgsl_device *device);
Loading