Files
luban-lite-t3e-pro/doc/topics/sdk/dvp/dvp_design.html
2025-01-23 16:37:00 +08:00

246 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-cn" lang="zh-cn" data-whc_version="26.0">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="description" content="本模块源代码在内核目录 linux-5.4/drivers/media/platform/artinchip 下,目录结构如下: drivers/media/platform/artinchip/ ├── aic_buf.c // 和 buf 管理相关的处理代码 ├── aic_dvp.c // DVP 驱动的初始化入口,主要实现了 probe、Notifier 接口 ├── aic_dvp.h ..."/><meta name="DC.rights.owner" content="(C) 版权 2025"/><meta name="copyright" content="(C) 版权 2025"/><meta name="generator" content="DITA-OT"/><meta name="DC.type" content="concept"/><meta name="DC.contributor" content="yan.wang"/><meta name="DC.date.modified" content="2024-12-02"/><meta name="DC.format" content="HTML5"/><meta name="DC.identifier" content="dvp_design_intro"/><meta name="DC.language" content="zh-CN"/><title>设计说明</title><!-- Build number 2023110923. --><meta name="wh-path2root" content="../../../"/><meta name="wh-toc-id" content=""/><meta name="wh-source-relpath" content="topics/sdk/dvp/dvp_design.dita"/><meta name="wh-out-relpath" content="topics/sdk/dvp/dvp_design.html"/>
<link rel="stylesheet" type="text/css" href="../../../webhelp/app/commons.css?buildId=2023110923"/>
<link rel="stylesheet" type="text/css" href="../../../webhelp/app/topic.css?buildId=2023110923"/>
<script src="../../../webhelp/app/options/properties.js?buildId=20250121171154"></script>
<script src="../../../webhelp/app/localization/strings.js?buildId=2023110923"></script>
<script src="../../../webhelp/app/search/index/keywords.js?buildId=20250121171154"></script>
<script defer="defer" src="../../../webhelp/app/commons.js?buildId=2023110923"></script>
<script defer="defer" src="../../../webhelp/app/topic.js?buildId=2023110923"></script>
<link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-styles-web.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/notes.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-common.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-images.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/footnote.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/aic-web-watermark.css?buildId=2023110923"/><link rel="stylesheet" type="text/css" href="../../../webhelp/template/topic-body-list.css?buildId=2023110923"/></head>
<body id="dvp_design_intro" class="wh_topic_page frmBody">
<a href="#wh_topic_body" class="sr-only sr-only-focusable">
跳转到主要内容
</a>
<header class="navbar navbar-default wh_header">
<div class="container-fluid">
<div class="wh_header_flex_container navbar-nav navbar-expand-md navbar-dark">
<div class="wh_logo_and_publication_title_container">
<div class="wh_logo_and_publication_title">
<a href="http://www.artinchip.com" class=" wh_logo d-none d-sm-block "><img src="../../../company-logo-white.png" alt="RTOS SDK 使用指南SDK 指南文件"/></a>
<div class=" wh_publication_title "><a href="../../../index.html"><span class="booktitle"><span class="ph mainbooktitle">RTOS SDK 使用指南</span><span class="ph booktitlealt">SDK 指南文件</span></span></a></div>
</div>
</div>
<div class="wh_top_menu_and_indexterms_link collapse navbar-collapse" id="wh_top_menu_and_indexterms_link">
</div>
</div>
</div>
</header>
<div class=" wh_search_input navbar-form wh_topic_page_search search " role="form">
<form id="searchForm" method="get" role="search" action="../../../search.html"><div><input type="search" placeholder="搜索 " class="wh_search_textfield" id="textToSearch" name="searchQuery" aria-label="搜索查询" required="required"/><button type="submit" class="wh_search_button" aria-label="搜索"><span class="search_input_text">搜索</span></button></div></form>
</div>
<div class="container-fluid" id="wh_topic_container">
<div class="row">
<nav class="wh_tools d-print-none navbar-expand-md" aria-label="Tools">
<div data-tooltip-position="bottom" class=" wh_breadcrumb "></div>
<div class="wh_right_tools">
<button class="wh_hide_highlight" aria-label="切换搜索突出显示" title="切换搜索突出显示"></button>
<button class="webhelp_expand_collapse_sections" data-next-state="collapsed" aria-label="折叠截面" title="折叠截面"></button>
<div class=" wh_print_link print d-none d-md-inline-block "><button onClick="window.print()" title="打印此页" aria-label="打印此页"></button></div>
</div>
</nav>
</div>
<div class="wh_content_area">
<div class="row">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12" id="wh_topic_body">
<button id="wh_close_topic_toc_button" class="close-toc-button d-none" aria-label="Toggle topic table of content" aria-controls="wh_topic_toc" aria-expanded="true">
<span class="close-toc-icon-container">
<span class="close-toc-icon"></span>
</span>
</button>
<div class=" wh_topic_content body "><main role="main"><article class="- topic/topic concept/concept topic concept" role="article" aria-labelledby="ariaid-title1"><span class="edit-link" style="font-size:12px; opacity:0.6; text-align:right; vertical-align:middle"><a target="_blank" href="http://172.16.35.88/tasks/jdssno1uvvbf2mltu9kb9v3if05d5gopuakboe8hlud18rma/edit/F:/aicdita/aicdita-cn/topics/sdk/dvp/dvp_design.dita">Edit online</a></span><h1 class="- topic/title title topictitle1" id="ariaid-title1">设计说明</h1><div class="date inPage">2 Dec 2024</div><div style="color: gray;">
Read time: 3 minute(s)
</div><div class="- topic/body concept/conbody body conbody"><div class="- topic/p p" data-ofbid="d300194e22__20250121171805">本模块源代码在内核目录
<span class="+ topic/ph sw-d/filepath ph filepath">linux-5.4/drivers/media/platform/artinchip</span>下,目录结构如下:<pre class="+ topic/pre pr-d/codeblock pre codeblock language-c" id="dvp_design_intro__pre_lg2_vzg_d1c" data-ofbid="dvp_design_intro__pre_lg2_vzg_d1c">drivers/media/platform/artinchip/
├── aic_buf.c <em class="hl-comment">// 和 buf 管理相关的处理代码</em>
├── aic_dvp.c <em class="hl-comment">// DVP 驱动的初始化入口,主要实现了 probe、Notifier 接口</em>
├── aic_dvp.h <em class="hl-comment">// DVP 驱动共用的头文件,其中定义了寄存器、共用数据结构、全局函数等</em>
├── aic_dvp_hw.c <em class="hl-comment">// 对寄存器的访问封装</em>
├── aic_video.c <em class="hl-comment">// 和 L2 框架强相关的一些接口定义,如 ops、ioctl_ops 的接口实现等</em>
├── Kconfig
└── Makefile</pre></div><section class="- topic/section section" id="dvp_design_intro__section_wwl_b1h_d1c" data-ofbid="dvp_design_intro__section_wwl_b1h_d1c"><h2 class="- topic/title title sectiontitle">V4L2 软件框架</h2>
<p class="- topic/p p" data-ofbid="d300194e34__20250121171805">Linux 中的 V4L2 框架是一个专门为视频输入输出设备而设计的成熟方案DVP 驱动需要基于 V4L2。</p>
<div class="- topic/p p" data-ofbid="d300194e37__20250121171805">
<figure class="- topic/fig fig fignone" id="dvp_design_intro__fig_rkz_41h_d1c" data-ofbid="dvp_design_intro__fig_rkz_41h_d1c"><br/><div class="imagecenter"><img class="- topic/image image imagecenter" id="dvp_design_intro__image_xwl_b1h_d1c" src="../../../images/dvp/v4l2_system.jpg" alt="v4l2_system"/></div><br/><figcaption data-caption-side="bottom" class="- topic/title title figcapcenter"><span class="figtitleprefix fig--title-label"><span class="fig--title-label-number"> 1</span><span class="fig--title-label-punctuation">. </span></span><span class="fig--title">Linux V4L2 子系统架构图</span></figcaption></figure>
</div>
<ol class="- topic/ol ol" id="dvp_design_intro__ol_ywl_b1h_d1c" data-ofbid="dvp_design_intro__ol_ywl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e48__20250121171805">
<div class="- topic/p p" data-ofbid="d300194e50__20250121171805">V4L2Video For Linux 第 2 版,最早出现在 1998 年,一个针对无线广播(收音机)、视频捕获、视频输出设备的通用框架,源码目录
<span class="+ topic/ph sw-d/filepath ph filepath">drivers/media/v4l2-core</span>。V4L2 中支持的 5 大类接口设备:<ul class="- topic/ul ul" id="dvp_design_intro__ul_axl_b1h_d1c" data-ofbid="dvp_design_intro__ul_axl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e56__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e58__20250121171805">Video capture interface影像捕获接口。</p>
</li><li class="- topic/li li" data-ofbid="d300194e61__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e63__20250121171805">Video output interface视频输出接口主要用于电视信号类。</p>
</li><li class="- topic/li li" data-ofbid="d300194e66__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e68__20250121171805">Video overlay interface视频覆盖接口方便视频显示设备直接从捕获设备上获取数据。</p>
</li><li class="- topic/li li" data-ofbid="d300194e71__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e73__20250121171805">VBI interface垂直消隐接口可提供垂直消隐区的数据接入包括 raw 和 sliced 两种。</p>
</li><li class="- topic/li li" data-ofbid="d300194e76__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e78__20250121171805">Radio interface广播接口主要是从 AM 或 FM 调谐器中获取音频数据。</p>
</li></ul></div>
</li><li class="- topic/li li" data-ofbid="d300194e82__20250121171805">
<p class="- topic/p p" data-ofbid="d300194e84__20250121171805">V4L2 为用户空间提供了字符设备的通用接口,设备节点 /dev/videoX主设备号 81次设备号的分配跟设备类型有关规则定义如下</p>
<div class="table-container"><table class="- topic/table table frame-all" id="dvp_design_intro__table_dxl_b1h_d1c" data-ofbid="dvp_design_intro__table_dxl_b1h_d1c" data-cols="2"><caption></caption><colgroup><col style="width:50%"/><col style="width:50%"/></colgroup><thead class="- topic/thead thead"><tr class="- topic/row"><th class="- topic/entry entry colsep-1 rowsep-1" id="dvp_design_intro__table_dxl_b1h_d1c__entry__1">设备类型</th><th class="- topic/entry entry colsep-0 rowsep-1" id="dvp_design_intro__table_dxl_b1h_d1c__entry__2">次设备号</th></tr></thead><tbody class="- topic/tbody tbody"><tr class="- topic/row"><td class="- topic/entry entry colsep-1 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__1">视频设备</td><td class="- topic/entry entry colsep-0 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__2">0~63</td></tr><tr class="- topic/row"><td class="- topic/entry entry colsep-1 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__1">Radio 设备</td><td class="- topic/entry entry colsep-0 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__2">64~127</td></tr><tr class="- topic/row"><td class="- topic/entry entry colsep-1 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__1">Teletext 设备</td><td class="- topic/entry entry colsep-0 rowsep-1" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__2">192~233</td></tr><tr class="- topic/row"><td class="- topic/entry entry colsep-1 rowsep-0" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__1">VBI 设备</td><td class="- topic/entry entry colsep-0 rowsep-0" headers="dvp_design_intro__table_dxl_b1h_d1c__entry__2">224~255</td></tr></tbody></table></div>
<p class="- topic/p p" data-ofbid="d300194e119__20250121171805">用户态 APP 通过 ioctl 控制 video 设备,通过 mmap 进行内存映射。在/dev 目录中会产生 videoX、radioX 和 vbiX
设备节点。</p>
</li><li class="- topic/li li" data-ofbid="d300194e122__20250121171805">在 V4L2 框架中,将每一个 Sensor、DVP 硬件设备都看作一个 subdev相应的有一个字符设备节点
/dev/v4l-subdevX用户态通过这些节点的 ioctl 接口可以完成 subdev 的格式协商、时序配置等功能。</li><li class="- topic/li li" data-ofbid="d300194e124__20250121171805">Notifier 子模块是为了解决多个设备之间的初始化顺序、以及媒体流对接的匹配检查,如 DVP 需要等 Sensor 初始化完成后,才能去真正完成 video
device 的注册。可见DVP 和 Sensor 要有一个绑定的关系,这个关系是由 DTS 中的 remote-endpoint 来指定的。Notifier
会调用 Fwnode 系列接口来解析和获取 remote-endpoint 的属性字段。</li><li class="- topic/li li" data-ofbid="d300194e126__20250121171805">为了进行数据流的管理V4L2 维护了一个 device 链表,每一个 video device、V4L2 device、V4L2-subdev 都是一个
Media device 实例,这些 Media device 在数据结构的设计上第一个成员变量都是一个 struct media_entity其中有
list_head 成员,借此互相链接起来。见下一节详述。</li></ol>
</section><section class="- topic/section section" id="dvp_design_intro__section_cyl_b1h_d1c" data-ofbid="dvp_design_intro__section_cyl_b1h_d1c"><h2 class="- topic/title title sectiontitle">V4L2 的 Buf 队列管理</h2>
<p class="- topic/p p" data-ofbid="d300194e134__20250121171805">V4L2 的 Buffer 管理由 videobuf 子模块实现,从源头看分为两种方式的 Buffer</p>
<ol class="- topic/ol ol" id="dvp_design_intro__ol_dyl_b1h_d1c" data-ofbid="dvp_design_intro__ol_dyl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e138__20250121171805">驱动申请 Buffer<p class="- topic/p p" data-ofbid="d300194e140__20250121171805">用户态通过 VIDIOC_REQBUFS ioctl 命令触发 Buffer 申请,然后使用 mmap 接口来获取用户态的
Buffer 地址。这种方式Buffer 个数一般有个最大值 32 VIDEO_MAX_FRAME。</p></li><li class="- topic/li li" data-ofbid="d300194e142__20250121171805">用户态申请 Buffer<p class="- topic/p p" data-ofbid="d300194e144__20250121171805">用户态根据实际需要知道要申请多少 Buffer然后借助其他机制可以是 dma-buf在用户态完成
Buffer当然必须是物理连续的申请并将物理地址告诉 Video 驱动。</p></li></ol>
<p class="- topic/p p" data-ofbid="d300194e147__20250121171805">按照 Buffer 的物理连续,又可以分为三种情况:(详见
<span class="+ topic/ph sw-d/filepath ph filepath">Documentationmediakapiv4l2-videobuf.rst</span></p>
<ol class="- topic/ol ol" id="dvp_design_intro__ol_gyl_b1h_d1c" data-ofbid="dvp_design_intro__ol_gyl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e154__20250121171805">物理连续、不连续的 Buffer 混用<p class="- topic/p p" data-ofbid="d300194e156__20250121171805">几乎所有用户空间的 Buffer 都属于这种情况,这样最大可能的发挥虚拟内存管理的灵活性。缺点也很明显,这些
Buffer 给硬件的话需要有支持 scatter 的 DMA。</p></li><li class="- topic/li li" data-ofbid="d300194e158__20250121171805">物理不连续、虚拟地址连续的 Buffer<p class="- topic/p p" data-ofbid="d300194e160__20250121171805">它们由 vmalloc()分配,也用于支持 scatter 接口的 DMA 硬件。</p></li><li class="- topic/li li" data-ofbid="d300194e162__20250121171805">物理连续的 Buffer<p class="- topic/p p" data-ofbid="d300194e164__20250121171805">非常适合 DMA 类硬件的访问。</p></li></ol>
<div class="- topic/note note note note_note" id="dvp_design_intro__note_y3h_gch_d1c" data-ofbid="dvp_design_intro__note_y3h_gch_d1c"><span class="note__title">注:</span>
<p class="- topic/p p" data-ofbid="d300194e170__20250121171805">驱动开发者必须三选一,对于我们的 DVP 模块来说,要选择 3。并且底层用到 dma-buf。</p>
</div>
<p class="- topic/p p" data-ofbid="d300194e174__20250121171805">V4L 第二版不再支持 Overlay 类型,而 V4L 第一版不支持 DMABUF 类型。</p>
<p class="- topic/p p" data-ofbid="d300194e177__20250121171805">V4L2 在数据流传输的时候需要多个 Buf 切换,通过 struct vb2_queue 结构中的 Qbuf 两个 Buf 队列来管理DVP 驱动中还需要维护一个
buf_list 来配合 DVP 控制器的地址更新。整个 Buf 流转的过程如下图:</p>
<div class="- topic/p p" data-ofbid="d300194e180__20250121171805">
<figure class="- topic/fig fig fignone" id="dvp_design_intro__fig_npb_d1h_d1c" data-ofbid="dvp_design_intro__fig_npb_d1h_d1c"><br/><div class="imagecenter"><img class="- topic/image image imagecenter" id="dvp_design_intro__image_kyl_b1h_d1c" src="../../../images/dvp/dvp_buf_list.jpg" alt="dvp_buf_list"/></div><br/><figcaption data-caption-side="bottom" class="- topic/title title figcapcenter"><span class="figtitleprefix fig--title-label"><span class="fig--title-label-number"> 2</span><span class="fig--title-label-punctuation">. </span></span><span class="fig--title">DVP 驱动中的 Buf 队列管理</span></figcaption></figure>
</div>
<ul class="- topic/ul ul" id="dvp_design_intro__ul_lyl_b1h_d1c" data-ofbid="dvp_design_intro__ul_lyl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e191__20250121171805">Qbuf 队列(在代码中见 struct vb2_queue-&gt;queued_list是一些空闲 Buf等待 Sensor 的数据到来后DVP
驱动会从这个队列中找可用 Buf 来保存下一帧数据。</li><li class="- topic/li li" data-ofbid="d300194e193__20250121171805">DQbuf 队列(在代码中见 struct vb2_queue-&gt;done_list是一些填了视频数据的
Buf等待用户来处理这些数据一般用户处理完后需要将 Buf 还给驱动,也就是还给 Qbuf。</li><li class="- topic/li li" data-ofbid="d300194e195__20250121171805">从 Qbuf 和 DQbuf 来的 buf 格式是 buffer其中没有字段可以保存物理地址DVP 控制器需要),同时还需要为每个 buf
记录一个是否正在被 DVP 使用的状态,所以 DVP 驱动中定义了基于 vb2_buffer 结构的封装 buffer并且维护一个和 Qbuf
几乎同步的队列。</li><li class="- topic/li li" data-ofbid="d300194e197__20250121171805">从图中的流转过程看运行期间在某一时刻DVP 需要使用一个 BufAPP 需要使用一个 BufQBuf 需要有一个 Buf 在等待(否则 DVP 的
done 中断来了后发现没有等待的 Qbuf 会发生丢帧),一共至少要有 3 个 Buf。</li><li class="- topic/li li" data-ofbid="d300194e199__20250121171805">以 YUV422 格式计算,有两个 plane在 L2 框架中这一组 plane 算一个 Buf3 个 Buf 就需要申请 6 个
plane<code class="+ topic/ph pr-d/codeph ph codeph">总大小 = 长 * 宽 * 2 * 3</code></li><li class="- topic/li li" data-ofbid="d300194e204__20250121171805">DVP 驱动中需要定义一个 queue 实例Video device 中会有一个指针*queue 指向该实例。</li></ul>
</section><section class="- topic/section section" id="dvp_design_intro__section_myl_b1h_d1c" data-ofbid="dvp_design_intro__section_myl_b1h_d1c"><h2 class="- topic/title title sectiontitle">DVP 驱动的子模块结构</h2>
<p class="- topic/p p" data-ofbid="d300194e212__20250121171805">基于以上对 V4L2 框架的分析DVP 驱动内部可以分为以下 5 个子模块:</p>
<div class="- topic/p p" data-ofbid="d300194e215__20250121171805">
<figure class="- topic/fig fig fignone" id="dvp_design_intro__fig_bzw_b1h_d1c" data-ofbid="dvp_design_intro__fig_bzw_b1h_d1c"><br/><div class="imagecenter"><img class="- topic/image image imagecenter" id="dvp_design_intro__image_nyl_b1h_d1c" src="../../../images/dvp/dvp_drv_structure.jpg" alt="dvp_drv_structure"/></div><br/><figcaption data-caption-side="bottom" class="- topic/title title figcapcenter"><span class="figtitleprefix fig--title-label"><span class="fig--title-label-number"> 3</span><span class="fig--title-label-punctuation">. </span></span><span class="fig--title">DVP 驱动的子模块结构</span></figcaption></figure>
</div>
<ul class="- topic/ul ul" id="dvp_design_intro__ul_oyl_b1h_d1c" data-ofbid="dvp_design_intro__ul_oyl_b1h_d1c"><li class="- topic/li li" data-ofbid="d300194e226__20250121171805">Video Dvice 管理,主要实现和 device 相关的注册、ioctl 处理。</li><li class="- topic/li li" data-ofbid="d300194e228__20250121171805">Notifier 管理,主要处理和 Sensor 设备的初始化次序的依赖关系。</li><li class="- topic/li li" data-ofbid="d300194e230__20250121171805">Buf 管理,主要实现 Buf 的入队、出队,以及在中断响应时切换 DVP 控制器的输出地址等。</li><li class="- topic/li li" data-ofbid="d300194e232__20250121171805">Subdev 管理,主要实现输入格式相关的接口。</li><li class="- topic/li li" data-ofbid="d300194e234__20250121171805">寄存器访问,封装了对 DVP 控制器寄存器的读写访问。</li></ul>
</section></div></article></main></div>
</div>
<nav role="navigation" id="wh_topic_toc" aria-label="On this page" class="col-lg-2 d-none d-lg-block navbar d-print-none">
<div id="wh_topic_toc_content">
<div class=" wh_topic_toc "><div class="wh_topic_label">在本页上</div><ul><li class="section-item"><div class="section-title"><a href="#dvp_design_intro__section_wwl_b1h_d1c" data-tocid="dvp_design_intro__section_wwl_b1h_d1c">V4L2 软件框架</a></div></li><li class="section-item"><div class="section-title"><a href="#dvp_design_intro__section_cyl_b1h_d1c" data-tocid="dvp_design_intro__section_cyl_b1h_d1c">V4L2 的 Buf 队列管理</a></div></li><li class="section-item"><div class="section-title"><a href="#dvp_design_intro__section_myl_b1h_d1c" data-tocid="dvp_design_intro__section_myl_b1h_d1c">DVP 驱动的子模块结构</a></div></li></ul></div>
</div>
</nav>
</div>
</div>
</div>
<footer class="navbar navbar-default wh_footer">
<div class=" footer-container mx-auto ">
<title>footer def</title>
<style><!--
.p1 {
font-family: FangZhengShuSong, Times, serif;
}
.p2 {
font-family: Arial, Helvetica, sans-serif;
}
.p3 {
font-family: "Lucida Console", "Courier New", monospace;
}
--></style>
<div class="webhelp.fragment.footer">
<p class="p1">Copyright © 2019-2024 广东匠芯创科技有限公司. All rights reserved.</p>
</div><div>
<div class="generation_time">
Update Time: 2025-01-21
</div>
</div>
</div>
</footer>
<div id="go2top" class="d-print-none">
<span class="oxy-icon oxy-icon-up"></span>
</div>
<div id="modal_img_large" class="modal">
<span class="close oxy-icon oxy-icon-remove"></span>
<div id="modal_img_container"></div>
<div id="caption"></div>
</div>
<script src="${pd}/publishing/publishing-styles-AIC-template/js/custom.js" defer="defer"></script>
</body>
</html>