ZCU106 VCU Linux驅動轉裸機驅動篇(四)

開始

首先上一張編碼器的圖:
在這裏插入圖片描述
從圖中可以看出,編碼器由一個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

寫的亂七八糟,因爲這玩意移植起太麻煩了,哎~不過還好有眉頭了,嘻嘻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章