273 Commits
Author SHA1 Message Date
logicog 018eab9810 Also display RTL837X_REG_LED_MODE 2026-06-10 05:45:19 +02:00
logicog ec36658ab9 Add ZX310S-4T2XT device photos 2026-06-10 05:45:19 +02:00
logicog eeded0f788 Add (Horaco) ZX310S-4T2XT
The ZX310S-4T2XT is a managed device with 2x2.5GBit and 2x10GBit Ethernet.
It is sold, among others, by Horaco as an unbranded device.

CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY 2x RTL8261BE
2026-06-10 05:45:19 +02:00
logicog 8f3b738e59 Merge pull request #257 from logicog/revert-252-main
Revert "Don't disable flash DIO operation before flashing"
2026-06-07 10:47:10 +02:00
TylerDurden-23 62065875e3 Revert "Don't disable flash DIO operation before flashing" 2026-06-07 10:42:39 +02:00
René van Dorst 94e34a5991 Merge pull request #251 from feelfree69/make
make: seperate output directories by MACHINE
2026-06-05 19:16:04 +00:00
René van Dorst b58b1dfb35 Merge pull request #252 from feelfree69/main
Don't disable flash DIO operation before flashing
2026-06-05 19:13:30 +00:00
feelfree69 4ca5b4e87a Don't disable flash DIO operation before flashing - it works fine with DIO 2026-06-01 15:07:37 +02:00
logicog 5a8a8ed91b Merge pull request #237 from Erdnusschokolade/fix/config-persistence
Fix config persistence: missing commands, delete handling, multipart upload
2026-06-01 06:46:11 +02:00
René van Dorst ad64e450e1 Merge pull request #246 from logicog/sfp_speed
Add support for configuring SFP modules speeds via CLI
2026-05-31 18:33:05 +00:00
feelfree69 cfeffc434d Merge pull request #248 from zectaiga/swtg024as-a-2-0-1-fixes
Fix SWTG024AS-A 2.0.1 port and LED mapping
2026-05-31 10:42:01 +02:00
feelfree69 8670709b6e make: seperate output directories by MACHINE 2026-05-31 01:17:33 +02:00
logicog 1a457c29ac Add support for 100FX modules and forcing 100FX 2026-05-30 23:08:44 +02:00
logicog ce496ab25f Merge pull request #249 from vDorst/fix_led_settings
Fix SFP led for 2.5gbit for MACHINE_SWGT024_V2_0
2026-05-30 22:07:56 +02:00
René van Dorst 964ef2da7a Fix SFP led for 2.5gbit for MACHINE_SWGT024_V2_0
While testing #246, I noticd that SFP did not light-up while forcing
2.5gbit link. This is because RJ45 and SFP share the same LED-settings.
But RJ45 has two leds-settings.
Solution is to add settings for SFP for both managed and unmanaged
variant.
2026-05-30 21:02:42 +02:00
logicog 8c61010a84 Add support for configuring SFP modules speeds 2026-05-29 20:46:08 +02:00
Taiga Ogawa 053dbe286e Fix SWTG024AS-A 2.0.1 port and LED mapping 2026-05-30 03:44:15 +09:00
feelfree69 e68e5cef46 Merge pull request #244 from kekopop/main
Add PCB-SWTG024AS-A-V2.0.1
2026-05-26 22:15:21 +02:00
kekopop b5543b6aeb Update machine.c 2026-05-26 22:04:26 +02:00
kekopop a51fcf1478 Update machine.h 2026-05-26 22:03:42 +02:00
kekopop 247cb4dd2f Add files via upload 2026-05-26 19:44:31 +02:00
logicog 394fc99485 Merge pull request #242 from tofurky/fix_xgspon_rates
Broaden range of SFP+ rates mapped to SDS_10GR
2026-05-26 05:32:54 +02:00
logicog cf0707475d Merge pull request #241 from tofurky/regset_arg_count
Correct argument count for regset command
2026-05-26 05:25:22 +02:00
Matt Merhar 73b99b2f08 Broaden range of SFP+ rates mapped to SDS_10GR
A commonly used SFP+ form-factor XGS-PON ONT (WAS-110) reports 0x63 at
power on and then switches to 0x64 after booting up.

0x63 -> 9.9gbps
0x64 -> 10gbps

These are outside of the previous 0x66-0x69 range which prevented the
link from ever being brought up.
2026-05-25 21:45:42 -04:00
Matt Merhar 005eaa3248 Correct argument count for regset command
Fixes: 2cdab5f9d9 ("parse_reg{set,get}() make use cmd_words_len.")
2026-05-25 20:24:27 -04:00
feelfree69 98f1e9443a Merge pull request #239 from amstan/ztyuav
doc: Describe other PCB-K0402WS-V3.0 devices
2026-05-25 23:23:16 +02:00
feelfree69 4c2be334d5 Merge pull request #233 from Erdnusschokolade/feature/vlan-overview
Add VLAN selector dropdown and overview table to vlan.html
2026-05-25 12:30:30 +02:00
Alexandru M Stan 073cc1e4a4 doc: Describe other PCB-K0402WS-V3.0 devices
I recently brought a "Ztyuav Z-QWYT0402", the insides looked identical to the
existing supported "Hisource Hi-K0402WS". Both of them have the
"PCB-K0402-V3.0" silkscreen.

I flashed the vanilla image and it seems to work great.

I changed the documentation to be more inclusive of other devices (including
adding a picture of mine). I suspect more devices might fall into this
"PCB-K0402-V3.0" bucket, for example the "YuanLey YS25-0402" with
the vlan switch also looks suspiciously identical from the outside.

I also added some details I noticed while flashing mine:
teardown, flash padding, how the selector switch actually works.
2026-05-24 18:33:23 -07:00
Erdnusschokolade ba919280ac Address PR #233 review feedback
- itoa16_html: add comment that the function is sufficient for VLAN
  IDs (<=4094); generalization not needed.
- send_vlanlist: replace post-write bounds check with a pre-write
  guard using worst-case entry size (138 bytes + 1 for closing
  bracket). Old comment claimed ~45 bytes per entry, which only
  held for short names. With a 117-char name (the actual bound from
  CMD_BUF_SIZE) entries can reach 138 bytes, and the post-check
  would not have prevented an overflow.
- Document the 0x02 check in sfr_data[0] as the VLAN table entry
  valid flag.
2026-05-24 23:31:18 +02:00
Erdnusschokolade dcc60c3824 Fix conf_overwrite vlan/mgmt conflict
The pattern /^vlan\s+\d{1,4}\b/ matched both VLAN membership entries
(vlan N <ports>) and management entries (vlan N mgmt), causing them
to overwrite each other in configuration[]. When saving, whichever
form came last in the cmd_log would dedupe the other out of the
final config — resulting in either lost membership or a stale mgmt
setting.

Split into two patterns using negative lookahead:
- /^vlan\s+\d{1,4}\s+mgmt$/      matches only mgmt entries
- /^vlan\s+\d{1,4}(?!\s+mgmt\b)/  matches everything else

Both dedup independently. Discovered via hardware test on 6XH-X
where 'vlan 44 mgmt' silently dropped 'vlan 44 management 2t 5u'
from saved config, locking out web UI on next boot.
2026-05-24 11:26:04 +02:00
Erdnusschokolade caad366b3b Fix config persistence: missing commands, delete handling, multipart
Multiple related bugs in the Save-to-Flash path:

1. Multipart upload was missing the required filename argument,
   causing the backend parser to fail. Added 'config.txt' to the
   form.append call. This was likely the primary reason Save-to-Flash
   was unreliable.

2. Web UI was not pausing its polling interval during flash write,
   causing CPU contention and intermittent crashes. Added isSaving
   lock and clearInterval before sendConfig.

3. conf_cmds whitelist was incomplete. Added: syslog, passwd, pvid,
   ingress, port name, lag, laghash, isolate, stp, igmp, mtu, bw,
   vlan N mgmt, vlan N d.

4. VLAN regex blocked named VLANs. New pattern allows optional name
   (starts with letter, matching CLI parser semantics).

5. vlan N d (delete) was not persisted. parseConf now removes the
   matching vlan N ... entry from configuration[] when seeing a
   delete command, without storing the delete itself. Result: the
   saved config describes the end state.

6. configuration[] was not cleared between flashSave invocations,
   leading to stale entries from prior interactions.

7. conf_overwrite boundary fix: 'pvid 1' no longer matches 'pvid 10'
   etc. Added trailing space in startsWith check.

8. All conf_cmds patterns now anchored with ^...$ for full-line
   match. parseConf normalizes whitespace before testing.

9. Port range widened to \d{1,2} so ports 11+ are accepted.

Structural fixes (1, 2, 6, 7, 8) ported from mcaptur's closed PR #219;
remaining fixes (3, 4, 5, 9) and overall regex strategy are new.
2026-05-24 11:26:04 +02:00
Erdnusschokolade ce0ee859d6 Fix: Untagged Ports column included non-member ports
The hardware bitmask format encodes both "untagged members" and
"non-members" in the upper 10 bits (per doc/vlan.md). The existing
fetchVLAN() correctly masks this with the membership bitmask before
display, but loadVlanTable() did not, causing non-member ports to
appear in the Untagged Ports column.

Tested on KeepLiNK KP-9000-6XH-X.
2026-05-24 11:20:57 +02:00
Erdnusschokolade a369e46fe6 Add VLAN overview table to VLAN configuration page
Below the configuration form, a new table lists all configured VLANs
with their port memberships: Member, Tagged, Untagged, and PVID
columns. Port ranges are formatted compactly (e.g. "1-2,5").

Port-to-bit mapping uses the existing physToLogPort[] array populated
by /status.json, so the table is consistent with the icon view in
fetchVLAN() and works on any supported machine.

Each row has a delete button that sends "vlan N d" via /cmd, with
a confirmation dialog. VLAN 1 cannot be deleted (no button shown).

Table and dropdown both refresh automatically after Update/Create
and after delete via a new refreshVlanViews() helper.

The N+1 request pattern (1x /vlanlist + Nx /vlan.json) keeps the
backend simple and avoids buffer overflow risks for systems with
many VLANs. For typical configurations (<50 VLANs), page load
remains under one second.
2026-05-24 11:20:57 +02:00
Erdnusschokolade defb37c06a Add VLAN selector dropdown to VLAN configuration page
A new <select> element above the VLAN ID input lets users pick an
existing VLAN by name instead of typing the ID. Options are loaded
from /vlanlist on page load and re-loaded after successful
Update/Create operations.

Selection triggers the existing fetchVLAN() flow.

Falls back gracefully if /vlanlist returns an empty list or fails:
the dropdown is hidden and the existing ID input remains functional.
2026-05-24 11:20:57 +02:00
Erdnusschokolade a5f77e4caf Add /vlanlist HTTP endpoint
Returns a JSON array of all configured VLANs with their IDs and names,
e.g. [{"id":1,"name":""},{"id":20,"name":"IoT"}].

The endpoint iterates VLAN IDs 1..4094 and filters by the validity bit
in sfr_data[0] (0x02), following the same pattern as vlan_create() and
vlan_setup() in rtl837x_port.c.

Also adds a small itoa16_html() helper for emitting decimal numbers
up to 4 digits (analogous to the existing 8-bit itoa_html()), used
for VLAN IDs which can reach 4094. Response builder uses the existing
vlan_name() helper for the name lookup, consistent with send_vlan().

Buffer overflow is prevented by breaking out of the iteration loop at
TCP_OUTBUF_SIZE - 60.

This endpoint is the foundation for upcoming UI improvements
(VLAN selector dropdown and overview table).
2026-05-24 11:20:57 +02:00
logicog 1311cb9ea9 Merge pull request #232 from Erdnusschokolade/fix/vlan-name-rename
Fix VLAN name persistence across rename and delete operations
2026-05-23 12:47:06 +02:00
Erdnusschokoladeandlogicog 7d0d8525d2 Fix two OOB reads in parse_vlan()
1. While loop scanning VLAN name terminated only on ' ', not '\0'.
   When the name is the last token in cmd_buffer, the loop reads past
   the buffer into adjacent XRAM.

2. Entering 'vlan' without arguments causes parse_vlan() to read
   cmd_words_b[1] which points to undefined memory, causing atoi_short()
   to interpret residual bytes from previous commands as a VLAN ID.
   Bug found and fix proposed by logicog during review of PR #232.

Co-Authored-By: logicog <logicog@users.noreply.github.com>
2026-05-23 11:19:42 +02:00
logicog 201289990b Merge pull request #236 from Erdnusschokolade/doc/vlan-mgmt-command
doc: document vlan <id> mgmt command
2026-05-23 07:31:39 +02:00
Erdnusschokolade 3a93ce1786 doc: document vlan <id> mgmt command
Adds CLI reference for the previously undocumented vlan <id> mgmt
command, including the disable case (vlan 0 mgmt), default state,
and a lockout warning.

Fixes #235
2026-05-23 00:26:13 +02:00
René van Dorst 4b42be8cae Merge pull request #234 from logicog/fix_duplex
Fix duplex setting on the CLI
2026-05-22 19:38:33 +00:00
logicog 32f9b91def Fix duplex setting on the CLI
Fixes commands such as
> port 1 duplex half
2026-05-22 21:07:29 +02:00
Erdnusschokolade 21f33abfa7 Fix VLAN name persistence across rename and delete operations
Previously, renaming a VLAN or deleting and recreating it with a
different name did not update the displayed name. The vlan_names[]
array is an append-only buffer where vlan_name() returns the first
matching entry, so stale entries kept winning.

This commit adds vlan_name_remove(), which locates an entry by
VLAN ID and removes it via array compaction. The function is called
in two places:

  - parse_vlan() in cmd_parser.c, before appending a new name entry,
    to remove any pre-existing entry for the same VLAN ID
  - vlan_delete() in rtl837x_port.c, to clean up the name when a
    VLAN is removed

The implementation reuses the existing vlan_name() lookup, scans for
the trailing space of the matched entry, then shifts remaining bytes
left. Locals are declared as static __xdata to avoid the SDCC
overlay segment limit on banked functions.

Tested on KeepLiNK KP-9000-6XH-X:
  - vlan 99 AAA p1u; vlan 99 BBB -> name updated to BBB
  - vlan 99 d; vlan 99 CCC p1u   -> name correctly CCC, not stale AAA

Note: This fix addresses the runtime XMEM state. Persistence of
renamed VLAN names across reboot requires the user to download and
re-upload /config, as is the existing pattern for all configuration
changes in this firmware.
2026-05-21 17:39:29 +02:00
René van Dorst d253c9feee Merge pull request #231 from xristos-sk/fix-rtl837x_stp-bug,-cmpMac-always-0-when-checking-for-new-root
fix: rtl837x_stp bug, cmpMac always 0 when checking for new root
2026-05-19 19:57:45 +00:00
sk_thes 2552f586d8 fix: rtl837x_stp bug, cmpMac always 0 when checking for new root
When checking for a new root, a root_bridge with the same priority as STP_I will never be adopted as cmpMAC always returns 0.

This PR fixes this bug by changing the comparison of MACs to what was intended
2026-05-18 22:47:31 +00:00
logicog f113b2c0e5 Merge pull request #230 from vDorst/refactor_is_word
Refactor is_word() and is_word_x()
2026-05-18 18:31:17 +02:00
logicog 2d912d80c9 Merge pull request #229 from vDorst/fix_login
Fix and refactor is_url_word_x()
2026-05-18 18:30:28 +02:00
logicog 0682df3027 Merge pull request #226 from UAb5eSMn/execute_commands
Support for executing multiple commands via /cmd
2026-05-18 18:29:55 +02:00
René van Dorst 4b40efafbb Fix and refactor is_url_word_x().
With content_type = "application/x-www-form-urlencoded", "+" means space.
This case was not handled.

Also refactor the code to make a loop to process the hex digits.
2026-05-17 21:23:35 +02:00
René van Dorst 02992771ad change is_word_x() return type from char to bool.
Saves 10 bytes.
2026-05-17 21:15:39 +02:00
René van Dorst f81c497728 refactor is_word_x()
Saved 22 bytes.
2026-05-17 21:13:07 +02:00
René van Dorst b46cc2087f change is_word() return type from char to bool.
Saves 52 bytes.
2026-05-17 21:12:57 +02:00
René van Dorst 3904daced7 refactor is_word()
Saved 23 bytes.
2026-05-17 19:14:27 +02:00
René van Dorst 623247da4f httpd: Added extra content_type check for login.
Ensure login content_type is "application/x-www-form-urlencoded".
2026-05-17 17:17:15 +02:00
René van Dorst aa5368cf34 Merge pull request #228 from zectaiga/add-fns1200p
Add support for FOXNEO FNS-1200P (RTL8372, 4x2.5G PoE+ + 2x SFP+)
2026-05-17 11:58:18 +00:00
René van Dorst 2b39d723c7 Merge pull request #225 from orbisai0security/fix-v010-firmware-upload-auth-integrity
fix: authenticate config upload before flash erase and abort failed firmware CRC
2026-05-17 11:52:22 +00:00
Taiga Ogawa f6cb1152f9 Add support for FOXNEO FNS-1200P (RTL8372, 4x2.5G PoE+ + 2x SFP+)
- machine.c/h: add MACHINE_FNS1200P with verified GPIO assignments for
  both SFP ports, LED SET0 (amber 2.5G / green 1G-100M-10M) and SET1
  (SFP all-speeds), led_mux from original firmware register dump, and
  machine_custom_init() enabling LED_GLB_IO_EN bit 6
- doc/devices/FNS-1200P.md: device overview, port layout, serial
  console (S1 three through-holes = UART0 115200 8N1 3.3V),
  LED and SFP GPIO tables
- doc/devices/photos/FNS-1200P/: chassis front panel and PCB top photos
- doc/supported_devices.md: add FNS-1200P to the list

GPIO assignments and LED register values were cross-checked between
live GPIO observation (RTLPlayground gpio command) and an original
firmware register dump.
2026-05-16 17:53:32 +09:00
René van Dorst bf9fa35338 Merge pull request #224 from logicog/fix_passwd
Add URL decoding for password comparison.
2026-05-15 20:04:15 +00:00
logicog 8ab2a6a9da Add URL decoding for password comparison. 2026-05-15 16:04:48 +02:00
UAb5eSMn 2316ffd493 Support for executing multiple commands via /cmd 2026-05-15 13:27:09 +02:00
orbisai0security a71eb57702 fix: V-010 security vulnerability
Automated security fix generated by Orbis Security AI
2026-05-15 02:46:09 +00:00
René van Dorst a2b2dbcfbf Merge pull request #221 from feelfree69/kp9000
Adding Keeplink KP-9000-6XH-X2
2026-05-15 02:08:42 +00:00
feelfree69 8cee16e96b add documentation for KP-9000-6XH-X2.md 2026-05-10 12:20:04 +02:00
feelfree69 a1135863bb add MACHINE_KP_9000_6XH_X2 2026-05-10 12:16:48 +02:00
dobodu ede4137101 Revise compiling section and add cautionary notes since #193 (#211)
* Revise compiling section and add cautionary notes

Updated compiling instructions and added warnings about flashing procedures.

* Refactor caution messages in README.md

Updated caution messages to use new formatting for emphasis.

* Revise caution and reminder notes in README

Updated caution and reminder sections for clarity and consistency.

* Fix typos in README regarding firmware update

Corrected typo errors in the README.

* Add image for advanced settings

Add advanced_seetings.png

* Add advanced settings configuration details to README

Added advanced settings section with configuration instructions.

* Fix image source in README for advanced settings

Corrected the image source filename for advanced settings.

* Revise IP and port command descriptions in README

Updated command descriptions in README for clarity.

* Revise README.md for clarity and updated instructions

Updated sections in README.md for clarity and accuracy, including compiling requirements, installation instructions, and cautionary notes.

* Revise README for clarity and emphasis

Updated formatting and emphasized important notes in the README.

* Correct image file name and compilation output in README

Updated README to reflect changes in image file names and compilation output.
2026-05-08 08:32:07 +02:00
logicog 0106f99ee0 Merge pull request #214 from feelfree69/flash_erase
Erase flash before writing upload image
2026-05-08 08:30:45 +02:00
logicog 733348059d Merge pull request #217 from mcaptur/main
Hi-Source HI-k0801WS - deleted a line by mistake
2026-05-08 08:27:12 +02:00
Mark Captur 950b763d69 Hi-Source HI-k0801WS - deleted a line by mistake 2026-05-08 07:38:43 +02:00
feelfree69 22aaa9fbfe Renamed and moved FLASH_PAGE_SIZE; added compile-time check 2026-05-08 07:13:41 +02:00
logicog 89e22f0893 Merge pull request #216 from mcaptur/main
Add hardware profile and LED fix for Hi-Source HI-k0801WS
2026-05-08 06:40:29 +02:00
Mark Captur 809efaa8d8 Hi-Source HI-k0801WS 2026-05-08 06:11:43 +02:00
Mark Captur 271878a62f Hi-Source HI-k0801WS 2026-05-08 06:09:17 +02:00
Mark Captur 299b54f2a3 Add pics for Hi-Source HI-k0801WS 2026-05-08 06:03:15 +02:00
Mark Captur f47fec7098 Add pics for Hi-Source HI-k0801WS 2026-05-08 06:02:21 +02:00
Mark Captur 04ce2cb8a1 Add doc for Hi-Source HI-k0801WS 2026-05-08 05:53:04 +02:00
Mark Captur 96eddf5a0c Add hardware profile and LED fix for Hi-Source HI-k0801WS 2026-05-07 16:06:00 +02:00
logicog 2cd6f5d782 Merge pull request #212 from feelfree69/make
Makefile: Improve filenames of images
2026-05-04 07:55:54 +02:00
feelfree69 c6dc5cc21c Don't delete *.bin files on 'make clean' - 'make distclean' does this 2026-05-04 07:11:44 +02:00
feelfree69 502033590e untracked files don't mark a build as -dirty 2026-05-04 06:55:11 +02:00
feelfree69 f81529bd07 Merge pull request #210 from logicog/fix_chrome_uploads
Fix chrome uploads
2026-05-03 16:53:48 +02:00
feelfree69 9714818b1f Erase flash before writing upload image 2026-05-03 15:55:36 +02:00
logicog 9c668969d4 Fix POST upload request handling for Chrome browser
Chrome sends upload requests using POST with multipart/form-data
content type in multiple packets for the header part of the form-data.

Introduce a TSTATE_MULTIPART for the httpd server states that denotes
that so far only a part of the multipart header has been transmitted.
Once the full header has been transmitted, we change to TSTATE_POST
as for Firefox which sends all the multipart header in one piece.

The main further change required then is to make sure that the parsing
of the initial part of the multipart request is only parsed once and initially
to distinguish between configuration and firmware uploads.
2026-05-03 08:16:55 +02:00
feelfree69 241bcb273f rename output of installer-Makefile to rtlplayground_oem_upgrade.bin 2026-05-02 21:45:39 +02:00
feelfree69 10367d0cdb Use a revision- and MACHINE-dependent output-filename 2026-05-02 21:44:44 +02:00
René van Dorst 09d90d6d97 Merge pull request #175 from logicog/ZX310S-4T2XH
10GBit Ethernet Switch support (Horaco ZX310S-4T2XH)
2026-05-02 17:22:52 +00:00
logicog 12c98ba6bd Merge pull request #148 from feelfree69/syslog
Syslog: Duplicates console output to remote syslog server; Web-Interface: Send console commands to device
2026-04-27 20:30:39 +02:00
feelfree69 3f66a18104 Merge branch 'main' into syslog 2026-04-24 12:01:30 +02:00
logicog 8abbececd1 Add device description for ZX310S-4T2XH 2026-04-24 10:53:05 +02:00
logicog d6dbf4e4dd Add photos of ZX310S-4T2XH 2026-04-24 10:53:05 +02:00
logicog e2b3201c9f Add machine name for ZX310S-4T2XH 2026-04-24 10:53:05 +02:00
logicog a7f4543698 Add support for (Horaco) ZX310S-4T2XH
Add support for the ZX310S-4T2XH switch, which is a 4x2.5GBit + 1x10GBit + SFP
device. The device does not have any branding and is sold under different
brand names, in particular by Horaco. There is no branding on either label
nor PCB.

CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV
10GBit PHY: RTL8261BE

UART header present, but solder holes are filled with solder that needs
removal, first, e.g with a 1.2mm drill.

The original firmware uses 57600baud 8N1
2026-04-24 10:53:05 +02:00
logicog 2e0e55967c Do not send SFP info if no SFP port present 2026-04-24 10:53:05 +02:00
logicog 7877ce60f3 Add support for 5G link speeds, make 5G/10G LED blue 2026-04-24 10:53:05 +02:00
logicog a3dd25e0fe Add SDS parameter for RTL8261 setup 2026-04-24 10:53:05 +02:00
logicog 441340a4d4 Add SMI configuration support for dual 10G Ethernet 2026-04-24 10:53:05 +02:00
logicog 9a3f8c359d Enable 10g EEE on init 2026-04-24 10:53:05 +02:00
logicog 63ab6500c0 Add 10G/5G speed configuration/display 2026-04-24 10:53:05 +02:00
logicog ec5f74bbed Add is10g_port field in phy_settings 2026-04-24 10:53:05 +02:00
logicog a597d2d08b Fix EEE control register address and add 5G/10G EEE defines
Register RTL8373_EEE_CTRL_BASE did not actually exist at 0x606c,
instead RTL837X_EEE_STATUS is actually not only a status, but also
a control register for EEE enable/disable at the MAC.

The defines are not actually register bits, but port EEE settings,
so move them to rtl837x_port.h while adding 5G/10G flags.
2026-04-24 10:53:05 +02:00
logicog abc9cb7afd Add 5G speed display support and 5/10G EEE display/settings 2026-04-24 10:53:05 +02:00
logicog 6d579c4f00 Add speed bits for 5G/10G EEE 2026-04-24 10:53:05 +02:00
logicog c342964327 Add SDS init for RTL8261BE connection 2026-04-24 10:53:05 +02:00
logicog fd3a272255 Add RTL8261BE PHY configuration
Add configuration of the RTL8261BE PHY on startup.
2026-04-24 10:52:24 +02:00
logicog 4f4f69ecc1 Handle RTL8261BE SerDes configuration
The RTL8261BE uses a 10GBit QSGMII connection. Add handler for initial
configuration of the SerDes speed and upon link changes.
2026-04-24 10:52:24 +02:00
logicog c8e21b394b Add forgotten register RTL837X_REG_LED3_2_SET3
The register had been forgotten in the LED configuration registers,
add the register definition and print out the content in leds_dump().
2026-04-24 10:50:53 +02:00
logicog c34249b90a Add n_10g property in machine structure
This uint8_t field corresponds to the n_sfp field and gives the number
of 10G ports for the machine. The values can be 0, 1, 2 for known machines,
all currently supported machines do not have any 10G ports, so no
need to change any entries in machine.c
2026-04-24 10:50:53 +02:00
René van Dorst 042f4324a4 Merge pull request #166 from logicog/frame_header
Cleanup Frame header structures and fix management VLAN
2026-04-24 06:53:07 +00:00
logicog e280ccd2f9 Use RTL descriptor definition 2026-04-24 08:42:00 +02:00
logicog baa4e5e142 Use header structures of TX and RX, add dot1q for management VLAN TX 2026-04-22 22:36:26 +02:00
logicog b53e7e1a06 Add NOTHS macro 2026-04-22 22:36:26 +02:00
logicog 14b45735e2 Cleanup STP, use new frame descriptor definitions 2026-04-22 22:36:26 +02:00
logicog 946e80cebe Add frame descriptor structure 2026-04-22 22:36:26 +02:00
logicog e2df95ba90 Cleanup DHCP client code 2026-04-22 22:36:26 +02:00
logicog 570ee6c995 Move initialization routines to BANK2 2026-04-22 22:36:26 +02:00
feelfree69 e849af4a70 adapted syslog cmd_parsing to new method 2026-04-21 21:38:41 +02:00
feelfree69 812bf3bb67 Move code of rtl837x_pins.c to BANK2 due to BANK0 overflow 2026-04-21 21:37:25 +02:00
feelfree69 da8ec8fe88 Merge branch 'logicog:main' into syslog 2026-04-21 21:26:45 +02:00
logicog 01fa43510e Merge pull request #206 from vDorst/fix_cmd_parsing
Fix cmd parsing
2026-04-21 21:24:22 +02:00
René van Dorst d2e79d4d80 Fix: In commit 8cbafaa cmd_tokenize() has changed. Missed that it also used
outside cmd_parser.c.
Fix the other location and headerfile.
2026-04-21 21:17:22 +02:00
René van Dorst 016061d8db cmd: Fix 8324edc atoi_short() commit.
vlan initialization was removed while trying out an other version.
But was not restored back.
2026-04-21 21:16:03 +02:00
feelfree69 f7989cc737 Merge branch 'logicog:main' into syslog 2026-04-21 14:29:44 +02:00
logicog 5035366551 Merge pull request #204 from vDorst/remove___gptrxxx_calls
Remove `__gptrput()` and `__gptrget()` calls
2026-04-21 05:38:33 +02:00
logicog 2a8f183e6a Merge pull request #203 from vDorst/refactor_cmd_parsing
Refactor cmd parsing
2026-04-19 22:51:04 +02:00
René van Dorst 18225f5d22 uip: more fix. 2026-04-19 22:18:39 +02:00
René van Dorst 224471d676 uip: move second argument to __xdata free up 4 sram bytes. 2026-04-19 22:18:39 +02:00
René van Dorst 50d06c61bc change prototype uip_udp_new(), saves 1 sram. 2026-04-19 22:18:39 +02:00
René van Dorst d5709bcaf3 fix atoi 2026-04-19 22:18:39 +02:00
René van Dorst 52d943d5e4 rtlplayground: de-__gptrput()-call in read_reg_timer() 2026-04-19 22:18:39 +02:00
René van Dorst e79e90dd35 cmd_parser: de-__gptrput()-call in vlan_ingress_mode_parse() 2026-04-19 22:18:36 +02:00
René van Dorst da768171a5 change cmd_tokenize().
Remove the return argument because `err_status` is also reflecting the result.
Fix the error message when too many arguments are found.

