From nobody Fri Oct 2 01:15:10 2026 Received: from angie.orcam.me.uk (angie.orcam.me.uk [78.133.224.34]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5F00144213A; Thu, 6 Aug 2026 10:54:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.133.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013660; cv=none; b=QgyI2GBxHftm7JgQc5+fOmRqNiHo+BrxP90xgejNecPbrohBSAfxhetV5RGCqzV9T/0MQO0PkmlVVmoexJh9lSKGuOAkNTEoz9sDT+OU1hlrpnAeMTWXaxkmVMpm5ZEGkkg/3WXz7ayLPJnWAMeYblkz1VaVklDJy5f/hzn8xdc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013660; c=relaxed/simple; bh=M/q0w0HkJkXLGwmMs3rK0NDDqH4SLiaI63tSPLES40Y=; h=Date:From:To:cc:Subject:In-Reply-To:Message-ID:References: MIME-Version:Content-Type; b=AXhro0sFXA3Io/FT/aq2UYKqy4z3CDYY61vH3VsFM9Ksw/WlUNI7nZ355xnMDSkcOfTv0tzEpLSdcOHTc3W2yXtfU2b7GF3sgVVkGqGY5E3kuhPvAo0HYUsJrXp9Qt0YdKzSMBErwVQOrAV/FC+PMLm50xYvJT7lFXfM6kJeflE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk; spf=none smtp.mailfrom=orcam.me.uk; arc=none smtp.client-ip=78.133.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=orcam.me.uk Received: by angie.orcam.me.uk (Postfix, from userid 500) id DC09692009D; Thu, 6 Aug 2026 12:54:16 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id D627692009B; Thu, 6 Aug 2026 11:54:16 +0100 (BST) Date: Thu, 6 Aug 2026 11:54:16 +0100 (BST) From: "Maciej W. Rozycki" To: Thomas Bogendoerfer , Greg Kroah-Hartman , Jiri Slaby cc: linux-mips@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 1/3] serial: sb1250-duart: Fix console message clobbering at channel resets In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Ensure any characters outstanding have been sent before issuing channel=20 resets so as to prevent messages issued to the bootconsole from getting=20 clobbered. Contrary to device documentation at the time the transmitter empty bit=20 is set only the transmit FIFO has been drained and there is still data=20 outstanding in the transmitter shift register, so wait an extra amount=20 of time for that register to drain too. This also prevents subsequent=20 messages produced to the console from getting clobbered, owing to what seems a transmitter synchronisation issue. When called from sbd_serial_console_init() it is too early for fsleep()=20 to work and even before lpj has been calculated, and therefore neither=20 udelay() works. Therefore delay by hand, observing that roughly 170=20 iterations over an Input Port Register read are sufficient for the=20 transmitter to drain with the BCM1250 SoC clocked at 800MHz, so using=20 2048 iterations should give enough margin including in particular for=20 the faster BCM1480 SoC clocked at 1GHz. Fixes: b45d52797432 ("sb1250-duart.c: SB1250 DUART serial support") Signed-off-by: Maciej W. Rozycki Cc: stable@vger.kernel.org # v2.6.23+ --- Changes from v2 (1/6),=20 : - In the early-boot case delay by hand rather than via udelay() and switch=20 to fsleep() for the late execution case. - Update the Fixes: tag now that the delay has been sanitised and is more=20 than just a placeholder. Changes from v1 (1/4), : - Sanitise the change heading. --- drivers/tty/serial/sb1250-duart.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) linux-serial-sb1250-duart-reset-drain.diff Index: linux-swarm64/drivers/tty/serial/sb1250-duart.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- linux-swarm64.orig/drivers/tty/serial/sb1250-duart.c +++ linux-swarm64/drivers/tty/serial/sb1250-duart.c @@ -516,6 +516,33 @@ static void sbd_init_port(struct sbd_por =20 if (sport->initialised) return; + /* + * Contrary to documentation, which says that the transmitter + * empty bit is set when "there are no characters to send and + * the transmitter is idle," the bit is already set by hardware + * once the transmit FIFO has been drained only and while the + * transmitter shift register still holds data being supplied + * to the line. Consequently issuing a transmitter reset at + * this point causes the final character outstanding to be lost. + * + * Moreover, resetting the transmitter while transmission is + * in progress appears to make the transmitter go out of sync + * and subsequent characters issued after the transmitter has + * been reprogrammed and re-enabled are sent corrupted or with + * their bit patterns shifted. + * + * So once the transmitter empty bit has been set wait an extra + * amount of time, sufficient for the transmitter shift register + * to drain at 115200bps, which is the baud rate setting used by + * a standard CFE firmware compilation. + */ + sbd_line_drain(sport); + if (IS_ENABLED(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && + system_state < SYSTEM_SCHEDULING) + for (int i =3D 0; i < 2048; i++) + read_sbdshr(sport, R_DUART_IN_PORT); + else + fsleep(100); =20 /* There is no DUART reset feature, so just set some sane defaults. */ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX); From nobody Fri Oct 2 01:15:10 2026 Received: from angie.orcam.me.uk (angie.orcam.me.uk [78.133.224.34]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 606013C585B; Thu, 6 Aug 2026 10:54:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.133.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013664; cv=none; b=QTwF1HiuVLpcvtI3nC6Z8mrMAAfdr9RIX7NYtf7VjPQ4gYaypPMA3EQ6+7+1aUAff3fD93+jVI5EISKp/M4I57wGA3qYmCNgZSkCCur+a0fmZW7zZuZd01lgLZAtDptAc57+q/G1kmZB/YGk8DT3+KFqty/7ByAchBlv8/KM0GM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013664; c=relaxed/simple; bh=COUB0rok/1qglYUQLEE98d4VyQvksWsyXzffcK4OyPc=; h=Date:From:To:cc:Subject:In-Reply-To:Message-ID:References: MIME-Version:Content-Type; b=tBXpAqrf+uII+Mi3PERwnWoJPImwwybzXi2Q9jK69/Oex8Wc/wX7XBdZs0b/1NQ7jro1elc0hNrxEZWHXkYo1GClL+vw3Cus9/opOjC3s8WNQX7PZn0hBphDfe0RAI47iPkwUTMULM08kODVg2E2butdIsXsuVMeUVRsXRlStWQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk; spf=none smtp.mailfrom=orcam.me.uk; arc=none smtp.client-ip=78.133.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=orcam.me.uk Received: by angie.orcam.me.uk (Postfix, from userid 500) id 6636992009C; Thu, 6 Aug 2026 12:54:21 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id 5F75692009B; Thu, 6 Aug 2026 11:54:21 +0100 (BST) Date: Thu, 6 Aug 2026 11:54:21 +0100 (BST) From: "Maciej W. Rozycki" To: Thomas Bogendoerfer , Greg Kroah-Hartman , Jiri Slaby cc: linux-mips@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 2/3] serial: sb1250-duart: Fix bootconsole handover lockup In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Calling sbd_init_port() in the course of setting up the serial device=20 causes line parameters to be messed up and the transmitter disabled. =20 We've been lucky in that no message is usually produced to the kernel=20 log between this call and the later call to uart_set_options() in the=20 course of console setup done by sbd_serial_console_init(), or the system=20 would hang as the console output handler in CFE tried to access a port=20 whose transmitter has been disabled and line parameters messed up. It'll change with the next change to the driver, so fix sbd_init_port()=20 such that line parameters are set for 115200n8 console operation as with=20 the CFE firmware and the transmitter re-enabled after reset. Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to en= able runtime PM") Signed-off-by: Maciej W. Rozycki Cc: stable@vger.kernel.org # v6.5+ Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- No change from v2 (2/3), . Changes from v1 (2/4), : - Sanitise the change heading. --- drivers/tty/serial/sb1250-duart.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) linux-serial-sb1250-duart-prom-console.diff Index: linux-macro/drivers/tty/serial/sb1250-duart.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- linux-macro.orig/drivers/tty/serial/sb1250-duart.c +++ linux-macro/drivers/tty/serial/sb1250-duart.c @@ -542,14 +542,19 @@ static void sbd_init_port(struct sbd_por /* There is no DUART reset feature, so just set some sane defaults. */ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX); write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX); - write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8); + write_sbdchn(sport, R_DUART_MODE_REG_1, + V_DUART_PARITY_MODE_NONE | V_DUART_BITS_PER_CHAR_8); write_sbdchn(sport, R_DUART_MODE_REG_2, 0); + write_sbdchn(sport, R_DUART_CLK_SEL, V_DUART_BAUD_RATE(115200)); write_sbdchn(sport, R_DUART_FULL_CTL, V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15)); write_sbdchn(sport, R_DUART_OPCR_X, 0); write_sbdchn(sport, R_DUART_AUXCTL_X, 0); write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0); =20 + /* Re-enable transmission for the initial PROM-based console. */ + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); + sport->initialised =3D 1; } From nobody Fri Oct 2 01:15:10 2026 Received: from angie.orcam.me.uk (angie.orcam.me.uk [78.133.224.34]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6520A439335; Thu, 6 Aug 2026 10:54:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=78.133.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013671; cv=none; b=mk2A9K7dBVndJleKGm0saAceT8OP7FVPj0i/VQ51mtxGGSyZEDhql2OcDEXlHHIXgtYGuMjwIsdx5ATr8YPoWfnwEpmh0JpNddzdWr9cjm933UGw3M1f4uNiVJPYpUtWUE2qiSR7dx/QI9xeowxLh57jDsVluxrNgMKOWnAtZxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786013671; c=relaxed/simple; bh=W4Oi2S/NlpMzAx32Ly6onlQ2x5PVz6MkgsFrco/Eqq4=; h=Date:From:To:cc:Subject:In-Reply-To:Message-ID:References: MIME-Version:Content-Type; b=QRpWyvx/8fcF2zRlX49DX2UNo2lan215RP33D8c37eBtt1WcB+nqhT07L9/AL434y36pIYDJ8a2VEmB/45vBKDEYk2n26uKJ1FtI6mE1/ZLPpbVNZnR2Jlu6nnHuXiUzwhYRuVbUufmPsVdPCKeSfE0FSOS9MD0DdV4RMWKJY40= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk; spf=none smtp.mailfrom=orcam.me.uk; arc=none smtp.client-ip=78.133.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=orcam.me.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=orcam.me.uk Received: by angie.orcam.me.uk (Postfix, from userid 500) id 6230792009C; Thu, 6 Aug 2026 12:54:28 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id 5FF5B92009B; Thu, 6 Aug 2026 11:54:28 +0100 (BST) Date: Thu, 6 Aug 2026 11:54:28 +0100 (BST) From: "Maciej W. Rozycki" To: Thomas Bogendoerfer , Greg Kroah-Hartman , Jiri Slaby cc: linux-mips@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 3/3] serial: sb1250-duart: Convert to use a platform device In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Prevent a crash from happening as the first serial port is initialised: pata-swarm: PATA interface at GenBus slot 4 workingset: timestamp_bits=3D62 max_order=3D18 bucket_order=3D0 Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253) CPU 1 Unable to handle kernel paging request at virtual address 000000000= 0000208, epc =3D=3D ffffffff8067f8f8, ra =3D=3D ffffffff80666330 Oops[#1]: CPU: 1 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.19.0-dirty #27 NONE=20 $ 0 : 0000000000000000 0000000014001fe0 0000000000000020 ffffffff806661= 30 $ 4 : 0000000000000000 a800000100e6f118 ffffffff8112cbc0 00000000000000= 00 $ 8 : 0000000000000002 0000000000000000 0000000000000000 0000000001a800= 00 $12 : 0000000000000000 ffffffff809fd488 000000004ddf14dd ffffffff000000= 00 $16 : a800000100e6f000 0000000000000000 ffffffff8112c1d0 a800000100e6f0= 00 $20 : 0000000000000000 00000000000004d0 0000000000000004 ffffffff8112c1= d0 $24 : 0000000000000001 0000000000000003 = =20 $28 : a80000010007c000 a80000010007fcb0 00000000000000ef ffffffff806663= 30 Hi : fffffffffffffdb9 Lo : 0000000000000035 epc : ffffffff8067f8f8 __dev_fwnode+0x0/0x8 ra : ffffffff80666330 serial_base_ctrl_add+0xb8/0x180 Status: 14001fe3 KX SX UX KERNEL EXL IE=20 Cause : 80800008 (ExcCode 02) BadVA : 0000000000000208 PrId : 03040102 (SiByte SB1) Process swapper/0 (pid: 1, threadinfo=3D(____ptrval____), task=3D(____ptr= val____), tls=3D0000000000000000) Stack : 0000000000000000 ffffffff80cd5178 ffffffff80cd0000 ffffffff8112c1= c8 0000000000000260 ffffffff806655c4 a800000100275bc0 ffffffff8064ac= 88 004000408112c000 0000000000000002 0000000000000000 ffffffff801965= d0 a800000100786ba0 ffffffff80cd5178 a800000100786ba0 00000000000000= 04 a800000100275bc0 0000000000000000 0000000000000000 ffffffff80cd51= 78 0000000000000000 ffffffff8112c1c8 0000000000000260 00000000000004= d0 0000000000000004 ffffffff80bf0000 00000000000000ef ffffffff80d171= dc ffffffff80d17120 ffffffff80d25658 0000000000000000 ffffffff80d500= 00 ffffffff80d2f928 ffffffff80d50000 ffffffff80d25698 ffffffff80cfce= cc 00ffffff80b84428 0000000000000000 0000000000000006 00000000000000= 06 ... Call Trace: [] __dev_fwnode+0x0/0x8 [] serial_base_ctrl_add+0xb8/0x180 [] serial_core_register_port+0x174/0x8e0 [] sbd_init+0xbc/0xf4 [] do_one_initcall+0x64/0x150 [] kernel_init_freeable+0x25c/0x30c [] kernel_init+0x24/0x118 [] ret_from_kernel_thread+0x14/0x1c =20 Code: 67bd0010 03e00008 2402ffea <03e00008> dc820208 67bdffa0 ffbe005= 0 ffb70048 ffb60040=20 =20 ---[ end trace 0000000000000000 ]--- -- where a pointer is dereferenced that has been derived from a null pointer to the port's parent device. Since no device is available with legacy probing and it's not anymore a preferable way to discover devices anyway, switch the driver to using a platform device and use it as the port's parent device. Use platform_driver_probe() because SB1250 DUART devices are embedded=20 onchip the SoC and therefore not that straightforward to remove. An unfortunate consequence of the switch to a platform device is we now=20 hand the console over from the bootconsole much later in the bootstrap.=20 The CFE console handler appears good enough though to work so late and=20 in particular with interrupts enabled. Conversely, only starting the console device so late lets the port=20 initialisation code always use fsleep() for transmitter draining, so=20 drop the other variant since it is now dead code. Since there is one way only remaining to reach sbd_init_port() now, drop=20 the port initialisation marker as no longer needed and go through the=20 channel resets unconditionally. Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to en= able runtime PM") Signed-off-by: Maciej W. Rozycki Cc: stable@vger.kernel.org # needs to use .remove_new for <=3D 6.10 --- Changes from v2 (3/6), : - Update port initialisation code according to transmitter drain delay=20 improvements in 1/3. Changes from v1 (3/4), : - Sanitise the change heading. --- arch/mips/sibyte/swarm/platform.c | 97 ++++++++++++++++++++++-- drivers/tty/serial/sb1250-duart.c | 152 +++++++++++++--------------------= ----- 2 files changed, 145 insertions(+), 104 deletions(-) linux-serial-sb1250-duart-platform.diff Index: linux-swarm64/arch/mips/sibyte/swarm/platform.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- linux-swarm64.orig/arch/mips/sibyte/swarm/platform.c +++ linux-swarm64/arch/mips/sibyte/swarm/platform.c @@ -8,7 +8,13 @@ =20 #include #include +#if defined(CONFIG_SIBYTE_BCM1x80) +#include +#include +#else #include +#include +#endif =20 #if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR) =20 @@ -85,6 +91,82 @@ device_initcall(swarm_pata_init); =20 #endif /* defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR)= */ =20 +#if defined(CONFIG_SIBYTE_BCM1x80) +static struct resource sb1250_duart_resources[][2] =3D { + { + { + .name =3D "sb1250-duart0", + .flags =3D IORESOURCE_MEM, + .start =3D A_BCM1480_DUART0, + .end =3D (A_BCM1480_DUART0 + + 4 * BCM1480_DUART_CHANREG_SPACING - 1), + }, + { + .name =3D "sb1250-duart0", + .flags =3D IORESOURCE_IRQ, + .start =3D K_BCM1480_INT_UART_0, + .end =3D K_BCM1480_INT_UART_1, + }, + }, + { + { + .name =3D "sb1250-duart1", + .flags =3D IORESOURCE_MEM, + .start =3D A_BCM1480_DUART1, + .end =3D (A_BCM1480_DUART1 + + 4 * BCM1480_DUART_CHANREG_SPACING - 1), + }, + { + .name =3D "sb1250-duart1", + .flags =3D IORESOURCE_IRQ, + .start =3D K_BCM1480_INT_UART_2, + .end =3D K_BCM1480_INT_UART_3, + }, + }, +}; +#else /* !defined(CONFIG_SIBYTE_BCM1x80) */ +static struct resource sb1250_duart_resources[][2] =3D { + { + { + .name =3D "sb1250-duart0", + .flags =3D IORESOURCE_MEM, + .start =3D A_DUART, + .end =3D A_DUART + 4 * DUART_CHANREG_SPACING - 1, + }, + { + .name =3D "sb1250-duart0", + .flags =3D IORESOURCE_IRQ, + .start =3D K_INT_UART_0, + .end =3D K_INT_UART_1, + }, + }, +}; +#endif /* !defined(CONFIG_SIBYTE_BCM1x80) */ + +static struct platform_device sb1250_duart_device[] =3D { + { + .name =3D "sb1250-duart", + .id =3D 0, + .resource =3D sb1250_duart_resources[0], + .num_resources =3D ARRAY_SIZE(sb1250_duart_resources[0]), + }, +#if defined(CONFIG_SIBYTE_BCM1x80) + { + .name =3D "sb1250-duart", + .id =3D 1, + .resource =3D sb1250_duart_resources[1], + .num_resources =3D ARRAY_SIZE(sb1250_duart_resources[1]), + }, +#endif +}; + +static struct platform_device *sb1250_duart_devices[] __initdata =3D { + &sb1250_duart_device[0], +#if defined(CONFIG_SIBYTE_BCM1x80) + &sb1250_duart_device[1], +#endif +}; + #define sb1250_dev_struct(num) \ static struct resource sb1250_res##num =3D { \ .name =3D "SB1250 MAC " __stringify(num), \ @@ -113,28 +195,31 @@ static struct platform_device *sb1250_de =20 static int __init sb1250_device_init(void) { - int ret; + int ret1, ret2; + + ret1 =3D platform_add_devices(sb1250_duart_devices, + ARRAY_SIZE(sb1250_duart_devices)); =20 /* Set the number of available units based on the SOC type. */ switch (soc_type) { case K_SYS_SOC_TYPE_BCM1250: case K_SYS_SOC_TYPE_BCM1250_ALT: - ret =3D platform_add_devices(sb1250_devs, 3); + ret2 =3D platform_add_devices(sb1250_devs, 3); break; case K_SYS_SOC_TYPE_BCM1120: case K_SYS_SOC_TYPE_BCM1125: case K_SYS_SOC_TYPE_BCM1125H: case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ - ret =3D platform_add_devices(sb1250_devs, 2); + ret2 =3D platform_add_devices(sb1250_devs, 2); break; case K_SYS_SOC_TYPE_BCM1x55: case K_SYS_SOC_TYPE_BCM1x80: - ret =3D platform_add_devices(sb1250_devs, 4); + ret2 =3D platform_add_devices(sb1250_devs, 4); break; default: - ret =3D -ENODEV; + ret2 =3D 0; break; } - return ret; + return ret1 ? ret1 : ret2; } device_initcall(sb1250_device_init); Index: linux-swarm64/drivers/tty/serial/sb1250-duart.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- linux-swarm64.orig/drivers/tty/serial/sb1250-duart.c +++ linux-swarm64/drivers/tty/serial/sb1250-duart.c @@ -3,7 +3,7 @@ * Support for the asynchronous serial interface (DUART) included * in the BCM1250 and derived System-On-a-Chip (SOC) devices. * - * Copyright (c) 2007 Maciej W. Rozycki + * Copyright (c) 2007, 2026 Maciej W. Rozycki * * Derived from drivers/char/sb1250_duart.c for which the following * copyright applies: @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -45,10 +46,6 @@ #include #include =20 -#define SBD_CHANREGS(line) A_BCM1480_DUART_CHANREG((line), 0) -#define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0) -#define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line)) - #define DUART_CHANREG_SPACING BCM1480_DUART_CHANREG_SPACING =20 #define R_DUART_IMRREG(line) R_BCM1480_DUART_IMRREG(line) @@ -59,10 +56,6 @@ #include #include =20 -#define SBD_CHANREGS(line) A_DUART_CHANREG((line), 0) -#define SBD_CTRLREGS(line) A_DUART_CTRLREG(0) -#define SBD_INT(line) (K_INT_UART_0 + (line)) - #else #error invalid SB1250 UART configuration =20 @@ -85,7 +78,6 @@ struct sbd_port { struct uart_port port; unsigned char __iomem *memctrl; int tx_stopped; - int initialised; }; =20 /* @@ -100,6 +92,7 @@ struct sbd_duart { #define to_sport(uport) container_of(uport, struct sbd_port, port) =20 static struct sbd_duart sbd_duarts[DUART_MAX_CHIP]; +static struct uart_driver sbd_reg; =20 =20 /* @@ -514,8 +507,6 @@ static void sbd_init_port(struct sbd_por { struct uart_port *uport =3D &sport->port; =20 - if (sport->initialised) - return; /* * Contrary to documentation, which says that the transmitter * empty bit is set when "there are no characters to send and @@ -537,12 +528,7 @@ static void sbd_init_port(struct sbd_por * a standard CFE firmware compilation. */ sbd_line_drain(sport); - if (IS_ENABLED(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && - system_state < SYSTEM_SCHEDULING) - for (int i =3D 0; i < 2048; i++) - read_sbdshr(sport, R_DUART_IN_PORT); - else - fsleep(100); + fsleep(100); =20 /* There is no DUART reset feature, so just set some sane defaults. */ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX); @@ -559,8 +545,6 @@ static void sbd_init_port(struct sbd_por =20 /* Re-enable transmission for the initial PROM-based console. */ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); - - sport->initialised =3D 1; } =20 static void sbd_set_termios(struct uart_port *uport, struct ktermios *term= ios, @@ -799,50 +783,54 @@ static const struct uart_ops sbd_ops =3D { }; =20 /* Initialize SB1250 DUART port structures. */ -static void __init sbd_probe_duarts(void) +static int __init sbd_probe(struct platform_device *pdev) { - static int probed; + struct resource *mem_resource, *irq_resource; int chip, side; - int max_lines, line; =20 - if (probed) - return; + mem_resource =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq_resource =3D platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mem_resource || !irq_resource) + return -ENODEV; =20 - /* Set the number of available units based on the SOC type. */ - switch (soc_type) { - case K_SYS_SOC_TYPE_BCM1x55: - case K_SYS_SOC_TYPE_BCM1x80: - max_lines =3D 4; - break; - default: - /* Assume at least two serial ports at the normal address. */ - max_lines =3D 2; - break; - } + chip =3D pdev->id; + sbd_duarts[chip].mapctrl =3D mem_resource->start + + DUART_CHANREG_SPACING * 3; + for (side =3D 0; side < DUART_MAX_SIDE; side++) { + struct sbd_port *sport =3D &sbd_duarts[chip].sport[side]; + struct uart_port *uport =3D &sport->port; =20 - probed =3D 1; + sport->duart =3D &sbd_duarts[chip]; =20 - for (chip =3D 0, line =3D 0; chip < DUART_MAX_CHIP && line < max_lines; - chip++) { - sbd_duarts[chip].mapctrl =3D SBD_CTRLREGS(line); + uport->dev =3D &pdev->dev; + uport->irq =3D irq_resource->start + side; + uport->uartclk =3D 100000000 / 20 * 16; + uport->fifosize =3D 16; + uport->iotype =3D UPIO_MEM; + uport->flags =3D UPF_BOOT_AUTOCONF; + uport->ops =3D &sbd_ops; + uport->line =3D chip * DUART_MAX_SIDE + side; + uport->mapbase =3D mem_resource->start + + DUART_CHANREG_SPACING * (side + 1); + uport->has_sysrq =3D IS_ENABLED(CONFIG_SERIAL_SB1250_DUART_CONSOLE); + if (uart_add_one_port(&sbd_reg, uport)) + uport->dev =3D NULL; + } =20 - for (side =3D 0; side < DUART_MAX_SIDE && line < max_lines; - side++, line++) { - struct sbd_port *sport =3D &sbd_duarts[chip].sport[side]; - struct uart_port *uport =3D &sport->port; + return 0; +} =20 - sport->duart =3D &sbd_duarts[chip]; +static void __exit sbd_remove(struct platform_device *pdev) +{ + int chip, side; =20 - uport->irq =3D SBD_INT(line); - uport->uartclk =3D 100000000 / 20 * 16; - uport->fifosize =3D 16; - uport->iotype =3D UPIO_MEM; - uport->flags =3D UPF_BOOT_AUTOCONF; - uport->ops =3D &sbd_ops; - uport->line =3D line; - uport->mapbase =3D SBD_CHANREGS(line); - uport->has_sysrq =3D IS_ENABLED(CONFIG_SERIAL_SB1250_DUART_CONSOLE); - } + chip =3D pdev->id; + for (side =3D DUART_MAX_SIDE - 1; side >=3D 0; side--) { + struct sbd_port *sport =3D &sbd_duarts[chip].sport[side]; + struct uart_port *uport =3D &sport->port; + + if (uport->dev) + uart_remove_one_port(&sbd_reg, uport); } } =20 @@ -900,23 +888,14 @@ static int __init sbd_console_setup(stru int bits =3D 8; int parity =3D 'n'; int flow =3D 'n'; - int ret; =20 if (!sport->duart) return -ENXIO; - - ret =3D sbd_map_port(uport); - if (ret) - return ret; - - sbd_init_port(sport); - if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(uport, co, baud, parity, bits, flow); } =20 -static struct uart_driver sbd_reg; static struct console sbd_console =3D { .name =3D "duart", .write =3D sbd_console_write, @@ -927,16 +906,6 @@ static struct console sbd_console =3D { .data =3D &sbd_reg }; =20 -static int __init sbd_serial_console_init(void) -{ - sbd_probe_duarts(); - register_console(&sbd_console); - - return 0; -} - -console_initcall(sbd_serial_console_init); - #define SERIAL_SB1250_DUART_CONSOLE &sbd_console #else #define SERIAL_SB1250_DUART_CONSOLE NULL @@ -953,43 +922,30 @@ static struct uart_driver sbd_reg =3D { .cons =3D SERIAL_SB1250_DUART_CONSOLE, }; =20 +static struct platform_driver sbd_driver =3D { + .remove =3D __exit_p(sbd_remove), + .driver =3D { .name =3D "sb1250-duart" }, +}; + /* Set up the driver and register it. */ static int __init sbd_init(void) { - int i, ret; - - sbd_probe_duarts(); + int ret; =20 ret =3D uart_register_driver(&sbd_reg); if (ret) return ret; + ret =3D platform_driver_probe(&sbd_driver, sbd_probe); + if (ret) + uart_unregister_driver(&sbd_reg); =20 - for (i =3D 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) { - struct sbd_duart *duart =3D &sbd_duarts[i / DUART_MAX_SIDE]; - struct sbd_port *sport =3D &duart->sport[i % DUART_MAX_SIDE]; - struct uart_port *uport =3D &sport->port; - - if (sport->duart) - uart_add_one_port(&sbd_reg, uport); - } - - return 0; + return ret; } =20 /* Unload the driver. Unregister stuff, get ready to go away. */ static void __exit sbd_exit(void) { - int i; - - for (i =3D DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >=3D 0; i--) { - struct sbd_duart *duart =3D &sbd_duarts[i / DUART_MAX_SIDE]; - struct sbd_port *sport =3D &duart->sport[i % DUART_MAX_SIDE]; - struct uart_port *uport =3D &sport->port; - - if (sport->duart) - uart_remove_one_port(&sbd_reg, uport); - } - + platform_driver_unregister(&sbd_driver); uart_unregister_driver(&sbd_reg); }