arch/arm/ameba: enable SMP on AmebaSmart CA32 (RTL8730E)

RTL8730E has dual Cortex-A32 cores (CA32) in the AP domain.  Core1 is
powered off by default and requires an explicit HSYS power-on sequence
before ATF SP_MIN can service the PSCI CPU_ON call.  Without it, SP_MIN
writes the entry point to the mailbox and times out waiting for Core1 to
poll it.

Add rtl8730e_core1_power_on() that mirrors SDK smp.c:rtk_core1_power_on():
assert reset, assert isolation, two-stage power-on with up_udelay() for
correct 50/50/500/50 us timing, then release isolation and reset.  Call it
from up_cpu_start() before psci_cpu_on().

Enable CONFIG_SMP / CONFIG_SMP_NCPUS=2 / CONFIG_ARM_PSCI in the nsh
defconfig.

Enabling SMP also exposed a latent WHC skb alignment bug: the Realtek
WHC WiFi driver keeps the AP/NP DDR views coherent with by-VA
DCache_Clean/Invalidate at SKB_CACHE_SZ (64 on RTL8730E) granularity,
which requires every skb buffer to be cache-line aligned.  The port had
omitted CONFIG_MM_DEFAULT_ALIGNMENT (defaulting to 8; the 8721Dx parts
set 32), so heap-allocated skb buffers were unaligned and the cache
maintenance spilled onto the neighbouring skb struct, corrupting its
immutable buf pointer (seen as skb->buf = 0x05 and a TX memcpy data
abort on "renew wlan0").  This was harmless on single core -- the
non-shareable DDR mapping made the stray maintenance a no-op -- but the
SMP shareable mapping plus real dual-core concurrency turned it into a
hard fault.  Set CONFIG_MM_DEFAULT_ALIGNMENT=64 in the nsh defconfig.

Hardware verified on RTL8730E (C-cut): /proc/cpuinfo shows both processor 0
and processor 1; getprime 2 completes two concurrent threads in ~573 ms
(same as single-thread), confirming true parallel execution across both cores.
"renew wlan0" now obtains a DHCP lease (192.168.1.101) without faulting.

Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
This commit is contained in:
dechao_gong 2026-09-15 13:01:04 +08:00 • committed by Xiang Xiao
parent 7b5861122f
commit 4416660ce2
3 changed files with 86 additions and 3 deletions

View file

@ -170,9 +170,16 @@ bool os_heap_add(uint8_t *start_addr, size_t heap_size)
* the NP DMAs them, so an unaligned base would clobber neighbouring data on
* cache maintenance. whc_ipc_host_init_skb() outright rejects an unaligned
* skb_data_buf ("skb_data_buf malloc fail!"), leaving the skb pool empty and
* the TX path handing the NP a garbage buffer pointer. This is guaranteed
* by CONFIG_MM_DEFAULT_ALIGNMENT=32 (>= SKB_CACHE_SZ) -- every NuttX heap
* block is then cache-line aligned, so plain kmm_* suffices here.
* the TX path handing the NP a garbage buffer pointer. Worse, when the pool
* squeaks past that check but is not aligned to the full cache line, the
* driver's by-VA DCache_Clean/Invalidate spills onto the neighbouring skb
* struct and corrupts its (immutable) buf pointer, so a later TX memcpy
* faults on a garbage skb->data (seen as skb->buf = 0x05).
*
* This is guaranteed by CONFIG_MM_DEFAULT_ALIGNMENT >= SKB_CACHE_SZ -- every
* NuttX heap block is then cache-line aligned, so plain kmm_* suffices here.
* SKB_CACHE_SZ is 32 on the other Ameba WHC parts but 64 on AmebaSmart
* (RTL8730E), so that board's defconfig sets CONFIG_MM_DEFAULT_ALIGNMENT=64.
*/
void *rtos_mem_malloc(uint32_t size)

View file

