ZCU106 VCU Linux驱动转裸机驱动篇(四)

开始

首先上一张编码器的图:
ZCU106 VCU Linux驱动转裸机驱动篇(四)_第1张图片
从图中可以看出,编码器由一个MCU控制,然后通过AXI总线和外面数据交互,然后APU通过邮箱和MCU进行数据通信以及交互
下面是我们开修改过的probe函数,用在裸机上的,然后虽然名字没变,但里面内容以及大变,我们一次往下看

static int al5e_probe(device* pdev)
{
	int err;
	static int current_minor;

	struct al5_codec_desc *codec = &enc_codec;
	//devm_kzalloc主要用于设备内存的申请,在设备释放时可以自动释放内存
	//获取设备资源、dma、vcu的内存地址等
	err = al5_codec_set_up(codec, pdev, max_users_nb);
	if (err) {
		xil_printf("[ vcu ] Failed to setup codec : %s", pdev);
		return err;
	}
	//传输固件到mcu
	err = al5_codec_set_firmware(codec, AL5E_FIRMWARE,
				     AL5E_BOOTLOADER_FIRMWARE);
	if (err) {
		xil_printf("[ vcu ] %s - Failed to setup firmware!\r\n", pdev);
		//al5_codec_tear_down(codec);
		return err;
	}
	//创建设备
	//err = al5e_setup_codec_cdev(codec, current_minor);
	if (err) {
		xil_printf("[ vcu ] Failed to setup cdev : %s", pdev);
		//dev_err(&pdev->dev, "Failed to setup cdev");
		//al5_codec_tear_down(codec);
		return err;
	}
	codec->minor = current_minor;
	++current_minor;

	return 0;
}

有几个重要的函数这里说下:这里主要是设置mcu 指令的地址在哪里,我们通过ffats文件系统读取到数据以后吧数据放在缓冲区内

	config.cmd_base = (unsigned long)codec->regs + MAILBOX_CMD;
	config.cmd_size = MAILBOX_SIZE;
	config.status_base = (unsigned long)codec->regs + MAILBOX_STATUS;
	config.status_size = MAILBOX_SIZE;

	xil_printf("[ vcu ] start create interface with mcu\r\n");
	err = al5_mcu_interface_create(&mcu, codec->dev, &config,
				       codec->regs + AL5_MCU_INTERRUPT);
	if (err) {
		xil_printf(codec->dev);
		xil_printf("[ vcu ] --Can't create interface with mcu");
		//goto fail;
	}
	xil_printf("[ vcu ] start init user group!\r\n");
	al5_group_init(&codec->users_group, mcu, max_users_nb, codec->dev);

	err = alloc_mcu_caches(codec);
	if (err) {
		xil_printf(codec->dev);
		xil_printf("[ vcu ] --icache failed to be allocated");
		//goto fail;
	}

	//中断处理
	err = request_vcu_irq();
	if(err)
		xil_printf("[ vcu ] vcu irq register failed!\r\n");

中断主要是读取邮箱里面的数据,然后这里仿照linux实现一套上下文机制

static SemaphoreHandle_t xIrqSemaphore = NULL;

static struct irq_desc irq_root = {
		.next = NULL,
		.action = NULL,
		.data = NULL

};

void request_bottom_irq(struct irq_desc* irq_desc_ptr)
{
	struct irq_desc* cur = &irq_root;
	struct irq_desc* next = cur->next;

	while(next){
		cur = next;
		next = cur->next;
	}

	cur->next = irq_desc_ptr;
	irq_desc_ptr->next = NULL;
}


void raise_bottom_irq_from_irq(struct irq_desc* irq_desc_ptr)
{
	static BaseType_t xHigherPriorityTaskWoken;

	irq_desc_ptr->isRaised = 1;

	if(xIrqSemaphore) {
		//xil_printf("rasie irq botom, raise sem: %c\r\n", *(char *)(irq_desc_ptr->data));
		xHigherPriorityTaskWoken = 0;
		if(!xSemaphoreGiveFromISR( xIrqSemaphore, &xHigherPriorityTaskWoken )){
			xil_printf("Can't send SEM\r\n");
		}
	}

}


static void do_irq()
{
	struct irq_desc* cur = &irq_root;
	struct irq_desc* next = cur->next;

	xil_printf("irq in\r\n");
	while(next){
		cur = next;
		next = cur->next;

		if(cur) {
			if(cur->action && cur->isRaised) {
				cur->action(cur->data);
				cur->isRaised = 0;
			}
		}
		if(!next) break;
	}
	xil_printf("irq exit\r\n");
}


void irq_bottom_thread_entry(void *parameter)
{

	xIrqSemaphore = xSemaphoreCreateBinary();
	if(xIrqSemaphore == NULL) {
		while(1)
			xil_printf("Create SEM ERR!\n");
	}

	while (1)
	{
		if(xSemaphoreTake(xIrqSemaphore, portMAX_DELAY) == pdTRUE)
		{
			xil_printf("rasie irq do irq\r\n");
			do_irq();
			//xSemaphoreGive( xIrqSemaphore );
		}else {
			xil_printf("no rasie irq\r\n");
		}
	}
}

