Linux启动过程分析(十一)----da850_register_edma(da850_edma_rsv)

da850_register_edma(da850_edma_rsv)->


int __init da850_register_edma(struct edma_rsv_info *rsv[2])
{
	if (rsv && !cpu_is_davinci_da8xx_arm_only()) {
		da850_edma_cc_info[0].rsv = rsv[0];
		da850_edma_cc_info[1].rsv = rsv[1];
	}

	return platform_device_register(&da850_edma_device);
}

所以先看一下da850_edma_rsv的结构:

static struct edma_rsv_info *da850_edma_rsv[2] = {
	&da850_edma_cc0_rsv,
	&da850_edma_cc1_rsv,
};

da850_edma_cc_info[0].rsv = rsv[0];
da850_edma_cc_info[1].rsv = rsv[1];
展开后:
da850_edma_cc_info[0].rsv = da850_edma_cc0_rsv;
da850_edma_cc_info[1].rsv = da850_edma_cc1_rsv;
在arch/arm/mach-davinci/Device-da8xx.c文件中可以找到da850_edma_cc_info的初始化:


static struct edma_soc_info da850_edma_cc_info[] = {
	{
		.n_channel		= 32,
		.n_region		= 4,
		.n_slot			= 128,
		.n_tc			= 2,
		.n_cc			= 1,
		.queue_tc_mapping	= da8xx_queue_tc_mapping,
		.queue_priority_mapping	= da8xx_queue_priority_mapping,
		.default_queue		= EVENTQ_1,
	},
	{
		.n_channel		= 32,
		.n_region		= 4,
		.n_slot			= 128,
		.n_tc			= 1,
		.n_cc			= 1,
		.queue_tc_mapping	= da850_queue_tc_mapping,
		.queue_priority_mapping	= da850_queue_priority_mapping,
		.default_queue		= EVENTQ_0,
	},
};

其中没有rsv这个变量,再来看一下edma_soc_info这个结构体的定义,可以看到
struct edma_rsv_info *rsv,rsv这个结构体表示为其它核(如DSP)预留的资源


/* platform_data for EDMA driver */
struct edma_soc_info {

	/* how many dma resources of each type */
	unsigned	n_channel;
	unsigned	n_region;
	unsigned	n_slot;
	unsigned	n_tc;
	unsigned	n_cc;
	/*
	 * Default queue is expected to be a low-priority queue.
	 * This way, long transfers on the default queue started
	 * by the codec engine will not cause audio defects.
	 */
	enum dma_event_q	default_queue;

	/* Resource reservation for other cores */
	struct edma_rsv_info	*rsv;

	const s8	(*queue_tc_mapping)[2];
	const s8	(*queue_priority_mapping)[2];
};

继续展开:
da850_edma_cc_info[0].rsv = da850_edma_cc0_rsv;
da850_edma_cc_info[1].rsv = da850_edma_cc1_rsv;
->


static struct edma_rsv_info da850_edma_cc0_rsv = {
	.rsv_chans	= da850_dma0_rsv_chans,
	.rsv_slots	= da850_dma0_rsv_slots,
};

static struct edma_rsv_info da850_edma_cc1_rsv = {
	.rsv_chans	= da850_dma1_rsv_chans,
	.rsv_slots	= da850_dma1_rsv_slots,
};


->

static const s16 da850_dma0_rsv_chans[][2] = {
	/* (offset, number) */
	{ 8,  6},//表示edma0cc0的8-13通道预留给DSP
	{24,  4},//表示edma0cc0的24-27通道预留给DSP
	{30,  2},//表示edma0cc0的30-31通道预留给DSP
	{-1, -1}//表示edma0cc0的14-23、28、29通道预留给ARM
};

static const s16 da850_dma0_rsv_slots[][2] = {
	/* (offset, number) */
	{ 8,  6},//表示edma0cc0的slot8-slot13预留给DSP
	{24,  4},//表示edma0cc0的slot24-slot27预留给DSP
	{30, 50},//表示edma0cc0的slot30-slot79预留给DSP
	{-1, -1}//表示edma0cc0的slot14-23,28,29,80-127预留给ARM
};

static const s16 da850_dma1_rsv_chans[][2] = {
	/* (offset, number) */
	{ 0, 28},//表示edma1cc0的0-27通道预留给DSP
	{30,  2},//表示edma1cc0的30、31通道预留给DSP
	{-1, -1}//表示edma1cc0的28,29通道预留给ARM
};

static const s16 da850_dma1_rsv_slots[][2] = {
	/* (offset, number) */
	{ 0, 28},//表示edma1cc0的slot0-slot27预留给DSP
	{30, 90},//表示edma1cc0的slot29-slot119预留给DSP
	{-1, -1}//表示edma1cc0的slot28,120-127预留给ARM
};

除了给DSP预留edma的通道和slot,da850_register_edmad的关键一步是进行了设备的注册即调用了platform_device_register(&da850_edma_device)这个函数:
platform_device_register(&da850_edma_device)
->


/**
 * 用于注册一个平台级别的设备
 * @pdev: platform device we're adding
 */
int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);
}

device_initalize()用于初始化设备结构:


/**
 * device_initialize - init device structure.
 * @dev: device.
 *
 * This prepares the device for use by other layers by initializing
 * its fields.
 * It is the first half of device_register(), if called by
 * that function, though it can also be called separately, so one
 * may use @dev's fields. In particular, get_device()/put_device()
 * may be used for reference counting of @dev after calling this
 * function.
 *
 * All fields in @dev must be initialized by the caller to 0, except
 * for those explicitly set to some other value.  The simplest
 * approach is to use kzalloc() to allocate the structure containing
 * @dev.
 *
 * NOTE: Use put_device() to give up your reference instead of freeing
 * @dev directly once you have called this function.
 */
void device_initialize(struct device *dev)
{
	dev->kobj.kset = devices_kset;
	kobject_init(&dev->kobj, &device_ktype);
	INIT_LIST_HEAD(&dev->dma_pools);
	mutex_init(&dev->mutex);
	lockdep_set_novalidate_class(&dev->mutex);
	spin_lock_init(&dev->devres_lock);
	INIT_LIST_HEAD(&dev->devres_head);
	device_pm_init(dev);
	set_dev_node(dev, -1);
}

platform_device_add用于向设备层级中添加platform设备


/**
 * platform_device_add - add a platform device to device hierarchy
 * @pdev: platform device we're adding
 *
 * This is part 2 of platform_device_register(), though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
	int i, ret = 0;

	if (!pdev)
		return -EINVAL;

	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;//父设备设置为platform_bus

	pdev->dev.bus = &platform_bus_type;//设置挂在platform总线上

	if (pdev->id != -1)
		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
	else
		dev_set_name(&pdev->dev, "%s", pdev->name);

	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *p, *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);

		p = r->parent;
		if (!p) {
			if (resource_type(r) == IORESOURCE_MEM)
				p = &iomem_resource;
			else if (resource_type(r) == IORESOURCE_IO)
				p = &ioport_resource;
		}

		if (p && insert_resource(p, r)) {
			printk(KERN_ERR
			       "%s: failed to claim resource %d\n",
			       dev_name(&pdev->dev), i);
			ret = -EBUSY;
			goto failed;
		}
	}

	pr_debug("Registering platform device '%s'. Parent at %s\n",
		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));

	ret = device_add(&pdev->dev);
	if (ret == 0)
		return ret;

 failed:
	while (--i >= 0) {
		struct resource *r = &pdev->resource[i];
		unsigned long type = resource_type(r);

		if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
			release_resource(r);
	}

	return ret;
}

再来看这个设备结构体的具体内容:
static struct platform_device da830_edma_device = {
.name = “edma”,
.id = -1,
.dev = {
.platform_data = da830_edma_info,
},
.num_resources = ARRAY_SIZE(da830_edma_resources),
.resource = da830_edma_resources,
};


static struct resource da830_edma_resources[] = {
	{
		.name	= "edma_cc0",
		.start	= DA8XX_TPCC_BASE,
		.end	= DA8XX_TPCC_BASE + SZ_32K - 1,
		.flags	= IORESOURCE_MEM,
	},
	{
		.name	= "edma_tc0",
		.start	= DA8XX_TPTC0_BASE,
		.end	= DA8XX_TPTC0_BASE + SZ_1K - 1,
		.flags	= IORESOURCE_MEM,
	},
	{
		.name	= "edma_tc1",
		.start	= DA8XX_TPTC1_BASE,
		.end	= DA8XX_TPTC1_BASE + SZ_1K - 1,
		.flags	= IORESOURCE_MEM,
	},
	{
		.name	= "edma0",
		.start	= IRQ_DA8XX_CCINT0,
		.flags	= IORESOURCE_IRQ,
	},
	{
		.name	= "edma0_err",
		.start	= IRQ_DA8XX_CCERRINT,
		.flags	= IORESOURCE_IRQ,
	},
};

platform 是一个虚拟的地址总线,相比 PCI、USB,它主要用于描述SOC上的片上资源。platform 所描述的资源有一个共同点:在CPU 的总线上直接取址。平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源。

platform 总线下驱动的开发步骤是:

1、 设备

需要实现的结构体是:platform_device 。

1)初始化 resource 结构变量

2)初始化 platform_device 结构变量

3)向系统注册设备:platform_device_register。

以上三步,必须在设备驱动加载前完成,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。platform_driver_register()中添加device到内核最终还是调用的device_add函数。Platform_device_add和device_add最主要的区别是多了一步insert_resource(p, r),即将platform资源(resource)添加进内核,由内核统一管理。

2、驱动

驱动注册中,需要实现的结构体是:platform_driver 。

在驱动程序的初始化函数中,调用了platform_driver_register()注册 platform_driver 。需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的 。这样在 platform_driver_register() 注册时,会将当前注册的 platform_driver 中的 name 变量的值和已注册的所有 platform_device 中的 name 变量的值进行比较,只有找到具有相同名称的 platform_device 才能注册成功。当注册成功时,会调用 platform_driver 结构元素 probe 函数指针。

platform_driver_register()的注册过程:

1 platform_driver_register(&s3c2410fb_driver)

2 driver_register(&drv->driver)

3 bus_add_driver(drv)

4 driver_attach(drv)

5 bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)

6 __driver_attach(struct device * dev, void * data)

7 driver_probe_device(drv, dev)

8 really_probe(dev, drv)

在really_probe()中:为设备指派管理该设备的驱动:dev->driver = drv, 调用probe()函数初始化设备:drv->probe(dev)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值