Skip to content

realtek: add rtl9607 usb support#2

Open
jameywine wants to merge 2 commits intortl9607c-devfrom
rtl9607c-dev-usb
Open

realtek: add rtl9607 usb support#2
jameywine wants to merge 2 commits intortl9607c-devfrom
rtl9607c-dev-usb

Conversation

@jameywine
Copy link
Copy Markdown
Owner

This commit adds support for EHCI controller on RTL9607.
That also includes 2 patches for addition of ehci driver and usb2 phy driver for it. There is also XHCI controller but it is yet to be developed.

This is yet to be tested and to potentially be improved.

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 5, 2026

Pushed some fixes

Now everything fails here:

[    1.088042] rtl960x-usb2-phy soc:usb-phy@18140200: error -EINVAL: invalid resource (null)
[    1.097337] rtl960x-usb2-phy soc:usb-phy@18140200: failed to remap phy usb2 ext regs
[    1.106060] rtl960x-usb2-phy soc:usb-phy@18140200: probe with driver rtl960x-usb2-phy failed with error -22

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 6, 2026 via email

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 6, 2026 via email

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 6, 2026

Since you have placed the nodes inside the soc simple-bus node, can you also remove the 0x18 from the USB and USB phy nodes?

I tried both - moving inside bus node, moving out, left bus offset instead of full address - neither worked. I'll return to this problem later

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 6, 2026

Not great...

