Skip to content

fix aic8800 WiFi & BT on lichee-pi-4a #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 7, 2025

Conversation

nekorouter
Copy link

@nekorouter nekorouter commented Jul 3, 2025

fix aic8800 WiFi & BT on lichee-pi-4a

  • fix rfkill not working to properly toggle gpio for aic8800 (thanks to @KamijoToma for resolving this bug)
  • add uart1 & uart3
  • cherry-pick sdhci-of-dwcmshc fix from upstream (torvalds@27e8fe0)
  • fix bluetooth tty number to ttyS4
  • rollback to manually attach rtl8723 HCI port using systemd script
  • update aic8800 driver to 20241119 (v4.0)

Summary by Sourcery

Fix GPIO-based RF kill handling and module configuration for the AIC8800 wireless on the Lichee-Pi-4A.

Enhancements:

  • Use of_get_named_gpio instead of deprecated of_find_gpio/desc_to_gpio for WiFi and Bluetooth power pins
  • Add null checks around gpio_free and driver data deallocation in rfkill-wlan remove path

Build:

  • Switch rfkill-wlan.o and rfkill-bt.o from built-in (obj-y) to loadable modules (obj-m)

Copy link

sourcery-ai bot commented Jul 3, 2025

Reviewer's Guide

This PR refactors RFKill GPIO handling to use the DT-friendly of_get_named_gpio interface with updated property names, strengthens cleanup logic, switches the WLAN/BT drivers to build as loadable modules, enables UART1/3 in the Lichee-Pi-4A device tree, and bumps the AIC8800 Wi-Fi driver to v4.0.

ER diagram for device tree UART additions

erDiagram
    SOC ||--o{ UART1 : enables
    SOC ||--o{ UART3 : enables
    SOC {
        string name
    }
    UART1 {
        int id
        string status
    }
    UART3 {
        int id
        string status
    }
Loading

File-Level Changes

Change Details Files
Standardize RFKill GPIO initialization via of_get_named_gpio
  • Replaced of_find_gpio + desc_to_gpio with of_get_named_gpio
  • Updated DT property names to "WIFI,poweren-gpios" and "BT,power-gpios"
  • Adjusted LOG messages to reflect new GPIO values
net/rfkill/rfkill-wlan.c
net/rfkill/rfkill-bt.c
Harden RFKill WLAN cleanup path
  • Added null-pointer guards around gpio_free and kfree
  • Commented out obsolete gpio_is_valid check
  • Ensured rfkill struct is only freed if non-null
net/rfkill/rfkill-wlan.c
Convert WLAN/BT RFKill drivers to loadable modules
  • Changed obj-y to obj-m for rfkill-wlan.o and rfkill-bt.o in Makefile
net/rfkill/Makefile
Expose UART1 and UART3 in Lichee-Pi-4A Device Tree
  • Added pinctrl configurations for uart1 and uart3
  • Updated aliases and pin-mux nodes accordingly
arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts
Upgrade AIC8800 Wi-Fi driver to version 4.0
  • Bumped driver version to v4.0
  • Updated API calls and init routines to match v4.0 changes
  • Adjusted Kconfig/Makefile entries for new driver
drivers/net/wireless/aic8800/*

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @nekorouter - I've reviewed your changes - here's some feedback:

  • The PR description mentions adding UART1 & UART3 entries, but I don’t see any DTS updates for those in the diff—please include them or remove that reference to avoid confusion.
  • Since you’re converting rfkill-wlan and rfkill-bt into loadable modules, please verify that Kconfig/module dependencies are updated so they load in the correct order under CONFIG_RFKILL_GPIO.
  • Consider switching to the gpiod descriptor API (e.g. devm_gpiod_get_optional()) for GPIO handling to simplify resource management instead of manual of_get_named_gpio()/gpio_free() calls.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The PR description mentions adding UART1 & UART3 entries, but I don’t see any DTS updates for those in the diff—please include them or remove that reference to avoid confusion.
- Since you’re converting rfkill-wlan and rfkill-bt into loadable modules, please verify that Kconfig/module dependencies are updated so they load in the correct order under CONFIG_RFKILL_GPIO.
- Consider switching to the gpiod descriptor API (e.g. devm_gpiod_get_optional()) for GPIO handling to simplify resource management instead of manual of_get_named_gpio()/gpio_free() calls.

## Individual Comments

### Comment 1
<location> `net/rfkill/rfkill-wlan.c:198` </location>
<code_context>
 	struct rfkill_wlan_data *rfkill = platform_get_drvdata(pdev);

-	if (gpio_is_valid(rfkill->pdata->power_n.io))
+//	if (gpio_is_valid(rfkill->pdata->power_n.io))
+	if (rfkill && rfkill->pdata && gpio_is_valid(rfkill->pdata->power_n.io))
 		gpio_free(rfkill->pdata->power_n.io);
-
</code_context>

<issue_to_address>
Added null checks for rfkill and rfkill->pdata before gpio_is_valid.

If rfkill or rfkill->pdata is null, it may signal a logic issue elsewhere. Consider adding logging or explicit handling for these cases.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
//	if (gpio_is_valid(rfkill->pdata->power_n.io))
	if (rfkill && rfkill->pdata && gpio_is_valid(rfkill->pdata->power_n.io))
		gpio_free(rfkill->pdata->power_n.io);
=======
	if (!rfkill) {
		pr_err("%s: rfkill is NULL in %s\n", __func__, __FILE__);
	} else if (!rfkill->pdata) {
		pr_err("%s: rfkill->pdata is NULL in %s\n", __func__, __FILE__);
	} else if (gpio_is_valid(rfkill->pdata->power_n.io)) {
		gpio_free(rfkill->pdata->power_n.io);
	}
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `net/rfkill/rfkill-wlan.c:201` </location>
<code_context>
 		gpio_free(rfkill->pdata->power_n.io);
-
-	kfree(rfkill);
+	if (rfkill)
+		kfree(rfkill);
 	g_rfkill = NULL;

</code_context>

<issue_to_address>
Redundant null check before kfree.

Since kfree handles NULL pointers safely, you can remove the explicit null check to simplify the code.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 198 to 199
// if (gpio_is_valid(rfkill->pdata->power_n.io))
if (rfkill && rfkill->pdata && gpio_is_valid(rfkill->pdata->power_n.io))
gpio_free(rfkill->pdata->power_n.io);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Added null checks for rfkill and rfkill->pdata before gpio_is_valid.

If rfkill or rfkill->pdata is null, it may signal a logic issue elsewhere. Consider adding logging or explicit handling for these cases.

Suggested change
// if (gpio_is_valid(rfkill->pdata->power_n.io))
if (rfkill && rfkill->pdata && gpio_is_valid(rfkill->pdata->power_n.io))
gpio_free(rfkill->pdata->power_n.io);
if (!rfkill) {
pr_err("%s: rfkill is NULL in %s\n", __func__, __FILE__);
} else if (!rfkill->pdata) {
pr_err("%s: rfkill->pdata is NULL in %s\n", __func__, __FILE__);
} else if (gpio_is_valid(rfkill->pdata->power_n.io)) {
gpio_free(rfkill->pdata->power_n.io);
}

if (rfkill)
kfree(rfkill);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Redundant null check before kfree.

Since kfree handles NULL pointers safely, you can remove the explicit null check to simplify the code.

@nekorouter nekorouter changed the title WIP: fix&update aic8800 on lichee-pi-4a WIP: fix aic8800 wifi on lichee-pi-4a Jul 4, 2025
nekorouter and others added 3 commits July 4, 2025 15:07
Fix functions in rfkill-wlan / rfkill-bt for getting gpio name from devicetree.
Fix null pointer error in rfkill-wlan.

Signed-off-by: KamijoToma <[email protected]>
Signed-off-by: NekoRouter <[email protected]>
Add definition for uart1 and uart3.

Signed-off-by: NekoRouter <[email protected]>
While working with the T-Head 1520 LicheePi4A SoC, certain conditions
arose that allowed me to reproduce a race issue in the sdhci code.

To reproduce the bug, you need to enable the sdio1 controller in the
device tree file
`arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi` as follows:

&sdio1 {
	bus-width = <4>;
	max-frequency = <100000000>;
	no-sd;
	no-mmc;
	broken-cd;
	cap-sd-highspeed;
	post-power-on-delay-ms = <50>;
	status = "okay";
	wakeup-source;
	keep-power-in-suspend;
};

When resetting the SoC using the reset button, the following messages
appear in the dmesg log:

[    8.164898] mmc2: Got command interrupt 0x00000001 even though no
command operation was in progress.
[    8.174054] mmc2: sdhci: ============ SDHCI REGISTER DUMP ===========
[    8.180503] mmc2: sdhci: Sys addr:  0x00000000 | Version:  0x00000005
[    8.186950] mmc2: sdhci: Blk size:  0x00000000 | Blk cnt:  0x00000000
[    8.193395] mmc2: sdhci: Argument:  0x00000000 | Trn mode: 0x00000000
[    8.199841] mmc2: sdhci: Present:   0x03da0000 | Host ctl: 0x00000000
[    8.206287] mmc2: sdhci: Power:     0x0000000f | Blk gap:  0x00000000
[    8.212733] mmc2: sdhci: Wake-up:   0x00000000 | Clock:    0x0000decf
[    8.219178] mmc2: sdhci: Timeout:   0x00000000 | Int stat: 0x00000000
[    8.225622] mmc2: sdhci: Int enab:  0x00ff1003 | Sig enab: 0x00ff1003
[    8.232068] mmc2: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000000
[    8.238513] mmc2: sdhci: Caps:      0x3f69c881 | Caps_1:   0x08008177
[    8.244959] mmc2: sdhci: Cmd:       0x00000502 | Max curr: 0x00191919
[    8.254115] mmc2: sdhci: Resp[0]:   0x00001009 | Resp[1]:  0x00000000
[    8.260561] mmc2: sdhci: Resp[2]:   0x00000000 | Resp[3]:  0x00000000
[    8.267005] mmc2: sdhci: Host ctl2: 0x00001000
[    8.271453] mmc2: sdhci: ADMA Err:  0x00000000 | ADMA Ptr:
0x0000000000000000
[    8.278594] mmc2: sdhci: ============================================

I also enabled some traces to better understand the problem:

     kworker/3:1-62      [003] .....     8.163538: mmc_request_start:
mmc2: start struct mmc_request[000000000d30cc0c]: cmd_opcode=5
cmd_arg=0x0 cmd_flags=0x2e1 cmd_retries=0 stop_opcode=0 stop_arg=0x0
stop_flags=0x0 stop_retries=0 sbc_opcode=0 sbc_arg=0x0 sbc_flags=0x0
sbc_retires=0 blocks=0 block_size=0 blk_addr=0 data_flags=0x0 tag=0
can_retune=0 doing_retune=0 retune_now=0 need_retune=0 hold_retune=1
retune_period=0
          <idle>-0       [000] d.h2.     8.164816: sdhci_cmd_irq:
hw_name=ffe70a0000.mmc quirks=0x2008008 quirks2=0x8 intmask=0x10000
intmask_p=0x18000
     irq/24-mmc2-96      [000] .....     8.164840: sdhci_thread_irq:
msg=
     irq/24-mmc2-96      [000] d.h2.     8.164896: sdhci_cmd_irq:
hw_name=ffe70a0000.mmc quirks=0x2008008 quirks2=0x8 intmask=0x1
intmask_p=0x1
     irq/24-mmc2-96      [000] .....     8.285142: mmc_request_done:
mmc2: end struct mmc_request[000000000d30cc0c]: cmd_opcode=5
cmd_err=-110 cmd_resp=0x0 0x0 0x0 0x0 cmd_retries=0 stop_opcode=0
stop_err=0 stop_resp=0x0 0x0 0x0 0x0 stop_retries=0 sbc_opcode=0
sbc_err=0 sbc_resp=0x0 0x0 0x0 0x0 sbc_retries=0 bytes_xfered=0
data_err=0 tag=0 can_retune=0 doing_retune=0 retune_now=0 need_retune=0
hold_retune=1 retune_period=0

Here's what happens: the __mmc_start_request function is called with
opcode 5. Since the power to the Wi-Fi card, which resides on this SDIO
bus, is initially off after the reset, an interrupt SDHCI_INT_TIMEOUT is
triggered. Immediately after that, a second interrupt SDHCI_INT_RESPONSE
is triggered. Depending on the exact timing, these conditions can
trigger the following race problem:

1) The sdhci_cmd_irq top half handles the command as an error. It sets
   host->cmd to NULL and host->pending_reset to true.
2) The sdhci_thread_irq bottom half is scheduled next and executes faster
   than the second interrupt handler for SDHCI_INT_RESPONSE. It clears
   host->pending_reset before the SDHCI_INT_RESPONSE handler runs.
3) The pending interrupt SDHCI_INT_RESPONSE handler gets called, triggering
   a code path that prints: "mmc2: Got command interrupt 0x00000001 even
   though no command operation was in progress."

To solve this issue, we need to clear pending interrupts when resetting
host->pending_reset. This ensures that after sdhci_threaded_irq restores
interrupts, there are no pending stale interrupts.

The behavior observed here is non-compliant with the SDHCI standard.
Place the code in the sdhci-of-dwcmshc driver to account for a
hardware-specific quirk instead of the core SDHCI code.

Signed-off-by: Michal Wilczynski <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
Fixes: 43658a5 ("mmc: sdhci-of-dwcmshc: Add support for T-Head TH1520")
Cc: [email protected]
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Ulf Hansson <[email protected]>
Signed-off-by: NekoRouter <[email protected]>
@nekorouter nekorouter changed the title WIP: fix aic8800 wifi on lichee-pi-4a fix aic8800 wifi on lichee-pi-4a Jul 4, 2025
TH1520 has 6 serial port, expand 8250 runtime uart port number up to 6 to match with hardware.

Signed-off-by: NekoRouter <[email protected]>
For rtl8723/aic8800 different hardware compatibility, using systemd to manually attach HCI port;
This definition can conflict with aic8800, so disable it for now.

Signed-off-by: NekoRouter <[email protected]>
Update aic8800 driver to 20241119 (aic8800d_linux_sdk_V4.0_2024_1119_06da8476).

Signed-off-by: NekoRouter <[email protected]>
@nekorouter nekorouter changed the title fix aic8800 wifi on lichee-pi-4a fix aic8800 WiFi & BT on lichee-pi-4a Jul 7, 2025
@RevySR RevySR merged commit a0e92c7 into revyos:th1520-lts Jul 7, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants