玩客云Amlogic S805 适配Win10 arm32记录 – 11

11.

在进行驱动编写之前,我们还有一件不痛不痒的的库需要实现,他就是RealTimeClockLib,缩写RTC,虽然说作用不是很大,但却是UEFI中一个重要的部分,RealTimeClockLib主要负责当前日期时间的获取和设置,由于玩客云没有内置时钟芯片,所以一断电,时间就废了,所以我们当前写的RealTimeClockLib其实没有多大用,是个软件实现的软时钟,或者可以说是一个假的库,主要是为了实现一个欺上瞒下的功能,保证上层在调用这个库时不会造成空指针,跑飞或者返回异常的情况就成功了,我们大概看下这个库的框架,主要有以下几个函数

/**
  Returns the current time and date information, and the time-keeping capabilities
  of the virtual RTC.

  For simplicity, this LibGetTime does not report Years/Months, instead it will
  only report current Day, Hours, Minutes and Seconds starting from the beginning
  of CPU up-time. Otherwise, a more complex logic will be required to account
  for leap years and days/month differences.

  @param  Time                  A pointer to storage to receive a snapshot of
                                the current time.
  @param  Capabilities          An optional pointer to a buffer to receive the
                                real time clock device's capabilities.

  @retval EFI_SUCCESS           The operation completed successfully.
  @retval EFI_INVALID_PARAMETER Time is NULL.
  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.

**/
EFI_STATUS
EFIAPI
LibGetTime (
  OUT EFI_TIME *Time,
  OUT EFI_TIME_CAPABILITIES *Capabilities
  );

/**
  Sets the current local time and date information.

  @param  Time                  A pointer to the current time.

  @retval EFI_UNSUPPORTED      This operation is not supported.

**/
EFI_STATUS
EFIAPI
LibSetTime (
  IN EFI_TIME *Time
  );

/**
  Returns the current wakeup alarm clock setting.

  @param  Enabled               Indicates if the alarm is currently enabled or
                                disabled.
  @param  Pending               Indicates if the alarm signal is pending and
                                requires acknowledgement.
  @param  Time                  The current alarm setting.

  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.

**/
EFI_STATUS
EFIAPI
LibGetWakeupTime (
  OUT BOOLEAN *Enabled,
  OUT BOOLEAN *Pending,
  OUT EFI_TIME *Time
  );

/**
  Sets the system wakeup alarm clock time.

  @param  Enabled               Enable or disable the wakeup alarm.
  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.

  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.

**/
EFI_STATUS
EFIAPI
LibSetWakeupTime (
  IN BOOLEAN Enabled,
  OUT EFI_TIME *Time
  );

/**
  This is the declaration of an EFI image entry point. This can be the entry point
  to an application written to this specification, an EFI boot service driver,
  or an EFI runtime driver.

  @param  ImageHandle           Handle that identifies the loaded image.
  @param  SystemTable           System Table for this image.

  @retval EFI_SUCCESS           The operation completed successfully.

**/
EFI_STATUS
EFIAPI
LibRtcInitialize (
  IN EFI_HANDLE ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  );

/**
  Fixup internal data so that EFI can be call in virtual mode.
  Call the passed in Child Notify event and convert any pointers in
  lib to virtual mode.

  @param[in]    Event   The Event that is being processed
  @param[in]    Context Event Context
**/
VOID
EFIAPI
LibRtcVirtualNotifyEvent (
  IN EFI_EVENT Event,
  IN VOID *Context
  );

这里我们主要需要实现一个LibGetTime和LibSetTime即可,具体实现方法可以参考U-boot中的写法,路径为drivers/rtc/aml_rtc.c

其实说白了主要就是两个函数,设置时间和读取时间,其他的函数例如唤醒,我们现在并不需要,直接返回不支持即可。剩下的就是将设置时间和读取时间转换成读写寄存器即可,详细实现可以参考: https://github.com/pig-world/OneCloudPkg/blob/main/Library/RealTimeClockLib/RealTimeClockLib.c

2021/12/04更新一点点内容:

最近有人问到我相关问题,在这里稍微补充两点吧。

关于HDMI,之前我一直以为显示部分的驱动很难做,但事实上并不是这样,这块芯片已经内置了HDMI控制器,只需要对HDMI参数进行一些配置(写寄存器),再往指定地址0x7900000(显存)写数据即可实现显示了,并不需要我们去考虑如何去发送数据,时序之类的问题,换句话说,一块芯片在出厂的时候,就已经确定了它所能支持的图像控制器类型(HDMI,MIPI,LVDS,RGB,SPI,eDP),也就是只支持对应协议的屏幕,这些在数据手册中都有说明。在我之前的想法中,屏幕是通过GPIO口去驱动,需要自己去写传输信号的控制代码,属于单片机的思维。目前的SOC芯片在硬件层面已经帮你做完这些事情了,这并不是说通过GPIO去驱动屏幕不可行,最主要的原因是GPIO目前的速度还达不到显示高清图像的需求,驱动一个128×64这种的屏幕还是绰绰有余的,如果你想适配目前手边的屏幕,但是经过查询发现目前的SOC不支持当前的屏幕控制器类型,那就得通过转接板来实现了。

关于USB部分,S805采用了DesignWare的USB通用方案,可以参考dwc_otg的实现(可参考树莓派,瑞芯微的代码实现),并且市面上很大SOC都是使用的他们的方案,有详细的datasheet,照着资料操作即可,目前没有太多时间详细描述实现方法,但总体来说有资料,照葫芦画瓢并不是很难,最怕的是没有任何资料,或者资料有残缺,S805这块SOC的datasheet只有100多页,按常理推断至少应该有几百上千页才对,换种思路想一想,即使给出了完整的datasheet,想完美驱动也谈何容易呢?官方的开发者尚且还需要找厂家要技术售后支持,个人的力量实在是太渺小了。

主要参考:

  1. Linux下dwc_otg驱动的实现文档DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Main Page (cam.ac.uk)
  2. 完整的寄存器说明(主要参考第19节),特别注意一下Host Initialization和Host Initialization部分即可。

2020/01/01 项目已开源到Github:

有兴趣的小伙伴可以点击 https://github.com/pig-world/OneCloudPkg 进行查看,上述内容是之前写的草稿,也一并发出来了,目前基本的UEFI功能已经实现,但是由于时间问题,后续的文章还没来得及写出来,并且考虑到目前的关注UEFI的人数实在太少,再看看S805的性能实在太拉跨,继续折腾意义并不是很大,因此本系列的文章无限期推迟更新。

新的一年,我会将精力放在其他更多有意思的项目上,感谢大家的支持。

《玩客云Amlogic S805 适配Win10 arm32记录 – 11》有3条留言

留下评论