maybe the order should be other way around in reg property. So like `reg = <0x180210a4 0x14>, <0x18140200 0x14>;
Or possibly remove the 2nd reg region in favor of doing ioremap inside the driver itself, as a temp measure

I think for the time being we should avoid placing it under soc node until we can make it work
Other thing is just some debugging messages and what not.

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 6, 2026

remove the 2nd reg region in favor of doing ioremap inside the driver itself, as a temp measure

That's what I did, and it worked - there was resource overlap between usb driver and usb phy nodes

So now it fails in ehci_handshake() with timeout, trying to read data from register

I would suggest you be more careful with registers endianess - utmi_get/set(), unlike rest of the code, present in LE. And it does polling after reads and before writes

I think it would be better if you will look at your code again. Feel free to use (or discard) any changes from me

@jameywine
Copy link
Copy Markdown
Owner Author

That's what I did, and it worked - there was resource overlap between usb driver and usb phy nodes

Right yeah, #define BSP_EHCI_UTMI_CTRL (BSP_EHCI_BASE + 0xA4) It is based off of the ehci base address and not the usb2_ext but used during phy initialization...
I don't know of any good ways to get ehci address from the usb phy right now, something to figure out later on

I would suggest you be more careful with registers endianess - utmi_get/set(), unlike rest of the code, present in LE. And it does polling after reads and before writes

Good notice, i didn't give them much about le32_to_cpu. I do find it weird that the utmi_wait happens even during writes, because it suppose to return the reg???
But sure, i can include the wait thing with writes for now.

@jameywine
Copy link
Copy Markdown
Owner Author

I think it would be better if you will look at your code again. Feel free to use (or discard) any changes from me

Included your fixes with some adjustments and added the utmi set and wait functions as suggested earlier

Comment thread target/linux/realtek/files-6.12/drivers/phy/realtek/phy-rtl960x-usb2.c Outdated
Comment thread target/linux/realtek/files-6.12/drivers/phy/realtek/phy-rtl960x-usb2.c Outdated
Comment thread target/linux/realtek/files-6.12/drivers/phy/realtek/phy-rtl960x-usb2.c Outdated
Comment thread target/linux/realtek/files-6.12/drivers/usb/host/ehci-rtl960x.c Outdated
Comment thread target/linux/realtek/Makefile
@jameywine
Copy link
Copy Markdown
Owner Author

Included most of the things from your reviews

The UTMI REG situation is yet to be improved but that should come after usb is confirmed working

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 9, 2026

Btw, I've tested actual driver version, and problem is still same

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 9, 2026 via email

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 9, 2026

By "actual usb version", are you talking about the USB driver from GPL code?

No, I meant content of this branch after fixes (endianess, set_bits)

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 9, 2026 via email

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 9, 2026

Full bootlog with some debug patches

Bootlog
[    0.000000] Linux version 6.12.68 (misha@gamepc) (mips-openwrt-linux-musl-gcc (OpenWrt GCC 14.3.0 r32948-42340b2d4c) 14.3.0, GNU ld (GNU Binutils) 2.44) #0 SMP Sat Feb  7 12:34:45 2026
[    0.000000] Realtek RTL9607C subtype 0B rev B (6831) SoC with 256 MB
[    0.000000] printk: legacy bootconsole [early0] enabled
[    0.000000] CPU0 revision is: 0001a120 (MIPS interAptiv (multi))
[    0.000000] MIPS: machine is BT-PON BT-G711AX
[    0.000000] earlycon: ns16550a0 at MMIO 0x18002000 (options '115200n8')
[    0.000000] printk: legacy bootconsole [ns16550a0] enabled
[    0.000000] Initrd not found or empty - disabling initrd
[    0.000000] Using appended Device Tree.
[    0.000000] OF: reserved mem: Reserved memory: No reserved-memory node in the DT
[    0.000000] VPE topology {2,2} total 4
[    0.000000] Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
[    0.000000] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[    0.000000] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000000000000-0x000000000fffffff]
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000000000-0x000000000fffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000000fffffff]
[    0.000000] percpu: Embedded 12 pages/cpu s18480 r8192 d22480 u49152
[    0.000000] pcpu-alloc: s18480 r8192 d22480 u49152 alloc=12*4096
[    0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
[    0.000000] Kernel command line: earlycon
[    0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[    0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
[    0.000000] Writing ErrCtl register=00000000
[    0.000000] Readback ErrCtl register=00000000
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 65536
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000]  Tracing variant of Tasks RCU enabled.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[    0.000000] RCU Tasks Trace: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=4.
[    0.000000] NR_IRQS: 256
[    0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
[    0.000000] rtl83xx-clk: initialized, CPU 1250 MHz, MEM 626 MHz (16 Bit DDR3), LXB 200 MHz
[    0.000000] clocksource: GIC: mask: 0xffffffffffffffff max_cycles: 0x12049cd048c, max_idle_ns: 440795204120 ns
[    0.000002] sched_clock: 64 bits at 1250MHz, resolution 0ns, wraps every 4398046511103ns
[    0.009251] clocksource: realtek_otto_timer: mask: 0xfffffff max_cycles: 0xfffffff, max_idle_ns: 38225208801 ns
[    0.020678] Calibrating delay loop... 829.84 BogoMIPS (lpj=4149248)
[    0.117555] pid_max: default: 32768 minimum: 301
[    0.130057] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.138253] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.155576] rcu: Hierarchical SRCU implementation.
[    0.160997] rcu:     Max phase no-delay instances is 1000.
[    0.168213] smp: Bringing up secondary CPUs ...
[    0.174467] Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
[    0.174507] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[    0.174518] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[    0.174593] CPU1 revision is: 0001a120 (MIPS interAptiv (multi))
[    0.250619] Counter synchronization [CPU#0 -> CPU#1]: passed
[    0.288578] Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
[    0.288616] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[    0.288627] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[    0.288672] CPU2 revision is: 0001a120 (MIPS interAptiv (multi))
[    0.620632] Counter synchronization [CPU#0 -> CPU#2]: passed
[    0.657652] Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
[    0.657686] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[    0.657697] MIPS secondary cache 256kB, 8-way, linesize 32 bytes.
[    0.657749] CPU3 revision is: 0001a120 (MIPS interAptiv (multi))
[    0.730646] Counter synchronization [CPU#0 -> CPU#3]: passed
[    0.766560] smp: Brought up 1 node, 4 CPUs
[    0.773039] Memory: 236516K/262144K available (8185K kernel code, 645K rwdata, 1724K rodata, 10684K init, 250K bss, 24252K reserved, 0K cma-reserved, 0K highmem)
[    0.791912] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.802990] futex hash table entries: 1024 (order: 3, 32768 bytes, linear)
[    0.815006] pinctrl core: initialized pinctrl subsystem
[    0.823223] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    0.830359] thermal_sys: Registered thermal governor 'step_wise'
[    0.830697] FPU Affinity set after 16580 emulations
[    0.853594] usbcore: registered new interface driver usbfs
[    0.859795] usbcore: registered new interface driver hub
[    0.865877] usbcore: registered new device driver usb
[    0.873418] clocksource: Switched to clocksource realtek_otto_timer
[    0.888078] NET: Registered PF_INET protocol family
[    0.893796] IP idents hash table entries: 4096 (order: 3, 32768 bytes, linear)
[    0.902775] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)
[    0.912181] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.920868] TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
[    0.929489] TCP bind hash table entries: 2048 (order: 3, 32768 bytes, linear)
[    0.937615] TCP: Hash tables configured (established 2048 bind 2048)
[    0.945604] MPTCP token hash table entries: 256 (order: 0, 4096 bytes, linear)
[    0.954099] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.961426] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.970129] NET: Registered PF_UNIX/PF_LOCAL protocol family
[    0.986312] workingset: timestamp_bits=14 max_order=16 bucket_order=2
[    0.996380] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    1.002917] jffs2: version 2.2 (NAND) (SUMMARY) (ZLIB) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
[    1.022180] Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
[    1.031047] printk: legacy console [ttyS0] disabled
[    1.037367] 18002000.uart: ttyS0 at MMIO 0x18002000 (irq = 22, base_baud = 12500000) is a 16550A
[    1.047538] printk: legacy console [ttyS0] enabled
[    1.047538] printk: legacy console [ttyS0] enabled
[    1.058278] printk: legacy bootconsole [early0] disabled
[    1.058278] printk: legacy bootconsole [early0] disabled
[    1.071163] printk: legacy bootconsole [ns16550a0] disabled
[    1.071163] printk: legacy bootconsole [ns16550a0] disabled
[    1.122754] brd: module loaded
[    1.132227] spi-nand spi0.0: GigaDevice SPI NAND was found.
[    1.138709] spi-nand spi0.0: 128 MiB, block size: 128 KiB, page size: 2048, OOB size: 128
[    1.148698] rtl-nand-ecc-engine 1801a600.ecc: only flash geometry data=2048, oob=64 supported
[    1.158415] nand: No suitable ECC configuration
[    1.163644] spi-nand spi0.0: probe with driver spi-nand failed with error -22
[    1.269856] rtusb-ehci 18021000.ehci: EHCI Host Controller
[    1.276058] rtusb-ehci 18021000.ehci: new USB bus registered, assigned bus number 1
[    1.287758] ehci_handshake:166 fail timeout
[    1.292425] halt fail
[    1.294985] rtusb-ehci 18021000.ehci: can't setup: -145
[    1.300818] rtusb-ehci 18021000.ehci: USB bus 1 deregistered
[    1.307173] rtusb-ehci 18021000.ehci: Failed to add USB HCD
[    1.313417] rtusb-ehci 18021000.ehci: probe with driver rtusb-ehci failed with error -145
[    1.322780] i2c_dev: i2c /dev entries driver
[    1.331193] NET: Registered PF_INET6 protocol family
[    1.340329] Segment Routing with IPv6
[    1.344645] In-situ OAM (IOAM) with IPv6
[    1.349136] NET: Registered PF_PACKET protocol family
[    1.354898] 8021q: 802.1Q VLAN Support v1.8
[    1.396172] clk: Disabling unused clocks
[    1.448922] Freeing unused kernel image (initmem) memory: 10684K
[    1.455680] This architecture does not have kernel memory protection.
[    1.462864] Run /init as init process
[    1.466964]   with arguments:
[    1.470271]     /init
[    1.472789]   with environment:
[    1.476294]     HOME=/
[    1.478922]     TERM=linux
[    1.826508] init: Console is alive
[    1.830733] init: - watchdog -
[    1.845249] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[    1.854995] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[    1.865665] init: - preinit -
[    4.703420] random: crng init done
ls: /sys/class/net/lan*: No such file or directory
BusyBox v1.37.0 (2026-01-02 17:07:02 UTC) multi-call binary.

Usage: basename FILE [SUFFIX] | -a FILE... | -s SUFFIX FILE...

Strip directory path and SUFFIX from FILE

        -a              All arguments are FILEs
        -s SUFFIX       Remove SUFFIX (implies -a)
mtd_get_mac_ascii: partition u-boot-env2 not found!
mtd_get_mac_ascii: partition u-boot-env2 not found!
mtd_get_mac_ascii: partition u-boot-env not found!
Cannot parse config file '/etc/fw_env.config': No such file or directory
Failed to find NVMEM device
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
[    9.160648] procd: - early -
[    9.164239] procd: - watchdog -
[    9.732320] procd: - watchdog -
[    9.737029] procd: - ubus -
[    9.795433] procd: - init -
Please press Enter to activate this console.
[   10.208717] kmodloader: loading kernel modules from /etc/modules.d/*
[   10.282039] kmodloader: done loading kernel modules from /etc/modules.d/*
[   10.942540] urngd: v1.0.2 started.
Patch
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index cbc0b86fcc36..840d5b02df7e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -153,14 +153,17 @@ int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,

        do {
                result = ehci_readl(ehci, ptr);
-               if (result == ~(u32)0)          /* card removed */
+               if (result == ~(u32)0){         /* card removed */
+       printk("%s:%d fail handshake nodev\n", __func__, __LINE__);
                        return -ENODEV;
+                       }
                result &= mask;
                if (result == done)
                        return 0;
                udelay (1);
                usec--;
        } while (usec > 0);
+       printk("%s:%d fail timeout\n", __func__, __LINE__);
        return -ETIMEDOUT;
 }
 EXPORT_SYMBOL_GPL(ehci_handshake);
@@ -189,6 +192,7 @@ static int ehci_halt (struct ehci_hcd *ehci)

        if (ehci_is_TDI(ehci) && !tdi_in_host_mode(ehci)) {
                spin_unlock_irq(&ehci->lock);
+       printk("%s:%d TDI wtf\n", __func__, __LINE__);
                return 0;
        }

@@ -501,8 +505,10 @@ static int ehci_init(struct usb_hcd *hcd)
                default:        BUG();
                }
        }
-       if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
+       if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0){
+       printk("mem init fail\n");
                return retval;
+               }

        /* controllers may cache some of the periodic schedule ... */
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
@@ -693,11 +699,14 @@ int ehci_setup(struct usb_hcd *hcd)

        /* data structure init */
        retval = ehci_init(hcd);
-       if (retval)
+       if (retval){
+       printk("init fail\n");
                return retval;
+               }

        retval = ehci_halt(ehci);
        if (retval) {
+       printk("halt fail\n");
                ehci_mem_cleanup(ehci);
                return retval;
        }
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 4c6c08b675b5..c9680b9fc899 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -146,6 +146,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                        32 /* byte alignment (for hw parts) */,
                        4096 /* can't cross 4K */);
        if (!ehci->qtd_pool) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }

@@ -156,10 +157,12 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                        32 /* byte alignment (for hw parts) */,
                        4096 /* can't cross 4K */);
        if (!ehci->qh_pool) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }
        ehci->async = ehci_qh_alloc (ehci, flags);
        if (!ehci->async) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }

@@ -170,6 +173,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                        32 /* byte alignment (for hw parts) */,
                        4096 /* can't cross 4K */);
        if (!ehci->itd_pool) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }

@@ -180,6 +184,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                        32 /* byte alignment (for hw parts) */,
                        4096 /* can't cross 4K */);
        if (!ehci->sitd_pool) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }

@@ -189,14 +194,17 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                        ehci->periodic_size * sizeof(__le32),
                        &ehci->periodic_dma, flags);
        if (ehci->periodic == NULL) {
+       printk("%s:%d fail\n", __func__, __LINE__);
                goto fail;
        }

        if (ehci->use_dummy_qh) {
                struct ehci_qh_hw       *hw;
                ehci->dummy = ehci_qh_alloc(ehci, flags);
-               if (!ehci->dummy)
+               if (!ehci->dummy){
+       printk("%s:%d fail\n", __func__, __LINE__);
                        goto fail;
+                       }

                hw = ehci->dummy->hw;
                hw->hw_next = EHCI_LIST_END(ehci);
@@ -216,6 +224,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
        ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
        if (ehci->pshadow != NULL)
                return 0;
+       printk("%s:%d fail\n", __func__, __LINE__);

 fail:
        ehci_dbg (ehci, "couldn't init memory\n");

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 9, 2026

More debug logs

[    1.312724] rtusb-ehci 18021000.ehci: EHCI Host Controller
[    1.318893] rtusb-ehci 18021000.ehci: new USB bus registered, assigned bus number 1
[    1.327473] ehci_setup:694 ehci caps: 0xb8021000, value: 0x10000001
[    1.334478] ehci_setup:695 ehci regs: 0xb8021001
[    1.339706] ehci_halt:187 ehci regs: 0xb8021001
[    1.347811] ehci_handshake:166 fail timeout 0xb8021005
[    1.353564] halt fail

I does not know anything about USB controllers, but unaligned address seems... pretty wrong

@jameywine
Copy link
Copy Markdown
Owner Author

Anything on the usb phy driver side? Is it run from the phy_init?

Something tells me that we need to create custom function that will be used in place of ehci_setup through the overrides
https://github.com/jameywine/openwrt/pull/2/changes#diff-596c3b309c23bbf28895af5144c9859cc6f01a263fc9c619169b0d0cdb8ad502R39
Basically, setting .reset parameter here

Similar way it is done in the xhci usb driver for the closed rtl8198c pull request?
https://github.com/openwrt/openwrt/pull/11094/changes#diff-87dd69997820724b77451d6e02e502d09b181b610ff2be1c9b85ed12f11439f1R313

unaligned address seems... pretty wrong

I also don't know much about the usb stuff but looking at ehci_setup, it is adding something to regs

	ehci->regs = (void __iomem *)ehci->caps +
	    HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));

@jameywine
Copy link
Copy Markdown
Owner Author

Other avenues to explores:

There is ehci-pci load during the oem reboot, maybe enabling will help somehow?

[    2.480000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    2.490000] ehci-pci: EHCI PCI platform driver
[    2.490000] ehci-platform: EHCI generic platform driver

Perhaps we can do something similar to bcma-hcd and alike that deals with platform_device struct?
https://github.com/torvalds/linux/blob/master/drivers/usb/host/bcma-hcd.c

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 9, 2026

Figured out which driver was used in SDK:

Details
[    2.780000] usbcore: registered new interface driver asix
[    2.780000] usbcore: registered new interface driver ax88179_178a
[    2.790000] usbcore: registered new interface driver cdc_ether
[    2.800000] usbcore: registered new interface driver net1080
[    2.800000] usbcore: registered new interface driver rndis_host
[    2.810000] usbcore: registered new interface driver cdc_subset
[    2.820000] usbcore: registered new interface driver zaurus
[    2.820000] usbcore: registered new interface driver cdc_ncm
[    2.830000] usbcore: registered new interface driver qmi_wwan
[    2.830000] usbcore: registered new interface driver cdc_mbim
[    2.840000] mousedev: PS/2 mouse device common for all mice
[    2.850000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    2.850000] ehci-pci: EHCI PCI platform driver
[    2.860000] ehci-platform: EHCI generic platform driver
[    2.870000] ehci-platform ehci-platform.0: EHCI Host Controller
[    2.870000] ehci-platform ehci-platform.0: new USB bus registered, assigned bus number 1
[    2.880000] ehci-platform ehci-platform.0: irq 74, io mem 0x18021000
[    2.910000] ehci-platform ehci-platform.0: USB 2.0 started, EHCI 1.00
[    2.910000] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    2.920000] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.930000] usb usb1: Product: EHCI Host Controller
[    2.930000] usb usb1: Manufacturer: Linux 4.4.140 ehci_hcd
[    2.940000] usb usb1: SerialNumber: ehci-platform.0
[    2.940000] hub 1-0:1.0: USB hub found
[    2.950000] hub 1-0:1.0: 1 port detected
[    2.950000] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    2.960000] ohci-pci: OHCI PCI platform driver
[    2.960000] ohci-platform: OHCI generic platform driver
[    2.970000] ohci-platform ohci-platform.0: Generic Platform OHCI controller
[    2.980000] ohci-platform ohci-platform.0: new USB bus registered, assigned bus number 2
[    2.990000] ohci-platform ohci-platform.0: irq 74, io mem 0x18020000
[    3.050000] usb usb2: New USB device found, idVendor=1d6b, idProduct=0001
[    3.060000] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    3.060000] usb usb2: Product: Generic Platform OHCI controller
[    3.070000] usb usb2: Manufacturer: Linux 4.4.140 ohci_hcd
[    3.080000] usb usb2: SerialNumber: ohci-platform.0
[    3.080000] hub 2-0:1.0: USB hub found
[    3.090000] hub 2-0:1.0: 1 port detected
[    3.090000] usbcore: registered new interface driver cdc_acm
[    3.100000] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[    3.110000] usbcore: registered new interface driver cdc_wdm
[    3.110000] usbcore: registered new interface driver usb-storage
[    3.120000] usbcore: registered new interface driver usbserial
[    3.130000] usbcore: registered new interface driver usbserial_generic
[    3.130000] usbserial: USB Serial support registered for generic
[    3.140000] usbcore: registered new interface driver cp210x
[    3.150000] usbserial: USB Serial support registered for cp210x
[    3.150000] usbcore: registered new interface driver option
[    3.160000] usbserial: USB Serial support registered for GSM modem (1-port)
[    3.170000] usbcore: registered new interface driver usbhid
[    3.170000] usbhid: USB HID core driver

It's ehci-platform. Tried it using the same device node - same problem with timeout during halt (for record - I've moved all register initialization to PHY code to test this)

ehci-hcd reads value 0x10000001 from hc_capbase (exactly reg from dts) and takes least significant byte (0x01). But that value doesn't make sense according to specification (it must contain offset of next set of registers - obviously not 1). What do makes sense - value 0x10 (most significant byte - or least significant in reversed endianess). I believe it points to issues with endianess between driver and controller. ehci-platform have some endianess options available (Documentation/devicetree/bindings/usb/generic-ehci.yaml), but I didn't look at it well for now (and that's what I'm planning to do)

There is ehci-pci load during the oem reboot, maybe enabling will help somehow?

I believe that's the case when OEMs don't cares about disabling unneeded SDKs defaults

Perhaps we can do something similar to bcma-hcd and alike that deals with platform_device struct?

Didn't get you

Similar way it is done in the xhci usb driver for the closed rtl8198c pull request?

Seems like simple workaround for PHY initializing. Anyway, what are we gonna do in custom .reset?

@jameywine
Copy link
Copy Markdown
Owner Author

It's ehci-platform. Tried it using the same device node - same problem with timeout during halt (for record - I've moved all register initialization to PHY code to test this)

Ah so that is what happens with ehci-platform from the usb.c code.. its platform device that is added with platform_add_devices function during init and ehci-platform driver picks it up?

static struct resource bsp_usb_ehci_resource[] = {
	[0] = {
		.start = PADDR(BSP_EHCI_BASE),
		.end   = PADDR(BSP_EHCI_BASE) + BSP_EHCI_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = BSP_USB_2_IRQ,
		.end   = BSP_USB_2_IRQ,
		.flags = IORESOURCE_IRQ,
	}
};

static struct platform_device bsp_usb_ehci_device = {
	//.name          = "rtl86xx-ehci",
	.name          = "ehci-platform",
	.id            = 0,
	.num_resources = ARRAY_SIZE(bsp_usb_ehci_resource),
	.resource      = bsp_usb_ehci_resource,
	.dev           = {
		.dma_mask = &bsp_usb_dmamask,
		.coherent_dma_mask = 0xFFFFFFFFUL,
	}
};

static struct platform_device *bsp_usb_devs0[] __initdata = {
#ifdef CONFIG_USB_OHCI_HCD
	&bsp_usb_ohci_device,
#endif
#ifdef CONFIG_USB_EHCI_HCD
	&bsp_usb_ehci_device,
#endif
};

Didn't get you

I was just saying that doing similar thing these drivers do (i.e creating platform_device, inializing and then adding with Actually nevermind that, for some reason i thought they were using platform_add_devices but upon further look, i realize i was thinking of something else.

Seems like simple workaround for PHY initializing. Anyway, what are we gonna do in custom .reset?

Good point, since we are doing phy init through a proper phy driver, i don't think we need it

So, we just need to instigate what is so different about the platform_device *bsp_usb_devs0 from usb.c and why does the similar device tree node calling the same driver doesn't

@jameywine
Copy link
Copy Markdown
Owner Author

jameywine commented Feb 9, 2026

@ProMix0 I think i found the potential reason for this?

Browsing through the patches of the realtek's edited linux from GPL archive versus the vanilla linux, i stumbled upon this

diff -urN linux-5.10.226/drivers/usb/host/ehci.h rtl9607-u2.2_GP3000/rtl9607-u2.2/linux-5.10.x/drivers/usb/host/ehci.h
--- linux-5.10.226/drivers/usb/host/ehci.h	2024-09-12 14:06:51.000000000 +0500
+++ rtl9607-u2.2_GP3000/rtl9607-u2.2/linux-5.10.x/drivers/usb/host/ehci.h	2025-06-11 07:42:22.000000000 +0500
@@ -739,6 +739,9 @@
 static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
 		__u32 __iomem *regs)
 {
+#if defined(CONFIG_RTK_MIPS_SOC)
+	return (le32_to_cpu((*(volatile unsigned long *)(regs))));
+#else
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 	return ehci_big_endian_mmio(ehci) ?
 		readl_be(regs) :
@@ -746,6 +749,7 @@
 #else
 	return readl(regs);
 #endif
+#endif
 }
 
 #ifdef CONFIG_SOC_IMX28
@@ -763,6 +767,9 @@
 static inline void ehci_writel(const struct ehci_hcd *ehci,
 		const unsigned int val, __u32 __iomem *regs)
 {
+#if defined(CONFIG_RTK_MIPS_SOC)
+	((*(volatile unsigned long *)(regs))=cpu_to_le32(val));
+#else
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 	ehci_big_endian_mmio(ehci) ?
 		writel_be(val, regs) :
@@ -773,6 +780,7 @@
 	else
 		writel(val, regs);
 #endif
+#endif
 }

So realtek has simply changed how ehci reads and writes are done and used le32_to_cpu and cpu_to_le32

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Feb 10, 2026

Thing is, readl() (and ioread32()) read values in native endianess (big endian). There is readl_be(), which do cpu_to_be32, which effectively does nothing for BE cpu. And there is ioread32_be(), which do byteswap, resulting in LE values (ironic)

There is SWAP_IO_SPACE, which might allow readl() to return little endian values, but system hangs, what means that there is (a lot of?) code, depending on native endianess

The only solution I see right now - define ehci-platform to use readl_be() and redefine readl_be() there (just like it done for IXP4XX)

P.S. With correct endianess ehci-platform works fine - at least it reads USB stick

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Mar 5, 2026

Tested driver with both revision, seems to be working for me (still usb sticks read and write, XHCI not tested)

@jameywine jameywine force-pushed the rtl9607c-dev branch 3 times, most recently from 546214c to c1a27b2 Compare March 20, 2026 07:59
@jameywine jameywine marked this pull request as ready for review March 26, 2026 17:45
@jameywine
Copy link
Copy Markdown
Owner Author

This should be in a good shape to send upstream. For now i will only send the usb2 phy part as these are the ones that we have tested and confirmed to be working.

I am still not sure about ehci/ohci quirks but i guess it wouldn't hurt to send it for comments at the very least and hear opinions of usb maintainers.

Also, @ProMix0 as you were helping with quite a bit with usb2 phy part, are you okay if i add you as co-developed-by?

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Mar 26, 2026

Okay. I'm interested in upstream guys opinion about all that endianess stuff

@jameywine
Copy link
Copy Markdown
Owner Author

This commit adds support for EHCI and OHCI controller on RTL9607.
It uses the generic ehci-platform and ohci-platform drivers and
due to endian issues a quirk patch was added that adds
"force little endian" property which rtl9607 needs for its
EHCI and OCHI controller.

There is also a patch which adds support for USB2 PHY
on RTL9607 to the existing phy-rtk-usb2 driver.

Co-developed-by: ProMix0 <misha.zavertkin@mail.ru>
Signed-off-by: ProMix0 <misha.zavertkin@mail.ru>
Signed-off-by: Rustam Adilov <adilov@tutamail.com>
This commit adds support for XHCI controller on RTL9607
with the help of generic-xhci driver.

There is also a patch that adds support for rtl9607 to the
existing phy-rtk-usb3 driver.

Signed-off-by: Rustam Adilov <adilov@tutamail.com>
@jameywine
Copy link
Copy Markdown
Owner Author

I am thinking of whether it would be better to use swab32 functions instead of _le32 ones for in usb2 phy reads and writes.

@ProMix0
Copy link
Copy Markdown
Collaborator

ProMix0 commented Apr 13, 2026

I think it's better to tell why we are doing that (_le32), rather than "we just doing that" (swab32)

On the other side, there is REVERSED in GPIO driver flags, which doing reverse without further explanations. But personally I don't like that

@jameywine
Copy link
Copy Markdown
Owner Author

I think it's better to tell why we are doing that (_le32), rather than "we just doing that" (swab32)

My main thoughts are just to solve the errors that come from using these _le32 and also partly because of LLM review.

Explaining the reason behind these would be the same as with _le32 and that is Realtek's USB host memory region is fucked up and we need to perform byte swap to make it work, whether it is swab32 or le32.

At the very least, swab32 makes for a cleaner code.

On the other side, there is REVERSED in GPIO driver flags, which doing reverse without further explanations. But personally I don't like that

I think it is fine and there has been a hefty conversation chain on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants