LINUX.ORG.RU

platform driver & device_tree

 ,


0

1

Здравствуйте всем!

Для модуля на платформе zynq пытаюсь написать platform_driver. Это достаточно новая тема для меня. В модуле есть источник данных DDS, который выдает их через AXI_DMA в DDR3. Написал приложение, программируя регистры узлов через mmap(). Все работает: DMA, GPIO, DDS. Приложение использовалось для отладки прошивки FPGA. Теперь нужно написать «правильно» с использованием драйвера и подсистемы dmaengine linux.

За основу взял вот это: https://github.com/Xilinx/linux-xlnx/blob/master/drivers/dma/xilinx/axidmatest.c

И столкнулся со следующими вопросами:

1) Как еще можно получить дескриптор конкретного канала DMA, кроме: dma_request_slave_channel(&pdev->dev, «dma») + создание дополнительного виртуального устройства в dts (см. ниже метка - custom_device)? Т.е. можно ли получить дескриптор канала не из platform_device? Пытался добавлять dmas и dma-names непосредственно в axi_dma_0 - результата не получил.

2) Как можно получить ресурсы узла gpio@41200000, если у меня в виртуальном устройстве есть phandle этого узла. (нужно для синхронизации и сброса) Ну или как можно получить эти ресурсы из dtb? Т.к. в поле dev->dev.of_node есть только phandle.

Вот фрагмент моего dts:

                axi_dma_0: dma@40400000 {
                        #dma-cells = <1>;
                        compatible = "xlnx,axi-dma-1.00.a";
                        dma-channel@40400030 {
                                compatible = "xlnx,axi-dma-s2mm-channel";
                                dma-channels = <0x1>;
                                interrupts = <0 29 4>;
                                xlnx,datawidth = <0x40>;
                                xlnx,device-id = <0x0>;
                        };
                };
                axi_gpio_0: gpio@41200000 {
                        #gpio-cells = <2>;
                        compatible = "xlnx,xps-gpio-1.00.a";
                        gpio-controller ;
                        reg = <0x41200000 0x10000>;
                };
                custom_device: custom {
                        compatible = "custom,axi-dma-test-1.00.a";
                        dmas = <&axi_dma_0 0>;
                        dma-names = "dma";
                        gpio0 = <&axi_gpio_0>;
                };

Могу предоставить любую дополнительную информацию. Буду балгодарен за любую помощь. Спасибо.



Последнее исправление: karak (всего исправлений: 1)

Все ресурсы находятся через Open Firmware (функции of_*). У меня под рукой сейчас кода нет, но в ядре точно есть примеры.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо за ответ. Да, я просмотрел большинство функций в of.h и примеры работы в драйверах, но использование, подходящих, на мой взгляд функций, почему-то не помогает. Понятно, что проблема во мне :) пока исследую, как эти фукнции работают.

#define GPIO_PROPERTY_NAME "gpio0"
//#define GPIO_PROPERTY_NAME "axi_gpio_0"
//#define GPIO_PROPERTY_NAME "gpio"

    ph = of_get_property(pdev->dev.of_node, GPIO_PROPERTY_NAME, 0);
    if(ph) {
        pr_err("%s() - of_get_property(%s) - Ok. ph = 0x%x\n", __func__, GPIO_PROPERTY_NAME, ph[0]);
        dn = of_find_node_by_phandle(ph[0]);
        if(dn) {
            uint32_t reg[2] = {0,0};
            pr_err("%s() - of_find_node_by_phandle(): - Ok\n", __func__);
            if(of_property_read_u32_array(dn, "reg", reg, sizeof(reg)) == 0) {
                pr_err("%s(). reg[0]: 0x%x\n", __func__, reg[0]);
                pr_err("%s(). reg[1]: 0x%x\n", __func__, reg[1]);
            } else {
                pr_err("%s(). Erorr in of_property_read_u32_array()\n", __func__);
            }
            of_node_put(dn);
        } else {
            pr_err("%s(). Erorr in of_find_node_by_phandle()\n", __func__);
        }
    } else {
        pr_err("%s(). Erorr in of_get_property()\n", __func__);
    }

И вывод при загрузке драйвера:

# modprobe isdmatest
zynq_init()
zynq_probe(). Get DMA channel: dma2chan0
zynq_probe(). of_find_node_by_phandle(): gpio - Ok
zynq_probe(). reg[0]: 0xe000a000
zynq_probe(). reg[1]: 0x0

но это не тот адрес, который должен быть, да и размер маловат.

karak
() автор топика
Ответ на: комментарий от karak

но это не тот адрес, который должен быть, да и размер маловат.

Отчего же не тот ?

#define GPIO_PROPERTY_NAME "gpio0"
...
ph = of_get_property(pdev->dev.of_node, GPIO_PROPERTY_NAME, 0); 

А вот что мы видим в стандартном zynq dts по поводу gpio0:

		gpio0: gpio@e000a000 {
			compatible = "xlnx,zynq-gpio-1.0";
			#gpio-cells = <2>;
			clocks = <&clkc 42>;
			gpio-controller;
			interrupt-parent = <&intc>;
			interrupts = <0 20 4>;
			reg = <0xe000a000 0x1000>;
		};