@ -25,6 +25,7 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include "arm_internal.h"
@ -132,6 +133,71 @@ void arm_boot(void)
#endif
}
/* RTL8730E HSYS / CA32 register addresses for Core1 power sequencing.
* Core1 is powered off by default; ATF SP_MIN waits for Core1 to poll its
* mailbox but the core never wakes unless the HSYS power rails are enabled
* first. These constants mirror the SDK smp.c / ameba_hsys.h definitions
* without requiring vendor headers.
*/
#define RTL8730E_HSYS_BASE 0x41000000u
#define RTL8730E_HSYS_HP_PWC 0x000u
#define RTL8730E_HSYS_HP_ISO 0x004u
#define RTL8730E_CA32_RST_CTRL 0x41000204u
#define HSYS_PSW_HP_AP_CORE(x) (((x) & 0x3u) << 4)
#define HSYS_PSW_HP_AP_CORE_2ND(x) (((x) & 0x3u) << 6)
#define HSYS_ISO_HP_AP_CORE(x) (((x) & 0x3u) << 4)
#define HSYS_GET_ISO_HP_AP_CORE(x) (((x) >> 4) & 0x3u)
#define CA32_NCOREPORESET(x) (((x) & 0x3u) << 0)
#define CA32_NCORERESET(x) (((x) & 0x3u) << 4)
static void rtl8730e_core1_power_on(void)
{
volatile uint32_t *pwc = (volatile uint32_t *)(RTL8730E_HSYS_BASE +
RTL8730E_HSYS_HP_PWC);
volatile uint32_t *iso = (volatile uint32_t *)(RTL8730E_HSYS_BASE +
RTL8730E_HSYS_HP_ISO);
volatile uint32_t *rst = (volatile uint32_t *)RTL8730E_CA32_RST_CTRL;
uint32_t val;
/* Assert reset on core1 */
*rst &= ~(CA32_NCOREPORESET(0x2u) | CA32_NCORERESET(0x2u));
/* Assert isolation on core1 */
val = *iso;
val |= HSYS_ISO_HP_AP_CORE(0x2u);
*iso = val;
up_udelay(50);
/* First-stage power-on (mask 0x3 keeps core0 rails stable) */
val = *pwc;
val |= HSYS_PSW_HP_AP_CORE(0x3u);
*pwc = val;
up_udelay(50);
/* Second-stage power-on */
val = *pwc;
val |= HSYS_PSW_HP_AP_CORE_2ND(0x3u);
*pwc = val;
up_udelay(500);
/* Release isolation */
val = *iso;
val &= ~HSYS_ISO_HP_AP_CORE(0x3u);
*iso = val;
up_udelay(50);
/* Release reset */
*rst |= (CA32_NCOREPORESET(0x2u) | CA32_NCORERESET(0x2u));
}
#if defined(CONFIG_ARM_PSCI) && defined(CONFIG_SMP)
int up_cpu_start(int cpu)
{
@ -149,6 +215,12 @@ int up_cpu_start(int cpu)
UP_DSB();
#endif
if (cpu == 1)
{
rtl8730e_core1_power_on();
up_udelay(40);
}
return psci_cpu_on(cpu, (uintptr_t)__start);
}
#endif

View file

@ -13,6 +13,9 @@ CONFIG_ARCH_BOARD_CA32_EVB=y
CONFIG_ARCH_CHIP="rtl8730e"
CONFIG_ARCH_CHIP_RTL8730E=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARM_PSCI=y
CONFIG_SMP=y
CONFIG_SMP_NCPUS=2
CONFIG_ARCH_LOWVECTORS=y
CONFIG_IDENTITY_TEXTMAP=y
CONFIG_ARM_SEMIHOSTING_HOSTFS=y
@ -38,6 +41,7 @@ CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=4096
CONFIG_INIT_ENTRYPOINT="init_main"
CONFIG_LIBC_EXECFUNCS=y
CONFIG_MM_DEFAULT_ALIGNMENT=64
CONFIG_MODULE=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512