refactor `execute_config()`, error out when err_status is not OK.
2026-04-19 22:00:31 +02:00
René van Dorst 94bf4425ba uip: de-__gptrput()-call access to struct uip_udp_conn 2026-04-18 22:38:42 +02:00
René van Dorst 3e599f0e06 dhcp: de-__gptrput()-call in ip_opt() 2026-04-18 22:27:55 +02:00
René van Dorst 6c6d11ab33 dhcp: de-__gptrget()-call in dhcp_print_ip() 2026-04-18 22:20:46 +02:00
René van Dorst 791f68582d httpd: de-__gptrget()-call in string_to_html() 2026-04-18 22:20:46 +02:00
René van Dorst facc4afe40 uip: de-__gptrget()-call in timer_{set,reset,restart,exprired}() 2026-04-18 22:20:46 +02:00
René van Dorst 8134ca7ec7 uip: de-__gptrget()-call in uip_ipaddr_copy() 2026-04-18 22:20:46 +02:00
René van Dorst 642030c7b2 uip: de-__gptrget()-call in uip_add32() 2026-04-18 22:20:46 +02:00
René van Dorst 8324edc5f7 cmd_parser: Improve atoi_byte() and atoi_short().
Because no memory type is specified to the reference location, sdcc is
using a helper function to access the location. But sdcc is using a
register to tell the helper function which memory-type is used.
This registers must also be preseved until all access to that location is done.
2026-04-18 22:19:35 +02:00
René van Dorst f2ff7d7737 parse_ee() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst a24b63a81f parse_mtu() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst abe3513bc6 parse_port() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 49c43082a3 parse_mirror() make use of cmd_words_len, refactor small parts 2026-04-18 19:35:51 +02:00
René van Dorst f71e869b97 parse_ingress() make use of cmd_words_len, refactor small parts 2026-04-18 19:35:51 +02:00
René van Dorst 1fe236246a parse_isolate() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 2acf2499d1 parse_lag_hash() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 56e0d0a5d1 parse_lag() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 7380aeb10d parse_bw() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 0d698dc572 parse_passwd() make use of cmd_words_len, change password memcpy. 2026-04-18 19:35:51 +02:00
René van Dorst c7fb354f08 parse_sds{get,set}() and parse_phy{get,set}() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 2cdab5f9d9 parse_reg{set,get}() make use cmd_words_len. 2026-04-18 19:35:51 +02:00
René van Dorst 301577efc8 parse_vlan() make use of cmd_words_len. 2026-04-18 19:35:51 +02:00
René van Dorst 1156f00f95 cmd_parser() make use of cmd_words_len 2026-04-18 19:35:51 +02:00
René van Dorst 8cbafaa347 Change cmd_tokenize() it only stores valid locations and use a length field. 2026-04-18 19:35:48 +02:00
René van Dorst 80ff1b25c9 Improve: cmd_compare().
Because `cmd` is guaranteed by the compiler to be NULL-terminated, we can make use of that to ensure the loop always ends.
So we don't need to know when the next words starts.
2026-04-18 19:15:25 +02:00
René van Dorst 1a5208110c Merge pull request #195 from logicog/fix_config_reading
Fix reading configuration over flash block boundaries
2026-04-17 11:46:03 +02:00
logicog e2717ef7ca Count pages instead of bytes reading config in execute_config() 2026-04-17 11:37:15 +02:00
logicog 1769528420 Introduce global error variable, check during config execution 2026-04-16 22:01:51 +02:00
logicog 9d4c06d752 Merge pull request #200 from feelfree69/port_names
Port names
2026-04-14 18:51:43 +02:00
feelfree69 2565aeadf4 Do no show empty names in tooltips 2026-04-14 18:28:13 +02:00
logicog c3530aaafc Handle error when configuration file cmd too long 2026-04-14 18:00:29 +02:00
TylerDurden-23 6af19e1e6b Merge pull request #197 from logicog/isolation
Port Isolation CLI command
2026-04-14 08:02:16 +02:00
logicog 1683eef94b Fix bug where cmd_words[] is not properly initialized 2026-04-14 05:16:45 +02:00
logicog 036d9ca229 Add port isolation cmd 2026-04-13 20:13:28 +02:00
feelfree69 b31179acbe move extern declaration for port_names to trl837x_common.h 2026-04-13 19:14:24 +02:00
logicog b7ad67d336 Make port isolation API available 2026-04-13 18:15:01 +02:00
feelfree69 e130777b24 serial console cosmetic change 2026-04-13 14:55:50 +02:00
feelfree69 41f0dad49d Add ability to assign a name to a port 2026-04-13 14:55:10 +02:00
feelfree69 2e48415c95 fix after rebase: added udp_apps.c 2026-04-12 13:46:53 +02:00
feelfree69 22f8b9a287 rebase minor change in syslog cmd parsing 2026-04-12 13:08:05 +02:00
feelfree69 c91177d992 Web-If: Add Console-Cmd input 2026-04-12 13:02:42 +02:00
feelfree69 c1a414833d Various refactorings 2026-04-12 13:02:42 +02:00
feelfree69 2a9c7d2828 restart syslog when changing ip 2026-04-12 13:02:42 +02:00
feelfree69 d776118815 Revert unneeded changes 2026-04-12 13:02:42 +02:00
feelfree69 f7b8aed2f7 first working(?) version 2026-04-12 13:02:42 +02:00
feelfree69 7eb3676aaf remove log command 2026-04-12 13:02:42 +02:00
feelfree69 eaa21d5975 rebase First try to make use of uIP for sending syslog 2026-04-12 13:02:37 +02:00
feelfree69 193eacf51b rebase add syslog-addr to web-interface 2026-04-12 13:00:12 +02:00
feelfree69 b60811b984 initialize all vars; remove unused code 2026-04-12 12:58:02 +02:00
feelfree69 b85861347b Added setting for syslog IP 2026-04-12 12:58:02 +02:00
feelfree69 b21bfac917 rebase first prototype 2026-04-12 12:57:49 +02:00
logicog d4d12fe3b4 Merge pull request #192 from janh/cmd-sds-phy
Add commands to read/write SerDes and PHY registers
2026-04-10 15:37:01 +02:00
logicog 4440bcc43a Fix reading configuration over flash block boundaries 2026-04-09 22:34:32 +02:00
Jan Hoffmann f6a5163f33 Add commands to access PHY registers 2026-04-06 18:25:40 +02:00
Jan Hoffmann e210f31f0e Add commands to access SerDes registers 2026-04-06 18:25:35 +02:00
Jan Hoffmann 9eecdd071a Add atoi_byte function
Similar to atoi_short, but reads into a uint8_t instead of a uint16_t.
2026-04-06 18:25:30 +02:00
René van Dorst c4368c68be Merge pull request #189 from bstreiff/pcb23_v2_2
Add support for keepLink KP-9000-9XHML-X (2M-PCB23-V2.2 version)
Rename machine keepLink KP-9000-9XHML-X (2M-PCB23-V3.1 version)
2026-04-05 14:04:10 +00:00
ranma 1b02f303b2 Merge pull request #190 from ranma/fix-bit-linking
Fix declaration of tx_buf_empty bit var

__sbit is for SFRs, for regular data __bit should be used. Otherwise the variables is not correctly declared in the BSEG section, leading to bit temporaries being allocated in the same location.

When this causes the tx_buf_empty to be overwritten to 0, then the next write_char will hang forever.

With this change the bit is properly declared in BSEG for the linker, which in my testing resolves the overlap issue:
```
;--------------------------------------------------------
; bit data
;--------------------------------------------------------
        .area BSEG    (BIT)
_tx_buf_empty::
        .ds 1
```

Only the vlan and mtu commands call atoi_short, which has a local bit _atoi_short_sloc0_1_0 which is the first bit in the BSEG, and assigning to that one corrupted the tx_buf_empty bit.
Though this is also a compiler optimization-failure, the _atoi_short_sloc0_1_0 value isn't even used after assignment, AFAICS it is a dead store.

Its from the isnumber inline:
```
[...]
;--------------------------------------------------------
; bit data
;--------------------------------------------------------
        .area BSEG    (BIT)
_atoi_short_sloc0_1_0:
        .ds 1
_parse_ip_sloc0_1_0:
        .ds 1
[...]
;       cmd_parser.c:85: l -= '0';
        mov     r3,a  
        add     a,#0xd0
;       cmd_parser.c:86: return (l <= ('9'-'0'));
        add     a,#0xff - 0x09
        cpl     c
;       cmd_parser.c:172: while (isnumber(cmd_buffer[idx])) {
        mov     _atoi_short_sloc0_1_0,c
        jnc     00103$
[...]
```
2026-04-05 11:05:10 +02:00
Tobias Diedrich fd9a7717ce Fix declaration of tx_buf_empty bit var
__sbit is for SFRs, for regular data __bit should be used.
Otherwise the variables is not correctly declared in the BSEG
section, leading to bit temporaries being allocated in the same
location.

When this causes the tx_buf_empty to be overwritten to 0, then
the next write_char will hang forever.
2026-04-04 22:02:45 +02:00
Brenda Streiff 29ce05b70e Add keepLink KP-9000-9XHML-X V2.2 version
This splits the current MACHINE_KP_9000_9XHML_X definition into "V2_2"
and "V3_1" versions for the two known versions of this hardware.

