基於MK802 MiniPC的擴展開發應用-軟/硬件修改和擴展


這是一個文章系列的一部分,介紹基於MK802這類MiniPC的擴展開發,並展現他在計算機視覺、機器人控制方面的潛能php

歡迎轉載,但請保留原始做者信息(Shikai Chen, http://www.csksoft.net),以及指向本文原始出處的連接!html

訪問目錄:基於MK802 MiniPC的擴展開發應用-簡介篇(http://www.csksoft.net/blog/post/mk802_dev_intro.html)linux

 

revision: 1android

這部分將介紹各類針對MK802硬件以及軟件的修改技巧,相對來講,這部分介紹的都屬於各類雜碎的小技巧,文章構成上比較零碎,而且相對於整個系列文章其餘部分獨立。
雖然這些都是各類小技巧,有些甚至屬於雕蟲小技,不過在必要的地方我也會經過問題自己作一些對linux kernel的進一步介紹。
git

在本文中將介紹的例子有:

  1. 引出MK802的內部調試串口信號,用於kernel的調試和開發github

  2. 經過fex腳本配置hdmi的輸出分辨率至1080p和其餘尺寸以及色彩深度shell

  3. 在自制系統內利用MK802的內置Flash存儲文件編程

  4. 將CPU主頻超頻至1.1G,以及實現動態頻率調節下降功耗
    bash

 

1. MK802硬件系統介紹

這麼短的文章不期望能把整個硬件構架狀況交代清楚,這裏僅給出對本文後續Hack所須要的背景信息。網絡

徹底瞭解MK802的硬件構成,須要擁有廠家的相關文檔,而這些文檔每每是須要簽署NDA協議後提供的,並不能公開獲取,因此這裏的介紹只是透過個人拆解分析,以及基於網上相關資料(見參考文獻)彙總得出的。他們可能與真實狀況存在誤差。

 

1.1. CPU和SOC資源


這裏介紹CPU和相關SOC的目的是爲了讓你們瞭解MK802的性能狀況。就目前廠家提供的固件以及咱們自制的固件而言,大部分的SOC資源都沒有獲得有效的利用。就像在前一篇文章中我也提到,目前在傳統Linux發行版上還大部分沒有上述SOC的驅動,就好比Mali 400 GPU和G2D 2D圖形加速的支持,以及視頻編解碼的驅動支持。不過目前社區也有人在嘗試着經過逆向工程的手段,實如今傳統linux發行版上使用這類SOC。

透過廠家以及以前文章的介紹,MK802是採用Allwinner A10 CPU芯片的系統方案,該芯片基於ARM Cortex A8構架,工做在1Ghz左右的頻率,GPU SOC採用了ARM Mali-400 MP[2]。
其餘的片上資源包括[1]:
 支持2160p(支持3D視頻格式輸出)的HD視頻decoder,包含對H.264,MPEG-1/2/4的格式的硬件解碼支持,以及對應的硬件編碼器
 硬件2D圖像加速(G2D)
 USB2.0高速的HOST接口
 USB2.0高速的OTG接口
 SDIO總線x4
 CSI總線
 100Mbps以太網控制器
 SATA2.0接口 (3Gbps)
 IDE(PATA)接口
 Can總線
 I2S、SPDIF、AC97音頻接口
 PS二、SPI、TWI(I2C)、UART(串口)接口
 LVDS、VGA、HDMI視頻輸出接口
 電阻觸摸屏控制器
這塊芯片的SOC資源仍是比較不錯的,連SATA2.0也有,不過咱們的MK802並無把這些資源的信號都提供出來。因此像SATA口咱們是沒法再MK802上使用到了。不過市面上也有其餘很多基於Allwinner A10的機器,其中不乏這些資源均可用的機型[3]。本系列文章的內容一樣對他們有效。

1.2. MK802的硬件構成


MK802的硬件組成以下圖所示,諸如HDMI這類你們都已經清楚地接口,這裏就不標出了。

圖:MK802硬件設備

資源/設備/接口

圖中標號

描述

Nand Flash

1

4Gb

Allwinner A10 CPU

2

見上文

DDR3 RAM

3

按配置有1G/512M

DCDC供電

4

簡單的DCDC模塊,非PMIC

USB WIFI模組

5

採用rtl8192芯片的USB WIFI模塊

USB 2.0 OTG

6

能夠用做USB host鏈接外設

調試串口觸點

7

後文將介紹將其信號引出用於調試

能夠看出MK802的PCB佈局比較緊湊,可以作信號擴展的機會很少,能夠進行的有:
 將內部的調試串口信號引出
 利用USB WIFI模組額外的一條USB總線,外接更多的設備
 替換DCDC模組,或者將其輸出引出

本文接下來將介紹這裏列舉的第一條,其餘若是你們有興趣能夠本身嘗試。

1.3. 功耗狀況:


參考文獻[1]給出了一樣採用Allwinner A10芯片的另外一臺機器Mele A1000的功耗狀況,因爲它與MK802的硬件類似度極高,所以能夠基本認爲與MK802一致。這裏我就直接引用[1]的數據:

使用場景

功耗狀況

u-boot idle (uboot自動啓動被打斷)

1.15W (0.23A, 5V)

Android系統空閒狀態

1.7W (0.34A, 5V)

Android頻繁瀏覽網頁時

2.75W (0.55A, 5V)

Androidyoutube播放720p視頻

4.6W

Ubuntu 12.04 + SATA HDD 下載bt,不接顯示器輸出

5.0 – 6.5W

這個功耗水平仍是很使人滿意的,須要注意上表的數據是基於Mele A1000採集獲得的,因爲MK802具備更少的硬件外設,所以功耗水平應該更低。另外上表的最後一項還包含SATA硬盤,所以5W的功耗中應該也包含了硬盤消耗。

若是但願下降MK802的功耗,除了在運行期間禁用相關的硬件功能(好比關閉hdmi圖形輸出),還有一個有效措施是按照需求下降CPU主頻,這部分將在後文介紹。

2. MK802的設備配置(fex文件)和工做機制

在前一篇文章[4]的uboot/linux kernel編譯環節,我提到了Allwinner A10 CPU的kernel使用了一個fex腳本的配置文件,用於對於系統各類參數的配置。這裏將專門介紹一下這個文件。


圖:在自制系統過程當中須要編譯的配置腳本


該文件的原始形式是如上圖所示的文本格式的配置文件,在前文[4]中提到了在實際系統製做中,該文本格式的文件將使用fex2bin的程序,將他轉化成二進制的格式,並最終以文件名script.bin同linux kernel鏡像(uImage)一塊兒發佈在SD卡的FAT分區當中。

在MK802啓動階段,該fex腳本的二進制形式首先會經過uboot腳本boot.scr加載到一個固定的內存地址。隨後在Linux kernel啓動的不一樣時期,各類相關的驅動程序在初始化階段將讀取該配置腳本,完成對設備的初始化。具體過程將在下文的fex script深刻討論部分介紹。這裏須要瞭解的是咱們能夠經過對該文件進行修改達到對某些設備的配置。

若是感興趣,你們能夠先下載該文件觀察一下:

https://github.com/cnxsoft/a10-config/blob/master/script.fex/mk802.fex

能夠觀察到其中有諸如對於TWI(I2C)、DDR RAM、串口、SPI、HDMI各種設備的參數配置。以及還有一些MK802上並不存在的設備的配置,好比LCD、加速度傳感器等。
這多是因爲該配置文件是社區基於其餘的Allwinner A10方案的設備修改而來的,另外經過分析MK802的linux kernel能夠知道,其中包含了不少應該是來自Allwinner A10 的參考開發系統的代碼,其中諸如加速度傳感器、LCD等的驅動程序仍舊包含在如今的代碼中。這些代碼雖然不會起到實際做用,但在加載的過程當中仍舊可能會從fex腳本中讀取對應的配置信息。所以並非其中全部的配置項目都是會起做用的。

那麼如何進行配置呢?該配置文件的具體介紹網上並無公開的文檔進行解釋(在文獻[1]同提到有泄露的廠家文檔,能夠自行驗證),所以主要經過以下2個途徑:
1. 猜想
2. 查看Linux kernel代碼

對於一些顯而易見的配置項目,好比這條:

[target]
boot_clock = 1008
dcdc2_vol = 1400
dcdc3_vol = 1250
ldo2_vol = 3000
ldo3_vol = 2800
ldo4_vol = 2800


其中這類XXX_vol的項目對於懂行的朋友而言一看就知道是配置PMIC芯片的供電輸出的。可是即便這樣猜想知道了這個配置項目的意義,但也不能保證該配置項就能夠起到做用。正如上文所說,MK802並無帶有PMIC,DCDC的供電應該是沒法配置的。另外Linux kernel代碼中或許就沒有對這項配置項進行讀取(好比配置項的DDR內存大小,目前的kernel就是忽略的,須要修改uboot代碼實現1Gb內存的使用,見上一篇文章[4])。

對於沒法猜想含義或者不肯定是否有效的配置項,就須要閱讀Linux kernel的代碼來了解他的具體配置方法和是否起做用了。考慮到不是全部人對這個過程感興趣,所以我將他的介紹安排到了文章模塊的深刻探討部分。我將在那部分以實際的代碼爲基礎介紹。

 

3. 給MK802引出調試串口信號


我blog早些時候曾介紹過這個部分[5],這裏介紹的內容和以前的基本一致,若是已經看過該文章,能夠略過此小節。

3.1. 目的和意義


使用該串口信號咱們能夠即時的獲取MK802的底層工做狀況(uboot和kernel的log),以及可以獲得一個Shell終端,用於登錄linux系統,在沒有網絡或者顯示器的狀況下就能夠對MK802進行操做。而且若是在自制系統時候出現問題,致使MK802沒法正常啓動時,使用調試串口幾乎就是惟一的查找緣由的方式了。另外這個調試串口也能夠做爲與外部設備通信的接口,但我不推薦這種作法,所以本文也不會介紹。

通常作linux kenrel和設備驅動的開發,沒有VC IDE debugger這種好用的工具,就連gdb server不少時候都無論用。最多見的辦法就是經過printf把日誌從串口打印出來調試。(固然若是正在開發串口驅動,那隻好經過點亮幾個LED燈來調試了,這聽上去很瘋狂,但這是事實)。雖然也有ICE/JTAG這類硬件調試器,但對於linux kernel這類OS的調試,硬件調試器就顯得很不直觀,並且不少time critical的邏輯沒法經過下斷點復現。所以,通常作硬件/kernel/驅動層次開發,有一個用於打印printk信息的串口是很是必要的。


 

3.2. 硬件修改


MK802內部含有調試用的串口,但並無將他的信號鏈接出來。經過簡單的焊接工做,咱們能夠把該信號鏈接出來,並使用usb轉串口模塊與pc相連。

圖:將MK802外殼當心拆開

這裏須要將MK802拆開,拆開過程須要比較當心,外殼之間是採用卡口相互固定的,可用硬質的塑料板或者專門的拆機撬棒打開,隨後能夠觀察到在A10芯片的那側有以下圖所示的幾個金色的焊盤:


圖:MK802 PCB上測試點的信號定義


這些測試點沒有絲印標出信號含義,但其實很容易猜到:右起第二個肉眼就能看出是GND。最右側經過萬用表測量是3.3V。那天然是VCC。左邊2個天然有很大嫌疑是TXD和RXD的TTL電平的串口信號。那麼怎麼肯定那個是TX哪一個是RX? 注意左起第二個有一個上拉電阻。通常輸入信號纔要上拉/下拉。那極可能就是RX。用示波器看了下,果真最左側有信號發出。

這個咱們僅須要用到的信號就是TX/RX/GND。VCC也能夠接出來給外部一些低功耗的設備提供3.3V的電能。

當心的將上述信號用導線焊接連出來,而且使用諸如基於FT232/CP2102等芯片的usb轉串口(TTL)的適配器上。注意MK802的RX信號須要與適配器的TX端鏈接。

 

圖:在測試點上焊接導線,並用熱熔膠固定

圖:使用usb轉串口鏈接


到這裏對硬件的修改工做就完成了。

3.3. 經過調試串口查看kernel log以及登錄shell


將上文提到的usb轉串口適配器鏈接電腦。使用Putty(Windows)[6]、高級終端(Windows)、Minicom(Linux\Mac)等支持串口終端的工具打開此串口。並將MK802通電,就能看到啓動過程當中從uboot以及linux kernel輸出的各類log了。

這裏的串口設置是比較通用的115200bps 8bit 1 stopbit的設置。對於絕多大多數的嵌入式設備(以及PC),串口調試均採用該配置。

 

 

圖:使用Putty做爲串口調試終端

圖:從串口輸出的啓動一開始的uboot log

圖:串口輸出的kernel log

對於經過上一篇文章[4]製做的系統,咱們能夠在系統啓動完畢後在串口終端獲得一個bash shell,對於熟悉命令行操做的人來講,已經能夠很自如的使用起MK802了。在後續的系列文章中,我也將介紹如何在沒有HDMI接口的顯示器且沒有配置過網絡的狀況下,僅使用串口完成wifi網絡的配置,以及設置vnc供後續遠程圖形桌面登錄的技巧。

 圖:在啓動完畢後將顯示bash shell的提示符,能夠進行命令行操做


4. 軟件部分的修改和擴展

這裏開始將介紹軟件部分的各類修改或者擴展,主要圍繞前文提到的fex腳本的修改和Linux kernel代碼修改展開。

4.1. 修改顯示分辨率至1080p


前文介紹過MK802所使用的Allwinner A10 CPU帶有在HDMI上輸出1080p的畫面的能力,可是官方的Android系統以及前一篇文章介紹的自制系統仍舊以720p(1280x720)做爲輸出分辨率。
這並非硬件問題,而是軟件(驅動)的配置問題。不過對於Android,目前的4.0版本在設計上並不能支持1080p的畫面,所以咱們沒法對這個系統進行修改。而對於咱們自制的基於傳統linux發行版的系統,就能夠很簡單的修改fex腳本的一行參數達到1080p的配置:
打開上文提到的mk802.fex文件。(具體請參考上文對fex腳本介紹的章節),定位到314行附近,找到screen0_output_mode參數的設置語句,將他賦值爲9(以前是5)。


圖:修改mk802.fex,實現1080p輸出


完成修改之後,使用上一篇文章[4]提到的fex2bin程序將改fex腳本編譯成bin格式:

fex2bin mk802.fex script.bin


這裏提供編譯好的bin文件,方便你們:

http://www.csksoft.net/data/mk802/script.1080p.7z

接下來,只要將該文件把存放自制系統SD卡的第一個分區的對應文件替換,從新啓動mk802,就能夠獲得1080p分辨率的hdmi輸出畫面了。

若是不熟悉這個過程,可在linux下使用以下命令:

mkdir –p sdcard
sudo mount /dev/sdd1 sdcard
sudo cp script.bin sdcard
sudo umount /dev/sdd1

請將上述代碼的下劃線部分替換成符合你實際狀況的sd卡的設備名,若是不清楚,能夠參考[4]的 1.8. 將系統部署到SD卡 章節。

對於爲什麼這裏要將screen0_output_mode設置爲9,若是對此感興趣,能夠參考本文後文的深刻討論部分。


4.2. 使用內部Flash空間存儲數據


MK802自己具備4Gbyte的NAND flash用於存放自身的android系統以及用戶數據。當咱們使用從SD卡啓動的自制系統之後,也能夠將這自身帶有的4Gb的flash空間加以利用保存本身的數據。
不過這個過程會將內置flash中的原有數據破壞,所以這裏也將介紹如何去備份自身flash的數據並恢復。另外咱們不須要擔憂由於破壞了自身android系統致使系統變磚的問題,正像前文[4]提到的,Allwinner A10芯片支持從usb修復的模式,任什麼時候候咱們均可以利用官方提供的修復包恢復到出廠時候的狀況,不須要擔憂變磚。

內置的Nand flash在linux下的設備名:


在咱們的自制系統中,使用sudo fdisk –l查看目前系統可被做爲文件系統的設備列表。(若是提示fdisk命令不存在,可使用apt-get安裝)

sudo fdisk –l

在輸出數據中能夠找到相似下圖的信息:

圖:利用fdisk查看可用的塊設備

經過fdisk的輸出,咱們能夠看到諸如/dev/nandX格式的設備,一共有以下的幾個:

Nand Flash設備名

容量

標籤

/dev/nanda

16 Mbyte

bootloader

/dev/nandb

2 Mbyte

env

/dev/nandc

33 Mbyte

boot

/dev/nandd

536 Mbyte

system

/dev/nande

1073 Mbyte

data

/dev/nandf

1 Mbyte

misc

/dev/nandg

33 Mbyte

recovery

/dev/nandh

134 Mbyte

cache

/dev/nandi

1 Mbyte

private

/dev/nandj

335 Mbyte

sysrecovery

/dev/nandk

1815 Mbyte

UDISK


上表的設備名和容量是能夠從前面的fdisk –l命令中知道的,而對應的標籤,能夠經過dmesg命令查看系統啓動時的log獲得:

dmesg | less


而後搜索「nand」字符串,能夠找到這塊log:

圖:kernel驅動的輸出信息包含了內部flash設備的分區信息

經過對應的標籤名,咱們大體能夠猜到這些分區在原生Android系統中的做用。不過相比這個,咱們更關心如何使用這些分區。

數據備份和恢復


咱們接下來對這些內部flash的使用會破壞原始的數據。若是你須要保留這些數據的話,不妨按照這裏的操做備份他們。這裏如下如今須要備份上表中UDISK標籤的那個nand flash塊(/dev/nandk)爲例子,若是你須要備份全部的分塊內容,須要用這裏給的命令對每一個分塊進行操做。
首先須要明確用於存放備份的目的地有足夠的空間,假設咱們保存在自制系統的SD卡上,能夠用df –h命令查看如今的剩餘空間:

root@linaro-alip:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/mmcblk0p2  7.3G  1.7G  5.3G  24% /
devtmpfs        408M  4.0K  408M   1% /dev
none            408M  4.0K  408M   1% /tmp
none             82M  264K   82M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            408M     0  408M   0% /run/shm
none            408M     0  408M   0% /var/tmp

上面粗體字的一行是當前根文件系統的總大小(7.3G),已用空間和剩餘空間(5.3G)。而咱們要備份的分塊只要1.8G左右,足夠存放。

接下來就是用dd命令備份:

sudo dd if=/dev/nandk of=nandk_backup.img bs=1M

這段命令將/dev/nandk分塊設備的內容保存到當前目錄下名爲nandk_backup.img的文件。

在備份完成後,就能夠放心修改這個分塊的數據了。從此若是須要將他恢復,一樣使用dd命令:

sudo dd of=/dev/nandk if= nandk_backup.img bs=64k



圖:恢復以前的分塊備份數據

這裏能夠看到dd這個命令的靈活性,只要對調of(output flow)/if(input flow)參數的內容,就能實現備份和恢復。所以使用上必須小心,若是弄錯方向,不但破壞了要備份的數據,更可能有其餘災難後果(寫錯了地方)。另外你們可能注意到恢復命令的參數(bs=64k)與以前備份的(bs=1M)不一樣。這是由於nand flash的特性形成的。Nand flash不像DDR內存那樣能夠隨意讀寫修改,他的寫操做老是伴隨着頁擦除動做。而一個頁通常爲64kbyte(或者是其約數),所以制定64kbyte爲寫入單位能夠顯著提升性能。

另外若是以爲這樣直接將原始的分塊數據備份太浪費空間,能夠在備份的同時加上壓縮,使用以下的命令進行備份便可直接產生gzip壓縮的備份鏡像:

sudo dd if=/dev/nandk | gzip –c > nandk_backup.img.gz

在恢復時使用以下命令:

gunzip –c nandk_backup.img.gz | sudo dd of=/dev/nandk

若是要備份的分塊實際內容較少,則能夠產生體積相對小的多的備份鏡像。

從新格式化而且掛載


要使用每一個分塊做爲存儲設備其實和使用移動硬盤或者u盤操做同樣:進行分區、格式化以及掛載。若是熟悉linux下這些操做,就能夠跳過這裏的介紹了
咱們使用cfdisk這個分區工具簡化操做,你也可使用前一篇文章用到的parted命令。
若是系統沒有這個程序,能夠用apt-get安裝:

sudo apt-get install cfdisk

這裏仍舊以/dev/nandk這個分塊做爲例子:

sudo cfdisk /dev/nandk


此時出現以下畫面:


圖:cfdisk進入畫面

 

這裏咱們打算將這個分塊做爲一個分區,則直接選擇[NEW],按回車,隨後選擇[Primary],再逐步確認。最後出現以下畫面:

 

圖:完成預先分區意向


雖然此時顯示已經爲分區後的結果,但其實並無真的操做nand flash寫入咱們的分區設置,所以此時退出程序還能夠撤銷。咱們選擇[Write]寫入咱們的設定,並肯定該操做後(輸入yes),選擇[Quit]退出便可。

此時能夠再運行fdisk確認咱們的分區動做已經執行了:

sudo fdisk –l /dev/nandk


 

圖:fdisk提示分區動做已生效

隨後咱們將該分區(/dev/nandk1)格式化爲ext4文件系統:


圖:將分區格式化爲ext4文件系統

此時咱們就可使用mount進行掛載了,假設掛在到/media/internal目錄上:

sudo mkdir –p /media/internal
mount /dev/nandk1 /media/internal

這樣一來,目錄/media/internal中的任何文件都會保存在MK802內部的flash空間上了,這個空間大小是大約是1.8G。咱們能夠用df –h命令來驗證:


圖:使用df –h驗證內部flash空間已經掛載

能夠看到最後一條顯示,/media/internal目錄屬於/dev/nandk1設備,而且有1.7G空間。

從新分塊


你們可能會有疑問,前面介紹中MK802使用的是一整塊nand flash芯片,爲什麼如今會有那麼多的分塊設備?是否能夠將這些分塊設備合併起來組成一個完整的4Gb分塊呢?
答案是確定的。其實這裏的分塊也是人爲設定的,分塊的配置一樣也保存在這個nand flash芯片上。在linux kernel啓動時,由維護nand flash芯片操做的驅動讀取分塊配置,纔有瞭如今看到的分塊組織。
所以咱們只要改寫這個分塊配置,就能夠達到從新分塊的效果。這部分的原理和操做將在本文後面的深刻討論部分介紹。

4.3. CPU超頻和頻率控制與節能


 

給CPU超頻:

MK802這類基於ARM CPU的設備其實均可以超頻,只是沒有PC那樣簡單。這裏將介紹將MK802 CPU頻率從原先的1.008Ghz提升到1.104Ghz。雖然提升的比例幅度不高,只有100Mhz左右,可是從實際體驗中,仍是能明顯感覺到速度提升的。若是對MK802的性能有所不滿,不妨作下嘗試,這裏也給出我作過超頻修改過的hardware pack包,能夠按照上一篇文章[4]中的操做,給自制系統加上。

http://www.csksoft.net/data/mk802/mk802_hwpack_cskbuild_overclock.7z

不過須要注意的是這樣的超頻可能會形成不穩定因素,畢竟官方將他的主頻設定在如今的數值上也是通過周密考慮的。所以對於穩定性又要求的應用,請不要用這裏的修改。

這裏咱們須要修改Linux kernel進行超頻,kernel代碼採用前一篇文章[4]採用的版本。因爲Allwinner A10的kernel帶有了cpufreq特性支持,而且代碼自己其實已經支持更高頻率的設定,所以這裏的超頻修改顯得十分容易:

修改位於kernel代碼樹下arch/arm/mach-sun4i/cpu-freq/cpu-freq.h這個文件,定位到第43行,將SUN4I_CPUFREQ_MAX宏定義爲目標頻率1104000000便可:


圖:修改cpu-freq.h提升頻率變動上限


這個宏用於對於allwinner a10 cpu頻率調節(cpufreq.c)模塊中的最高頻率上限的定義,也就是說cpu的主頻能夠達到這個宏所定義的頻率。

至於爲什麼是1104000000這樣一個數值,主要是根據芯片時鐘的PLL倍頻和分頻參數得來的,對於接觸過數字電路時鐘部分設計或者單片機時鐘編程的朋友會比較熟悉這個話題。不過咱們目前沒有a10 cpu的手冊,分頻參數其實在kernel代碼中找到的,見cpu-freq同目錄下的cpu-freq-table.c


圖:對於不一樣a10有效頻率範圍的定義

 

原來目前的linux kernel已經包含了對更高頻率的定義支持,咱們這裏的選值正是經過這裏的定義得出的。該代碼還有更加高的頻率能夠選擇,好比1.2G,個人測試顯示,目前1.104Ghz已是能夠長期工做的最高頻率了,更高的頻率會致使系統運行中的隨機crash。

在修改了上述代碼後還不夠,若是是按照上一篇文章介紹的方法編譯的kernel,則須要從新設置config,將以前禁用的cpufreq支持從新開啓:

 

 

圖:增長CPU Freq的支持


隨後從新編譯kernel,並部署到SD卡上的系統,便可以使用超頻了。

不過目前我給出的鏡像會在系統系統後將CPU頻率模式從新設置成ondemand governor[8]。該模式會隨着CPU負載動態調節頻率,所以大部分狀況下咱們設定的1.104Ghz頻率並不會達到。爲了強制CPU工做在最高頻率,使用下面的命令:

echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor


該命令將設置performance governor,此時查看cpu當前主頻,已經顯示工做在咱們指望的1.104Ghz了。另外也能夠經過/proc/cpuinfo獲得驗證:


圖:驗證CPU已經工做在超頻

 

節能和性能考慮:


這裏從CPU主頻的角度考慮MK802的節能問題。這其實天然是主頻越高,能耗越大了。所以若是須要節能,MK802的頻率就應該下降。上文介紹的超頻方案同時也開啓了CPU動態調整的支持(CPU Freq)。同時例子中也展現了MK802在運行當中是能夠動態改變主頻的。
若是打算將MK802用於對能耗有所考慮的場合,則能夠考慮加入cpufreq特性的支持,並將系統運行在ondemand的scaling governor上。這樣CPU的主頻將按當前的負載狀態動態調整。而若是須要工做在最大頻率,則使用performance governor。對應的,有powersaving governor能夠將cpu主頻設置到最低主頻上。這能夠用於實現系統休眠。
不過因爲CPU主頻調整自己也會消耗性能和時間,並且ondemand模式並不能很是有效的將主頻調節到一個正好合適的地步。在實際使用中(主要是圖形化桌面操做中),將發現採用了ondemand governor模式,系統會變得很是不流暢。

 5. 小結


本文主要介紹的hack技巧就介紹到這裏。在接下來的系列文章將開始介紹如何爲MK802平臺開發應用程序,而且會介紹一些會用到的工具。一樣本文到到此並未結束,下邊的部分是爲想更進一步瞭解hack背後細節的朋友準備的。

6. 深刻討論


這裏將結合Kernel代碼深刻介紹上述每一個hack的具體細節。這裏我就假設讀者具備相關的經驗了,不過多介紹背景知識。

6.1. Fex腳本的加載和解析過程

uboot階段


fex的binary形式文件首先會在uboot執行腳本階段被加載到固定的內存地址上。這部分的代碼能夠參考uboot腳本mk20050pxd:


setenv boot_mmc 'fatload mmc 0 0x43000000 script.bin; fatload mmc 0 0x48000000 ${kernel}; if fatload mmc 0 0x43100000 uInitrd; then bootm 0x48000000 0x43100000; else bootm 0x48000000; fi'
setenv bootcmd 'run boot.scr setargs boot_mmc'
setenv bootdelay '3'
setenv console 'ttyS0,115200'
setenv extraargs 'rootwait'

上述代碼將script.bin(fex腳本)加載到內存的0x43000000區域,隨後uboot負責加載linux kernel並跳轉至kernel的入口函數。

kernel啓動


在Linux kernel啓動的前期會執行arch/arm相關的平臺初始化代碼,其中位於arch/arm/mach-sun4i/sys_config.c文件爲fex腳本的對應操做函數代碼。其中包含了初始化過程,見LN:586:

int gpio_init(void)
{
    printk("Init eGon pin module V2.0\n");
    gpio_g_pioMemBase = (u32)CSP_OSAL_PHY_2_VIRT(CSP_PIN_PHY_ADDR_BASE , CSP_PIN_PHY_ADDR_SIZE);
    #ifdef FPGA_RUNTIME_ENV
    return script_parser_init((char *)(sys_cofig_data));
    #else
    return script_parser_init((char *)__va(SYS_CONFIG_MEMBASE));
    #endif
}


其中,SYS_CONFIG_MEMBASE宏的定義:

#define   SYS_CONFIG_MEMBASE                 (PLAT_PHYS_OFFSET + SZ_32M + SZ_16M)


恰好能夠計算獲得地址:0x43000000。也就是script.bin的加載地址。此時fex的操做函數庫初始化完畢,該函數庫提供了以下主要接口,供其餘的驅動模塊調用查詢fex中的對應配置項:

int script_parser_fetch(char *main_name, char *sub_name, int value[], int count);

所以,只要搜索對函數script_parser_fetch的引用,就能明確整個kernel中對fex腳本的讀取代碼的位置,以及具體哪些fex項目會被真正生效。


圖:經過查找對script_parser_fetch的引用,明確對應的驅動代碼

 

各驅動啓動


這裏之後文接着提到的framebuffer驅動爲例,該驅動位於drivers/video/sun4i/disp/dev_fb.c。其中對於script_parser_fetch採用了一個wrapper函數:OSAL_Script_FetchParser_Data:
見LN:42:


圖:framebuffer驅動對於fex配置讀取的代碼

 

這部分的代碼將在該設備驅動的加載初始化被執行,從而完成對fex配置的讀取和對應模式的設置工做。

6.2. framebuffer設備對Fex腳本的解析配置

上文已經交代了這裏所說的framebuffer設備的驅動代碼位置以及負責解析fex腳本的代碼塊。這裏回到前文提出的問題,爲什麼screen0_output_mode設置成9便可?
咱們能夠定位到LN:95:

    if(OSAL_Script_FetchParser_Data("disp_init""screen0_output_mode", &value, 1) < 0)
    {
        __wrn("fetch script data disp_init.screen0_output_mode fail\n");
        return -1;
    }
    if(init_para->output_type[0] == DISP_OUTPUT_TYPE_TV || init_para->output_type[0] == DISP_OUTPUT_TYPE_HDMI)
    {
        init_para->tv_mode[0]= (__disp_tv_mode_t)value;
    }
    else if(init_para->output_type[0] == DISP_OUTPUT_TYPE_VGA)
    {
        init_para->vga_mode[0]= (__disp_vga_mode_t)value;
    }

這部分代碼即爲對screen0_output_mode配置的讀取,並按照screen0_output_type設置到對應的域中,這裏咱們真正關心的是tv_mode[0]對應類型__disp_tv_mode_t的定義:

typedef enum
{
    DISP_TV_MOD_480I                = 0,
    DISP_TV_MOD_576I                = 1,
    DISP_TV_MOD_480P                = 2,
    DISP_TV_MOD_576P                = 3,
    DISP_TV_MOD_720P_50HZ           = 4,
    DISP_TV_MOD_720P_60HZ           = 5,
    DISP_TV_MOD_1080I_50HZ          = 6,
    DISP_TV_MOD_1080I_60HZ          = 7,
    DISP_TV_MOD_1080P_24HZ          = 8,
    DISP_TV_MOD_1080P_50HZ          = 9,
    DISP_TV_MOD_1080P_60HZ          = 0xa,
    DISP_TV_MOD_1080P_24HZ_3D_FP    = 0x17,
    DISP_TV_MOD_720P_50HZ_3D_FP     = 0x18,
    DISP_TV_MOD_720P_60HZ_3D_FP     = 0x19,
    DISP_TV_MOD_PAL                 = 0xb,
    DISP_TV_MOD_PAL_SVIDEO          = 0xc,
    DISP_TV_MOD_NTSC                = 0xe,
    DISP_TV_MOD_NTSC_SVIDEO         = 0xf,
    DISP_TV_MOD_PAL_M               = 0x11,
    DISP_TV_MOD_PAL_M_SVIDEO        = 0x12,
    DISP_TV_MOD_PAL_NC              = 0x14,
    DISP_TV_MOD_PAL_NC_SVIDEO       = 0x15,
    DISP_TV_MODE_NUM               = 0x1a,
}__disp_tv_mode_t;


這裏貼出了該枚舉型的定義(include/linux/drv_display_sun4i.h LN:171),能夠看到加粗的一行:

DISP_TV_MOD_1080P_50HZ          = 9,

 

 這即是9對應的實際顯示模式:1080p 50hz。一樣,按照這個枚舉定義表,還有更多的配置,諸如DISP_TV_MOD_1080P_24HZ_3D_FP(3D畫面?)可使用,這就等待你們挖掘了。對於上面的3D畫面模式,我猜測一旦開啓後,他會將原先對應2個顯示器輸出的framebuffer分別用於左右眼的畫面,這個有待驗證。

經過分析這些代碼,咱們還能夠知道fex腳本中更多配置的含義和對應的配置值。所以給咱們hack的空間還有不少。

6.3. Nand Flash的驅動部分解讀和從新分塊


能夠經過以前提到的dmesg中的log追查到Nand Flash的驅動代碼。它位於:drivers/block/sun4i_nand/。能夠看出這是Allwinner專門設計的一個Nandflash驅動庫。
從代碼結構上看,這個驅動庫完成了從NAND flash芯片基本的讀寫、擦出操做的壞塊標註等高級的功能的實現,感受仍是比較高級的。
這裏重點關注的是drivers/block/sun4i_nand/nfd/mbr.c這個文件,位於LN:126

 for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
 {
     if((mbr->array[part_cnt].user_type == 2) || (mbr->array[part_cnt].user_type == 0))
     {
   PRINT("The %d disk name = %s, class name = %s, disk size = %d\n", part_index, mbr->array[part_cnt].name,
      mbr->array[part_cnt].classname, mbr->array[part_cnt].lenlo);

         disk_array[part_index].offset = mbr->array[part_cnt].addrlo;
   disk_array[part_index].size = mbr->array[part_cnt].lenlo;
   part_index ++;
     }
 }

加粗代碼就是產生以前提到的nand分塊和對應標籤名稱log的部分。分析代碼能夠知道這些信息來自於全局結構mbr,而該結構體數據在該文件LN:82獲得加載:

if(LML_Read((MBR_START_ADDRESS + MBR_SIZE*i)/512,MBR_SIZE/512,mbr) == 0)


從函數LML_Read的定義註釋(sun4i_nand/src/logic/logic_ctl.c) :

Description: Read data from logic disk area to buffer

能夠知道,這個函數的做用就是把(MBR_START_ADDRESS + MBR_SIZE*i)/512地址的flash空間數據讀取到mbr指向的內存中,而mbr的結構定義是:

/* mbr info */
typedef struct tag_MBR{
 __u32 crc32;     // crc, from byte 4 to mbr tail
 __u32 version;     // version
 __u8  magic[8];     // magic number
 __u8  copy;      // mbr backup count
 __u8  index;     // current part no
 __u16   PartCount;    // part counter
 PARTITION array[MAX_PART_COUNT];// part info
 __u8 res[MBR_RESERVED];         // reserved space
}MBR;

以及其中的PARTITION array的類型定義:
/* part info */
typedef struct tag_PARTITION{
 __u32 addrhi;    //start address high 32 bit
 __u32 addrlo;    //start address low 32 bit
 __u32 lenhi;    //size high 32 bit
 __u32 lenlo;    //size low 32 bit
 __u8  classname[12];  //major device name
 __u8  name[12];    //minor device name
 unsigned  int       user_type;          
 unsigned  int       ro;               
 __u8  res[16];    //reserved
}PARTITION;

這裏咱們很明確的能夠知道控制nand flash區塊的數據存在地址,以及如何來修改它了:只要本身構造一系列PARTITION array對象,並會寫到這段區域便可。

不過我發現其實這個工做社區中已經有人作了[7]。能夠將它的代碼作必要修改後並編譯後,修改MK802 內部nand flash的分區表,這樣就能夠實現咱們前面所說的區塊合併了。


7. 參考文獻


[1] Allwinner A10 - ARM Cortex A8 SoC
http://rhombus-tech.net/allwinner_a10/

 

[2] Mali (GPU)
http://en.wikipedia.org/wiki/Mali_(GPU)

 

[3] Allwinner A10 devices
http://wiki.xbmc.org/index.php?title=Allwinner_A10_devices

 

[4] 基於MK802 MiniPC的擴展開發應用--系統自制
http://www.csksoft.net/blog/post/mk802_dev_sysbuild.html

 

[5] 給MK802(USB大小的Android4.0小PC)引出串口信號,變成ARM開發版
http://www.csksoft.net/blog/post/288.html

 

[6] PuTTY: A Free Telnet/SSH Client
http://www.chiark.greenend.org.uk/~sgtatham/putty/

 

[7] 修改內部nand flash分區的工具(git commit)
https://github.com/amery/sunxi-tools/commit/c8ae7438a79e8973cf572b4cbf6206c658f8e943

 

[8] CPU Governors explained
http://forum.xda-developers.com/showthread.php?t=1736168

相關文章
相關標籤/搜索