Merge "msm: kgsl: Move GMU to a component device"

This commit is contained in:
qctecmdr 2020-03-04 09:11:42 -08:00 • committed by Gerrit - the friendly Code Review server
commit f265cc530d
7 changed files with 238 additions and 139 deletions

View file

@ -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)) {
@ -1462,19 +1466,16 @@ static int adreno_probe(struct platform_device *pdev)
}
status = kgsl_bus_init(device, pdev);
if (status) {
device->pdev = NULL;
return status;
}
if (status)
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);
status = component_bind_all(dev, NULL);
if (status) {
device->pdev = NULL;
kgsl_bus_close(device);
return status;
}
@ -1492,10 +1493,8 @@ static int adreno_probe(struct platform_device *pdev)
ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION));
status = kgsl_device_platform_probe(device);
if (status) {
device->pdev = NULL;
return status;
}
if (status)
goto err;
/* Probe for the optional CX_DBGC block */
adreno_cx_dbgc_probe(device);
@ -1521,8 +1520,7 @@ static int adreno_probe(struct platform_device *pdev)
status = PTR_ERR_OR_ZERO(device->memstore);
if (status) {
kgsl_device_platform_remove(device);
device->pdev = NULL;
return status;
goto err;
}
/* Initialize the snapshot engine */
@ -1580,6 +1578,13 @@ static int adreno_probe(struct platform_device *pdev)
#endif
return 0;
err:
device->pdev = NULL;
component_unbind_all(dev, NULL);
kgsl_bus_close(device);
return status;
}
static void _adreno_free_memories(struct adreno_device *adreno_dev)
@ -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();
}

View file

@ -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;
}

View file

@ -118,7 +118,7 @@ u32 *kgsl_bus_get_table(struct platform_device *pdev,
if (num <= 0)
return ERR_PTR(-EINVAL);
levels = kcalloc(num, sizeof(*levels), GFP_KERNEL);
levels = devm_kcalloc(&pdev->dev, num, sizeof(*levels), GFP_KERNEL);
if (!levels)
return ERR_PTR(-ENOMEM);
@ -172,10 +172,5 @@ done:
void kgsl_bus_close(struct kgsl_device *device)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
kfree(pwr->ddr_table);
/* FIXME: Make sure icc put can handle NULL or IS_ERR */
icc_put(pwr->icc_path);
icc_put(device->pwrctrl.icc_path);
}

View file

@ -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>
@ -945,7 +946,7 @@ static int gmu_bus_vote_init(struct kgsl_device *device)
if (count > 0)
cnoc = build_rpmh_bw_votes(a660_cnoc_bcms,
ARRAY_SIZE(a660_cnoc_bcms), cnoc_table, count);
kfree(cnoc_table);
devm_kfree(&device->pdev->dev, cnoc_table);
if (IS_ERR(cnoc)) {
free_rpmh_bw_votes(ddr);
@ -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;
}
device->gmu_core.flags = 0;
device->gmu_core.ptr = NULL;
gmu->pdev = NULL;
kfree(gmu);
memset(&device->gmu_core, 0, sizeof(device->gmu_core));
}
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,
},
};

View file

@ -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;
node = of_find_matching_node_and_match(NULL, gmu_match_table,
&match);
if (!node)
return;
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;
}
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;
if (gmu_core_ops && gmu_core_ops->remove)
gmu_core_ops->remove(device);
node = of_find_matching_node_and_match(NULL, gmu_match_table,
&match);
if (!node)
return;
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)

View file

@ -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);

View file

@ -4,6 +4,7 @@
*/
#include <linux/clk-provider.h>
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
@ -271,11 +272,12 @@ error:
rgmu_snapshot(device);
}
static struct gmu_core_ops rgmu_ops;
/* Do not access any RGMU registers in RGMU probe function */
static int rgmu_probe(struct kgsl_device *device, struct device_node *node)
static int rgmu_probe(struct kgsl_device *device, struct platform_device *pdev)
{
struct rgmu_device *rgmu;
struct platform_device *pdev = of_find_device_by_node(node);
struct resource *res;
int ret = -ENXIO;
@ -287,12 +289,11 @@ static int rgmu_probe(struct kgsl_device *device, struct device_node *node)
rgmu->pdev = pdev;
/* Set up RGMU regulators */
ret = rgmu_regulators_probe(rgmu, node);
ret = rgmu_regulators_probe(rgmu, pdev->dev.of_node);
if (ret)
return ret;
/* Set up RGMU clocks */
ret = rgmu_clocks_probe(rgmu, node);
ret = rgmu_clocks_probe(rgmu, pdev->dev.of_node);
if (ret)
return ret;
@ -343,6 +344,7 @@ static int rgmu_probe(struct kgsl_device *device, struct device_node *node)
rgmu->idle_level = GPU_HW_ACTIVE;
set_bit(GMU_ENABLED, &device->gmu_core.flags);
device->gmu_core.core_ops = &rgmu_ops;
device->gmu_core.dev_ops = &adreno_a6xx_rgmudev;
return 0;
@ -447,9 +449,14 @@ static bool rgmu_regulator_isenabled(struct kgsl_device *device)
return (rgmu->gx_gdsc && regulator_is_enabled(rgmu->gx_gdsc));
}
struct gmu_core_ops rgmu_ops = {
.probe = rgmu_probe,
.remove = rgmu_stop,
static void rgmu_remove(struct kgsl_device *device)
{
rgmu_stop(device);
memset(&device->gmu_core, 0, sizeof(device->gmu_core));
}
static struct gmu_core_ops rgmu_ops = {
.init = rgmu_init,
.start = rgmu_start,
.stop = rgmu_stop,
@ -458,3 +465,48 @@ struct gmu_core_ops rgmu_ops = {
.regulator_isenabled = rgmu_regulator_isenabled,
.suspend = rgmu_suspend,
};
static int kgsl_rgmu_bind(struct device *dev, struct device *master, void *data)
{
struct kgsl_device *device = dev_get_drvdata(master);
return rgmu_probe(device, to_platform_device(dev));
}
static void kgsl_rgmu_unbind(struct device *dev, struct device *master,
void *data)
{
struct kgsl_device *device = dev_get_drvdata(master);
rgmu_remove(device);
}
static const struct component_ops kgsl_rgmu_ops = {
.bind = kgsl_rgmu_bind,
.unbind = kgsl_rgmu_unbind,
};
static int kgsl_rgmu_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &kgsl_rgmu_ops);
}
static int kgsl_rgmu_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &kgsl_rgmu_ops);
return 0;
}
static const struct of_device_id kgsl_rgmu_match_table[] = {
{ .compatible = "qcom,gpu-rgmu" },
{ },
};
struct platform_driver kgsl_rgmu_driver = {
.probe = kgsl_rgmu_probe,
.remove = kgsl_rgmu_remove,
.driver = {
.name = "kgsl-rgmu",
.of_match_table = kgsl_rgmu_match_table,
},
};