首先上一张编码器的图:
从图中可以看出,编码器由一个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
目前做到了初始化设备,打开设备,然后编码器已经进入准备编码状态了,下一步开始驱动压缩了~
写的乱七八糟,因为这玩意移植起太麻烦了,哎~不过还好有眉头了,嘻嘻