Portowanie OpenWrt na Belkin F5D8235-4 V1
Ostatnia zmiana: 2013-11-26 18:43

Urządzenie całkowicie nie jest wspierane w OpenWrt. Nowsze wersje (v2) były oparte o architekturę ramips, więc istniała nadzieja że w tym przypadku będzie podobnie. Niestety aby się o tym przekonać należało po prostu rozkręcić urządzenie i dostać się do interfejsu szeregowego.

Interfejs szeregowy

Najprostsza sprawa może być najtrudniejsza, tak samo było w tym przypadku - a rozbiło się na próbie rozebrania urządzenia. Brak na zewnątrz widocznych śrubek nie wróżył nic dobrego. Próba delikatnego powadzenia obudowy też nie przyniosła rezultatu. Zdjęcia podobnego produktu - F5D8235 V2 znalezione na sieci ujawniły, że śruby schowane są pod przednim panelem. Producent w tym przypadku zastosował sprytny (dla niego) trik - aby w ogóle rozebrać urządzenie należy zdjąć przednią folię z panelu, co niestety oznacza albo uszkodzenie folii albo warstwy kleju pod nią (i tym samym widać, że urządzenie było rozbierane). Można też po prostu wyciąć dziury w obudowie - jak się wie dokładnie w którym miejscu. Zdecydowałem się na ściągnięcie folii, tym samym uzyskałem dostęp do śrub.



Po wykręceniu i wyjęciu z zatrzasków ukazała się płyta - i tu kolejne zaskoczenie - prawie cała powierzchnia, wszystkie układy scalone przykryte są miedzianą folią, która jest przylutowania do płytki. Więc bez jej ściągnięcia nie da się nawet zobaczyć jakie układy scalone zostały zastosowane.



Szybki rzut oka na płytkę ujawnia 9 (!) pinowe złącze. Ponieważ nie ma innego na płytce to istniała nadzieja że zawarte z nim sygnały mogą być interfejsem szeregowym, Multimetr w dłoń i szybko dało się zdiagnozować masę (GND). Następnie podłączenie sygnału RX kabla szeregowego (najgłupszą metodą - po kolei do wszystkich złączy) przyniosło oczekiwane rezultaty w postaci serii krzaczków na ekranie podczas startu urządzenia.

Krzaczki zwykle oznaczają tylko jedno - ustawioną złą prędkość, więc przestawienie w terminalu prędkości transmisji na 57600 (zamiast normalnego 115200) dało wynik w postaci logów uruchamiania systemu. Taką samą metodą wystarczyło zlokalizować linię wejściową i miałem komplet. Sygnały wglądają następująco


    Pin Sygnał
    1 TX
    7 RX
    8 GND

Logi z oryginalnego oprogramowania są zwykle bezcenne - tak i było tym razem, tym bardziej ze nie zdecydowałem się na usunięcie miedzianego ekranu. Ich analiza przyniosła następujące wnioski:
- system oparty jest na SoC Ramips 288x, taktowany 266 MHz
- pamięć flash to 8MB
- pamięć RAM to 32MB
- bootloader o zmodyfikowany u-boot (o czym będzie dalej)
- mamy kontroler USB 2.0 (ehci)
- przełącznik sieciowy na układzie RTL8366S (gigabit)
- układ radiowy: Ralink rt2860

Więc mamy do czynienia z normalnym systemem pod OpenWrt, choć trochę wolnym (266MHz). Czas więc na zabranie się do portowania OpenWrt na to urządzenie.

Bootloader

Za program startowy został wybrany U-boot, ale zmodyfikowany przez Ralinka. Log podczas uruchomienia.


============================================
Ralink UBoot Version: 2.0
--------------------------------------------
ASIC 2880_MP (MAC to GigaMAC Mode)
DRAM COMPONENT: 128Mbits
DRAM BUS: 32BIT
Total memory: 32Mbytes
Date:Jun 12 2008 Time:15:40:46
============================================
    D-CACHE set to 4 way
    I-CACHE set to 4 way

    ##### The CPU freq = 266 MHZ ####

    SDRAM bus set to 32 bit
    SDRAM size =32 Mbytes

Please choose the operation:
            1: Load system code to SDRAM via TFTP.
            2: Load system code then write to Flash via TFTP.
            3: Boot system code via Flash (default).
            4: Entr boot command line interface.
            5: Load ucos code to SDRAM via TFTP.

Mamy więc do dyspozycji proste opcje pozwalające na zładowanie systemu do ramu, do flash, uruchomienie systemu lub wejście w tryb poleceń. Czasu na wybranie odpowiedniego polecenia jest bardzo mało, więc po prostu wystarczyło trzymać wciśnięty określony przycisk podczas startu urządzenia.

Na pierwszy ogień poszła opcja numer 4 czy linia poleceń. Zgłosił się standardowy uboot, po wpisaniu help mamy do dyspozycji opcje jakie spotykane są w innych urządzeniach (uproszczone jak w tplinku). Była także opcja printenv, która może dostarczyć interesujących danych:


RT2880 # printenv
bootcmd=tftp
bootdelay=3
baudrate=57600
ethaddr="00:AA:BB:CC:DD:10"
ipaddr=10.10.10.123
serverip=10.10.10.3
preboot=echo;echo
ramargs=setenv bootargs root=/dev/ram rw
addip=setenv bootargs $(bootargs) ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname):$(netdev):off
addmisc=setenv bootargs $(bootargs) console=ttyS0,$(baudrate) ethaddr=$(ethaddr) panic=1
flash_self=run ramargs addip addmisc;bootm $(kernel_addr) $(ramdisk_addr)
kernel_addr=BFC40000
u-boot=u-boot.bin
load=tftp 8A100000 $(u-boot)
u_b=protect off 1:0-1;era 1:0-1;cp.b 8A100000 BC400000 $(filesize)
loadfs=tftp 8A100000 root.cramfs
u_fs=era bc540000 bc83ffff;cp.b 8A100000 BC540000 $(filesize)
test_tftp=tftp 8A100000 root.cramfs;run test_tftp
stdin=serial
stdout=serial
stderr=serial
ethact=Eth0 (10/100-M)

Inne opcje tego uboota można było pominąć, ponieważ załadowanie firmware można zrobić wybierając jedną z poprzednich opcji.

Ponowny reset i wybranie opcji 1 - uruchomienie obrazu z pamięci ram. Ujawniło to też następne dane:
- domyślny adres ip w bootloaderze to 10.10.10.123
- adres spodziewanego serwera tftpd to 10.10.10.3
- domyślna nazwa obrazu to test.bin

Pobrałem obraz kernela z http://downloads.openwrt.org/snapshots/trunk/ramips/openwrt-ramips-rt288x-uImage.bin, zapisałem w katalogu tftpd. Obraz został wczytany i... uruchomił się. Choć nie do końca - wywalił się na wczytaniu systemu plików (bo go nie było, to sam kernel), ale sam fakt że działa dobrze rzutowało na przyszłość.

Mapa pamięci flash

Należało teraz więc dorobić wsparcie dla tego urządzenia. Wracając do logów oryginalnego systemu mamy podział pamięci flash


Using physmap partition definition
Creating 5 MTD partitions on "RT2880 SOC Physically mapped flash":
0x00000000-0x00050000 : "uboot"
0x00050000-0x007e0000 : "Kernel and Rootfs"
0x00180000-0x007e0000 : "Rootfs"
0x007e0000-0x007f0000 : "Nvram"
0x007f0000-0x00800000 : "Factory"

I należało to wykorzystać przy budowie własnego oprogramowania. Wszystkie zmiany są do wykonania plikach w katalogu target/linux/ramips w źródłach OpenWrt. W katalogu files/arch/mips/ralink/rt288x znajdują się definicje 2 urządzeń. Jedna z nich dla WZR-AGL300NH okazała sie szczególnie cenna, bo jest bardzo prosta - zawiera tylko definicję urządzenia i mapę pamięci flash. Wzorując się na niej zbudowałem swoją własną mapę pamięci (w nowym pliku mach-f5d8235-v1.c), modyfikując dodatkowo pliki Kconfig oraz Makefile żeby ten plik budował się podczas kompilacji. Dodatkowa zmiana była potrzebna w pliku files/arch/mips/include/asm/mach-ralink/machine.h aby dodać definicję tego urządzenia. W systemie była już także definicja dla F5D8235 V2, ale jako że jest to urządzenie oparte na SoC rt305x okazała się teraz mało przydatna.

