開始
首先上一張編碼器的圖:
從圖中可以看出,編碼器由一個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
寫的亂七八糟,因爲這玩意移植起太麻煩了,哎~不過還好有眉頭了,嘻嘻