Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Petalinux. PL DDR
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
doom13
Приветствую.
Плата zc706, системой управляет Linux.
Может кто подскажет, как "правильно прикрутить" PL DDR memory, чтобы был доступ из Kernel Space?
PL DDR используется под буферы данных и дескрипторы для AXI DMA (s2mm + mm2s), ядро Linux должно только обновлять дескрипторы DMA (DMA будет гонять данные между IP-блоками в FPGA).
Пока сделал так:
1) добавил в devicetree
Код
mig7series_ddr3: mig7series_ddr3 {
        compatible = "xlnx,mig7series_ddr3";
        device_type = "mig7series_ddr3";
        reg = <0x80000000 0x40000000>;
    };

2) драйвер выполняет
CODE

static int mig7series_probe(struct platform_device *pdev)
{
// struct resource *r_irq; /* Interrupt resources */
struct resource *r_mem; /* IO mem resources */
struct device *dev = &pdev->dev;
struct mig7series_local *lp = NULL;
int rc = 0, i;

dev_info(dev, "Device Tree Probing\n");

/* Get iospace for the device */
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

pr_info("r_mem = %p\n", r_mem);
if (!r_mem) {
dev_err(dev, "invalid address\n");
return -ENODEV;
}

lp = (struct mig7series_local *) kmalloc(sizeof(struct mig7series_local), GFP_KERNEL);
if (!lp) {
dev_err(dev, "Cound not allocate axidma_ddrmaster device\n");
return -ENOMEM;
}

dev_set_drvdata(dev, lp);

pr_info("r_mem->start = %p\n", r_mem->start);
pr_info("r_mem->end = %p\n", r_mem->end);

lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;

pr_info("lp->mem_start = %p\n", lp->mem_start);
pr_info("lp->mem_end = %p\n", lp->mem_end);

if (!request_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1, MIG7SERIES_DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at %p\n", (void *)lp->mem_start);
rc = -EBUSY;
goto error1;
}

lp->base_addr = ioremap(lp->mem_start, /*lp->mem_end - lp->mem_start + 1*/126*1024*1024);
if (!lp->base_addr) {
dev_err(dev, "axidma_ddrmaster: Could not allocate iomem\n");
rc = -EIO;
goto error2;
}

dev_info(dev, "mig7series_ddr3 at 0x%08x mapped to 0x%08x\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr);

pl_ddr3 = lp;

return 0;

error2:
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
kfree(lp);
dev_set_drvdata(dev, NULL);
return rc;
}


данный кусок памяти становится доступен на запись/чтение, но отдает не всё адресное пространство DDR (1 GB), а только 126*1024*1024 байт (вроде бы и достаточно, но как заполучить всю память?).
И вообще, правильный ли подход?

Стартануть DMA и обновлять дескрипторы пока не пробовал.
doom13
Ещё вопрос, кусок кода:
Код
struct mig7series_local {
    unsigned long mem_start;
    unsigned long mem_end;
    void __iomem *base_addr;
};

struct resource *r_mem; /* IO mem resources */
struct mig7series_local *lp = NULL;
int rc = 0, i;

/* Get iospace for the device */
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

pr_info("r_mem = %p\n", r_mem);
if (!r_mem) {
    dev_err(dev, "invalid address\n");
    return -ENODEV;
}

lp = (struct mig7series_local *) kmalloc(sizeof(struct mig7series_local), GFP_KERNEL);
if (!lp) {
    dev_err(dev, "Cound not allocate axidma_ddrmaster device\n");
    return -ENOMEM;
}


lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;

pr_info("lp->mem_start = %p\n", lp->mem_start);
pr_info("lp->mem_end = %p\n", lp->mem_end);

if (!request_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1,    MIG7SERIES_DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at %p\n", (void *)lp->mem_start);
    rc = -EBUSY;
    goto error1;
}

lp->base_addr = ioremap(lp->mem_start, /*lp->mem_end - lp->mem_start + 1*/PL_DDR3_MMAPED_SIZE);
if (!lp->base_addr) {
dev_err(dev, "axidma_ddrmaster: Could not allocate iomem\n");
    rc = -EIO;
    goto error2;
}

pr_info("lp->base_addr = %p\n", lp->base_addr);
pr_info("phys_to_virt(lp->mem_start) = %p\n", phys_to_virt(lp->mem_start));
pr_info("virt_to_phys(lp->base_addr) = %p\n", virt_to_phys(lp->base_addr));

в консоль выводит
Код
lp->mem_start = 80000000
lp->mem_end = bfffffff
lp->base_addr = f1000000
phys_to_virt(lp->mem_start) = 40000000
virt_to_phys(lp->base_addr) = 31000000

Почему преобразования phys_to_virt и virt_to_phys работают неправильно?
nill
Цитата(doom13 @ Nov 11 2016, 16:09) *
данный кусок памяти становится доступен на запись/чтение, но отдает не всё адресное пространство DDR (1 GB), а только 126*1024*1024 байт (вроде бы и достаточно, но как заполучить всю память?).

Ядро резервирует 1 Гб адресного пространства под собственные нужды. В этот кусок, помимо прочего, отображается память, полученнвя через ioremap. Вы пытаетесь в эту область отобразить свой гигабайт и он туда не влазит. Как получить всё - не подскажу, поскольку не сталкивался, но попробуйте почитать Documentation/io-mapping.txt. Можно ещё поискать как это делается для видеопамяти.

Цитата(doom13 @ Nov 11 2016, 20:29) *
Почему преобразования phys_to_virt и virt_to_phys работают неправильно?

Эти преоразования имеют смысл только для системной памяти. И вообще, эти функции не рекомендуется использовать, где-то в документации к ядру об этом сказано.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.