Confirmed to work:
- LED configuration matches stock firmware
- Port ordering matches label
- A SFP can be detected and EEPROM read (I don't have a fiber cable to test link)
- Reset button presses are detected
2026-04-04 11:40:03 -05:00
Brenda Streiff 97ae6bf1d3 Document the '2M-PCB23-V2.2' PCB
Sold as "keepLINK KP-9000-9XHML-X". This is different from the other, "V3.1"
version of the "keepLINK KP-9000-9XHML-X".
2026-04-04 11:40:03 -05:00
TylerDurden-23 4ccb988d70 Merge pull request #188 from UAb5eSMn/machine_check
Check if machine.c can be compiled for all machines
2026-03-31 19:36:57 +02:00
UAb5eSMn 075d7e43f7 Check if machine.c can be compiled for all machines 2026-03-30 22:28:36 +02:00
René van Dorst 97e73d95aa Merge pull request #183 from janh/fix-i2c-and-sfp-ddm
Fix I2C access and SFP diagnostic monitoring in web interface
2026-03-30 17:21:51 +00:00
René van Dorst 2eb6bac4a5 Merge pull request #186 from UAb5eSMn/machine_fix
Fix compilation issue for machine HG0402XG_V1_1
2026-03-29 18:16:17 +00:00
UAb5eSMn 7d4ccf8f23 Remove machine HORACO_ZX_SG4T2 from comment 2026-03-29 20:10:56 +02:00
UAb5eSMn c0f6b8a1a6 Fix compilation error for machine HG0402XG_V1_1 2026-03-29 20:10:56 +02:00
TylerDurden-23 f3b6c16161 Merge pull request #185 from vDorst/fix_swgt024_v2_0
Fix swgt024 v2.0
2026-03-29 18:29:18 +02:00
René van Dorst 73f92f2e12 Add SWGT024_V2_0 Unmanaged pinout and machine type. 2026-03-29 16:35:31 +02:00
René van Dorst bfab8cbba3 Rename MACHINE_SWGT024_V2_0 to MACHINE_SWGT024_V2_0_MANAGED.
So we can support other versions too.
2026-03-29 16:13:38 +02:00
René van Dorst eedb0dec01 SWGT024 v2.0: Fix LED and RESET defines for managed version
Original firmware used for RJ45:
* Amber leds only for 2.5GBit link/act.
* Green leds only for other speeds.
2026-03-29 16:13:36 +02:00
logicog 08ad843c56 Merge pull request #184 from vDorst/rename_led_28
Rename LED_28 to LED_28_SYS.
2026-03-29 07:50:27 +02:00
Jan Hoffmann 05693f5171 Also show SFP TX/RX power in dBm 2026-03-29 00:33:48 +01:00
Jan Hoffmann 6eaa1985aa Fix SFP diagnostic monitoring data in web interface
If the module is not internally calibrated, it is necessary to apply
calibration values to get meaningful results.
2026-03-29 00:33:48 +01:00
Jan Hoffmann 45ba32f65d Fix scaling for power values in SFP diagnostics 2026-03-29 00:33:48 +01:00
Jan Hoffmann 0b4f59483b Don't write SFP options value twice in status JSON 2026-03-29 00:33:48 +01:00
René van Dorst 385c850d2f add comments 2026-03-28 21:40:43 +01:00
René van Dorst cdbc48f2c2 Rename LED_28 to LED_28_SYS.
So it clear that led 28 is the SYSTEM LED.
2026-03-28 19:29:49 +01:00
Jan Hoffmann efe0c282ba Fix I2C access code
While the current implementation works for what it is actually used, it
is broken when trying to do larger transfers.

The length field in the control register has a size of 4 bits. In every
transfer, length+1 bytes are read. Thus, each transfer is limited to a
maximum of 16 bytes. Add a check for the length, and write the correct
value to the register.

Also update the loop in "sfp_send_data" to properly increment the output
register. Remove the unused special case for a length of 128 bytes.
2026-03-28 18:14:15 +01:00
René van Dorst 54fced05b0 Merge pull request #178 from bennydiamond/Support_ZX_SWTGW215AS
Add support for PCB-SWTG115AS-V2.0
2026-03-28 13:16:07 +00:00
bennydiamond b64dfd8c25 Correction on IO mappings
Add further clarification on mapping assumptions
2026-03-27 20:56:09 -04:00
bennydiamond 5f1cd4cce0 Update documentation 2026-03-27 19:34:39 -04:00
bennydiamond 7ffd0c25c2 Support for PCB-SWTG115AS-V2.0
Marketed as Lianguo ZX-SWTGW215AS
2026-03-27 19:34:39 -04:00
René van Dorst 8b4e09ad69 Merge pull request #181 from janh/improve-1g-sfp-compat
Improve compatibility with 1G SFP modules
2026-03-27 22:58:30 +00:00
René van Dorst 34d53dddf2 Merge pull request #179 from bennydiamond/Early_boot_wipe_config
Wipe config if button held at boot
2026-03-27 20:05:55 +00:00
René van Dorst ec5f655bba Merge pull request #180 from janh/k0501w-rename-version
Rename K0501W to include PCB version
2026-03-27 19:52:29 +00:00
René van Dorst 7291f38e46 Merge pull request #182 from janh/commands-newline
Make sure that the output of all commands ends with a newline
2026-03-27 19:05:29 +00:00
Jan Hoffmann c3b99fdcdf Make sure that the output of all commands ends with a newline 2026-03-27 19:36:14 +01:00
Jan Hoffmann 9f800bae01 Improve compatibility with 1G SFP modules
Some modules report a nominal signaling rate of 1200 MBd.
2026-03-27 17:56:40 +01:00
logicog df498b0879 Merge pull request #173 from diijkstra/vlan_console
Console: Add Ingress type & VLAN show table
2026-03-26 21:02:33 +01:00
Jan Hoffmann 03422463e4 Rename K0501W to include PCB version
It seems very likely that other versions are not compatible, so make it
clear by including it in the machine type and name. Also update the
documentation.
2026-03-26 19:59:06 +01:00
bennydiamond 2bfbe5358b LED pattern definition on early boot reset
LED Double blink while button is held

FAST blink for 3 seconds when config is reset
2026-03-26 12:31:20 -04:00
TylerDurden-23 3bb89bfb80 Merge pull request #177 from janh/k0501w
Add support for K0501W boards
2026-03-26 10:12:32 +01:00
bennydiamond dba3679e2f Wipe config if button held at boot
Blocking by design to prevent loading config

Button must be held between 10 and 30 seconds to trigger reset.

If held more than 30 seconds, boot normally. This is to prevent lock-up in case of weird hardware variants.
2026-03-25 23:15:04 -04:00
Jan Hoffmann f331a6129a Add support for K0501W boards
This board appears for example in the Davuaz Da-K6501W switch, and is
designed similarly to Hi-K0402WS.

However, it only has one SFP port and another 2.5G copper port using
RTL8221B 2.5G PHY instead. Also, some components on the board, like
additional LEDs, mode switch, and second flash chip are not populated.

Like earlier revisions of the K0402W(S) board, there is no UART, so
debugging is limited.

As this is an unmanaged switch, installation needs a flash programmer.
2026-03-25 19:31:14 +01:00
logicog 877e5a68fb Merge pull request #176 from janh/improve-2500m-sfp-compat
Improve compatibility with 2.5G SFP modules
2026-03-24 18:13:27 +01:00
Jan Hoffmann ed6c95e522 Improve compatibility with 2.5G SFP modules
Some modules might report a nominal bitrate of 2500 Mbd or 3200 Mbd
instead of 3100 Mbd. Accept the entire range to make them work.
2026-03-24 15:26:29 +01:00
diijkstra cb8d0e45bb Review: Move w initialization 2026-03-23 19:31:06 +01:00
TylerDurden-23 877b16e837 Merge pull request #174 from logicog/fix_vlan_display
Fix display of VLANs for ports
2026-03-22 18:20:33 +01:00
logicog fce64ac368 Fix display of VLANs for ports 2026-03-22 13:45:42 +01:00
logicog dd9e5c8ff8 Merge pull request #172 from diijkstra/trendnet
Document firmware upload via CLI
2026-03-22 05:26:45 +01:00
diijkstra f7fcf0eda7 Console: Add Ingress type & VLAN show table
Added new `vlan show` command to dump current VLAN settings.
Supports printing PVID & ingress filtering per port.

Added new `ingress [p]<mode>` command to setup ingress filtering.
Added wrappers for enabling/disabling vlan filtering. Currently
not configurable, but state in console is read via ASIC registers.

Full VLAN dump & web support of new commands will be added later.
2026-03-21 12:29:26 +01:00
diijkstra 905cf38f1f Trendnet: Another mapping fix
Physical to logical mapping was reverted for SFP ports.
2026-03-21 12:22:36 +01:00
diijkstra b0370f7bb3 Doc: Describe how to upload firmware via CLI & HTTP
Rough explanation how to upload a new firmware. Probably, we should
support basic auth on upload for easier use, but lets document
what we have.
2026-03-21 12:22:36 +01:00
logicog d21d269d49 Merge pull request #152 from mmmspatz/mspatz/fix_vlan_page
Fix "Get Configuration" on vlan.html
2026-03-19 11:36:59 +01:00
feelfree69 cb81f82cf6 Merge pull request #170 from logicog/fix_bank0
Fix missing assignment of bank when html_data.c code is generated
2026-03-19 11:23:07 +01:00
logicog 59e7a21955 Merge pull request #159 from diijkstra/web_sfp_state
Web: Add SFP state/pin status
2026-03-19 05:22:24 +01:00
logicog c530ec4ae3 Fix missing assignment of bank when html_data.c code is generated 2026-03-18 08:34:26 +01:00
TylerDurden-23 8e2b48ef25 Merge pull request #167 from logicog/browsser_trouble
Fix browser issues with Chrome and latest Firefox
2026-03-17 10:29:02 +01:00
logicog 65f094c1d1 Merge pull request #163 from feelfree69/parser_fix
fix crash
2026-03-16 17:51:24 +01:00
logicog 090283d538 Add retry mechanism for xhttp requests to make Chrome happy 2026-03-16 17:32:50 +01:00
logicog 7e3a0f5d8f Allow javascript to modify svg styles for Firefox version >140 2026-03-16 17:32:15 +01:00
feelfree69 4706f6232a simplify parsing code 2026-03-15 15:43:34 +01:00
diijkstra b47a868db3 Web: Handle missing LOS pin
When device has no LOS pin and module has no extended status, the
RX LOS value will not be shown. When both are present, the equality
check is performed. When only one is present, the present value
will be shown.

json from the switch, will still contain the field, but can be
null for when pin is not available.
2026-03-15 12:18:02 +01:00
feelfree69 454eb28bce Merge branch 'logicog:main' into parser_fix 2026-03-15 08:58:15 +01:00
logicog dc283bc724 Merge pull request #165 from feelfree69/bank0_overflow
Fail building image on BANK0 overflow
2026-03-15 07:39:38 +01:00
feelfree69 a001cd3da7 Fail also on BANK0 overflow 2026-03-14 22:15:33 +01:00
feelfree69 e92b4a2358 Don't allow partial commands 2026-03-14 19:47:56 +01:00
René van Dorst 47c5443f0e Merge pull request #164 from TylerDurden-23/fix-1gbaset-sfp
Fix 1GBase-T SFP module not working on serdes port 1.
2026-03-14 17:03:05 +00:00
chriz baa3e7edb7 Fix 1GBase-T SFP module not working on serdes port 1. 2026-03-14 16:33:54 +01:00
feelfree69 34d46aa29a fix crash 2026-03-14 13:59:14 +01:00
diijkstra 6b64534f40 WEB: Display single RX LOS
As sugested, lets display single value, and raise alarm when pin
is different than module.
2026-03-14 13:15:01 +01:00
logicog b18ed62042 Merge pull request #161 from diijkstra/backspace
Console: Handle ^H as backspace
2026-03-14 13:14:39 +01:00
diijkstra 16edc6b421 Console: Handle ^H as backspace
Currently only ASCII DEL (key code 127) is handled as backspace, but some terminal
emulators are sending ^H which is ASCII BS (key code 8). Looks like we can
safely treat both in the same matter.
2026-03-14 12:35:16 +01:00
logicog f1e5b7e31a Merge pull request #92 from vDorst/doc_gpio
doc: gpio overview and mux settings
2026-03-14 12:17:06 +01:00
diijkstra 1f6e07a1af Web: Add SFP state/pin status
The state of the SFP module is being already send in status.json,
but was not parsed via Web UI. When debuging SFP LOS/Signal detection
it is usefull to see what module is reporting back.

Extended the SFP mouse-over information with:
 - RX LOS as reported in 0x02 bit of register 238
 - External TX Disabled from 0x80 bit of register 238
 - TX fault from 0x04 of the same register
 - The last state of RX LOS pin (available also when there is no 0x40
   option on the module)

This should help identify missing/incorrect setup of TX disabled pin.
2026-03-13 23:56:43 +01:00
logicog 0952676504 Merge pull request #158 from diijkstra/trendnet
TEG-S562: Port LEDs
2026-03-13 23:46:22 +01:00
diijkstra 95cbc1a2e0 TEG-S562: Correctly assign SFP
Looks like the SFP numbers are reversed, since GPIOs were mapped
to SFP numbers, the need to be reversed too. This fixes swapped
display of SFP stats on the webpage.
2026-03-13 23:36:29 +01:00
diijkstra d5fdaf28e8 Light description for led-set
Very light description for port_led_set and led_sets, which was
helpfull when bringing up the trendnet device.
2026-03-13 21:43:22 +01:00
diijkstra 511d35f63d TEG-S562: Port LEDs
Added support for all leds on the device.

Stock port sets are slightly differently configured, where additional
LED0 on SET_0 and LED1&LED2 where configured for link/collisions/duplex.
This has not been reproduced as those lines are probably not connected
anywhere.
2026-03-13 21:40:34 +01:00
logicog 96484bc62a Merge pull request #156 from feelfree69/make-cleanup
Cleanup Makefile
2026-03-11 20:54:47 +01:00
feelfree69 765000ce4f fixed html dependencies 2026-03-11 19:08:32 +01:00
feelfree69 dc9b211924 BUILDDIR without slash 2026-03-11 19:01:21 +01:00
feelfree69 b559c3b868 avoid doubled generation of html_data.* 2026-03-11 07:34:18 +01:00
feelfree69 13fe354da7 add dependency file generation 2026-03-11 07:26:15 +01:00
feelfree69 fc4b12725c Cleanup Makefile 2026-03-10 21:57:16 +01:00
logicog 0a52386e60 Merge pull request #155 from feelfree69/fix-bank-overflow
fix bank overflow
2026-03-10 21:47:46 +01:00
feelfree69 4b167151a5 fix bank overflow 2026-03-10 21:35:25 +01:00
René van Dorst f474b5822b Merge pull request #151 from logicog/concurrency
Web request concurrency management
2026-03-10 18:49:18 +00:00
logicog fa37940075 Control xhttp concurrency 2026-03-10 06:16:18 +01:00
Mark H. Spatz 893dcd8fcf update vlan.md 2026-03-08 19:49:37 -04:00
Mark H. Spatz 16f4e2a1c6 Fix range check in vlan_get() 2026-03-08 17:52:39 -04:00
Mark H. Spatz 364d538abd Fix "VLAN ID" field max value on vlan.html 2026-03-08 17:50:54 -04:00
Mark H. Spatz 4cef63200f Fix "Get Configuration" on vlan.html
I noticed that entering some vlan config, clicking "Update/Create", then
clicking "Get Configuration" resulted in Tagged/Untagged/PVID displaying
completely wrong data. It looks like the parisng in fetchVLAN() in
vlan.js was just completely disconnected from the layout of the
registers read by vlan_get() in rtl837x_port.c. Who knows how that
happened.

1. Fix fetchVLAN() member/untag parsing: the old code read bits [9:0]
   as untagged and bits [10:19] as tagged, but the VLAN table register
   layout is members in [9:0] and untag in [19:10]. Now correctly
   derives tagged (member && !untag) and untagged (member && untag).

2. Add PVID to vlan.json response: PVID is stored per-port in separate
   PVID registers (RTL837x_PVID_BASE_REG), not in the VLAN table entry.
   The old code nonsensically tried to read it from bits [20:29] of the
   VLAN table. Add port_pvid_get() and build a pvid bitmask in
   send_vlan() so the JS can parse it correctly.

3. Remove auto-PVID logic from setC(): setC() is called by fetchVLAN()
   while it's loading existing config, and so this logic mangled the
   display of the existing config. Also, it doesn't make sense to
   auto-set the PVID for tagged members (PVID relates to untagged
   ingress.)
2026-03-07 15:18:06 -05:00
René van Dorst a0313eab87 doc: gpio overview and mux settings 2026-01-22 23:04:07 +01:00
104 changed files with 4483 additions and 1079 deletions
+3 -1
View File
@@ -17,5 +17,7 @@ jobs:
run: |
apt update
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev -y
- name: Check if machine.c can be compiled for all machines
run: make machine_check
- name: Make project
run: make MACHINE="KP_9000_6XHML_X2"
run: make MACHINE="KP_9000_6XHML_X2"
+57 -33
View File
@@ -9,34 +9,49 @@ CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
ASM = sdas8051
AFLAGS= -plosgff
SUBDIRS := tools uip httpd
SUBDIRS := tools
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
BUILDDIR = output/
VERSION_HEADER := version.h
ifeq ($(MACHINE),)
MACHINE:= $(shell grep "^\s*#define MACHINE_" machine.h | sed "s/^\s*#define MACHINE_//")
else
CC_FLAGS += -DMACHINE_$(MACHINE)
endif
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)rtlplayground.bin
BUILDDIR = output/$(MACHINE)
VERSION_HEADER := version.h
GIT_VERSION := $(shell git rev-parse --short HEAD)
ifeq ($(shell git status --porcelain --untracked-files=no),)
else
GIT_VERSION := $(GIT_VERSION)-dirty
endif
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
create_build_dir:
mkdir -p $(BUILDDIR)
mkdir -p $(BUILDDIR)/uip
mkdir -p $(BUILDDIR)/httpd
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c \
rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
OBJS += uip/$(BUILDDIR)/timer.rel uip/$(BUILDDIR)/uip-fw.rel uip/$(BUILDDIR)/uip-neighbor.rel uip/$(BUILDDIR)/uip-split.rel uip/$(BUILDDIR)/uip.rel uip/$(BUILDDIR)/uip_arp.rel uip/$(BUILDDIR)/uiplib.rel httpd/$(BUILDDIR)/httpd.rel httpd/$(BUILDDIR)/page_impl.rel
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c
SRCS += rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c rtl837x_init.c syslog.c
SRCS += uip/timer.c uip/uip.c uip/uip_arp.c uip/uiplib.c uip/uip-fw.c uip/uip-neighbor.c uip/uip-split.c udp_apps.c
SRCS += httpd/httpd.c httpd/page_impl.c
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
DEPS := ${SRCS:%.c=$(BUILDDIR)/%.d}
HTML := $(shell find $(html) -name '*.js' -or -name '*.html' -or -name '*.svg')
html_data.c html_data.h: html tools
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
html_data.c html_data.h: $(HTML) tools/output/fileadder
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
$(VERSION_HEADER):
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
@echo "#define VERSION_H" >> $(VERSION_HEADER)
@echo "#define VERSION_SW \"v$(VERSION)-g$(shell git rev-parse --short HEAD)\"" >> $(VERSION_HEADER)
@echo "#define VERSION_SW \"$(VERSION_EXTENSION)\"" >> $(VERSION_HEADER)
@echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
@echo "#endif" >> $(VERSION_HEADER)
@@ -46,37 +61,46 @@ $(SUBDIRS):
$(MAKE) -C $@
clean:
-make -C uip clean
-make -C httpd clean
-rm html_data.c html_data.h $(VERSION_HEADER)
-rm -r $(BUILDDIR)
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
$(BUILDDIR)crtstart.rel: crtstart.asm
$(ASM) $(AFLAGS) -o $@ $<
distclean:
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-rm -rf $(BUILDDIR)
$(BUILDDIR)crc16.rel: crc16.asm
$(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)/%.rel: %.c
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
$(BUILDDIR)/%.rel: %.asm
${ASM} ${AFLAGS} -o $@ $<
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
$(BUILDDIR)rtlplayground.ihx: $(OBJS) $(BUILDDIR)crtstart.rel $(BUILDDIR)crc16.rel
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
objcopy --input-target=ihex -O binary $< $@
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img
if [ -e $@ ]; then rm $@; fi
tools/$(BUILDDIR)imagebuilder -i $^ $@
tools/$(BUILDDIR)fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
tools/$(BUILDDIR)crc_calculator -u $@
tools/output/imagebuilder -i $^ $@
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data -b BANK1 $@
tools/output/crc_calculator -u $@
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
.PHONY: clean all $(SUBDIRS)
.PHONY:
machine_check:
@mkdir -p $(BUILDDIR)/tmp
@set -eo pipefail; \
for MACHINE in `grep -e ' MACHINE_' machine.c | sed -e 's%^.* MACHINE_%%' -e 's%[ ]*//.*$$%%' | sort -u`; \
do \
echo "Checking $${MACHINE}"; \
$(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine.c; \
done
@rm -rf $(BUILDDIR)/tmp
-include $(DEPS)
+133 -54
View File
@@ -52,88 +52,145 @@ devices by looking at the image using e.g. Ghidra. If you want to contribute to
design of the web-interface or get a feeling for the interface first, a standalone
device simulator is provided, which runs entirely under Linux as a local webserver.
## Compiling
## (0) Compiling Requirements
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
```
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev
```
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
> [!TIP]
> You can write configuration parameters in config.txt (see below) in order your switch to get
> straight at the first boot, a correct IP configuration.
Now, building the firmware image should work:
```
make
```
Note, that the image generated ends in .bin, not .img, in order to make
IMSProg happy.
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy.
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
for example
```
rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
```
> [!CAUTION]
> This image can be flashed directly to the chip OR through the firmware update/upgrade
> interface of RTLPlaygound interface
## (2) Compiling for OEM running device with management options (web upgrade)
Managed switches can be updated from the existing original firmware using a SPECIFIC upgrade image.
You first need to build the firmware for direct chip flashing : See below (1)
Then
```
cd installer
make
```
image location is stored in `RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin`
> [!CAUTION]
> This image must ONLY be used for original OEM firmware web interface firmware upgrade.
> You do not need this image if you are already on RTLplayground firmware.
> Unless you go back to the original OEM firmware, you would only flash this specific firmware
> only once. Future upgrades of RTLPlayground will only need to follow (1)
example of compilation console output
Managed switches can be updated from the existing original firmware using an upgrade image.
In the `installer`folder of the source code you will need to run `make` which will build
an image out of `rtlplayground.bin` built in the previous step:
```
RTLPlayground/installer$ make
mkdir -p output/
mkdir -p output
gcc updatebuilder.c -o output/updatebuilder
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
cp ../output//rtlplayground.bin output/
./output//updatebuilder -i output/rtlinstaller.ihx output/rtlplayground.bin
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin
Input file size: 524288
Bytes read: 524288
EOF
Payload sum 1 is: 0x29d10
Payload sum 2 is: 0x29d10
Payload sum with header is: 0x2b0fc
Payload sum is: 0xad8a75
Header checksum is: 0x4c3
Payload sum 1 is: 0x25100
Payload sum 2 is: 0x25100
Payload sum with header is: 0x264ec
Payload sum is: 0xf8fe94
Header checksum is: 0x5a1
```
The resulting image can be found in `RTLPlayground/installer/output/rtlplayground.bin`
> [!CAUTION]
> DO NOT UPLOAD THE UPGADE IMAGE UNLESS YOU CAN MAKE A BACKUP USING A SOIC CLAMP OF THE
> ORIGINAL FIRMWARE!
## Installation
## (3) Sandbox Usage with Ghidra (optional)
You can play with the image using ghidra or flash real Switch Hardware. For
ghidra see this information about [Ghidra images](ghidra.md).
## (4) Installation through the Web interface (software way)
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
Unmanaged switch cannot be flashed this way (see 5).
Go to "Firmware update" tab, select the correct file.
> [!IMPORTANT]
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
> [!CAUTION]
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
> ABSOLUTELY NO GUARANTY CAN BE GIVEN THAT YOU WILL NOT DESTROY YOUR SWITCH,
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
> Check one more time that your device matches the machine type before flashing.
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
You can upload the upgrade image of managed switches via the web interface of the
original firmware just as if you were installing a firmware upgrade. However,
this is strongly discouraged, as you may brick your device, unless you can make
firmware backups via a SOIC clamp or soldered flash socket, first!
Finally, push the Upload File Button and you're done !
For unmanaged devices, the only way to install RTLPlayground is by flashing the
Flash memory directly.
You will need to open your switch to flash the image directly onto the flash chip,
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
flash chip and install a SOIC adapter):
- Disconnect power from switch
- Attach the clip onto the flash chip
- Connect USB of flash programmer, the power LED on the switch will light
up, check cabling if not. Don't panic, mixing up GND and 3.3V does not
seem to destroy the switch (at leasts the on I did this to).
- Use IMSProg (flashrom should work, too) to detect the clip
- MAKE A BACKUP OF THE EXISTING FIRMWARE!
- then load the firmware into IMSProg
- and program flash
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
Now you can connect a serial cable to the UART port found on all the
devices, set 8N1 @ 115200 baud and power up the switch.
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
This is also the only way to unbrick your device if something went wroong.
The device will perform some examples and provide a minimal console, the
documentation of which can be found in the source code rtlplayground.c`.
> [!IMPORTANT]
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
> Alternatively you can de-solder the flash chip and install a SOIC adapter).
> For flashing the chip directly, you must use the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
## The web-interface
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247).
The default password is `1234`.
> [!CAUTION]
> As you need to open your switch case, consider that the warranty is gone.
- Disconnect power from switch.
- Open the switch.
- Attach the clip onto the flash chip (Red line on Pin 1, Pin 1 has a point marker).
- Connect USB of flash programmer, the power LED on the switch will light up, check cabling if not.
- Don't panic, mixing up GND and 3.3V usually does not destroy the switch.
- Use IMSProg, Flashrom, or whatever Programmer to detect the chip.
- MAKE A BACKUP (DUMP) OF THE EXISTING FIRMWARE !
- ERASE THE ROM (BLANK) !
- Load the firmware into IMSProg.
- Flash is to the ROM chip.
- Disconect the clip from the ROM chip.
- You're done, ready for the first boot.
## (6) Connecting a serial interface (optional)
You can connect a serial cable to the UART port found on all the devices, set 8N1 @ 115200 baud.
## (7) Power Up
When you power up the switch, the device will perform some examples and provide a minimal console
(if wired to a serial interface), the documentation of which can be found in the source code rtlplayground.c`.
## (8) The web-interface
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
specified an IP adress in the config.txt before compilation.
> [!TIP]
> The default password is `1234`.
## (9) The command line
## The command line
The command line is very rudimentary and mostly for testing purposes.
The following is a boot-log with some examples:
```
@@ -198,7 +255,6 @@ PORT 04 1G
<MODULE INSERTED> Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000
> stat
CMD: stat
Port State Link TxGood TxBad RxGood RxBad
@@ -216,17 +272,40 @@ Lightron Inc. WSPXG-ES3LC-IHA 0000
CMD: sfp
Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000
```
## (10) Advanced configuration
You can configure more deeply the switch without the need of the console mode.
While in compilation part, you might write directly to config.txt file before making the binary firmware
```
nano config.txt
```
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
```
ip xxx.xxx.xxx.xxx = IP adress of the switch
gw yyy.yyy.yyy.yyy = IP adress of the gateway
netmask zzz.zzz.zzz.zzz = Network mask of the switch
port x name xxx = Name xxx the port number x
port z 1g = Set 1g speed for port z
igmp on/off = Turn IGMP on or off
```
[To be continue]
Enjoy playing!
## Other documents
The following documents give further documentation on specific features of
the RTL837x SoCs:
## (11) Other documents
The following documents give further documentation on specific features of the RTL837x SoCs:
- [RTL8372/3 Feature support](doc/hardware.md)
- [CPU Port](doc/CpuPort.md)
- [L2 learning](doc/l2.md)
- [CPU Port](doc/CpuPort.md)
- [IGMP (IP-MC streaming)](doc/igmp.md)
- [SFP+ ports](doc/sfp.md)
- [Trunking aka. port aggregation](doc/trunking.md)
+2 -2
View File
@@ -169,7 +169,7 @@ void cmd_edit(void) __banked
} else { // An unknown or not yet complete Escape sequence: wait
continue;
}
} else if (sbuf[l] == 127) { // Backspace
} else if (sbuf[l] == 127 || sbuf[l] == 8) { // Backspace DEL or BS/^H
if (cursor > 0) {
write_char('\010');
for (uint8_t i = cursor; i < cmd_line_len; i++)
@@ -197,7 +197,7 @@ void cmd_edit(void) __banked
if (cmd_line_len)
cmd_available = 1;
else
print_string("\n> ");
print_cmd_prompt();
cursor = 0;
cmd_line_len = 0;
history_editptr = 0xffff;
+788 -180
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -7,10 +7,13 @@
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
extern __xdata uint8_t cmd_available;
extern __xdata uint8_t err_status;
uint8_t cmd_tokenize(void) __banked;
void cmd_tokenize(void) __banked;
void cmd_parser(void) __banked;
void execute_config(void) __banked;
void execute_commands(__xdata uint8_t *p) __banked;
void print_sw_version(void) __banked;
void clear_command_history(void) __banked;
#endif
+5 -8
View File
@@ -71,18 +71,13 @@ struct dhcp_pkt {
uint8_t cookie[4];
};
/*
#define DHCP_P ((__xdata struct dhcp_pkt *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE])
#define DHCP_OPT ((__xdata uint8_t *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE + sizeof (struct dhcp_pkt)])
*/
#define DHCP_P ((__xdata struct dhcp_pkt *)uip_appdata)
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
__xdata uint32_t long_value;
void dhcp_print_ip(uint8_t *a)
void dhcp_print_ip(__xdata uint8_t *a)
{
itoa(a[0]); write_char('.');
itoa(a[1]); write_char('.');
@@ -216,7 +211,7 @@ void dhcp_send_request(void)
}
void ip_opt(uint8_t * __xdata ip)
void ip_opt(__xdata uint8_t * ip)
{
dhcp_state.opt_ptr++;
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
@@ -353,8 +348,10 @@ void dhcp_stop(void) __banked
}
void dhcp_callback(void) __banked
void dhcp_callback(uint16_t lport) __banked
{
if (lport != HTONS(DHCPC_CLIENT_PORT)) // Is this call for us? If not, ignore it
return;
if (!dhcp_state.state)
return;
if (uip_closed()) {
+2 -7
View File
@@ -16,7 +16,7 @@
void dhcp_start(void) __banked;
void dhcp_stop(void) __banked;
// void dhcp_periodic(void) __banked;
void dhcp_callback(void) __banked;
void dhcp_callback(uint16_t lport) __banked;
struct dhcp_state {
@@ -35,14 +35,9 @@ struct dhcp_state {
uint32_t rebind;
uint32_t renewal;
struct uip_udp_conn *conn;
__xdata struct uip_udp_conn *conn;
};
typedef struct dhcp_state uip_udp_appstate_t;
/* Finally we define the application function to be called by uIP. */
#ifndef UIP_UDP_APPCALL
#define UIP_UDP_APPCALL dhcp_callback
#endif /* UIP_APPCALL */
#endif
+32
View File
@@ -0,0 +1,32 @@
# Automation
## Upload
You can automate upload of the firmware via WEB with curl:
1. Authorize with /login endpoint and save cookie:
```bash
curl -c cookies.txt http://${SWITCH_IP}/login -d pwd=${PASSWORD} -i
```
This will save session cookie in cookies.txt
2. Send the firmware via form:
```bash
curl -b cookies.txt http://${SWITCH_IP}/upload -F "uploadedfile=@${FIRMWARE_FILE_PATH}" -i
```
You can expect that server will close connection, without responding to request.
Wait for SWITCH_IP to be responding again.
## Port status
In similar way to upload, you can fetch the json status of the ports.
1. Get the session cookie as for upload.
2. Hit the `/status.json` with cookie:
```bash
curl -b cookies.txt http://${SWITCH_IP}/status.json
```
+177
View File
@@ -0,0 +1,177 @@
### 2M-PCB23-V2.2
## Brands
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|----------|-----------------|---------|---------------|-------|-------------|
| keepLINK | KP-9000-9XHML-X | Yes | 2M-PCB23-V2.2 | 2M | 8373 + 8224 |
## PCB
<img src="photos/2M-PCB23-V2.2-managed/2M-PCB23-V2.2-top.jpg" width="300" />
## Port overview
```
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP(J13) │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 9 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ PORT 6 │ │ PORT 7 │ │ PORT 8 │ │ MAC 8 │ O (PWR) │
│ O │ MAC 0 │ │ MAC 1 │ │ MAC 2 │ │ MAC 3 │ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 1 │ O (SFP) │
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
# Connectors
### J13, SFP connector
| SFP Pin | Signal | GPIO | Notes |
| ------- | ----------------- | ------ | ------------------------------ |
| 2 | TX_FAULT | ?? | |
| 3 | TX_DISABLE | ?? | |
| 4 | MODDEF2 SDA | GPIO39 | |
| 5 | MODDEF1 SCL | GPIO40 | |
| 6 | MODDEF0 PRESENT | GPIO30 | "OE Exist" reported by `fiber` |
| 7 | RATE SEL | ?? | |
| 8 | LOS | GPIO37 | "OE LOS" reported by `fiber` |
| 9 | TO? | ?? | |
### T5, serial console
| pin | GPIO | Signal |
| --- | ------ | -------------- |
| 1 | GPIO32 | U0RXD (Input) |
| 2 | GND | Ground |
| 3 | GPIO31 | U0TXD (Output) |
### S1, unknown connector
| pin | GPIO | Signal |
| --- | -------- | -------------- |
| 1 | ??? | |
| x | | |
| 3 | ??? | |
| 4 | ??? | |
| 5 | ??? | |
Potentially slave interface or SMI.
### U7, flash memory
Flash chip is FM25Q16A.
### Reset button
GPIO54
## Register values
As probed with `regget` on stock firmware "V1.6".
### Model
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| MODEL_NAME_INFO | 0x0004 | 0x83730000 |
| CHIP_MODE_INFO | 0x0008 | 0x00008000 |
| CHIP_INFO | 0x000C | 0x00300000 |
### GPIO
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| GPIO_OUT0 | 0x003c | 0x10000000 |
| GPIO_OUT1 | 0x0040 | 0x00000010 |
| GPIO_OE0 | 0x004c | 0x10000000 |
| GPIO_OE1 | 0x0050 | 0x00000010 |
| BOND_INFO | 0x7f60 | 0x00000fff |
| STRAP_INFO | 0x7f64 | 0x0002f515 |
| IO_DRVING_0 | 0x7f68 | 0x00000000 |
| IO_DRVING_1 | 0x7f6c | 0x00000000 |
| IO_DRVING_2 | 0x7f70 | 0x00000000 |
| IO_SLEW_0 | 0x7f74 | 0x00000000 |
| IO_SLEW_1 | 0x7f78 | 0x00000000 |
| IO_SLEW_2 | 0x7f7c | 0x00000000 |
| IO_SMT_EN_0 | 0x7f80 | 0xffffffff |
| IO_SMT_EN_1 | 0x7f84 | 0xffffffff |
| IO_SMT_EN_2 | 0x7f88 | 0x0003ffff |
| IO_MUX_SEL_0 | 0x7f8c | 0x28000000 |
| IO_MUX_SEL_1 | 0x7f90 | 0x40000041 |
| IO_MUX_SEL_2 | 0x7f94 | 0x00000000 |
### LED
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| LED_GLB_CTRL | 0x6520 | 0x0023e0f0 |
| LED3_0_SET3_2_CTRL1 | 0x6524 | 0xff001400 |
| LED3_0_SET1_0_CTRL1 | 0x6528 | 0x000f0000 |
| LED3_2_SET3_CTRL0 | 0x652c | 0x007f013f |
| LED1_0_SET3_CTRL0 | 0x6530 | 0x02000400 |
| LED3_2_SET2_CTRL0 | 0x6534 | 0x01400141 |
| LED1_0_SET2_CTRL0 | 0x6538 | 0x01440170 |
| LED3_2_SET1_CTRL0 | 0x653c | 0x18000041 |
| LED1_0_SET1_CTRL0 | 0x6540 | 0x0044017f |
| LED3_2_SET0_CTRL0 | 0x6544 | 0x00000044 |
| LED1_0_SET0_CTRL0 | 0x6548 | 0x00410175 |
| LED_PORT_SET_SEL_CTRL | 0x654c | 0x00010000 |
| SW_LED_LOAD | 0x6550 | 0x00000000 |
| LED_PORT_SW_EN_CTRL[0..7] | 0x6554 | 0x00000000 |
| LED_PORT_SW_EN_CTRL[8] | 0x6558 | 0x00000000 |
| LED_PORT_SW_CTRL[0] | 0x655c | 0x00000000 |
| LED_PORT_SW_CTRL[1] | 0x6560 | 0x00000000 |
| LED_PORT_SW_CTRL[2] | 0x6564 | 0x00000000 |
| LED_PORT_SW_CTRL[3] | 0x6568 | 0x00000000 |
| LED_PORT_SW_CTRL[4] | 0x656c | 0x00000000 |
| LED_PORT_SW_CTRL[5] | 0x6570 | 0x00000000 |
| LED_PORT_SW_CTRL[6] | 0x6574 | 0x00000000 |
| LED_PORT_SW_CTRL[7] | 0x6578 | 0x00000000 |
| LED_PORT_SW_CTRL[8] | 0x657c | 0x00000000 |
| LED_LOAD_LV1_10G | 0x6580 | 0x000fa000 |
| LED_LOAD_LV2_10G | 0x6584 | 0x00271000 |
| LED_LOAD_LV3_10G | 0x6588 | 0x004e2000 |
| LED_LOAD_LV1_5G | 0x658c | 0x000fa000 |
| LED_LOAD_LV2_5G | 0x6590 | 0x00271000 |
| LED_LOAD_LV3_5G | 0x6594 | 0x004e2000 |
| LED_LOAD_LV1_2P5G | 0x6598 | 0x000fa000 |
| LED_LOAD_LV2_2P5G | 0x659c | 0x00271000 |
| LED_LOAD_LV3_2P5G | 0x65a0 | 0x004e2000 |
| LED_LOAD_LV1_1G | 0x65a4 | 0x000fa000 |
| LED_LOAD_LV2_1G | 0x65a8 | 0x00271000 |
| LED_LOAD_LV3_1G | 0x65ac | 0x004e2000 |
| LED_LOAD_LV1_500M | 0x65b0 | 0x0007d000 |
| LED_LOAD_LV2_500M | 0x65b4 | 0x00138800 |
| LED_LOAD_LV3_500M | 0x65b8 | 0x00271000 |
| LED_LOAD_LV1_100M | 0x65bc | 0x00019000 |
| LED_LOAD_LV2_100M | 0x65c0 | 0x0003e800 |
| LED_LOAD_LV3_100M | 0x65c4 | 0x0007d000 |
| LED_LOAD_LV1_10M | 0x65c8 | 0x00002800 |
| LED_LOAD_LV2_10M | 0x65cc | 0x00006400 |
| LED_LOAD_LV3_10M | 0x65d0 | 0x0000c800 |
| LED_P_LOAD_CTRL | 0x65d4 | 0x00000000 |
| LED_GLB_ACTIVE | 0x65d8 | 0x3ffbedff |
| LED_GLB_IO_EN | 0x65dc | 0x77ffffff |
| LED_GLB_MUX_1 | 0c65e0 | 0x05102040 |
| LED_GLB_MUX_2 | 0x65e4 | 0x0c289206 |
| LED_GLB_MUX_3 | 0x65e8 | 0x1245038d |
| LED_GLB_MUX_4 | 0x65ec | 0x19616554 |
| LED_GLB_MUX_5 | 0x65f0 | 0x2079d71a |
| LED_GLB_MUX_6 | 0x65f4 | 0x000238a1 |
| LED_RLDP_CTRL_1 | 0x65f8 | 0x00000019 |
| LED_RLDP_CTRL_2 | 0x65fc | 0xffffffff |
| LED_RLDP_CTRL_3 | 0x6600 | 0x00006600 |
| LED_DUMY_0_ADDR | 0x6604 | 0x00000000 |
| LED_DUMY_1_ADDR | 0x6608 | 0x00000000 |
# LEDs
| Name | Components | Controlled by |
| ----------------------------- | --------------------------- | -------------------------- |
| RJ45 Right Green ("LINK/ACT") | | RJ45 LED0 |
| RJ45 Left Orange ("2.5G") | | RJ45 LED1 |
| RJ45 Left Green ("1G") | | RJ45 LED2 |
| "P" (PWR) | Top LED in "LED6" stack | probably pulled from Vcc |
| SFP Link ("9") | Bottom LED in "LED6" stack | SFP LED0 |
| ?? | D23 | SFP LED1 |
| ?? | D22 | SFP LED2 |
+93
View File
@@ -0,0 +1,93 @@
# FOXNEO FNS-1200P
RTL8372-based 4×2.5G PoE+ + 2×SFP+ unmanaged switch.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Manufacturer**: FOXNEO
- **Model**: FNS-1200P
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps with PoE+
- 2 × SFP+: 1G / 2.5G / 10G
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE+ is not configurable via RTLPlayground)
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
- LEDs: amber (2.5G) and green (1G/100M/10M) per copper port; combined link/act on SFP ports
### PCB overview
**Board markings**
- Top silkscreen: PCB-K0402W-U13-V2.0 / DIP-K0402WB-V2.0
**Key components**
- U3: SPI NOR flash, 2 MiB
- U7: unpopulated SOP8 footprint — I2C bus (RTL8372 slave at 0x5c) is accessible from its pads, useful for register dumps
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
Front panel
<img src="photos/FNS-1200P/chassis-front.jpg" width="400" />
Top side (PCB)
<img src="photos/FNS-1200P/PCB-top.jpg" width="300" />
### Port layout
| Front panel position | Logical port | Physical port | Type |
|----------------------|--------------|---------------|---------|
| SFP left | 8 | 5 | SFP+ |
| RJ45 1 | 4 | 1 | Copper |
| RJ45 2 | 5 | 2 | Copper |
| RJ45 3 | 6 | 3 | Copper |
| RJ45 4 | 7 | 4 | Copper |
| SFP right | 3 | 6 | SFP+ |
### Serial console
The PCB has three unpopulated through-holes intended for a slide switch, directly connected to UART0.
Numbered from the left (SFP port side), the pinout is:
| Position (left→right) | Signal | GPIO |
|-----------------------|--------|--------------------------|
| 1 (leftmost) | RX | GPIO32\_UART0\_RX (32) |
| 2 (middle) | GND | GND |
| 3 (rightmost) | TX | GPIO31\_UART0\_TX (31) |
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
- Connect a USB-TTL adapter: adapter TX → pin 1, GND → pin 2, adapter RX → pin 3
### LED configuration
Copper ports use LED SET0, SFP ports use LED SET1.
| SET | LED0 | LED2 |
|------|--------------------------------------------------|---------------------------------------------------|
| SET0 | Amber — lights on 2.5G link | Green — lights on 1G / 100M / 10M link |
| SET1 | All speeds — lights on any link with activity | — |
LED pad to physical port mapping:
| GPIO pads | Port |
|-----------|-------------------------|
| GPIO811 | Physical port 5 (left SFP) |
| GPIO1214 | Physical port 1 (RJ45 1) |
| GPIO1517 | Physical port 2 (RJ45 2) |
| GPIO1820 | Physical port 3 (RJ45 3) |
| GPIO2123 | Physical port 4 (RJ45 4) |
| GPIO2427 | Physical port 6 (right SFP) |
### SFP GPIO assignments
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|------------------|-----------------------------|------------------------|--------|----------------------|--------------------------|
| Left (logical 8) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
| Right (logical 3)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO51\_I2C\_SDA2\_UART1\_RX | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
GPIO assignments were verified by observing GPIO state changes during SFP module insertion/removal
and cross-checked against an original firmware register dump.
`pin_tx_disable` is GPIO\_NA on both ports (original firmware keeps all GPIOs as inputs).
-62
View File
@@ -1,62 +0,0 @@
# Hisource Hi-K0402WS
Following is documentation for unmanaged switch marked as `Hi-K0402WS`.
Original software is running UART on 9600 baud rate.
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0402WS
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/K0402W-V3.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0402W-V3.0-unmanaged\PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
+36
View File
@@ -0,0 +1,36 @@
# Hisource Hi-K0801WS
Following is documentation for unmanaged switch marked as `Hi-K0801WS`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0801WS
- **Ports**:
- 8 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO801W-V2.0 / DIP-KO801WS-V2.0
Top side
<img src="photos/K0801W-V2.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0801W-V2.0-unmanaged\PCB-bottom.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+23
View File
@@ -0,0 +1,23 @@
# K0501W V2.0
This board appears for example in the Davuaz Da-K6501W switch.
The general design of the board is similar to Hi-K0402WS V3.0.
However, there are several differences:
- One SFP port is replaced by a RTL8221B 2.5G PHY
- Only one LED is populated for the SFP port
- No mode switch and only one flash chip
- Older design using RTL8372 instead of RTL8372N (which also means different GPIO and LED configuration)
- Like earlier versions of the K0402W(S) board, there is no UART
All ports and LEDs are supported.
Installation is possible using a flash programmer.
The BoyaMicro 25Q16BSSIG flash chip is supported by flashprog with chip name "B.25D16AS/BY25Q16BS/BY25Q16ES".
## PCB pictures
The board is marked `PCB-K0501W-V2.0 DIP-K0501WS-V2.0`.
<img src="photos/K0501W_V2_0/pcb-top.jpg" width="300" />
<img src="photos/K0501W_V2_0/pcb-bottom.jpg" width="300" />
+57
View File
@@ -0,0 +1,57 @@
# Keeplink KP-9000-6XH-X2
Following is documentation for unmanaged switch marked as `KP-9000-6XH-X2`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port
- **Model**: KP-9000-6XH-X2
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port with 10G modules
- LEDs
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview
Front side:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-front.jpg" width="600" />
Label:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-label.jpg" width="600" />
### PCB overview
**Board markings**
- Top silkscreen: 2M-PCB43-V2.1
Top side
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-top.jpg" width="600" />
Bottom
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-bottom.jpg" width="600" />
## Reset Button
There's an unpopulated Reset button on the front left side of the PCB.
It can easily be soldered, you'll need an 4.5mmx4.5mm 90° button switch with a 3-pin footprint.
I got mine here: https://de.aliexpress.com/item/1005007295346702.html
The front case has already the hole in the metal case, you just have to punch a hole through the foil.
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+76
View File
@@ -0,0 +1,76 @@
# PCB-K0402WS-V3.0
Following is documentation for a variety of unmanaged switch internally marked as `PCB-K0402WS-V3.0`. They are sold under many brands.
Original software is running UART on 9600 baud rate.
Note during opening the device: there might be a hidden 5th screw on the back
of the device just above the big label, might be covered by a QC sticker.
### Brands
* Hisource Hi-K0402WS
<img src="photos/PCB-K0402WS-V3.0/HiSource_HI-K0402WS.jpg" width="300" />
* Ztyuav Z-QWYT0402
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402.jpg" width="300" />
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
### Programming
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
The switch actually controls the HOLD line of each flash chip, and toggling the switch results in a reboot.
If the programming clip keeps HOLD not connected, the flashing will commence on whatever the switch selected, regardless on which chip was clipped.
For the initial flash (at least with flashrom), the bin file produced by the build is much smaller than the flash chip, it is suggested to pad the file to keep flashrom happy: `truncate -s 2097152 rtlplayground-*-PCB_K0402WS_V3.bin`. Note: do not then proceed to use this resulting padded file for the web flashing (as it bricks the device), use the original unpadded .bin.
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/PCB-K0402WS-V3.0/PCB-top.jpg" width="300" />
Bottom
<img src="photos/PCB-K0402WS-V3.0/PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
+164
View File
@@ -0,0 +1,164 @@
### ZX-SWTGW215AS
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Lianguo | ZX-SWTGW215AS | Yes | PCB-SWTG115AS-V2.0 | FM25Q16A | 8272 |
## RTLPlayground target
Use machine target `MACHINE_LIANGUO_ZX_SWTGW215AS` for this device.
Physical hardware verification: 5x RJ45 ports + 1x SFP port.
Port 5 RJ45 is interfaced through a RTL8221B IC.
## PCB
<img src="photos/ZX-SWTGW215AS/pcb_top.jpg" width="300" />
# Connectors
## Port overview
```
┌──────────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP (J4) │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 6 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ LOG 8 │ │
│ O │ LOG 4 │ │ LOG 5 │ │ LOG 6 │ │ LOG 7 │ │ LOG 3 │ │ SerDes 1 │ │
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
```
| Type | RTLPlayground logical ports | Physical index |
|---|---|---|
| RJ45 | 3, 4, 5, 6, 7 | 1-5 |
| SFP | 8 | 6 |
## J4
* Location: SFP connector `J4`.
* Connected to: 10GMAC number 8, SerDes 1.
|`J4` SFP PINs | Signal | GPIO | Notes |
|---|---|---|---|
|3| TX_DISABLE | GPIO_NA | Not connected |
|4| MODDEF2 SDA | GPIO39 | I2C SDA |
|5| MODDEF1 SCL | GPIO40 | I2C SCL |
|6| MODDEF0 PRESENT | GPIO30 | Detect |
|8| LOS | GPIO37 | RX Loss of Signal |
### Notes
* Not all signals were mapped mechanically, hence they've been left out of documentation.
## T3, Slave Interface
This connector goes to U4 `I2C EEPROM` and U10 `SPI FLASH` (mappings identical to SWTG024AS).
For detailed Slave Interface functionality and protocol information, see [T3 documentation in SWTG024AS.md](SWTG024AS.md#t3-slave-interface).
|`T3` pin|what|Signal|
|---|---|---|
|1| U4-P6, 33R U10-P6 | I2C-SCL, SPI-CLK, Slave SCK/SCL/MDC/EE_SCL |
|2| GND | --- |
|3| U4-P5, U10-P5 | I2C-SDA, SPI-DI/DO, Slave SDI/SDA/MDIO/EE_SDA |
|4| VCC |
|5| 33R -> U10-P2 | SPI-DO/D1 |
|6| U10-P1 | SPI-CS |
### Notes
* 1 pin is square shaped.
## T5, Serial Console
|`T5` pin|GPIO|Signal|
|---|---|---|
| 1 | GPIO31 | U0TXD (Output) |
| 2 | GND | |
| 3 | GPIO32 | U0RXD (Input) |
| 4 | 3V3 | |
### Notes
* 1 pin is square shaped.
## T8
|`T8` pin|GPIO|Signal|
|---|---|---|
| 1 | GPIO46 | |
| 2 | GND | |
| 3 | GPIO48 | |
| 4 | 3V3 | |
| 5 | GPIO47 | |
| 6 | GPIO49 | |
### Notes
* 1 pin is square shaped.
* Mapping unverified but assumed the same as [LIANGUO SWTG024AS](SWTG024AS.md#t8).
# Reset Circuit
| Function | GPIO |
|---|---|
| Reset button | GPIO54 |
### Notes
* Circuit is active-low
# GPIO
Note: T3/U4/U10-related signal annotations below are copied from [LIANGUO SWTG024AS T3 section](SWTG024AS.md#t3-slave-interface) as well as T8 port from [LIANGUO SWTG024AS T8 section](SWTG024AS.md#t8). They should be treated as assumed identical for ZX-SWTGW215AS as it has not been 100% confirmed true at the moment.
| HEX VAL. | GPIO | Component / Purpose | Notes | | GPIO | Component / Purpose | Notes |
| -------- | ------ | ---- | ---- | ---- | ---- | ---- | ---- |
| 00000001 | GPIO00 | | | | GPIO32 | T5-3 | U0RXD |
| 00000002 | GPIO01 | | | | GPIO33 | | |
| 00000004 | GPIO02 | | | | GPIO34 | | |
| 00000008 | GPIO03 | | | | GPIO35 | | |
| 00000010 | GPIO04 | | | | GPIO36 | | |
| 00000020 | GPIO05 | | | | GPIO37 | J4-8 | SFP LOS |
| 00000040 | GPIO06 | | | | GPIO38 | | |
| 00000080 | GPIO07 | | | | GPIO39 | J4-4 | SFP I2C SDA |
| 00000100 | GPIO08 | | | | GPIO40 | J4-5 | SFP I2C SCL |
| 00000200 | GPIO09 | | | | GPIO41 | | |
| 00000400 | GPIO10 | | | | GPIO42 | U10-P6, U4-P6, T3-1 | SPI FLASH CLK / I2C-SCL (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00000800 | GPIO11 | | | | GPIO43 | U10-P5, U4-P5, T3-3 | SPI FLASH DI/IO0 / I2C-SDA (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00001000 | GPIO12 | | | | GPIO44 | U10-P2, T3-5 | SPI FLASH DO/IO1 (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00002000 | GPIO13 | PORT1 LED GREEN | | | GPIO45 | U10-P1, T3-6 | SPI FLASH CS (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00004000 | GPIO14 | PORT1 LED ORANGE | | | GPIO46 | T8-1 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00008000 | GPIO15 | | | | GPIO47 | T8-5 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00010000 | GPIO16 | PORT2 LED GREEN | | | GPIO48 | T8-3 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00020000 | GPIO17 | PORT2 LED ORANGE | | | GPIO49 | T8-6 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00040000 | GPIO18 | PORT3 LED GREEN | | | GPIO50 | | |
| 00080000 | GPIO19 | PORT3 LED ORANGE | | | GPIO51 | | |
| 00100000 | GPIO20 | PORT4 LED GREEN | | | GPIO52 | | |
| 00200000 | GPIO21 | PORT4 LED ORANGE | | | GPIO53 | | |
| 00400000 | GPIO22 | PORT5 LED GREEN | | | GPIO54 | Reset Button | GPIO54_ACL_BIT2_EN |
| 00800000 | GPIO23 | PORT5 LED ORANGE | | | GPIO55 | | |
| 01000000 | GPIO24 | SFP LED GREEN | J4 | | GPIO56 | | |
| 02000000 | GPIO25 | | | | GPIO57 | | |
| 04000000 | GPIO26 | | | | GPIO58 | | |
| 08000000 | GPIO27 | | | | GPIO59 | | |
| 10000000 | GPIO28 | LED-SYSTEM | | | GPIO60 | | |
| 20000000 | GPIO29 | | | | GPIO61 | | |
| 40000000 | GPIO30 | J4-6 | SFP DETECT | | GPIO62 | | |
| 80000000 | GPIO31 | T5-1 | U0TXD | | GPIO63 | | |
# LEDs
| NAME | GPIO | Port(s) | Function | Notes |
| ---- | ---- | ---- | ---- | ---- |
| PORT1 LED GREEN | GPIO13 |5| Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT1 LED ORANGE | GPIO14 | 5 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT2 LED GREEN | GPIO16 | 4 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT2 LED ORANGE | GPIO17 | 4 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT3 LED GREEN | GPIO18 | 3 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT3 LED ORANGE | GPIO19 | 3 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT4 LED GREEN | GPIO20 | 2 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT4 LED ORANGE | GPIO21 | 2 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT5 LED GREEN | GPIO22 | 1 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT5 LED ORANGE | GPIO23 | 1 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| SFP LED GREEN | GPIO24 | 6 (SFP J4) | Multi-speed | LEDS_10G, LEDS_5G, LEDS_2G5, LEDS_1G, LEDS_100M, LEDS_LINK, LEDS_ACT |
| LED-SYSTEM | GPIO28 | --- | System status | --- |
## Notes
While [SWTG024AS.md](SWTG024AS.md) can be used as a general reference for hardware concepts and interface specifications, this device should not be assumed to be identical beside the difference implicitely highlighted below. Not all information has been validated for compatibility with the SWTG215AS. Consult the SWTG024AS documentation with caution and verify any critical details against this device's.
+12 -13
View File
@@ -14,10 +14,11 @@ The memory chip is `Winbond W25Q16JV` with 16M-bit size.
1. 2.5G ports on all advertised speeds.
2. SFP+ communication.
3. Serial, Web UI.
4. All LEDs
## Known issues
1. LEDs are not initialized properly.
None.
## PCB
@@ -38,10 +39,10 @@ Bottom
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP │ │ SFP │ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP 2 │ │ SFP 1 │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC ? │ │ MAC ? │ │
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes ? │ │ SerDes ? │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC 8 │ │ MAC 3 │ │
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 0 │ │ SerDes 1 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```
@@ -105,9 +106,9 @@ GPIO mapping unknown.
| 00000002 | GPIO01 | | GPIO33 | |
| 00000004 | GPIO02 | | GPIO34 | Random changes |
| 00000008 | GPIO03 | | GPIO35 | |
| 00000010 | GPIO04 | | GPIO36 | SFP1 Present |
| 00000020 | GPIO05 | | GPIO37 | SFP1 RX Los |
| 00000040 | GPIO06 | | GPIO38 | SFP2 Present |
| 00000010 | GPIO04 | | GPIO36 | SFP2 Present |
| 00000020 | GPIO05 | | GPIO37 | SFP2 RX Los |
| 00000040 | GPIO06 | | GPIO38 | SFP1 Present |
| 00000080 | GPIO07 | | GPIO39 | |
| 00000100 | GPIO08 | | GPIO40 | |
| 00000200 | GPIO09 | | GPIO41 | |
@@ -119,11 +120,11 @@ GPIO mapping unknown.
| 00008000 | GPIO15 | PORT2 Link | GPIO47 | SFP1 I2C SDA |
| 00010000 | GPIO16 | PORT2-LED-GREEN | GPIO48 | SFP2 I2C CLK |
| 00020000 | GPIO17 | PORT2-LED-AMBER | GPIO49 | SFP2 I2C SDA |
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP2 Rx LOS |
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP1 TX Disable |
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP1 Rx LOS |
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP2 TX Disable |
| 00100000 | GPIO20 | PORT4-LED-AMBER | GPIO52 | |
| 00200000 | GPIO21 | PORT4 Link | GPIO53 | |
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP2 TX Disable |
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP1 TX Disable |
| 00800000 | GPIO23 | PORT4-LED-AMBER | GPIO55 | |
| 01000000 | GPIO24 | | GPIO56 | |
| 02000000 | GPIO25 | | GPIO57 | |
@@ -136,8 +137,6 @@ GPIO mapping unknown.
## LEDs
Leds are not yet working as in stock firmware. This will be handled later.
Ports 1-4 are amber for 100M/1G links, Green for 2.5G.
Port 5-6 are green for 10G/1G link. Both should flash on activity.
@@ -166,7 +165,7 @@ Voltage is made by a `APW8713` (U3).
### `3.3` Voltage
Voltage is crated regulated by chip marke as `GoIAT` (U2).
Voltage is crated regulated by chip marked as `GoIAT` (U2).
## SFP SPI
+59
View File
@@ -0,0 +1,59 @@
# ZX310S-4T2XH/
The following is a documentation for the managed switch marked as `ZX310S-4T2XH`
and sold by Horaco.
The original software is running UART on 57600 baud rate. The solder holes
of the UART header are filled in. In order to install a UART header, they
need to be cleared first. A 1.2mm drill can be used, alternatively a
de-soldering wick.
The original firmware uses 57600 baud 8N1
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 1 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XH/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The 10GBit port works. TODO: Fix EEE, speed selection
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T1T1X-V1.0.1-24107
Top side
<img src="photos/ZX310S-4T2XH/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XH/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
+53
View File
@@ -0,0 +1,53 @@
# ZX310S-4T2XT
The following is a documentation for the managed switch marked as
`ZX310S-4T2XT` and sold by Horaco.
The original software is running UART on 57600 baud rate 8N1.
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY 2x RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XT/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps, including EEE
- The 10GBit ports works, including EEE.
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T2XT-V1.0.0-22273
Top side
<img src="photos/ZX310S-4T2XT/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XT/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Before

Width:  |  Height:  |  Size: 521 KiB

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

+98
View File
@@ -0,0 +1,98 @@
# GPIO Pin, Function and MUX registers.
These functions should bevalid for `RTL8372`, `RTL8372N`, `RTL8373`, and `RTL8373N`.
`N`-version doesn't seems to have all the GPIO pins available on the outside of the package.
| GPIO | Function | TYPE | MUX REG, BIT | (RTL8372) PIN# | (RTL8372N) PIN# |
| ----- | ---- | ---- | ---- | ---- | ---- |
| GPIO0 | LED0 | I/OPU | IO_MUX_SEL_0, BIT 0 | G1 | 12 |
| GPIO1 | LED1 | I/OPU | IO_MUX_SEL_0, BIT 1 | G2 | 15 |
| GPIO2 | LED2 | I/OPU | IO_MUX_SEL_0, BIT 2 | G3 | 14 |
| GPIO3 | LED3 | I/OPU | IO_MUX_SEL_0, BIT 3 | H1 | 16 |
| GPIO4 | LED4 | I/OPU | IO_MUX_SEL_0, BIT 4 | H2 | 18 |
| GPIO5 | LED5 | I/OPU | IO_MUX_SEL_0, BIT 5 | H3 | 20 |
| GPIO6 | LED6 | I/OPU | IO_MUX_SEL_0, BIT 6 | J1 | 22 |
| GPIO7 | LED7 | I/OPU | IO_MUX_SEL_0, BIT 7 | J2 | NoPin? |
| GPIO8 | LED8 | I/OPU | IO_MUX_SEL_0, BIT 8 | J3 | 24 |
| GPIO9 | LED9 | I/OPD | IO_MUX_SEL_0, BIT 9 | L1 | 23 |
| GPIO10 | LED10 | I/OPU | IO_MUX_SEL_0, BIT 10 | L2 | 26 |
| GPIO11 | LED11 | I/OPU | IO_MUX_SEL_0, BIT 11 | L3 | NoPin? |
| GPIO12 | LED12 | I/OPD | IO_MUX_SEL_0, BIT 12 | M1 | 28 |
| GPIO13 | LED13 | I/OPU | IO_MUX_SEL_0, BIT 13 | M2 | NoPin? |
| GPIO14 | LED14 | I/OPU | IO_MUX_SEL_0, BIT 14 | M3 | NoPin? |
| GPIO15 | LED15 | I/OPU | IO_MUX_SEL_0, BIT 15 | N1 | 25 |
| GPIO16 | LED16 | I/OPU | IO_MUX_SEL_0, BIT 16 | N2 | NoPin? |
| GPIO17 | LED17 | I/OPU | IO_MUX_SEL_0, BIT 17 | N3 | NoPin? |
| GPIO18 | LED18 | I/OPD | IO_MUX_SEL_0, BIT 18 | P1 | 30 |
| GPIO19 | LED19 | I/OPU | IO_MUX_SEL_0, BIT 19 | P2 | NoPin? |
| GPIO20 | LED20 | I/OPU | IO_MUX_SEL_0, BIT 20 | P3 | NoPin? |
| GPIO21 | LED21 | I/OPU | IO_MUX_SEL_0, BIT 21 | R1 | 27 |
| GPIO22 | LED22 | I/OPU | IO_MUX_SEL_0, BIT 22 | R2 | NoPin? |
| GPIO23 | LED23 | I/OPU | IO_MUX_SEL_0, BIT 23 | R3 | NoPin? |
| GPIO24 | LED24 | I/OPU | IO_MUX_SEL_0, BIT 24 | N19 | 88 |
| GPIO25 | LED25 | I/OPU | IO_MUX_SEL_0, BIT 25 | P19 | 86 |
| GPIO26 | LED26 | I/OPU | IO_MUX_SEL_0, BIT 26 | P18 | 84 |
| GPIO27 | LED27 | I/OPU | IO_MUX_SEL_0, BIT 27 | R19 | 82 |
| GPIO28 | SYS_LED | I/OPU | IO_MUX_SEL_0, BIT 28 | F1 | 13 |
| GPIO29 | GLB_RLDP_LED_EN | | IO_MUX_SEL_0, BIT 29 | | NoPin? |
| GPIO30 | ACL_BIT3_EN | | IO_MUX_SEL_2, BIT 3 | F3 | 11 |
| GPIO31 | UART TX (OUTPUT) | | IO_MUX_SEL_1, BIT 0 | L20 | 90 |
| GPIO32 | UART TX (INPUT) | | IO_MUX_SEL_1, BIT 1 | L21 | |
| GPIO33 | GPIO_INT | | IO_MUX_SEL_1, BIT 2 | | |
| GPIO34 | MDC0 | | IO_MUX_SEL_1, BIT 3 | | |
| GPIO35 | MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
| GPIO36 | PWM_OUT | | IO_MUX_SEL_1, BIT 30 | B13 | |
| GPIO37 | --- | | | L18 | |
| GPIO38 | --- | | | K19 | |
| GPIO39 | MSDA4 | | IO_MUX_SEL_1, BIT 29 | K20 | 95 |
| GPIO40 | MDC1/SCL3 | | IO_MUX_SEL_1, BIT 5 & 6 | J29 | |
| GPIO41 | MDIO1/MSDA3 | | IO_MUX_SEL_1, BIT 5 & 6 | J19 | |
| GPIO42 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D1 | |
| GPIO43 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E1 | |
| GPIO44 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D2 | |
| GPIO45 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E2 | |
| GPIO46 | MSCK0 | | IO_MUX_SEL_1, BIT 7 & 8 | A2 | |
| GPIO47 | MSDA0 | | IO_MUX_SEL_1, BIT 9 & 10 | B2 | |
| GPIO48 | MSCK1 | | IO_MUX_SEL_1, BIT 11 & 12 | A1 | |
| GPIO49 | MSDA1 | | IO_MUX_SEL_1, BIT 13 & 14 | B1 | |
| GPIO50 | MSCL2/U1TXD | | IO_MUX_SEL_1, BIT 15 & 16 | C1 | |
| GPIO51 | MSDA2/U1RXD | | IO_MUX_SEL_1, BIT 17 & 18 | C2 | |
| GPIO52 | ACL_BIT0_EN | | IO_MUX_SEL_2, BIT 0 | | |
| GPIO53 | ACL_BIT1_EN | | IO_MUX_SEL_2, BIT 1 | | |
| GPIO54 | ACL_BIT2_EN | | IO_MUX_SEL_2, BIT 2 | E5 | |
| GPIO55 | PTP_CLK125M_IN | | IO_MUX_SEL_1, BIT 19 | | |
| GPIO56 | PTP_CLK_OUT | | IO_MUX_SEL_1, BIT 20 | | |
| GPIO57 | PTP_TOD_OUT | | IO_MUX_SEL_1, BIT 21 | | |
| GPIO58 | PTP_PPS_OUT | | IO_MUX_SEL_1, BIT 22 | | |
| GPIO59 | PTP_TOD_IN | | IO_MUX_SEL_1, BIT 23 | | |
| GPIO60 | PTP_PPS_IN | | IO_MUX_SEL_1, BIT 24 | | |
| GPIO61 | SYNCELOCK0 | | IO_MUX_SEL_1, BIT 27 | | |
| GPIO62 | SYNCELOCK1 | | IO_MUX_SEL_1, BIT 28 | | |
| GPIO63 | GPIO_MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
## I2C
| I2C | Function |Type | (RTL8372) PIN# | (RTL8372N) PIN# |
| ---- | ---- | ---- | ---- | ---- |
| GPIO47 | SDA0 | I/OPU | | B1 | 142 |
| GPIO49 | SDA1 | I/OPU | | B2 | 144 |
| GPIO51 | SDA2 | I/OPU | | C2 | ??? |
| GPIO41 | SDA3 | I/OPU | | J20 | 98 |
| GPIO39 | SDA4 | I/OPU | | K20 | 95 |
| GPIO46 | SCL0 | I/OPU | | A2 | 138 |
| GPIO48 | SCL1 | I/OPU | | A1 | 140 |
| GPIO50 | SCL2 | I/OPU | | C1 | ??? |
| GPIO40? | SCL3 | OPU | | J20 | |
# Other funcitons
| Function | Type | (RTL8372) PIN# | (RTL8372N) PIN# |
| ---- | ---- | ---- | ---- |
| nRESET | | A6 | 131 |
| PTP_SYNC | | B10 | 130 |
| INT | OPU | B6 | 132 |
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+2
View File
@@ -41,6 +41,8 @@ This list is incomplete.
| Winbond | W25Q32FV |
| Winbond | W25Q32JV |
| Winbond | W25Q16JL |
| Winbond | W25Q16DV |
| Winbond | W25Q80DV |
| Fundan | FM25Q16A |
*NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber.
+1
View File
@@ -9,6 +9,7 @@ The following devices have been tested and are fully working:
- No-Name ZX-SWTGW215AS, managed version of kp-9000-6hx-x, ordered on
AliExpress as keepLINK 5+1 port managed
- TrendNet TEG-S562 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
- FNS-1200P (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide]
(https://github.com/up-n-atom/SWTG118AS)
+34 -7
View File
@@ -33,15 +33,23 @@ An entry is deleted by adding an invalid entry (00 instead of 0x02 in
RTL837x_TBL_DATA_IN_A).
A port is assigned a PVID by setting the PVID-bits of the corresponding
register of the port. 2 ports share a register. One port uses the higher
16 bits, the other (even ports) use the lower. The base register is
register of the port. 2 ports share a register. An odd port uses bits [23:12],
an even port uses bits [11:0]. The base register is
RTL837x_PVID_BASE_REG (0x4e1c) and the registers go to 0x4e2c so that also
the CPU-Port may have a PVID.
Register RTL837x_REG_INGRESS (0x4e10) allows to define the iingress rules of
Register RTL837x_REG_INGRESS (0x4e10) allows to define the ingress rules of
a port. 2 bits define a rule and bits 0-19 are being used. A value of 00
defines no filtering, 01 (0x01) allows only tagged packets, while 10 (0x02)
allows only untagged packets to enter a port. The default PVID is 1.
allows only untagged packets to enter a port.
Register RTL837X_VLAN_PORT_IGR_FLTR (0x4e18) enables or disables ingres VLAN
filtering, each bit corresponds to given port (port0 -> bit0, port9 -> bit9).
When enabled, incomming package's vlan tag is checked against VLAN membership
on given port. When package contains VLAN not in member list, package is dropped.
The default PVID on all port is 1, ingress VLAN filtering is enabled and all types of
frames are accepted on input on all ports.
By default, the ports transmit Ethernet frames with Realtek's proprietary
tag format. By setting bit 6 (0x40) of the respective port configuration
@@ -51,7 +59,9 @@ registers 0x1238, 0x1338, ...
The code currently provides the following functions:
```
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
void vlan_create(uint16_t vlan, uint16_t members, uint16_t tagged) __banked;
uint16_t port_pvid_get(uint8_t port) __banked;
void vlan_create(void) __banked; // reads from global vlan_settings
int8_t vlan_get(register uint16_t vlan) __banked; // returns data in sfr_data
void vlan_delete(uint16_t vlan) __banked;
```
@@ -66,9 +76,26 @@ vlan <VLAN-ID> p[t/u]...
vlan <VLAN-ID> d
deletes the VLAN
vlan show
Dumps the current ingress vlan settings.
vlan <VLAN-ID> mgmt
Restricts network access to the switch (web UI, syslog) to the given
VLAN. Use `vlan 0 mgmt` to disable the filter. Default is `vlan 1 mgmt`.
Warning: setting this to an unreachable VLAN locks out the web UI;
recovery requires serial console.
pvid <port> <VLAN-ID>
assigns PVID to a port. ports are numbered as on the casing
ingress <port> [tagged|untagged|all]
Allows ingress only for the named packages at the given port
ingress [p]<t|u|a>...
Allows ingress packages on port `p` only when `t`agged, `u`ntagged or `a`ny.
Multiple ports can be given at once as in vlan. When `p` is missing, all ports
are assigned the same mode. CPU port can not be changed.
Use `vlan show` to see current configuration.
Example:
`ingress 1t 2a` -> Set port 1 as tagged input only, set port 2 accepting any frames.
`ingress a` -> Set all ports to accept both tagged and untagged frames (default behaviour).
```
+7 -5
View File
@@ -3,7 +3,6 @@ function createBW() {
var tbl = document.getElementById('bwtable');
const limit = '<input type="checkbox" id="limit_port" onchange="exec();">'
if (tbl.rows.length <= 2 && numPorts) {
clearInterval(createBWInterval);
console.log("CREATING TABLE ", tbl.rows.length);
for (let i = 2; i < 2 + numPorts; i++) {
const tr = tbl.insertRow();
@@ -94,6 +93,7 @@ async function applyBandwidth(i) {
function getBW() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
console.log("IN getBW ");
if (this.readyState == 4 && this.status == 200) {
const s = JSON.parse(xhttp.responseText);
console.log("BW: ", JSON.stringify(s));
@@ -126,11 +126,13 @@ function getBW() {
}
};
xhttp.open("GET", "/bandwidth.json", true);
xhttp.timeout = 1500; xhttp.send();
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
getBW();
const iCount = setInterval(getBW, 2000);
update( () => {
createBW();
getBW();
const interval = setInterval(update, 2000);
});
});
const createBWInterval = setInterval(createBW, 1010);
+71 -22
View File
@@ -1,35 +1,84 @@
var configInterval = Number();
var configuration = [];
const conf_cmds = [
/ip\s+(\d{1,3}\.){3}\d{1,3}/, /gw\s+(\d{1,3}\.){3}\d{1,3}/, /netmask\s+(\d{1,3}\.){3}\d{1,3}/,
/eee(\s+\d)?\s+(on|off)/, /mirror(\s+(\d|10))(\s+(\d|10)(t|r)?)+/, /vlan\s+(\d{1,4})(\s+(\d|10)(t|u)?)+/
/^ip\s+(\d{1,3}\.){3}\d{1,3}$/,
/^ip\s+dhcp$/,
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
/^syslog\s+(on|off)$/,
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
/^passwd\s+\S+$/,
/^vlan\s+\d{1,4}\s+d$/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}[tu]?)+$/,
/^pvid\s+\d{1,2}\s+\d{1,4}$/,
/^ingress(\s+\d{1,2}[tua])+$/,
/^ingress\s+[tua]$/,
/^port\s+\d{1,2}\s+name\s+\S+$/,
/^eee(\s+\d{1,2})?\s+(on|off)$/,
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,
/^lag\s+\d(\s+\d{1,2})+$/,
/^laghash\s+\d(\s+\w+)+$/,
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
/^stp\s+(on|off)$/,
/^igmp\s+(on|off)$/,
/^mtu\s+\d{1,2}\s+\d+$/,
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
];
const conf_overwrite = [
/ip/, /gw/, /netmask/, /eee\s+\w+/, /eee(\s+\w)/, /mirror/, /vlan\s+(\d{1,4})/
/^ip\b/,
/^gw\b/,
/^netmask\b/,
/^syslog\s+ip\b/,
/^syslog\b/,
/^passwd\b/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
/^pvid\s+\d{1,2}\b/,
/^ingress\b/,
/^port\s+\d{1,2}\s+name\b/,
/^eee\s+\d{1,2}\b/,
/^eee\b/,
/^mirror\b/,
/^lag\s+\d+\b/,
/^laghash\b/,
/^isolate\s+\d{1,2}\b/,
/^stp\b/,
/^igmp\b/,
/^mtu\s+\d{1,2}\b/,
/^bw\s+(in|out)\s+\d{1,2}\b/,
];
function parseConf(s){
var a = s.split(/\r\n|\n/);
for (var l = 0; l < a.length; l++) {
if (!a[l].length || a[l] == "\n" || a[l] == "\r\n")
continue;
console.log(l + ' --> ' + a[l]);
var ignore = true;
for (const x of conf_cmds)
if (x.test(a[l])) ignore = false;
if (ignore) continue;
for (const x of conf_overwrite) {
if (x.test(a[l])) {
console.log("Match ", x, " to ", a[l]);
m = a[l].match(x);
console.log("Starts with ", m[0]);
configuration = configuration.filter(item => !(item.startsWith(m[0])));
}
}
configuration.push(a[l]);
for (var l = 0; l < a.length; l++) {
var line = a[l].trim().replace(/\s+/g, ' ');
if (!line.length) continue;
const deleteMatch = line.match(/^vlan\s+(\d{1,4})\s+d$/);
if (deleteMatch) {
const prefix = "vlan " + deleteMatch[1] + " ";
configuration = configuration.filter(c =>
c !== "vlan " + deleteMatch[1] && !c.startsWith(prefix));
continue;
}
console.log("Configuration now:");
for (const x of configuration) { console.log(x); }
console.log(l + ' --> ' + line);
var ignore = true;
for (const x of conf_cmds)
if (x.test(line)) { ignore = false; break; }
if (ignore) continue;
for (const x of conf_overwrite) {
if (x.test(line)) {
let m = line.match(x);
let matchStr = m[0];
configuration = configuration.filter(item =>
!(item === matchStr || item.startsWith(matchStr + " ")));
break;
}
}
configuration.push(line);
}
console.log("Configuration now:");
for (const x of configuration) { console.log(x); }
}
async function fetchConfig() {
+7 -5
View File
@@ -1,7 +1,6 @@
function createEEE() {
var tbl = document.getElementById('eeetable');
if (tbl.rows.length <= 2 && numPorts) {
clearInterval(createEEEInterval);
console.log("CREATING TABLE ", tbl.rows.length);
for (let i = 2; i < 2 + numPorts; i++) {
console.log("Table row: " + i + "pState: " + pState[i-2]);
@@ -40,11 +39,14 @@ function getEEE() {
}
};
xhttp.open("GET", "/eee.json", true);
xhttp.timeout = 1500; xhttp.send();
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
getEEE();
const iCount = setInterval(getEEE, 2000);
update( () => {
createEEE();
getEEE();
const interval = setInterval(update, 2000);
const iCount = setInterval(getEEE, 2000);
});
});
const createEEEInterval = setInterval(createEEE, 1000);
+7
View File
@@ -2,6 +2,13 @@
<html>
<script src="/main.js"></script>
<script src="/main_info.js"></script>
<script>
window.addEventListener("load", function() {
update( () => {
const interval = setInterval(update, 2000);
});
});
</script>
<link rel="stylesheet" href="style.css">
<title>FreeSwitchOS Main Page</title>
</head>
+6 -2
View File
@@ -130,10 +130,14 @@ function getL2() {
}
};
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
xhttp.timeout = 1500; xhttp.send();
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
l2GetInterval = setInterval(getL2, 1000);
update( () => {
getL2();
const interval = setInterval(update, 2000);
l2GetInterval = setInterval(getL2, 1000);
});;
});
+8 -5
View File
@@ -3,7 +3,6 @@ var lagInterval = Number();
function lagForm() {
if (!numPorts)
return;
clearInterval(lagInterval);
for (let j=0; j < 4; j++) {
var lag = "mLAG" + j
console.log("Adding LAG " + lag)
@@ -35,9 +34,6 @@ function setL(p, c){
console.log("LAG setting: ", p, " to ", c);
document.getElementById(p).checked=c;
}
window.addEventListener("load", function() {
lagInterval = setInterval(lagForm, 200);
});
function fetchLag() {
var xhttp = new XMLHttpRequest();
@@ -58,7 +54,7 @@ function fetchLag() {
}
};
xhttp.open("GET", `/lag.json`, true);
xhttp.send();
sendXHTTP(xhttp);
}
async function lagSub(l) {
var cmd = "lag " + l;
@@ -76,3 +72,10 @@ async function lagSub(l) {
console.error(`Error: ${err}`);
}
}
window.addEventListener("load", function() {
update( () => {
lagForm();
const interval = setInterval(update, 2000);
});
});
+189 -20
View File
@@ -9,6 +9,9 @@ var pAdvertised = new Int8Array(10);
var numPorts = 0;
var logToPhysPort = new Int8Array(10);
var physToLogPort = new Int8Array(10);
var portNames = new Array(10);
var currentRequests = [];
var currentCallback;
function drawPorts() {
var f = document.getElementById('ports');
console.log("DRAWING PORTS: ", numPorts);
@@ -38,9 +41,86 @@ function drawPorts() {
}
}
function update() {
function parseUint16(val) {
return parseInt(val, 16) & 0xffff;
}
function parseInt16(val) {
let valInt = parseInt(val, 16);
let num = valInt & 0x7fff;
if (valInt & 0x8000) {
return num - 0x8000;
}
return num;
}
function applyCalibrationSlopeOffset(val, cal) {
if (typeof cal !== 'string') {
return val;
}
if (cal.startsWith("0x")) {
cal = cal.substring(2);
}
if (cal.length != 8) {
return val;
}
let slope = parseUint16(cal.substring(0, 4)) / 256;
let offset = parseInt16(cal.substring(4, 8));
return slope * val + offset;
}
function applyRxPowerCalibration(val, cal) {
if (typeof cal !== 'string') {
return val;
}
if (cal.startsWith("0x")) {
cal = cal.substring(2);
}
if (cal.length != 40) {
return val;
}
let bytes = cal.match(/.{1,2}/g).map(function (x) { return parseInt(x, 16); });
let view = new DataView(new Uint8Array(bytes).buffer);
return view.getFloat32(0) * Math.pow(val, 4)
+ view.getFloat32(4) * Math.pow(val, 3)
+ view.getFloat32(8) * Math.pow(val, 2)
+ view.getFloat32(12) * val
+ view.getFloat32(16);
}
function decodeSfpTemp(val, cal) {
let temp = parseInt16(val);
return applyCalibrationSlopeOffset(temp, cal) / 256;
}
function decodeSfpVcc(val, cal) {
let vcc = parseUint16(val);
return applyCalibrationSlopeOffset(vcc, cal) / 10000;
}
function decodeSfpTxBias(val, cal) {
let bias = parseUint16(val);
return applyCalibrationSlopeOffset(bias, cal) / 500;
}
function decodeSfpTxPower(val, cal) {
let txPower = parseUint16(val);
return applyCalibrationSlopeOffset(txPower, cal) / 10000;
}
function decodeSfpRxPower(val, cal) {
let rxPower = parseUint16(val);
return applyRxPowerCalibration(rxPower, cal) / 10000;
}
function convertPowerTodBm(val) {
return 10 * Math.log10(val);
}
function update(callback) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
console.log("IN UPDATE ");
if (this.readyState == 4 && this.status == 401)
document.location = "/login.html"
if (this.readyState == 4 && this.status == 200) {
@@ -57,6 +137,7 @@ function update() {
let n = p.portNum;
logToPhysPort[p.logPort] = n;
physToLogPort[n-1] = p.logPort;
portNames[p.logPort] = p.name;
let pid = "port" + n;
let ttid = "tt_" + n;
n--;
@@ -67,16 +148,25 @@ function update() {
continue;
var bgs = psvg.contentDocument.getElementsByClassName("bg");
var leds = psvg.contentDocument.getElementsByClassName("led");
if (leds[0] == null || leds[0].style == null)
continue;
const portName = p.name || portNames[p.logPort] || '';
var iHTML = "<table border=\"0\" class=\"tt_table\">";
if (portName) iHTML += "<tr><td align=\"left\">Name</td><td>:</td><td>" + portName + "</td></tr>";
if (p.enabled == 0) {
pState[n] = -1;
bgs[0].style.fill = "red";
leds[0].style.fill = "black"; leds[1].style.fill = "black";
psvg.style.opacity = 0.4;
tt.innerHTML = "Not enabled.";
iHTML += "<tr><td align=\"left\">Status</td><td>:</td><td>Not enabled.</td></tr>";
iHTML += "</table>";
tt.innerHTML = iHTML;
} else {
psvg.style.opacity = 1.0;
pState[n] = p.link;
if (p.link == 4 || p.link == 5 || p.link == 6) {
if (p.link == 5 || p.link == 7) {
leds[0].style.fill = "green"; leds[1].style.fill = "blue";
} else if (p.link == 4 || p.link == 6) {
leds[0].style.fill = "green"; leds[1].style.fill = "orange";
} else if (p.link == 1 || p.link == 2 || p.link == 3) {
leds[0].style.fill = "green"; leds[1].style.fill = "green";
@@ -84,34 +174,113 @@ function update() {
leds[0].style.fill = "black"; leds[1].style.fill = "black";
psvg.style.opacity = 0.4
}
var iHTML = "<table border=\"0\" class=\"tt_table\">";
iHTML += "<tr><td align=\"left\">Link speed</td><td>:</td><td>" + linkS[p.link + 1] + "</td></tr>";
if (p.isSFP) {
pAdvertised[n] = 0;
pAdvertised[n] = 0;
const hasExtendedStatus = p.sfp_options & 0x40;
iHTML += "<tr><td>Vendor</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>";
iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
if (p.sfp_options & 0x40) {
iHTML += "<tr><td>Temp</td><td>:</td><td>" + (Number(p.sfp_temp) >> 8) + "." + ((Number(p.sfp_temp) & 0xff)/256.0 * 100).toFixed(0) + "&#8239;&#8451;</td></tr>";
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + "&#8239;V</td></tr>";
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + (Number(p.sfp_txbias) / 500.0).toFixed(1) + "&#8239;mA</td></tr>";
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + "&#8239;mW</td></tr>";
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + "&#8239;mW</td></tr>";
if (hasExtendedStatus) {
let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal);
let txPowerdBm = convertPowerTodBm(txPower);
let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal);
let rxPowerdBm = convertPowerTodBm(rxPower);
iHTML += "<tr><td>Temp</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + "&#8239;&#8451;</td></tr>";
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + "&#8239;V</td></tr>";
iHTML += "<tr><td>TX-Fault</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>";
iHTML += "<tr><td>TX-Disabled</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>";
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + "&#8239;mA</td></tr>";
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + txPower.toFixed(3) + "&#8239;mW / " + txPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + rxPower.toFixed(3) + "&#8239;mW / " + rxPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
}
// Not all devices & modules have LOS pin...
const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null;
const rx_los_module = hasExtendedStatus ? Boolean(Number(p.sfp_state) & 0x2) : null;
if (rx_los_module !== null || rx_los_pin !== null) {
iHTML += `<tr><td>RX-LOS</td><td>:</td><td>${rxLosHTML(rx_los_pin, rx_los_module)}</td></tr>`;
}
} else {
pAdvertised[n] = parseInt(p.adv, 2);
}
};
iHTML += "</table>";
tt.innerHTML = iHTML;
}
}}
if (callback)
callback();
}};
xhttp.open("GET", "/status.json", true);
xhttp.timeout = 5000;
sendXHTTP(xhttp);
}
function rxLosHTML(pinStatus, moduleStatus) {
if (moduleStatus !== null && pinStatus !== null && moduleStatus !== pinStatus) {
return `pin=${pinStatus}<br/>mod=${moduleStatus}<br/>❗❗❗❗`;
}
// Returns first non null value
return moduleStatus ?? pinStatus;
}
function callbackXHTTP()
{
x = currentRequests.shift();
x.onreadystatechange = currentCallback;
x.onreadystatechange();
if (currentRequests.length === 0)
return;
x = currentRequests[0];
currentCallback = x.onreadystatechange;
x.onreadystatechange = callbackXHTTP;
var retries = 10;
while (retries) {
try {
setTimeout(() => {
x.send();
console.log("B1");
}, 20);
} catch (error) {
retries--;
setTimeout(() => {
console.log(`Retry ${retries}/${maxRetries} failed: ${error.message}`);
}, 200);
if (retries < 1) {
throw error;
}
}
};
xhttp.open("GET", "/status.json", true);
xhttp.timeout = 5000; xhttp.send();
console.log("B2");
return;
}
}
function sendXHTTP(x)
{
console.log("sendXHTTP ", x);
if (currentRequests.length === 0) {
currentRequests.push(x);
currentCallback = x.onreadystatechange;
x.onreadystatechange = callbackXHTTP;
var retries = 10;
while (retries) {
try {
x.send();
console.log("A1");
} catch (error) {
retries--;
setTimeout(() => {
console.log(`Retry ${retries}/${maxRetries} failed: ${error.message}`);
}, 200);
if (retries < 1) {
throw error;
}
}
console.log("A2");
return;
}
console.log("A3");
return;
}
currentRequests.push(x);
}
window.addEventListener("load", function() {
update();
const interval = setInterval(update, 2000);
});
+9 -6
View File
@@ -4,7 +4,6 @@ const mirrors = ["mPortsTX", "mPortsRX"];
function mirrorForm() {
if (!numPorts)
return;
clearInterval(mirrorInterval);
for (let j=0; j < mirrors.length; j++) {
console.log("Adding Mirror " + j)
var m = document.getElementById(mirrors[j]);
@@ -34,9 +33,6 @@ function mirrorForm() {
function setM(p, c){
document.getElementById(p).checked=c;
}
window.addEventListener("load", function() {
mirrorInterval = setInterval(mirrorForm, 200);
});
function fetchMirror() {
var xhttp = new XMLHttpRequest();
@@ -51,11 +47,18 @@ function fetchMirror() {
for (let i = 1; i <= numPorts; i++) {
let p = i - 1;
if (numPorts < 9)
p = physToLogPort[p];members & (1<<p)
p = physToLogPort[p];
setM("mPortsTX"+i, m_tx&(1<<p)); setM("mPortsRX"+i, m_rx&(1<<p));
}
}
};
xhttp.open("GET", `/mirror.json`, true);
xhttp.send();
sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
update( () => {
mirrorForm();
const interval = setInterval(update, 2000);
});
});
+1 -1
View File
@@ -11,7 +11,7 @@
<h1>Port Configuration</h1>
<form id="vform" action="/vlan.html">
<table id="speedtable">
<tr> <th>Port</th> <th>Current Link Speed</th><th>Set Speed</th><th>Disabled</th><th>Apply</th></tr>
<tr> <th>Port</th> <th>Name</th> <th>Current Link Speed</th><th>Set Speed</th><th>Disabled</th><th>Apply</th></tr>
</table>
<h2 style="margin-top:3em">Configure Maximum Frame Size (MTU) forwarded at Port</h2>
<table id="mtutable" style="margin-top:1em">
+11 -8
View File
@@ -3,7 +3,6 @@ var clicked = new Int8Array(10);
function createPortTable() {
var tbl = document.getElementById('speedtable');
if (tbl.rows.length <= 2 && numPorts) {
clearInterval(pTableInterval);
const sSelect = '<select name="speed_sel" id="speed_sel">'
+ '<option value="auto">Auto</option>'
+ '<option value="2g5">2500MBit/Full</option>'
@@ -20,6 +19,8 @@ function createPortTable() {
console.log("Table row: " + i + "pState: " + pState[i-2]);
const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`));
let portName = portNames[physToLogPort[i-1]] || '';
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1];
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
@@ -67,7 +68,7 @@ function updatePortTable() {
for (let i = 1; i <= numPorts ; i++) {
if (pIsSFP[i-1])
continue;
tbl.rows[i].cells[1].innerHTML = `${linkS[pState[i-1]+1]}`;
tbl.rows[i].cells[2].innerHTML = `${linkS[pState[i-1]+1]}`;
if (!clicked[i] && pState[i - 1] < 0) {
document.getElementById('speed_sel_' + i).disabled = true;
document.getElementById('disable_port_' + i).checked = true;
@@ -130,17 +131,19 @@ function getMTUs() {
if (!mtu)
continue;
mtu.value = mtus[n];
clearInterval(pMTUInterval);
}
}
};
xhttp.open("GET", "/mtu.json", true);
xhttp.timeout = 1500; xhttp.send();
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
const updatePortTableInterval = setInterval(updatePortTable, 1000);
update( () => {
createPortTable();
updatePortTable();
getMTUs()
const interval = setInterval(update, 2000);
const updatePortTableInterval = setInterval(updatePortTable, 1000);
});
});
const pTableInterval = setInterval(createPortTable, 1000);
const pMTUInterval = setInterval(getMTUs, 1200);
+1 -1
View File
@@ -38,7 +38,7 @@
</div>
<h1>Port Statistics</h1>
<table id="statstable">
<tr> <th>Port</th> <th>link</th> <th>TX Good</th> <th>TX Bad</th> <th>RX Good</th> <th>RX Bad</th> <th> All Counters </th></tr>
<tr> <th>Port</th> <th>Name</th> <th>link</th> <th>TX Good</th> <th>TX Bad</th> <th>RX Good</th> <th>RX Bad</th> <th> All Counters </th></tr>
<script src="/stat.js"></script>
</table>
</div>
+17 -8
View File
@@ -151,7 +151,7 @@ function getCounters(port) {
}
};
xhttp.open("GET", "/counters.json?port=" + port, true);
xhttp.timeout = 1500; xhttp.send();
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
@@ -162,17 +162,19 @@ function fillStats() {
if (tbl.rows.length > 1) {
for (let i = 0; i < numPorts; i++) {
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
tbl.rows[i+1].cells[1].innerHTML = `${linkS[pState[i]+1]}`;
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`;
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
tbl.rows[i+1].cells[2].innerHTML = `${linkS[pState[i]+1]}`;
tbl.rows[i+1].cells[3].innerHTML = `${txG[i]} pkts`;
tbl.rows[i+1].cells[4].innerHTML = `${txB[i]} pkts`;
tbl.rows[i+1].cells[5].innerHTML = `${rxG[i]} pkts`;
tbl.rows[i+1].cells[6].innerHTML = `${rxB[i]} pkts`;
}
} else {
for (let i = 0; i < numPorts; i++) {
console.log("Table row: " + i);
const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
let portName = portNames[physToLogPort[i]] || '';
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
@@ -184,8 +186,6 @@ function fillStats() {
}
}
const stat = setInterval(fillStats, 1000);
const popup = document.getElementById('popup');
const closePopup = document.getElementById('closePopup');
closePopup.addEventListener('click', () => {
@@ -196,3 +196,12 @@ window.addEventListener('click', (event) => {
popup.style.display = 'none';
}
});
window.addEventListener("load", function() {
update( () => {
update();
fillStats();
const stat = setInterval(fillStats, 1000);
const interval = setInterval(update, 2000);
});
});
+1
View File
@@ -163,3 +163,4 @@ margin: 30px 0;
}
select { text-align-last: right; font-family: monospace}
option { direction: rtl; font-family: sans-serif}
#vlanTable td { text-align: left; }
+12
View File
@@ -16,6 +16,7 @@
<div class="tab-bar">
<button class="tab-btn active" onclick="openTab(event, 'system-tab')">System</button>
<button class="tab-btn" onclick="openTab(event, 'advanced-tab')">Advanced</button>
<button class="tab-btn" onclick="openTab(event, 'console-tab')">Console</button>
</div>
<nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
@@ -56,6 +57,17 @@
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" value="Reset Switch">
</div>
<div id="console-tab" class="tab-content">
<h1>Console Command</h1>
<label for="console_command">Enter command:</label>
<input type="text" id="console_cmd" name="console_cmd" style="width:40%;">
<input style="width:20%;" class="action" id="cmd_sub" onclick="cmdSub();" type="button" value="Send Command"><br/>
<br/><br/>
Be careful when entering console commands, you can lock yourself out!<br/>
</div>
</div>
<script src="/config.js"></script>
<script src="/system.js"></script>
+46 -26
View File
@@ -1,4 +1,5 @@
var systemInterval = Number();
var isSaving = false;
const ips = ["ip", "netmask", "gw"];
function checkIp(ip) {
@@ -12,51 +13,70 @@ async function ipSub() {
if (!checkIp(document.getElementById(ips[i]).value))
return;
}
var cmd = '';
for (let i=0; i<3;i++){
var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
fetchIP();
} catch(err) {
console.error(`Error: ${err}`);
}
cmd += ips[i]+' '+document.getElementById(ips[i]).value+'\n';
}
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
fetchIP();
} catch(err) {
console.error(`Error: ${err}`);
}
}
async function cmdSub() {
var cmd = document.getElementById('console_cmd').value;
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
} catch(err) {
console.error(`Error: ${err}`);
}
}
async function sendConfig(c) {
const form = new FormData();
if (isSaving) return;
isSaving = true;
clearInterval(systemInterval);
const form = new FormData();
form.append("MAX_FILE_SIZE", "4096");
form.append("configuration", new Blob([c], {type: "application/octet-stream"}));
form.append("configuration", new Blob([c], {type: "application/octet-stream"}), "config.txt");
try {
const response = await fetch('/config', {
method: 'POST',
body: form
});
console.log('Completed!', response);
try {
await fetch('/cmd_log_clear', { method: 'GET' });
} catch(e) {}
} catch(err) {
console.error(`Error: ${err}`);
} finally {
isSaving = false;
systemInterval = setInterval(fetchIP, 1000);
}
}
async function flashSave() {
fetchConfig().then((s) => {
parseConf(s);
fetchCmdLog().then((s) => {
parseConf(s);
var body = "";
for (const x of configuration) { body = body + x + "\n"; }
console.log("CONFIGURATION to save: ", body);
sendConfig(body);
});
});
setTimeout(() => {
fetchIP();
}, 500);
configuration = [];
const savedConfig = await fetchConfig();
const cmdLog = await fetchCmdLog();
if (savedConfig) parseConf(savedConfig);
if (cmdLog) parseConf(cmdLog);
const body = configuration.join('\n') + '\n';
console.log("CONFIGURATION to save: ", body);
await sendConfig(body);
}
async function flashStartupSave() {
+24 -1
View File
@@ -10,9 +10,16 @@
<div id="ports"></div>
<h1>VLAN Configuration</h1>
<form id="vform" action="/vlan.html">
<div>
<label for="vlanSelect">VLAN auswählen:</label>
<select id="vlanSelect" style="margin: 0 0 0 8px">
<option value="" disabled selected>— VLAN wählen —</option>
</select>
</div>
<br/>
<div>
<label for="vid">VLAN ID:</label>
<input type="number" min="1" max="2047" id="vid" name="vid">
<input type="number" min="1" max="4094" id="vid" name="vid">
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();">Get Configuration</button>
</div>
<br/><br/>
@@ -29,6 +36,22 @@
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" value="Update / Create">
<script src="/vlan_sub.js"></script>
</form>
<h2>Configured VLANs</h2>
<table id="vlanTable" style="width:90%">
<thead>
<tr>
<th>VLAN</th>
<th>Name</th>
<th>Member Ports</th>
<th>Tagged Ports</th>
<th>Untagged Ports</th>
<th>PVID Ports</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="vlanTableBody">
</tbody>
</table>
</div>
<script src="/navigation.js"></script>
</body>
+139 -15
View File
@@ -3,7 +3,6 @@ var vlanInterval = Number();
function vlanForm() {
if (!numPorts)
return;
clearInterval(vlanInterval);
var t = document.getElementById('tPorts');
var u = document.getElementById('uPorts');
var p = document.getElementById('pPorts');
@@ -39,11 +38,6 @@ function vlanForm() {
function setC(t, p, c){
document.getElementById(t+'port'+p).checked=c;
// When a tagged port is checked, automatically select the PVID port as well
const tportElem = document.getElementById('tport'+p);
if (tportElem && tportElem.checked) {
document.getElementById('pport'+p).checked=true;
}
}
function utClicked(t){
@@ -58,10 +52,6 @@ function pvClicked(p){
}
}
window.addEventListener("load", function() {
vlanInterval = setInterval(vlanForm, 100);
});
function fetchVLAN() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
@@ -70,10 +60,17 @@ function fetchVLAN() {
console.log("VLAN: ", JSON.stringify(s));
m = parseInt(s.members, 16);
document.getElementById('vname').value = s.name;
for (let i = 1; i <= numPorts; i++) {
setC('t', i, (m>>(10+i-1))&1);
setC('u', i, (m>>(i-1))&1);
setC('p', i, (m>>(20+i-1))&1);
var members = m & 0x3FF;
var untag = (m >> 10) & 0x3FF;
var pvid = parseInt(s.pvid, 16);
console.log("PVID: ", pvid);
for (let p = 1; p <= numPorts; p++) {
var bit = physToLogPort[p-1];
var isMember = (members >> bit) & 1;
var isUntag = (untag >> bit) & 1;
setC('t', p, isMember && !isUntag);
setC('u', p, isMember && isUntag);
setC('p', p, (pvid >> bit) & 1);
}
}
};
@@ -83,5 +80,132 @@ function fetchVLAN() {
return;
}
xhttp.open("GET", `/vlan.json?vid=${v}`, true);
xhttp.send();
sendXHTTP(xhttp);
}
function portsToRange(mask, nPorts) {
var parts = [];
var start = -1, prev = -1;
for (var p = 1; p <= nPorts; p++) {
var bit = physToLogPort[p - 1];
if ((mask >> bit) & 1) {
if (start < 0) start = p;
prev = p;
} else {
if (start >= 0) {
parts.push(start === prev ? String(start) : start + '-' + prev);
start = -1; prev = -1;
}
}
}
if (start >= 0)
parts.push(start === prev ? String(start) : start + '-' + prev);
return parts.length ? parts.join(',') : '-';
}
async function loadVlanTable() {
var tbody = document.getElementById('vlanTableBody');
if (!tbody) return;
tbody.innerHTML = '';
var resp;
try { resp = await fetch('/vlanlist'); } catch(e) { return; }
if (!resp.ok) return;
var vlans = await resp.json();
for (var i = 0; i < vlans.length; i++) {
var v = vlans[i];
var vresp;
try { vresp = await fetch('/vlan.json?vid=' + v.id); } catch(e) { continue; }
if (!vresp.ok) continue;
var s = await vresp.json();
var m = parseInt(s.members, 16);
var members = m & 0x3FF;
var untag = ((m >> 10) & 0x3FF) & members;
var tagged = members & ~untag;
var pvid = parseInt(s.pvid, 16) & 0x3FF;
var tr = document.createElement('tr');
var td, a, btn;
td = document.createElement('td');
a = document.createElement('a');
a.href = '#';
a.textContent = v.id;
(function(vid) {
a.onclick = function(e) {
e.preventDefault();
document.getElementById('vid').value = vid;
fetchVLAN();
};
})(v.id);
td.appendChild(a); tr.appendChild(td);
td = document.createElement('td');
td.textContent = v.name || ''; tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(members, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(tagged, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(untag, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(pvid, numPorts); tr.appendChild(td);
td = document.createElement('td');
if (v.id !== 1) {
btn = document.createElement('button');
btn.textContent = '✕';
(function(vid) {
btn.onclick = function() { deleteVlan(vid); };
})(v.id);
td.appendChild(btn);
}
tr.appendChild(td);
tbody.appendChild(tr);
}
}
function deleteVlan(id) {
if (!confirm('Delete VLAN ' + id + '?')) return;
fetch('/cmd', { method: 'POST', body: 'vlan ' + id + ' d' })
.then(function() { refreshVlanViews(); })
.catch(function(err) { console.error('Delete failed:', err); });
}
function refreshVlanViews() {
loadVlanList();
loadVlanTable();
}
function loadVlanList() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState !== 4) return;
var sel = document.getElementById('vlanSelect');
if (this.status !== 200) {
sel.style.display = 'none';
return;
}
var vlans = JSON.parse(this.responseText);
if (!vlans.length) {
sel.style.display = 'none';
return;
}
sel.options.length = 1;
for (var i = 0; i < vlans.length; i++) {
var opt = document.createElement('option');
opt.value = vlans[i].id;
opt.text = vlans[i].name ? vlans[i].id + ' — ' + vlans[i].name : String(vlans[i].id);
sel.appendChild(opt);
}
};
xhttp.open('GET', '/vlanlist', true);
sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
update( () => {
vlanForm();
refreshVlanViews();
document.getElementById('vlanSelect').onchange = function() {
document.getElementById('vid').value = this.value;
fetchVLAN();
};
const interval = setInterval(update, 2000);
});
});
+1
View File
@@ -28,6 +28,7 @@ async function vlanSub() {
});
console.log('Completed!', response);
}
refreshVlanViews();
} catch(err) {
console.error(`Error: ${err}`);
}
-26
View File
@@ -1,26 +0,0 @@
CC = sdcc
CC_FLAGS = -mmcs51 -I. -I.. -I../uip
ASM = sdas8051
AFLAGS= -plosgff
BUILDDIR = output/
SRCS = httpd.c page_impl.c
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
all: create_build_dir $(OBJS)
create_build_dir:
mkdir -p $(BUILDDIR)
$(BUILDDIR)%.asm: %.c
$(CC) $(CC_FLAGS) -o $@ -c -S $<
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
${ASM} ${AFLAGS} -o $@ $^
clean:
rm -r $(BUILDDIR)
.PHONY: all clean
+167 -83
View File
@@ -14,9 +14,6 @@
#define SESSION_ID_LENGTH 12
#define SESSION_TIMEOUT 200
// SPI FLASH MEMORY PAGE SIZE.
#define FLASHMEM_PAGE_SIZE 0x100
#define CMARK_S 6
#pragma codeseg BANK1
@@ -60,11 +57,12 @@ __xdata uint32_t now;
__xdata uint8_t *timeptr;
__xdata uint32_t last_session_use;
#define TSTATE_NONE 0
#define TSTATE_TX 1
#define TSTATE_ACKED 2
#define TSTATE_CLOSED 3
#define TSTATE_POST 4
#define TSTATE_NONE 0
#define TSTATE_TX 1
#define TSTATE_ACKED 2
#define TSTATE_CLOSED 3
#define TSTATE_POST 4
#define TSTATE_MULTIPART 5
extern __xdata uint16_t crc_value;
__xdata uint16_t crc_final;
@@ -118,33 +116,88 @@ char strcmp(__xdata uint8_t *c, __code uint8_t * __xdata d)
}
char is_word(__xdata uint8_t *c, __code uint8_t * __xdata d)
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
{
uint8_t i = 0;
uint8_t u, c;
while (d[i] && (d[i] == c[i]))
i++;
while (1) {
u = *xdata_str_p++;
c = *code_str_p++;
if (d[i])
return 0;
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
return 0;
return 1;
if (c == '\0') {
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
return false;
return true;
}
if (c != u) {
return false;
}
}
}
char is_word_x(__xdata uint8_t *c, __xdata uint8_t *d)
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
{
register uint8_t i = 0;
uint8_t u, s;
while (d[i] && (d[i] == c[i]))
i++;
while(1) {
u = *uri_str_p++;
s = *src_str_p++;
if (d[i])
return 0;
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
return 0;
return 1;
if (s == '\0') {
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
return false;
return true;
}
if (u == '%') {
bool again = true;
u = 0;
while(1) {
// Swap instruction is fine for rotation
u = (u << 4) | (u >> 4);
uint8_t p = *uri_str_p++;
u |= p - '0' < 10 ? (p - '0') : (p - 'A' + 10);
// force `jbc`-instruction.
if (again) {
again = false;
} else {
break;
}
}
} else if (u == '+') {
u = ' ';
}
if (s != u) {
return false;
}
}
}
bool is_word_x(__xdata uint8_t *lhs_str_p, __xdata uint8_t *rhs_str_p)
{
uint8_t u, c;
while (1) {
u = *lhs_str_p++;
c = *rhs_str_p++;
if (c == '\0') {
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
return false;
return true;
}
if (c != u) {
return false;
}
}
}
@@ -294,14 +347,14 @@ uint8_t stream_upload(uint16_t bptr)
if (verify_crc) {
dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n');
if (crc_final == 0xb001) {
print_string("Checksum OK.");
print_string("Checksum OK.\nUpload to flash done, will reset!\n");
// close connection to avoid retries by browser
uip_close();
reset_chip();
} else {
print_string("Checksum incorrect!");
print_string("Checksum incorrect! Aborting.\n");
uip_close();
}
print_string("\nUpload to flash done, will reset!\n");
// close connection to avoid retries by browser
uip_close();
reset_chip();
}
// Make sure there is a 0 at the end of the uploaded data
flash_buf[0] = 0;
@@ -329,18 +382,22 @@ uint8_t stream_upload(uint16_t bptr)
}
crc16(p + bptr);
flash_buf[write_len++] = p[bptr++];
if (write_len >= FLASHMEM_PAGE_SIZE) {
if (write_len >= FLASH_PAGE_SIZE) {
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
if (uptr % FLASH_SECTOR_SIZE == 0) {
flash_region.addr = uptr;
flash_sector_erase();
}
flash_region.addr = uptr;
flash_region.len = FLASHMEM_PAGE_SIZE;
flash_region.len = FLASH_PAGE_SIZE;
flash_write_bytes(flash_buf);
uptr += FLASHMEM_PAGE_SIZE;
write_len -= FLASHMEM_PAGE_SIZE;
uptr += FLASH_PAGE_SIZE;
write_len -= FLASH_PAGE_SIZE;
// Copy the remaining byte for the next page to the beginning of the buffer.
if (write_len > 0) {
memcpy(flash_buf, flash_buf + FLASHMEM_PAGE_SIZE, write_len);
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len);
}
}
bindex = 0;
@@ -355,39 +412,74 @@ void handle_post(void)
__xdata uint8_t *p = uip_appdata;
__xdata uint8_t *request_path = p + 6;
dbg_string("Is POST\n");
p += 5; // Skip post
// Find end of request path
while (*p && !is_separator(*p))
p++;
*p++ = '\0';
// Was the multipart header sent in multiple packets?
if (s->tstate != TSTATE_MULTIPART) {
dbg_string("Is POST\n");
p += 5; // Skip post
// Find end of request path
while (*p && !is_separator(*p))
p++;
*p++ = '\0';
// Find end of request header
boundary[0] ='\0';
p = scan_header(p);
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
if (!*p || !content_type) {
dbg_string("Bad Request!\n");
send_not_found();
return;
// Find end of request header
boundary[0] ='\0';
p = scan_header(p);
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
if (!*p || !content_type) {
dbg_string("Bad Request!\n");
send_not_found();
return;
}
if (is_word(request_path, "upload")) {
if (flash_size < FIRMWARE_UPLOAD_START*2)
{
print_string("Flash too small for firmware upload!\n");
send_bad_request();
return;
}
print_string("Firmware upload started.");
uptr = FIRMWARE_UPLOAD_START;
verify_crc = 1;
max_upload = 1024576;
} else if (is_word(request_path, "config")) {
if (!authenticated) {
send_unauthorized();
return;
}
dbg_string("Configuration upload, erasing config mem!\n");
uptr = CONFIG_START;
verify_crc = 0;
max_upload = 2048;
flash_region.addr = CONFIG_START;
flash_sector_erase();
}
// Check for other POST requests, which are not multipart, below
} else {
dbg_string("Multipart request\n");
}
if (is_word(request_path, "cmd")) {
register uint8_t i = 0;
p += 4;
if (!authenticated) {
send_unauthorized();
return;
}
while (*p && *p != '\n' && *p != '\r')
cmd_buffer[i++] = *p++;
cmd_buffer[i] = '\0';
if (i)
cmd_available = 1;
execute_commands(p);
if (err_status != ERR_OK) {
send_bad_request();
return;
}
} else if (is_word(request_path, "login")) {
dbg_string("POST login\n");
if (!content_type || !is_word(content_type, "application/x-www-form-urlencoded")) {
dbg_string("Bad request!\n");
send_bad_request();
return;
}
p += 8; // Read also over "pwd="
if (is_word_x(p, passwd)) {
if (is_url_word_x(p, passwd)) {
dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use);
gen_random_bytes(session_id, SESSION_ID_LENGTH);
@@ -398,10 +490,11 @@ void handle_post(void)
outbuf[slen++] = session_id[i];
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
} else {
dbg_string("Password invalid!\n");
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: login.html\r\n\r\n");
}
return;
} else if (is_word(request_path, "upload") || is_word(request_path, "config")) {
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
dbg_string("POST upload/config request\n");
if (!authenticated) {
send_unauthorized();
@@ -415,8 +508,10 @@ void handle_post(void)
// We skip the intial parts as part of the header
do {
p = skip_boundary(p);
if (!*p)
goto bad_request;
if (!*p) {
s->tstate = TSTATE_MULTIPART;
return;
}
p = scan_header(p);
if (!*p)
goto bad_request;
@@ -426,25 +521,6 @@ void handle_post(void)
dbg_string("Have content octets\n");
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
if (is_word(request_path, "upload")) {
if (flash_size < FIRMWARE_UPLOAD_START*2)
{
print_string("Flash too small for firmware upload!\n");
send_bad_request();
return;
}
print_string("Firmware upload started.");
uptr = FIRMWARE_UPLOAD_START;
verify_crc = 1;
max_upload = 1024576;
} else {
dbg_string("Configuration upload, erasing config mem!\n");
uptr = CONFIG_START;
verify_crc = 0;
max_upload = 2048;
flash_region.addr = CONFIG_START;
flash_sector_erase();
}
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
set_sys_led_state(SYS_LED_FAST);
@@ -473,6 +549,12 @@ void httpd_appcall(void)
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
dbg_char('P');
#ifdef DEBUG
if (uip_newdata())
write_char('N');
print_byte(s->tstate);
write_char(' ');
#endif
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
dbg_string("Connected...\n");
s->tstate = TSTATE_NONE;
@@ -544,10 +626,10 @@ void httpd_appcall(void)
dbg_char('\n');
#endif
p = uip_appdata;
if (is_word(p, "POST")) {
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART) {
handle_post();
// If this is an ongoing post stream, then wait for the next packet
if (s->tstate == TSTATE_POST) {
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART) {
uip_len = 0;
return;
}
@@ -600,6 +682,8 @@ void httpd_appcall(void)
send_mtu();
} else if (is_word(q, "/lag.json")) {
send_lag();
} else if (is_word(q, "/vlanlist")) {
send_vlanlist();
} else if (is_word(q, "/config")) {
send_config();
} else if (is_word(q, "/cmd_log")) {
@@ -630,7 +714,7 @@ void httpd_appcall(void)
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
slen += strtox(outbuf + slen, mime_strings[f_data[entry].mime]);
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\n\r\n");
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\nContent-Security-Policy: style-src 'self' 'unsafe-inline'\r\n\r\n");
len_left = f_data[entry].len;
if (len_left > (TCP_OUTBUF_SIZE - slen)) {
+113 -19
View File
@@ -13,11 +13,11 @@
#include "version.h"
#include "machine.h"
#include "page_impl.h"
#include "syslog.h"
// #define DEBUG
#include "debug.h"
#define L2_MAX_TRANSFER 30
#pragma codeseg BANK1
@@ -97,7 +97,20 @@ void itoa_html(uint8_t v)
char_to_html('0' + (v % 10));
}
void string_to_html(register char *s)
void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
{
uint8_t print_zeros = 0;
uint8_t d;
d = v / 1000;
if (d) { char_to_html('0' + d); print_zeros = 1; }
d = (v / 100) % 10;
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
d = (v / 10) % 10;
if (d || print_zeros) char_to_html('0' + d);
char_to_html('0' + (v % 10));
}
void string_to_html(__code char *s)
{
while (*s) char_to_html(*s++);
}
@@ -175,11 +188,15 @@ void send_sfp_info(uint8_t sfp)
void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
{
// maximum supported transfer size is 16 bytes
if (len > 16)
return;
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL);
@@ -196,13 +213,10 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
for (uint8_t i = 0; i < len & 0xf; i++) {
for (uint8_t i = 0; i < len; i++) {
if (!(i & 0x3))
reg_read_m(RTL837X_REG_I2C_OUT + (i >> 2));
if (len & 0x80)
char_to_html(sfr_data[3 - (i & 0x3)]);
else
byte_to_html(sfr_data[3 - (i & 0x3)]);
reg_read_m(RTL837X_REG_I2C_OUT + i);
byte_to_html(sfr_data[3 - (i & 0x3)]);
}
}
@@ -226,6 +240,11 @@ void send_basic_info(void)
itoa_html(uip_netmask[0] >> 8); char_to_html('.');
itoa_html(uip_netmask[1]); char_to_html('.');
itoa_html(uip_netmask[1] >> 8);
slen += strtox(outbuf + slen, "\",\"syslog_server_ip\":\"");
itoa_html(syslog_state.server_ip[0]); char_to_html('.');
itoa_html(syslog_state.server_ip[1]); char_to_html('.');
itoa_html(syslog_state.server_ip[2]); char_to_html('.');
itoa_html(syslog_state.server_ip[3]);
slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
@@ -242,14 +261,16 @@ void send_basic_info(void)
slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
string_to_html(get_flash_size_str());
slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
send_sfp_info(0);
char_to_html('"');
if (machine.n_sfp == 2) {
slen += strtox(outbuf + slen, ",\"sfp_slot_1\":\"");
send_sfp_info(1);
char_to_html('"');
if (machine.n_sfp) {
slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
send_sfp_info(0);
if (machine.n_sfp == 2) {
slen += strtox(outbuf + slen, "\",\"sfp_slot_1\":\"");
send_sfp_info(1);
}
}
char_to_html('"');
char_to_html('}');
}
@@ -270,6 +291,14 @@ void send_vlan(uint16_t vlan)
while(vlan_names[n] && vlan_names[n] != ' ')
char_to_html(vlan_names[n++]);
}
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
uint16_t pvid_mask = 0;
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
if (port_pvid_get(i) == vlan)
pvid_mask |= (1 << i);
}
byte_to_html(pvid_mask >> 8);
byte_to_html(pvid_mask);
slen += strtox(outbuf + slen, "\"}");
}
@@ -624,6 +653,11 @@ void send_status(void)
itoa_html(machine.log_to_phys_port[i]);
slen += strtox(outbuf + slen, ",\"logPort\":");
itoa_html(i);
slen += strtox(outbuf + slen, ",\"name\":\"");
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
char_to_html(port_names[i][j]);
}
slen += strtox(outbuf + slen, "\"");
if (machine.is_sfp[i]) {
slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":");
@@ -632,7 +666,6 @@ void send_status(void)
slen += strtox(outbuf + slen,",\"sfp_options\":\"0x");
byte_to_html(sfp_options[machine.is_sfp[i]-1]);
if (sfp_options[machine.is_sfp[i]-1] & 0x40) {
sfp_send_data(machine.is_sfp[i] - 1, 92, 1);
slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 224, 2);
slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x");
@@ -643,6 +676,19 @@ void send_status(void)
sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 232, 2);
if (sfp_options[machine.is_sfp[i]-1] & 0x10) {
slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 212, 4);
slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 216, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 204, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 208, 4);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 184, 16);
sfp_send_data(machine.is_sfp[i] - 1, 200, 4);
}
slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x");
sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
}
@@ -655,7 +701,12 @@ void send_status(void)
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
for (register uint8_t s = 0; s < 16; s++)
outbuf[slen++] = sfp_module_serial[machine.is_sfp[i]-1][s];
char_to_html('"');
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
if (machine.sfp_port[machine.is_sfp[i]-1].pin_los == GPIO_NA) {
slen += strtox(outbuf + slen,"null");
} else {
bool_to_html(sfp_pins_last & (0x2 << (((machine.is_sfp[i]-1) << 2))));
}
} else {
bool_to_html(0);
}
@@ -787,3 +838,46 @@ void send_cmd_log(void)
p = (p + 1) & CMD_HISTORY_MASK;
}
}
void send_vlanlist(void)
{
/* Worst case per entry: {"id":4094,"name":"<117-char name>"} = 138 bytes
* (name bound: CMD_BUF_SIZE=128 minus command prefix); +1 for closing ']'.
* At worst case ~18 VLANs fit; typical configs with short names fit many more. */
__xdata uint16_t i;
__xdata uint16_t n;
uint8_t first = 1;
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
char_to_html('[');
for (i = 1; i < 4095; i++) {
if (vlan_get(i) < 0)
continue;
if (!(sfr_data[0] & 0x02)) /* bit 1: VLAN table entry valid */
continue;
if (slen + 139 > TCP_OUTBUF_SIZE) /* 138 bytes worst-case entry + 1 byte for closing ']' */
break;
if (!first)
char_to_html(',');
first = 0;
slen += strtox(outbuf + slen, "{\"id\":");
itoa16_html(i);
slen += strtox(outbuf + slen, ",\"name\":\"");
n = vlan_name(i);
if (n != 0xffff) {
while (vlan_names[n] && vlan_names[n] != ' ')
char_to_html(vlan_names[n++]);
}
slen += strtox(outbuf + slen, "\"}");
}
char_to_html(']');
}
+1
View File
@@ -14,6 +14,7 @@ void send_mtu(void);
void send_config(void);
void send_cmd_log(void);
void send_lag(void);
void send_vlanlist(void);
/* Convert only the lower nibble to ascii HEX char.
For convenience the upper nibble is masked out.
+11 -12
View File
@@ -6,37 +6,36 @@ CC_FLAGS = -mmcs51
ASM = sdas8051
AFLAGS= -plosgff
BUILDDIR = output/
BUILDDIR = output
SRCS = installer.c
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
all: create_build_dir $(BUILDDIR)updatebuilder $(BUILDDIR)rtlplayground.bin
all: create_build_dir $(BUILDDIR)/updatebuilder $(BUILDDIR)/rtlplayground_oem_upgrade.bin
create_build_dir:
mkdir -p $(BUILDDIR)
$(BUILDDIR)updatebuilder: updatebuilder.c
$(BUILDDIR)/updatebuilder: updatebuilder.c
gcc $^ -o $@
$(BUILDDIR)installer.rel: installer.c
$(BUILDDIR)/installer.rel: installer.c
$(CC) $(CC_FLAGS) --code-loc ${CODE_LOCATION} -o $@ -c $<
$(BUILDDIR)crtstart.rel: crtstart.asm
$(BUILDDIR)/crtstart.rel: crtstart.asm
$(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
$(BUILDDIR)/%.rel: $(BUILDDIR)/%.asm
${ASM} ${AFLAGS} -o $@ $^
$(BUILDDIR)%.rel: %.c
$(BUILDDIR)/%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)rtlinstaller.ihx: $(BUILDDIR)crtstart.rel $(OBJS)
$(BUILDDIR)/rtlinstaller.ihx: $(BUILDDIR)/crtstart.rel $(OBJS)
$(CC) $(CC_FLAGS) -Wl-bHOME=${INSTALLER_ADDRESS} -Wl-r -o $@ $^
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlinstaller.ihx ../$(BUILDDIR)/rtlplayground.bin
cp ../$(BUILDDIR)/rtlplayground.bin $(BUILDDIR)
./$(BUILDDIR)/updatebuilder -i $< $(BUILDDIR)rtlplayground.bin
$(BUILDDIR)/rtlplayground_oem_upgrade.bin: $(BUILDDIR)/rtlinstaller.ihx ../$(BUILDDIR)/rtlplayground.bin
./$(BUILDDIR)/updatebuilder -i $< -o $(BUILDDIR)/rtlplayground_oem_upgrade.bin ../$(BUILDDIR)/rtlplayground.bin
clean:
rm -r $(BUILDDIR)
+531 -36
View File
@@ -1,6 +1,7 @@
#include "machine.h"
#include "rtl837x_pins.h"
#include "rtl837x_leds.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
#include "rtl837x_common.h"
@@ -27,7 +28,7 @@ __code const struct machine machine = {
.sfp_port[1].sds = 1,
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
/* Conditions for LED on:
* dual led orange: ledset_0 & ledset_2
@@ -73,6 +74,58 @@ __code const struct machine machine = {
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_6XH_X2
__code const struct machine machine = {
.machine_name = "keepLink KP-9000-6XH-X2",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
// Right SFP port
.sfp_port[1].pin_detect = GPIO37,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_2G5 | LEDS_LINK, // Left LED (Amber)
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Right LED (Green)
0,
0
},
{
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,
0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,
0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void) {
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_KP_9000_9XH_X_EU
__code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XH-X-EU",
@@ -89,7 +142,7 @@ __code const struct machine machine = {
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
LEDS_2G5 | LEDS_LINK,
@@ -100,9 +153,62 @@ __code const struct machine machine = {
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_9XHML_X
#elif defined MACHINE_KP_9000_9XHML_X_V2_2
__code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XHML-X",
.machine_name = "keepLink KP-9000-9XHML-X V2.2",
.isRTL8373 = 1,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
.phys_to_log_port = { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
.is_sfp = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
.led_sets = {
{ /* Set 0 for RJ45 connectors */
/* LED0: Right Green */
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
/* LED1: Left Orange */
LEDS_2G5 | LEDS_LINK,
/* LED2: Left Green */
LEDS_1G | LEDS_LINK,
/* LED3: None */
0,
}, { /* Set 1 for SFP port */
/* LED0: Single Green "9" LED */
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
/* LED1: D23 LED on PCB */
LEDS_1G | LEDS_LINK,
/* LED2: D22 LED on PCB */
LEDS_2G5 | LEDS_LINK,
/* LED3: Unused */
LEDS_COL | LEDS_DUPLEX,
}, { /* Set 2: Unused, but set to same things as stock firmware for consistency */
LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_LINK | LEDS_ACT | LEDS_5G,
LEDS_10G | LEDS_ACT | LEDS_LINK,
}, { /* Set 3: Unused, but set to same things as stock firmware for consistency */
LEDS_TX,
LEDS_RX,
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_9XHML_X_V3_1
__code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XHML-X V3.1",
.isRTL8373 = 1,
.min_port = 0,
.max_port = 8,
@@ -115,7 +221,7 @@ __code const struct machine machine = {
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{ /* RJ45: First LED, yellow, second LED: green */
@@ -137,9 +243,52 @@ __code const struct machine machine = {
void machine_custom_init(void) { }
#elif defined MACHINE_SWGT024_V2_0
#elif defined MACHINE_SWGT024_V2_0_MANAGED
__code const struct machine machine = {
.machine_name = "SWGT024 V2.0",
.machine_name = "SWGT024 V2.0 Managed",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp= {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port (J4)
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
// Right SFP port (J2)
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* RJ45: Green LED */
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0,
/* Amber LED */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0
}, { /* SFP PORT: SINGLE GREEN LED */
LEDS_10M | LEDS_100M | LEDS_1G | LEDS_2G5 | LEDS_10G | LEDS_LINK | LEDS_ACT,
0,
0,
0,
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_SWGT024_V2_0_UNMANAGED
__code const struct machine machine = {
.machine_name = "SWGT024 V2.0 Unmanaged",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
@@ -159,19 +308,23 @@ __code const struct machine machine = {
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
.reset_pin = GPIO36_PWM_OUT,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
/* Conditions for LED on:
* dual led orange: ledset_0 & ledset_2
* dual led green: ledset_2 & !ledset_0
* single right led green: ledset_0 & !ledset_1
*/
.led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
LEDS_2G5 | LEDS_LINK | LEDS_10G,
LEDS_1G | LEDS_LINK,
0 },
},
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* RJ45: Green LED */
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0,
/* Amber LED */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0
}, { /* SFP PORT: SINGLE GREEN LED */
LEDS_10M | LEDS_100M | LEDS_1G | LEDS_2G5 | LEDS_10G | LEDS_LINK | LEDS_ACT,
0,
0,
0,
},
},
};
void machine_custom_init(void) { }
@@ -192,7 +345,7 @@ __code const struct machine machine = {
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{ /* RJ45: First LED, yellow, second LED: green */
@@ -231,12 +384,12 @@ __code const struct machine machine = {
.sfp_port[0].pin_los = 10,
.sfp_port[0].pin_tx_disable = 0xFF,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c_bus ={ .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.sfp_port[1].pin_detect = 30,
.sfp_port[1].pin_los = 51,
.sfp_port[1].pin_tx_disable = 0xFF,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c_bus = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
@@ -274,7 +427,7 @@ __code const struct machine machine = {
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
0, // unused
@@ -289,6 +442,39 @@ __code const struct machine machine = {
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs
__code const struct machine machine = {
.machine_name = "Lianguo ZX-SWTGW215AS",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
0, // unused
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
0
}, // unused
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
0, // unused
0, // unused
0
}, // unused },
},
.led_mux_custom = 0,
};
void machine_custom_init(void) { }
#elif defined MACHINE_DEFAULT_8C_1SFP
@@ -307,7 +493,7 @@ __code const struct machine machine = {
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | LED_29 },
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
LEDS_2G5 | LEDS_LINK,
@@ -326,26 +512,42 @@ __code const struct machine machine = {
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO36_PWM_OUT,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
.sfp_port[0].sds = 0,
.sfp_port[0].i2c = { .sda = GPIO47_I2C_SDA0, .scl = GPIO46_I2C_SCL0 },
.sfp_port[1].pin_detect = GPIO38,
.sfp_port[1].pin_los = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_tx_disable = GPIO54_ACL_BIT2_EN,
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
.sfp_port[1].pin_los = GPIO37,
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].sds = 1,
.sfp_port[1].i2c = { .sda = GPIO49_I2C_SDA1, .scl = GPIO48_I2C_SCL1 },
.reset_pin = GPIO_NA,
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
0, // Unused
LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber
0 // Unused
},
{
0, // Unused
0, // Unused
LEDS_10G | LEDS_1G | LEDS_LINK | LEDS_ACT, // Green
0, // Unused
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_HI_K0402WS
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS) // Sold as a variety of devices, see doc/
__code const struct machine machine = {
.machine_name = "HiSource HI-K0402WS",
.machine_name = "PCB-K0402WS-V3.0",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
@@ -367,7 +569,7 @@ __code const struct machine machine = {
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_28 | LED_29, .enable = LED_27 | LED_28 | LED_29 },
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
@@ -392,6 +594,299 @@ __code const struct machine machine = {
void machine_custom_init(void) {
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_K0501W_V2_0
__code const struct machine machine = {
.machine_name = "K0501W V2.0",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0
},
{
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_ZX310S_4T2XH
__code const struct machine machine = {
.machine_name = "ZX310S-4T2XH",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.n_10g = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x3f, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
/* Ports 1-4: Orange: 2.5GBit, Green: 10/100/1000MBit
* Port 5: Blue: 10GBit, Green: 10Mbit-5GBit
* SFP-port: Blue: 10GBit, Green 100MBit-5GBit
*/
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT | LEDS_5G,
LEDS_LINK | LEDS_ACT | LEDS_10G,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
}
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_HI_K0801WS
__code const struct machine machine = {
.machine_name = "Hi-Source HI-k0801WS",
.isRTL8373 = 1,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = {
.sda = GPIO39_I2C_SDA4,
.scl = GPIO40_I2C_SCL3_MDC1
},
.reset_pin = GPIO_NA,
.high_leds = {
.mux = LED_27 | LED_29,
.enable = LED_28_SYS | LED_29
},
/* Ports 1-8 use set 0, port 9 SFP uses set 1 */
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{ /* Set 0: RJ45 copper ports
* Amber = 2.5G
* Green = 1G/100M/10M with activity
*/
LEDS_2G5 | LEDS_LINK | LEDS_ACT, /* Amber */
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* Green */
0
},
{ /* Set 1: SFP port, single green LED for all valid speeds */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_FNS1200P
__code const struct machine machine = {
.machine_name = "FNS-1200P",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
/* Left SFP (logical 8, SDS1): GPIO30=ModAbs, GPIO37=RX_LOS */
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
/* Copper ports use SET0; SFP ports use SET1 */
.port_led_set = {0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* SET0: copper — LED0=amber (2.5G), LED2=green (1G/100M/10M) */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0
},
{ /* SET1: SFP — all speeds link/act */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0, 0
},
},
.led_mux_custom = 1,
.led_mux = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* GPIO0-7: unused */
0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, /* GPIO8-14 */
0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, /* GPIO15-20 */
0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 /* GPIO21-27 */
},
};
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
__code const struct machine machine = {
.machine_name = "PCB-SWTG024AS-A-2.0.1",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
// SFP port on SDS0 / logical port 3
.sfp_port[0].pin_detect = GPIO37,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 0,
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
// SFP port on SDS1 / logical port 8
.sfp_port[1].pin_detect = GPIO38,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 1,
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT
},
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
}
#elif defined MACHINE_ZX310S_4T2XT
__code const struct machine machine = {
.machine_name = "ZX310S_4T2XT",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 0,
.n_10g = 2,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 0},
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x3f, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
/* Ports 1-4: Green: 2.5GBit, Orange: 10/100/1000MBit
* Ports 5-6: Green: 10GBit, Orange: <= 5GBit
*/
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_5G,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
}
},
};
void machine_custom_init(void) {
// For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000,
// which would disables all LEDS, enable them manually:
REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf);
}
#else
#error "Please select a machine type in machine.h"
#endif
+23 -5
View File
@@ -8,16 +8,25 @@
*/
// #define MACHINE_KP_9000_6XHML_X2
// #define MACHINE_KP_9000_6XH_X
// #define MACHINE_KP_9000_6XH_X2
// #define MACHINE_KP_9000_9XH_X_EU
// #define MACHINE_KP_9000_9XHML_X
// #define MACHINE_SWGT024_V2_0
// #define MACHINE_HORACO_ZX_SG4T2
// #define MACHINE_KP_9000_9XHML_X_V2_2
// #define MACHINE_KP_9000_9XHML_X_V3_1
// #define MACHINE_SWGT024_V2_0_MANAGED
// #define MACHINE_SWGT024_V2_0_UNMANAGED
// #define MACHINE_TRENDNET_TEG_S562
// #define MACHINE_HG0402XG_V1_1
// #define MACHINE_SWTG018AS_A_V_2_0
// #define MACHINE_SWTGW218AS
// #define MACHINE_HI_K0402WS
// #define MACHINE_PCB_K0402WS_V3
// #define MACHINE_K0501W_V2_0
// #define MACHINE_LIANGUO_ZX_SWTGW215AS
// #define MACHINE_ZX310S_4T2XH
// #define MACHINE_ZX310S_4T2XT
// #define MACHINE_DEFAULT_8C_1SFP
// #define MACHINE_HI_K0801WS
// #define MACHINE_FNS1200P
// #define MACHINE_PCB_SWTG024AS_A_2_0_1
typedef struct {
// GPIO pins for SDA/SCL
@@ -27,7 +36,8 @@ typedef struct {
#define LED_27 1
#define LED_28 2
// SYSTEM LED
#define LED_28_SYS 2
#define LED_29 4
struct high_leds {
@@ -49,9 +59,12 @@ struct sfp_port
typedef struct machine {
char machine_name[30];
uint8_t isRTL8373;
// Lowest logical port number
uint8_t min_port;
// Highest logical port number
uint8_t max_port;
uint8_t n_sfp;
uint8_t n_10g;
uint8_t log_to_phys_port[9];
uint8_t phys_to_log_port[9]; // Starts at 0 for port 1
uint8_t is_sfp[9]; // 0 for non-SFP ports 1 or 2 for the I2C port number
@@ -59,7 +72,12 @@ typedef struct machine {
struct sfp_port sfp_port[2];
uint8_t reset_pin;
struct high_leds high_leds;
// Defines which led-set (0-3) will be used for given logical port
// led-set is physical group of LEDs that can be configured to show different port status combinations (see port_led_set below)
uint8_t port_led_set[9];
// Defines led-set configuration, applied to all ports using particular led-set
// Each led-set can have 4 different hardware LED configurations. Which one should be used, depends how LED is wired on the board
// See stock RTL837X_REG_LED3_2_SETx and RTL837X_REG_LED1_0_SETx registers for reference configuration
uint32_t led_sets[4][4];
uint8_t led_mux_custom;
uint8_t led_mux[28];
+7 -2
View File
@@ -22,16 +22,21 @@
#define PHY_ANEG_CTRL 0x00
#define PHY_ANEG_ADV 0x10
#define PHY_ANEG_LP_ABILITY 0x13
#define PHY_ANEG_MGBASE_CTRL 0x20
#define PHY_ANEG_MGBASE_ADV 0x21
#define PHY_ANEG_MGBASE_CTRL 0x20
#define PHY_ANEG_MGBASE_ADV 0x21
#define PHY_EEE_ADV 0x3c
#define PHY_EEE_LP_ABILITY 0x3d
#define PHY_EEE_ADV2 0x3e
#define PHY_EEE_LP_ABILITY2 0x3f
// Register bits for EEE capabilities at a given speed
// PHY_EEE_ADV2
#define PHY_EEE_BIT_2G5 0x01
#define PHY_EEE_BIT_5G 0x02
// PHY_EEE_ADV
#define PHY_EEE_BIT_1G 0x04
#define PHY_EEE_BIT_100M 0x02
#define PHY_EEE_BIT_10G 0x08
/*
* MMD 31 Registers
+34 -5
View File
@@ -36,12 +36,20 @@ extern __xdata uint8_t sbuf[SBUF_SIZE];
// Size of the TCP Output buffer
#define TCP_OUTBUF_SIZE 2500
// Size of the port name, including the terminating null byte
#define PORT_NAME_SIZE 32
// Size of the memory area dedicated to VLAN-names
#define VLAN_NAMES_SIZE 1024
// Size of the flash buffer used for writing to flash, must be a multiple of the flash page size (0x100)
#define FLASH_BUF_SIZE 512
// Errors for commands
#define ERR_OK 0
#define ERR_TOO_MANY_ARGUMENTS 1
#define ERR_CMD_TOO_LONG 2
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
// the VLAN tag is inserted after the RTL tag
@@ -62,10 +70,11 @@ struct vlan_tag {
#define RTL_TAG_SIZE (sizeof (struct rtl_tag))
#define VLAN_TAG_SIZE (sizeof (struct vlan_tag))
#define RTL_FRAME_TAG_ID 0x8899
#define RTL_FRAME_TAG_VERSION 0x04
// For RX and TX, an 8 byte header describing the frame to be moved to the Asic
// and received from the Asic is used
#define RTL_FRAME_HEADER_SIZE 8
// For TX, an 8 byte (plus 4 byte padding when when VLAN is enabled)
// header describing the frame to be moved to the Asic is used
#define RTL_FRAME_DESC_SIZE 12
// This is the standard size of an Ethernet frame header
#define ETHER_HEADER_SIZE 14
@@ -83,6 +92,15 @@ struct vlan_tag {
#define CMD_HISTORY_SIZE 0x400
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
enum sfp_speeds {
SFP_SPEED_AUTO = 0,
SFP_SPEED_100M,
SFP_SPEED_1G,
SFP_SPEED_2G5,
SFP_SPEED_5G,
SFP_SPEED_10G
};
/**
* Representation of a 48-bit Ethernet address.
*/
@@ -95,10 +113,13 @@ struct flash_region_t {
uint16_t len;
};
extern __xdata char port_names[9][PORT_NAME_SIZE];
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
extern __xdata struct uip_eth_addr uip_ethaddr;
// Headers for calls in the common code area (HOME/BANK0)
void print_string_no_syslog(__code char *p);
void print_string(__code char *p);
void print_string_x(__xdata char *p);
void print_long(uint32_t a);
@@ -107,6 +128,7 @@ void print_byte(uint8_t a);
void itoa(uint8_t v);
void print_sfr_data(void);
void print_phy_data(void);
void print_cmd_prompt(void);
void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v);
void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v);
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg);
@@ -115,8 +137,11 @@ void reg_read(uint16_t reg_addr);
void reg_read_m(uint16_t reg_addr);
void reg_write(uint16_t reg_addr);
void reg_write_m(uint16_t reg_addr);
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
void delay(uint16_t t);
void sleep(uint16_t t);
void write_char_no_syslog(char c);
void write_char(char c);
void print_reg(uint16_t reg);
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg);
@@ -136,9 +161,13 @@ uint16_t strcpy(register __xdata uint8_t *dst, register const char *s);
void tcpip_output(void);
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
void get_random_32(void);
void read_reg_timer(uint32_t * tmr);
void read_reg_timer(__xdata uint32_t * tmr);
void sfp_print_info(uint8_t sfp);
bool gpio_pin_test(uint8_t pin);
void set_sys_led_state(uint8_t state);
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
void sds_config_mac(uint8_t sds, uint8_t mode);
void sds_config(uint8_t sds, uint8_t mode);
void handle_sfp(void);
#endif
+11
View File
@@ -1,6 +1,16 @@
#ifndef _RTL837X_FLASH_H_
#define _RTL837X_FLASH_H_
// SPI FLASH MEMORY PAGE SIZE.
#define FLASH_PAGE_SIZE 0x100
// SPI FLASH MEMORY SECTOR SIZE = ERASE SIZE.
#define FLASH_SECTOR_SIZE 0x1000
#if (FLASH_SECTOR_SIZE % FLASH_PAGE_SIZE) != 0
#error "FLASH_SECTOR_SIZE must be a multiple of FLASH_PAGE_SIZE"
#endif
void flash_init(uint8_t enable_dio);
void flash_read_uid(void);
void flash_write_enable(void);
@@ -13,3 +23,4 @@ void flash_write_bytes(__xdata uint8_t *ptr);
__code char* get_flash_size_str(void);
#endif
+264
View File
@@ -0,0 +1,264 @@
#include <stdint.h>
#include "rtl837x_common.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
#include "rtl837x_port.h"
#include "rtl837x_phy.h"
#include "phy.h"
#include "machine.h"
extern __xdata uint8_t sfr_data[4];
extern __code struct machine machine;
extern __xdata struct machine_runtime machine_detected;
#pragma codeseg BANK2
#pragma constseg BANK2
/*
* Configure the PHY-Side of the SDS-SDS link between SoC and PHY
*/
void static sds_init(void)
{
phy_read(0, PHY_MMD30, 0xd);
uint16_t pval = SFR_DATA_U16;
// PHY Initialization:
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
delay(20);
pval &= 0xfff0;
pval |= 0x0a;
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
delay(10);
phy_write_mask(0x1, PHY_MMD30, 0xd, pval);
phy_read(0, PHY_MMD30, 0xd);
pval = SFR_DATA_U16;
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
pval &= 0xfff0;
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
phy_write_mask(0x1, PHY_MMD30, 0xd, pval);
if (machine_detected.isN) {
uint16_t pval;
print_string(" N-settings");
if (machine.n_10g)
print_string(" - 10g");
// Serdes 0 RX PN swap for 64B/66B
sds_read(1, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(1, 6, 2, pval | 0x2000);
// Serdes 1 RX PN swap for 8B/10B
sds_read(1, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(1, 0, 0, pval | 0x200);
// Serdes 0 RX PN swap for 64B/66B
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x2000);
if (!machine.n_10g) {
if (machine_detected.isRTL8373) {
// RTL8224: Serdes 0 RX PN swap for 64B/66B
// We assume that RTL8373N always paired with RTL8224N.
// This sds register value is 0x0000 at reset.
// So only write to it.
RTL8224_SDS_WRITE(0, 6, 2, 0x2000);
} else {
// Serdes 0 RX PN swap for 8B/10B
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x200);
}
} else if (machine.n_10g == 1) {
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
sfr_mask_data(0, 0x0f,0x0c);
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
REG_SET(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x0000596a);
} else if (machine.n_10g == 2) {
REG_SET(RTL837X_CFG_PHY_MDI_REVERSE, 0xc);
REG_SET(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x0000596a);
}
}
print_string("\nsds_init done\n");
}
void rtl8373_init(void) __banked
{
print_string("\nrtl8373_init called\n");
// r65d8:3ffbedff R65d8-3ffbedff
reg_bit_set(0x65d8, 0x1d);
sds_init();
// Disable all SERDES for configuration
REG_SET(RTL837X_REG_SDS_MODES, 0x000037ff);
// q000601:c800 Q000601:c804 q000601:c804 Q000601:c800
sds_read(0, 0x06, 0x01);
uint16_t pval = SFR_DATA_U16;
sds_write_v(0, 0x06, 0x01, pval | 0x04);
delay(50);
sds_read(0, 0x06, 0x01);
pval = SFR_DATA_U16;
sds_write_v(0, 0x06, 0x01, pval & 0xfffb);
phy_config_8224();
sds_config_mac(1, SDS_OFF); // Off for now until SFP+ port used
sds_config_mac(2, SDS_SGMII); // For RTL8224
sds_config(0, SDS_QXGMII); // For RTL8224
// SDS 1 setup
// q012100:4902 Q012100:4906 q013605:0000 Q013605:4000 Q011f02:001f q011f15:0086
sds_write_v(1, 0x21, 0x00, 0x4906);
sds_write_v(1, 0x36, 0x05, 0x4000);
sds_write_v(1, 0x1f, 0x02, 0x001f);
sds_read(1, 0x1f, 0x15);
pval = SFR_DATA_U16;
// r0a90:000000f3 R0a90-000000fc
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
sfr_mask_data(0, 0x0f,0x0c);
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
if (machine_detected.isN) {
print_string(" TX_POLARITY_SWAP\n");
// FOR N-Version: #TX_POLARITY_SWAP
reg_read_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
sfr_data[2] = 0x59;
sfr_data[3] = 0x6a;
reg_write_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
}
rtl8224_phy_enable();
// Disable PHYs for configuration
phy_write_mask(0xff,PHY_MMD31,0xa610,0x2858);
// Set bits 0x13 and 0x14 of 0x5fd4
// r5fd4:0002914a R5fd4-001a914a
reg_bit_set(0x5fd4, 0x13);
reg_bit_set(0x5fd4, 0x14);
// Configure ports
uint16_t reg = 0x1238; // Port base register for the bits we set
for (char i = 0; i < 9; i++) {
// Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag
REG_SET(reg, 0xe77);
reg += 0x100;
}
// r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031
reg_bit_set(0xb7c, 5);
// R7124-00001050 R7128-00001050 R712c-00001050 R7130-00001050 R7134-00001050 R7138-00001050
// R713c-00001050 R7140-00001050 R7144-00001050 R7148-00001050
REG_SET(0x7124, 0x1050); REG_SET(0x7128, 0x1050); REG_SET(0x712c, 0x1050);
REG_SET(0x7130, 0x1050); REG_SET(0x7134, 0x1050); REG_SET(0x7138, 0x1050);
REG_SET(0x713c, 0x1050); REG_SET(0x7140, 0x1050); REG_SET(0x7144, 0x1050);
REG_SET(0x7148, 0x1050);
reg_bit_set(RTL837X_REG_HW_CONF, 0);
// enable EEE for all ports at 2.5G, but don't reset the PHYs
port_eee_enable_all(EEE_2G5 | EEE_NORESET);
// TODO: patch the PHYs
// Re-enable PHY after configuration
phy_write_mask(0xff,PHY_MMD31,0xa610,0x2058);
// Enables MAC access
// Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init
// r632c:00000540 R632c-001f8540 // RTL8373: 001ff540
reg_read_m(0x632c);
sfr_mask_data(1, 0x70, 0xf0); // The ports of the RTL8824
sfr_mask_data(2, 0x10, 0x1f);
reg_write_m(0x632c);
print_string("\nrtl8373_init done\n");
}
void rtl8372_init(void) __banked
{
print_string("\nrtl8372_init called\n");
sds_init();
if (machine.n_10g != 2)
phy_config(8); // PHY configuration: External 8221B?
if (machine.n_10g)
phy_config_8261(3, 0);
if (machine.n_10g == 2)
phy_config_8261(8, 1);
else
phy_config(3); // PHY configuration: all internal PHYs?
// Set the MAC SerDes Modes Bits 0-4: SDS 0 = 0x2 (0x2), Bits 5-9: SDS 1: 1f (off)
// r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003e2 r7b20:000003e2 R7b20-000003e2
if (machine.n_10g == 1) {
REG_SET(RTL837X_REG_SDS_MODES, 0x3ed); // Disable SFP for now, set RTL8261BE SDS 0 to 0xd
} else if(machine.n_10g == 2) {
REG_SET(RTL837X_REG_SDS_MODES, 0x1ad); // Both 10g ports use SDS_QXGMII
} else {
reg_read_m(RTL837X_REG_SDS_MODES);
sfr_mask_data(1, 0, 0x03);
sfr_mask_data(0, 0, 0xe2);
reg_write_m(RTL837X_REG_SDS_MODES);
}
// r0a90:000000f3 R0a90-000000fc
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
sfr_mask_data(0, 0x0f, 0x0c);
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
// Disable PHYs for configuration
phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2858);
// Set bits 0x13 and 0x14 of 0x5fd4
// r5fd4:0002914a R5fd4-001a914a
reg_bit_set(0x5fd4, 0x13);
reg_bit_set(0x5fd4, 0x14);
// Configure ports 3-8:
//
// r1538:00000e33 R1538-00000e37 r1538:00000e37 R1538-00000e37 r1538:00000e37 R1538-00000f37
// [...]
///
uint16_t reg = 0x1238 + 0x300; // Port base register for the bits we set
for (char i = machine.min_port; i <= machine.max_port; i++) {
// Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag
REG_SET(reg, 0xe77);
reg += 0x100;
}
// r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031
reg_bit_set(0xb7c, 5);
reg_bit_set(RTL837X_REG_HW_CONF, 0);
// enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs
port_eee_enable_all(EEE_10G | EEE_NORESET);
// TODO: patch the PHYs
// Re-enable PHY after configuration
phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2058);
// Enables MAC access
// Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init
// r632c:00000540 R632c-001f8540 // RTL8373: 001ff540
reg_read_m(0x632c);
sfr_mask_data(1, 0x70, 0x80);
sfr_mask_data(2, 0x10, 0x1f);
reg_write_m(0x632c);
print_string("\nrtl8372_init done\n");
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef _RTL837X_INIT_H_
#define _RTL837X_INIT_H_
void rtl8372_init(void) __banked;
void rtl8373_init(void) __banked;
#endif
+6 -2
View File
@@ -35,6 +35,7 @@ void leds_dump(void) __banked
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
@@ -45,6 +46,7 @@ void leds_dump(void) __banked
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
print_string("RTL837X_REG_LED_MODE: "); print_reg(RTL837X_REG_LED_MODE); write_char('\n');
print_string("LED pad Configuration:\n");
for (uint8_t i = 0; i < 28; i++) {
print_byte(i);
@@ -190,7 +192,8 @@ void leds_setup(void) __banked
else
reg_bit_clear(RTL837X_PIN_MUX_0, 27);
if (machine.high_leds.mux & LED_28)
// SYSTEM LED
if (machine.high_leds.mux & LED_28_SYS)
reg_bit_set(RTL837X_PIN_MUX_0, 28);
else
reg_bit_clear(RTL837X_PIN_MUX_0, 28);
@@ -205,7 +208,8 @@ void leds_setup(void) __banked
else
reg_bit_clear(RTL837X_REG_LED_GLB_IO_EN, 27);
if (machine.high_leds.enable & LED_28)
// SYSTEM LED
if (machine.high_leds.enable & LED_28_SYS)
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 28);
else
reg_bit_clear(RTL837X_REG_LED_GLB_IO_EN, 28);
+98 -6
View File
@@ -86,6 +86,76 @@ void rtl8224_phy_enable(void) __banked
}
void phy_config_8261(uint8_t phy, uint8_t sds) __banked
{
print_string("phy_config_8261: phy "); print_byte(phy);
print_string(" sds "); print_byte(sds); write_char('\n');
phy_write(phy, PHY_MMD30, 0x141, 0x80aa); // P000008.1e000141:80aa P000008.1e000143:8c07 p031e.0143:0c07
phy_write(phy, PHY_MMD30, 0x143, 0x8c07);
phy_read(phy, PHY_MMD30, 0x143);
print_phy_data();
phy_write(phy, PHY_MMD30, 0x141, 0x5078); // P000008.1e000141:5078 P000008.1e000143:8c86 p031e.0143:0c86
phy_write(phy, PHY_MMD30, 0x143, 0x8c86);
phy_read(phy, PHY_MMD30, 0x143);
print_phy_data();
phy_read(phy, PHY_MMD30, 0x105);
print_phy_data(); // p031e.0105:0000
phy_write(phy, PHY_MMD30, 0xe1, 0x00); // P000008.1e0000e1:0000
phy_write(phy, PHY_MMD30, 0xe3, 0x00); // P000008.1e0000e3:0000
phy_write(phy, PHY_MMD30, 0xe4, 0x01); // P000008.1e0000e4:0001
phy_write(phy, PHY_MMD30, 0xe0, 0x2f); // P000008.1e0000e0:002f
// The following are actually bit-ops:
phy_write(phy, PHY_MMD31, 0xa442, 0x8418); // p031f.a442:0418 P000008.1f00a442:8418
phy_write(phy, PHY_MMD31, 0xa448, 0x07a0); // p031f.a448:07a0 P000008.1f00a448:07a0
phy_write(phy, PHY_MMD31, 0xa43a, 0x003f); // p031f.a43a:0030 P000008.1e0000e2:003f
phy_write(phy, PHY_MMD31, 0xc800, 0x5a02); // P000008.1f00c800:5a02
phy_write(phy, PHY_MMD30, 0x01ee, 0x5a02); // p031e.01ee:5a00 P000008.1e0001ee:5a02
phy_write(phy, PHY_MMD30, 0x0230, 0x0002); // p031e.0230:0000 P000008.1e000230:0002
phy_write(phy, PHY_MMD31, 0xc802, 0x0073); // p031f.c802:0000 P000008.1f00c802:0073
phy_write(phy, PHY_MMD30, 0x01ef, 0xe004); // p031e.01ef:0004 P000008.1e0001ef:e004
delay(20);
phy_write(phy, PHY_MMD30, 0x01ef, 0x0004); // p031e.01ef:e004 P000008.1e0001ef:0004
delay(20);
phy_write(phy, PHY_MMD30, 0x0230, 0x01c2); // p031e.0230:01c2 P000008.1e000230:0002
phy_read(phy, PHY_MMD30, 0x103);
print_phy_data(); // p031e.0103:8261
phy_write(phy, PHY_MMD30, 0x01c8, 0x0104); // p031e.01c8:0104 P000008.1e0001c8:0104
phy_write(phy, PHY_MMD30, 0x01c9, 0x8080); // p031e.01c9:8080 P000008.1e0001c9:8080
phy_write(phy, PHY_MMD30, 0x01ca, 0x2020); // p031e.01ca:2020 P000008.1e0001ca:2020
phy_write(phy, PHY_MMD30, 0x0105, 0x0000); // p031e.0105:0000 P000008.1e000105:0000
phy_write(phy, PHY_MMD30, 0x00c2, 0x880d); // p031e.00c2:880d P000008.1e0000c2:880d
phy_write(phy, PHY_MMD30, 0x03f1, 0x0072); // p031e.03f1:0072 P000008.1e0003f1:0072
phy_write(phy, PHY_MMD30, 0x02a2, 0x0010); // p031e.02a2:0010 P000008.1e0002a2:0010
phy_write(phy, PHY_MMD30, 0x00c1, 0x0127); // p031e.00c1:0127 P000008.1e0000c1:0127
phy_write(phy, PHY_MMD30, 0x00c1, 0x0167); // p031e.00c1:0127 P000008.1e0000c1:0167
sds_write_v(sds, 0x21, 0x00, 0x4096); // Q002100:4906
sds_write_v(sds, 0x36, 0x05, 0x4000); // Q003605:4000
sds_write_v(sds, 0x1f, 0x02, 0x001f); // Q001f02:001f
phy_read(phy, 0x01, 0x0000);
print_phy_data(); // p0301.0000:2040
phy_write(phy, 0x01, 0x0000, 0x2040); // P000008.01000000:2040
delay(20);
sds_write_v(sds, 0, 0, 0x1603); // Q000000:1603
delay(20);
sds_write_v(sds, 0, 0, 0x1601); // Q000000:1601
delay(20);
sds_write_v(sds, 0, 0, 0x1603); //Q000000:1603
delay(20);
// r6330:00005555 R6330-00005555 r7b20:000003ed R7b20-000003ed
print_string("\r\nphy_config_8261 done\n");
}
void phy_config(uint8_t phy) __banked
{
print_string("\r\nphy_config: ");
@@ -193,6 +263,10 @@ void phy_set_speed(void) __banked
uint16_t v;
print_string("Setting port "); write_char(machine.log_to_phys_port[phy_settings.port] + '0');
if (machine.n_10g && phy_settings.port == 3)
phy_settings.is10g_port = 1;
if (machine.n_10g == 2 && phy_settings.port == 8)
phy_settings.is10g_port = 1;
if (phy_settings.speed == PHY_OFF) {
print_string(" to disabled");
} else {
@@ -200,6 +274,8 @@ void phy_set_speed(void) __banked
switch(phy_settings.speed) {
case PHY_SPEED_AUTO:
print_string("auto");
if (phy_settings.is10g_port)
print_string (" (10g)");
break;
case PHY_SPEED_10M:
print_string("10M");
@@ -246,7 +322,10 @@ void phy_set_speed(void) __banked
// bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200); // Loop timing enabled
if (phy_settings.is10g_port)
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0e00);
else
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200);
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_CTRL, 0x3200); // Restart AN
} else {
// AN Control Register (MMD 7.0x0000)
@@ -285,6 +364,12 @@ void phy_set_speed(void) __banked
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
} else if (phy_settings.speed == PHY_SPEED_5G) {
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0400, 0x0000);
} else if (phy_settings.speed == PHY_SPEED_10G) {
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0800, 0x0000);
}
}
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_CTRL, 0x3000); // Enable AN
@@ -367,12 +452,15 @@ void phy_show(uint8_t port) __banked
print_string("5G");
break;
default:
print_string("10M");
print_string("Down");
}
if ( (((v & 0x0600) >> 7) | ((v & 0x0030) >> 4)) <= 6) { // Link is up
if (v & 0x8)
print_string(" full duplex");
else
print_string(" half duplex");
}
if (v & 0x8)
print_string(" full duplex");
else
print_string(" half duplex");
phy_read(port, PHY_MMD_AN, PHY_ANEG_CTRL);
v = SFR_DATA_U16;
@@ -439,6 +527,10 @@ void phy_show(uint8_t port) __banked
v = SFR_DATA_U16;
if (v & 0x0080)
print_string(" 2500BaseN-Full");
if (v & 0x0100)
print_string(" 5000BaseN-Full");
if (v & 0x1000)
print_string(" 10GBaseN-Full");
}
phy_read(port, PHY_MMD_AN, PHY_ANEG_LP_ABILITY);
v = SFR_DATA_U16;
+2
View File
@@ -14,6 +14,7 @@ struct phy_settings {
uint8_t duplex;
uint8_t port;
uint8_t speed;
uint8_t is10g_port;
};
extern __xdata struct phy_settings phy_settings;
@@ -28,6 +29,7 @@ void phy_reset(uint8_t port) __banked;
void rtl8224_read_reg_u16(uint16_t reg) __banked;
void rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked;
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t val) __banked;
void phy_config_8261(uint8_t phy, uint8_t sds) __banked;
#define RTL8224_SDS_WRITE(sds_id, page, reg, v) uint16_t _sdscmd = (uint16_t)(sds_id & 0x01) | (1 << 14) | (1 << 15); \
_sdscmd |= (page & 0x3F) << 1; \
+10 -7
View File
@@ -2,7 +2,10 @@
#include "rtl837x_common.h"
#include "rtl837x_regs.h"
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) {
#pragma codeseg BANK2
#pragma constseg BANK2
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked {
switch (sda_pin) {
case GPIO47_I2C_SDA0:
return 0;
@@ -19,7 +22,7 @@ uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) {
}
}
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) {
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked{
switch (scl_pin) {
case GPIO46_I2C_SCL0:
return 0;
@@ -35,18 +38,18 @@ uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) {
}
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
static uint16_t gpio_output_reg(uint8_t pin) {
static uint16_t gpio_output_reg(uint8_t pin) __banked{
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
}
/* Returns RTL837X_REG_GPIO_XX_DIRECTION register address */
static uint16_t gpio_direction_reg(uint8_t pin) {
static uint16_t gpio_direction_reg(uint8_t pin) __banked {
return pin < 32 ? RTL837X_REG_GPIO_00_31_DIRECTION : RTL837X_REG_GPIO_32_63_DIRECTION;
}
/* Enable GPIO functions for pin */
static void gpio_mux_setup(uint8_t pin)
static void gpio_mux_setup(uint8_t pin) __banked
{
// Some GPIOs require setting MUX registers to enable GPIO
switch (pin) {
@@ -94,7 +97,7 @@ static void gpio_mux_setup(uint8_t pin)
}
}
void gpio_input_setup(uint8_t pin) {
void gpio_input_setup(uint8_t pin) __banked {
if (pin == GPIO_NA) {
return;
}
@@ -103,7 +106,7 @@ void gpio_input_setup(uint8_t pin) {
reg_bit_clear(gpio_direction_reg(pin), (pin % 32));
}
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) {
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked{
if (pin == GPIO_NA) {
return;
}
+4 -4
View File
@@ -72,22 +72,22 @@
#define GPIO_NA 0xFF
/* Convert SDA PIN GPIO to I2C bus number */
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin);
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked;
/* Convert SCL PIN GPIO to I2C bus number */
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin);
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked;
/*
* Setup a GPIO pin as input
* pin: GPIO pin number 0-63
*/
void gpio_input_setup(uint8_t pin);
void gpio_input_setup(uint8_t pin) __banked;
/*
* Setup a GPIO pin as output
* pin: GPIO pin number 0-63
* initial_val: 1 for bit set in RTL837X_REG_GPIO_xx_OUTPUT, 0 for bit not set
*/
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val);
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked;
#endif
+226 -20
View File
@@ -35,6 +35,7 @@ void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata u
print_string("\nport_mirror_set called \n");
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
print_short(rx_pmask); print_string(", tx mask: "); print_short(tx_pmask);
write_char('\n');
REG_WRITE(RTL837x_MIRROR_CONF, rx_pmask >> 8, rx_pmask, tx_pmask >> 8, tx_pmask);
REG_WRITE(RTL837x_MIRROR_CTRL, 0, 0, 0, (port << 1) | 0x1);
@@ -48,16 +49,38 @@ void port_mirror_del(void) __banked
}
void port_ingress_filter(__xdata uint8_t port, __xdata uint8_t type) __banked
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked
{
if (type & 0x1)
if (port > 9 || type >= VLAN_INVALID) {
print_string("Invalid port or ingress filter type\n");
return false;
}
if (type & 0x1) {
reg_bit_set(RTL837x_REG_INGRESS, port << 1);
else
} else {
reg_bit_clear(RTL837x_REG_INGRESS, port << 1);
if (type & 0x2)
}
if (type & 0x2) {
reg_bit_set(RTL837x_REG_INGRESS, (port << 1) + 1);
else
} else {
reg_bit_clear(RTL837x_REG_INGRESS, (port << 1) + 1);
}
return true;
}
vlan_ingress_mode_t port_ingress_filter_get(__xdata uint8_t port) __banked
{
reg_read_m(RTL837x_REG_INGRESS);
if (port > 9) {
return VLAN_INVALID;
}
// Each port is represented by 2 bits in the ingress register, starting from bit 0 for port 0
const uint8_t sfr_index = 3 - (port / 4);
const uint8_t shift = (port % 4) << 1;
return (vlan_ingress_mode_t)((sfr_data[sfr_index] >> shift) & 0x03);
}
@@ -78,22 +101,67 @@ void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked
}
}
uint16_t port_pvid_get(uint8_t port) __banked
{
uint16_t reg = RTL837x_PVID_BASE_REG + ((port >> 1) << 2);
reg_read_m(reg);
if (port & 0x1) {
return (sfr_data[1] << 4) | (sfr_data[2] >> 4);
} else {
return ((sfr_data[2] & 0x0f) << 8) | sfr_data[3];
}
}
void vlan_delete(uint16_t vlan) __banked
{
print_string("\nvlan_delete called \n"); print_short(vlan);
vlan_name_remove(vlan);
REG_WRITE(RTL837x_TBL_DATA_IN_A, 0, 0, 0, 0);
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE);
}
void vlan_name_remove(uint16_t vlan) __banked
{
static __xdata uint16_t name_pos;
static __xdata uint16_t entry_start;
static __xdata uint16_t pos;
static __xdata uint16_t entry_len;
static __xdata uint16_t move_count;
static __xdata uint16_t j;
name_pos = vlan_name(vlan);
if (name_pos == 0xffff)
return;
entry_start = name_pos - 3;
pos = entry_start;
while (pos < vlan_ptr && vlan_names[pos] != ' ')
pos++;
if (pos >= vlan_ptr)
return;
pos++;
entry_len = pos - entry_start;
move_count = vlan_ptr - pos;
for (j = 0; j < move_count; j++)
vlan_names[entry_start + j] = vlan_names[pos + j];
vlan_ptr -= entry_len;
vlan_names[vlan_ptr] = 0;
}
/*
* Reads VLAN information from VLAN table
* Returns data in sfr_data
*/
int8_t vlan_get(register uint16_t vlan) __banked
{
if (vlan >= 0x3ff) // VLAN 4095 is special
if (vlan >= 0xfff) // VLAN 4095 is special
return -1;
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_EXECUTE);
@@ -199,7 +267,8 @@ void vlan_setup(void) __banked
// EGRESS filtering for port: removal of additional VLAN tag (mode 0x3 for each port)
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, i << 1);
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, (i << 1) + 1);
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, i);
// Enable INGRESS filtering for port: discard packets not belonging to member VLAN on that port
port_ingress_vlan_filter_set(i, true);
#ifdef DEBUG
print_string("\n");
@@ -224,6 +293,7 @@ void vlan_setup(void) __banked
#ifdef DEBUG
print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738);
print_string("\nvlan_setup, REG 0x4e10: "); print_reg(0x4e10);
print_string("\nvlan_setup, REG 0x4e18: "); print_reg(0x4e18);
print_string("\nvlan_setup, REG 0x4e14: "); print_reg(0x4e14);
print_string("\nvlan_setup, REG 0x4e30: "); print_reg(0x4e30);
@@ -351,7 +421,7 @@ void port_l2_setup(void) __banked
void port_stats_print(void) __banked
{
print_string("\n Port\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n");
print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n");
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
write_char('0' + machine.log_to_phys_port[i]); write_char('\t');
@@ -404,6 +474,9 @@ void port_stats_print(void) __banked
case 5:
print_string("2.5G\t");
break;
case 6:
print_string("5G\t");
break;
case 99:
print_string("Down\t");
break;
@@ -427,14 +500,14 @@ void port_stats_print(void) __banked
}
void port_isolate(register uint8_t port, __xdata uint16_t pmask)
void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked
{
if (port <= machine.max_port)
REG_SET(RTL837X_PORT_ISOLATION_BASE + (port << 2), pmask);
}
uint16_t port_isolation_get(register uint8_t port)
uint16_t port_isolation_get(register uint8_t port) __banked
{
if (port > machine.max_port)
return 0;
@@ -453,20 +526,19 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
return;
}
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
print_string("EEE on for "); print_byte(port); print_string(" speed ");
// Enable all speeds up to the specified speed
if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_100) {
if (speed & EEE_100) {
print_string("100m\n");
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100);
// Enable EEE advertisement for 100BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_100M);
if (!(speed & EEE_NORESET))
phy_reset(port);
return;
}
if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_1000) {
if (speed & EEE_1000) {
print_string("1g\n");
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100 | EEE_1000);
// Disable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, 0);
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
@@ -475,9 +547,8 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
phy_reset(port);
return;
}
if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_2G5) {
if (speed & EEE_2G5) {
print_string("2g5\n");
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100 | EEE_1000 | EEE_2G5);
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
// Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
@@ -486,6 +557,26 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
phy_reset(port);
return;
}
if (speed & EEE_5G) {
print_string("5g\n");
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
// Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, PHY_EEE_BIT_2G5 | PHY_EEE_BIT_5G);
if (!(speed & EEE_NORESET))
phy_reset(port);
return;
}
if (speed & EEE_10G) {
print_string("10g\n");
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_10G | PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
// Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, PHY_EEE_BIT_2G5 | PHY_EEE_BIT_5G);
if (!(speed & EEE_NORESET))
phy_reset(port);
return;
}
}
@@ -496,7 +587,7 @@ void port_eee_disable(uint8_t port) __banked
return;
print_string("EEE off for "); print_byte(port); write_char('\n');
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), 0);
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
// Disable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
@@ -516,8 +607,24 @@ void port_eee_status(uint8_t port) __banked
uint16_t v;
print_string("Advertising: ");
if (machine.n_10g) {
phy_read(port, PHY_MMD_AN, PHY_EEE_ADV);
v = SFR_DATA_U16;
if (v & PHY_EEE_BIT_10G)
print_string(" 10G");
else
print_string(" ");
}
phy_read(port, PHY_MMD_AN, PHY_EEE_ADV2);
v = SFR_DATA_U16;
if (machine.n_10g) {
if (v & PHY_EEE_BIT_5G)
print_string(" 5G");
else
print_string(" ");
}
v = SFR_DATA_U16;
if (v & PHY_EEE_BIT_2G5)
print_string(" 2.5G");
else
@@ -534,8 +641,22 @@ void port_eee_status(uint8_t port) __banked
print_string(" ");
print_string(" Link Partner: ");
if (machine.n_10g) {
phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY);
v = SFR_DATA_U16;
if (v & PHY_EEE_BIT_10G)
print_string(" 10G");
else
print_string(" ");
}
phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY2);
v = SFR_DATA_U16;
if (machine.n_10g) {
if (v & PHY_EEE_BIT_5G)
print_string(" 5G");
else
print_string(" ");
}
if (v & PHY_EEE_BIT_2G5)
print_string(" 2.5G");
else
@@ -563,7 +684,16 @@ void port_eee_status(uint8_t port) __banked
void port_eee_enable_all(__xdata uint8_t speed) __banked
{
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
port_eee_enable(i, speed);
if (i == 3 && machine.n_10g) {
port_eee_enable(i, speed);
} else if (i == 8 && machine.n_10g == 2) {
port_eee_enable(i, speed);
} else {
if (speed & EEE_10G)
port_eee_enable(i, speed & EEE_NORESET | EEE_2G5);
else
port_eee_enable(i, speed);
}
}
}
@@ -605,8 +735,9 @@ void port_rldp_on(__xdata uint16_t p_ms)
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked
{
print_string("port_lag_members_set, lag: "); print_byte(lag); print_string(", members: "); print_short(members);
write_char('\n');
if (lag > 3)
print_string("Link aggregation group must be 0-3!");
print_string("Link aggregation group must be 0-3!\n");
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2));
if (!(sfr_data[0] | sfr_data [1] | sfr_data [2] | sfr_data [3]))
REG_SET(RTL837X_TRK_HASH_CTRL_BASE, LAG_HASH_DEFAULT);
@@ -621,7 +752,82 @@ void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banke
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked
{
print_string("port_lag_hash_set, lag: "); print_byte(lag); print_string(", hash: "); print_byte(hash_bits);
write_char('\n');
if (lag > 3)
print_string("Link aggregation group must be 0-3!");
print_string("Link aggregation group must be 0-3!\n");
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
}
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked
{
switch (mode) {
case VLAN_UNTAGGED:
print_string("Untag.");
break;
case VLAN_TAGGED:
print_string("Tagged");
break;
case VLAN_ALL:
print_string("Any");
break;
default:
print_string("!!err!!");
}
}
static void print_phys_port(uint8_t port) __banked
{
if (port >= machine.min_port && port <= machine.max_port)
write_char(machine.log_to_phys_port[port] + '0');
else if (port == 9)
write_char('9');
else
write_char('?');
}
void print_vlan_ingress_port(uint8_t log_port) __banked
{
print_phys_port(log_port);write_char('\t');
print_short(port_pvid_get(log_port));write_char('\t');
print_port_ingress_filter_mode(port_ingress_filter_get(log_port));write_char('\t');
port_ingress_vlan_filter_get(log_port) ? print_string("Enabled") : print_string("Disabled");
write_char('\n');
}
/*
* Dumps the VLAN ingress configuration
*/
void vlan_dump(void) __banked
{
print_string("Ingress VLAN configuration:\n");
print_string("Port\tPVID\tType\tFiltering\n");
for (uint8_t port = machine.min_port; port <= machine.max_port; port++) {
print_vlan_ingress_port(port);
}
print_vlan_ingress_port(9);
write_char('\n');
print_string("Type - Which frame types are allowed: untagged, tagged or any\n");
print_string("Filtering - Whether packets not belonging to member VLANs on that port are dropped\n");
print_string("PVID - Assumed VLAN for untagged packets\n");
}
/** Set the ingress VLAN filtering */
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked
{
if (port < machine.min_port || port > machine.max_port && port != 9) {
return false;
}
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, port);
return true;
}
/** Get the ingress VLAN filtering status */
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked
{
if (port < machine.min_port || port > machine.max_port && port != 9) {
return false;
}
return reg_bit_test(RTL837X_VLAN_PORT_IGR_FLTR, port);
}
+34 -1
View File
@@ -2,6 +2,7 @@
#define _RTL837X_PORT_H_
#include <stdint.h>
#include "rtl837x_regs.h"
#define STAT_COUNTER_TX_PKTS 46
#define STAT_COUNTER_RX_PKTS 47
@@ -13,12 +14,35 @@
reg_read_m(RTL837X_STAT_GET); \
} while (sfr_data[3] & 0x1);
// Possible values for ingress filter type
typedef enum {
VLAN_ALL = INGR_ALLOW_ALL,
VLAN_TAGGED = INGR_ALLOW_TAGGED,
VLAN_UNTAGGED = INGR_ALLOW_UNTAGGED,
VLAN_INVALID = 3
} vlan_ingress_mode_e;
// Since we lack a way to force enum to be 1 byte,
// This is a typedef for the VLAN ingress filter type
// which holds vlan_ingress_mode_e values
typedef uint8_t vlan_ingress_mode_t;
struct vlan_settings {
uint16_t vlan;
uint16_t members;
uint16_t tagged;
};
/*
* Port EEE settings
*/
#define EEE_100 0x01
#define EEE_1000 0x04
#define EEE_2G5 0x10
#define EEE_5G 0x20
#define EEE_10G 0x40
#define EEE_NORESET 0x80
extern __xdata struct vlan_settings vlan_settings;
uint8_t port_l2_forget(void) __banked;
@@ -26,13 +50,16 @@ void port_l2_learned(void) __banked;
void port_stats_print(void) __banked;
int8_t vlan_get(register uint16_t vlan) __banked;
__xdata uint16_t vlan_name(register uint16_t vlan) __banked;
void vlan_name_remove(uint16_t vlan) __banked;
void vlan_setup(void) __banked;
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
uint16_t port_pvid_get(uint8_t port) __banked;
void vlan_create(void) __banked;
void vlan_delete(uint16_t vlan) __banked;
void vlan_dump(void) __banked;
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked;
void port_mirror_del(void) __banked;
void port_ingress_filter(__xdata uint8_t port, __xdata uint8_t type) __banked;
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked;
void port_l2_setup(void) __banked;
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked;
@@ -42,4 +69,10 @@ void port_eee_status_all(void) __banked;
void port_eee_enable(__xdata uint8_t port, __xdata uint8_t speed) __banked;
void port_eee_disable(uint8_t port) __banked;
void port_eee_status(uint8_t port) __banked;
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked;
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked;
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked;
void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked;
uint16_t port_isolation_get(register uint8_t port) __banked;
#endif
+5 -6
View File
@@ -32,6 +32,7 @@
#define RTL837X_REG_LED_GLB_IO_EN 0x65DC
#define RTL837X_REG_LED3_0_SET3 0x6524
#define RTL837X_REG_LED3_0_SET1 0x6528
#define RTL837X_REG_LED3_2_SET3 0x652C
#define RTL837X_REG_LED1_0_SET3 0x6530
#define RTL837X_REG_LED3_2_SET2 0x6534
#define RTL837X_REG_LED1_0_SET2 0x6538
@@ -72,6 +73,7 @@
*/
#define SDS_SGMII 0x02
#define SDS_1000BX_FIBER 0x04
#define SDS_100FX 0x05
#define SDS_QXGMII 0x0d
#define SDS_HISGMII 0x12
#define SDS_HSG 0x16
@@ -268,14 +270,11 @@
/*
* EEE
*/
#define RTL837X_EEE_STATUS 0x125C
#define RTL837X_EEE_CTRL_BASE 0x125C
#define EEE_RX_ENABLE 0x01
#define EEE_TX_ENABLE 0x02
#define RTL837X_MAC_EEE_ABLTY 0x6404
#define RTL8373_PHY_EEE_ABLTY 0x642C
#define RTL8373_EEE_CTRL_BASE 0x606c
#define EEE_100 0x01
#define EEE_1000 0x04
#define EEE_2G5 0x10
#define EEE_NORESET 0x80
/*
* RANDOM
+5 -5
View File
@@ -62,7 +62,7 @@ struct stp_pkt_in {
uint8_t stp_addr[6];
uint8_t src_addr[6];
struct rtl_tag rtl_tag;
uint8_t vtag[4];
struct vlan_tag vlan_tag;
uint16_t msg_len;
uint8_t dsap;
uint8_t ssap;
@@ -82,7 +82,7 @@ struct stp_pkt_in {
uint16_t fwd_delay;
};
#define STP_O ((__xdata struct stp_pkt *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE])
#define STP_O ((__xdata struct stp_pkt *)&uip_buf[RTL_FRAME_DESC_SIZE])
#define STP_I ((__xdata struct stp_pkt_in *)&uip_buf[0])
#define FLAG_PROPOSAL 0x02
@@ -136,7 +136,7 @@ void stp_in(void) __banked
// print_string("Flags: "); print_byte(STP_I->flags); write_char('\n');
print_string("Check new Root\n");
if (STP_I->root.prio < root_bridge.prio
|| ((STP_I->root.prio == root_bridge.prio) && cmpMAC(STP_I->root.mac, STP_I->root.mac) < 0)) {
|| ((STP_I->root.prio == root_bridge.prio) && cmpMAC(STP_I->root.mac, root_bridge.mac) < 0)) {
print_string("Updating Root bridge\n");
root_bridge.prio = STP_I->root.prio;
memcpy(root_bridge.mac, STP_I->root.mac, 6);
@@ -149,8 +149,8 @@ void stp_cnf_send(uint8_t port)
STP_O->stp_addr[0] = 0x01; STP_O->stp_addr[1] = 0x80; STP_O->stp_addr[2] = 0xc2;
STP_O->stp_addr[3] = STP_O->stp_addr[4] = STP_O->stp_addr[5] = 0x00;
STP_O->rtl_tag.tag = HTONS(0x8899);
STP_O->rtl_tag.version = 0x04;
STP_O->rtl_tag.tag = HTONS(RTL_FRAME_TAG_ID);
STP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
STP_O->rtl_tag.reason = 0x00;
STP_O->rtl_tag.flags = 0x0020; // Disable L2 learning
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
+260 -281
View File
@@ -15,6 +15,7 @@
#include "rtl837x_igmp.h"
#include "rtl837x_leds.h"
#include "rtl837x_bandwidth.h"
#include "rtl837x_init.h"
#include "dhcp.h"
#include "cmd_parser.h"
#include "cmd_editor.h"
@@ -23,6 +24,7 @@
#include "uip/uip_arp.h"
#include "machine.h"
#include "phy.h"
#include "syslog.h"
extern __code const struct machine machine;
extern __xdata uint32_t flash_size;
@@ -30,6 +32,8 @@ extern __xdata uint32_t flash_size;
extern __xdata uint16_t crc_value;
__xdata struct machine_runtime machine_detected;
void crc16(__xdata uint8_t *v) __naked;
void flash_default_config(void);
void early_boot_handle_button(void);
// See setup_serial_timer1() for valid baudrate settings!
#define SERIAL_BAUD_RATE 115200
@@ -95,6 +99,7 @@ extern __xdata struct dhcp_state dhcp_state;
__xdata volatile uint8_t sbuf_ptr;
__xdata uint8_t sbuf[SBUF_SIZE];
// Registry data in sfr is in *big endian* order, so sfr_data[0] is the MSB and sfr_data[3] the LSB
__xdata uint8_t sfr_data[4];
extern __xdata uint8_t gpio_last_value[8];
@@ -124,17 +129,62 @@ __code uint16_t bit_mask[16] = {
__xdata uint8_t linkbits_last[4];
__xdata uint8_t linkbits_last_p89;
// Last known state of the SFP detection/Loss of Signal pins
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
__xdata uint8_t sfp_pins_last;
__xdata char sfp_module_vendor[2][17];
__xdata char sfp_module_model[2][17];
__xdata char sfp_module_serial[2][17];
__xdata uint8_t sfp_options[2];
__xdata uint8_t sfp_speed[2];
__xdata bool button_last;
__xdata uint8_t button_sec_counter_last;
__sbit tx_buf_empty;
volatile __bit tx_buf_empty;
struct eth_in {
struct uip_eth_addr dst;
struct uip_eth_addr src;
struct rtl_tag rtl_tag;
struct vlan_tag vlan_tag;
u16_t ether_type;
};
// Dot 1Q tag size is the size of tpid + tci
#define DOT_1Q_TAG_SIZE 4
struct q_frame {
uint8_t tx_seq;
uint8_t chksum_flags; // 0x7 enables Checksums for frame header, L2 and L3
uint8_t reserved_1 [2];
uint16_t len; // Length is Little Endian
uint8_t reserved_2 [2];
struct uip_eth_addr dst;
struct uip_eth_addr src;
uint16_t tpid;
uint16_t tci;
};
struct nonq_frame {
uint8_t padding[DOT_1Q_TAG_SIZE];
uint8_t tx_seq;
uint8_t chksum_flags; // 0x7 enables Checksums for frame header, L2 and L3
uint8_t reserved_1 [2];
uint16_t len; // Length is Little Endian
uint8_t reserved_2 [2];
struct uip_eth_addr dst;
struct uip_eth_addr src;
};
#define ETH_IN ((__xdata struct eth_in *)&uip_buf[0])
#define ETHERTYPE_OFFSET (12 + VLAN_TAG_SIZE + RTL_TAG_SIZE)
// The output frame structure with initial frame descriptor including padding
#define FRAME ((__xdata struct nonq_frame *)&uip_buf[0])
// The output frame structure with 802.1Q field and the padding moved before the buffer-start
#define FRAME_Q ((__xdata struct q_frame *)&uip_buf[0])
void isr_timer0(void) __interrupt(1)
{
}
@@ -167,7 +217,7 @@ void isr_serial(void) __interrupt(4)
}
void write_char(char c)
void write_char_no_syslog(char c)
{
do {
} while (tx_buf_empty == 0);
@@ -181,6 +231,17 @@ void write_char(char c)
SBUF = c;
}
void write_char(char c)
{
write_char_no_syslog(c);
if (syslog_state.enabled) {
logbuf[syslog_state.writeptr++] = c;
syslog_state.writeptr &= (LOGBUF_SIZE - 1);
if (c == '\n')
syslog_state.line_available = 1;
}
}
void itoa(uint8_t v)
{
@@ -204,6 +265,12 @@ void print_string(__code char *p)
write_char(*p++);
}
void print_string_no_syslog(__code char *p)
{
while (*p)
write_char_no_syslog(*p++);
}
void print_string_x(__xdata char *p)
{
while (*p)
@@ -301,6 +368,11 @@ void print_byte(uint8_t a)
write_char(low);
}
void print_cmd_prompt(void)
{
print_string_no_syslog("\n> ");
}
/*
* External IRQ 0 Service Routine: Called on link change?
* Note that all registers are being put on the STACK because of calling a subroutine
@@ -459,7 +531,7 @@ void reg_bit_clear(uint16_t reg_addr, char bit)
/*
* This sets a bit in the 32bit wide switch register reg_addr
* This tests a bit in the 32bit wide switch register reg_addr
*/
uint8_t reg_bit_test(uint16_t reg_addr, char bit)
{
@@ -551,15 +623,38 @@ void nic_rx_packet(register uint16_t buffer, register uint16_t ring_ptr)
*/
void nic_tx_packet(uint16_t ring_ptr)
{
// uint16_t buffer = (uint16_t) tx_buf;
uint16_t buffer = (uint16_t) uip_buf + VLAN_TAG_SIZE;
SFR_NIC_DATA_U16LE = buffer;
uint16_t len;
/* If we have a management VLAN, we have inserted a dot1Q-tag into the frame and
* the frame starts at the beginning of uip_buf with the RTL TX descriptor,
* otherwise the frame is a normal Ethernet frame which starts with
* an RTL TX descriptor being padded at the beginning, in the second case
* we need to skip the padding for the sending of the frame.
*/
if (management_vlan) {
SFR_NIC_DATA_U16LE = (uint16_t) uip_buf;
len = FRAME_Q->len;
/*
(__xdata struct rtl_dot1q_frame *)uip_buf
#define FRAME (((__xdata struct rtl_dot1q_frame *)&uip_buf[0]).nonq_frame)*/
} else {
SFR_NIC_DATA_U16LE = (uint16_t) uip_buf + VLAN_TAG_SIZE;
len = FRAME->len;
}
#ifdef RXTXDBG
print_string("TX: \n");
for (uint8_t i = 0; i < 100; i++) {
print_byte(uip_buf[i]);
write_char(' ');
}
write_char('\n');
#endif
ring_ptr <<= 3;
ring_ptr |= 0x8000;
SFR_NIC_RING_U16LE = ring_ptr;
uint16_t len = (((uint16_t)uip_buf[VLAN_TAG_SIZE + 5]) << 8) | uip_buf[VLAN_TAG_SIZE + 4];
len += 0xf;
len >>= 3;
SFR_NIC_CTRL = len;
@@ -682,7 +777,7 @@ void cpy_4(__xdata uint8_t dest[], __xdata uint8_t source[])
}
void read_reg_timer(uint32_t * tmr)
void read_reg_timer(__xdata uint32_t * tmr)
{
uint8_t * val = (uint8_t *)tmr;
SFR_REG_ADDR_U16 = RTL837X_REG_SEC_COUNTER;
@@ -731,19 +826,78 @@ void delay(uint16_t t)
PCON |= 1;
}
void early_boot_handle_button(void)
{
if (machine.reset_pin == GPIO_NA)
return;
gpio_input_setup(machine.reset_pin);
// Debounce after init
delay(100);
// If the button is not already held at boot, continue normally.
if (gpio_pin_test(machine.reset_pin))
return;
set_sys_led_state(SYS_LED_FAST);
print_string("\n[Reset button held at boot]\n");
if (gpio_pin_test(machine.reset_pin))
return;
const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ;
const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ;
const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms
const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms
__xdata uint32_t start_ticks = ticks;
__xdata uint32_t last_blink_step = start_ticks;
__xdata uint8_t blink_step = 0;
set_sys_led_state(SYS_LED_ON);
while (!gpio_pin_test(machine.reset_pin)) {
__xdata uint32_t held_ticks = ticks - start_ticks;
if (held_ticks > max_hold_ticks) {
print_string("[Button held >30s at boot; continuing normal boot]\n");
return;
}
// Double blink pattern while button is held:
// ON (100ms), OFF (100ms), ON (100ms), OFF (500ms)
__xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks;
if ((ticks - last_blink_step) >= step_ticks) {
blink_step = (blink_step + 1) & 0x3;
set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF);
last_blink_step = ticks;
}
PCON |= 1;
}
set_sys_led_state(SYS_LED_ON);
if ((ticks - start_ticks) >= min_hold_ticks) {
print_string("[Button held 10s-30s at boot; restoring default config]\n");
set_sys_led_state(SYS_LED_FAST);
flash_default_config();
delay(3UL * SYS_TICK_HZ);
}
}
/*
* Configure the SerDes of the SoC for a particular mode
* to connect to an SFP module or a PHY
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
* SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
*/
void sds_config(uint8_t sds, uint8_t mode)
{
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
sds_config_mac(sds, mode);
if (mode == SDS_10GR || mode == SDS_QXGMII) // 10G Fiber, 10G connection to RTL8224
if (mode == SDS_10GR || mode == SDS_QXGMII)
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
else
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
@@ -773,13 +927,17 @@ void sds_config(uint8_t sds, uint8_t mode)
v = 0x0200;
page = 0x2e;
break;
case SDS_100FX:
v = 0x0200;
page = 0x26;
break;
default:
print_string("Error in SDS Mode\n");
return;
}
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
if (page == 0x2e) { // 10G Fiber
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
@@ -808,10 +966,34 @@ void sds_config(uint8_t sds, uint8_t mode)
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
// RTL8261BE
if (machine.n_10g && mode == SDS_QXGMII) {
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
return;
}
if (mode != SDS_QXGMII)
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
if (sds == 0 && mode == SDS_1000BX_FIBER) {
if (mode == SDS_1000BX_FIBER) {
sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020
sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0
sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d
@@ -828,9 +1010,9 @@ uint8_t sfp_read_reg(uint8_t slot, uint8_t reg)
{
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x51 >> 5, (0x51 << 3) & 0xff);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x50 >> 5, (0x50 << 3) & 0xff);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL);
@@ -859,26 +1041,27 @@ uint8_t sfp_read_reg(uint8_t slot, uint8_t reg)
void tcpip_output(void)
{
// Add TX-TAG
uip_buf[VLAN_TAG_SIZE] = tx_seq++;
uip_buf[VLAN_TAG_SIZE + 1] = 0x07; // Enable all checksums
uip_buf[VLAN_TAG_SIZE + 5] = uip_len >> 8;
uip_buf[VLAN_TAG_SIZE + 4] = uip_len;
uip_buf[VLAN_TAG_SIZE + 2] = uip_buf[VLAN_TAG_SIZE + 3] = 0;
uip_buf[VLAN_TAG_SIZE + 6] = uip_buf[VLAN_TAG_SIZE + 7] = 0;
FRAME->tx_seq = tx_seq++;
FRAME->chksum_flags = 0x07; // Enable all checksums
FRAME->reserved_1[0] = 0x00; FRAME->reserved_1[1] = 0x00;
FRAME->len = uip_len;
FRAME->reserved_2[0] = 0x00; FRAME->reserved_2[1] = 0x00;
// For the management VLAN we insert an 802.1Q VLAN tag
if (management_vlan) {
// Shift the ethernet header before the HW type including the rtl_frame_desc to the beginning of uip_buf
// to allow space to insert the dot 1Q tag
for (uint8_t i = 0; i < sizeof(struct q_frame) - DOT_1Q_TAG_SIZE; i++)
uip_buf[i] = uip_buf[i + DOT_1Q_TAG_SIZE];
FRAME_Q->len += DOT_1Q_TAG_SIZE;
FRAME_Q->tpid = HTONS(0x8100); // Change ether-type to Dot1Q
FRAME_Q->tci = HTONS(management_vlan);
}
reg_read_m(RTL837X_REG_CPU_TX_CURR_PKT);
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
ring_ptr |= sfr_data[3];
#ifdef RXTXDBG
print_string("TX: \n");
for (uint8_t i = 0; i < 120; i++) {
print_byte(uip_buf[i]);
write_char(' ');
}
write_char('\n');
#endif
// Move data over from xmem buffer to ASIC side using DMA
nic_tx_packet(ring_ptr);
@@ -922,14 +1105,13 @@ void handle_rx(void)
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
uip_len = (((uint16_t)rx_headers[5]) << 8) | rx_headers[4];
// Retrieve VLAN from VLAN-tag
rx_packet_vlan = uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 2] & 0xf;
rx_packet_vlan <<= 8;
rx_packet_vlan |= uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 3];
rx_packet_vlan = NTOHS(ETH_IN->vlan_tag.vlan) & 0x0fff;
#ifdef RXTXDBG
print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n');
print_string(" RX dst: "); print_byte(uip_buf[0]); print_byte(uip_buf[1]); print_byte(uip_buf[2]);
print_byte(uip_buf[3]); print_byte(uip_buf[4]); print_byte(uip_buf[5]); write_char('\n');
print_string(" MGMT-VLAN: "); print_short(management_vlan); write_char('\n');
#endif
if (stpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x80 && uip_buf[2] == 0xc2 // STP packet?
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x00) {
@@ -944,12 +1126,12 @@ void handle_rx(void)
if (uip_len) {
tcpip_output();
}
} else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x06) { // ARP?
} else if (ETH_IN->ether_type == HTONS(0x0806)) { // ARP
uip_arp_arpin();
if (uip_len) {
tcpip_output();
}
} else if (uip_buf[ETHERTYPE_OFFSET] == 0x08 && uip_buf[ETHERTYPE_OFFSET + 1] == 0x00) { // TCP?
} else if (ETH_IN->ether_type == HTONS(0x0800)) { // IPv4
if (!management_vlan || management_vlan == rx_packet_vlan) {
uip_arp_ipin(); // Learn MAC addresses in TCP packets
uip_input();
@@ -992,11 +1174,13 @@ void handle_tx(void)
static inline uint8_t sfp_rate_to_sds_config(register uint8_t rate)
{
if (rate == 0xd)
if (rate == 0x1 || rate == 0x2)
return SDS_100FX;
if (rate == 0xc || rate == 0xd)
return SDS_1000BX_FIBER;
if (rate == 0x1f) // Ethernet 2.5 GBit
if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit
return SDS_HSG;
if (rate > 0x65 && rate < 0x70)
if (rate >= 0x63 && rate < 0x70)
return SDS_10GR;
return 0xff;
}
@@ -1057,6 +1241,14 @@ void handle_sfp(void)
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
delay(100); // Delay, because some modules need time to wake up
uint8_t rate = sfp_read_reg(sfp, 12);
if (sfp_speed[sfp] == SFP_SPEED_100M)
rate = 0x1;
else if (sfp_speed[sfp] == SFP_SPEED_1G)
rate = 0xc;
else if (sfp_speed[sfp] == SFP_SPEED_2G5)
rate = 0x19;
else if (sfp_speed[sfp] == SFP_SPEED_10G)
rate = 0x69;
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
print_string(" Encoding: "); print_byte(sfp_read_reg(sfp, 11));
print_string(" Module: "); sfp_print_info(sfp);
@@ -1212,13 +1404,17 @@ void idle(void)
uint8_t p5 = sfr_data[2] >> 4;
uint8_t p5_last = linkbits_last[2] >> 4;
cpy_4(linkbits_last, sfr_data);
// Handle link change of the RTL8221 PHY, adjust SDS mode
if (p5_last != p5) {
// Handle link change of the RTL8221 PHY, adjust SDS mode, RTL8261BE always uses SDS_QXGMII
if (!machine.n_10g && p5_last != p5) {
if (p5 == 0x5) // 2.5GBit Mode
sds_config(0, SDS_HISGMII);
else if (p5 == 0x2) // 1GBit
sds_config(0, SDS_SGMII);
}
if (machine.n_10g)
sds_config(0, SDS_QXGMII);
if (machine.n_10g == 2)
sds_config(1, SDS_QXGMII);
} else {
cpy_4(linkbits_last, sfr_data);
}
@@ -1243,9 +1439,10 @@ void idle(void)
// Check whether a command is waiting in the cmd_buffer and execute
if (cmd_available) {
cmd_available = 0;
if (!cmd_tokenize())
cmd_tokenize();
if (err_status == ERR_OK)
cmd_parser();
print_string("\n> ");
print_cmd_prompt();
}
}
@@ -1471,78 +1668,6 @@ void nic_setup(void)
}
/*
* Configure the PHY-Side of the SDS-SDS link between SoC and PHY
*/
void sds_init(void)
{
/*
p001e.000d:9535 R02f8-00009535 R02f4-0000953a P000001.1e00000d:953a
p001e.000d:953a p001e.000d:953a R02f8-0000953a R02f4-00009530 P000001.1e00000d:9530
RTL8373:
p001e.000d:0010 R02f8-00000010 R02f4-0000001a P000001.1e00000d:b7fe
p001e.000d:0010 p001e.000d:0010 R02f8-00000010 R02f4-00000010 P000001.1e00000d:b7fe
*/
phy_read(0, PHY_MMD30, 0xd);
uint16_t pval = SFR_DATA_U16;
// PHY Initialization:
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
delay(20);
pval &= 0xfff0;
pval |= 0x0a;
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
delay(10);
phy_write_mask(0x1, PHY_MMD30, 0xd, pval);
phy_read(0, PHY_MMD30, 0xd);
pval = SFR_DATA_U16;
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
pval &= 0xfff0;
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
phy_write_mask(0x1, PHY_MMD30, 0xd, pval);
if (machine_detected.isN) {
uint16_t pval;
print_string(" N-settings");
// Serdes 0 RX PN swap for 64B/66B
sds_read(1, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(1, 6, 2, pval | 0x2000);
// Serdes 1 RX PN swap for 8B/10B
sds_read(1, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(1, 0, 0, pval | 0x200);
// Serdes 0 RX PN swap for 64B/66B
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x2000);
if (machine_detected.isRTL8373) {
// RTL8224: Serdes 0 RX PN swap for 64B/66B
// We assume that RTL8373N always paired with RTL8224N.
// This sds register value is 0x0000 at reset.
// So only write to it.
RTL8224_SDS_WRITE(0, 6, 2, 0x2000);
} else {
// Serdes 0 RX PN swap for 8B/10B
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x200);
}
}
}
void set_sys_led_state(uint8_t state)
{
reg_read_m(RTL837X_REG_LED_MODE);
@@ -1564,167 +1689,6 @@ void rtl8373_revision(void)
}
void rtl8373_init(void)
{
print_string("\nrtl8373_init called\n");
// r65d8:3ffbedff R65d8-3ffbedff
reg_bit_set(0x65d8, 0x1d);
sds_init();
// Disable all SERDES for configuration
REG_SET(RTL837X_REG_SDS_MODES, 0x000037ff);
// q000601:c800 Q000601:c804 q000601:c804 Q000601:c800
sds_read(0, 0x06, 0x01);
uint16_t pval = SFR_DATA_U16;
sds_write_v(0, 0x06, 0x01, pval | 0x04);
delay(50);
sds_read(0, 0x06, 0x01);
pval = SFR_DATA_U16;
sds_write_v(0, 0x06, 0x01, pval & 0xfffb);
phy_config_8224();
sds_config_mac(1, SDS_OFF); // Off for now until SFP+ port used
sds_config_mac(2, SDS_SGMII); // For RTL8224
sds_config(0, SDS_QXGMII);
// SDS 1 setup
// q012100:4902 Q012100:4906 q013605:0000 Q013605:4000 Q011f02:001f q011f15:0086
sds_write_v(1, 0x21, 0x00, 0x4906);
sds_write_v(1, 0x36, 0x05, 0x4000);
sds_write_v(1, 0x1f, 0x02, 0x001f);
sds_read(1, 0x1f, 0x15);
pval = SFR_DATA_U16;
// r0a90:000000f3 R0a90-000000fc
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
sfr_mask_data(0, 0x0f,0x0c);
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
if (machine_detected.isN) {
print_string(" TX_POLARITY_SWAP\n");
// FOR N-Version: #TX_POLARITY_SWAP
reg_read_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
sfr_data[2] = 0x59;
sfr_data[3] = 0x6a;
reg_write_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
}
rtl8224_phy_enable();
// Disable PHYs for configuration
phy_write_mask(0xff,PHY_MMD31,0xa610,0x2858);
// Set bits 0x13 and 0x14 of 0x5fd4
// r5fd4:0002914a R5fd4-001a914a
reg_bit_set(0x5fd4, 0x13);
reg_bit_set(0x5fd4, 0x14);
// Configure ports
uint16_t reg = 0x1238; // Port base register for the bits we set
for (char i = 0; i < 9; i++) {
// Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag
REG_SET(reg, 0xe77);
reg += 0x100;
}
// r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031
reg_bit_set(0xb7c, 5);
// R7124-00001050 R7128-00001050 R712c-00001050 R7130-00001050 R7134-00001050 R7138-00001050
// R713c-00001050 R7140-00001050 R7144-00001050 R7148-00001050
REG_SET(0x7124, 0x1050); REG_SET(0x7128, 0x1050); REG_SET(0x712c, 0x1050);
REG_SET(0x7130, 0x1050); REG_SET(0x7134, 0x1050); REG_SET(0x7138, 0x1050);
REG_SET(0x713c, 0x1050); REG_SET(0x7140, 0x1050); REG_SET(0x7144, 0x1050);
REG_SET(0x7148, 0x1050);
reg_bit_set(RTL837X_REG_HW_CONF, 0);
// enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs
port_eee_enable_all(EEE_2G5 | EEE_NORESET);
// TODO: patch the PHYs
// Re-enable PHY after configuration
phy_write_mask(0xff,PHY_MMD31,0xa610,0x2058);
// Enables MAC access
// Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init
// r632c:00000540 R632c-001f8540 // RTL8373: 001ff540
reg_read_m(0x632c);
sfr_mask_data(1, 0x70, 0xf0); // The ports of the RTL8824
sfr_mask_data(2, 0x10, 0x1f);
reg_write_m(0x632c);
print_string("\nrtl8373_init done\n");
}
void rtl8372_init(void)
{
print_string("\nrtl8372_init called\n");
sds_init();
phy_config(8); // PHY configuration: External 8221B?
phy_config(3); // PHY configuration: all internal PHYs?
// Set the MAC SerDes Modes Bits 0-4: SDS 0 = 0x2 (0x2), Bits 5-9: SDS 1: 1f (off)
// r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003e2 r7b20:000003e2 R7b20-000003e2
reg_read_m(RTL837X_REG_SDS_MODES);
sfr_mask_data(1, 0, 0x03);
sfr_mask_data(0, 0, 0xe2);
reg_write_m(RTL837X_REG_SDS_MODES);
// r0a90:000000f3 R0a90-000000fc
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
sfr_mask_data(0, 0x0f, 0x0c);
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
// Disable PHYs for configuration
phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2858);
// Set bits 0x13 and 0x14 of 0x5fd4
// r5fd4:0002914a R5fd4-001a914a
reg_bit_set(0x5fd4, 0x13);
reg_bit_set(0x5fd4, 0x14);
// Configure ports 3-8:
//
// r1538:00000e33 R1538-00000e37 r1538:00000e37 R1538-00000e37 r1538:00000e37 R1538-00000f37
// [...]
///
uint16_t reg = 0x1238 + 0x300; // Port base register for the bits we set
for (char i = machine.min_port; i <= machine.max_port; i++) {
// Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag
REG_SET(reg, 0xe77);
reg += 0x100;
}
// r0b7c:000000d8 R0b7c-000000f8 r6040:00000030 R6040-00000031
reg_bit_set(0xb7c, 5);
reg_bit_set(RTL837X_REG_HW_CONF, 0);
// enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs
port_eee_enable_all(EEE_2G5 | EEE_NORESET);
// TODO: patch the PHYs
// Re-enable PHY after configuration
phy_write_mask(0xf0,PHY_MMD31,0xa610,0x2058);
// Enables MAC access
// Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init
// r632c:00000540 R632c-001f8540 // RTL8373: 001ff540
reg_read_m(0x632c);
sfr_mask_data(1, 0x70, 0x80);
sfr_mask_data(2, 0x10, 0x1f);
reg_write_m(0x632c);
print_string("\nrtl8372_init done\n");
}
/*
* The SoC manages Link-State for steering the LEDs and can set PHY-settings
* automatically through Realtek's SMI (Simple Managagement) Interface, a
@@ -1739,7 +1703,11 @@ void init_smi(void)
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
* which are at port 8 and additionally at port 3 for a dual SFP device
*/
REG_SET(RTL837X_REG_SMI_MAC_TYPE, machine.n_sfp == 2 ? 0x00005515 : 0x00005555);
if (machine.n_10g == 2) {
REG_SET(RTL837X_REG_SMI_MAC_TYPE, 0x00015555);
} else {
REG_SET(RTL837X_REG_SMI_MAC_TYPE, machine.n_sfp == 2 ? 0x00005515 : 0x00005555);
}
// Configure polling of all PHYs by the MAC to detect link-state changes
if (machine_detected.isRTL8373) {
@@ -1766,6 +1734,11 @@ void init_smi(void)
sfr_mask_data(1, 0x80, 0);
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
}
if (machine.n_10g == 2) {
// Set address of second external PHY on port 8
REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
}
}
@@ -1910,7 +1883,7 @@ void check_and_flash_update_image(void)
__xdata uint16_t i = 0;
__xdata uint16_t j = 0;
__xdata uint8_t * __xdata bptr;
print_string("found update image! Checking integrity");
print_string("found update image!\nChecking integrity");
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing will fail
set_sys_led_state(SYS_LED_FAST);
crc_value = 0x0000;
@@ -2038,6 +2011,8 @@ void main(void)
// Print SW version
print_sw_version();
// Set AUTONEG for SFP ports
sfp_speed[0] = sfp_speed[1] = SFP_SPEED_AUTO;
// Reset NIC
reg_bit_set(RTL837X_REG_RESET, RESET_NIC_BIT);
do {
@@ -2087,6 +2062,8 @@ void main(void)
check_and_flash_update_image();
syslog_init();
#ifdef DEBUG
// This register seems to work on the RTL8373 only if also the SDS
// Is correctly configured. Therefore, we can test it, here...
@@ -2114,11 +2091,10 @@ void main(void)
uip_arp_init();
httpd_init();
management_vlan = 0; // Disabled
management_vlan = 1; // Default management VLAN is 1
setup_i2c();
setup_sfp_gpio();
print_string(greeting);
print_string("\nClock register: ");
@@ -2130,13 +2106,16 @@ void main(void)
// p031f.a610:2058 p041f.a610:2058 p051f.a610:2058 r4f3c:00000000 p061f.a610:2058 p071f.a610:2058
port_stats_print();
early_boot_handle_button();
execute_config();
print_string("\n> ");
print_cmd_prompt();
idle_ready = 1;
set_sys_led_state(SYS_LED_ON);
cmd_editor_init();
while (1) {
cmd_edit();
idle(); // Enter Idle mode until interrupt occurs
+105
View File
@@ -0,0 +1,105 @@
#include "machine.h"
#include "syslog.h"
#include "uip/uip.h"
#include "rtl837x_common.h"
#pragma codeseg BANK2
#pragma constseg BANK2
#define SYSLOG_P ((__xdata uint8_t *)uip_appdata)
__xdata char logbuf[LOGBUF_SIZE];
__xdata struct syslog_state syslog_state;
__xdata uip_ipaddr_t server_ip;
#define state syslog_state
void syslog_init(void) __banked
{
state.enabled = 0;
state.syslog_conn = 0;
state.writeptr = 0;
state.readptr = 0;
state.line_available = 0;
state.server_ip[0] = 0; state.server_ip[1] = 0; state.server_ip[2] = 0; state.server_ip[3] = 0;// Default to 0.0.0.0
}
void syslog_start(void) __banked
{
if (state.syslog_conn == 0) {
uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]);
state.syslog_conn = uip_udp_new(&server_ip, HTONS(514));
if (state.syslog_conn == 0) {
print_string_no_syslog("Failed to create a new UDP client\n");
return;
}
print_string_no_syslog("Started syslog to IP ");
itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.');
itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n');
state.enabled = 1;
}
else {
print_string_no_syslog("Syslog is already running\n");
}
}
void syslog_stop(void) __banked
{
state.enabled = 0;
if (state.syslog_conn != 0) {
uip_udp_remove(state.syslog_conn);
state.syslog_conn = 0;
print_string_no_syslog("Stopped syslog\n");
} else {
print_string_no_syslog("Syslog is not running\n");
}
}
void syslog_callback(uint16_t lport) __banked
{
if (lport != state.syslog_conn->lport)
return;
if ((state.readptr != state.writeptr) && state.line_available)
{
int16_t log_size = state.writeptr - state.readptr;
if (log_size < 0)
log_size += LOGBUF_SIZE;
// Skipping linefeeds at the start of the log line
uint16_t log_start = state.readptr;
while (log_size > 0 && logbuf[log_start] == '\n') {
log_start = (log_start + 1) & (LOGBUF_SIZE - 1);
log_size--;
}
// Skipping linefeeds and whitespaces at the end of the log line
uint16_t log_end = state.writeptr;
while ( (log_size > 0) &&
((logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == '\n') ||
(logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == ' ')))
{
log_end = (log_end - 1) & (LOGBUF_SIZE - 1);
log_size--;
}
if (log_size == 0) {
state.readptr = state.writeptr;
state.line_available = 0;
return;
}
memcpyc(SYSLOG_P, "<14>", 4); // Syslog priority prefix
if (log_end < log_start) {
memcpy(SYSLOG_P + 4, logbuf + log_start, LOGBUF_SIZE - log_start);
memcpy(SYSLOG_P + 4 + LOGBUF_SIZE - log_start, logbuf, log_end);
} else {
memcpy(SYSLOG_P + 4, logbuf + log_start, log_end - log_start);
}
uip_udp_send(log_size+4);
state.readptr = state.writeptr;
state.line_available = 0;
}
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef _SYSLOG_H_
#define _SYSLOG_H_
#include <stdint.h>
#define LOGBUF_SIZE 512
struct syslog_state {
uint8_t enabled;
uint8_t line_available;
uint16_t writeptr ;
uint16_t readptr;
uint8_t server_ip[4];
struct uip_udp_conn *syslog_conn;
};
extern __xdata struct syslog_state syslog_state;
extern __xdata char logbuf[LOGBUF_SIZE];
void syslog_init(void) __banked;
void syslog_start(void) __banked;
void syslog_stop(void) __banked;
void syslog_callback(uint16_t lport) __banked;
#endif
+9 -9
View File
@@ -1,27 +1,27 @@
CC = gcc
CCFLAGS = -Wall -o
BUILDDIR = output/
BUILDDIR = output
all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim\
$(BUILDDIR)crc_calculator $(BUILDDIR)imagebuilder
all: create_build_dir $(BUILDDIR)/injector $(BUILDDIR)/fileadder $(BUILDDIR)/httpd_sim\
$(BUILDDIR)/crc_calculator $(BUILDDIR)/imagebuilder
create_build_dir:
mkdir -p $(BUILDDIR)
clean:
rm -r $(BUILDDIR)
rm -rf $(BUILDDIR)
$(BUILDDIR)injector: injector.c
$(BUILDDIR)/injector: injector.c
gcc $^ $(CCFLAGS) $@
$(BUILDDIR)fileadder: fileadder.c
$(BUILDDIR)/fileadder: fileadder.c
gcc $^ $(CCFLAGS) $@
$(BUILDDIR)crc_calculator: crc_calculator.c
$(BUILDDIR)/crc_calculator: crc_calculator.c
gcc $^ $(CCFLAGS) $@
$(BUILDDIR)httpd_sim: httpd_sim.c httpd_sim.h
$(BUILDDIR)/httpd_sim: httpd_sim.c httpd_sim.h
gcc $< $(CCFLAGS) $@ -I/usr/include/json-c -ljson-c
$(BUILDDIR)imagebuilder: imagebuilder.c
$(BUILDDIR)/imagebuilder: imagebuilder.c
gcc $^ $(CCFLAGS) $@
+5 -5
View File
@@ -91,7 +91,7 @@ int main(int argc, char **argv)
}
int nbanks = (filesize - BANK0_SIZE) / BANK_STRIDE;
printf("Input file contains %d banks\n", nbanks);
printf("Input file contains %d banks\n", nbanks+1);
/* Verify the size of banks in input file:
* Bank 0: 0x00002 - 0x04000 <- 0x00000 - 0x03ffe
@@ -112,15 +112,15 @@ int main(int argc, char **argv)
}
for (int b = BANK0_SIZE; b < BANK_STRIDE + BANK0_SIZE; b ++) {
if (buffer[b]) {
printf("WARNING: Bank 0: code segment too large at 0x%x!\n", b);
break;
printf("Error: Bank 0: code segment too large at 0x%x!\n", b);
return 5;
}
}
for (int bank = 1; bank <= nbanks; bank++) {
for (int b = (bank + 1) * BANK_STRIDE; b < (bank + 1) * BANK_STRIDE + BANK0_SIZE; b ++) {
if (buffer[b]) {
printf("WARNING: Bank %d: code segment too large at 0x%x!\n", bank, b);
break;
printf("Error: Bank %d: code segment too large at 0x%x!\n", bank, b);
return 5;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
#include "uip/uip.h"
#include "udp_apps.h"
void udp_callbacks(void)
{
dhcp_callback(uip_udp_conn->lport); // let the application decide if this is for it or not
syslog_callback(uip_udp_conn->lport); // let the application decide if this is for it or not
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef _UDPAPPS_H_
#define _UDPAPPS_H_
#include "dhcp.h"
#include "syslog.h"
void udp_callbacks(void);
#ifndef UIP_UDP_APPCALL
#define UIP_UDP_APPCALL udp_callbacks
#endif /* UIP_UDP_APPCALL */
#endif
-26
View File
@@ -1,26 +0,0 @@
CC = sdcc
CC_FLAGS = -mmcs51 -I. -I.. -I../httpd
ASM = sdas8051
AFLAGS= -plosgff
BUILDDIR = output/
SRCS = timer.c uip_arp.c uip.c uip-fw.c uiplib.c uip-neighbor.c uip-split.c
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
all: create_build_dir $(OBJS)
create_build_dir:
mkdir -p $(BUILDDIR)
$(BUILDDIR)%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
${ASM} ${AFLAGS} $^
clean:
rm -r $(BUILDDIR)
.PHONY: all clean
+4 -4
View File
@@ -64,7 +64,7 @@
*
*/
void
timer_set(struct timer *t, clock_time_t interval)
timer_set(__xdata struct timer *t, clock_time_t interval)
{
t->interval = interval;
t->start = clock_time();
@@ -84,7 +84,7 @@ timer_set(struct timer *t, clock_time_t interval)
* \sa timer_restart()
*/
void
timer_reset(struct timer *t)
timer_reset(__xdata struct timer *t)
{
t->start += t->interval;
}
@@ -104,7 +104,7 @@ timer_reset(struct timer *t)
* \sa timer_reset()
*/
void
timer_restart(struct timer *t)
timer_restart(__xdata struct timer *t)
{
t->start = clock_time();
}
@@ -121,7 +121,7 @@ timer_restart(struct timer *t)
*
*/
int
timer_expired(struct timer *t)
timer_expired(__xdata struct timer *t)
{
return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;
}
+4 -4
View File
@@ -76,10 +76,10 @@ struct timer {
clock_time_t interval;
};
void timer_set(struct timer *t, clock_time_t interval);
void timer_reset(struct timer *t);
void timer_restart(struct timer *t);
int timer_expired(struct timer *t);
void timer_set(__xdata struct timer *t, clock_time_t interval);
void timer_reset(__xdata struct timer *t);
void timer_restart(__xdata struct timer *t);
int timer_expired(__xdata struct timer *t);
#endif /* __TIMER_H__ */
+1 -1
View File
@@ -153,7 +153,7 @@ typedef unsigned short uip_stats_t;
our project. */
/*#include "smtp.h"*/
#include "httpd.h"
#include "dhcp.h"
#include "udp_apps.h"
/*#include "telnetd.h"*/
/*#include "webserver.h" */
/*#include "dhcpc.h"*/
+5 -5
View File
@@ -234,14 +234,14 @@ __xdata struct uip_stats uip_stat;
#endif /* UIP_STATISTICS == 1 */
#if UIP_LOGGING == 1
#define UIP_LOG(m) print_string(m)
#define UIP_LOG(m) print_string_no_syslog(m);
#else
#define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */
#if ! UIP_ARCH_ADD32
void
uip_add32(u8_t *op32, u16_t op16)
uip_add32(u8_t __xdata * op32, u16_t op16)
{
uip_acc32[3] = op32[3] + (op16 & 0xff);
uip_acc32[2] = op32[2] + (op16 >> 8);
@@ -465,8 +465,8 @@ uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banke
#endif /* UIP_ACTIVE_OPEN */
/*---------------------------------------------------------------------------*/
#if UIP_UDP
struct uip_udp_conn *
uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) __banked
__xdata struct uip_udp_conn *
uip_udp_new(__xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked
{
__xdata struct uip_udp_conn *conn;
@@ -1901,7 +1901,7 @@ htons(u16_t val)
}
/*---------------------------------------------------------------------------*/
void
uip_send(register __xdata const void *data, register uint16_t len) __banked
uip_send(__xdata const void *data, __xdata uint16_t len) __banked
{
if(len > 0) {
uip_slen = len;

Some files were not shown because too many files have changed in this diff Show More