Pierwsza kompilacja kernela, uruchomienie (zadziałał!) i pojawił się poważny problem. Moja mapa pamięci flash okazała się niewystarczająca bo kernel przy uruchomieniu wypisał


Reducing visibility of 8192KiB chip to 4096KiB

(zmniejszenie ilości flash z 8MB do 4MB), Więc gdzieś był błąd. Dalsza analiza kodów przynosiła smutną odpowiedź - okazało się że dla RT2880 na stałe jest zapisane. że ma 4MB lub 16MB pamięć flash. Więc należało to zmodyfikować. Definicja rozmiaru flasha znajduje się w files/arch/mips/ralink/rt288x/devices.c który m.in. określa rozmiar flasha stałą RT2880_FLASH0_SIZE, która wynosi... 4MB. Zmiana była bardzo prosta (choć niszczy wsparcie dla innych architektur) - zamiast RT2880_FLASH0_SIZE należało napisać 2*RT2880_FLASH0_SIZE i mamy 8MB.

Ponowna kompilacja i działa tak jak trzeba. Jest cała pamięć flash, 8MB, podział jest taki jak trzeba, system został prawidłowo rozpoznany. Oczywiście nadal brakowało systemu plików, ale przynajmniej się uruchomił. Dopisałem kolejną poprawkę, przywracając w/w tak jak był, a za to dodając kolejną definicje wielkości pamięci flash (czyli tak jak to powinno być zrobione od początku).

System plików

Gotowy obraz powinien zawierać kernel + system plików, aby móc go załadować opcją 2 bootloadera do urządzenia. W pliku target/linux/ramips/images/Makefile są definicje tworzenia obrazów. Szczególnie przydatna okazała się linią do budowy obrazu F5D8235 V2 - produkowała ona generyczny obraz (znany z tplinków plik *-sysupgrade) który zawiera właśnie kernel i system plików. Wzorując się więc na nim (wzorując, bo ma inny podział pamięci flash) stworzyłem podobny dla F5D8235 V1.

Kolejna kompilacja, Obraz skompilował się poprawnie pod nazwą openwrt-ramips-rt288x-f5d8235v1-squashfs-sysupgrade.bin, liczył 3.2MB. Zmieniłem jego nazwę na test.bin, umieściłem w katalogu serwera tftpd. Restart urządzenia, przytrzymanie przycisku 1 i należało odpowiedzieć na parę pytań:
- czy jesteśmy pewni (tak)
- ip urządzenia (10.10.10.123 domyślnie) - enter
- ip serwera (10.10.10.3 domyślnie) - enter
- nazwę obrazu (test.bin domyślnie) - enter
i po tym rozpoczęło się pobieranie pliku. Trwało dość długo (kilkanaście sekund), potem flash pamięci i ponowne uruchomienie. Wszystkie możliwe diody LED zaświeciły się (a jest ich trochę - to urządzenie ma także 5 ledów na miernik sygnału czy transferu).

System wczytał kernel, znalazł system plików. Dalsze uruchamianie zakończyło się błędem kernela (moduł sieci radiowej RT28xx nie załadował się, spowodował awarię modułu), ale system pozwolił na zalogowanie się! W ten sposób miałem działające (choć niekompletne jeszcze) OpenWrt. Nie działa WiFi, nie sprawdzałem USB, nie ma obsługi przycisków i LED. Szybkie sprawdzenie systemu przyniosło kolejną niespodziankę - nie ma sieci...

Sieć przewodowa

Następna analiza źródeł architektury przyniosła proste rozwiązanie - stworzony przeze mnie plik mach-f5d8235-v1.c okazał się poprawny, ale po prostu zabrakło w nim kodu do obsługi ethernetu. Dodanie jednej linii - rt288x_register_ethernet(); , kompilacja i ponowne uruchomienie spowodowało pojawienie się interfejsu eth0; został stworzony br-lan i dostał on domyślny adres 192.168.1.1.

Sukces. Ping 8.8.8.8 i... nie działa. Nie działa w ogóle, nie ma nawet odpowiedzi laptopa do którego jest podłączone urządzenie. Olśnienie przyszło stosunkowo szybko - okazało się że interfejs działa, jak fizycznie kabel został przepięty do portu WAN. Lan jest obsługiwany przez RTL8366S, ale to czeka w kolejce do zrobienia.

Następna wersja V2 również jest wyposażona w taki sam chip. Pracuje ona korzystając z GPIO1 (I2C - SDA) oraz GPIO2 (SCLK). Praktycznie więc 1:1 przeniosłem struktury odpowiedzialne za przełącznik, skompilowałem i okazało się że nie działa. Zgłosił się z błędem inicjacji GPIO o numerze -16. Przeglądając definicję okazało się, ze dla ramipsa trzeba jeszcze jawnie określić że ma korzystać z magistrali I2C (RT2880_GPIO_MODE_I2C dla inicjacji platformy). Po dodaniu, kompilacji i uruchomieniu - działa.


Realtek RTL8366S ethernet switch driver version 0.2.2
rtl8366s rtl8366s: RTL8366 ver. 1 chip found

Okazało się to proste. Teraz tylko należy zdefiniować odpowiedni plik network. Tu z pomocą przychodzi narzędzie swconfig. Proste polecenie:


    # swconfig dev switch0 help

pokazało m.in:


    switch0: rtl8366s(RTL8366S), ports: 6 (cpu @ 5), vlans: 4096

Jest więc do dyspozycji 6 portów (0-5), ostatni jest portem CPU. Natomiast polecenie


    # swconfig dev switch0 port 0 get link

Pokazuje status linku. Teraz już zostało mi proste podłączenie kabla ethernetowego pod każdy port i sprawdzenie który jest który. Port 0 okazał się wanem, porty 1-4 lanami, więc cała konfiguracja sieci wygląda tak:


    config interface loopback
        option ifname lo
        option proto static
        option ipaddr 127.0.0.1
        option netmask 255.0.0.0

    config interface lan
        option ifname eth0.1
        option type bridge
        option proto static
        option ipaddr 192.168.1.1
        option netmask 255.255.255.0

    config interface wan
        option ifname eth0.2
        option proto dhcp

    config switch
        option name rtl8366s
        option reset 1
        option enable_vlan 1
        option blinkrate 2

    config switch_vlan
        option device rtl8366s
        option vlan 1
        option ports "1 2 3 4 5t"

    config switch_vlan
        option device rtl8366s
        option vlan 2
        option ports "0 5t"

Proste, prawda? Urządzenie wzbogaciło się o obsługę sieci przewodowej...

USB

Na szybko skompilowałem moduły do usb. Zainstalowałem, podłączyłem i jak zwykle - nie działa. Niestety problem jest bardziej poważny, ponieważ RT288X w ogóle nie definiuje zasobów dla USB, więc trzeba to wszystko napisać od początku.

Sieć bezprzewodowa

Pamiętając oryginalne logi można było znaleźć informację o interfejsie radiowym, który został zrealizowany z wykorzystaniem układu radiowego Ralink rt2860. W OpenWrt obsługiwany on jest przez moduł kmod-rt2x00-pci. Wystarczyło go zaznaczyć, skompilować i uruchomić. I jak zwykle okazało się że nie działa, wyświetlał komunikat:


    phy0 -> rt2x00lib_request_eeprom_file: Error - Failed to request EEPROM.

Ustawiane jest to m.in. w pliku target/linux/ramips/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom - dopisane podobnej regułki jak dla f5d8235-v2 spowodowało działanie interfejsu.

Przyciski i LED

Sprawa była stosunkowo prosta - wykorzystując sysfs i gpio należy wykryć gdzie są diody i przyciski. Dla tych pierwszych ustawia się gpio jako wyjściowe i sprawdza czy po ustawieniu/zgaszeniu coś się zmienia w diodach. Podobnie dla przycisków - ustawiamy linię jako wejściową i sprawdzamy czy zmieni się jej stan po naciśnięciu przycisku.

W ten sposób znalazłem gpio odpowiedzialne za przyciski oraz niektóre diody LED.

Aktualna łatka ze zmianami dostępna na: https://lists.openwrt.org/pipermail/openwrt-devel/2011-December/013053.html, obsługa została oficjalnie włączona do OpenWrt Trunk: https://dev.openwrt.org/changeset/29617

Na dzień dzisiejszy brakuje:
- USB (dla RT288X w ogóle brak jest obsługi)
- niektórych LED (trzeba je znaleźć)

CDN.