WhyCan Forum

人过留名,雁过留声,感谢各位朋友不离不弃地支持。 QQ: 516333132 (挖坑网/填坑网) admin@whycan.cn

您尚未登录。

#1 2018-08-14 12:33:04

达克罗德
会员
注册时间: 2018-04-10
累计积分: 598

谁有V3S或者F1C100s的DMA例程?

当前xboot似乎没有DMA的驱动,我想看看能否把SPI的读写以及memcpy用DMA来加速

离线

#2 2018-08-14 13:39:07

晕哥
Administrator
注册时间: 2017-09-06
累计积分: 8,230

Re: 谁有V3S或者F1C100s的DMA例程?

离线

#3 2018-08-14 13:48:32

达克罗德
会员
注册时间: 2018-04-10
累计积分: 598

Re: 谁有V3S或者F1C100s的DMA例程?

非常感谢,你找资源可真快呀!

离线

#4 2018-08-14 13:55:43

晕哥
Administrator
注册时间: 2017-09-06
累计积分: 8,230

Re: 谁有V3S或者F1C100s的DMA例程?

因为刚好在搞这个 f1c100s 官方bsp, 用官方的 sys_config.fex(全志发明的设备树)套路, 发现屏幕驱动有问题。
顺手就传上来了.

离线

#5 2018-08-19 22:10:41

mianhua
会员
注册时间: 2018-08-19
累计积分: 6

Re: 谁有V3S或者F1C100s的DMA例程?

请问显示的时候是不是已经用了DMA?
void fb_present(struct framebuffer_t * fb, struct render_t * render)
{
    struct fb_f1c100s_pdata_t * pdat = (struct fb_f1c100s_pdata_t *)fb->priv;

    if(render && render->pixels)
    {
        pdat->index = (pdat->index + 1) & 0x1;
        memcpy(pdat->vram[pdat->index], render->pixels, render->pixlen);
        dma_cache_sync(pdat->vram[pdat->index], render->pixlen, DMA_TO_DEVICE);
        f1c100s_debe_set_address(pdat, pdat->vram[pdat->index]);
    }
}

离线

#6 2018-08-19 22:23:59

达克罗德
会员
注册时间: 2018-04-10
累计积分: 598

Re: 谁有V3S或者F1C100s的DMA例程?

mianhua 说:

请问显示的时候是不是已经用了DMA?
void fb_present(struct framebuffer_t * fb, struct render_t * render)
{
    struct fb_f1c100s_pdata_t * pdat = (struct fb_f1c100s_pdata_t *)fb->priv;

    if(render && render->pixels)
    {
        pdat->index = (pdat->index + 1) & 0x1;
        memcpy(pdat->vram[pdat->index], render->pixels, render->pixlen);
        dma_cache_sync(pdat->vram[pdat->index], render->pixlen, DMA_TO_DEVICE);
        f1c100s_debe_set_address(pdat, pdat->vram[pdat->index]);
    }
}

这里dma_cache_sync我没有看到dma具体实现,感觉还是靠memcpy软拷贝的

离线

#7 2018-08-26 23:21:17

达克罗德
会员
注册时间: 2018-04-10
累计积分: 598

Re: 谁有V3S或者F1C100s的DMA例程?

void sys_dma_init()
{
	/* Enable gate for DMA clock, and perform softreset */
	write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) | (0x1 << 6));
	write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) & ~(0x1 << 6));
	for(int i = 0; i < 10; i++)
		continue;
	write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 6));
}

void sys_dma_wait_end(int ch)
{
	u32_t cfg_reg = 0x80000000;
	/* when the dma end, it clear this bit automatically */
	while ((cfg_reg & 0x80000000) ) {
		cfg_reg = read32(NDMA_CHANNEL_REG_BASE(ch) +
						NDMA_CFG_REG);
	}
}

