реклама на сайте
подробности

 
 
> Petalinux. PL DDR
doom13
сообщение Nov 11 2016, 09:09
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 404
Регистрация: 11-03-11
Из: Минск, Беларусь
Пользователь №: 63 539



Приветствую.
Плата 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 и обновлять дескрипторы пока не пробовал.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 2)
doom13
сообщение Nov 11 2016, 13:29
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 404
Регистрация: 11-03-11
Из: Минск, Беларусь
Пользователь №: 63 539



Ещё вопрос, кусок кода:
Код
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 работают неправильно?
Go to the top of the page
 
+Quote Post
nill
сообщение Nov 12 2016, 08:01
Сообщение #3


Частый гость
**

Группа: Validating
Сообщений: 124
Регистрация: 10-08-05
Пользователь №: 7 502



Цитата(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 работают неправильно?

Эти преоразования имеют смысл только для системной памяти. И вообще, эти функции не рекомендуется использовать, где-то в документации к ядру об этом сказано.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 21:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01269 секунд с 7
ELECTRONIX ©2004-2016