adreno源码系列注册platform_driver
Posted bubbleben
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了adreno源码系列注册platform_driver相关的知识,希望对你有一定的参考价值。
1. adreno_platform_driver
static struct adreno_device device_3d0;
static const struct of_device_id adreno_match_table[] =
.compatible = "qcom,kgsl-3d0", .data = &device_3d0 ,
,
;
static struct platform_driver adreno_platform_driver =
// kgsl probe函数[见第2节]
.probe = adreno_probe,
.remove = adreno_remove,
// device_driver
.driver =
.name = "kgsl-3d",
//
.pm = &adreno_pm_ops,
.of_match_table = of_match_ptr(adreno_match_table),
;
2. adreno_probe
static int adreno_probe(struct platform_device *pdev)
struct component_match *match = NULL;
adreno_add_gmu_components(&pdev->dev, &match);
if (match)
return component_master_add_with_match(&pdev->dev,
&adreno_ops, match);
else
// 绑定adreno设备[见2.1节]
return adreno_bind(&pdev->dev);
2.1 adreno_bind
static int adreno_bind(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
const struct adreno_gpu_core *gpucore;
int ret;
u32 chipid;
// 判断GPU是否被禁用
if (adreno_is_gpu_disabled(pdev))
dev_err(&pdev->dev, "adreno: GPU is disabled on this device\\n");
return -ENODEV;
// 识别GPU型号[见2.2节]
gpucore = adreno_identify_gpu(pdev, &chipid);
if (IS_ERR(gpucore))
return PTR_ERR(gpucore);
// 调用2.5节中adreno_a6xx_gmu_gpudev定义的a6xx_gmu_device_probe
ret = gpucore->gpudev->probe(pdev, chipid, gpucore);
if (!ret)
struct kgsl_device *device = dev_get_drvdata(dev);
device->pdev_loaded = true;
return ret;
2.2 adreno_identify_gpu
static const struct adreno_gpu_core *
adreno_identify_gpu(struct platform_device *pdev, u32 *chipid)
const struct adreno_gpu_core *gpucore;
// 解析dts文件qcom,chipid节点, 获取GPU型号
if (adreno_get_chipid(pdev, chipid))
dev_crit(&pdev->dev, "Unable to get the GPU chip ID\\n");
return ERR_PTR(-ENODEV);
// 根据GPU型号查找对应的adreno_gpu_core[见2.3节]
gpucore = _get_gpu_core(pdev, chipid);
if (!gpucore)
dev_crit(&pdev->dev, "Unknown GPU chip ID %8.8x\\n", *chipid);
return ERR_PTR(-ENODEV);
/*
* Identify non-longer supported targets and spins and print a helpful
* message
*/
if (gpucore->features & ADRENO_DEPRECATED)
if (gpucore->compatible)
dev_err(&pdev->dev,
"Support for GPU %s has been deprecated\\n",
gpucore->compatible);
else
dev_err(&pdev->dev,
"Support for GPU %x.%d.%x.%d has been deprecated\\n",
gpucore->core, gpucore->major,
gpucore->minor, gpucore->patchid);
return ERR_PTR(-ENODEV);
// 返回adreno_gpu_core
return gpucore;
2.3 _get_gpu_core
static const struct adreno_gpu_core *
_get_gpu_core(struct platform_device *pdev, unsigned int chipid)
// GPU 系列号
unsigned int core = ADRENO_CHIPID_CORE(chipid);
// GPU 主版本号
unsigned int major = ADRENO_CHIPID_MAJOR(chipid);
// GPU 副版本号
unsigned int minor = ADRENO_CHIPID_MINOR(chipid);
// GPU patchid
unsigned int patchid = ADRENO_CHIPID_PATCH(chipid);
int i;
struct device_node *node;
/*
* When "qcom,gpu-models" is defined, use gpu model node to match
* on a compatible string, otherwise match using legacy way.
*/
node = adreno_get_gpu_model_node(pdev);
if (!node || !of_find_property(node, "compatible", NULL))
node = pdev->dev.of_node;
/* Check to see if any of the entries match on a compatible string */
for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++)
if (adreno_gpulist[i]->compatible &&
of_device_is_compatible(node,
adreno_gpulist[i]->compatible))
return adreno_gpulist[i];
// 遍历adreno_gpulist并选择匹配的adreno_gpu_core:adreno_gpu_core_a640[见2.4节]
for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++)
if (core == adreno_gpulist[i]->core &&
_rev_match(major, adreno_gpulist[i]->major) &&
_rev_match(minor, adreno_gpulist[i]->minor) &&
_rev_match(patchid, adreno_gpulist[i]->patchid))
return adreno_gpulist[i];
return NULL;
2.4 adreno_gpu_core_a640
static const struct adreno_a6xx_core adreno_gpu_core_a640 =
.base =
// 版本
DEFINE_ADRENO_REV(ADRENO_REV_A640, 6, 4, 0, ANY_ID),
// 特性
.features = ADRENO_RPMH | ADRENO_GPMU |
ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT |
ADRENO_IFPC | ADRENO_PREEMPTION,
// adreno_gpudev:adreno_a6xx_gmu_gpudev[见2.5节]
.gpudev = &adreno_a6xx_gmu_gpudev,
// 默认的性能计数器
.perfcounters = &adreno_a6xx_legacy_perfcounters,
.gmem_size = SZ_1M, //Verified 1MB
.bus_width = 32,
.snapshot_size = 2 * SZ_1M,
,
.prim_fifo_threshold = 0x00200000,
.gmu_major = 2,
.gmu_minor = 0,
.sqefw_name = "a630_sqe.fw",
.gmufw_name = "a640_gmu.bin",
.zap_name = "a640_zap",
.hwcg = a640_hwcg_regs,
.hwcg_count = ARRAY_SIZE(a640_hwcg_regs),
.vbif = a640_vbif_regs,
.vbif_count = ARRAY_SIZE(a640_vbif_regs),
.hang_detect_cycles = 0xcfffff,
.protected_regs = a630_protected_regs,
.disable_tseskip = true,
.highest_bank_bit = 15,
;
2.5 adreno_a6xx_gmu_gpudev
const struct adreno_gpudev adreno_a6xx_gmu_gpudev =
.reg_offsets = a6xx_register_offsets,
// gmu probe函数
.probe = a6xx_gmu_device_probe,
.start = a6xx_start,
.snapshot = a6xx_gmu_snapshot,
.init = a6xx_init,
.irq_handler = a6xx_irq_handler,
.rb_start = a6xx_rb_start,
.regulator_enable = a6xx_gmu_sptprac_enable,
.regulator_disable = a6xx_gmu_sptprac_disable,
.read_throttling_counters = a6xx_read_throttling_counters,
.microcode_read = a6xx_microcode_read,
.gpu_keepalive = a6xx_gpu_keepalive,
.hw_isidle = a6xx_hw_isidle,
.iommu_fault_block = a6xx_iommu_fault_block,
.reset = a6xx_gmu_restart,
.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
.preemption_init = a6xx_preemption_init,
.preemption_schedule = a6xx_preemption_schedule,
.set_marker = a6xx_set_marker,
.preemption_context_init = a6xx_preemption_context_init,
.sptprac_is_on = a6xx_gmu_sptprac_is_on,
.ccu_invalidate = a6xx_ccu_invalidate,
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
.coresight = &a6xx_coresight, &a6xx_coresight_cx,
#endif
.read_alwayson = a6xx_read_alwayson,
.power_ops = &a6xx_gmu_power_ops,
;
2.6 a6xx_gmu_device_probe
int a6xx_gmu_device_probe(struct platform_device *pdev,
u32 chipid, const struct adreno_gpu_core *gpucore)
struct adreno_device *adreno_dev;
struct kgsl_device *device;
struct a6xx_device *a6xx_dev;
int ret;
// 创建a6xx_device
a6xx_dev = devm_kzalloc(&pdev->dev, sizeof(*a6xx_dev),
GFP_KERNEL);
if (!a6xx_dev)
return -ENOMEM;
// 取a6xx_device的成员adreno_device
adreno_dev = &a6xx_dev->adreno_dev;
// gmu probe[见第3节]
ret = a6xx_probe_common(pdev, adreno_dev, chipid, gpucore);
if (ret)
return ret;
// 取adreno_device的成员kgsl_device
device = KGSL_DEVICE(adreno_dev);
INIT_WORK(&device->idle_check_ws, gmu_idle_check);
timer_setup(&device->idle_timer, gmu_idle_timer, 0);
adreno_dev->irq_mask = A6XX_INT_MASK;
return 0;
3. a6xx_probe_common
int a6xx_probe_common(struct platform_device *pdev,
struct adreno_device *adreno_dev, u32 chipid,
const struct adreno_gpu_core *gpucore)
const struct adreno_gpudev *gpudev = gpucore->gpudev;
// 初始化adreno_device
adreno_dev->gpucore = gpucore;
adreno_dev->chipid = chipid;
adreno_reg_offset_init(gpudev->reg_offsets);
adreno_dev->hwcg_enabled = true;
adreno_dev->preempt.preempt_level = 1;
adreno_dev->preempt.skipsaverestore = true;
adreno_dev->preempt.usesgmem = true;
/* Set the GPU busy counter for frequency scaling */
adreno_dev->perfctr_pwr_lo = A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L;
/* Set the counter for IFPC */
if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC))
adreno_dev->perfctr_ifpc_lo =
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L;
// adreno_device probe[见第4节]
return adreno_device_probe(pdev, adreno_dev);
4. adreno_device_probe
int adreno_device_probe(struct platform_device *pdev,
struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct device *dev = &pdev->dev;
unsigned int priv = 0;
int status;
u32 size;
place_marker("M - DRIVER GPU Init");
/* Initialize the adreno device structure */
// 初始化adreno_device[见第5节]
adreno_setup_device(adreno_dev);
dev_set_drvdata(dev, device);
device->pdev = pdev;
adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
status = adreno_read_speed_bin(pdev);
if (status < 0)
return status;
device->speed_bin = status;
// 获取GPU寄存器物理地址和大小和GPU频率[见第6节]
status = adreno_of_get_power(adreno_dev, pdev);
if (status)
return status;
status = kgsl_bus_init(device, pdev);
if (status)
goto err;
/*
* Bind the GMU components (if applicable) before doing the KGSL
* platform probe
*/
if (of_find_matching_node(dev->of_node, adreno_gmu_match))
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
* that we cannot use 64 bit virtual addresses on a 32 bit kernel even
* though the hardware and the rest of the KGSL driver supports it.
*/
if (adreno_support_64bit(adreno_dev))
kgsl_mmu_set_feature(device, KGSL_MMU_64BIT);
/*
* Set the SMMU aperture on A6XX targets to use per-process pagetables.
*/
if (adreno_is_a6xx(adreno_dev))
kgsl_mmu_set_feature(device, KGSL_MMU_SMMU_APERTURE);
if (ADRENO_FEATURE(adreno_dev, ADRENO_IOCOHERENT))
kgsl_mmu_set_feature(device, KGSL_MMU_IO_COHERENT);
device->pwrctrl.bus_width = adreno_dev->gpucore->bus_width;
device->mmu.secured = (IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) &&
ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION));
/* Probe the LLCC - this could return -EPROBE_DEFER */
status = adreno_probe_llcc(adreno_dev, pdev);
if (status)
goto err;
/*
* IF the GPU HTW slice was successsful set the MMU feature so the
* domain can set the appropriate attributes
*/
if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice))
kgsl_mmu_set_feature(device, KGSL_MMU_LLCC_ENABLE);
// [见第7节]
status = kgsl_device_platform_probe(device);
if (status)
goto err;
/* Probe for the optional CX_DBGC block */
adreno_cx_dbgc_probe(device);
/* Probe for the optional CX_MISC block */
adreno_cx_misc_probe(device);
adreno_isense_probe(device);
/* Allocate the memstore for storing timestamps and other useful info */
if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV))
priv |= KGSL_MEMDESC_PRIVILEGED;
// 分配kgsl_device全局共享的内存: 见"adreno源码系列之Gpu内存申请"
device->memstore = kgsl_allocate_global(device,
KGSL_MEMSTORE_SIZE, 0, 0, priv, "memstore");
status = PTR_ERR_OR_ZERO(device->memstore);
if (status)
kgsl_device_platform_remove(device);
goto err;
/* Initialize the snapshot engine */
size = adreno_dev->gpucore->snapshot_size;
/*
* Use a default size if one wasn't specified, but print a warning so
* the developer knows to fix it
*/
if (WARN(!size, "The snapshot size was not specified in the gpucore\\n"))
size = SZ_1M;
kgsl_device_snapshot_probe(device, size);
adreno_debugfs_init(adreno_dev);
adreno_profile_init(adreno_dev);
adreno_sysfs_init(adreno_dev);
kgsl_pwrscale_init(device, pdev, CONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR);
/* Initialize coresight for the target */
adreno_coresight_init(adreno_dev);
#ifdef CONFIG_INPUT
if (!device->pwrctrl.input_disable)
adreno_input_handler.private = device;
/*
* It isn't fatal if we cannot register the input handler. Sad,
* perhaps, but not fatal
*/
if (input_register_handler(&adreno_input_handler))
adreno_input_handler.private = NULL;
dev_err(device->dev,
"Unable to register the input handler\\n");
#endif
place_marker("M - DRIVER GPU Ready");
return 0;
err:
device->pdev = NULL;
if (of_find_matching_node(dev->of_node, adreno_gmu_match))
component_unbind_all(dev, NULL);
kgsl_bus_close(device);
return status;
5. adreno_setup_device
static void adreno_setup_device(struct adreno_device *adreno_dev)
u32 i;
// 初始化kgsl_device名称
adreno_dev->dev.name = "kgsl-3d0";
// 初始化kgsl_device的函数表[见5.1节]
adreno_dev->dev.ftbl = &adreno_functable;
init_completion(&adreno_dev->dev.hwaccess_gate);
init_completion(&adreno_dev->dev.halt_gate);
idr_init(&adreno_dev->dev.context_idr);
mutex_init(&adreno_dev->dev.mutex);
INIT_LIST_HEAD(&adreno_dev->dev.globals);
/* Set the fault tolerance policy to replay, skip, throttle */
adreno_dev->ft_policy = BIT(KGSL_FT_REPLAY) |
BIT(KGSL_FT_SKIPCMD) | BIT(KGSL_FT_THROTTLE);
/* Enable command timeouts by default */
adreno_dev->long_ib_detect = true;
INIT_WORK以上是关于adreno源码系列注册platform_driver的主要内容,如果未能解决你的问题,请参考以下文章