然后比较重要的是设置高速指令的地址在哪里:

static int alloc_mcu_caches(struct al5_codec_desc *codec)
{
	/* alloc the icache and the dcache */
	//codec->icache = al5_alloc_dma(codec->device, AL5_ICACHE_SIZE);
	//if (!codec->icache)
	//	return -ENOMEM;
	codec->icache.dma_handle = (u32)codec->icache.cpu_handle;
	usleep(10);
	xil_printf("[ vcu ] icache addr : 0x%x\r\n", codec->icache.dma_handle);
	//usleep(1000);
	/* dcache map base addr */

	codec->dcache_base_addr = 0;
//视频地址
	al5_writel(codec->icache.dma_handle >> 32, AXI_ADDR_OFFSET_IP);
	//printf("icache phy is at %p", (void *)codec->icache.dma_handle);

	return 0;
}

读取固件函数

static int request_all_firmwares(struct al5_codec_desc *codec,
				 struct firmware *fw,
				 struct firmware *bl_fw,
				 char *fw_file,
				 char *bl_fw_file)
{
	FIL fil; //文件对象
	//int fw_size = 0;
	FRESULT ret;//文件操作结果
	UINT fnum; //文件成功读写数量

	if(sd_init() != 0)
		return -1;

	ret = f_open(&fil, fw_file, FA_READ);
	if(ret != FR_OK){
		xil_printf("[ vcu ] Err find firware file %s\r\n", fw_file);
		return -1;
	} else {
		fw->size = f_size(&fil);
		f_read(&fil, fw->data, fw->size, &fnum);
		f_close(&fil);
		//xil_printf(fw_file);
		xil_printf("[ vcu ] %s--file size is %d, read num : %d\r\n", fw_file, (int)fw->size, fnum);
	}

	ret = f_open(&fil, bl_fw_file, FA_READ);
	if(ret != FR_OK){
		xil_printf("Err find firware file %s\r\n", bl_fw_file);
			return -1;
	} else {
		bl_fw->size = f_size(&fil);
		f_read(&fil, bl_fw->data, bl_fw->size, &fnum);
		f_close(&fil);
		//xil_printf(bl_fw_file);
		xil_printf("[ vcu ] %s--file size is %d, read num : %d\r\n", bl_fw_file, (int)bl_fw->size, fnum);
	}
	return ret;
}

固件下载

主要是把bootloader以及固件下载进去

static int setup_and_start_mcu(struct al5_codec_desc *codec,
			       struct firmware *fw,
			       struct firmware *bl_fw)
{
	int ret;

	stop_mcu(codec);//停止mcu
	reset_mcu(codec);//复位

	ret = copy_firmware(codec, fw, bl_fw);//复制固件
	if (ret)
		return ret;

	set_icache_offset(codec);//指令缓存
	set_dcache_offset(codec);//数据缓存
	set_mcu_interrupt_mask(codec);//引发中断

	start_mcu(codec);//开始运行mcu

	return 0;
}

copy固件如下:

	if (fw->size > AL5_ICACHE_SIZE) {
		xil_printf("[ vcu ] firmware is too big\r\n");
		return -1;
	}

	if (bl_fw->size > MCU_SRAM_SIZE) {
		xil_printf("[ vcu ] bootloader firmware is too big\r\n");
		return -1;
	}
	if(codec->icache.cpu_handle != fw->data)
		memcpy(codec->icache.cpu_handle, fw->data, fw->size);
	else
		xil_printf("[ vcu ] cache is same with buf!\r\n");

	memcpy_toio_32(codec->regs, bl_fw->data, bl_fw->size);

	return 0;

启动打印

[ vcu ] CLK : start read A0141000
[ vcu ] clk :Ref clock from logicoreIP is 33320000Hz
[ vcu ] clk :Core clock from logicoreIP is 667000000Hz
[ vcu ] clk :Mcu clock from logicoreIP is 444000000Hz
[ vcu ] pll set ok
[ vcu ] start create interface with mcu
[ vcu ] mcu set up init mailbox ok!
[ vcu ] start init user group!
[ vcu ] icache addr : 0x370C0
[ vcu ] al5e.fw--file size is 126572, read num : 126572
[ vcu ] al5e_bl.fw--file size is 14680, read num : 14680
[ vcu ] start setup_mcu..
[ vcu ] cache is same with buf!
[ irq ] : Got irq from Mcu: top half
[ vcu ] wait irq time :1 s
[ vcu ] l2 prefetch size:0 (bits), l2 color bitdepth:10
[ irq ] : Got irq from Mcu: top half
[ irq ] : Got irq from Mcu: top half
[ vcu ] wait irq time :1 s
[ vcu ] open success
[ vcu ] version : Sicllon2.0

目前做到了初始化设备,打开设备,然后编码器已经进入准备编码状态了,下一步开始驱动压缩了~

END

写的乱七八糟,因为这玩意移植起太麻烦了,哎~不过还好有眉头了,嘻嘻

你可能感兴趣的:(VCU,zynq,ARM)