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的主要内容,如果未能解决你的问题,请参考以下文章

adreno源码系列adreno_ringbuffer

adreno源码系列adreno_ringbuffer

adreno源码系列adreno_dispatcher

adreno源码系列adreno_dispatcher

adreno源码系列启动kgsl

adreno源码系列启动kgsl