alx777 ★★
()
Ответ на: комментарий от alx777

Да. Протупил. Смотрел на одинаковость меток только xxx-pl файл, который SDK генерирует, а вот остальные (а их там несколько) нет! Спасибо. Сделал неправильно :) Сейчас исправляю буду двигаться дальше.

karak
() автор топика
Ответ на: комментарий от karak

После того как поправил имена свойств, получил следующее:

Дерево устройств (фрагмент)

                axi_dma_0: dma@40400000 {
                        #dma-cells = <1>;
                        compatible = "xlnx,axi-dma-1.00.a";
                        dma-channel@40400030 {
                                compatible = "xlnx,axi-dma-s2mm-channel";
                                dma-channels = <0x1>;
                                interrupts = <0 29 4>;
                                xlnx,datawidth = <0x40>;
                                xlnx,device-id = <0x0>;
                        };
                };
                axi_gpio_0: gpio@41200000 {
                        #gpio-cells = <2>;
                        compatible = "xlnx,xps-gpio-1.00.a";
                        gpio-controller ;
                        reg = <0x41200000 0x10000>;
                };
                custom_module: custom {
                        compatible = "custom,axi-dma-test-1.00.a";
                        dmas = <&axi_dma_0 0>;
                        dma-names = "dma";
                        custom_gpio0 = <&axi_gpio_0>;
                };

Драйвер (фрагмент)

#define GPIO_PROPERTY_NAME "custom_gpio0"
//#define GPIO_PROPERTY_NAME "gpio0"
//#define GPIO_PROPERTY_NAME "axi_gpio_0"
//#define GPIO_PROPERTY_NAME "gpio"

    ph = of_get_property(pdev->dev.of_node, GPIO_PROPERTY_NAME, &len);
    if(ph) {
        printk(KERN_ERR"%s() - of_get_property() - Ok. ph = 0x%x\n", __func__, ph[0]);
        dn = of_find_node_by_phandle(ph[0]);
        if(dn) {
            uint32_t reg = 0;
            uint32_t size = 0;
            printk(KERN_ERR"%s() - of_find_node_by_phandle(): - Ok\n", __func__);
            //if(of_property_read_u32_array(dn, "reg", reg, sizeof(reg)) == 0) {
            if(of_property_read_u32(dn, "reg", &reg) == 0) {
                printk(KERN_ERR"%s(). reg = 0x%x\n", __func__, reg);
            }
            if(of_property_read_u32(dn, "size", &size) == 0) {
                printk(KERN_ERR"%s(). size = 0x%x\n", __func__, size);
            }
            of_node_put(dn);
        }
    }

Вывод при загрузке драйвера:

# modprobe isdmatest
zynq_init()
zynq_probe(). Get DMA channel: dma2chan0
zynq_probe() - of_get_property() - Ok. ph = 0x10000000

Теперь не могу получить ничего :( Т.е. dn = of_find_node_by_phandle(ph[0]) возвращает 0. Наверное нужно использовать что-то другое в этом случае. И, почему-то, когда вернул GPIO_PROPERTY_NAME «gpio0» (в dts и драйвере), то ничего не происходит. Так же возвращается 0. (DTS пересобирал и перегружал устройство каждый раз после пересборки DTS)

karak
() автор топика
Ответ на: комментарий от alx777

Спасибо! Да. Это читал. Хотя умные люди не читают, они перечитывают :) а еще не перечитывал!

Еще можно в копилку добавить, вдруг кто воспользуется:

http://elinux.org/Device_Tree_Usage

http://elinux.org/Device_Tree_Mysteries

karak
() автор топика
Ответ на: комментарий от karak

После выполнения обратной операции:

dtc -O dts custom.dtb -o custom.dts

Вижу, что в custom.dts есть нужные поля, но их значения phandle отличаются от того, что я получаю.


gpio@41200000 {
        compatible = "xlnx,xps-gpio-1.00.a";
        ++++++++++++
        linux,phandle = <0x10>;
        phandle = <0x10>;
};

custom {
        compatible = "custom,axi-dma-test-1.00.a";
        dmas = <0xf 0x0>;
        dma-names = "dma";
        custom_gpio0 = <0x10>;
};

Старшие биты в значении ph = 0x10000000 - совпадают :)

karak
() автор топика
Ответ на: комментарий от karak

Когда «тупо заменил» и вместо

dn = of_find_node_by_phandle(ph[0]);
стал использовать значение которое есть в phandle = <0x10>
dn = of_find_node_by_phandle(0x10);
то получил вроде как правильный вывод:
# modprobe isdmatest
zynq_init()
zynq_probe(). Get DMA channel: dma2chan0
zynq_probe() - of_get_property() - Ok. len = 4, ph = 0x10000000
zynq_probe() - of_find_node_by_phandle(): - Ok
zynq_probe(). reg = 0x41200000
Отсюда вспомнилось, что dtb в be формате, и добавив
dn = of_find_node_by_phandle(be32_to_cpu(*ph));
получил правильный результат.

karak
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.