英文:
How to add device tree support and DMA assignement to character device module?
问题
你好,开发者们,
我正在开发一个Linux内核模块,它使用DMA通道来在STM32MP157F上传输内存。
这个功能已经实现,但还需要进行额外的调整。STM mdma内核模块通过使用以下私有配置结构来实现这一点:
struct stm32_mdma_chan_config {
u32 request;
u32 priority_level;
u32 transfer_config;
u32 mask_addr;
u32 mask_data;
bool m2m_hw;
};
我想将优先级从0x0设置为0x3,这是其允许的最大值。
变量priority_level
在stm32_mdma_of_xlate函数中设置:
static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct stm32_mdma_chan_config config;
config.request = dma_spec->args[0];
config.priority_level = dma_spec->args[1];
// 其他操作
}
系统中的其他模块/驱动程序使用设备树设置,例如以下用于其所使用的DMA通道配置:
spi@44004000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
dmas = <0x0e 0x25 0x400 0x01 0x0e 0x26 0x400 0x01>;
dma-names = "rxspi@44004000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
dmas = <0x0e 0x25 0x400 0x01 0x0e 0x26 0x400 0x01>;
dma-names = "rx\0tx";
};
tx";
};
spi-stm32.c在其stm32_spi_probe函数中调用of_match_device。我相信DMA配置是在其执行过程中完成的。
我想为我的字符设备驱动程序实现类似的功能:
mydriver@0 {
compatible = "mydriver";
dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>,
<&mdma1 37 0x0 0x40002 0x0 0x0>;
dma-names = "rx", "tx";
};
但目前这被忽略了,因为我没有平台设备可以用来调用of_match_device。我似乎被太多的源代码所迷惑...
对我有什么建议吗?
更新:
目前正在研究http://xillybus.com/tutorials/device-tree-zynq-3
祝好 Gunther
英文:
Hello fellow developers,
I am developing a Linux kernel module that uses a DMA channel to transfer memory
(on STM32MP157F).
This works but additional tuning should be made. The STM mdma kernel module makes this possible by using this private configuration struct:
struct stm32_mdma_chan_config {
u32 request;
u32 priority_level;
u32 transfer_config;
u32 mask_addr;
u32 mask_data;
bool m2m_hw;
};
I would like set the priority from 0x0 to 0x3 which is its maximum allowed value.
The variable priority_level is set in stm32_mdma_of_xlate function:
static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct stm32_mdma_chan_config config;
config.request = dma_spec->args[0];
config.priority_level = dma_spec->args[1];
....
}
Other modules/drivers in the system use a device tree setting like this for its and the used DMA channel configuration.
spi@44004000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
dmas = <0x0e 0x25 0x400 0x01 0x0e 0x26 0x400 0x01>;
dma-names = "rxspi@44004000 {
#address-cells = <0x01>;
#size-cells = <0x00>;
dmas = <0x0e 0x25 0x400 0x01 0x0e 0x26 0x400 0x01>;
dma-names = "rx\0tx";
};
tx";
};
spi-stm32.c calls of_match_device in its stm32_spi_probe function. I believe the dma configuration is done during its execution.
I would like something similar for my character device driver:
mydriver@0 {
compatible = "mydriver";
dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>,
<&mdma1 37 0x0 0x40002 0x0 0x0>;
dma-names = "rx", "tx";
};
But this is currently ignored because I do not have a platform device I could use to call
of_match_device. I seem to be blinded by to much source code to look at ...
Any tips for me?
Update:
Currently studying http://xillybus.com/tutorials/device-tree-zynq-3
Best regards Gunther
答案1
得分: 2
我在进行了一些额外的研究后解决了我的问题。以下是这些步骤:
我不得不向设备树添加一个自定义条目:
mydriver_0: mydriver@0 {
compatible = "mydriver";
dmas = <&mdma1 22 0x3 0x1200000a 0x48001008 0x00000020 1>;
dma-names = "dma0";
};
使驱动程序可以作为平台驱动程序加载。创建一个与设备树条目匹配的of_device_id
匹配表。将module_init()
更改为调用platform_driver_register()
以注册匹配表。然后实现一个探测函数,调用先前的初始化函数。存储pdev
。
static int mydriver_drv_probe(struct platform_device *pdev)
{
// 为以后调用 dma_channel_req(&pdev->dev, "dma0"); 存储 pdev
// TODO 初始化驱动程序
return 0;
}
/* 与设备树的连接 */
static struct of_device_id mydriver_of_match[] =
{
{ .compatible = "mydriver" },
{}
};
MODULE_DEVICE_TABLE(of, mydriver_of_match);
static struct platform_driver mydriver_platform_driver = {
.probe = mydriver_drv_probe,
.remove = mydriver_drv_remove,
.driver = {
.name = "mydriver",
.owner = THIS_MODULE,
.of_match_table = mydriver_of_match,
},
};
static int __init _mydriver_driver_init(void)
{
return platform_driver_register(&mydriver_platform_driver);
}
module_init(_mydriver_driver_init);
获取正确配置的DMA通道:
chan = dma_request_chan(&pdev->dev, "dma0");
我测试过这个,它有效。所请求的DMA通道是使用我的设备树中的"dmas"条目配置的。
希望对其他人有所帮助!
英文:
I solved my issues after doing some extra research.
These are the steps:
I had to add a custom entry to the device tree:
<!-- language: lang-dts -->
mydriver_0: mydriver@0 {
compatible = "mydriver";
dmas = <&mdma1 22 0x3 0x1200000a 0x48001008 0x00000020 1>;
dma-names = "dma0";
};
Make the driver loadable as a platform driver. Create an of_device_id
match table matching the device tree entry. Change module_init()
to call platform_driver_register()
to register the matching table. Then implement a probe function calling the previous init function. Store pdev
.
<!-- language: lang-c -->
static int mydriver_drv_probe(struct platform_device *pdev)
{
// store pdev for later call to: dma_channel_req(&pdev->dev, "dma0");
// TODO init driver
return 0;
}
/* Connection to device tree */
static struct of_device_id mydriver_of_match[] =
{
{ .compatible = "mydriver" },
{}
};
MODULE_DEVICE_TABLE(of, mydriver_of_match);
static struct platform_driver mydriver_platform_driver = {
.probe = mydriver_drv_probe,
.remove = mydriver_drv_remove,
.driver = {
.name = "mydriver",
.owner = THIS_MODULE,
.of_match_table = mydriver_of_match,
},
};
static int __init _mydriver_driver_init(void)
{
return platform_driver_register(&mydriver_platform_driver);
}
module_init(_mydriver_driver_init);
Get the correctly configured DMA channel:
<!-- language: lang-c -->
chan = dma_request_chan(&pdev->dev, "dma0");
I tested this and it worked. The requested DMA channel is configured using the my device tree "dmas" entry.
I hope this of use for somebody else!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论