mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 04:42:04 -04:00
msm: kgsl: Fixup the GMU probe
Clean up the GMU probe to use standard functions and proper reference to make it more defer tolerant. Change-Id: Ic0dedbad7c561e24c07053ea3b19ef62e34621cb Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
parent
76f54bf67f
commit
8152ccc95e
2 changed files with 80 additions and 126 deletions
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
struct gmu_iommu_context {
|
||||
const char *name;
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
struct iommu_domain *domain;
|
||||
};
|
||||
|
||||
|
|
@ -277,48 +277,57 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu,
|
|||
}
|
||||
|
||||
static int gmu_iommu_cb_probe(struct gmu_device *gmu,
|
||||
struct gmu_iommu_context *ctx,
|
||||
struct device_node *node)
|
||||
const char *name, struct gmu_iommu_context *ctx,
|
||||
struct device_node *parent, iommu_fault_handler_t handler)
|
||||
{
|
||||
struct platform_device *pdev = of_find_device_by_node(node);
|
||||
struct device *dev;
|
||||
struct device_node *node = of_get_child_by_name(parent, name);
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
dev = &pdev->dev;
|
||||
of_dma_configure(dev, node, true);
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
|
||||
ctx->dev = dev;
|
||||
pdev = of_find_device_by_node(node);
|
||||
of_dma_configure(&pdev->dev, node, true);
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
ctx->pdev = pdev;
|
||||
ctx->domain = iommu_domain_alloc(&platform_bus_type);
|
||||
if (ctx->domain == NULL) {
|
||||
dev_err(&gmu->pdev->dev, "gmu iommu fail to alloc %s domain\n",
|
||||
ctx->name);
|
||||
platform_device_put(pdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = iommu_attach_device(ctx->domain, dev);
|
||||
if (ret) {
|
||||
dev_err(&gmu->pdev->dev, "gmu iommu fail to attach %s device\n",
|
||||
ctx->name);
|
||||
iommu_domain_free(ctx->domain);
|
||||
ret = iommu_attach_device(ctx->domain, &pdev->dev);
|
||||
if (!ret) {
|
||||
iommu_set_fault_handler(ctx->domain, handler, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"gmu iommu fail to attach %s device\n", ctx->name);
|
||||
iommu_domain_free(ctx->domain);
|
||||
ctx->domain = NULL;
|
||||
platform_device_put(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *compatible;
|
||||
int index;
|
||||
iommu_fault_handler_t hdlr;
|
||||
} cbs[] = {
|
||||
{ "qcom,smmu-gmu-user-cb",
|
||||
GMU_CONTEXT_USER,
|
||||
gmu_user_fault_handler,
|
||||
},
|
||||
{ "qcom,smmu-gmu-kernel-cb",
|
||||
GMU_CONTEXT_KERNEL,
|
||||
gmu_kernel_fault_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static void gmu_iommu_cb_close(struct gmu_iommu_context *ctx)
|
||||
{
|
||||
if (!ctx->domain)
|
||||
return;
|
||||
|
||||
iommu_detach_device(ctx->domain, &ctx->pdev->dev);
|
||||
iommu_domain_free(ctx->domain);
|
||||
|
||||
platform_device_put(ctx->pdev);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
/*
|
||||
* gmu_iommu_init() - probe IOMMU context banks used by GMU
|
||||
|
|
@ -328,34 +337,17 @@ static struct {
|
|||
*/
|
||||
static int gmu_iommu_init(struct gmu_device *gmu, struct device_node *node)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct gmu_iommu_context *ctx = NULL;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
of_platform_populate(node, NULL, NULL, &gmu->pdev->dev);
|
||||
devm_of_platform_populate(&gmu->pdev->dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cbs); i++) {
|
||||
child = of_find_compatible_node(node, NULL, cbs[i].compatible);
|
||||
if (child) {
|
||||
ctx = &gmu_ctx[cbs[i].index];
|
||||
ret = gmu_iommu_cb_probe(gmu, ctx, child);
|
||||
if (ret)
|
||||
return ret;
|
||||
iommu_set_fault_handler(ctx->domain,
|
||||
cbs[i].hdlr, ctx);
|
||||
}
|
||||
}
|
||||
ret = gmu_iommu_cb_probe(gmu, "gmu_user",
|
||||
&gmu_ctx[GMU_CONTEXT_USER], node, gmu_user_fault_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gmu_ctx); i++) {
|
||||
if (gmu_ctx[i].domain == NULL) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Missing GMU %s context bank node\n",
|
||||
gmu_ctx[i].name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return gmu_iommu_cb_probe(gmu, "gmu_kernel",
|
||||
&gmu_ctx[GMU_CONTEXT_KERNEL], node, gmu_kernel_fault_handler);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -394,14 +386,8 @@ static void gmu_memory_close(struct gmu_device *gmu)
|
|||
clear_bit(i, &gmu->kmem_bitmap);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gmu_ctx); i++) {
|
||||
ctx = &gmu_ctx[i];
|
||||
|
||||
if (ctx->domain) {
|
||||
iommu_detach_device(ctx->domain, ctx->dev);
|
||||
iommu_domain_free(ctx->domain);
|
||||
}
|
||||
}
|
||||
gmu_iommu_cb_close(&gmu_ctx[GMU_CONTEXT_USER]);
|
||||
gmu_iommu_cb_close(&gmu_ctx[GMU_CONTEXT_KERNEL]);
|
||||
}
|
||||
|
||||
static enum gmu_mem_type gmu_get_blk_memtype(struct gmu_device *gmu,
|
||||
|
|
@ -1061,60 +1047,44 @@ static int gmu_reg_probe(struct kgsl_device *device)
|
|||
|
||||
res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM,
|
||||
"kgsl_gmu_reg");
|
||||
if (res == NULL) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"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 kgsl_gmu_reg invalid register region\n",
|
||||
gmu->pdev->dev.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gmu->reg_phys = res->start;
|
||||
gmu->reg_len = resource_size(res);
|
||||
device->gmu_core.reg_virt = devm_ioremap(&gmu->pdev->dev,
|
||||
res->start, resource_size(res));
|
||||
if (device->gmu_core.reg_virt == NULL) {
|
||||
dev_err(&gmu->pdev->dev, "kgsl_gmu_reg ioremap failed\n");
|
||||
if (!res) {
|
||||
dev_err(&gmu->pdev->dev, "The GMU register region isn't defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
device->gmu_core.gmu2gpu_offset = (res->start - device->reg_phys) >> 2;
|
||||
device->gmu_core.reg_len = resource_size(res);
|
||||
|
||||
/*
|
||||
* We can't use devm_ioremap_resource here because we purposely double
|
||||
* map the gpu_cc registers for debugging purposes
|
||||
*/
|
||||
device->gmu_core.reg_virt = devm_ioremap(&gmu->pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
if (!device->gmu_core.reg_virt) {
|
||||
dev_err(&gmu->pdev->dev, "Unable to map the GMU registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gmu_regulators_probe(struct gmu_device *gmu,
|
||||
struct device_node *node)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
const char *name;
|
||||
struct property *prop;
|
||||
struct device *dev = &gmu->pdev->dev;
|
||||
int ret = 0;
|
||||
gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx");
|
||||
if (IS_ERR(gmu->cx_gdsc)) {
|
||||
if (PTR_ERR(gmu->cx_gdsc) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Couldn't get the vddcx gdsc\n");
|
||||
return PTR_ERR(gmu->cx_gdsc);
|
||||
}
|
||||
|
||||
of_property_for_each_string(node, "regulator-names", prop, name) {
|
||||
if (!strcmp(name, "vddcx")) {
|
||||
gmu->cx_gdsc = devm_regulator_get(dev, name);
|
||||
if (IS_ERR(gmu->cx_gdsc)) {
|
||||
ret = PTR_ERR(gmu->cx_gdsc);
|
||||
dev_err(dev, "dt: GMU couldn't get CX gdsc\n");
|
||||
gmu->cx_gdsc = NULL;
|
||||
return ret;
|
||||
}
|
||||
} else if (!strcmp(name, "vdd")) {
|
||||
gmu->gx_gdsc = devm_regulator_get(dev, name);
|
||||
if (IS_ERR(gmu->gx_gdsc)) {
|
||||
ret = PTR_ERR(gmu->gx_gdsc);
|
||||
dev_err(dev, "dt: GMU couldn't get GX gdsc\n");
|
||||
gmu->gx_gdsc = NULL;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "dt: Unknown GMU regulator: %s\n", name);
|
||||
return -ENODEV;
|
||||
}
|
||||
gmu->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd");
|
||||
if (IS_ERR(gmu->gx_gdsc)) {
|
||||
if (PTR_ERR(gmu->gx_gdsc) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Couldn't get the vdd gdsc\n");
|
||||
return PTR_ERR(gmu->gx_gdsc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1321,7 +1291,7 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
|
|||
|
||||
gmu->pdev = pdev;
|
||||
|
||||
device->gmu_core.ptr = (void *)gmu;
|
||||
device->gmu_core.ptr = gmu;
|
||||
hfi = &gmu->hfi;
|
||||
gmu->load_mode = TCM_BOOT;
|
||||
|
||||
|
|
@ -1330,11 +1300,11 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
|
|||
set_dma_ops(&gmu->pdev->dev, NULL);
|
||||
|
||||
/* Set up GMU regulators */
|
||||
ret = gmu_regulators_probe(gmu, pdev->dev.of_node);
|
||||
ret = gmu_regulators_probe(gmu, pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
|
||||
ret = devm_clk_bulk_get_all(&pdev->dev, &gmu->clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1343,8 +1313,9 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
|
|||
/* Get a pointer to the GMU clock */
|
||||
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");
|
||||
return -ENODEV;
|
||||
dev_err(&pdev->dev, "Couldn't get gmu_clk\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set up GMU IOMMU and shared memory with GMU */
|
||||
|
|
@ -1366,10 +1337,6 @@ static int gmu_probe(struct kgsl_device *device, struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
device->gmu_core.gmu2gpu_offset =
|
||||
(gmu->reg_phys - device->reg_phys) >> 2;
|
||||
device->gmu_core.reg_len = gmu->reg_len;
|
||||
|
||||
/* Initialize HFI and GMU interrupts */
|
||||
hfi->hfi_interrupt_num = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq",
|
||||
hfi_irq_handler, device);
|
||||
|
|
@ -1474,9 +1441,6 @@ static int gmu_enable_gdsc(struct gmu_device *gmu)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(gmu->cx_gdsc))
|
||||
return 0;
|
||||
|
||||
ret = regulator_enable(gmu->cx_gdsc);
|
||||
if (ret)
|
||||
dev_err(&gmu->pdev->dev,
|
||||
|
|
@ -1738,14 +1702,8 @@ static void gmu_remove(struct kgsl_device *device)
|
|||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
struct kgsl_hfi *hfi;
|
||||
|
||||
if (gmu == NULL || gmu->pdev == NULL)
|
||||
return;
|
||||
|
||||
hfi = &gmu->hfi;
|
||||
|
||||
tasklet_kill(&hfi->tasklet);
|
||||
tasklet_kill(&gmu->hfi.tasklet);
|
||||
|
||||
gmu_stop(device);
|
||||
|
||||
|
|
|
|||
|
|
@ -141,8 +141,6 @@ struct icc_path;
|
|||
/**
|
||||
* struct gmu_device - GMU device structure
|
||||
* @ver: GMU Version information
|
||||
* @reg_phys: GMU CSR physical address
|
||||
* @reg_len: GMU CSR range
|
||||
* @gmu_interrupt_num: GMU interrupt number
|
||||
* @fw_image: GMU FW image
|
||||
* @hfi_mem: pointer to HFI shared memory
|
||||
|
|
@ -174,8 +172,6 @@ struct gmu_device {
|
|||
u32 hfi;
|
||||
} ver;
|
||||
struct platform_device *pdev;
|
||||
unsigned long reg_phys;
|
||||
unsigned int reg_len;
|
||||
int gmu_interrupt_num;
|
||||
const struct firmware *fw_image;
|
||||
struct gmu_memdesc *hfi_mem;
|
||||
|
|
|
|||
Loading…
Reference in a new issue