Splashing splashing liukun321
From: http://blog.csdn.net/liukun321
Samsung series processors, from s3c6410 onwards, integrate an MFC (Multi format CODEC) multi-format Media codec hardware module on the SOC. And Samsung's Linux BSP is open source for its drive. Having seen the MFC-driven friends, I must have found that during the driver initialization process, the kernel needs to load a Samsung MFC firmware. MFC is no use without it. Let's see how this firmware is connected to the kernel. Where to get the firmware.
First look at the MFC firmware loading, this process is as follows, with exynos4412 Linux 3.5 BSP As an example, in LINUX-3.5\DRIVERS\MEDIA\VIDEO\S5P-MFC\S5P_MFC.C:
static int S5p_mfc_open (struct file *file) {Structs5p_mfc_dev *dev = video_drvdata (file); Structs5p_mfc_ctx *ctx = NULL; Structvb2_queue *q; Unsignedlong flags; intret = 0; Exynos_cpufreq_lock_freq (1,max_cpu_freq); #ifdef Config_busfreq_opp Dev_lock (Dev->bus_dev,dev->device, BUSFR Eq_400mhz); #endif mfc_debug_enter (); dev->num_inst++; /* It is guarded by Mfc_mutex in VfD *//*allocate Memory for context */ctx= kzalloc (sizeof *ctx, Gfp_ker NEL); if (!ctx) {mfc_err ("Notenough memory\n"); Ret=-enomem; Gotoerr_alloc; } v4l2_fh_init (&ctx->fh,video_devdata (file)); File->private_data= &ctx->fh; V4l2_fh_add (&CTX->FH); ctx->dev= Dev; Init_list_head (&ctx->src_queue); Init_list_head (&ctx->dst_queue); Ctx->src_queue_cnt= 0; CtX->dst_queue_cnt= 0; /*get Context Number */ctx->num= 0; while (Dev->ctx[ctx->num]) {ctx->num++; if (ctx->num >= mfc_num_contexts) {mfc_err ("Toomany open contexts\n"); Ret=-ebusy; Gotoerr_no_ctx; }}/*mark Context as Idle */Spin_lock_irqsave (&dev->condlock,flags); Clear_bit (ctx->num,&dev->ctx_work_bits); Spin_unlock_irqrestore (&dev->condlock,flags); Dev->ctx[ctx->num]= CTX; if (s5p_mfc_get_node_type (file) = = Mfcnode_decoder) {ctx->type= mfcinst_decoder; Ctx->c_ops= Get_dec_codec_ops (); /*setup CTRL Handler */Ret= S5p_mfc_dec_ctrls_setup (CTX); if (ret) {mfc_err ("Failedto Setup MFC controls\n"); Gotoerr_ctrls_setup; }}else if (s5p_mfc_get_node_type (file) = = Mfcnode_encoder) {ctx->type= mfcinst_encoder; Ctx->c_ops= Get_enc_codec_ops (); /*only for Encoder */init_list_head (&ctx->ref_queue); Ctx->ref_queue_cnt= 0; /*setup CTRL Handler */Ret= S5p_mfc_enc_ctrls_setup (CTX); if (ret) {mfc_err ("Failedto Setup MFC controls\n"); Gotoerr_ctrls_setup; }}else {ret=-enoent; Gotoerr_bad_node; } ctx->fh.ctrl_handler= &ctx->ctrl_handler; ctx->inst_no=-1; /*load firmware If this is the first instance */if (dev->num_inst = = 1) {Dev->watchdog_ti mer.expires= Jiffies + Msecs_to_jiffies (Mfc_watchdog_interval); Add_timer (&dev->watchdog_timer); Ret= s5p_mfc_power_on (); if (Ret < 0) {Mfc_err ("PowerOn failed\n"); gotoerr_pwr_enable; } s5p_mfc_clock_on (); ret = S5p_mfc_alloc_and_load_firmware (dev); if (ret) GOTOERR_ALLOC_FW; /*init the FW */ret= s5p_mfc_init_hw (Dev); if (ret) GOTOERR_INIT_HW; S5p_mfc_clock_off (); }/*init videobuf2 queue for CAPTURE */q= &ctx->vq_dst; Q->type= V4l2_buf_type_video_capture_mplane; q->drv_priv= &ctx->fh; if (s5p_mfc_get_node_type (file) = = Mfcnode_decoder) {q->io_modes= Vb2_mmap | Vb2_dmabuf; Q->ops= Get_dec_queue_ops (); }else if (s5p_mfc_get_node_type (file) = = Mfcnode_encoder) {q->io_modes= Vb2_mmap | Vb2_userptr | Vb2_dmabuf; Q->ops= Get_enc_queue_ops (); }else {ret=-enoent; Gotoerr_queue_init; } q->mem_ops= (struct vb2_mem_ops *) &vb2_dma_contig_memops; ret= Vb2_queue_init (q); if (ret) {mfc_err ("Failedto Initialize VIDEOBUF2 queue (capture) \ n"); Gotoerr_queue_init; }/*init videobuf2 queue for OUTPUT */q= &ctx->vq_src; Q->type= V4l2_buf_type_video_output_mplane; Q->io_modes= Vb2_mmap; q->drv_priv= &ctx->fh; if (s5p_mfc_get_node_type (file) = = Mfcnode_decoder) {q->io_modes= Vb2_mmap | Vb2_dmabuf; Q->ops= Get_dec_queue_ops (); }else if (s5p_mfc_get_node_type (file) = = Mfcnode_encoDER) {q->io_modes= Vb2_mmap | Vb2_userptr | Vb2_dmabuf; Q->ops= Get_enc_queue_ops (); }else {ret=-enoent; Gotoerr_queue_init; } q->mem_ops= (struct vb2_mem_ops *) &vb2_dma_contig_memops; ret= Vb2_queue_init (q); if (ret) {mfc_err ("Failedto initialize VIDEOBUF2 queue (output) \ n"); Gotoerr_queue_init; } init_waitqueue_head (&ctx->queue); Mfc_debug_leave (); Returnret; /*deinit When failure occured */err_queue_init:err_init_hw:s5p_mfc_release_firmware (dev); err_alloc_fw:de V->ctx[ctx->num]= NULL; Del_timer_sync (&dev->watchdog_timer); S5p_mfc_clock_off (); Err_pwr_enable:if (dev->num_inst = = 1) {if (S5p_mfc_power_off () < 0) Mfc_err ("Poweroff failed\n"); S5p_mfc_release_fIrmware (Dev); }err_ctrls_setup:s5p_mfc_dec_ctrls_delete (CTX); Err_bad_node:err_no_ctx:v4l2_fh_del (&CTX->FH); V4l2_fh_exit (&CTX->FH); Kfree (CTX);err_alloc:dev->num_inst--; Mfc_debug_leave (); Returnret;}
Expand 83rd Line function ret = s5p_mfc_alloc_and_load_firmware (dev); :
int S5p_mfc_alloc_and_load_firmware (struct S5p_mfc_dev *dev) {struct firmware *fw_blob;size_t bank2_base_phys;void *b_ Base;int err;/* Firmare have to is present as a separate file or compiled * into kernel. */mfc_debug_enter (); err = Request_firmware ((const struct firmware * *) &fw_blob, "S5P-MFC.FW", Dev->v4l2_dev.dev ); if (err! = 0) {Mfc_err ("Firmware is not present in The/lib/firmware directory nor compiled in kernel\n"); return-einval ;} Dev->fw_size = ALIGN (Fw_blob->size, Firmware_align), if (s5p_mfc_bitproc_buf) {Mfc_err ("attempting to allocate Firmware when it seems the it is already loaded\n "); Release_firmware (fw_blob); return-enomem;} S5p_mfc_bitproc_buf = Vb2_dma_contig_memops.alloc (Dev->alloc_ctx[mfc_bank1_alloc_ctx], dev->fw_size); if (IS_ ERR (S5p_mfc_bitproc_buf)) {s5p_mfc_bitproc_buf = Null;mfc_err ("Allocating bitprocessor buffer failed\n"); release_ Firmware (fw_blob); return-enomem;}
Just look at the key section and analyze the request_firmware (const struct firmware**) &fw_blob, "S5P-MFC.FW", Dev->v4l2_dev.dev); From the function name, it is not difficult to think of its function: loading firmware. In fact, the data in the firmware is moved to a member of the Fw_blob in the memory, how to move, look at the back analysis. Speaking of which, it is necessary to take a look at the definition of struct firmware.
struct Firmware {
size_t size;
Const U8*data;
struct page**pages;
};
It's time to talk about the firmware loading process, which allocates memory for the instantiated struct firmware structure duringrequest_firmware execution, and the function will be/sys/class/ Under firmware , create a new directory with the name of the device name, which contains 3 properties:
Loading : This property should be set to the user-space process that loads the firmware1. When loading is complete, it will be set to0. is set to-1, the firmware load is aborted.
data : A binary property used to receive firmware data. In the SettingsLoadingto be1after, The user-space process writes the firmware to this property.
Device : one link to/sys/devicesThe symbolic link under the related entry.
Once you have created Sysfs Entry Entry , The kernel will generate a hot plug event for the device and pass the include variable FIRMWARE environment variables to handle hot-swappable user-space programs. the FIRMWARE is set to The firmware file name provided to the Request_firmware.
The User space program locates the firmware file and copies it to the binary attribute provided by the kernel, and if the file cannot be located, the user space program sets the loading property to-1.
If the firmware request is not serviced within 10 seconds, the kernel discards and returns a failed state to the driver. The timeout period can be changed by the Sysfs property/sys/class/firmware/timeout property.
Having said so much, I actually fell a point. In fact, in the execution of Request_firmware, there is a process: to determine whether the firmware is compiled into the kernel, if the kernel is added to the process of compiling the firmware, the above process is a white tear---not used. Look at the following code:
Fw_priv =_request_firmware_prepare (firmware_p, name, device, True,false);
if (Is_err_or_null (FW_PRIV))
Returnptr_ret (FW_PRIV);
This is a small piece of code at the beginning of the Request_firmware function, _request_firmware_prepare function execution process, to determine if the firmware is compiled into the kernel, from the kernel global firmware address (pointer) to the destination address of the copy, that is, copied to The Structfirmware data member points to the memory (which eventually completes the loading of the firmware), and then _request_firmware_prepare returns a null pointer, which in turn request_ The firmware function also returns. This process code is implemented as follows:
static struct Firmware_priv *_request_firmware_prepare (const struct firmware **firmware_p, const char *name, struct Device *device, BOOL uevent, bool nowait) {struct firmware *firmware;struct firmware_priv *fw_priv;if (!firmware_p) return Err_ptr (-einval), *firmware_p = firmware = Kzalloc (sizeof (*firmware), Gfp_kernel), if (!firmware) {Dev_err (device, "%s: Kmalloc (struct firmware) failed\n ", __func__); return err_ptr (-ENOMEM);} if (Fw_get_builtin_firmware (firmware, name)) {dev_dbg (device, "firmware:using built-in firmware%s\n", name); return NULL;} ..... }
There's a bunch of stuff on the firmware loading process that's actually more than just MFC , almost all firmware loading is followed by the above procedure.
A little more practical stuff.
Where do we get the firmware?
1 , to find Samsung technical support.
2 , find third-party development board after sale.
3 , from the Internet Down .
The first two are nonsense, Samsung will not respond to our small users. Development Board after sale? They will only say: Look for yourself, CD-ROM it! It's on the CD, but what do I want to do with the high version?
It's not that hard, Google a little bit of the popular distribution Linux Kernel Branch, firmware is good for the full platform. We'll have it immediately.
Here is the firmware I got:
Samsung MFC firmware Download
The following files are included in the total:
* MFCV5 firmware (S5P-MFC.FW) * MFCV6 firmware, version 1 (S5P-MFC-V6.FW) * MFCV6 firmware, version 2 (S5P-MFC-V6-V2.FW) * MFCV7 firmware (S5P-MFC-V7.FW) * MFCV8 firmware (S5P-MFC-V8.FW)
In my kernel package, I use S5P-MFC.FW, which is MFCv5.
In addition, we found some information about the relationship between the MFC firmware version and the processor:
S5p-mfc-v7.fw:used in Exynos 5420
S5p-mfc-v8.fw:used in Exynos 5800
The content of this article is so much, the next article would like to be able to connect to the article, analysis Live555 server process. Live555 with a short time, text code out, the total sense of quality is not. Sometime it.