void sys_dma_dram_copy(int dma_ch, void * dest, void *src, size_t len)
{
	virtual_addr_t addr = NDMA_CHANNEL_REG_BASE(dma_ch);
	u32_t val = 0;
	u32_t bytes_cnt;

	while(len)
	{
		if(len >= SZ_128K)
		{
			bytes_cnt = SZ_128K;
		}
		else
		{
			bytes_cnt = len;
		}
		len -= bytes_cnt;

		/* Set source address */
		write32(addr + NDMA_SRC_ADR_REG, (u32_t)src);

		/* Set dst address */
		write32(addr + NDMA_DST_ADR_REG, (u32_t)dest);

		/* Set byte number */
		write32(addr + NDMA_BYTE_CNT_REG, bytes_cnt);

		/* Set config and start */
		val = (1 << 31) | (2 << 24) | (1 << 23) | (0x11 << 16) | (2 << 8) | (1 << 7) | (0x11 << 0);
		// val = NDMA_SDRAM2SDRAM_CFG;
		write32(addr + NDMA_CFG_REG, val);

		/* Wait end */
		sys_dma_wait_end(dma_ch);
		src += bytes_cnt;
		dest += bytes_cnt;
	}
}

今天写了个最简单的SDRAM to SDRAM的DMA copy函数,已经调试通过。
注意src需要是用dma_alloc_coherent函数得到的空间才行,估计是cache同步的问题,否则数据有异常。

把这个函数用在framebuffer的拷贝上,替代memcpy,结果发现速度还不如memcpy。估计F1C100S的DMA时钟很慢?另外一个主要原因是DMA一次传输竟然只支持128KB字节,所以不得不CPU polling在这里然后等结束后继续下一个128KB传输,DMA的并行处理机制完全没被充分利用起来。等我有时间了,做个用中断中管理DMA的,才能充分发挥DMA的优势。

下面是带头文件的源程序:
f1c100s-dma.zip

离线

#8 2018-08-27 07:38:58

晕哥
Administrator
注册时间: 2017-09-06
累计积分: 8,230

Re: 谁有V3S或者F1C100s的DMA例程?

这个实在太好了,
晚点移植到MDK也分享上来。

离线

#9 2018-09-03 11:34:24

达克罗德
会员
注册时间: 2018-04-10
累计积分: 598

Re: 谁有V3S或者F1C100s的DMA例程?

dedicated DMA支持16M字节传输,所以可以简化代码

static void sys_ddma_wait_end(int ch)
{
	u32_t cfg_reg = 0x80000000;
	/* when the dma end, it clear this bit automatically */
	while ((cfg_reg & 0x80000000) ) {
		cfg_reg = read32(DDMA_CHANNEL_REG_BASE(ch) +
						DDMA_CFG_REG);
	}
}

void sys_ddma_dram_copy(int dma_ch, void * dest, void *src, size_t bytes_cnt)
{
	virtual_addr_t base = DDMA_CHANNEL_REG_BASE(dma_ch);
	u32_t val = 0;

	if (bytes_cnt > SZ_16M)
	{
		bytes_cnt = SZ_16M;
	}

	/* Set source address */
	write32(base + DDMA_SRC_ADR_REG, (u32_t)src);

	/* Set dst address */
	write32(base + DDMA_DST_ADR_REG, (u32_t)dest);

	/* Set byte number */
	write32(base + DDMA_BYTE_CNT_REG, bytes_cnt);

	/* Set config and start */
	val = (1 << 31) | (2 << 24) | (1 << 23) | (0x1 << 16) | (2 << 8) | (1 << 7) | (0x1 << 0);
	// val = NDMA_SDRAM2SDRAM_CFG;
	write32(base + DDMA_CFG_REG, val);

	/* Wait end */
	sys_ddma_wait_end(dma_ch);
}

离线

#10 2019-10-30 19:57:05

ffplay
会员
注册时间: 2019-08-31
累计积分: 69

Re: 谁有V3S或者F1C100s的DMA例程?

好帖, 帮顶起来.

离线

页脚