[PATCH 00/18] Apple M1 SoC platform bring-up

STALE2012d

Revision v1 of 4 in this series.

111 messages, 9 authors, 2021-02-10 · page 1 of 2 · open the first message on its own page

[PATCH 00/18] Apple M1 SoC platform bring-up

From: Hector Martin <hidden>
Date: 2021-02-04 20:41:37

This series brings up initial support for the Apple M1 SoC, used in the
2020 Mac Mini, MacBook Pro, and MacBook Air models.

The following features are supported in this initial port:

- UART (samsung-style) with earlycon support
- Interrupts, including affinity and IPIs (Apple Interrupt Controller)
- SMP (through standard spin-table support)
- simplefb-based framebuffer
- Devicetree for the Mac Mini (should work for the others too at this
  stage)

The primary pain points of this port are:

- Apple SoCs require FIQs, as the timers and "fast" IPIs are hardwired
  to the FIQ interrupt line. This patchset introduces FIQ support through
  the alternatives mechanism, so as to not affect other platforms,
  implemented as simply merging IRQs and FIQs. The AIC driver takes care
  of discriminating and routing IRQs to the right users.

- These SoCs blackhole nGnRE writes to internal MMIO ranges, and require
  nGnRnE. There is no obvious right solution to solve this. I do not
  expect the two patches for that in this series to be merged as-is, but
  the commit messages describe the problem and potential solutions. I
  hope we can have a discussion and converge on the right approach to
  solve this problem in the sanest way.

These machines officially support booting unsigned/user-provided
XNU-like kernels, with a very different boot protocol and devicetree
format. We are developing an initial bootloader, m1n1 [1], to take care
of as many hardware peculiarities as possible and present a standard
Linux arm64 boot protocol and device tree. In the future, I expect that
production setups will add U-Boot and perhaps GRUB into the boot chain,
to make the boot process similar to other ARM64 platforms.

The machines expose their debug UART over USB Type C, triggered with
vendor-specific USB-PD commands. Currently, the easiest way to get a
serial console on these machines is to use a second M1 box and a simple
USB C cable [2]. You can also build a DIY interface using an Arduino, a
FUSB302 chip or board, and a 1.2V UART-TTL adapter [3]. In the coming
weeks we will be designing an open hardware project to provide
serial/debug connectivity to these machines (and, hopefully, also
support other UART-over-Type C setups from other vendors). Please
contact me privately if you are interested in getting an early prototype
version of one of these devices.

A quickstart guide to booting Linux kernels on these machines is
available at [4], and we are documenting the hardware at [5].

[1] https://github.com/AsahiLinux/m1n1/
[2] https://github.com/AsahiLinux/macvdmtool/
[3] https://github.com/AsahiLinux/vdmtool/
[4] https://github.com/AsahiLinux/docs/wiki/Developer-Quickstart
[5] https://github.com/AsahiLinux/docs/wiki

== Project Blurb ==

Asahi Linux is an open community project dedicated to developing and
maintaining mainline support for Apple Silicon on Linux. Feel free to
drop by #asahi on freenode to chat with us, or check our website for
more information on the project:

https://asahilinux.org/


Hector Martin (18):
  dt-bindings: vendor-prefixes: add AAPL prefix
  dt-bindings: arm: cpus: Add AAPL,firestorm & icestorm compatibles
  dt-bindings: arm: AAPL: Add bindings for Apple ARM platforms
  arm64: Kconfig: Introduce CONFIG_ARCH_APPLE
  tty: serial: samsung_tty: add support for Apple UARTs
  dt-bindings: serial: samsung: Add AAPL,s5l-uart compatible
  tty: serial: samsung_tty: enable for ARCH_APPLE
  arm64: cpufeature: Add a feature for FIQ support
  arm64: cputype: Add CPU types for the Apple M1 big/little cores
  arm64: Introduce FIQ support
  arm64: Kconfig: Require FIQ support for ARCH_APPLE
  arm64: setup: Use nGnRnE IO mappings for fixmap on Apple platforms
  arm64: ioremap: use nGnRnE mappings on platforms that require it
  dt-bindings: interrupt-controller: Add DT bindings for apple-aic
  irqchip/apple-aic: Add support for the Apple Interrupt Controller
  irqchip/apple-aic: Add SMP / IPI support
  dt-bindings: display: add AAPL,simple-framebuffer
  arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

 .../devicetree/bindings/arm/AAPL.yaml         |  36 ++
 .../devicetree/bindings/arm/cpus.yaml         |   2 +
 .../bindings/display/simple-framebuffer.yaml  |   5 +
 .../interrupt-controller/AAPL,aic.yaml        |  88 +++
 .../bindings/serial/samsung_uart.yaml         |   4 +-
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  14 +
 arch/arm64/Kconfig                            |  10 +
 arch/arm64/Kconfig.platforms                  |   8 +
 arch/arm64/boot/dts/Makefile                  |   1 +
 arch/arm64/boot/dts/apple/Makefile            |   2 +
 arch/arm64/boot/dts/apple/apple-j274.dts      | 143 +++++
 arch/arm64/include/asm/assembler.h            |   4 +
 arch/arm64/include/asm/cpucaps.h              |   3 +-
 arch/arm64/include/asm/cpufeature.h           |   6 +
 arch/arm64/include/asm/cputype.h              |   6 +
 arch/arm64/include/asm/daifflags.h            |   7 +
 arch/arm64/include/asm/fixmap.h               |  10 +-
 arch/arm64/include/asm/io.h                   |   9 +-
 arch/arm64/include/asm/irqflags.h             |  17 +-
 arch/arm64/kernel/cpufeature.c                |  32 ++
 arch/arm64/kernel/entry.S                     |  27 +-
 arch/arm64/kernel/setup.c                     |  12 +
 drivers/irqchip/Kconfig                       |  10 +
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-apple-aic.c               | 501 ++++++++++++++++++
 drivers/tty/serial/Kconfig                    |   2 +-
 drivers/tty/serial/samsung_tty.c              | 297 +++++++++--
 .../interrupt-controller/apple-aic.h          |  14 +
 include/linux/serial_s3c.h                    |  16 +
 include/uapi/linux/serial_core.h              |   3 +
 31 files changed, 1243 insertions(+), 49 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/AAPL.yaml
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
 create mode 100644 arch/arm64/boot/dts/apple/Makefile
 create mode 100644 arch/arm64/boot/dts/apple/apple-j274.dts
 create mode 100644 drivers/irqchip/irq-apple-aic.c
 create mode 100644 include/dt-bindings/interrupt-controller/apple-aic.h

--
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 01/18] dt-bindings: vendor-prefixes: add AAPL prefix

From: Hector Martin <hidden>
Date: 2021-02-04 20:41:58

Amusingly, this wasn't yet documented, even though this vendor prefix
has been used since time immemorial on PPC.

Signed-off-by: Hector Martin <redacted>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 041ae90b0d8f..d7950c723472 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -25,6 +25,8 @@ patternProperties:
   # Keep list in alphabetical order.
   "^70mai,.*":
     description: 70mai Co., Ltd.
+  "^AAPL,.*":
+    description: Apple Inc.
   "^abb,.*":
     description: ABB
   "^abilis,.*":
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 04/18] arm64: Kconfig: Introduce CONFIG_ARCH_APPLE

From: Hector Martin <hidden>
Date: 2021-02-04 20:42:30

This adds a Kconfig option to toggle support for Apple ARM SoCs.
At this time this targets the M1 and later "Apple Silicon" Mac SoCs.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig.platforms | 7 +++++++
 1 file changed, 7 insertions(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 6eecdef538bd..e3e3bd2c4374 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -29,6 +29,13 @@ config ARCH_ALPINE
 	  This enables support for the Annapurna Labs Alpine
 	  Soc family.
 
+config ARCH_APPLE
+	bool "Apple Silicon SoC family"
+	select GENERIC_IRQ_CHIP
+	help
+	  This enables support for Apple's in-house ARM SoC family, starting
+	  with the Apple M1.
+
 config ARCH_BCM2835
 	bool "Broadcom BCM2835 family"
 	select TIMER_OF
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Hector Martin <hidden>
Date: 2021-02-04 20:42:30

Apple SoCs are a distant descendant of Samsung designs and use yet
another variant of their UART style, with different interrupt handling.

In particular, this variant has the following differences with existing
ones:

* It includes a built-in interrupt controller with different registers,
  using only a single platform IRQ

* Internal interrupt sources are treated as edge-triggered, even though
  the IRQ output is level-triggered. This chiefly affects the TX IRQ
  path: the driver can no longer rely on the TX buffer empty IRQ
  immediately firing after TX is enabled, but instead must prime the
  FIFO with data directly.

Signed-off-by: Hector Martin <redacted>
---
 drivers/tty/serial/samsung_tty.c | 297 +++++++++++++++++++++++++++----
 include/linux/serial_s3c.h       |  16 ++
 include/uapi/linux/serial_core.h |   3 +
 3 files changed, 280 insertions(+), 36 deletions(-)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 8ae3e03fbd8c..6d812ba1b748 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -56,6 +56,9 @@
 /* flag to ignore all characters coming in */
 #define RXSTAT_DUMMY_READ (0x10000000)
 
+/* IRQ number used when the handler is called in non-IRQ context */
+#define NO_IRQ -1
+
 struct s3c24xx_uart_info {
 	char			*name;
 	unsigned int		type;
@@ -144,6 +147,14 @@ struct s3c24xx_uart_port {
 #endif
 };
 
+enum s3c24xx_irq_type {
+	IRQ_DISCRETE = 0,
+	IRQ_S3C6400 = 1,
+	IRQ_APPLE = 2,
+};
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
 /* conversion functions */
 
 #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev)
@@ -231,11 +242,20 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
 /*
  * s3c64xx and later SoC's include the interrupt mask and status registers in
  * the controller itself, unlike the s3c24xx SoC's which have these registers
- * in the interrupt controller. Check if the port type is s3c64xx or higher.
+ * in the interrupt controller. Apple SoCs use a different flavor of mask
+ * and status registers. This function returns the IRQ style to use.
  */
-static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+static int s3c24xx_irq_type(struct uart_port *port)
 {
-	return to_ourport(port)->info->type == PORT_S3C6400;
+	switch (to_ourport(port)->info->type) {
+	case PORT_S3C6400:
+		return IRQ_S3C6400;
+	case PORT_APPLE:
+		return IRQ_APPLE;
+	default:
+		return IRQ_DISCRETE;
+	}
+
 }
 
 static void s3c24xx_serial_rx_enable(struct uart_port *port)
@@ -289,10 +309,17 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	if (!ourport->tx_enabled)
 		return;
 
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		s3c24xx_clear_bit(port, APPLE_UCON_TXTHRESH_ENA, S3C2410_UCON);
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
 		dmaengine_pause(dma->tx_chan);
@@ -315,8 +342,6 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	ourport->tx_mode = 0;
 }
 
-static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
-
 static void s3c24xx_serial_tx_dma_complete(void *args)
 {
 	struct s3c24xx_uart_port *ourport = args;
@@ -353,10 +378,17 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	u32 ucon;
 
 	/* Mask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		WARN_ON(1); // No DMA
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	/* Enable tx dma mode */
 	ucon = rd_regl(port, S3C2410_UCON);
@@ -369,6 +401,8 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	ourport->tx_mode = S3C24XX_TX_DMA;
 }
 
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id);
+
 static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 {
 	struct uart_port *port = &ourport->port;
@@ -383,16 +417,30 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 	ucon = rd_regl(port, S3C2410_UCON);
 	ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
 	ucon |= S3C64XX_UCON_TXMODE_CPU;
-	wr_regl(port,  S3C2410_UCON, ucon);
 
 	/* Unmask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
-		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
-				  S3C64XX_UINTM);
-	else
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
+		break;
+	case IRQ_S3C6400:
+		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
+		break;
+	default:
 		enable_irq(ourport->tx_irq);
+		break;
+	}
+
+	wr_regl(port,  S3C2410_UCON, ucon);
 
 	ourport->tx_mode = S3C24XX_TX_PIO;
+
+	/*
+	 * The Apple version only has edge triggered TX IRQs, so we need
+	 * to kick off the process by sending some characters here.
+	 */
+	if (s3c24xx_irq_type(port) == IRQ_APPLE)
+		s3c24xx_serial_tx_chars(NO_IRQ, ourport);
 }
 
 static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
@@ -513,11 +561,18 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
 
 	if (ourport->rx_enabled) {
 		dev_dbg(port->dev, "stopping rx\n");
-		if (s3c24xx_serial_has_interrupt_mask(port))
-			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
-					S3C64XX_UINTM);
-		else
-			disable_irq_nosync(ourport->rx_irq);
+		switch (s3c24xx_irq_type(port)) {
+		case IRQ_APPLE:
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+			break;
+		case IRQ_S3C6400:
+			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
+			break;
+		default:
+			disable_irq_nosync(ourport->tx_irq);
+			break;
+		}
 		ourport->rx_enabled = 0;
 	}
 	if (dma && dma->rx_chan) {
@@ -651,14 +706,18 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
 
 	/* set Rx mode to DMA mode */
 	ucon = rd_regl(port, S3C2410_UCON);
-	ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
-			S3C64XX_UCON_EMPTYINT_EN |
-			S3C64XX_UCON_DMASUS_EN |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_MASK);
-	ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_CPU;
+	ucon &= ~S3C64XX_UCON_RXMODE_MASK;
+	ucon |= S3C64XX_UCON_RXMODE_CPU;
+
+	/* Apple types use these bits for IRQ masks */
+	if (s3c24xx_irq_type(port) != IRQ_APPLE) {
+		ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+				S3C64XX_UCON_EMPTYINT_EN |
+				S3C64XX_UCON_DMASUS_EN |
+				S3C64XX_UCON_TIMEOUT_EN);
+		ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+				S3C64XX_UCON_TIMEOUT_EN;
+	}
 	wr_regl(port, S3C2410_UCON, ucon);
 
 	ourport->rx_mode = S3C24XX_RX_PIO;
@@ -831,7 +890,9 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 	unsigned long flags;
 	int count, dma_count = 0;
 
-	spin_lock_irqsave(&port->lock, flags);
+	/* Only lock if called from IRQ context */
+	if (irq != NO_IRQ)
+		spin_lock_irqsave(&port->lock, flags);
 
 	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
@@ -893,7 +954,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 		s3c24xx_serial_stop_tx(port);
 
 out:
-	spin_unlock_irqrestore(&port->lock, flags);
+	if (irq != NO_IRQ)
+		spin_unlock_irqrestore(&port->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -916,6 +978,26 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
 	return ret;
 }
 
+/* interrupt handler for Apple SoC's.*/
+static irqreturn_t apple_serial_handle_irq(int irq, void *id)
+{
+	struct s3c24xx_uart_port *ourport = id;
+	struct uart_port *port = &ourport->port;
+	unsigned int pend = rd_regl(port, S3C2410_UTRSTAT);
+	irqreturn_t ret = IRQ_HANDLED;
+
+	if (pend & (APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO)) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO);
+		ret = s3c24xx_serial_rx_chars(irq, id);
+	}
+	if (pend & APPLE_UTRSTAT_TXTHRESH) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_TXTHRESH);
+		ret = s3c24xx_serial_tx_chars(irq, id);
+	}
+
+	return ret;
+}
+
 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
 	struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@ -1098,7 +1180,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
 	if (ourport->tx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->tx_irq, ourport);
 		ourport->tx_enabled = 0;
 		ourport->tx_claimed = 0;
@@ -1106,18 +1188,34 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	}
 
 	if (ourport->rx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->rx_irq, ourport);
 		ourport->rx_claimed = 0;
 		ourport->rx_enabled = 0;
 	}
 
 	/* Clear pending interrupts and mask all interrupts */
-	if (s3c24xx_serial_has_interrupt_mask(port)) {
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE: {
+		unsigned int ucon;
+
+		ucon = rd_regl(port, S3C2410_UCON);
+		ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTO_ENA_MSK);
+		wr_regl(port, S3C2410_UCON, ucon);
+
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+		free_irq(port->irq, ourport);
+		break;
+	}
+	case IRQ_S3C6400:
 		free_irq(port->irq, ourport);
 
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTM, 0xf);
+		break;
 	}
 
 	if (ourport->dma)
@@ -1215,6 +1313,47 @@ static int s3c64xx_serial_startup(struct uart_port *port)
 	return ret;
 }
 
+static int apple_serial_startup(struct uart_port *port)
+{
+	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	unsigned long flags;
+	unsigned int ufcon;
+	int ret;
+
+	wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
+	if (ret) {
+		dev_err(port->dev, "cannot get irq %d\n", port->irq);
+		return ret;
+	}
+
+	/* For compatibility with s3c24xx Soc's */
+	ourport->rx_enabled = 1;
+	ourport->rx_claimed = 1;
+	ourport->tx_enabled = 0;
+	ourport->tx_claimed = 1;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ufcon = rd_regl(port, S3C2410_UFCON);
+	ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+	if (!uart_console(port))
+		ufcon |= S3C2410_UFCON_RESETTX;
+	wr_regl(port, S3C2410_UFCON, ufcon);
+
+	enable_rx_pio(ourport);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Enable Rx Interrupt */
+	s3c24xx_set_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+	s3c24xx_set_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+
+	return ret;
+}
+
 /* power power management control */
 
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1544,6 +1683,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
 		return "S3C2412";
 	case PORT_S3C6400:
 		return "S3C6400/10";
+	case PORT_APPLE:
+		return "APPLE";
 	default:
 		return NULL;
 	}
@@ -1868,9 +2009,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 	/* setup info for port */
 	port->dev	= &platdev->dev;
 
+	switch (s3c24xx_irq_type(port)) {
+	/* Startup sequence is different for Apple SoC's */
+	case IRQ_APPLE:
+		s3c24xx_serial_ops.startup = apple_serial_startup;
+		break;
 	/* Startup sequence is different for s3c64xx and higher SoC's */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	case IRQ_S3C6400:
 		s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
+		break;
+	}
 
 	port->uartclk = 1;
 
@@ -1905,7 +2053,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 		ourport->tx_irq = ret + 1;
 	}
 
-	if (!s3c24xx_serial_has_interrupt_mask(port)) {
+	if (s3c24xx_irq_type(port) == IRQ_DISCRETE) {
 		ret = platform_get_irq(platdev, 1);
 		if (ret > 0)
 			ourport->tx_irq = ret;
@@ -1945,10 +2093,24 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 		pr_warn("uart: failed to enable baudclk\n");
 
 	/* Keep all interrupts masked and cleared */
-	if (s3c24xx_serial_has_interrupt_mask(port)) {
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE: {
+		unsigned int ucon;
+
+		ucon = rd_regl(port, S3C2410_UCON);
+		ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTO_ENA_MSK);
+		wr_regl(port, S3C2410_UCON, ucon);
+
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+		break;
+	}
+	case IRQ_S3C6400:
 		wr_regl(port, S3C64XX_UINTM, 0xf);
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTSP, 0xf);
+		break;
 	}
 
 	dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
@@ -2142,7 +2304,33 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
 
 	if (port) {
 		/* restore IRQ mask */
-		if (s3c24xx_serial_has_interrupt_mask(port)) {
+		switch (s3c24xx_irq_type(port)) {
+		case IRQ_APPLE:
+			unsigned int ucon;
+
+			clk_prepare_enable(ourport->clk);
+			if (!IS_ERR(ourport->baudclk))
+				clk_prepare_enable(ourport->baudclk);
+
+			ucon = rd_regl(port, S3C2410_UCON);
+
+			ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+				APPLE_UCON_RXTHRESH_ENA_MSK |
+				APPLE_UCON_RXTO_ENA_MSK);
+
+			if (ourport->tx_enabled)
+				ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
+			if (ourport->rx_enabled)
+				ucon |= APPLE_UCON_RXTHRESH_ENA_MSK |
+					APPLE_UCON_RXTO_ENA_MSK;
+
+			wr_regl(port, S3C2410_UCON, ucon);
+
+			if (!IS_ERR(ourport->baudclk))
+				clk_disable_unprepare(ourport->baudclk);
+			clk_disable_unprepare(ourport->clk);
+			break;
+		case IRQ_S3C6400:
 			unsigned int uintm = 0xf;
 
 			if (ourport->tx_enabled)
@@ -2156,6 +2344,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
 			if (!IS_ERR(ourport->baudclk))
 				clk_disable_unprepare(ourport->baudclk);
 			clk_disable_unprepare(ourport->clk);
+			break;
 		}
 	}
 
@@ -2556,6 +2745,34 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
 #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
 #endif
 
+#if defined(CONFIG_ARCH_APPLE)
+static struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
+	.info = &(struct s3c24xx_uart_info) {
+		.name		= "Apple S5L UART",
+		.type		= PORT_APPLE,
+		.fifosize	= 16,
+		.rx_fifomask	= S3C2410_UFSTAT_RXMASK,
+		.rx_fifoshift	= S3C2410_UFSTAT_RXSHIFT,
+		.rx_fifofull	= S3C2410_UFSTAT_RXFULL,
+		.tx_fifofull	= S3C2410_UFSTAT_TXFULL,
+		.tx_fifomask	= S3C2410_UFSTAT_TXMASK,
+		.tx_fifoshift	= S3C2410_UFSTAT_TXSHIFT,
+		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
+		.num_clks	= 1,
+		.clksel_mask	= 0,
+		.clksel_shift	= 0,
+	},
+	.def_cfg = &(struct s3c2410_uartcfg) {
+		.ucon		= APPLE_UCON_DEFAULT,
+		.ufcon		= S3C2410_UFCON_DEFAULT,
+	},
+};
+#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data)
+#else
+#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+
 static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
 	{
 		.name		= "s3c2410-uart",
@@ -2578,6 +2795,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
 	}, {
 		.name		= "exynos5433-uart",
 		.driver_data	= EXYNOS5433_SERIAL_DRV_DATA,
+	}, {
+		.name		= "s5l-uart",
+		.driver_data	= S5L_SERIAL_DRV_DATA,
 	},
 	{ },
 };
@@ -2599,6 +2819,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
 		.data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
 	{ .compatible = "samsung,exynos5433-uart",
 		.data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
+	{ .compatible = "AAPL,s5l-uart",
+		.data = (void *)S5L_SERIAL_DRV_DATA },
 	{},
 };
 MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
@@ -2694,6 +2916,9 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
 
 OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
 			s3c2410_early_console_setup);
+/* Apple SoCs are close enough to s3c2410 for earlycon */
+OF_EARLYCON_DECLARE(s5l, "AAPL,s5l-uart",
+			s3c2410_early_console_setup);
 
 /* S3C2412, S3C2440, S3C64xx */
 static struct samsung_early_console_data s3c2440_early_console_data = {
diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
index ca2c5393dc6b..377c8c6e5b97 100644
--- a/include/linux/serial_s3c.h
+++ b/include/linux/serial_s3c.h
@@ -246,6 +246,22 @@
 				 S5PV210_UFCON_TXTRIG4 |	\
 				 S5PV210_UFCON_RXTRIG4)
 
+
+#define APPLE_UCON_RXTO_ENA	9
+#define APPLE_UCON_RXTHRESH_ENA	12
+#define APPLE_UCON_TXTHRESH_ENA	13
+#define APPLE_UCON_RXTO_ENA_MSK		(1 << APPLE_UCON_RXTO_ENA)
+#define APPLE_UCON_RXTHRESH_ENA_MSK	(1 << APPLE_UCON_RXTHRESH_ENA)
+#define APPLE_UCON_TXTHRESH_ENA_MSK	(1 << APPLE_UCON_TXTHRESH_ENA)
+
+#define APPLE_UCON_DEFAULT	  S3C2410_UCON_RXFIFO_TOI
+
+#define APPLE_UTRSTAT_RXTHRESH	(1<<4)
+#define APPLE_UTRSTAT_TXTHRESH	(1<<5)
+#define APPLE_UTRSTAT_RXTO	(1<<9)
+#define APPLE_UTRSTAT_ALL_FLAGS	(0x3f0)
+
+
 #ifndef __ASSEMBLY__
 
 #include <linux/serial_core.h>
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 62c22045fe65..59d102b674db 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -277,4 +277,7 @@
 /* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART	122
 
+/* Apple Silicon (M1/T8103) UART (Samsung variant) */
+#define PORT_APPLE	123
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 06/18] dt-bindings: serial: samsung: Add AAPL,s5l-uart compatible

From: Hector Martin <hidden>
Date: 2021-02-04 20:42:48

Apple mobile devices originally used Samsung SoCs (starting with the
S5L8900), and their current in-house SoCs continue to use compatible
UART peripherals. We'll call this UART variant AAPL,s5l-uart.

Signed-off-by: Hector Martin <redacted>
---
 Documentation/devicetree/bindings/serial/samsung_uart.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml
index 21ee627b2ced..40409b31f4dc 100644
--- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml
+++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/serial/samsung_uart.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Samsung S3C, S5P and Exynos SoC UART Controller
+title: Samsung S3C, S5P, Exynos, and S5L (Apple SoC) SoC UART Controller
 
 maintainers:
   - Krzysztof Kozlowski <krzk@kernel.org>
@@ -19,6 +19,7 @@ properties:
   compatible:
     items:
       - enum:
+          - AAPL,s5l-uart
           - samsung,s3c2410-uart
           - samsung,s3c2412-uart
           - samsung,s3c2440-uart
@@ -96,6 +97,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - AAPL,s5l-uart
               - samsung,exynos4210-uart
     then:
       properties:
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 07/18] tty: serial: samsung_tty: enable for ARCH_APPLE

From: Hector Martin <hidden>
Date: 2021-02-04 20:43:08

Apple M1 SoCs are distant descendants of Samsung SoCs and use similar
UART blocks.

Signed-off-by: Hector Martin <redacted>
---
 drivers/tty/serial/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 34a2899e69c0..e239977e37f7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -236,7 +236,7 @@ config SERIAL_CLPS711X_CONSOLE
 
 config SERIAL_SAMSUNG
 	tristate "Samsung SoC serial support"
-	depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+	depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST || ARCH_APPLE
 	select SERIAL_CORE
 	help
 	  Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 09/18] arm64: cputype: Add CPU types for the Apple M1 big/little cores

From: Hector Martin <hidden>
Date: 2021-02-04 20:43:31

These are not used at the moment, but let's add them for documentation
purposes.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/include/asm/cputype.h | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 2084a0340d16..6231e1f0abe7 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -100,6 +100,9 @@
 
 #define HISI_CPU_PART_TSV110		0xD01
 
+#define APPLE_CPU_PART_M1_ICESTORM	0x022
+#define APPLE_CPU_PART_M1_FIRESTORM	0x023
+
 #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
 #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
 #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
@@ -128,6 +131,8 @@
 #define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
 #define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
 #define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
+#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
+#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
 
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
 #define MIDR_FUJITSU_ERRATUM_010001		MIDR_FUJITSU_A64FX
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 08/18] arm64: cpufeature: Add a feature for FIQ support

From: Hector Martin <hidden>
Date: 2021-02-04 20:43:47

Apple ARM SoCs (A11 and newer) have some interrupt sources hard-wired to
the FIQ line. Introduce a cpufeature that can be used to enable FIQ
unmasking and handling via alternatives.

This is currently enabled for all Apple CPUs. If/when support is
implemented for older (pre-A11) iPhone/iPad SoCs which do not need FIQs,
or if newer SoCs are released without the FIQ requirement, we can
revisit the condition.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig                  | 10 +++++++++
 arch/arm64/include/asm/cpucaps.h    |  3 ++-
 arch/arm64/include/asm/cpufeature.h |  6 ++++++
 arch/arm64/include/asm/cputype.h    |  1 +
 arch/arm64/kernel/cpufeature.c      | 32 +++++++++++++++++++++++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f39568b28ec1..11cfdc07404f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1756,6 +1756,16 @@ config ARM64_DEBUG_PRIORITY_MASKING
 	  If unsure, say N
 endif
 
+config ARM64_FIQ_SUPPORT
+	bool "Support for FIQ interrupts"
+	help
+	  Adds support for handling FIQ interrupts as normal IRQs.
+	  This is required on Apple platforms where some IRQ sources are
+	  hardwired to the FIQ interrupt line.
+
+	  FIQs are only enabled at runtime on platforms that require them
+	  via the CPU feature framework.
+
 config RELOCATABLE
 	bool "Build a relocatable kernel image" if EXPERT
 	select ARCH_HAS_RELR
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index b77d997b173b..c36d926ad801 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -66,7 +66,8 @@
 #define ARM64_WORKAROUND_1508412		58
 #define ARM64_HAS_LDAPR				59
 #define ARM64_KVM_PROTECTED_MODE		60
+#define ARM64_NEEDS_FIQ				61
 
-#define ARM64_NCAPS				61
+#define ARM64_NCAPS				62
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 9a555809b89c..3a00cfb347c9 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -716,6 +716,12 @@ static __always_inline bool system_uses_irq_prio_masking(void)
 	       cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
 }
 
+static __always_inline bool system_uses_fiqs(void)
+{
+	return IS_ENABLED(CONFIG_ARM64_FIQ_SUPPORT) &&
+	       cpus_have_const_cap(ARM64_NEEDS_FIQ);
+}
+
 static inline bool system_supports_mte(void)
 {
 	return IS_ENABLED(CONFIG_ARM64_MTE) &&
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ef5b040dee44..2084a0340d16 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -59,6 +59,7 @@
 #define ARM_CPU_IMP_NVIDIA		0x4E
 #define ARM_CPU_IMP_FUJITSU		0x46
 #define ARM_CPU_IMP_HISI		0x48
+#define ARM_CPU_IMP_APPLE		0x61
 
 #define ARM_CPU_PART_AEM_V8		0xD0F
 #define ARM_CPU_PART_FOUNDATION		0xD00
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e99eddec0a46..0863cf7cf807 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1237,6 +1237,29 @@ static bool has_cache_idc(const struct arm64_cpu_capabilities *entry,
 	return ctr & BIT(CTR_IDC_SHIFT);
 }
 
+static void cpu_sync_irq_to_fiq(struct arm64_cpu_capabilities const *cap)
+{
+	u64 daif = read_sysreg(daif);
+
+	/*
+	 * By this point in the boot process IRQs are likely masked and FIOs
+	 * aren't, so we need to sync things to avoid spurious early FIQs.
+	 */
+
+	if (daif & PSR_I_BIT)
+		daif |= PSR_F_BIT;
+	else
+		daif &= ~PSR_F_BIT;
+
+	write_sysreg(daif, daif);
+}
+
+static bool needs_fiq(const struct arm64_cpu_capabilities *entry, int __unused)
+{
+	/* All supported Apple cores need this */
+	return read_cpuid_implementor() == ARM_CPU_IMP_APPLE;
+}
+
 static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unused)
 {
 	/*
@@ -2154,6 +2177,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		.min_field_value = 1,
 	},
+#ifdef CONFIG_ARM64_FIQ_SUPPORT
+	{
+		.desc = "FIQs",
+		.capability = ARM64_NEEDS_FIQ,
+		.type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
+		.matches = needs_fiq,
+		.cpu_enable = cpu_sync_irq_to_fiq,
+	},
+#endif
 	{},
 };
 
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 13/18] arm64: ioremap: use nGnRnE mappings on platforms that require it

From: Hector Martin <hidden>
Date: 2021-02-04 20:44:23

This follows from the fixmap patch, but relates to the general case.
This is a hack, and incomplete. Read on for discussion.

The problem: on Apple ARM platforms, SoC MMIO needs to use nGnRnE
mappings: writes using nGnRE are blackholed. This seems to be by design,
and there doesn't seem to be any fabric configuration or other bit we
can flip to make the problem go away.

As an additional confounding factor, reportedly PCIe MMIO BAR mappings
conversely *do* need to use nGnRE to work properly. So we can't even get
away with a single ioremap setting, but need to discriminate based on
what bus the device is in. Since these devices have Thunderbolt, all PCI
devices in the tree are potentially in scope. Ugh.

Ideas:

(1) Set up some devicetree property to default to nGnRnE at the platform
    level, and then make PCI drivers use nGnRE.

    This will require changing the PCI code to make pci_ioremap_bar do
    something other than a plain ioremap().

    Unfortunately, of the ~630 PCI drivers in the tree, only ~90 use
    pci_ioremap_bar(). This would require a tree-wide cleanup to
    introduce something akin to pci_ioremap(), and make all PCI
    drivers use it instead of naked ioremap().

    Currently there are three ioremap variants:

    ioremap()
    ioremap_wc()
    ioremap_uc() (not normally used on arm64)

    None of these really capture the nGnRE vs nGnRnE distinction. If
    a new variant is introduced in common code, we'd have to provide
    a default implementation that falls back to regular ioremap() on
    other arches. Something like ioremap() vs. ioremap_np() (nonposted)?

(2) The converse of (1): keep the nGnRE default, but introduce special
    casing to the OF binding code to use nGnRnE when instructed to do so
    on these platforms. This means of_iomap() needs changing.

    The advantage of this approach is that the set of possible non-PCI
    drivers that are useful on these SoCs is bounded, so not all drivers
    that don't go through that path need to be fixed.

    Additionally, this could take advantage of the OF address
    translation stuff to be smarter about deciding to use nGnRnE, e.g.
    doing it based on a property of the parent bus node.

    Of note, some devices (like samsung_tty) go through the platform
    device framework, which eventually goes into devm code. So
    of_address_to_resource would need to set some flag on the struct
    resource, that can then be used by both of_iomap() and
    devm_ioremap_resource() and friends to eventually call the right
    ioremap variant.

    The ioremap considerations from (1) apply here too.

(3) Do it at a lower level, in ioremap() itself. This requires that
    ioremap() somehow discriminates based on address range to pick what
    kind of mapping to make.

    Declaring these address ranges would be an issue. Options:

    a) An out of band list in a DT node, a la /reserved-memory

    b) Something based on the existing DT hierarchy, where we can scan
       bus ranges and locate buses with a property that says "nGnRnE" or
       "nGnRE" and dynamically build the list based on that.

    The advantage of this option is that it doesn't touch non-arch code.
    The disadvantage is that it adds a complete new bespoke mechanism to
    the DT, and that it does not let device drivers actually select the
    IO mode, which might be desirable in the future anyway for some
    devices.

All discussion and additional ideas welcome.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/include/asm/io.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 5ea8656a2030..f2609a4f5019 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -167,7 +167,14 @@ extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot
 extern void iounmap(volatile void __iomem *addr);
 extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
 
-#define ioremap(addr, size)		__ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
+/*
+ * Some platforms require nGnRnE for MMIO.
+ */
+extern bool arm64_use_ne_io;
+
+#define ioremap(addr, size)		__ioremap((addr), (size), \
+						  arm64_use_ne_io ? __pgprot(PROT_DEVICE_nGnRnE) \
+								  : __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_wc(addr, size)		__ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
 
 /*
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 14/18] dt-bindings: interrupt-controller: Add DT bindings for apple-aic

From: Hector Martin <hidden>
Date: 2021-02-04 20:44:49

AIC is the Apple Interrupt Controller found on Apple ARM SoCs, such as
the M1.

Signed-off-by: Hector Martin <redacted>
---
 .../interrupt-controller/AAPL,aic.yaml        | 88 +++++++++++++++++++
 MAINTAINERS                                   |  2 +
 .../interrupt-controller/apple-aic.h          | 14 +++
 3 files changed, 104 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
 create mode 100644 include/dt-bindings/interrupt-controller/apple-aic.h
diff --git a/Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml b/Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
new file mode 100644
index 000000000000..7e119614275a
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/AAPL,aic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple Interrupt Controller
+
+maintainers:
+  - Hector Martin <marcan@marcan.st>
+
+description: |
+  The Apple Interrupt Controller is a simple interrupt controller present on
+  Apple ARM SoC platforms, including various iPhone and iPad devices and the
+  "Apple Silicon" M1 Macs.
+
+  It provides the following features:
+
+  - Level-triggered hardware IRQs wired to SoC blocks
+    - Single mask bit per IRQ
+    - Per-IRQ affinity setting
+    - Automatic masking on event delivery (auto-ack)
+    - Software triggering (ORed with hw line)
+  - 2 per-CPU IPIs (meant as "self" and "other", but they are interchangeable
+    if not symmetric)
+  - Automatic prioritization (single event/ack register per CPU, lower IRQs =
+    higher priority)
+  - Automatic masking on ack
+  - Default "this CPU" register view and explicit per-CPU views
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  compatible:
+    contains:
+      enum:
+        - AAPL,aic
+        - AAPL,m1-aic
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+    description: |
+      The 1st cell contains the interrupt type:
+        - 0: Hardware IRQ
+        - 1: FIQ
+        - 2: IPI
+
+      The 2nd cell contains the interrupt number.
+        - HW IRQs: interrupt number
+        - FIQs:
+          - 0: physical timer
+          - 1: virtual timer
+        - IPIs:
+          - 0: normal/"other" IPI (used interanlly for virtual IPIs)
+          - 1: self IPI (normally unused)
+
+      The 3rd cell contains the interrupt flags. This is normally
+      IRQ_TYPE_LEVEL_HIGH (4).
+
+  reg:
+    description: |
+      Specifies base physical address and size of the AIC registers.
+    maxItems: 1
+
+required:
+  - compatible
+  - '#interrupt-cells'
+  - interrupt-controller
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        aic: interrupt-controller@23b100000 {
+            compatible = "AAPL,m1-aic", "AAPL,aic";
+            #interrupt-cells = <3>;
+            interrupt-controller;
+            reg = <0x2 0x3b100000 0x0 0x8000>;
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 91a7b33834ac..f3d4661731c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1634,6 +1634,8 @@ B:	https://github.com/AsahiLinux/linux/issues
 C:	irc://chat.freenode.net/asahi-dev
 T:	git https://github.com/AsahiLinux/linux.git
 F:	Documentation/devicetree/bindings/arm/AAPL.yaml
+F:	Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
+F:	include/dt-bindings/interrupt-controller/apple-aic.h
 
 ARM/ARTPEC MACHINE SUPPORT
 M:	Jesper Nilsson <jesper.nilsson@axis.com>
diff --git a/include/dt-bindings/interrupt-controller/apple-aic.h b/include/dt-bindings/interrupt-controller/apple-aic.h
new file mode 100644
index 000000000000..f54dc0cd6e9a
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/apple-aic.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_APPLE_AIC_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_APPLE_AIC_H
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define AIC_IRQ 0
+#define AIC_FIQ 1
+#define AIC_IPI 2
+
+#define AIC_TMR_PHYS 0
+#define AIC_TMR_VIRT 1
+
+#endif
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 17/18] dt-bindings: display: add AAPL,simple-framebuffer

From: Hector Martin <hidden>
Date: 2021-02-04 20:44:50

Apple SoCs run firmware that sets up a simplefb-compatible framebuffer
for us. Add a compatible for it, and two missing supported formats.

Signed-off-by: Hector Martin <redacted>
---
 .../devicetree/bindings/display/simple-framebuffer.yaml      | 5 +++++
 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer.yaml b/Documentation/devicetree/bindings/display/simple-framebuffer.yaml
index eaf8c54fcf50..941c10f40ae5 100644
--- a/Documentation/devicetree/bindings/display/simple-framebuffer.yaml
+++ b/Documentation/devicetree/bindings/display/simple-framebuffer.yaml
@@ -54,6 +54,7 @@ properties:
   compatible:
     items:
       - enum:
+          - AAPL,simple-framebuffer
           - allwinner,simple-framebuffer
           - amlogic,simple-framebuffer
       - const: simple-framebuffer
@@ -84,9 +85,13 @@ properties:
       Format of the framebuffer:
         * `a8b8g8r8` - 32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r
         * `r5g6b5` - 16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b
+        * `x8r8g8b8` - 32-bit pixels, d[23:16]=r, d[15:8]=g, d[7:0]=b
+        * `x2r10g10b10` - 32-bit pixels, d[29:20]=r, d[19:10]=g, d[9:0]=b
     enum:
       - a8b8g8r8
       - r5g6b5
+      - x8r8g8b8
+      - x2r10g10b10
 
   display:
     $ref: /schemas/types.yaml#/definitions/phandle
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Hector Martin <hidden>
Date: 2021-02-04 20:45:04

This currently supports:

* SMP (via spin-tables)
* AIC IRQs
* Serial (with earlycon)
* Framebuffer

A number of properties are dynamic, and based on system firmware
decisions that vary from version to version. These are expected
to be filled in by the loader.

Signed-off-by: Hector Martin <redacted>
---
 MAINTAINERS                              |   1 +
 arch/arm64/boot/dts/Makefile             |   1 +
 arch/arm64/boot/dts/apple/Makefile       |   2 +
 arch/arm64/boot/dts/apple/apple-j274.dts | 143 +++++++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 arch/arm64/boot/dts/apple/Makefile
 create mode 100644 arch/arm64/boot/dts/apple/apple-j274.dts
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a54ee5747d3..5481b5bc2ef7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1635,6 +1635,7 @@ C:	irc://chat.freenode.net/asahi-dev
 T:	git https://github.com/AsahiLinux/linux.git
 F:	Documentation/devicetree/bindings/arm/AAPL.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
+F:	arch/arm64/boot/dts/AAPL/
 F:	drivers/irqchip/irq-apple-aic.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 9b1170658d60..64f055d94948 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -6,6 +6,7 @@ subdir-y += amazon
 subdir-y += amd
 subdir-y += amlogic
 subdir-y += apm
+subdir-y += apple
 subdir-y += arm
 subdir-y += bitmain
 subdir-y += broadcom
diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile
new file mode 100644
index 000000000000..ec03c474efd4
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_APPLE) += apple-j274.dtb
diff --git a/arch/arm64/boot/dts/apple/apple-j274.dts b/arch/arm64/boot/dts/apple/apple-j274.dts
new file mode 100644
index 000000000000..238a1bcee066
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/apple-j274.dts
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Hector Martin <marcan@marcan.st>
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	model = "Apple Mac Mini M1 2020";
+	compatible = "AAPL,j274", "AAPL,m1", "AAPL,arm-platform";
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		bootargs = "earlycon";
+		stdout-path = "serial0:1500000";
+
+		framebuffer0: framebuffer@0 {
+			compatible = "AAPL,simple-framebuffer", "simple-framebuffer";
+			reg = <0 0 0 0>; // To be filled by loader
+			// Format properties will be added by loader
+			status = "disabled";
+		};
+	};
+
+	memory@800000000 {
+		device_type = "memory";
+		reg = <0 0 0 0>; // To be filled by loader
+	};
+
+	aliases {
+		serial0 = &serial0;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu1: cpu@1 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x1>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu2: cpu@2 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x2>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu3: cpu@3 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x3>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu4: cpu@10100 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10100>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu5: cpu@10101 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10101>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu6: cpu@10102 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10102>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu7: cpu@10103 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10103>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 1 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	clk24: clk24 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "clk24";
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		aic: interrupt-controller@23b100000 {
+			compatible = "AAPL,m1-aic", "AAPL,aic";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg = <0x2 0x3b100000 0x0 0x8000>;
+		};
+
+		serial0: serial@235200000 {
+			compatible = "AAPL,s5l-uart";
+			reg = <0x2 0x35200000 0x0 0x1000>;
+			reg-io-width = <4>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 605 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk24>, <&clk24>;
+			clock-names = "uart", "clk_uart_baud0";
+		};
+
+	};
+};
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 16/18] irqchip/apple-aic: Add SMP / IPI support

From: Hector Martin <hidden>
Date: 2021-02-04 20:45:42

Since the hardware IRQ controller only supports two IPIs per CPU and
Linux needs more, we implement 32 virtual IPIs using software and funnel
them through a single hardware IPI.

Signed-off-by: Hector Martin <redacted>
---
 drivers/irqchip/irq-apple-aic.c | 195 +++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index 533e3ce9f432..daeffcca67ca 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -26,7 +26,9 @@
  *
  * Implementation notes:
  *
- * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - This driver creates two IRQ domains, one for HW IRQs and the timer FIQs, and one for IPIs
+ * - Since Linux needs more than 2 IPIs, we implement a software IRQ controller and funnel all IPIs
+ *   into one per-CPU IPI (the second "self" IPI is unused).
  * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
  * - DT bindings use 3-cell form (like GIC):
  *   - <0 nr flags> - hwirq #nr
@@ -34,8 +36,8 @@
  *     - nr=0  physical timer
  *     - nr=1  virtual timer
  *   - <2 nr flags> - IPI #nr
- *     - nr=0  other IPI
- *     - nr=1  self IPI
+ *     - nr=0  other IPI (used internally for the virtual IPIs)
+ *     - nr=1  self IPI (unused)
  *
  */
 
@@ -91,6 +93,7 @@
 
 #define AIC_NR_FIQ		2
 #define AIC_NR_IPI		2
+#define AIC_NR_SWIPI		32
 
 /*
  * Max 31 bits in IPI SEND register (top bit is self).
@@ -101,9 +104,14 @@
 struct aic_irq_chip {
 	void __iomem *base;
 	struct irq_domain *hw_domain;
+	struct irq_domain *ipi_domain;
 	int nr_hw;
+	int ipi_hwirq;
 };
 
+atomic_t aic_vipi_flag[AIC_MAX_CPUS];
+atomic_t aic_vipi_mask[AIC_MAX_CPUS];
+
 static struct aic_irq_chip *aic_irqc;
 
 static inline u32 aic_ic_read(struct aic_irq_chip *ic, u32 reg)
@@ -159,6 +167,11 @@ static void aic_handle_irq(struct pt_regs *regs)
 		if (type == AIC_EVENT_TYPE_HW) {
 			handle_domain_irq(aic_irqc->hw_domain, irq, regs);
 		} else if (type == AIC_EVENT_TYPE_IPI) {
+			/*
+			 * Ensure loads from normal memory are ordered with respect to the wmb()
+			 * in aic_ipi_send_mask().
+			 */
+			rmb();
 			handle_domain_irq(aic_irqc->hw_domain,
 					  ic->nr_hw + AIC_NR_FIQ + irq - 1, regs);
 		} else {
@@ -202,11 +215,33 @@ static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
 		aic_handle_irq(regs);
 }
 
+static int aic_irq_set_affinity(struct irq_data *d,
+				const struct cpumask *mask_val, bool force)
+{
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+	int cpu;
+
+	if (hwirq > ic->nr_hw)
+		return -EINVAL;
+
+	if (force)
+		cpu = cpumask_first(mask_val);
+	else
+		cpu = cpumask_any_and(mask_val, cpu_online_mask);
+
+	aic_ic_write(ic, AIC_TARGET_CPU + hwirq * 4, BIT(cpu));
+	irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
+	return IRQ_SET_MASK_OK;
+}
+
 static struct irq_chip aic_chip = {
 	.name = "AIC",
 	.irq_mask = aic_irq_mask,
 	.irq_unmask = aic_irq_unmask,
 	.irq_eoi = aic_irq_eoi,
+	.irq_set_affinity = aic_irq_set_affinity,
 };
 
 static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,
@@ -264,6 +299,149 @@ static const struct irq_domain_ops aic_irq_domain_ops = {
 	.xlate = aic_irq_domain_xlate,
 };
 
+static void aic_ipi_mask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+	u32 irq_bit = BIT(irqd_to_hwirq(d));
+	int this_cpu = smp_processor_id();
+
+	atomic_and(~irq_bit, &aic_vipi_mask[this_cpu]);
+
+	if (!atomic_read(&aic_vipi_mask[this_cpu]))
+		aic_ic_write(ic, AIC_IPI_MASK_SET, AIC_IPI_OTHER);
+}
+
+static void aic_ipi_unmask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+	u32 irq_bit = BIT(irqd_to_hwirq(d));
+	int this_cpu = smp_processor_id();
+
+	/* Make sure the kernel's idea of logical CPU order is the same as AIC's */
+	WARN_ON(aic_ic_read(ic, AIC_WHOAMI) != this_cpu);
+
+	atomic_or(irq_bit, &aic_vipi_mask[this_cpu]);
+
+	aic_ic_write(ic, AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
+}
+
+static void aic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+	u32 irq_bit = BIT(irqd_to_hwirq(d));
+	u32 send = 0;
+	int cpu;
+
+	for_each_cpu(cpu, mask) {
+		if (atomic_read(&aic_vipi_mask[cpu]) & irq_bit) {
+			atomic_or(irq_bit, &aic_vipi_flag[cpu]);
+			send |= AIC_IPI_SEND_CPU(cpu);
+		}
+	}
+
+	if (send) {
+		/*
+		 * Ensure that stores to Normal memory are visible to the
+		 * other CPUs before issuing the IPI.
+		 */
+		wmb();
+		aic_ic_write(ic, AIC_IPI_SEND, send);
+	}
+}
+
+static struct irq_chip ipi_chip = {
+	.name = "AIC-IPI",
+	.irq_mask = aic_ipi_mask,
+	.irq_unmask = aic_ipi_unmask,
+	.ipi_send_mask = aic_ipi_send_mask,
+};
+
+static void aic_handle_ipi(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	int this_cpu = smp_processor_id();
+	int i;
+	unsigned long firing;
+
+	chained_irq_enter(chip, desc);
+	aic_ic_write(aic_irqc, AIC_IPI_ACK, AIC_IPI_OTHER);
+
+	firing = atomic_xchg(&aic_vipi_flag[this_cpu], 0);
+
+	for_each_set_bit(i, &firing, AIC_NR_SWIPI) {
+		generic_handle_irq(irq_find_mapping(aic_irqc->ipi_domain, i));
+	}
+
+	aic_ic_write(aic_irqc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
+	chained_irq_exit(chip, desc);
+}
+
+static int aic_ipi_alloc(struct irq_domain *d, unsigned int virq,
+			 unsigned int nr_irqs, void *args)
+{
+	int i;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_set_percpu_devid(virq + i);
+		irq_domain_set_info(d, virq + i, i, &ipi_chip, d->host_data,
+				    handle_percpu_devid_irq, NULL, NULL);
+	}
+
+	return 0;
+}
+
+static void aic_ipi_free(struct irq_domain *d, unsigned int virq,
+			 unsigned int nr_irqs)
+{
+	/* Not freeing IPIs */
+}
+
+static const struct irq_domain_ops aic_ipi_domain_ops = {
+	.alloc = aic_ipi_alloc,
+	.free = aic_ipi_free,
+};
+
+static int aic_init_smp(struct aic_irq_chip *irqc, struct device_node *node)
+{
+	struct irq_fwspec ipi_fwspec = {
+		.fwnode         = irqc->hw_domain->fwnode,
+		.param_count    = 3,
+		.param          = {
+			[0]     = AIC_IPI,
+			[1]     = 0,
+			[2]     = 0,
+		},
+	};
+	int base_ipi, mux_irq;
+
+	mux_irq = irq_create_fwspec_mapping(&ipi_fwspec);
+	if (WARN_ON(mux_irq <= 0))
+		return -ENODEV;
+
+	irqc->ipi_domain =
+		irq_domain_create_linear(irqc->hw_domain->fwnode, AIC_NR_SWIPI,
+					 &aic_ipi_domain_ops, irqc);
+	if (WARN_ON(!irqc->ipi_domain))
+		return -ENODEV;
+
+	irqc->ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE;
+	irq_domain_update_bus_token(irqc->ipi_domain, DOMAIN_BUS_IPI);
+
+	base_ipi = __irq_domain_alloc_irqs(irqc->ipi_domain, -1, AIC_NR_SWIPI,
+					   NUMA_NO_NODE, NULL, false, NULL);
+
+	if (WARN_ON(!base_ipi)) {
+		irq_domain_remove(irqc->ipi_domain);
+		return -ENODEV;
+	}
+
+	set_smp_ipi_range(base_ipi, AIC_NR_SWIPI);
+
+	irq_set_chained_handler_and_data(mux_irq, aic_handle_ipi, NULL);
+
+	return 0;
+}
+
 static int __init aic_of_ic_init(struct device_node *node,
 				 struct device_node *parent)
 {
@@ -298,6 +476,13 @@ static int __init aic_of_ic_init(struct device_node *node,
 
 	irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED);
 
+	if (aic_init_smp(irqc, node)) {
+		irq_domain_remove(irqc->hw_domain);
+		iounmap(irqc->base);
+		kfree(irqc);
+		return -ENODEV;
+	}
+
 	set_handle_irq(aic_handle_irq_or_fiq);
 
 	for (i = 0; i < BITS_TO_LONGS(irqc->nr_hw); i++)
@@ -307,8 +492,8 @@ static int __init aic_of_ic_init(struct device_node *node,
 	for (i = 0; i < irqc->nr_hw; i++)
 		aic_ic_write(irqc, AIC_TARGET_CPU + i * 4, 1);
 
-	pr_info("AIC: initialized with %d IRQs, %d FIQs, %d IPIs\n",
-		irqc->nr_hw, AIC_NR_FIQ, AIC_NR_IPI);
+	pr_info("AIC: initialized with %d IRQs, %d FIQs, %d IPIs, %d vIPIs\n",
+		irqc->nr_hw, AIC_NR_FIQ, AIC_NR_IPI, AIC_NR_SWIPI);
 
 	return 0;
 }
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Hector Martin <hidden>
Date: 2021-02-04 20:46:00

This is the root interrupt controller used on Apple ARM SoCs such as the
M1. This irqchip driver performs multiple functions:

* Discriminates between IRQs and FIQs

* Drives the AIC peripheral itself (which handles IRQs)

* Dispatches FIQs to downstream hard-wired clients (currently the ARM
  timer).

This patch introduces basic UP irqchip support, without SMP/IPI support.

Signed-off-by: Hector Martin <redacted>
---
 MAINTAINERS                     |   1 +
 drivers/irqchip/Kconfig         |  10 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-apple-aic.c | 316 ++++++++++++++++++++++++++++++++
 4 files changed, 328 insertions(+)
 create mode 100644 drivers/irqchip/irq-apple-aic.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f3d4661731c8..3a54ee5747d3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1635,6 +1635,7 @@ C:	irc://chat.freenode.net/asahi-dev
 T:	git https://github.com/AsahiLinux/linux.git
 F:	Documentation/devicetree/bindings/arm/AAPL.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
+F:	drivers/irqchip/irq-apple-aic.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 
 ARM/ARTPEC MACHINE SUPPORT
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index b147f22a78f4..288c01a9abd4 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -590,4 +590,14 @@ config MST_IRQ
 	help
 	  Support MStar Interrupt Controller.
 
+config APPLE_AIC
+	bool "Apple Interrupt Controller (AIC)"
+	depends on ARCH_APPLE || COMPILE_TEST
+	default ARCH_APPLE
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+	help
+	  Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
+	  such as the M1.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 0ac93bfaec61..0e2ba7c2dce7 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
 obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
 obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o
 obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
+obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
new file mode 100644
index 000000000000..533e3ce9f432
--- /dev/null
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 Hector Martin <marcan@marcan.st>
+ *
+ * Based on irq-lpc32xx:
+ *   Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com>
+ * Based on irq-bcm2836:
+ *   Copyright 2015 Broadcom
+ */
+
+/*
+ * AIC is a fairly simple interrupt controller with the following features:
+ *
+ * - 896 level-triggered hardware IRQs
+ *   - Single mask bit per IRQ
+ *   - Per-IRQ affinity setting
+ *   - Automatic masking on event delivery (auto-ack)
+ *   - Software triggering (ORed with hw line)
+ * - 2 per-CPU IPIs (meant as "self" and "other", but they are interchangeable if not symmetric)
+ * - Automatic prioritization (single event/ack register per CPU, lower IRQs = higher priority)
+ * - Automatic masking on ack
+ * - Default "this CPU" register view and explicit per-CPU views
+ *
+ * In addition, this driver also handles FIQs, as these are routed to the same IRQ vector. These
+ * are used for Fast IPIs (TODO) and the ARMv8 timer IRQs.
+ *
+ * Implementation notes:
+ *
+ * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
+ * - DT bindings use 3-cell form (like GIC):
+ *   - <0 nr flags> - hwirq #nr
+ *   - <1 nr flags> - FIQ #nr
+ *     - nr=0  physical timer
+ *     - nr=1  virtual timer
+ *   - <2 nr flags> - IPI #nr
+ *     - nr=0  other IPI
+ *     - nr=1  self IPI
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <asm/exception.h>
+
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+
+#define AIC_INFO		0x0004
+#define AIC_INFO_NR_HW(i)	((i) & 0x0000ffff)
+
+#define AIC_CONFIG		0x0010
+
+#define AIC_WHOAMI		0x2000
+#define AIC_EVENT		0x2004
+
+#define AIC_EVENT_TYPE_HW	1
+#define AIC_EVENT_TYPE_IPI	4
+#define AIC_EVENT_IPI_OTHER	1
+#define AIC_EVENT_IPI_SELF	2
+
+#define AIC_IPI_SEND		0x2008
+#define AIC_IPI_ACK		0x200c
+#define AIC_IPI_MASK_SET	0x2024
+#define AIC_IPI_MASK_CLR	0x2028
+
+#define AIC_IPI_SEND_CPU(cpu)	BIT(cpu)
+
+#define AIC_IPI_OTHER		BIT(0)
+#define AIC_IPI_SELF		BIT(31)
+
+#define AIC_TARGET_CPU		0x3000
+#define AIC_SW_SET		0x4000
+#define AIC_SW_CLR		0x4080
+#define AIC_MASK_SET		0x4100
+#define AIC_MASK_CLR		0x4180
+
+#define AIC_CPU_IPI_SET(cpu)	(0x5008 + (cpu << 7))
+#define AIC_CPU_IPI_CLR(cpu)	(0x500c + (cpu << 7))
+#define AIC_CPU_IPI_MASK_SET(cpu) (0x5024 + (cpu << 7))
+#define AIC_CPU_IPI_MASK_CLR(cpu) (0x5028 + (cpu << 7))
+
+#define MASK_REG(x)		(4 * ((x) >> 5))
+#define MASK_BIT(x)		BIT((x) & 0x1f)
+
+#define AIC_NR_FIQ		2
+#define AIC_NR_IPI		2
+
+/*
+ * Max 31 bits in IPI SEND register (top bit is self).
+ * >=32-core chips will need code changes anyway.
+ */
+#define AIC_MAX_CPUS 31
+
+struct aic_irq_chip {
+	void __iomem *base;
+	struct irq_domain *hw_domain;
+	int nr_hw;
+};
+
+static struct aic_irq_chip *aic_irqc;
+
+static inline u32 aic_ic_read(struct aic_irq_chip *ic, u32 reg)
+{
+	return readl(ic->base + reg);
+}
+
+static inline void aic_ic_write(struct aic_irq_chip *ic, u32 reg, u32 val)
+{
+	writel(val, ic->base + reg);
+}
+
+/* These functions do nothing for FIQs, because they have no masks */
+static void aic_irq_mask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+
+	if (d->hwirq < ic->nr_hw)
+		aic_ic_write(ic, AIC_MASK_SET + MASK_REG(d->hwirq),
+			     MASK_BIT(d->hwirq));
+}
+
+static void aic_irq_unmask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+
+	if (d->hwirq < ic->nr_hw)
+		aic_ic_write(ic, AIC_MASK_CLR + MASK_REG(d->hwirq),
+			     MASK_BIT(d->hwirq));
+}
+
+static void aic_irq_eoi(struct irq_data *d)
+{
+	/*
+	 * Reading the interrupt reason automatically acknowledges and masks
+	 * the IRQ, so we just unmask it here if needed.
+	 */
+	if (!irqd_irq_disabled(d) && !irqd_irq_masked(d))
+		aic_irq_unmask(d);
+}
+
+static void aic_handle_irq(struct pt_regs *regs)
+{
+	struct aic_irq_chip *ic = aic_irqc;
+	u32 event = aic_ic_read(ic, AIC_EVENT);
+
+	while (event) {
+		u32 type = event >> 16, irq = event & 0xffff;
+
+		/* AIC_EVENT is read-sensitive, ensure it happens before we proceed */
+		isb();
+
+		if (type == AIC_EVENT_TYPE_HW) {
+			handle_domain_irq(aic_irqc->hw_domain, irq, regs);
+		} else if (type == AIC_EVENT_TYPE_IPI) {
+			handle_domain_irq(aic_irqc->hw_domain,
+					  ic->nr_hw + AIC_NR_FIQ + irq - 1, regs);
+		} else {
+			pr_err("spurious IRQ event %d, %d\n", type, irq);
+		}
+
+		event = aic_ic_read(ic, AIC_EVENT);
+	}
+}
+
+#define TIMER_FIRING(x)                                                        \
+	(((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
+		 ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
+	 (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
+
+static void aic_handle_fiq(struct pt_regs *regs)
+{
+	/*
+	 * It would be really nice to find a system register that lets us get the FIQ source
+	 * state without having to peek down into clients...
+	 */
+	if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) {
+		handle_domain_irq(aic_irqc->hw_domain,
+				  aic_irqc->nr_hw + AIC_TMR_PHYS, regs);
+	}
+
+	if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) {
+		handle_domain_irq(aic_irqc->hw_domain,
+				  aic_irqc->nr_hw + AIC_TMR_VIRT, regs);
+	}
+}
+
+static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
+{
+	u64 isr = read_sysreg(isr_el1);
+
+	if (isr & PSR_F_BIT)
+		aic_handle_fiq(regs);
+
+	if (isr & PSR_I_BIT)
+		aic_handle_irq(regs);
+}
+
+static struct irq_chip aic_chip = {
+	.name = "AIC",
+	.irq_mask = aic_irq_mask,
+	.irq_unmask = aic_irq_unmask,
+	.irq_eoi = aic_irq_eoi,
+};
+
+static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	struct aic_irq_chip *ic = id->host_data;
+
+	irq_set_chip_data(irq, ic);
+	if (hw < ic->nr_hw) {
+		irq_set_chip_and_handler(irq, &aic_chip, handle_fasteoi_irq);
+	} else {
+		irq_set_percpu_devid(irq);
+		irq_set_chip_and_handler(irq, &aic_chip,
+					 handle_percpu_devid_irq);
+	}
+	irq_set_status_flags(irq, IRQ_LEVEL);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static void aic_irq_domain_unmap(struct irq_domain *id, unsigned int irq)
+{
+	irq_set_chip_and_handler(irq, NULL, NULL);
+}
+
+static int aic_irq_domain_xlate(struct irq_domain *id,
+				struct device_node *ctrlr, const u32 *intspec,
+				unsigned int intsize,
+				irq_hw_number_t *out_hwirq,
+				unsigned int *out_type)
+{
+	struct aic_irq_chip *ic = id->host_data;
+
+	if (intsize != 3)
+		return -EINVAL;
+
+	if (intspec[0] == AIC_IRQ && intspec[1] < ic->nr_hw)
+		*out_hwirq = intspec[1];
+	else if (intspec[0] == AIC_FIQ && intspec[1] < AIC_NR_FIQ)
+		*out_hwirq = ic->nr_hw + intspec[1];
+	else if (intspec[0] == AIC_IPI && intspec[1] < AIC_NR_IPI)
+		*out_hwirq = ic->nr_hw + AIC_NR_FIQ + intspec[1];
+	else
+		return -EINVAL;
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+
+	return 0;
+}
+
+static const struct irq_domain_ops aic_irq_domain_ops = {
+	.map = aic_irq_domain_map,
+	.unmap = aic_irq_domain_unmap,
+	.xlate = aic_irq_domain_xlate,
+};
+
+static int __init aic_of_ic_init(struct device_node *node,
+				 struct device_node *parent)
+{
+	int i;
+	void __iomem *regs;
+	u32 info;
+	struct aic_irq_chip *irqc;
+
+	regs = of_iomap(node, 0);
+	if (WARN_ON(!regs))
+		return -EIO;
+
+	irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
+	if (!irqc)
+		return -ENOMEM;
+
+	aic_irqc = irqc;
+	irqc->base = regs;
+
+	info = aic_ic_read(irqc, AIC_INFO);
+	irqc->nr_hw = AIC_INFO_NR_HW(info);
+
+	irqc->hw_domain =
+		irq_domain_add_linear(node,
+				      irqc->nr_hw + AIC_NR_FIQ + AIC_NR_IPI,
+				      &aic_irq_domain_ops, irqc);
+	if (WARN_ON(!irqc->hw_domain)) {
+		iounmap(irqc->base);
+		kfree(irqc);
+		return -ENODEV;
+	}
+
+	irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED);
+
+	set_handle_irq(aic_handle_irq_or_fiq);
+
+	for (i = 0; i < BITS_TO_LONGS(irqc->nr_hw); i++)
+		aic_ic_write(irqc, AIC_MASK_SET + i * 4, ~0);
+	for (i = 0; i < BITS_TO_LONGS(irqc->nr_hw); i++)
+		aic_ic_write(irqc, AIC_SW_CLR + i * 4, ~0);
+	for (i = 0; i < irqc->nr_hw; i++)
+		aic_ic_write(irqc, AIC_TARGET_CPU + i * 4, 1);
+
+	pr_info("AIC: initialized with %d IRQs, %d FIQs, %d IPIs\n",
+		irqc->nr_hw, AIC_NR_FIQ, AIC_NR_IPI);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(apple_m1_aic, "AAPL,aic", aic_of_ic_init);
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 02/18] dt-bindings: arm: cpus: Add AAPL,firestorm & icestorm compatibles

From: Hector Martin <hidden>
Date: 2021-02-04 20:46:01

These are the CPU cores in the "Apple Silicon" M1 SoC.

Signed-off-by: Hector Martin <redacted>
---
 Documentation/devicetree/bindings/arm/cpus.yaml | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml
index f02fd10de604..52cb69fd78c5 100644
--- a/Documentation/devicetree/bindings/arm/cpus.yaml
+++ b/Documentation/devicetree/bindings/arm/cpus.yaml
@@ -85,6 +85,8 @@ properties:
 
   compatible:
     enum:
+      - AAPL,icestorm
+      - AAPL,firestorm
       - arm,arm710t
       - arm,arm720t
       - arm,arm740t
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 03/18] dt-bindings: arm: AAPL: Add bindings for Apple ARM platforms

From: Hector Martin <hidden>
Date: 2021-02-04 20:46:20

This introduces bindings for all three 2020 Apple M1 devices:

* AAPL,j274 - Mac mini (M1, 2020)
* AAPL,j293 - MacBook Pro (13-inch, M1, 2020)
* AAPL,j313 - MacBook Air (M1, 2020)

Signed-off-by: Hector Martin <redacted>
---
 .../devicetree/bindings/arm/AAPL.yaml         | 36 +++++++++++++++++++
 MAINTAINERS                                   | 10 ++++++
 2 files changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/AAPL.yaml
diff --git a/Documentation/devicetree/bindings/arm/AAPL.yaml b/Documentation/devicetree/bindings/arm/AAPL.yaml
new file mode 100644
index 000000000000..145b184e4a24
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/AAPL.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/AAPL.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple ARM Machine Device Tree Bindings
+
+maintainers:
+  - Hector Martin <marcan@marcan.st>
+
+description: |
+  Apple ARM ("Apple Silicon") platforms should contain compatible strings
+  in the following format:
+
+  - AAPL,j274 (board/device ID)
+  - AAPL,m1 (SoC name)
+  - AAPL,arm-platform (used for all Apple ARM devices)
+
+properties:
+  $nodename:
+    const: "/"
+  compatible:
+    oneOf:
+      - description: Apple M1 SoC based platforms
+        items:
+          - enum:
+              - AAPL,j274 # Mac mini (M1, 2020)
+              - AAPL,j293 # MacBook Pro (13-inch, M1, 2020)
+              - AAPL,j313 # MacBook Air (M1, 2020)
+          - const: AAPL,m1
+          - const: AAPL,arm-platform
+
+additionalProperties: true
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index d3e847f7f3dc..91a7b33834ac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1625,6 +1625,16 @@ F:	arch/arm/mach-alpine/
 F:	arch/arm64/boot/dts/amazon/
 F:	drivers/*/*alpine*
 
+ARM/APPLE MACHINE SUPPORT
+M:	Hector Martin <marcan@marcan.st>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+W:	https://asahilinux.org
+B:	https://github.com/AsahiLinux/linux/issues
+C:	irc://chat.freenode.net/asahi-dev
+T:	git https://github.com/AsahiLinux/linux.git
+F:	Documentation/devicetree/bindings/arm/AAPL.yaml
+
 ARM/ARTPEC MACHINE SUPPORT
 M:	Jesper Nilsson <jesper.nilsson@axis.com>
 M:	Lars Persson <lars.persson@axis.com>
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 12/18] arm64: setup: Use nGnRnE IO mappings for fixmap on Apple platforms

From: Hector Martin <hidden>
Date: 2021-02-04 20:46:50

This is a hack. I do not expect this to be merged as-is.

The problem: on Apple ARM platforms, SoC MMIO needs to use nGnRnE
mappings: writes using nGnRE are blackholed. This seems to be by design,
and there doesn't seem to be any fabric configuration or other bit we
can flip to make the problem go away.

Particularly tricky is that this affects earlycon, which uses fixmap,
which all gets initialized before any of the usual cpufeatures /
alternatives stuff. So we need to take care of fixmap very early.

Options I can think of:

(1) Unconditionally use nGnRnE on all platforms for fixmap IO. Maybe
    this is actually fine? I suspect it might break some PCI-based
    earlycons?

(2) Deal with this special case in the earlycon code, since that seems
    to be the only user that matters on these platforms. Since the
    IO mapping is done in earlycon.c, this will require some cooperation
    with samsung_tty.c so earlycon knows when it needs to do this. Note
    that doing it with DT properties will break cmdline-only earlycon
    config (which otherwise works fine on this driver).

(3) This patch, but do something saner, like use a specific DT flag to
    trigger this mode instead of a platform match.

Any other ideas?

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/include/asm/fixmap.h | 10 +++++++++-
 arch/arm64/kernel/setup.c       | 12 ++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 4335800201c9..999351ce84df 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -94,7 +94,15 @@ enum fixed_addresses {
 #define FIXADDR_SIZE	(__end_of_permanent_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
 
-#define FIXMAP_PAGE_IO     __pgprot(PROT_DEVICE_nGnRE)
+/*
+ * We use nGnRE by default, but some platforms require nGnRnE for MMIO.
+ */
+extern bool arm64_use_ne_io;
+
+#define FIXMAP_PAGE_IO_DEFAULT	__pgprot(PROT_DEVICE_nGnRE)
+#define FIXMAP_PAGE_IO_STRICT	__pgprot(PROT_DEVICE_nGnRnE)
+#define FIXMAP_PAGE_IO		(arm64_use_ne_io ? FIXMAP_PAGE_IO_STRICT \
+						 : FIXMAP_PAGE_IO_DEFAULT)
 
 void __init early_fixmap_init(void);
 
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index c18aacde8bb0..cd2dc3bdbae4 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -56,6 +56,8 @@ static struct resource *standard_resources;
 
 phys_addr_t __fdt_pointer __initdata;
 
+bool arm64_use_ne_io;
+
 /*
  * Standard memory resources
  */
@@ -197,6 +199,16 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
 
 	pr_info("Machine model: %s\n", name);
 	dump_stack_set_arch_desc("%s (DT)", name);
+
+#ifdef CONFIG_ARCH_APPLE
+	/*
+	 * Apple SoCs need to use nGnRnE mappings for MMIO, and this needs
+	 * to be detected before earlycon is initialized.
+	 */
+	if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+				     "AAPL,arm-platform"))
+		arm64_use_ne_io = true;
+#endif
 }
 
 static void __init request_standard_resources(void)
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 11/18] arm64: Kconfig: Require FIQ support for ARCH_APPLE

From: Hector Martin <hidden>
Date: 2021-02-04 20:47:18

All currently supported Apple ARM SoCs (and possibly all future ones
too) require FIQs.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig.platforms | 1 +
 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index e3e3bd2c4374..8182d78e8e23 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -32,6 +32,7 @@ config ARCH_ALPINE
 config ARCH_APPLE
 	bool "Apple Silicon SoC family"
 	select GENERIC_IRQ_CHIP
+	select ARM64_FIQ_SUPPORT
 	help
 	  This enables support for Apple's in-house ARM SoC family, starting
 	  with the Apple M1.
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[PATCH 10/18] arm64: Introduce FIQ support

From: Hector Martin <hidden>
Date: 2021-02-04 20:47:18

Apple SoCs (A11 and newer) have some interrupt sources hardwired to the
FIQ line. Implement support for this by simply treating IRQs and FIQs
the same way in the interrupt vectors. This is conditional on the
ARM64_NEEDS_FIQ CPU feature flag, and thus will not affect other
systems.

Root irqchip drivers can discriminate between IRQs and FIQs by checking
the ISR_EL1 system register.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/include/asm/assembler.h |  4 ++++
 arch/arm64/include/asm/daifflags.h |  7 +++++++
 arch/arm64/include/asm/irqflags.h  | 17 +++++++++++++----
 arch/arm64/kernel/entry.S          | 27 +++++++++++++++++++++++----
 4 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index bf125c591116..6acfc372dc76 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -42,7 +42,11 @@
 
 	/* IRQ is the lowest priority flag, unconditionally unmask the rest. */
 	.macro enable_da_f
+alternative_if ARM64_NEEDS_FIQ
+	msr	daifclr, #(8 | 4)
+alternative_else
 	msr	daifclr, #(8 | 4 | 1)
+alternative_endif
 	.endm
 
 /*
diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
index 1c26d7baa67f..228a6039c701 100644
--- a/arch/arm64/include/asm/daifflags.h
+++ b/arch/arm64/include/asm/daifflags.h
@@ -112,6 +112,13 @@ static inline void local_daif_restore(unsigned long flags)
 		 * So we don't need additional synchronization here.
 		 */
 		gic_write_pmr(pmr);
+	} else if (system_uses_fiqs()) {
+		/*
+		 * On systems that use FIQs, disable FIQs if IRQs are disabled.
+		 * This can happen if the DAIF_* flags at the top of this file
+		 * are used to set DAIF directly.
+		 */
+		flags |= PSR_F_BIT;
 	}
 
 	write_sysreg(flags, daif);
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index ff328e5bbb75..689c573c4b47 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -19,8 +19,9 @@
  * side effects for other flags. Keeping to this order makes it easier for
  * entry.S to know which exceptions should be unmasked.
  *
- * FIQ is never expected, but we mask it when we disable debug exceptions, and
- * unmask it at all other times.
+ * FIQ is never expected on most platforms, but we mask it when we disable
+ * debug exceptions, and unmask it at all other times. On platforms that
+ * require FIQs, it tracks IRQ masking.
  */
 
 /*
@@ -34,8 +35,14 @@ static inline void arch_local_irq_enable(void)
 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
 	}
 
-	asm volatile(ALTERNATIVE(
+	/*
+	 * Yes, ALTERNATIVE() nests properly... only one of these should be
+	 * active on any given platform.
+	 */
+	asm volatile(ALTERNATIVE(ALTERNATIVE(
 		"msr	daifclr, #2		// arch_local_irq_enable",
+		"msr	daifclr, #3		// arch_local_irq_enable",
+		ARM64_NEEDS_FIQ),
 		__msr_s(SYS_ICC_PMR_EL1, "%0"),
 		ARM64_HAS_IRQ_PRIO_MASKING)
 		:
@@ -53,8 +60,10 @@ static inline void arch_local_irq_disable(void)
 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
 	}
 
-	asm volatile(ALTERNATIVE(
+	asm volatile(ALTERNATIVE(ALTERNATIVE(
 		"msr	daifset, #2		// arch_local_irq_disable",
+		"msr	daifset, #3		// arch_local_irq_disable",
+		ARM64_NEEDS_FIQ),
 		__msr_s(SYS_ICC_PMR_EL1, "%0"),
 		ARM64_HAS_IRQ_PRIO_MASKING)
 		:
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index c9bae73f2621..81ca04ebe37b 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -60,7 +60,7 @@
 #define BAD_FIQ		2
 #define BAD_ERROR	3
 
-	.macro kernel_ventry, el, label, regsize = 64
+	.macro kernel_ventry, el, label, regsize = 64, altlabel = 0, alt = 0
 	.align 7
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 	.if	\el == 0
@@ -87,7 +87,15 @@ alternative_else_nop_endif
 	tbnz	x0, #THREAD_SHIFT, 0f
 	sub	x0, sp, x0			// x0'' = sp' - x0' = (sp + x0) - sp = x0
 	sub	sp, sp, x0			// sp'' = sp' - x0 = (sp + x0) - x0 = sp
+	.if	\altlabel != 0
+	alternative_if \alt
+	b	el\()\el\()_\altlabel
+	alternative_else
 	b	el\()\el\()_\label
+	alternative_endif
+	.else
+	b	el\()\el\()_\label
+	.endif
 
 0:
 	/*
@@ -119,7 +127,15 @@ alternative_else_nop_endif
 	sub	sp, sp, x0
 	mrs	x0, tpidrro_el0
 #endif
+	.if	\altlabel != 0
+	alternative_if \alt
+	b	el\()\el\()_\altlabel
+	alternative_else
 	b	el\()\el\()_\label
+	alternative_endif
+	.else
+	b	el\()\el\()_\label
+	.endif
 	.endm
 
 	.macro tramp_alias, dst, sym
@@ -547,18 +563,21 @@ SYM_CODE_START(vectors)
 
 	kernel_ventry	1, sync				// Synchronous EL1h
 	kernel_ventry	1, irq				// IRQ EL1h
-	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+							// FIQ EL1h
+	kernel_ventry	1, fiq_invalid, 64, irq, ARM64_NEEDS_FIQ
 	kernel_ventry	1, error			// Error EL1h
 
 	kernel_ventry	0, sync				// Synchronous 64-bit EL0
 	kernel_ventry	0, irq				// IRQ 64-bit EL0
-	kernel_ventry	0, fiq_invalid			// FIQ 64-bit EL0
+							// FIQ 64-bit EL0
+	kernel_ventry	0, fiq_invalid, 64, irq, ARM64_NEEDS_FIQ
 	kernel_ventry	0, error			// Error 64-bit EL0
 
 #ifdef CONFIG_COMPAT
 	kernel_ventry	0, sync_compat, 32		// Synchronous 32-bit EL0
 	kernel_ventry	0, irq_compat, 32		// IRQ 32-bit EL0
-	kernel_ventry	0, fiq_invalid_compat, 32	// FIQ 32-bit EL0
+							// FIQ 32-bit EL0
+	kernel_ventry	0, fiq_invalid_compat, 32, irq_compat, ARM64_NEEDS_FIQ
 	kernel_ventry	0, error_compat, 32		// Error 32-bit EL0
 #else
 	kernel_ventry	0, sync_invalid, 32		// Synchronous 32-bit EL0
-- 
2.30.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 07/18] tty: serial: samsung_tty: enable for ARCH_APPLE

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 21:17:57

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
 config SERIAL_SAMSUNG
        tristate "Samsung SoC serial support"
-       depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+       depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST || ARCH_APPLE
By convention, please keep "|| COMPILE_TEST" last in the list.

            Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 07/18] tty: serial: samsung_tty: enable for ARCH_APPLE

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-04 21:27:58

On 05/02/2021 06.16, Arnd Bergmann wrote:
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
quoted
  config SERIAL_SAMSUNG
         tristate "Samsung SoC serial support"
-       depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+       depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST || ARCH_APPLE
By convention, please keep "|| COMPILE_TEST" last in the list.
Ack, good catch! Fixed for v2.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 21:31:03

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
+/ {
+       model = "Apple Mac Mini M1 2020";
+       compatible = "AAPL,j274", "AAPL,m1", "AAPL,arm-platform";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       chosen {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               bootargs = "earlycon";
+               stdout-path = "serial0:1500000";
+
+               framebuffer0: framebuffer@0 {
+                       compatible = "AAPL,simple-framebuffer", "simple-framebuffer";
+                       reg = <0 0 0 0>; // To be filled by loader
+                       // Format properties will be added by loader
+                       status = "disabled";
+               };
+       };
+
+       memory@800000000 {
+               device_type = "memory";
+               reg = <0 0 0 0>; // To be filled by loader
+       };
+
+       aliases {
+               serial0 = &serial0;
+       };
We tend to split the dts file into one file per SoC and one for the
specific board. I guess in this case the split can be slightly different,
but it does feel better to be prepared for sharing a lot of the contents
between the different products.

In most cases, you'd want the 'aliases' and 'chosen' nodes to be
in the board specific file.
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       compatible = "AAPL,icestorm";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0>; // To be filled by loader
+               };
Did you see the discussion on the #armlinux channel about the possibility
of moving the cpu-enable method to PSCI based on a UEFI runtime
interface?

There are a few open questions about what that would look like in the
end, but Ard has come up with a prototype for the kernel side of it
(obviously untested), which would interface either into the UEFI side
of u-boot, or a simple already-instantiated version that could be
kept inside of m1n1 and stay resident in memory.

I would like to see that model get adopted here eventually. If
we manage to get the other patches ready for an initial merge in
v5.12, we can probably start out with spin-table and move to that
in a following release though.

        Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 21:39:32

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
+/*
+ * AIC is a fairly simple interrupt controller with the following features:
+ *
+ * - 896 level-triggered hardware IRQs
+ *   - Single mask bit per IRQ
+ *   - Per-IRQ affinity setting
+ *   - Automatic masking on event delivery (auto-ack)
+ *   - Software triggering (ORed with hw line)
+ * - 2 per-CPU IPIs (meant as "self" and "other", but they are interchangeable if not symmetric)
+ * - Automatic prioritization (single event/ack register per CPU, lower IRQs = higher priority)
+ * - Automatic masking on ack
+ * - Default "this CPU" register view and explicit per-CPU views
+ *
+ * In addition, this driver also handles FIQs, as these are routed to the same IRQ vector. These
+ * are used for Fast IPIs (TODO) and the ARMv8 timer IRQs.
+ *
+ * Implementation notes:
+ *
+ * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
+ * - DT bindings use 3-cell form (like GIC):
+ *   - <0 nr flags> - hwirq #nr
+ *   - <1 nr flags> - FIQ #nr
+ *     - nr=0  physical timer
+ *     - nr=1  virtual timer
+ *   - <2 nr flags> - IPI #nr
+ *     - nr=0  other IPI
+ *     - nr=1  self IPI
I think we should discuss the binding a bit here. My initial thinking was that
it would be better to separate the AIC from the FIQ handling, as they don't
seem to have any relation in hardware, and representing them as two
separate nodes seems like a cleaner abstraction.
+#define TIMER_FIRING(x)                                                        \
+       (((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
+                ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
+        (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
+
+static void aic_handle_fiq(struct pt_regs *regs)
+{
+       /*
+        * It would be really nice to find a system register that lets us get the FIQ source
+        * state without having to peek down into clients...
+        */
+       if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_PHYS, regs);
+       }
+
+       if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_VIRT, regs);
+       }
+}
This seems to be a minor layering violation to me.

One idea I had was to just keep all the fiq handling in the timer driver
itself, jumping there directly from the top-level fiq entry whenever
we are on an Apple platform. At least as long as nothing else ever
uses fiq.

When we discussed the earlier submission for the aic, I understood
that FIQ is used for both timer and IPI, but the IPI actually has another
method based on normal AIC interrupts that can be used as an
alternative.
+static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
+{
+       u64 isr = read_sysreg(isr_el1);
+
+       if (isr & PSR_F_BIT)
+               aic_handle_fiq(regs);
+
+       if (isr & PSR_I_BIT)
+               aic_handle_irq(regs);
+}
Having the shared entry point here looks reasonable to me though, it
does seem to make a few things easier.

I wonder if there is a possible race here: if we are ever in a situation
where one of the two -- fiq or irq -- is disabled while the other one
is enabled, we could get into a state where a handler is run while
it should be masked.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-04 21:48:23

On 05/02/2021 06.29, Arnd Bergmann wrote:
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
quoted
+/ {
+       model = "Apple Mac Mini M1 2020";
+       compatible = "AAPL,j274", "AAPL,m1", "AAPL,arm-platform";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       chosen {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               bootargs = "earlycon";
+               stdout-path = "serial0:1500000";
+
+               framebuffer0: framebuffer@0 {
+                       compatible = "AAPL,simple-framebuffer", "simple-framebuffer";
+                       reg = <0 0 0 0>; // To be filled by loader
+                       // Format properties will be added by loader
+                       status = "disabled";
+               };
+       };
+
+       memory@800000000 {
+               device_type = "memory";
+               reg = <0 0 0 0>; // To be filled by loader
+       };
+
+       aliases {
+               serial0 = &serial0;
+       };
We tend to split the dts file into one file per SoC and one for the
specific board. I guess in this case the split can be slightly different,
but it does feel better to be prepared for sharing a lot of the contents
between the different products.

In most cases, you'd want the 'aliases' and 'chosen' nodes to be
in the board specific file.
I thought about that, but wasn't sure if splitting it up at this early 
stage made much sense since I'm not sure what the split should be, given 
all supported hardware is the same for all 3 released devices.

I'm happy to throw the aliases/chosen nodes into board specific files if 
you think that's a good starting point. Perhaps /memory too? Those 
properties are filled in/patched by the bootloader anyway...

There are also DT overlays; I was wondering if we could use those to 
keep the hierarchy and avoid having many duplicate trees in a 
hypothetical bootloader that embeds support for a large set of hardware, 
having it construct the final devicetree on the fly from SoC + a board 
overlay (and possibly further levels); but I'm not sure how that ties in 
with the device trees that live in the Linux tree. Do you have any 
pointers about this?

For reference, this is our current DT patching code in m1n1:

https://github.com/AsahiLinux/m1n1/blob/main/src/kboot.c

Eventually we're going to build some kind of tooling to automate diffing 
Apple device trees and importing changes/new devices into our own, 
though it will probably be quite a while until that is relevant; at this 
stage hand-maintaining them is perfectly fine (in any case this wouldn't 
be fully automated, so in the end our trees will still be organized 
however we want).
quoted
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       compatible = "AAPL,icestorm";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0 0>; // To be filled by loader
+               };
Did you see the discussion on the #armlinux channel about the possibility
of moving the cpu-enable method to PSCI based on a UEFI runtime
interface?

There are a few open questions about what that would look like in the
end, but Ard has come up with a prototype for the kernel side of it
(obviously untested), which would interface either into the UEFI side
of u-boot, or a simple already-instantiated version that could be
kept inside of m1n1 and stay resident in memory.

I would like to see that model get adopted here eventually. If
we manage to get the other patches ready for an initial merge in
v5.12, we can probably start out with spin-table and move to that
in a following release though.
I saw it go by but need to review it again; I've been missing too much 
sleep this week :) thanks for the reminder.

I think we might want to start with spin-table for now, given that there 
are no kernel changes needed anyway, but I'm happy to take the protoype 
for a spin (:)) and try implementing it in m1n1.

I do think it's valuable for whatever we do, at this stage, to not 
require u-boot; having that be an integral part of the boot chain is 
perfectly fine in the future but right now it helps to have a simple 
boot chain while we work out the early bring-up, and while u-boot grows 
the required support.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-04 22:05:30

On 05/02/2021 06.37, Arnd Bergmann wrote:
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
quoted
+ * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
+ * - DT bindings use 3-cell form (like GIC):
+ *   - <0 nr flags> - hwirq #nr
+ *   - <1 nr flags> - FIQ #nr
+ *     - nr=0  physical timer
+ *     - nr=1  virtual timer
+ *   - <2 nr flags> - IPI #nr
+ *     - nr=0  other IPI
+ *     - nr=1  self IPI
I think we should discuss the binding a bit here. My initial thinking was that
it would be better to separate the AIC from the FIQ handling, as they don't
seem to have any relation in hardware, and representing them as two
separate nodes seems like a cleaner abstraction.
This was actually my original approach (I still have the FIQ irqchip 
patch lying around), but that idea somewhat broke when we decided to 
merge the vectors.

If we split it up again, one of the two still needs to be the root, 
decide whether what fired is an IRQ or FIQ, and dispatch accordingly. Or 
we could have three nodes and have one root handler dispatch to IRQ and 
FIQ nodes, but that sounds like overkill... (?)

Are you proposing just having different drivers/nodes in the same file, 
or implementing these as separate drivers in separate files?
quoted
+#define TIMER_FIRING(x)                                                        \
+       (((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
+                ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
+        (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
+
+static void aic_handle_fiq(struct pt_regs *regs)
+{
+       /*
+        * It would be really nice to find a system register that lets us get the FIQ source
+        * state without having to peek down into clients...
+        */
+       if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_PHYS, regs);
+       }
+
+       if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_VIRT, regs);
+       }
+}
This seems to be a minor layering violation to me.
Absolutely. Under the assumption that these IRQ lines are ORed together 
into FIQ with no top-level dispatch though, there isn't a great solution 
here...

I think there is a chance FIQ interrupt child bits exist *somewhere*, so 
I actually plan on brute-forcing the list of implemented/valid CPU 
registers and trying to see if I can find some bits that do what I want. 
If it turns out they exist, this could alleviate some of the ugliness of 
the current approach.
One idea I had was to just keep all the fiq handling in the timer driver
itself, jumping there directly from the top-level fiq entry whenever
we are on an Apple platform. At least as long as nothing else ever
uses fiq.
In principle, as long as the timer handler only ever uses one IRQ (which 
I think is the case here, it just picks one of the 4, usually the 
physical timer, and it should only enable that one) it would work. But 
we still need *some* IRQ chip driver to deliver that, unless we want to 
throw a bunch of special-case code into the timer driver to hook 
directly into FIQs without an interrupt parent which... seems like it 
could get quite messy.
When we discussed the earlier submission for the aic, I understood
that FIQ is used for both timer and IPI, but the IPI actually has another
method based on normal AIC interrupts that can be used as an
alternative.
Correct, there are two parallel IPI implementations. It is my 
understanding that the CPU register based one, which ties into FIQ, is 
faster / more featureful (it has deferred IPIs, not sure if the plain 
AIC does those), as it is built into the core complexes instead of being 
part of the external AIC block. I could try benchmarking it within m1n1 
and see if I can find out how much faster it is.

I think it's worth thinking about supporting that IPI mechanism, which 
would necessitate dispatching FIQs too, so hard-coding it to route 
straight to the timer doesn't sound like a very future-proof plan... 
consider that Apple might put out a SoC in the future that rips out the 
AIC IPIs and leaves only the FIQ ones too.
quoted
+static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
+{
+       u64 isr = read_sysreg(isr_el1);
+
+       if (isr & PSR_F_BIT)
+               aic_handle_fiq(regs);
+
+       if (isr & PSR_I_BIT)
+               aic_handle_irq(regs);
+}
Having the shared entry point here looks reasonable to me though, it
does seem to make a few things easier.

I wonder if there is a possible race here: if we are ever in a situation
where one of the two -- fiq or irq -- is disabled while the other one
is enabled, we could get into a state where a handler is run while
it should be masked.
That's a good point. We could filter with the SPSR_ELx mask bits here.

Though the FIQ support patch tries pretty hard to keep the mask bits in 
sync after early boot, so this concern might be somewhat academic. I'm 
happy to implement it if you think it might help though.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 13/18] arm64: ioremap: use nGnRnE mappings on platforms that require it

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 22:23:28

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
    Currently there are three ioremap variants:

    ioremap()
    ioremap_wc()
    ioremap_uc() (not normally used on arm64)

    None of these really capture the nGnRE vs nGnRnE distinction. If
    a new variant is introduced in common code, we'd have to provide
    a default implementation that falls back to regular ioremap() on
    other arches. Something like ioremap() vs. ioremap_np() (nonposted)?
The ioport_map() function could be considered a variant of nonposted
I/O, as being nonposted is a requirement for PCI I/O space. It's
a bit weird to overload it here, as I/O space has a number of other
special cases, including a limit for the total size of the address space,
and the assumption that all I/O ports are always mapped into virtual
addresses at boot time.

Are the registers that need nGnRnE all part of a well-defined
physical address range that we could pretend to be I/O space?
Also, is the actual PCI I/O space within this region?

The main advantage here would be that we could reuse the
IORESOURCE_IO bit to signify a register in this area.

Note: I don't actually think this is going to be a good solution, just
throwing it out as another alternative in case everything else ends
up being worse.
(2) The converse of (1): keep the nGnRE default, but introduce special
    casing to the OF binding code to use nGnRnE when instructed to do so
    on these platforms. This means of_iomap() needs changing.
It probably also means changing of_address_to_resource(),
and devm_ioremap_resource().
(3) Do it at a lower level, in ioremap() itself. This requires that
    ioremap() somehow discriminates based on address range to pick what
    kind of mapping to make.

    Declaring these address ranges would be an issue. Options:

    a) An out of band list in a DT node, a la /reserved-memory

    b) Something based on the existing DT hierarchy, where we can scan
       bus ranges and locate buses with a property that says "nGnRnE" or
       "nGnRE" and dynamically build the list based on that.

    The advantage of this option is that it doesn't touch non-arch code.
    The disadvantage is that it adds a complete new bespoke mechanism to
    the DT, and that it does not let device drivers actually select the
    IO mode, which might be desirable in the future anyway for some
    devices.

All discussion and additional ideas welcome.
A very simple but ugly hack would be to take one of the high address
bits in phys_addr_t to encode the type, and then pass that through
all the way into the ioremap implementation.

This does have some precedent with the upper bits of the (96-bit)
PCI addresses encoding the type of resource, but it also conflates
the DT representation with the arm64 kernel implementation and
requires extending both in a fairly generic way to do something that
is highly platform specific.

         Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 12/18] arm64: setup: Use nGnRnE IO mappings for fixmap on Apple platforms

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 22:27:20

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
This is a hack. I do not expect this to be merged as-is.

The problem: on Apple ARM platforms, SoC MMIO needs to use nGnRnE
mappings: writes using nGnRE are blackholed. This seems to be by design,
and there doesn't seem to be any fabric configuration or other bit we
can flip to make the problem go away.

Particularly tricky is that this affects earlycon, which uses fixmap,
which all gets initialized before any of the usual cpufeatures /
alternatives stuff. So we need to take care of fixmap very early.

Options I can think of:

(1) Unconditionally use nGnRnE on all platforms for fixmap IO. Maybe
    this is actually fine? I suspect it might break some PCI-based
    earlycons?

(2) Deal with this special case in the earlycon code, since that seems
    to be the only user that matters on these platforms. Since the
    IO mapping is done in earlycon.c, this will require some cooperation
    with samsung_tty.c so earlycon knows when it needs to do this. Note
    that doing it with DT properties will break cmdline-only earlycon
    config (which otherwise works fine on this driver).

(3) This patch, but do something saner, like use a specific DT flag to
    trigger this mode instead of a platform match.

Any other ideas?
I think we should decide the approach for the normal ioremap()
path first. Once we have solved that, there is likely an obvious
answer for this one as well.

My feeling is that we'll end up with (2).

        Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 00/18] Apple M1 SoC platform bring-up

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 22:45:01

On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
This series brings up initial support for the Apple M1 SoC, used in the
2020 Mac Mini, MacBook Pro, and MacBook Air models.
I like this a lot overall, great work!

As you probably know, the timing would be really tight for a merge
in 5.12, but if we can work out a solution for the FIQ and MMIO
problems quickly and you get Ack's from the relevant maintainers
(arch/arm64, serial, irqchip), I'd be happy to merge all of it through
the soc tree even fairly late this cycle.
The following features are supported in this initial port:

- UART (samsung-style) with earlycon support
- Interrupts, including affinity and IPIs (Apple Interrupt Controller)
- SMP (through standard spin-table support)
- simplefb-based framebuffer
Side note about simplefb: Ard mentioned on IRC that there is
earlycon support in efifb but not in simplefb. Once we have
a u-boot based boot flow, it would be a great help for boot-time
debugging to use earlycon on the framebuffer for those that don't
have a special uart cable.

An alternative would be to rework the simplefb driver in some
form to allow earlycon without efifb. The earlycon support there
is actually fairly simple, but doing this would raise the question
of whether it can be shared between the two and possibly the
drm/kms based drivers.
- Devicetree for the Mac Mini (should work for the others too at this
  stage)

The primary pain points of this port are:

- Apple SoCs require FIQs, as the timers and "fast" IPIs are hardwired
  to the FIQ interrupt line. This patchset introduces FIQ support through
  the alternatives mechanism, so as to not affect other platforms,
  implemented as simply merging IRQs and FIQs. The AIC driver takes care
  of discriminating and routing IRQs to the right users.

- These SoCs blackhole nGnRE writes to internal MMIO ranges, and require
  nGnRnE. There is no obvious right solution to solve this. I do not
  expect the two patches for that in this series to be merged as-is, but
  the commit messages describe the problem and potential solutions. I
  hope we can have a discussion and converge on the right approach to
  solve this problem in the sanest way.
I would add here the cpu enable-method as a third point that needs to
be decided on before we can consider merging it. As I commented
in patch 18, staying with spin-table would be the easiest way to start,
but that means the risk of an incompatible DT change later on.

        Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 23:05:55

On Thu, Feb 4, 2021 at 11:06 PM Hector Martin 'marcan' [off-list ref] wrote:
On 05/02/2021 06.37, Arnd Bergmann wrote:
quoted
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:
quoted
+ * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
+ * - DT bindings use 3-cell form (like GIC):
+ *   - <0 nr flags> - hwirq #nr
+ *   - <1 nr flags> - FIQ #nr
+ *     - nr=0  physical timer
+ *     - nr=1  virtual timer
+ *   - <2 nr flags> - IPI #nr
+ *     - nr=0  other IPI
+ *     - nr=1  self IPI
I think we should discuss the binding a bit here. My initial thinking was that
it would be better to separate the AIC from the FIQ handling, as they don't
seem to have any relation in hardware, and representing them as two
separate nodes seems like a cleaner abstraction.
This was actually my original approach (I still have the FIQ irqchip
patch lying around), but that idea somewhat broke when we decided to
merge the vectors.

If we split it up again, one of the two still needs to be the root,
decide whether what fired is an IRQ or FIQ, and dispatch accordingly. Or
we could have three nodes and have one root handler dispatch to IRQ and
FIQ nodes, but that sounds like overkill... (?)
Maybe I'm misreading the low-level entry code, but my impression
was that the fiq and irq exception vectors could just be pointed to
two different root drivers from the code in kernel_ventry
Are you proposing just having different drivers/nodes in the same file,
or implementing these as separate drivers in separate files?
I was thinking of separate driver files.
quoted
quoted
+#define TIMER_FIRING(x)                                                        \
+       (((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
+                ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
+        (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
+
+static void aic_handle_fiq(struct pt_regs *regs)
+{
+       /*
+        * It would be really nice to find a system register that lets us get the FIQ source
+        * state without having to peek down into clients...
+        */
+       if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_PHYS, regs);
+       }
+
+       if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) {
+               handle_domain_irq(aic_irqc->hw_domain,
+                                 aic_irqc->nr_hw + AIC_TMR_VIRT, regs);
+       }
+}
This seems to be a minor layering violation to me.
Absolutely. Under the assumption that these IRQ lines are ORed together
into FIQ with no top-level dispatch though, there isn't a great solution
here...

I think there is a chance FIQ interrupt child bits exist *somewhere*, so
I actually plan on brute-forcing the list of implemented/valid CPU
registers and trying to see if I can find some bits that do what I want.
If it turns out they exist, this could alleviate some of the ugliness of
the current approach.
Right, that would of course be ideal.
quoted
One idea I had was to just keep all the fiq handling in the timer driver
itself, jumping there directly from the top-level fiq entry whenever
we are on an Apple platform. At least as long as nothing else ever
uses fiq.
In principle, as long as the timer handler only ever uses one IRQ (which
I think is the case here, it just picks one of the 4, usually the
physical timer, and it should only enable that one) it would work. But
we still need *some* IRQ chip driver to deliver that, unless we want to
throw a bunch of special-case code into the timer driver to hook
directly into FIQs without an interrupt parent which... seems like it
could get quite messy.
I looked at other architectures, and found that at least powerpc
and sparc64 have a really minimal timer tick, with their timer_interrupt()
function getting called directly from the exception vector, and
doing a minimum of accounting (irq_enter(), statistics, ...) manually.

It's a different question if we want to do that, or if there should always
be an irqchip for consistency.
quoted
When we discussed the earlier submission for the aic, I understood
that FIQ is used for both timer and IPI, but the IPI actually has another
method based on normal AIC interrupts that can be used as an
alternative.
Correct, there are two parallel IPI implementations. It is my
understanding that the CPU register based one, which ties into FIQ, is
faster / more featureful (it has deferred IPIs, not sure if the plain
AIC does those), as it is built into the core complexes instead of being
part of the external AIC block. I could try benchmarking it within m1n1
and see if I can find out how much faster it is.
Benchmarking would at least help understand why there are two.

My best guess was that this is mostly an artifact of the XNU kernel
design, where it makes sense to split the timer and IPI that
you want to be handled by Mach kernel from the device irqs
that (I guess) would be handled by the BSD kernel.
I think it's worth thinking about supporting that IPI mechanism, which
would necessitate dispatching FIQs too, so hard-coding it to route
straight to the timer doesn't sound like a very future-proof plan...
consider that Apple might put out a SoC in the future that rips out the
AIC IPIs and leaves only the FIQ ones too.
I don't think we have to pay too much attention to preparing the
code design for it, we can always change it when needed. However,
anything that impacts the DT binding here would have to be designed
to not get in the way of adding it later.
quoted
quoted
+static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
+{
+       u64 isr = read_sysreg(isr_el1);
+
+       if (isr & PSR_F_BIT)
+               aic_handle_fiq(regs);
+
+       if (isr & PSR_I_BIT)
+               aic_handle_irq(regs);
+}
Having the shared entry point here looks reasonable to me though, it
does seem to make a few things easier.

I wonder if there is a possible race here: if we are ever in a situation
where one of the two -- fiq or irq -- is disabled while the other one
is enabled, we could get into a state where a handler is run while
it should be masked.
That's a good point. We could filter with the SPSR_ELx mask bits here.

Though the FIQ support patch tries pretty hard to keep the mask bits in
sync after early boot, so this concern might be somewhat academic. I'm
happy to implement it if you think it might help though.
It's probably fine as it is, just wanted to make sure you were not missing
something here.

        Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-04 23:09:40

On Thu, Feb 4, 2021 at 10:44 PM Hector Martin 'marcan' [off-list ref] wrote:
On 05/02/2021 06.29, Arnd Bergmann wrote:
quoted
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:

We tend to split the dts file into one file per SoC and one for the
specific board. I guess in this case the split can be slightly different,
but it does feel better to be prepared for sharing a lot of the contents
between the different products.

In most cases, you'd want the 'aliases' and 'chosen' nodes to be
in the board specific file.
I thought about that, but wasn't sure if splitting it up at this early
stage made much sense since I'm not sure what the split should be, given
all supported hardware is the same for all 3 released devices.

I'm happy to throw the aliases/chosen nodes into board specific files if
you think that's a good starting point. Perhaps /memory too? Those
properties are filled in/patched by the bootloader anyway...
Yes, I think that would help make it more consistent with other
platforms even if we don't care too much here.
There are also DT overlays; I was wondering if we could use those to
keep the hierarchy and avoid having many duplicate trees in a
hypothetical bootloader that embeds support for a large set of hardware,
having it construct the final devicetree on the fly from SoC + a board
overlay (and possibly further levels); but I'm not sure how that ties in
with the device trees that live in the Linux tree. Do you have any
pointers about this?
We don't really have overlays in the kernel sources (yet), though it
is something that keeps coming up. For the moment, I'd just
assume you can have one .dts file for each thing you want to
support and keep the shared bits in .dtsi files.
quoted
Did you see the discussion on the #armlinux channel about the possibility
of moving the cpu-enable method to PSCI based on a UEFI runtime
interface?
...
I saw it go by but need to review it again; I've been missing too much
sleep this week :) thanks for the reminder.

I think we might want to start with spin-table for now, given that there
are no kernel changes needed anyway, but I'm happy to take the protoype
for a spin (:)) and try implementing it in m1n1.

I do think it's valuable for whatever we do, at this stage, to not
require u-boot; having that be an integral part of the boot chain is
perfectly fine in the future but right now it helps to have a simple
boot chain while we work out the early bring-up, and while u-boot grows
the required support.
Agreed.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: kernel test robot <hidden>
Date: 2021-02-04 23:56:53

Hi Hector,

I love your patch! Perhaps something to improve:

[auto build test WARNING on arm64/for-next/core]
[also build test WARNING on robh/for-next linus/master v5.11-rc6 next-20210125]
[cannot apply to tip/irq/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/c3bf64138f141e20577083d30e0542004c194a20
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
        git checkout c3bf64138f141e20577083d30e0542004c194a20
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All warnings (new ones prefixed by >>):
quoted
drivers/tty/serial/samsung_tty.c:60: warning: "NO_IRQ" redefined
      60 | #define NO_IRQ -1
         | 
   In file included from arch/arm/include/asm/hardirq.h:5,
                    from include/linux/hardirq.h:10,
                    from include/linux/interrupt.h:11,
                    from include/linux/serial_core.h:13,
                    from drivers/tty/serial/samsung_tty.c:36:
   arch/arm/include/asm/irq.h:22: note: this is the location of the previous definition
      22 | #define NO_IRQ ((unsigned int)(-1))
         | 
   drivers/tty/serial/samsung_tty.c: In function 's3c24xx_serial_resume_noirq':
   drivers/tty/serial/samsung_tty.c:2309:4: error: a label can only be part of a statement and a declaration is not a statement
    2309 |    unsigned int ucon;
         |    ^~~~~~~~
   drivers/tty/serial/samsung_tty.c:2334:4: error: a label can only be part of a statement and a declaration is not a statement
    2334 |    unsigned int uintm = 0xf;
         |    ^~~~~~~~


vim +/NO_IRQ +60 drivers/tty/serial/samsung_tty.c

    58	
    59	/* IRQ number used when the handler is called in non-IRQ context */
  > 60	#define NO_IRQ -1
    61	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: kernel test robot <hidden>
Date: 2021-02-05 02:21:26

Hi Hector,

I love your patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on robh/for-next linus/master v5.11-rc6 next-20210125]
[cannot apply to tip/irq/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/c3bf64138f141e20577083d30e0542004c194a20
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
        git checkout c3bf64138f141e20577083d30e0542004c194a20
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All errors (new ones prefixed by >>):

   drivers/tty/serial/samsung_tty.c:60: warning: "NO_IRQ" redefined
      60 | #define NO_IRQ -1
         | 
   In file included from arch/arm/include/asm/hardirq.h:5,
                    from include/linux/hardirq.h:10,
                    from include/linux/interrupt.h:11,
                    from include/linux/serial_core.h:13,
                    from drivers/tty/serial/samsung_tty.c:36:
   arch/arm/include/asm/irq.h:22: note: this is the location of the previous definition
      22 | #define NO_IRQ ((unsigned int)(-1))
         | 
   drivers/tty/serial/samsung_tty.c: In function 's3c24xx_serial_resume_noirq':
quoted
drivers/tty/serial/samsung_tty.c:2309:4: error: a label can only be part of a statement and a declaration is not a statement
    2309 |    unsigned int ucon;
         |    ^~~~~~~~
   drivers/tty/serial/samsung_tty.c:2334:4: error: a label can only be part of a statement and a declaration is not a statement
    2334 |    unsigned int uintm = 0xf;
         |    ^~~~~~~~


vim +2309 drivers/tty/serial/samsung_tty.c

  2299	
  2300	static int s3c24xx_serial_resume_noirq(struct device *dev)
  2301	{
  2302		struct uart_port *port = s3c24xx_dev_to_port(dev);
  2303		struct s3c24xx_uart_port *ourport = to_ourport(port);
  2304	
  2305		if (port) {
  2306			/* restore IRQ mask */
  2307			switch (s3c24xx_irq_type(port)) {
  2308			case IRQ_APPLE:
2309				unsigned int ucon;
  2310	
  2311				clk_prepare_enable(ourport->clk);
  2312				if (!IS_ERR(ourport->baudclk))
  2313					clk_prepare_enable(ourport->baudclk);
  2314	
  2315				ucon = rd_regl(port, S3C2410_UCON);
  2316	
  2317				ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
  2318					APPLE_UCON_RXTHRESH_ENA_MSK |
  2319					APPLE_UCON_RXTO_ENA_MSK);
  2320	
  2321				if (ourport->tx_enabled)
  2322					ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
  2323				if (ourport->rx_enabled)
  2324					ucon |= APPLE_UCON_RXTHRESH_ENA_MSK |
  2325						APPLE_UCON_RXTO_ENA_MSK;
  2326	
  2327				wr_regl(port, S3C2410_UCON, ucon);
  2328	
  2329				if (!IS_ERR(ourport->baudclk))
  2330					clk_disable_unprepare(ourport->baudclk);
  2331				clk_disable_unprepare(ourport->clk);
  2332				break;
  2333			case IRQ_S3C6400:
  2334				unsigned int uintm = 0xf;
  2335	
  2336				if (ourport->tx_enabled)
  2337					uintm &= ~S3C64XX_UINTM_TXD_MSK;
  2338				if (ourport->rx_enabled)
  2339					uintm &= ~S3C64XX_UINTM_RXD_MSK;
  2340				clk_prepare_enable(ourport->clk);
  2341				if (!IS_ERR(ourport->baudclk))
  2342					clk_prepare_enable(ourport->baudclk);
  2343				wr_regl(port, S3C64XX_UINTM, uintm);
  2344				if (!IS_ERR(ourport->baudclk))
  2345					clk_disable_unprepare(ourport->baudclk);
  2346				clk_disable_unprepare(ourport->clk);
  2347				break;
  2348			}
  2349		}
  2350	
  2351		return 0;
  2352	}
  2353	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: kernel test robot <hidden>
Date: 2021-02-05 02:28:13

Hi Hector,

I love your patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on robh/for-next linus/master v5.11-rc6 next-20210125]
[cannot apply to tip/irq/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/01ec72727a358a6f4208bf56808f1ce57a251413
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hector-Martin/Apple-M1-SoC-platform-bring-up/20210205-045228
        git checkout 01ec72727a358a6f4208bf56808f1ce57a251413
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All errors (new ones prefixed by >>):
quoted
drivers/irqchip/irq-apple-aic.c:51:10: fatal error: asm/exception.h: No such file or directory
      51 | #include <asm/exception.h>
         |          ^~~~~~~~~~~~~~~~~
   compilation terminated.


vim +51 drivers/irqchip/irq-apple-aic.c

    43	
    44	#include <linux/io.h>
    45	#include <linux/irqchip.h>
    46	#include <linux/irqchip/chained_irq.h>
    47	#include <linux/of_address.h>
    48	#include <linux/of_irq.h>
    49	#include <linux/of_platform.h>
    50	#include <linux/slab.h>
  > 51	#include <asm/exception.h>
    52	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-05 07:14:49

On 05/02/2021 08.08, Arnd Bergmann wrote:
On Thu, Feb 4, 2021 at 10:44 PM Hector Martin 'marcan' [off-list ref] wrote:
quoted
On 05/02/2021 06.29, Arnd Bergmann wrote:
quoted
On Thu, Feb 4, 2021 at 9:39 PM Hector Martin [off-list ref] wrote:

We tend to split the dts file into one file per SoC and one for the
specific board. I guess in this case the split can be slightly different,
but it does feel better to be prepared for sharing a lot of the contents
between the different products.

In most cases, you'd want the 'aliases' and 'chosen' nodes to be
in the board specific file.
I thought about that, but wasn't sure if splitting it up at this early
stage made much sense since I'm not sure what the split should be, given
all supported hardware is the same for all 3 released devices.

I'm happy to throw the aliases/chosen nodes into board specific files if
you think that's a good starting point. Perhaps /memory too? Those
properties are filled in/patched by the bootloader anyway...
Yes, I think that would help make it more consistent with other
platforms even if we don't care too much here.
Ack, I'll split it up for v2.
We don't really have overlays in the kernel sources (yet), though it
is something that keeps coming up. For the moment, I'd just
assume you can have one .dts file for each thing you want to
support and keep the shared bits in .dtsi files.
No problem. We'll experiment with overlays in m1n1 and see how that goes.

One thing I wanted to ask: is there some kind of "experimental" policy 
for DT bindings? At early platform bring-up stages it seems like it 
could be valuable to allow for breaking DT changes while we flesh out 
the details (this is especially true of a reverse engineered platform 
like this, where we don't have knowledge of all the hardware details a 
priori). The dozen or so users we might have at this stage obviously 
won't complain too much :)

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-05 07:43:14

On 05/02/2021 08.04, Arnd Bergmann wrote:
On Thu, Feb 4, 2021 at 11:06 PM Hector Martin 'marcan' [off-list ref] wrote:
quoted
If we split it up again, one of the two still needs to be the root,
decide whether what fired is an IRQ or FIQ, and dispatch accordingly. Or
we could have three nodes and have one root handler dispatch to IRQ and
FIQ nodes, but that sounds like overkill... (?)
Maybe I'm misreading the low-level entry code, but my impression
was that the fiq and irq exception vectors could just be pointed to
two different root drivers from the code in kernel_ventry
Certainly, but we'd have to introduce a fiq handler global and duplicate 
the handler code; this is what was done in the previous submission, but 
I seem to recall someone (Marc?) mentioned it would be cleaner to just 
merge them into the single IRQ path and discriminate in the irqchip, 
which is what I did here.

I can certainly go with either solution; I don't have a strong 
preference here.

Advantages of split path:

* More orthogonal

Advantages of merged path:

* Minimizes common vector changes needed for a single platform
* Keeps FIQ/IRQ code common, so FIQs are less likely to be accidentally 
broken by people not testing on Apple platforms.

Unclear:

* Performance. Split path runs less code, merged path has lower icache 
pressure.
quoted
Are you proposing just having different drivers/nodes in the same file,
or implementing these as separate drivers in separate files?
I was thinking of separate driver files.
That's what I previously had then :)

If this is the way to go I can certainly go back to that.
I looked at other architectures, and found that at least powerpc
and sparc64 have a really minimal timer tick, with their timer_interrupt()
function getting called directly from the exception vector, and
doing a minimum of accounting (irq_enter(), statistics, ...) manually.

It's a different question if we want to do that, or if there should always
be an irqchip for consistency.
I think the issue here is that those platforms presumably have *one* 
timer hard wired to a specific exception vector (e.g. on PowerPC that's 
the decrementer). So, that setup is shared by all implementations in 
that platform.

But on ARM64, the architectural timer is supposed to go through an 
irqchip (GIC in normal platforms), it's just that here it ended up 
hard-wired to FIQ - though not alone, since fast IPIs are also there, so 
we can't treat it as a strict "timer vector" either.

So even if we could do this for Apple SoCs, it would be a non-standard 
setup, since every other ARM64 platform puts the timer behind an 
irqchip. Therefore, I think it makes sense to always go through an 
irqchip, rather than introduce a bypass for these SoCs.

Also worth noting that we have at least two functional hardware timers 
here (not sure if there are more, we run with HCR_EL2.E2H=1 in m1n1 
which maps the EL2 timer to be the EL1 timer; I'm not yet sure if 
setting that to 0 will expose extra HV timers or not) wired to the same 
FIQ. I confirmed that both the virtual and physical timers function 
independently in m1n1.

I did confirm there are no secure timers, which is expected given that 
there is no EL3 on these chips.
Benchmarking would at least help understand why there are two.
Well, they call them "Fast IPIs" so *presumably* they are faster, but 
we'll see :)
I don't think we have to pay too much attention to preparing the
code design for it, we can always change it when needed. However,
anything that impacts the DT binding here would have to be designed
to not get in the way of adding it later.
I think this shouldn't pose much of a problem, since IPIs aren't exposed 
in the DT anyway. As long as we decide how we're handling IRQs vs FIQs 
(one or two nodes/drivers), then either of them could take 
responsibility for handling IPIs depending on the platform. We should 
probably just add a "fast-ipi" property to both nodes on platforms that 
support that, so that the drivers can make the decision based on it. Or 
perhaps that should be done with different compatibles?

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-05 09:48:23

On 05/02/2021 08.55, kernel test robot wrote:
quoted
quoted
drivers/tty/serial/samsung_tty.c:60: warning: "NO_IRQ" redefined
       60 | #define NO_IRQ -1
Turns out arm (32) defines NO_IRQ. Replaced with NOT_IN_IRQ for v2.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-05 09:55:22

On 05/02/2021 11.27, kernel test robot wrote:
config: arc-allyesconfig (attached as .config)
This is never going to build on !ARM64 since it uses ARM64 registers, so 
removing COMPILE_TEST for v2.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-05 10:35:06

On Fri, Feb 5, 2021 at 8:41 AM Hector Martin 'marcan' [off-list ref] wrote:
On 05/02/2021 08.04, Arnd Bergmann wrote:
quoted
On Thu, Feb 4, 2021 at 11:06 PM Hector Martin 'marcan' [off-list ref] wrote:
quoted
If we split it up again, one of the two still needs to be the root,
decide whether what fired is an IRQ or FIQ, and dispatch accordingly. Or
we could have three nodes and have one root handler dispatch to IRQ and
FIQ nodes, but that sounds like overkill... (?)
Maybe I'm misreading the low-level entry code, but my impression
was that the fiq and irq exception vectors could just be pointed to
two different root drivers from the code in kernel_ventry
Certainly, but we'd have to introduce a fiq handler global and duplicate
the handler code; this is what was done in the previous submission, but
I seem to recall someone (Marc?) mentioned it would be cleaner to just
merge them into the single IRQ path and discriminate in the irqchip,
which is what I did here.

I can certainly go with either solution; I don't have a strong
preference here.

Advantages of split path:

* More orthogonal

Advantages of merged path:

* Minimizes common vector changes needed for a single platform
* Keeps FIQ/IRQ code common, so FIQs are less likely to be accidentally
broken by people not testing on Apple platforms.

Unclear:

* Performance. Split path runs less code, merged path has lower icache
pressure.
quoted
quoted
Are you proposing just having different drivers/nodes in the same file,
or implementing these as separate drivers in separate files?
I was thinking of separate driver files.
That's what I previously had then :)

If this is the way to go I can certainly go back to that.
Marc is the authority on this one. I would prefer the split code
path, in particular if we end up using the FIQ just for the timer,
but if Marc (or Thomas, or the arm64 maintainers) has another
preference, do whatever they say.
quoted
I looked at other architectures, and found that at least powerpc
and sparc64 have a really minimal timer tick, with their timer_interrupt()
function getting called directly from the exception vector, and
doing a minimum of accounting (irq_enter(), statistics, ...) manually.

It's a different question if we want to do that, or if there should always
be an irqchip for consistency.
I think the issue here is that those platforms presumably have *one*
timer hard wired to a specific exception vector (e.g. on PowerPC that's
the decrementer). So, that setup is shared by all implementations in
that platform.

But on ARM64, the architectural timer is supposed to go through an
irqchip (GIC in normal platforms), it's just that here it ended up
hard-wired to FIQ - though not alone, since fast IPIs are also there, so
we can't treat it as a strict "timer vector" either.

So even if we could do this for Apple SoCs, it would be a non-standard
setup, since every other ARM64 platform puts the timer behind an
irqchip. Therefore, I think it makes sense to always go through an
irqchip, rather than introduce a bypass for these SoCs.

Also worth noting that we have at least two functional hardware timers
here (not sure if there are more, we run with HCR_EL2.E2H=1 in m1n1
which maps the EL2 timer to be the EL1 timer; I'm not yet sure if
setting that to 0 will expose extra HV timers or not) wired to the same
FIQ. I confirmed that both the virtual and physical timers function
independently in m1n1.

I did confirm there are no secure timers, which is expected given that
there is no EL3 on these chips.
I think the simplest implementation would be for the top-level fiq
handler to default to whatever it does today (complain, I suppose),
but have the arch timer call set_handle_fiq() in order to redirect
it to a custom entry point that does the irq_enter() etc bits and
then calls arch_timer_handler_phys.

Whatever solution we pick will end up weird and ugly, so why not
pick the one that takes the least amount of code ;-)
I think this shouldn't pose much of a problem, since IPIs aren't exposed
in the DT anyway. As long as we decide how we're handling IRQs vs FIQs
(one or two nodes/drivers), then either of them could take
responsibility for handling IPIs depending on the platform. We should
probably just add a "fast-ipi" property to both nodes on platforms that
support that, so that the drivers can make the decision based on it. Or
perhaps that should be done with different compatibles?
If it gets modeled as a separate irqchip with a separate driver, I would
also use a different compatible string for the fiq. If it gets integrated
straight into the timer code, that would be a custom compatible string
for that timer.

        Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 00/18] Apple M1 SoC platform bring-up

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-05 11:38:26

On 05/02/2021 05.39, Hector Martin wrote:
This series brings up initial support for the Apple M1 SoC, used in the
2020 Mac Mini, MacBook Pro, and MacBook Air models.
Forgot to CC: a few folks involved in the previous related thread, 
sorry! Adding them here, hope everyone got the series via the MLs.

v2 will be CCed to everyone else too.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-05 12:45:30

On Fri, Feb 5, 2021 at 8:11 AM Hector Martin 'marcan' [off-list ref] wrote:
One thing I wanted to ask: is there some kind of "experimental" policy
for DT bindings? At early platform bring-up stages it seems like it
could be valuable to allow for breaking DT changes while we flesh out
the details (this is especially true of a reverse engineered platform
like this, where we don't have knowledge of all the hardware details a
priori). The dozen or so users we might have at this stage obviously
won't complain too much :)
We don't have a hard policy here, other than the obvious "never break
setups that users rely on". As you expected, this usually means that
I wouldn't complain if you change something in the initial versions
and there is a good reason for that change, it shouldn't be a problem.

An extreme example here is the omap platform that keeps making
incompatible dt changes as there is still ongoing work for removing
the remaining platform specific code in arch/arm/ and replacing it
with DT descriptions.

Once your port is fairly complete and there are users that rely on stability
of the bindings, I would expect all further changes to be compatible in
both ways, allowing old kernels with new dtbs and the other way round.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-06 13:17:00

Hi Hector,

On Thu, 04 Feb 2021 20:39:38 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
Apple SoCs are a distant descendant of Samsung designs and use yet
another variant of their UART style, with different interrupt handling.

In particular, this variant has the following differences with existing
ones:

* It includes a built-in interrupt controller with different registers,
  using only a single platform IRQ

* Internal interrupt sources are treated as edge-triggered, even though
  the IRQ output is level-triggered. This chiefly affects the TX IRQ
  path: the driver can no longer rely on the TX buffer empty IRQ
  immediately firing after TX is enabled, but instead must prime the
  FIFO with data directly.

Signed-off-by: Hector Martin <redacted>
---
 drivers/tty/serial/samsung_tty.c | 297 +++++++++++++++++++++++++++----
 include/linux/serial_s3c.h       |  16 ++
 include/uapi/linux/serial_core.h |   3 +
 3 files changed, 280 insertions(+), 36 deletions(-)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 8ae3e03fbd8c..6d812ba1b748 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -56,6 +56,9 @@
 /* flag to ignore all characters coming in */
 #define RXSTAT_DUMMY_READ (0x10000000)
 
+/* IRQ number used when the handler is called in non-IRQ context */
+#define NO_IRQ -1
+
 struct s3c24xx_uart_info {
 	char			*name;
 	unsigned int		type;
@@ -144,6 +147,14 @@ struct s3c24xx_uart_port {
 #endif
 };
 
+enum s3c24xx_irq_type {
+	IRQ_DISCRETE = 0,
+	IRQ_S3C6400 = 1,
+	IRQ_APPLE = 2,
+};
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
 /* conversion functions */
 
 #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev)
@@ -231,11 +242,20 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
 /*
  * s3c64xx and later SoC's include the interrupt mask and status registers in
  * the controller itself, unlike the s3c24xx SoC's which have these registers
- * in the interrupt controller. Check if the port type is s3c64xx or higher.
+ * in the interrupt controller. Apple SoCs use a different flavor of mask
+ * and status registers. This function returns the IRQ style to use.
  */
-static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+static int s3c24xx_irq_type(struct uart_port *port)
 {
-	return to_ourport(port)->info->type == PORT_S3C6400;
+	switch (to_ourport(port)->info->type) {
+	case PORT_S3C6400:
+		return IRQ_S3C6400;
+	case PORT_APPLE:
+		return IRQ_APPLE;
+	default:
+		return IRQ_DISCRETE;
+	}
+
nit: For ease of reviewing, it'd be good if you could split this patch
with introducing the S3C6400 and "discrete" support initially, and
only then add the new stuff.
quoted hunk
 }
 
 static void s3c24xx_serial_rx_enable(struct uart_port *port)
@@ -289,10 +309,17 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	if (!ourport->tx_enabled)
 		return;
 
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		s3c24xx_clear_bit(port, APPLE_UCON_TXTHRESH_ENA, S3C2410_UCON);
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
 		dmaengine_pause(dma->tx_chan);
@@ -315,8 +342,6 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	ourport->tx_mode = 0;
 }
 
-static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
-
 static void s3c24xx_serial_tx_dma_complete(void *args)
 {
 	struct s3c24xx_uart_port *ourport = args;
@@ -353,10 +378,17 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	u32 ucon;
 
 	/* Mask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		WARN_ON(1); // No DMA
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	/* Enable tx dma mode */
 	ucon = rd_regl(port, S3C2410_UCON);
@@ -369,6 +401,8 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	ourport->tx_mode = S3C24XX_TX_DMA;
 }
 
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id);
+
 static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 {
 	struct uart_port *port = &ourport->port;
@@ -383,16 +417,30 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 	ucon = rd_regl(port, S3C2410_UCON);
 	ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
 	ucon |= S3C64XX_UCON_TXMODE_CPU;
-	wr_regl(port,  S3C2410_UCON, ucon);
 
 	/* Unmask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
-		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
-				  S3C64XX_UINTM);
-	else
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
+		break;
+	case IRQ_S3C6400:
+		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
+		break;
+	default:
 		enable_irq(ourport->tx_irq);
+		break;
+	}
+
+	wr_regl(port,  S3C2410_UCON, ucon);
 
 	ourport->tx_mode = S3C24XX_TX_PIO;
+
+	/*
+	 * The Apple version only has edge triggered TX IRQs, so we need
+	 * to kick off the process by sending some characters here.
+	 */
+	if (s3c24xx_irq_type(port) == IRQ_APPLE)
+		s3c24xx_serial_tx_chars(NO_IRQ, ourport);
Instead of directly calling into the handler (which has its own
problems, see below), could you just tickle the interrupt status
register to make an interrupt pending and trigger an actual interrupt?
I have no idea whether the HW supports this kind of trick though.
quoted hunk
 }
 
 static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
@@ -513,11 +561,18 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
 
 	if (ourport->rx_enabled) {
 		dev_dbg(port->dev, "stopping rx\n");
-		if (s3c24xx_serial_has_interrupt_mask(port))
-			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
-					S3C64XX_UINTM);
-		else
-			disable_irq_nosync(ourport->rx_irq);
+		switch (s3c24xx_irq_type(port)) {
+		case IRQ_APPLE:
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+			break;
+		case IRQ_S3C6400:
+			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
+			break;
+		default:
+			disable_irq_nosync(ourport->tx_irq);
+			break;
+		}
 		ourport->rx_enabled = 0;
 	}
 	if (dma && dma->rx_chan) {
@@ -651,14 +706,18 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
 
 	/* set Rx mode to DMA mode */
 	ucon = rd_regl(port, S3C2410_UCON);
-	ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
-			S3C64XX_UCON_EMPTYINT_EN |
-			S3C64XX_UCON_DMASUS_EN |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_MASK);
-	ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_CPU;
+	ucon &= ~S3C64XX_UCON_RXMODE_MASK;
+	ucon |= S3C64XX_UCON_RXMODE_CPU;
+
+	/* Apple types use these bits for IRQ masks */
+	if (s3c24xx_irq_type(port) != IRQ_APPLE) {
+		ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+				S3C64XX_UCON_EMPTYINT_EN |
+				S3C64XX_UCON_DMASUS_EN |
+				S3C64XX_UCON_TIMEOUT_EN);
+		ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+				S3C64XX_UCON_TIMEOUT_EN;
+	}
 	wr_regl(port, S3C2410_UCON, ucon);
 
 	ourport->rx_mode = S3C24XX_RX_PIO;
@@ -831,7 +890,9 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 	unsigned long flags;
 	int count, dma_count = 0;
 
-	spin_lock_irqsave(&port->lock, flags);
+	/* Only lock if called from IRQ context */
+	if (irq != NO_IRQ)
+		spin_lock_irqsave(&port->lock, flags);
Isn't that actually dangerous? What prevents the interrupt from firing
right in the middle of this sequence and create havoc when called from
enable_tx_pio()? I fail to see what you gain with sidestepping the
locking.
quoted hunk
 
 	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
@@ -893,7 +954,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 		s3c24xx_serial_stop_tx(port);
 
 out:
-	spin_unlock_irqrestore(&port->lock, flags);
+	if (irq != NO_IRQ)
+		spin_unlock_irqrestore(&port->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -916,6 +978,26 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
 	return ret;
 }
 
+/* interrupt handler for Apple SoC's.*/
+static irqreturn_t apple_serial_handle_irq(int irq, void *id)
+{
+	struct s3c24xx_uart_port *ourport = id;
+	struct uart_port *port = &ourport->port;
+	unsigned int pend = rd_regl(port, S3C2410_UTRSTAT);
+	irqreturn_t ret = IRQ_HANDLED;
The default should be IRQ_NONE, otherwise the kernel cannot detect a
screaming spurious interrupt.
quoted hunk
+
+	if (pend & (APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO)) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO);
+		ret = s3c24xx_serial_rx_chars(irq, id);
+	}
+	if (pend & APPLE_UTRSTAT_TXTHRESH) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_TXTHRESH);
+		ret = s3c24xx_serial_tx_chars(irq, id);
+	}
+
+	return ret;
+}
+
 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
 	struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@ -1098,7 +1180,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
 	if (ourport->tx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->tx_irq, ourport);
 		ourport->tx_enabled = 0;
 		ourport->tx_claimed = 0;
@@ -1106,18 +1188,34 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	}
 
 	if (ourport->rx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->rx_irq, ourport);
 		ourport->rx_claimed = 0;
 		ourport->rx_enabled = 0;
 	}
 
 	/* Clear pending interrupts and mask all interrupts */
-	if (s3c24xx_serial_has_interrupt_mask(port)) {
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE: {
+		unsigned int ucon;
+
+		ucon = rd_regl(port, S3C2410_UCON);
+		ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTO_ENA_MSK);
+		wr_regl(port, S3C2410_UCON, ucon);
+
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+		free_irq(port->irq, ourport);
+		break;
+	}
+	case IRQ_S3C6400:
 		free_irq(port->irq, ourport);
 
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTM, 0xf);
+		break;
 	}
 
 	if (ourport->dma)
@@ -1215,6 +1313,47 @@ static int s3c64xx_serial_startup(struct uart_port *port)
 	return ret;
 }
 
+static int apple_serial_startup(struct uart_port *port)
+{
+	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	unsigned long flags;
+	unsigned int ufcon;
+	int ret;
+
+	wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
Why IRQF_SHARED? Do you expect any other device sharing the same line
with this UART?
quoted hunk
+	if (ret) {
+		dev_err(port->dev, "cannot get irq %d\n", port->irq);
+		return ret;
+	}
+
+	/* For compatibility with s3c24xx Soc's */
+	ourport->rx_enabled = 1;
+	ourport->rx_claimed = 1;
+	ourport->tx_enabled = 0;
+	ourport->tx_claimed = 1;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ufcon = rd_regl(port, S3C2410_UFCON);
+	ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+	if (!uart_console(port))
+		ufcon |= S3C2410_UFCON_RESETTX;
+	wr_regl(port, S3C2410_UFCON, ufcon);
+
+	enable_rx_pio(ourport);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Enable Rx Interrupt */
+	s3c24xx_set_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+	s3c24xx_set_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+
+	return ret;
+}
+
 /* power power management control */
 
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1544,6 +1683,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
 		return "S3C2412";
 	case PORT_S3C6400:
 		return "S3C6400/10";
+	case PORT_APPLE:
+		return "APPLE";
 	default:
 		return NULL;
 	}
@@ -1868,9 +2009,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 	/* setup info for port */
 	port->dev	= &platdev->dev;
 
+	switch (s3c24xx_irq_type(port)) {
+	/* Startup sequence is different for Apple SoC's */
+	case IRQ_APPLE:
+		s3c24xx_serial_ops.startup = apple_serial_startup;
+		break;
 	/* Startup sequence is different for s3c64xx and higher SoC's */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	case IRQ_S3C6400:
 		s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
+		break;
+	}
 
 	port->uartclk = 1;
 
@@ -1905,7 +2053,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 		ourport->tx_irq = ret + 1;
 	}
 
-	if (!s3c24xx_serial_has_interrupt_mask(port)) {
+	if (s3c24xx_irq_type(port) == IRQ_DISCRETE) {
 		ret = platform_get_irq(platdev, 1);
 		if (ret > 0)
 			ourport->tx_irq = ret;
@@ -1945,10 +2093,24 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 		pr_warn("uart: failed to enable baudclk\n");
 
 	/* Keep all interrupts masked and cleared */
-	if (s3c24xx_serial_has_interrupt_mask(port)) {
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE: {
+		unsigned int ucon;
+
+		ucon = rd_regl(port, S3C2410_UCON);
+		ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTO_ENA_MSK);
+		wr_regl(port, S3C2410_UCON, ucon);
+
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+		break;
+	}
+	case IRQ_S3C6400:
 		wr_regl(port, S3C64XX_UINTM, 0xf);
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTSP, 0xf);
+		break;
 	}
 
 	dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
@@ -2142,7 +2304,33 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
 
 	if (port) {
 		/* restore IRQ mask */
-		if (s3c24xx_serial_has_interrupt_mask(port)) {
+		switch (s3c24xx_irq_type(port)) {
+		case IRQ_APPLE:
+			unsigned int ucon;
+
+			clk_prepare_enable(ourport->clk);
+			if (!IS_ERR(ourport->baudclk))
+				clk_prepare_enable(ourport->baudclk);
+
+			ucon = rd_regl(port, S3C2410_UCON);
+
+			ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+				APPLE_UCON_RXTHRESH_ENA_MSK |
+				APPLE_UCON_RXTO_ENA_MSK);
+
+			if (ourport->tx_enabled)
+				ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
+			if (ourport->rx_enabled)
+				ucon |= APPLE_UCON_RXTHRESH_ENA_MSK |
+					APPLE_UCON_RXTO_ENA_MSK;
+
+			wr_regl(port, S3C2410_UCON, ucon);
+
+			if (!IS_ERR(ourport->baudclk))
+				clk_disable_unprepare(ourport->baudclk);
+			clk_disable_unprepare(ourport->clk);
+			break;
+		case IRQ_S3C6400:
 			unsigned int uintm = 0xf;
 
 			if (ourport->tx_enabled)
@@ -2156,6 +2344,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
 			if (!IS_ERR(ourport->baudclk))
 				clk_disable_unprepare(ourport->baudclk);
 			clk_disable_unprepare(ourport->clk);
+			break;
 		}
 	}
 
@@ -2556,6 +2745,34 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
 #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
 #endif
 
+#if defined(CONFIG_ARCH_APPLE)
+static struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
+	.info = &(struct s3c24xx_uart_info) {
+		.name		= "Apple S5L UART",
+		.type		= PORT_APPLE,
+		.fifosize	= 16,
+		.rx_fifomask	= S3C2410_UFSTAT_RXMASK,
+		.rx_fifoshift	= S3C2410_UFSTAT_RXSHIFT,
+		.rx_fifofull	= S3C2410_UFSTAT_RXFULL,
+		.tx_fifofull	= S3C2410_UFSTAT_TXFULL,
+		.tx_fifomask	= S3C2410_UFSTAT_TXMASK,
+		.tx_fifoshift	= S3C2410_UFSTAT_TXSHIFT,
+		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
+		.num_clks	= 1,
+		.clksel_mask	= 0,
+		.clksel_shift	= 0,
+	},
+	.def_cfg = &(struct s3c2410_uartcfg) {
+		.ucon		= APPLE_UCON_DEFAULT,
+		.ufcon		= S3C2410_UFCON_DEFAULT,
+	},
+};
+#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data)
+#else
+#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+
 static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
 	{
 		.name		= "s3c2410-uart",
@@ -2578,6 +2795,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
 	}, {
 		.name		= "exynos5433-uart",
 		.driver_data	= EXYNOS5433_SERIAL_DRV_DATA,
+	}, {
+		.name		= "s5l-uart",
+		.driver_data	= S5L_SERIAL_DRV_DATA,
 	},
 	{ },
 };
@@ -2599,6 +2819,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
 		.data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
 	{ .compatible = "samsung,exynos5433-uart",
 		.data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
+	{ .compatible = "AAPL,s5l-uart",
+		.data = (void *)S5L_SERIAL_DRV_DATA },
 	{},
 };
 MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
@@ -2694,6 +2916,9 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
 
 OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
 			s3c2410_early_console_setup);
+/* Apple SoCs are close enough to s3c2410 for earlycon */
+OF_EARLYCON_DECLARE(s5l, "AAPL,s5l-uart",
+			s3c2410_early_console_setup);
 
 /* S3C2412, S3C2440, S3C64xx */
 static struct samsung_early_console_data s3c2440_early_console_data = {
diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
index ca2c5393dc6b..377c8c6e5b97 100644
--- a/include/linux/serial_s3c.h
+++ b/include/linux/serial_s3c.h
@@ -246,6 +246,22 @@
 				 S5PV210_UFCON_TXTRIG4 |	\
 				 S5PV210_UFCON_RXTRIG4)
 
+
+#define APPLE_UCON_RXTO_ENA	9
+#define APPLE_UCON_RXTHRESH_ENA	12
+#define APPLE_UCON_TXTHRESH_ENA	13
+#define APPLE_UCON_RXTO_ENA_MSK		(1 << APPLE_UCON_RXTO_ENA)
+#define APPLE_UCON_RXTHRESH_ENA_MSK	(1 << APPLE_UCON_RXTHRESH_ENA)
+#define APPLE_UCON_TXTHRESH_ENA_MSK	(1 << APPLE_UCON_TXTHRESH_ENA)
+
+#define APPLE_UCON_DEFAULT	  S3C2410_UCON_RXFIFO_TOI
+
+#define APPLE_UTRSTAT_RXTHRESH	(1<<4)
+#define APPLE_UTRSTAT_TXTHRESH	(1<<5)
+#define APPLE_UTRSTAT_RXTO	(1<<9)
+#define APPLE_UTRSTAT_ALL_FLAGS	(0x3f0)
+
+
 #ifndef __ASSEMBLY__
 
 #include <linux/serial_core.h>
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 62c22045fe65..59d102b674db 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -277,4 +277,7 @@
 /* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART	122
 
+/* Apple Silicon (M1/T8103) UART (Samsung variant) */
+#define PORT_APPLE	123
+
Do you actually need a new port type here? Looking at the driver
itself, it is mainly used to work out the IRQ model. Maybe introducing
a new irq_type field in the port structure would be better than
exposing this to userspace (which should see something that is exactly
the same as a S3C UART).

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 04/18] arm64: Kconfig: Introduce CONFIG_ARCH_APPLE

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-06 13:18:46

Hi Hector,

On Thu, 04 Feb 2021 20:39:37 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
This adds a Kconfig option to toggle support for Apple ARM SoCs.
At this time this targets the M1 and later "Apple Silicon" Mac SoCs.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig.platforms | 7 +++++++
 1 file changed, 7 insertions(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 6eecdef538bd..e3e3bd2c4374 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -29,6 +29,13 @@ config ARCH_ALPINE
 	  This enables support for the Annapurna Labs Alpine
 	  Soc family.
 
+config ARCH_APPLE
+	bool "Apple Silicon SoC family"
+	select GENERIC_IRQ_CHIP
nit: This is better selected by the interrupt controller that relies
on the generic irqchip infrastructure.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 08/18] arm64: cpufeature: Add a feature for FIQ support

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-06 14:00:04

Hi Hector,

On Thu, 04 Feb 2021 20:39:41 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
Apple ARM SoCs (A11 and newer) have some interrupt sources hard-wired to
the FIQ line. Introduce a cpufeature that can be used to enable FIQ
unmasking and handling via alternatives.

This is currently enabled for all Apple CPUs. If/when support is
implemented for older (pre-A11) iPhone/iPad SoCs which do not need FIQs,
or if newer SoCs are released without the FIQ requirement, we can
revisit the condition.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig                  | 10 +++++++++
 arch/arm64/include/asm/cpucaps.h    |  3 ++-
 arch/arm64/include/asm/cpufeature.h |  6 ++++++
 arch/arm64/include/asm/cputype.h    |  1 +
 arch/arm64/kernel/cpufeature.c      | 32 +++++++++++++++++++++++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f39568b28ec1..11cfdc07404f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1756,6 +1756,16 @@ config ARM64_DEBUG_PRIORITY_MASKING
 	  If unsure, say N
 endif
 
+config ARM64_FIQ_SUPPORT
+	bool "Support for FIQ interrupts"
+	help
+	  Adds support for handling FIQ interrupts as normal IRQs.
+	  This is required on Apple platforms where some IRQ sources are
+	  hardwired to the FIQ interrupt line.
+
+	  FIQs are only enabled at runtime on platforms that require them
+	  via the CPU feature framework.
+
This definitely should be selected by CONFIG_ARCH_APPLE. Otherwise,
you can easily end-up with a non-working system.
quoted hunk
 config RELOCATABLE
 	bool "Build a relocatable kernel image" if EXPERT
 	select ARCH_HAS_RELR
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index b77d997b173b..c36d926ad801 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -66,7 +66,8 @@
 #define ARM64_WORKAROUND_1508412		58
 #define ARM64_HAS_LDAPR				59
 #define ARM64_KVM_PROTECTED_MODE		60
+#define ARM64_NEEDS_FIQ				61
 
-#define ARM64_NCAPS				61
+#define ARM64_NCAPS				62
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 9a555809b89c..3a00cfb347c9 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -716,6 +716,12 @@ static __always_inline bool system_uses_irq_prio_masking(void)
 	       cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
 }
 
+static __always_inline bool system_uses_fiqs(void)
nit: fiq, not fiqs.
quoted hunk
+{
+	return IS_ENABLED(CONFIG_ARM64_FIQ_SUPPORT) &&
+	       cpus_have_const_cap(ARM64_NEEDS_FIQ);
+}
+
 static inline bool system_supports_mte(void)
 {
 	return IS_ENABLED(CONFIG_ARM64_MTE) &&
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ef5b040dee44..2084a0340d16 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -59,6 +59,7 @@
 #define ARM_CPU_IMP_NVIDIA		0x4E
 #define ARM_CPU_IMP_FUJITSU		0x46
 #define ARM_CPU_IMP_HISI		0x48
+#define ARM_CPU_IMP_APPLE		0x61
 
 #define ARM_CPU_PART_AEM_V8		0xD0F
 #define ARM_CPU_PART_FOUNDATION		0xD00
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e99eddec0a46..0863cf7cf807 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1237,6 +1237,29 @@ static bool has_cache_idc(const struct arm64_cpu_capabilities *entry,
 	return ctr & BIT(CTR_IDC_SHIFT);
 }
 
+static void cpu_sync_irq_to_fiq(struct arm64_cpu_capabilities const *cap)
+{
+	u64 daif = read_sysreg(daif);
+
+	/*
+	 * By this point in the boot process IRQs are likely masked and FIOs
+	 * aren't, so we need to sync things to avoid spurious early FIQs.
+	 */
+
+	if (daif & PSR_I_BIT)
+		daif |= PSR_F_BIT;
+	else
+		daif &= ~PSR_F_BIT;
+
+	write_sysreg(daif, daif);
Could this happen too late? If, as explained above, we can get a FIQ
until we mask it here, what prevents something (a timer?) from kicking
and creating havoc just before the sync?

If the answer is "nothing", then it probably means that the default
behaviour should be to treat PSTATE.I and PSTATE.F as containing the
same value at all times, and not just as an afterthought when we
detect that we're on a CPU type or another.

This could expand into enabling Group-0 interrupts with GICv3 on
systems that have a single security state (such as virtual machines),
though I don't really see a good use case for it.
quoted hunk
+}
+
+static bool needs_fiq(const struct arm64_cpu_capabilities *entry, int __unused)
+{
+	/* All supported Apple cores need this */
+	return read_cpuid_implementor() == ARM_CPU_IMP_APPLE;
+}
+
 static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unused)
 {
 	/*
@@ -2154,6 +2177,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		.min_field_value = 1,
 	},
+#ifdef CONFIG_ARM64_FIQ_SUPPORT
+	{
+		.desc = "FIQs",
+		.capability = ARM64_NEEDS_FIQ,
+		.type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
+		.matches = needs_fiq,
+		.cpu_enable = cpu_sync_irq_to_fiq,
+	},
+#endif
 	{},
 };
Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-06 15:39:50

On Thu, 04 Feb 2021 20:39:43 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
Apple SoCs (A11 and newer) have some interrupt sources hardwired to the
FIQ line. Implement support for this by simply treating IRQs and FIQs
the same way in the interrupt vectors. This is conditional on the
ARM64_NEEDS_FIQ CPU feature flag, and thus will not affect other
systems.

Root irqchip drivers can discriminate between IRQs and FIQs by checking
the ISR_EL1 system register.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/include/asm/assembler.h |  4 ++++
 arch/arm64/include/asm/daifflags.h |  7 +++++++
 arch/arm64/include/asm/irqflags.h  | 17 +++++++++++++----
 arch/arm64/kernel/entry.S          | 27 +++++++++++++++++++++++----
 4 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index bf125c591116..6acfc372dc76 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -42,7 +42,11 @@
 
 	/* IRQ is the lowest priority flag, unconditionally unmask the rest. */
 	.macro enable_da_f
+alternative_if ARM64_NEEDS_FIQ
+	msr	daifclr, #(8 | 4)
+alternative_else
 	msr	daifclr, #(8 | 4 | 1)
+alternative_endif
See my digression in patch 8. I really wonder what the benefit is to
treat FIQ independently of IRQ, and we might as well generalise
this. We could always panic on getting a FIQ on platforms that don't
expect one.

It'd be good to rope in the other interested parties (Mark for the
early entry code, James for RAS and SError handling).
quoted hunk
 	.endm
 
 /*
diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
index 1c26d7baa67f..228a6039c701 100644
--- a/arch/arm64/include/asm/daifflags.h
+++ b/arch/arm64/include/asm/daifflags.h
@@ -112,6 +112,13 @@ static inline void local_daif_restore(unsigned long flags)
 		 * So we don't need additional synchronization here.
 		 */
 		gic_write_pmr(pmr);
+	} else if (system_uses_fiqs()) {
+		/*
+		 * On systems that use FIQs, disable FIQs if IRQs are disabled.
+		 * This can happen if the DAIF_* flags at the top of this file
+		 * are used to set DAIF directly.
+		 */
+		flags |= PSR_F_BIT;
 	}
 
 	write_sysreg(flags, daif);
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index ff328e5bbb75..689c573c4b47 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -19,8 +19,9 @@
  * side effects for other flags. Keeping to this order makes it easier for
  * entry.S to know which exceptions should be unmasked.
  *
- * FIQ is never expected, but we mask it when we disable debug exceptions, and
- * unmask it at all other times.
+ * FIQ is never expected on most platforms, but we mask it when we disable
+ * debug exceptions, and unmask it at all other times. On platforms that
+ * require FIQs, it tracks IRQ masking.
  */
 
 /*
@@ -34,8 +35,14 @@ static inline void arch_local_irq_enable(void)
 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
 	}
 
-	asm volatile(ALTERNATIVE(
+	/*
+	 * Yes, ALTERNATIVE() nests properly... only one of these should be
+	 * active on any given platform.
+	 */
+	asm volatile(ALTERNATIVE(ALTERNATIVE(
 		"msr	daifclr, #2		// arch_local_irq_enable",
+		"msr	daifclr, #3		// arch_local_irq_enable",
+		ARM64_NEEDS_FIQ),
Err... no. Please. It may be a cool hack, but that's an unmaintainable
one in the long run. If you *really* have to have a special case here,
consider using a callback instead, and generate the right instruction
directly.
quoted hunk
 		__msr_s(SYS_ICC_PMR_EL1, "%0"),
 		ARM64_HAS_IRQ_PRIO_MASKING)
 		:
@@ -53,8 +60,10 @@ static inline void arch_local_irq_disable(void)
 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
 	}
 
-	asm volatile(ALTERNATIVE(
+	asm volatile(ALTERNATIVE(ALTERNATIVE(
 		"msr	daifset, #2		// arch_local_irq_disable",
+		"msr	daifset, #3		// arch_local_irq_disable",
+		ARM64_NEEDS_FIQ),
 		__msr_s(SYS_ICC_PMR_EL1, "%0"),
 		ARM64_HAS_IRQ_PRIO_MASKING)
 		:
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index c9bae73f2621..81ca04ebe37b 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -60,7 +60,7 @@
 #define BAD_FIQ		2
 #define BAD_ERROR	3
 
-	.macro kernel_ventry, el, label, regsize = 64
+	.macro kernel_ventry, el, label, regsize = 64, altlabel = 0, alt = 0
 	.align 7
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 	.if	\el == 0
@@ -87,7 +87,15 @@ alternative_else_nop_endif
 	tbnz	x0, #THREAD_SHIFT, 0f
 	sub	x0, sp, x0			// x0'' = sp' - x0' = (sp + x0) - sp = x0
 	sub	sp, sp, x0			// sp'' = sp' - x0 = (sp + x0) - x0 = sp
+	.if	\altlabel != 0
+	alternative_if \alt
+	b	el\()\el\()_\altlabel
+	alternative_else
 	b	el\()\el\()_\label
+	alternative_endif
+	.else
+	b	el\()\el\()_\label
+	.endif
 
 0:
 	/*
@@ -119,7 +127,15 @@ alternative_else_nop_endif
 	sub	sp, sp, x0
 	mrs	x0, tpidrro_el0
 #endif
+	.if	\altlabel != 0
+	alternative_if \alt
+	b	el\()\el\()_\altlabel
+	alternative_else
 	b	el\()\el\()_\label
+	alternative_endif
+	.else
+	b	el\()\el\()_\label
+	.endif
 	.endm
 
 	.macro tramp_alias, dst, sym
@@ -547,18 +563,21 @@ SYM_CODE_START(vectors)
 
 	kernel_ventry	1, sync				// Synchronous EL1h
 	kernel_ventry	1, irq				// IRQ EL1h
-	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+							// FIQ EL1h
+	kernel_ventry	1, fiq_invalid, 64, irq, ARM64_NEEDS_FIQ
It could be better to create a set of first class FIQ handlers rather
than this alternative target macro. I quickly hacked this instead,
which I find more readable.

Thanks,

	M.
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index a8c3e7aaca74..dc65b56626ab 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -547,18 +547,18 @@ SYM_CODE_START(vectors)
 
 	kernel_ventry	1, sync				// Synchronous EL1h
 	kernel_ventry	1, irq				// IRQ EL1h
-	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+	kernel_ventry	1, fiq				// FIQ EL1h
 	kernel_ventry	1, error			// Error EL1h
 
 	kernel_ventry	0, sync				// Synchronous 64-bit EL0
 	kernel_ventry	0, irq				// IRQ 64-bit EL0
-	kernel_ventry	0, fiq_invalid			// FIQ 64-bit EL0
+	kernel_ventry	0, fiq				// FIQ 64-bit EL0
 	kernel_ventry	0, error			// Error 64-bit EL0
 
 #ifdef CONFIG_COMPAT
 	kernel_ventry	0, sync_compat, 32		// Synchronous 32-bit EL0
 	kernel_ventry	0, irq_compat, 32		// IRQ 32-bit EL0
-	kernel_ventry	0, fiq_invalid_compat, 32	// FIQ 32-bit EL0
+	kernel_ventry	0, fiq, 32			// FIQ 32-bit EL0
 	kernel_ventry	0, error_compat, 32		// Error 32-bit EL0
 #else
 	kernel_ventry	0, sync_invalid, 32		// Synchronous 32-bit EL0
@@ -658,6 +658,10 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_sync)
 SYM_CODE_END(el1_sync)
 
 	.align	6
+SYM_CODE_START_LOCAL_NOALIGN(el1_fiq)
+alternative_if_not ARM64_NEEDS_FIQ
+	b	el1_fiq_invalid
+alternative_else_nop_endif
 SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
 	kernel_entry 1
 	gic_prio_irq_setup pmr=x20, tmp=x1
@@ -688,6 +692,7 @@ alternative_else_nop_endif
 
 	kernel_exit 1
 SYM_CODE_END(el1_irq)
+SYM_CODE_END(el1_fiq)
 
 /*
  * EL0 mode handlers.
@@ -710,10 +715,15 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_sync_compat)
 SYM_CODE_END(el0_sync_compat)
 
 	.align	6
+SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat)
+alternative_if_not ARM64_NEEDS_FIQ
+	b	el0_fiq_invalid
+alternative_else_nop_endif
 SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
 	kernel_entry 0, 32
 	b	el0_irq_naked
 SYM_CODE_END(el0_irq_compat)
+SYM_CODE_END(el0_fiq_compat)
 
 SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
 	kernel_entry 0, 32
@@ -722,6 +732,10 @@ SYM_CODE_END(el0_error_compat)
 #endif
 
 	.align	6
+SYM_CODE_START_LOCAL_NOALIGN(el0_fiq)
+alternative_if_not ARM64_NEEDS_FIQ
+	b	el0_fiq_invalid
+alternative_else_nop_endif
 SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
 	kernel_entry 0
 el0_irq_naked:
@@ -736,6 +750,7 @@ el0_irq_naked:
 
 	b	ret_to_user
 SYM_CODE_END(el0_irq)
+SYM_CODE_END(el0_fiq)
 
 SYM_CODE_START_LOCAL(el1_error)
 	kernel_entry 1

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 11/18] arm64: Kconfig: Require FIQ support for ARCH_APPLE

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-06 15:47:22

On Thu, 04 Feb 2021 20:39:44 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
All currently supported Apple ARM SoCs (and possibly all future ones
too) require FIQs.

Signed-off-by: Hector Martin <redacted>
---
 arch/arm64/Kconfig.platforms | 1 +
 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index e3e3bd2c4374..8182d78e8e23 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -32,6 +32,7 @@ config ARCH_ALPINE
 config ARCH_APPLE
 	bool "Apple Silicon SoC family"
 	select GENERIC_IRQ_CHIP
+	select ARM64_FIQ_SUPPORT
Ah, this is what I was expecting in the previous patch. I guess the
initial ARCH_APPLE patch could be moved down the line and add all the
dependencies in one go.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-06 16:24:03

On Sat, Feb 6, 2021 at 4:37 PM Marc Zyngier [off-list ref] wrote:
On Thu, 04 Feb 2021 20:39:43 +0000, Hector Martin [off-list ref] wrote:
quoted
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index bf125c591116..6acfc372dc76 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -42,7 +42,11 @@

      /* IRQ is the lowest priority flag, unconditionally unmask the rest. */
      .macro enable_da_f
+alternative_if ARM64_NEEDS_FIQ
+     msr     daifclr, #(8 | 4)
+alternative_else
      msr     daifclr, #(8 | 4 | 1)
+alternative_endif
See my digression in patch 8. I really wonder what the benefit is to
treat FIQ independently of IRQ, and we might as well generalise
this. We could always panic on getting a FIQ on platforms that don't
expect one.

It'd be good to rope in the other interested parties (Mark for the
early entry code, James for RAS and SError handling).
There might be another slightly hacky but less intrusive option
that could be done (almost) purely within the aic code:

* In the fiq handler code, check if normal interrupts were enabled
  when the fiq hit. Normally they are enabled, so just proceed to
  handle the timer and ipi directly

* if irq was disabled, defer the handling by doing a self-ipi
  through the aic's ipi method, and handle it from there
  when dealing with the next interrupt once interrupts get
  enabled.

This would be similar to the soft-disable feature on powerpc, which
never actually turns off interrupts from regular kernel code but
just checks a flag in local_irq_enable that gets set when a
hardirq happened.

          Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 04/18] arm64: Kconfig: Introduce CONFIG_ARCH_APPLE

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 08:06:22

On 06/02/2021 22.17, Marc Zyngier wrote:
quoted
+config ARCH_APPLE
+	bool "Apple Silicon SoC family"
+	select GENERIC_IRQ_CHIP
nit: This is better selected by the interrupt controller that relies
on the generic irqchip infrastructure.
Ack, changed for v2.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 08/18] arm64: cpufeature: Add a feature for FIQ support

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 08:33:38

On 06/02/2021 22.58, Marc Zyngier wrote:
Hector Martin [off-list ref] wrote:
quoted
+static void cpu_sync_irq_to_fiq(struct arm64_cpu_capabilities const *cap)
+{
+	u64 daif = read_sysreg(daif);
+
+	/*
+	 * By this point in the boot process IRQs are likely masked and FIOs
+	 * aren't, so we need to sync things to avoid spurious early FIQs.
+	 */
+
+	if (daif & PSR_I_BIT)
+		daif |= PSR_F_BIT;
+	else
+		daif &= ~PSR_F_BIT;
+
+	write_sysreg(daif, daif);
Could this happen too late? If, as explained above, we can get a FIQ
until we mask it here, what prevents something (a timer?) from kicking
and creating havoc just before the sync?
Nothing, other than timers not being enabled this early (hopefully the 
bootloader doesn't leave a rogue timer running for us...)
If the answer is "nothing", then it probably means that the default
behaviour should be to treat PSTATE.I and PSTATE.F as containing the
same value at all times, and not just as an afterthought when we
detect that we're on a CPU type or another.
I thought of this too. Originally I thought PSTATE.F was always set on 
other systems, and thus unmasking FIQs could cause problems if there is 
a pending rogue FIQ for some reason. However, while writing this patch I 
realized that as part of normal process state changes we already unmask 
FIQs anyway (see DAIF_PROCCTX).

Thus, in fact, this patch actually changes things (when the cpufeature 
is set) to mask FIQs in some cases where they currently aren't, and 
conversely to unmask them in some cases where they currently are. But 
the fact that FIQ masking is somewhat inconsistent to begin with 
suggests that we should be able to mess with it without causing breakage 
for other systems.

So I guess in this case it would be legitimate to just make I==F on 
every system, and if something breaks it should be fixed by making 
whatever is causing a rogue FIQ not do that, right?

That would leave the vector switcheroo as the only thing the cpufeature 
does, which would certainly simplify a lot of the patch.
This could expand into enabling Group-0 interrupts with GICv3 on
systems that have a single security state (such as virtual machines),
though I don't really see a good use case for it.
I could see having a separate vector path opening up the door for 
performance hacks for very specific use cases that want really low 
latency for *one* thing (e.g. the mess the Raspberry Pi folks do to work 
around that braindead USB controller's performance issues), though I 
imagine there would have to be very compelling reasons to develop a 
framework to do this sanely upstream.

Incidentally, I have a personal interest in real-time performance 
(especially audio); once the dust settles and we have a workable kernel 
for normal use I do hope to spend some time taking a deep dive into 
latencies and finding RT-unfriendly code, but that's pretty far off 
right now. Maybe PREEMPT_RT will even be merged by then :-) (I hope that 
without SMM to screw things up on these machines they might make very 
nice RT-capable boxes...)

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 08:38:27

On 07/02/2021 01.22, Arnd Bergmann wrote:
* In the fiq handler code, check if normal interrupts were enabled
   when the fiq hit. Normally they are enabled, so just proceed to
   handle the timer and ipi directly

* if irq was disabled, defer the handling by doing a self-ipi
   through the aic's ipi method, and handle it from there
   when dealing with the next interrupt once interrupts get
   enabled.

This would be similar to the soft-disable feature on powerpc, which
never actually turns off interrupts from regular kernel code but
just checks a flag in local_irq_enable that gets set when a
hardirq happened.
Case #2 seems messy. In AIC, we'd have to either:

* Disable FIQs, and hope that doesn't confuse any save/restore code 
going on, then set a flag and check it in *both* the IRQ and FIQ path 
since either might trigger depending on what happens next, or
* Mask the relevant timer, which we'd then need to make sure does not 
confuse the timer code (Unmask it again when we fire the interrupt? But 
what if the timer code intended to mask it in the interim?)

Neither sounds particularly clean to me... if we had FIQ status masking 
registers this would be more reasonable, but I'm not sure I'd want the 
AIC driver to mess with neither DAIF nor the timer registers. It's bad 
enough that it has to read the latter already (and I hope I can find a 
better way of doing that...).

Plus I don't know if the vector entry code and other scaffolding between 
the vector and the AIC driver would be happy with, effectively, 
recursive interrupts. This could work with a carefully controlled path 
to make sure it doesn't break things, but I'm not so sure about the 
current "just point FIQ and IRQ to the same place" approach here.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 08:48:40

On 07/02/2021 00.37, Marc Zyngier wrote:
See my digression in patch 8. I really wonder what the benefit is to
treat FIQ independently of IRQ, and we might as well generalise
this. We could always panic on getting a FIQ on platforms that don't
expect one.

It'd be good to rope in the other interested parties (Mark for the
early entry code, James for RAS and SError handling).
CCing Mark and James: TL;DR what do you think about unconditionally 
keeping DAIF.I == DAIF.F, would this break other platforms with spurious 
FIQs or conversely mask FIQs when we don't want to in some cases? The 
FIQ vector would remain a panic except on platforms that require using 
it, via an alternatives patch.
quoted
  	kernel_ventry	1, sync				// Synchronous EL1h
  	kernel_ventry	1, irq				// IRQ EL1h
-	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+							// FIQ EL1h
+	kernel_ventry	1, fiq_invalid, 64, irq, ARM64_NEEDS_FIQ
It could be better to create a set of first class FIQ handlers rather
than this alternative target macro. I quickly hacked this instead,
which I find more readable.
I think I ended up with the macro change to keep it 1:1 with IRQ, vs a 
separate branch... but I didn't think of the fallthrough-with-nop trick, 
neat. It is definitely is more readable. Are you OK with me pulling this 
patch in for v2, with your name on it?
-	kernel_ventry	0, fiq_invalid_compat, 32	// FIQ 32-bit EL0
+	kernel_ventry	0, fiq, 32			// FIQ 32-bit EL0
fiq_compat here, right?

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 09:13:18

On 06/02/2021 22.15, Marc Zyngier wrote:
quoted
-static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+static int s3c24xx_irq_type(struct uart_port *port)
  {
-	return to_ourport(port)->info->type == PORT_S3C6400;
+	switch (to_ourport(port)->info->type) {
+	case PORT_S3C6400:
+		return IRQ_S3C6400;
+	case PORT_APPLE:
+		return IRQ_APPLE;
+	default:
+		return IRQ_DISCRETE;
+	}
+
nit: For ease of reviewing, it'd be good if you could split this patch
with introducing the S3C6400 and "discrete" support initially, and
only then add the new stuff.
Good idea, will do for v2.
quoted
+	if (s3c24xx_irq_type(port) == IRQ_APPLE)
+		s3c24xx_serial_tx_chars(NO_IRQ, ourport);
Instead of directly calling into the handler (which has its own
problems, see below), could you just tickle the interrupt status
register to make an interrupt pending and trigger an actual interrupt?
I have no idea whether the HW supports this kind of trick though.
I thought of that, but I tried really hard to find such a feature with 
no success. The best I can do is unmask and trigger the *RX* timeout 
interrupt which will eventually fire but... this doesn't work so well in 
practice. There is no way to trigger IRQ flags directly (as those bits 
are write-1-to-clear).
quoted
-	spin_lock_irqsave(&port->lock, flags);
+	/* Only lock if called from IRQ context */
+	if (irq != NO_IRQ)
+		spin_lock_irqsave(&port->lock, flags);
Isn't that actually dangerous? What prevents the interrupt from firing
right in the middle of this sequence and create havoc when called from
enable_tx_pio()? I fail to see what you gain with sidestepping the
locking.
The callpath here is:

uart_start -> __uart_start -> (uart_ops.start_tx) 
s3c24xx_serial_start_tx -> s3c24xx_serial_start_tx_pio -> enable_tx_pio 
-> s3c24xx_serial_tx_chars

And uart_start takes the uart_port lock. None of the serial functions 
take the lock because the serial core already does, but obviously the 
IRQ handler needs to, *if* it's called as an IRQ handler only.
The default should be IRQ_NONE, otherwise the kernel cannot detect a
screaming spurious interrupt.
Good point, and this needs fixing in s3c64xx_serial_handle_irq too then 
(which is what I based mine off of).
quoted
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
Why IRQF_SHARED? Do you expect any other device sharing the same line
with this UART?
This also came from s3c64xx_serial_startup and... now I wonder why that 
one needs it. Maybe on some SoCs it does get shared? Certainly not for 
discrete rx/tx irq chips (and indeed those don't set the flag)...

CCing Thomas, who added the S3C64xx support (and should probably review 
this patch); is there a reason for IRQF_SHARED there? NB: v1 breaks the 
build on arm or with CONFIG_PM_SLEEP, those will be fixed for v2.

Either way, certainly not for Apple SoCs; I'll get rid of IRQF_SHARED 
for v2.
quoted
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 62c22045fe65..59d102b674db 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -277,4 +277,7 @@
  /* Freescale LINFlexD UART */
  #define PORT_LINFLEXUART	122
  
+/* Apple Silicon (M1/T8103) UART (Samsung variant) */
+#define PORT_APPLE	123
+
Do you actually need a new port type here? Looking at the driver
itself, it is mainly used to work out the IRQ model. Maybe introducing
a new irq_type field in the port structure would be better than
exposing this to userspace (which should see something that is exactly
the same as a S3C UART).
Well... every S3C variant already has its own port type here.

#define PORT_S3C2410    55
#define PORT_S3C2440    61
#define PORT_S3C2400    67
#define PORT_S3C2412    73
#define PORT_S3C6400    84

If we don't introduce a new one, which one should we pretend to be? :)

I agree that it might make sense to merge all of these into one, though; 
I don't know what the original reason for splitting them out is. But now 
that they're part of the userspace API, this might not be a good idea. 
Though, unsurprisingly, some googling suggests there are zero users of 
these defines in userspace.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 11/18] arm64: Kconfig: Require FIQ support for ARCH_APPLE

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 09:24:41

On 07/02/2021 00.46, Marc Zyngier wrote:
quoted
  config ARCH_APPLE
  	bool "Apple Silicon SoC family"
  	select GENERIC_IRQ_CHIP
+	select ARM64_FIQ_SUPPORT
Ah, this is what I was expecting in the previous patch. I guess the
initial ARCH_APPLE patch could be moved down the line and add all the
dependencies in one go.
I was trying to introduce the Kconfig before the code that depends on 
it; is it kosher to have it in the other order, looking for CONFIG_ 
defines that don't exist yet?

Though in this case the only user earlier in the series is the Samsung 
stuff, which doesn't care about FIQs, so I can just sort things as 
FIQ->ARCH_APPLE->samsung->AIC...

I'm not sure about AIC vs. ARCH_APPLE though. Right now the pattern is 
that AIC depends on ARCH_APPLE and also defaults to that. But then you 
can build with ARCH_APPLE and AIC disabled if you so choose, which does 
result in a broken system on these machines. AIC should build without 
ARCH_APPLE (as long as we're on ARM64), so we could reverse that.

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 09:28:03

On 07/02/2021 18.12, Hector Martin 'marcan' wrote:
On 06/02/2021 22.15, Marc Zyngier wrote:
quoted
The default should be IRQ_NONE, otherwise the kernel cannot detect a
screaming spurious interrupt.
Good point, and this needs fixing in s3c64xx_serial_handle_irq too then
(which is what I based mine off of).
quoted
quoted
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
Why IRQF_SHARED? Do you expect any other device sharing the same line
with this UART?
This also came from s3c64xx_serial_startup and... now I wonder why that
one needs it. Maybe on some SoCs it does get shared? Certainly not for
discrete rx/tx irq chips (and indeed those don't set the flag)...

CCing Thomas, who added the S3C64xx support (and should probably review
this patch); is there a reason for IRQF_SHARED there? NB: v1 breaks the
build on arm or with CONFIG_PM_SLEEP, those will be fixed for v2.
Seems Thomas does not work for Linaro any more :)

CCing Krzysztof instead, who is the Samsung arch maintainer.
Either way, certainly not for Apple SoCs; I'll get rid of IRQF_SHARED
for v2.
-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-07 12:26:39

On Sun, Feb 7, 2021 at 9:36 AM Hector Martin 'marcan' [off-list ref] wrote:
On 07/02/2021 01.22, Arnd Bergmann wrote:
quoted
* In the fiq handler code, check if normal interrupts were enabled
   when the fiq hit. Normally they are enabled, so just proceed to
   handle the timer and ipi directly

* if irq was disabled, defer the handling by doing a self-ipi
   through the aic's ipi method, and handle it from there
   when dealing with the next interrupt once interrupts get
   enabled.

This would be similar to the soft-disable feature on powerpc, which
never actually turns off interrupts from regular kernel code but
just checks a flag in local_irq_enable that gets set when a
hardirq happened.
Case #2 seems messy. In AIC, we'd have to either:

* Disable FIQs, and hope that doesn't confuse any save/restore code
going on, then set a flag and check it in *both* the IRQ and FIQ path
since either might trigger depending on what happens next, or
* Mask the relevant timer, which we'd then need to make sure does not
confuse the timer code (Unmask it again when we fire the interrupt? But
what if the timer code intended to mask it in the interim?)
I'm not quite following here. The IRQ should be disabled the entire time
while handling that self-IPI and the timer top half code, so if we get
another FIQ while handling the timer from the IRQ path, it will lead
either yet another self-IPI or it will be ignored in case the previous timer
event has not been Acked yet. I would expect that both cases are
race-free here, the only time that the FIQ needs to be disabled is
while actually handling the FIQ. Did I miss something?
Plus I don't know if the vector entry code and other scaffolding between
the vector and the AIC driver would be happy with, effectively,
recursive interrupts. This could work with a carefully controlled path
to make sure it doesn't break things, but I'm not so sure about the
current "just point FIQ and IRQ to the same place" approach here.
If we do what I described above, the FIQ and IRQ entry would have
to be separate and only arrive in the same code path when calling
into drivers/clocksource/arm_arch_timer.c. It's not recursive there
because that part is only called when IRQ is disabled, and no IRQ
is being executed while the FIQ hits.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-07 15:39:42

On 07/02/2021 21.25, Arnd Bergmann wrote:
On Sun, Feb 7, 2021 at 9:36 AM Hector Martin 'marcan' [off-list ref] wrote:
quoted
On 07/02/2021 01.22, Arnd Bergmann wrote:
quoted
* In the fiq handler code, check if normal interrupts were enabled
    when the fiq hit. Normally they are enabled, so just proceed to
    handle the timer and ipi directly

* if irq was disabled, defer the handling by doing a self-ipi
    through the aic's ipi method, and handle it from there
    when dealing with the next interrupt once interrupts get
    enabled.

This would be similar to the soft-disable feature on powerpc, which
never actually turns off interrupts from regular kernel code but
just checks a flag in local_irq_enable that gets set when a
hardirq happened.
Case #2 seems messy. In AIC, we'd have to either:

* Disable FIQs, and hope that doesn't confuse any save/restore code
going on, then set a flag and check it in *both* the IRQ and FIQ path
since either might trigger depending on what happens next, or
* Mask the relevant timer, which we'd then need to make sure does not
confuse the timer code (Unmask it again when we fire the interrupt? But
what if the timer code intended to mask it in the interim?)
I'm not quite following here. The IRQ should be disabled the entire time
while handling that self-IPI and the timer top half code, so if we get
another FIQ while handling the timer from the IRQ path, it will lead
either yet another self-IPI or it will be ignored in case the previous timer
event has not been Acked yet. I would expect that both cases are
race-free here, the only time that the FIQ needs to be disabled is
while actually handling the FIQ. Did I miss something?
FIQs are level-triggered, and there are only two* ways of masking them 
(that we know of): in the timer, or DAIF. That means that if we get a 
FIQ, we *must* do one of two things: either mask it in the timer 
register, or mask FIQs entirely. If we do neither of these, we get a FIQ 
storm.

So if a timer FIQ fires while IRQs are disabled, and we can't call into 
the timer code (because IRQs were disabled, so we need to defer handling 
via the IPI), the only other options are to either poke the timer mask 
bit directly, or to mask FIQs. Neither seems particularly correct.

* An exception seems to be non-HV timer interrupts firing while we have 
a VM guest running (HCR_EL2.TGE=0). This causes a single FIQ, and no 
more, which suggests there is a mask bit for guest timer FIQs somewhere 
that gets automatically set when the FIQ is delivered to the CPU core. 
I've yet to find where this bit lives, I'll be doing a brute force sweep 
of system register space soon to see if I can find it, and if there is 
anything else useful near it.
quoted
Plus I don't know if the vector entry code and other scaffolding between
the vector and the AIC driver would be happy with, effectively,
recursive interrupts. This could work with a carefully controlled path
to make sure it doesn't break things, but I'm not so sure about the
current "just point FIQ and IRQ to the same place" approach here.
If we do what I described above, the FIQ and IRQ entry would have
to be separate and only arrive in the same code path when calling
into drivers/clocksource/arm_arch_timer.c. It's not recursive there
because that part is only called when IRQ is disabled, and no IRQ
is being executed while the FIQ hits.
Right, that's what i'm saying; we can't re-use the IRQ handler like Marc 
proposed, because I don't think that expects to be called reentrantly; 
we'd have to have a separate FIQ entry, but since it can be called with 
IRQs enabled and handle the FIQ in-line, it also needs to be able to 
*conditionally* behave like a normal IRQ handler. This level of 
complexity seems somewhat dubious, just to not maintain the FIQ mask bit 
synced. That's not just AIC code any more, it needs a bespoke FIQ vector 
and logic to decide whether IRQs are masked (call AIC to self-IPI 
without doing the usual IRQ processing) or unmasked (go through regular 
IRQ accounting and behave like an IRQ).

Perhaps I'm misunderstanding what you're proposing here or how this 
would work :)

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-07 18:51:30

On Sun, Feb 7, 2021 at 4:40 PM Hector Martin 'marcan' [off-list ref] wrote:
On 07/02/2021 21.25, Arnd Bergmann wrote:
quoted
On Sun, Feb 7, 2021 at 9:36 AM Hector Martin 'marcan' [off-list ref] wrote:
quoted
On 07/02/2021 01.22, Arnd Bergmann wrote:
quoted
* In the fiq handler code, check if normal interrupts were enabled
    when the fiq hit. Normally they are enabled, so just proceed to
    handle the timer and ipi directly

* if irq was disabled, defer the handling by doing a self-ipi
    through the aic's ipi method, and handle it from there
    when dealing with the next interrupt once interrupts get
    enabled.

This would be similar to the soft-disable feature on powerpc, which
never actually turns off interrupts from regular kernel code but
just checks a flag in local_irq_enable that gets set when a
hardirq happened.
Case #2 seems messy. In AIC, we'd have to either:

* Disable FIQs, and hope that doesn't confuse any save/restore code
going on, then set a flag and check it in *both* the IRQ and FIQ path
since either might trigger depending on what happens next, or
* Mask the relevant timer, which we'd then need to make sure does not
confuse the timer code (Unmask it again when we fire the interrupt? But
what if the timer code intended to mask it in the interim?)
I'm not quite following here. The IRQ should be disabled the entire time
while handling that self-IPI and the timer top half code, so if we get
another FIQ while handling the timer from the IRQ path, it will lead
either yet another self-IPI or it will be ignored in case the previous timer
event has not been Acked yet. I would expect that both cases are
race-free here, the only time that the FIQ needs to be disabled is
while actually handling the FIQ. Did I miss something?
FIQs are level-triggered, and there are only two* ways of masking them
(that we know of): in the timer, or DAIF. That means that if we get a
FIQ, we *must* do one of two things: either mask it in the timer
register, or mask FIQs entirely. If we do neither of these, we get a FIQ
storm.

So if a timer FIQ fires while IRQs are disabled, and we can't call into
the timer code (because IRQs were disabled, so we need to defer handling
via the IPI), the only other options are to either poke the timer mask
bit directly, or to mask FIQs. Neither seems particularly correct.
Ok, I had not realized the timer was level triggered. In case of the
timer, I suppose it could be either masked or acknowledged from the
fiq top-half handler when deferring to irq, but I agree that it means a
layering violation in either case.

What might still work is an approach where FIQ is normally enabled,
and local_irq_disable() leaves it on, while local_irq_enable() turns
it on regardless of the current state.

In this case, the fiq handler could run the timer function if interrupts
are enabled but just turn off fiqs when they are turned off, waiting
for the next local_irq_enable() to get us back in the state where
the handler can run.  Not sure if that would buy us anything though,
or if that still requires platform specific conditionals in common code.
* An exception seems to be non-HV timer interrupts firing while we have
a VM guest running (HCR_EL2.TGE=0). This causes a single FIQ, and no
more, which suggests there is a mask bit for guest timer FIQs somewhere
that gets automatically set when the FIQ is delivered to the CPU core.
I've yet to find where this bit lives, I'll be doing a brute force sweep
of system register space soon to see if I can find it, and if there is
anything else useful near it.
Right. Maybe you can even find a bit that switches between FIQ and
IRQ mode for the timer, as that would solve the problem completely.
I think it's not that rare for irqchips to be configurable to either route
an interrupt one way or the other.
quoted
quoted
Plus I don't know if the vector entry code and other scaffolding between
the vector and the AIC driver would be happy with, effectively,
recursive interrupts. This could work with a carefully controlled path
to make sure it doesn't break things, but I'm not so sure about the
current "just point FIQ and IRQ to the same place" approach here.
If we do what I described above, the FIQ and IRQ entry would have
to be separate and only arrive in the same code path when calling
into drivers/clocksource/arm_arch_timer.c. It's not recursive there
because that part is only called when IRQ is disabled, and no IRQ
is being executed while the FIQ hits.
Right, that's what i'm saying; we can't re-use the IRQ handler like Marc
proposed, because I don't think that expects to be called reentrantly;
we'd have to have a separate FIQ entry, but since it can be called with
IRQs enabled and handle the FIQ in-line, it also needs to be able to
*conditionally* behave like a normal IRQ handler. This level of
complexity seems somewhat dubious, just to not maintain the FIQ mask bit
synced. That's not just AIC code any more, it needs a bespoke FIQ vector
and logic to decide whether IRQs are masked (call AIC to self-IPI
without doing the usual IRQ processing) or unmasked (go through regular
IRQ accounting and behave like an IRQ).

Perhaps I'm misunderstanding what you're proposing here or how this
would work :)
The way I had imagined it was to have a parallel set_handle_irq()
and set_handle_fiq() in the aic driver, which end up using the same
logic in the entry code to call into the driver. The code leading up
to that is all in assembler but isn't all that complex in the end, and
is already abstracted with macros to a large degree. For existing
machines that don't call set_handle_fiq() it could just end up in
either panic() or in WARN_ONCE() if an FIQ does happen
unexpectedly.

The aic_handle_fiq() function itself would be straightforward,
doing not much more than

       if (interrupts_enabled(ptregs))
             /* safe to call timer interrupt here, as interrupts are on */
             handle_domain_irq(aic->domain, AIC_TIMER_IRQ, regs);
       else
             /* need to defer until interrupts get re-enabled */
             aic_send_ipi(smp_processor_id(), TIMER_SELF_IPI);

Anyway, it's probably not worth pursuing this further if the timer
interrupt is level-triggered, as you explained above.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 09:27:23

On Thu, 04 Feb 2021 20:39:48 +0000,
Hector Martin [off-list ref] wrote:
quoted hunk
This is the root interrupt controller used on Apple ARM SoCs such as the
M1. This irqchip driver performs multiple functions:

* Discriminates between IRQs and FIQs

* Drives the AIC peripheral itself (which handles IRQs)

* Dispatches FIQs to downstream hard-wired clients (currently the ARM
  timer).

This patch introduces basic UP irqchip support, without SMP/IPI support.

Signed-off-by: Hector Martin <redacted>
---
 MAINTAINERS                     |   1 +
 drivers/irqchip/Kconfig         |  10 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-apple-aic.c | 316 ++++++++++++++++++++++++++++++++
 4 files changed, 328 insertions(+)
 create mode 100644 drivers/irqchip/irq-apple-aic.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f3d4661731c8..3a54ee5747d3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1635,6 +1635,7 @@ C:	irc://chat.freenode.net/asahi-dev
 T:	git https://github.com/AsahiLinux/linux.git
 F:	Documentation/devicetree/bindings/arm/AAPL.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
+F:	drivers/irqchip/irq-apple-aic.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 
 ARM/ARTPEC MACHINE SUPPORT
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index b147f22a78f4..288c01a9abd4 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -590,4 +590,14 @@ config MST_IRQ
 	help
 	  Support MStar Interrupt Controller.
 
+config APPLE_AIC
+	bool "Apple Interrupt Controller (AIC)"
+	depends on ARCH_APPLE || COMPILE_TEST
+	default ARCH_APPLE
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+	help
+	  Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
+	  such as the M1.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 0ac93bfaec61..0e2ba7c2dce7 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_PIC)		+= irq-loongson-pch-pic.o
 obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
 obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o
 obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
+obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
new file mode 100644
index 000000000000..533e3ce9f432
--- /dev/null
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 Hector Martin <marcan@marcan.st>
+ *
+ * Based on irq-lpc32xx:
+ *   Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com>
+ * Based on irq-bcm2836:
+ *   Copyright 2015 Broadcom
+ */
+
+/*
+ * AIC is a fairly simple interrupt controller with the following features:
+ *
+ * - 896 level-triggered hardware IRQs
+ *   - Single mask bit per IRQ
+ *   - Per-IRQ affinity setting
+ *   - Automatic masking on event delivery (auto-ack)
+ *   - Software triggering (ORed with hw line)
+ * - 2 per-CPU IPIs (meant as "self" and "other", but they are interchangeable if not symmetric)
+ * - Automatic prioritization (single event/ack register per CPU, lower IRQs = higher priority)
+ * - Automatic masking on ack
+ * - Default "this CPU" register view and explicit per-CPU views
+ *
+ * In addition, this driver also handles FIQs, as these are routed to the same IRQ vector. These
+ * are used for Fast IPIs (TODO) and the ARMv8 timer IRQs.
+ *
+ * Implementation notes:
+ *
+ * - This driver creates one IRQ domain for HW IRQs and the timer FIQs
+ * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu
+ * - DT bindings use 3-cell form (like GIC):
+ *   - <0 nr flags> - hwirq #nr
+ *   - <1 nr flags> - FIQ #nr
+ *     - nr=0  physical timer
+ *     - nr=1  virtual timer
+ *   - <2 nr flags> - IPI #nr
+ *     - nr=0  other IPI
+ *     - nr=1  self IPI
I really do not want to expose IPIs in the DT. The OS defines what
IPIs are used for, not the firmware/HW. No other platform requires
this either, so is there any reason to do so?
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
There isn't any chained interrupt controller here, AFAICT.
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <asm/exception.h>
+
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+
+#define AIC_INFO		0x0004
+#define AIC_INFO_NR_HW(i)	((i) & 0x0000ffff)
+
+#define AIC_CONFIG		0x0010
+
+#define AIC_WHOAMI		0x2000
+#define AIC_EVENT		0x2004
+
+#define AIC_EVENT_TYPE_HW	1
+#define AIC_EVENT_TYPE_IPI	4
+#define AIC_EVENT_IPI_OTHER	1
+#define AIC_EVENT_IPI_SELF	2
+
+#define AIC_IPI_SEND		0x2008
+#define AIC_IPI_ACK		0x200c
+#define AIC_IPI_MASK_SET	0x2024
+#define AIC_IPI_MASK_CLR	0x2028
+
+#define AIC_IPI_SEND_CPU(cpu)	BIT(cpu)
+
+#define AIC_IPI_OTHER		BIT(0)
+#define AIC_IPI_SELF		BIT(31)
+
+#define AIC_TARGET_CPU		0x3000
+#define AIC_SW_SET		0x4000
+#define AIC_SW_CLR		0x4080
+#define AIC_MASK_SET		0x4100
+#define AIC_MASK_CLR		0x4180
+
+#define AIC_CPU_IPI_SET(cpu)	(0x5008 + (cpu << 7))
+#define AIC_CPU_IPI_CLR(cpu)	(0x500c + (cpu << 7))
+#define AIC_CPU_IPI_MASK_SET(cpu) (0x5024 + (cpu << 7))
+#define AIC_CPU_IPI_MASK_CLR(cpu) (0x5028 + (cpu << 7))
+
+#define MASK_REG(x)		(4 * ((x) >> 5))
+#define MASK_BIT(x)		BIT((x) & 0x1f)
+
+#define AIC_NR_FIQ		2
+#define AIC_NR_IPI		2
+
+/*
+ * Max 31 bits in IPI SEND register (top bit is self).
+ * >=32-core chips will need code changes anyway.
+ */
+#define AIC_MAX_CPUS 31
+
+struct aic_irq_chip {
+	void __iomem *base;
+	struct irq_domain *hw_domain;
+	int nr_hw;
+};
+
+static struct aic_irq_chip *aic_irqc;
+
+static inline u32 aic_ic_read(struct aic_irq_chip *ic, u32 reg)
Please drop the inline, the compiler should manage this on its own
(and in most case will totally ignore that keyword one way or
another).
+{
+	return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
+}
+
+static inline void aic_ic_write(struct aic_irq_chip *ic, u32 reg, u32 val)
+{
+	writel(val, ic->base + reg);
+}
+
+/* These functions do nothing for FIQs, because they have no masks */
+static void aic_irq_mask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+
+	if (d->hwirq < ic->nr_hw)
+		aic_ic_write(ic, AIC_MASK_SET + MASK_REG(d->hwirq),
+			     MASK_BIT(d->hwirq));
+}
If these functions have no impact on the per-CPU interrupts, then
maybe these interrupts should be given a different irqchip.
+
+static void aic_irq_unmask(struct irq_data *d)
+{
+	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
+
+	if (d->hwirq < ic->nr_hw)
+		aic_ic_write(ic, AIC_MASK_CLR + MASK_REG(d->hwirq),
+			     MASK_BIT(d->hwirq));
+}
+
+static void aic_irq_eoi(struct irq_data *d)
+{
+	/*
+	 * Reading the interrupt reason automatically acknowledges and masks
+	 * the IRQ, so we just unmask it here if needed.
+	 */
+	if (!irqd_irq_disabled(d) && !irqd_irq_masked(d))
+		aic_irq_unmask(d);
This doesn't apply to per-CPU interrupts, right? Or does it?
+}
+
+static void aic_handle_irq(struct pt_regs *regs)
+{
+	struct aic_irq_chip *ic = aic_irqc;
+	u32 event = aic_ic_read(ic, AIC_EVENT);
+
+	while (event) {
+		u32 type = event >> 16, irq = event & 0xffff;
Nit: please consider introducing masks and using the bitfield macros
to extract the various fields.
+
+		/* AIC_EVENT is read-sensitive, ensure it happens before we proceed */
+		isb();
You seem to have a data dependency after this, so I can't see how the
ISB influences the read from AIC_EVENT. However you need to order it
with the read from the timer registers, and I believe it'd be better
to move the barrier there.
+
+		if (type == AIC_EVENT_TYPE_HW) {
+			handle_domain_irq(aic_irqc->hw_domain, irq, regs);
+		} else if (type == AIC_EVENT_TYPE_IPI) {
+			handle_domain_irq(aic_irqc->hw_domain,
+					  ic->nr_hw + AIC_NR_FIQ + irq - 1, regs);
nit: it would be slightly less cumbersome to compute the hwirq in a
switch, and have a single call to handle_domain_irq().

I also wonder whether using two top-level domains would be better. Not
a big deal though.
+		} else {
+			pr_err("spurious IRQ event %d, %d\n", type, irq);
Spurious interrupts aren't an error, in general. If you really want to
keep this, at the very least make it rate-limited.
+		}
+
+		event = aic_ic_read(ic, AIC_EVENT);
Consider turning the whole thing into a do{}while() so that there is
only a single read of AIC_EVENT in the function.
+	}
+}
+
+#define TIMER_FIRING(x)                                                        \
+	(((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
+		 ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
+	 (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
+
+static void aic_handle_fiq(struct pt_regs *regs)
+{
+	/*
+	 * It would be really nice to find a system register that lets us get the FIQ source
+	 * state without having to peek down into clients...
+	 */
nit: please try to keep comments within the 80 cols limit. I don't
mind code being wider, but comments benefit from being more rigorously
structured.

And yes, having to poll each end-point IP is really a drag. How does
the PMU work on this system? Is there any other per-CPU source?
+	if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) {
+		handle_domain_irq(aic_irqc->hw_domain,
+				  aic_irqc->nr_hw + AIC_TMR_PHYS, regs);
+	}
+
+	if (TIMER_FIRING(read_sysreg(cntv_ctl_el0))) {
+		handle_domain_irq(aic_irqc->hw_domain,
+				  aic_irqc->nr_hw + AIC_TMR_VIRT, regs);
+	}
This system runs VHE, so there is also CNT{P,V}_CTL_EL02 to consider.
But I really wonder how the whole thing works once these two timers
are assigned to a guest. Somehow, something must control the masking,
otherwise you wouldn't be able to enter a guest with a timer firing.

It also means that there is no way to have threaded per-CPU
interrupts, which means no Preempt-RT. You could wire the mask/unmask
callbacks to mess with the IMASK bit in individual timers, but that
doesn't solve the problem for guests.
+}
+
+static void __exception_irq_entry aic_handle_irq_or_fiq(struct pt_regs *regs)
+{
+	u64 isr = read_sysreg(isr_el1);
+
+	if (isr & PSR_F_BIT)
+		aic_handle_fiq(regs);
+
+	if (isr & PSR_I_BIT)
+		aic_handle_irq(regs);
+}
+
+static struct irq_chip aic_chip = {
+	.name = "AIC",
+	.irq_mask = aic_irq_mask,
+	.irq_unmask = aic_irq_unmask,
+	.irq_eoi = aic_irq_eoi,
+};
+
+static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	struct aic_irq_chip *ic = id->host_data;
+
+	irq_set_chip_data(irq, ic);
+	if (hw < ic->nr_hw) {
+		irq_set_chip_and_handler(irq, &aic_chip, handle_fasteoi_irq);
+	} else {
+		irq_set_percpu_devid(irq);
+		irq_set_chip_and_handler(irq, &aic_chip,
+					 handle_percpu_devid_irq);
+	}
+	irq_set_status_flags(irq, IRQ_LEVEL);
Are all interrupts level? How are MSIs implemented?
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static void aic_irq_domain_unmap(struct irq_domain *id, unsigned int irq)
+{
+	irq_set_chip_and_handler(irq, NULL, NULL);
+}
+
+static int aic_irq_domain_xlate(struct irq_domain *id,
+				struct device_node *ctrlr, const u32 *intspec,
+				unsigned int intsize,
+				irq_hw_number_t *out_hwirq,
+				unsigned int *out_type)
+{
+	struct aic_irq_chip *ic = id->host_data;
+
+	if (intsize != 3)
+		return -EINVAL;
+
+	if (intspec[0] == AIC_IRQ && intspec[1] < ic->nr_hw)
+		*out_hwirq = intspec[1];
+	else if (intspec[0] == AIC_FIQ && intspec[1] < AIC_NR_FIQ)
+		*out_hwirq = ic->nr_hw + intspec[1];
+	else if (intspec[0] == AIC_IPI && intspec[1] < AIC_NR_IPI)
+		*out_hwirq = ic->nr_hw + AIC_NR_FIQ + intspec[1];
+	else
+		return -EINVAL;
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+
+	return 0;
+}
+
+static const struct irq_domain_ops aic_irq_domain_ops = {
+	.map = aic_irq_domain_map,
+	.unmap = aic_irq_domain_unmap,
+	.xlate = aic_irq_domain_xlate,
+};
+
+static int __init aic_of_ic_init(struct device_node *node,
+				 struct device_node *parent)
+{
+	int i;
+	void __iomem *regs;
+	u32 info;
+	struct aic_irq_chip *irqc;
+
+	regs = of_iomap(node, 0);
+	if (WARN_ON(!regs))
+		return -EIO;
+
+	irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
+	if (!irqc)
+		return -ENOMEM;
+
+	aic_irqc = irqc;
+	irqc->base = regs;
+
+	info = aic_ic_read(irqc, AIC_INFO);
+	irqc->nr_hw = AIC_INFO_NR_HW(info);
+
+	irqc->hw_domain =
+		irq_domain_add_linear(node,
+				      irqc->nr_hw + AIC_NR_FIQ + AIC_NR_IPI,
+				      &aic_irq_domain_ops, irqc);
Please keep assignments on a single line.
+	if (WARN_ON(!irqc->hw_domain)) {
+		iounmap(irqc->base);
+		kfree(irqc);
+		return -ENODEV;
+	}
+
+	irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED);
+
+	set_handle_irq(aic_handle_irq_or_fiq);
+
+	for (i = 0; i < BITS_TO_LONGS(irqc->nr_hw); i++)
long is 64bit on arm64, so this loop is unlikely to do what you
want. Consider using BITS_TO_U32.
+		aic_ic_write(irqc, AIC_MASK_SET + i * 4, ~0);
+	for (i = 0; i < BITS_TO_LONGS(irqc->nr_hw); i++)
+		aic_ic_write(irqc, AIC_SW_CLR + i * 4, ~0);
+	for (i = 0; i < irqc->nr_hw; i++)
+		aic_ic_write(irqc, AIC_TARGET_CPU + i * 4, 1);
+
+	pr_info("AIC: initialized with %d IRQs, %d FIQs, %d IPIs\n",
+		irqc->nr_hw, AIC_NR_FIQ, AIC_NR_IPI);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(apple_m1_aic, "AAPL,aic", aic_of_ic_init);
Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Krzysztof Kozlowski <krzk@kernel.org>
Date: 2021-02-08 09:45:12

On Sun, Feb 07, 2021 at 06:26:43PM +0900, Hector Martin 'marcan' wrote:
On 07/02/2021 18.12, Hector Martin 'marcan' wrote:
quoted
On 06/02/2021 22.15, Marc Zyngier wrote:
quoted
The default should be IRQ_NONE, otherwise the kernel cannot detect a
screaming spurious interrupt.
Good point, and this needs fixing in s3c64xx_serial_handle_irq too then
(which is what I based mine off of).
quoted
quoted
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
Why IRQF_SHARED? Do you expect any other device sharing the same line
with this UART?
This also came from s3c64xx_serial_startup and... now I wonder why that
one needs it. Maybe on some SoCs it does get shared? Certainly not for
discrete rx/tx irq chips (and indeed those don't set the flag)...

CCing Thomas, who added the S3C64xx support (and should probably review
this patch); is there a reason for IRQF_SHARED there? NB: v1 breaks the
build on arm or with CONFIG_PM_SLEEP, those will be fixed for v2.
Seems Thomas does not work for Linaro any more :)

CCing Krzysztof instead, who is the Samsung arch maintainer.
Please use the scripts/get_maintainers.pl to get the list of people to
Cc. The script would point necessary folks.

A different issue is that all your emails from this thread were marked
by Google as spam.  I don't see any particular warning signs in the
header so it looks more of content-based match for spam.
quoted
Either way, certainly not for Apple SoCs; I'll get rid of IRQF_SHARED
for v2.
Please send a v2 after fixing issues pointed out by kbuild.

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-08 10:30:52

On Mon, Feb 8, 2021 at 10:25 AM Marc Zyngier [off-list ref] wrote:
On Thu, 04 Feb 2021 20:39:48 +0000, Hector Martin [off-list ref] wrote:
quoted
+{
+     return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
MSI interrupts require serializing with DMA, so at the minimum I think there
needs to be something that ensures that DMA from device into memory
has completed before delivering the completion interrupt to a driver. This
may already be implied when the AIC is entered, but this is hard to know
without actual hardware specs.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 10:35:17

On 2021-02-07 09:12, Hector Martin 'marcan' wrote:
On 06/02/2021 22.15, Marc Zyngier wrote:
[...]
quoted
quoted
-	spin_lock_irqsave(&port->lock, flags);
+	/* Only lock if called from IRQ context */
+	if (irq != NO_IRQ)
+		spin_lock_irqsave(&port->lock, flags);
Isn't that actually dangerous? What prevents the interrupt from firing
right in the middle of this sequence and create havoc when called from
enable_tx_pio()? I fail to see what you gain with sidestepping the
locking.
The callpath here is:

uart_start -> __uart_start -> (uart_ops.start_tx)
s3c24xx_serial_start_tx -> s3c24xx_serial_start_tx_pio ->
enable_tx_pio -> s3c24xx_serial_tx_chars

And uart_start takes the uart_port lock. None of the serial functions
take the lock because the serial core already does, but obviously the
IRQ handler needs to, *if* it's called as an IRQ handler only.
Right, that's the part I missed, thanks for pointing this out.
It'd probably be cleaner to move the whole s3c24xx_serial_tx_chars()
into a helper and keep the locking in the interrupt handler proper.

[...]
quoted
quoted
diff --git a/include/uapi/linux/serial_core.h 
b/include/uapi/linux/serial_core.h
index 62c22045fe65..59d102b674db 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -277,4 +277,7 @@
  /* Freescale LINFlexD UART */
  #define PORT_LINFLEXUART	122
  +/* Apple Silicon (M1/T8103) UART (Samsung variant) */
+#define PORT_APPLE	123
+
Do you actually need a new port type here? Looking at the driver
itself, it is mainly used to work out the IRQ model. Maybe introducing
a new irq_type field in the port structure would be better than
exposing this to userspace (which should see something that is exactly
the same as a S3C UART).
Well... every S3C variant already has its own port type here.

#define PORT_S3C2410    55
#define PORT_S3C2440    61
#define PORT_S3C2400    67
#define PORT_S3C2412    73
#define PORT_S3C6400    84

If we don't introduce a new one, which one should we pretend to be? :)
Pick one! :D
I agree that it might make sense to merge all of these into one,
though; I don't know what the original reason for splitting them out
is. But now that they're part of the userspace API, this might not be
a good idea. Though, unsurprisingly, some googling suggests there are
zero users of these defines in userspace.
I don't think we can do that, but I don't think we should keep adding
to this unless there is a very good reason. Greg would know, I expect.

Thanks,

          M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 01/18] dt-bindings: vendor-prefixes: add AAPL prefix

From: Krzysztof Kozlowski <krzk@kernel.org>
Date: 2021-02-08 10:40:19

On Fri, Feb 05, 2021 at 05:39:34AM +0900, Hector Martin wrote:
quoted hunk
Amusingly, this wasn't yet documented, even though this vendor prefix
has been used since time immemorial on PPC.

Signed-off-by: Hector Martin <redacted>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 041ae90b0d8f..d7950c723472 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -25,6 +25,8 @@ patternProperties:
   # Keep list in alphabetical order.
   "^70mai,.*":
     description: 70mai Co., Ltd.
+  "^AAPL,.*":
All prefixes are lower case... see ABB below (not mentioning that the
company name is not APPLE), so just "apple".
+    description: Apple Inc.
   "^abb,.*":
     description: ABB
Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 05/18] tty: serial: samsung_tty: add support for Apple UARTs

From: Krzysztof Kozlowski <krzk@kernel.org>
Date: 2021-02-08 11:04:54

On Fri, Feb 05, 2021 at 05:39:38AM +0900, Hector Martin wrote:
quoted hunk
Apple SoCs are a distant descendant of Samsung designs and use yet
another variant of their UART style, with different interrupt handling.

In particular, this variant has the following differences with existing
ones:

* It includes a built-in interrupt controller with different registers,
  using only a single platform IRQ

* Internal interrupt sources are treated as edge-triggered, even though
  the IRQ output is level-triggered. This chiefly affects the TX IRQ
  path: the driver can no longer rely on the TX buffer empty IRQ
  immediately firing after TX is enabled, but instead must prime the
  FIFO with data directly.

Signed-off-by: Hector Martin <redacted>
---
 drivers/tty/serial/samsung_tty.c | 297 +++++++++++++++++++++++++++----
 include/linux/serial_s3c.h       |  16 ++
 include/uapi/linux/serial_core.h |   3 +
 3 files changed, 280 insertions(+), 36 deletions(-)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 8ae3e03fbd8c..6d812ba1b748 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -56,6 +56,9 @@
 /* flag to ignore all characters coming in */
 #define RXSTAT_DUMMY_READ (0x10000000)
 
+/* IRQ number used when the handler is called in non-IRQ context */
+#define NO_IRQ -1
+
 struct s3c24xx_uart_info {
 	char			*name;
 	unsigned int		type;
@@ -144,6 +147,14 @@ struct s3c24xx_uart_port {
 #endif
 };
 
+enum s3c24xx_irq_type {
+	IRQ_DISCRETE = 0,
+	IRQ_S3C6400 = 1,
+	IRQ_APPLE = 2,
It seems you add the third structure to differentiate type of UART.
There is already port type and s3c24xx_serial_drv_data, no need for
third structure (kind of similar to tries of Tamseel Shams in recent
patches). It's too much. Instead, differentiate by port type or prepare
own set of uart_ops if it's really different (like you did with startup
op).
quoted hunk
+};
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
 /* conversion functions */
 
 #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev)
@@ -231,11 +242,20 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
 /*
  * s3c64xx and later SoC's include the interrupt mask and status registers in
  * the controller itself, unlike the s3c24xx SoC's which have these registers
- * in the interrupt controller. Check if the port type is s3c64xx or higher.
+ * in the interrupt controller. Apple SoCs use a different flavor of mask
+ * and status registers. This function returns the IRQ style to use.
  */
-static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+static int s3c24xx_irq_type(struct uart_port *port)
 {
-	return to_ourport(port)->info->type == PORT_S3C6400;
+	switch (to_ourport(port)->info->type) {
+	case PORT_S3C6400:
+		return IRQ_S3C6400;
+	case PORT_APPLE:
+		return IRQ_APPLE;
+	default:
+		return IRQ_DISCRETE;
+	}
+
No empty lines at end of function.
quoted hunk
 }
 
 static void s3c24xx_serial_rx_enable(struct uart_port *port)
@@ -289,10 +309,17 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	if (!ourport->tx_enabled)
 		return;
 
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		s3c24xx_clear_bit(port, APPLE_UCON_TXTHRESH_ENA, S3C2410_UCON);
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
 		dmaengine_pause(dma->tx_chan);
@@ -315,8 +342,6 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 	ourport->tx_mode = 0;
 }
 
-static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
-
 static void s3c24xx_serial_tx_dma_complete(void *args)
 {
 	struct s3c24xx_uart_port *ourport = args;
@@ -353,10 +378,17 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	u32 ucon;
 
 	/* Mask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		WARN_ON(1); // No DMA
+		break;
+	case IRQ_S3C6400:
 		s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
-	else
+		break;
+	default:
 		disable_irq_nosync(ourport->tx_irq);
+		break;
+	}
 
 	/* Enable tx dma mode */
 	ucon = rd_regl(port, S3C2410_UCON);
@@ -369,6 +401,8 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
 	ourport->tx_mode = S3C24XX_TX_DMA;
 }
 
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id);
+
 static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 {
 	struct uart_port *port = &ourport->port;
@@ -383,16 +417,30 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
 	ucon = rd_regl(port, S3C2410_UCON);
 	ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
 	ucon |= S3C64XX_UCON_TXMODE_CPU;
-	wr_regl(port,  S3C2410_UCON, ucon);
 
 	/* Unmask Tx interrupt */
-	if (s3c24xx_serial_has_interrupt_mask(port))
-		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
-				  S3C64XX_UINTM);
-	else
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE:
+		ucon |= APPLE_UCON_TXTHRESH_ENA_MSK;
+		break;
+	case IRQ_S3C6400:
+		s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
+		break;
+	default:
 		enable_irq(ourport->tx_irq);
+		break;
+	}
+
+	wr_regl(port,  S3C2410_UCON, ucon);
 
 	ourport->tx_mode = S3C24XX_TX_PIO;
+
+	/*
+	 * The Apple version only has edge triggered TX IRQs, so we need
+	 * to kick off the process by sending some characters here.
+	 */
+	if (s3c24xx_irq_type(port) == IRQ_APPLE)
+		s3c24xx_serial_tx_chars(NO_IRQ, ourport);
 }
 
 static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
@@ -513,11 +561,18 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
 
 	if (ourport->rx_enabled) {
 		dev_dbg(port->dev, "stopping rx\n");
-		if (s3c24xx_serial_has_interrupt_mask(port))
-			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
-					S3C64XX_UINTM);
-		else
-			disable_irq_nosync(ourport->rx_irq);
+		switch (s3c24xx_irq_type(port)) {
+		case IRQ_APPLE:
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+			s3c24xx_clear_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+			break;
+		case IRQ_S3C6400:
+			s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
+			break;
+		default:
+			disable_irq_nosync(ourport->tx_irq);
+			break;
+		}
 		ourport->rx_enabled = 0;
 	}
 	if (dma && dma->rx_chan) {
@@ -651,14 +706,18 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
 
 	/* set Rx mode to DMA mode */
 	ucon = rd_regl(port, S3C2410_UCON);
-	ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
-			S3C64XX_UCON_EMPTYINT_EN |
-			S3C64XX_UCON_DMASUS_EN |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_MASK);
-	ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
-			S3C64XX_UCON_TIMEOUT_EN |
-			S3C64XX_UCON_RXMODE_CPU;
+	ucon &= ~S3C64XX_UCON_RXMODE_MASK;
+	ucon |= S3C64XX_UCON_RXMODE_CPU;
+
+	/* Apple types use these bits for IRQ masks */
+	if (s3c24xx_irq_type(port) != IRQ_APPLE) {
+		ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+				S3C64XX_UCON_EMPTYINT_EN |
+				S3C64XX_UCON_DMASUS_EN |
+				S3C64XX_UCON_TIMEOUT_EN);
+		ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+				S3C64XX_UCON_TIMEOUT_EN;
+	}
 	wr_regl(port, S3C2410_UCON, ucon);
 
 	ourport->rx_mode = S3C24XX_RX_PIO;
@@ -831,7 +890,9 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 	unsigned long flags;
 	int count, dma_count = 0;
 
-	spin_lock_irqsave(&port->lock, flags);
+	/* Only lock if called from IRQ context */
+	if (irq != NO_IRQ)
+		spin_lock_irqsave(&port->lock, flags);
I would prefer to have two functions - unlocked (doing actual stuff) and
a locking wrapper. Something like is done for regulator_is_enabled().
However the s3c24xx_serial_tx_chars() also unlocks-locks inside, so it
might be not easy to split common part Anyway hacking interrupt handler
to NO_IRQ is confusing and not readable.
quoted hunk
 
 	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
@@ -893,7 +954,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 		s3c24xx_serial_stop_tx(port);
 
 out:
-	spin_unlock_irqrestore(&port->lock, flags);
+	if (irq != NO_IRQ)
+		spin_unlock_irqrestore(&port->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -916,6 +978,26 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
 	return ret;
 }
 
+/* interrupt handler for Apple SoC's.*/
+static irqreturn_t apple_serial_handle_irq(int irq, void *id)
+{
+	struct s3c24xx_uart_port *ourport = id;
+	struct uart_port *port = &ourport->port;
+	unsigned int pend = rd_regl(port, S3C2410_UTRSTAT);
+	irqreturn_t ret = IRQ_HANDLED;
+
+	if (pend & (APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO)) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_RXTHRESH | APPLE_UTRSTAT_RXTO);
+		ret = s3c24xx_serial_rx_chars(irq, id);
+	}
+	if (pend & APPLE_UTRSTAT_TXTHRESH) {
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_TXTHRESH);
+		ret = s3c24xx_serial_tx_chars(irq, id);
+	}
+
+	return ret;
+}
+
 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
 	struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@ -1098,7 +1180,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
 	if (ourport->tx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->tx_irq, ourport);
 		ourport->tx_enabled = 0;
 		ourport->tx_claimed = 0;
@@ -1106,18 +1188,34 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
 	}
 
 	if (ourport->rx_claimed) {
-		if (!s3c24xx_serial_has_interrupt_mask(port))
+		if (s3c24xx_irq_type(port) == IRQ_DISCRETE)
 			free_irq(ourport->rx_irq, ourport);
 		ourport->rx_claimed = 0;
 		ourport->rx_enabled = 0;
 	}
 
 	/* Clear pending interrupts and mask all interrupts */
-	if (s3c24xx_serial_has_interrupt_mask(port)) {
+	switch (s3c24xx_irq_type(port)) {
+	case IRQ_APPLE: {
+		unsigned int ucon;
+
+		ucon = rd_regl(port, S3C2410_UCON);
+		ucon &= ~(APPLE_UCON_TXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTHRESH_ENA_MSK |
+			APPLE_UCON_RXTO_ENA_MSK);
+		wr_regl(port, S3C2410_UCON, ucon);
+
+		wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+		free_irq(port->irq, ourport);
+		break;
+	}
+	case IRQ_S3C6400:
 		free_irq(port->irq, ourport);
 
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTM, 0xf);
+		break;
 	}
 
 	if (ourport->dma)
@@ -1215,6 +1313,47 @@ static int s3c64xx_serial_startup(struct uart_port *port)
 	return ret;
 }
 
+static int apple_serial_startup(struct uart_port *port)
+{
+	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	unsigned long flags;
+	unsigned int ufcon;
+	int ret;
+
+	wr_regl(port, S3C2410_UTRSTAT, APPLE_UTRSTAT_ALL_FLAGS);
+
+	ret = request_irq(port->irq, apple_serial_handle_irq, IRQF_SHARED,
+			  s3c24xx_serial_portname(port), ourport);
+	if (ret) {
+		dev_err(port->dev, "cannot get irq %d\n", port->irq);
+		return ret;
+	}
+
+	/* For compatibility with s3c24xx Soc's */
+	ourport->rx_enabled = 1;
+	ourport->rx_claimed = 1;
+	ourport->tx_enabled = 0;
+	ourport->tx_claimed = 1;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ufcon = rd_regl(port, S3C2410_UFCON);
+	ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
+	if (!uart_console(port))
+		ufcon |= S3C2410_UFCON_RESETTX;
+	wr_regl(port, S3C2410_UFCON, ufcon);
+
+	enable_rx_pio(ourport);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Enable Rx Interrupt */
+	s3c24xx_set_bit(port, APPLE_UCON_RXTHRESH_ENA, S3C2410_UCON);
+	s3c24xx_set_bit(port, APPLE_UCON_RXTO_ENA, S3C2410_UCON);
+
+	return ret;
+}
+
 /* power power management control */
 
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1544,6 +1683,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
 		return "S3C2412";
 	case PORT_S3C6400:
 		return "S3C6400/10";
+	case PORT_APPLE:
+		return "APPLE";
"Apple S5L"?
quoted hunk
 	default:
 		return NULL;
 	}
@@ -1868,9 +2009,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 	/* setup info for port */
 	port->dev	= &platdev->dev;
 
+	switch (s3c24xx_irq_type(port)) {
+	/* Startup sequence is different for Apple SoC's */
+	case IRQ_APPLE:
+		s3c24xx_serial_ops.startup = apple_serial_startup;
+		break;
 	/* Startup sequence is different for s3c64xx and higher SoC's */
-	if (s3c24xx_serial_has_interrupt_mask(port))
+	case IRQ_S3C6400:
 		s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
Don't overwrite specific ops. It's difficult to see then which ops are
being used. Instead create a new set of uart_ops matching the needs.

Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Krzysztof Kozlowski <krzk@kernel.org>
Date: 2021-02-08 11:15:05

On Fri, Feb 05, 2021 at 05:39:51AM +0900, Hector Martin wrote:
quoted hunk
This currently supports:

* SMP (via spin-tables)
* AIC IRQs
* Serial (with earlycon)
* Framebuffer

A number of properties are dynamic, and based on system firmware
decisions that vary from version to version. These are expected
to be filled in by the loader.

Signed-off-by: Hector Martin <redacted>
---
 MAINTAINERS                              |   1 +
 arch/arm64/boot/dts/Makefile             |   1 +
 arch/arm64/boot/dts/apple/Makefile       |   2 +
 arch/arm64/boot/dts/apple/apple-j274.dts | 143 +++++++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 arch/arm64/boot/dts/apple/Makefile
 create mode 100644 arch/arm64/boot/dts/apple/apple-j274.dts
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a54ee5747d3..5481b5bc2ef7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1635,6 +1635,7 @@ C:	irc://chat.freenode.net/asahi-dev
 T:	git https://github.com/AsahiLinux/linux.git
 F:	Documentation/devicetree/bindings/arm/AAPL.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/AAPL,aic.yaml
+F:	arch/arm64/boot/dts/AAPL/
apple

Don't make things different for this one platform (comparing to all
other platforms). Apple is not that special. :)
quoted hunk
 F:	drivers/irqchip/irq-apple-aic.c
 F:	include/dt-bindings/interrupt-controller/apple-aic.h
 
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 9b1170658d60..64f055d94948 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -6,6 +6,7 @@ subdir-y += amazon
 subdir-y += amd
 subdir-y += amlogic
 subdir-y += apm
+subdir-y += apple
 subdir-y += arm
 subdir-y += bitmain
 subdir-y += broadcom
diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile
new file mode 100644
index 000000000000..ec03c474efd4
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_APPLE) += apple-j274.dtb
diff --git a/arch/arm64/boot/dts/apple/apple-j274.dts b/arch/arm64/boot/dts/apple/apple-j274.dts
new file mode 100644
index 000000000000..238a1bcee066
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/apple-j274.dts
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Hector Martin <marcan@marcan.st>
A lot here might be difficult to reverse-egineer or figure out by
ourself, so usually people rely on vendor sources (the open source
compliance package). Didn't you receive such for the iOS (or whatever
was on your Mac)?
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/apple-aic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	model = "Apple Mac Mini M1 2020";
+	compatible = "AAPL,j274", "AAPL,m1", "AAPL,arm-platform";
I guess Rob will comment on the dt-bindings more... but for me a generic
"arm-platform" is too generic. What's the point of it? I didn't see any
of such generic compatibles in other platforms.
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		bootargs = "earlycon";
This should not be hard-coded in DTS. Pass it from bootloader.
+		stdout-path = "serial0:1500000";
Use aliases.
+
+		framebuffer0: framebuffer@0 {
+			compatible = "AAPL,simple-framebuffer", "simple-framebuffer";
+			reg = <0 0 0 0>; // To be filled by loader
+			// Format properties will be added by loader
Use /* style of comments
+			status = "disabled";
+		};
+	};
+
+	memory@800000000 {
+		device_type = "memory";
+		reg = <0 0 0 0>; // To be filled by loader
+	};
+
+	aliases {
+		serial0 = &serial0;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu1: cpu@1 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x1>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu2: cpu@2 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x2>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu3: cpu@3 {
+			compatible = "AAPL,icestorm";
+			device_type = "cpu";
+			reg = <0x0 0x3>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu4: cpu@10100 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10100>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu5: cpu@10101 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10101>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu6: cpu@10102 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10102>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+		cpu7: cpu@10103 {
+			compatible = "AAPL,firestorm";
+			device_type = "cpu";
+			reg = <0x0 0x10103>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0 0>; // To be filled by loader
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 1 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	clk24: clk24 {
Just "clock". Node names should be generic.
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "clk24";
What clock is it? Part of board or SoC? Isn't it a work-around for
missing clock drivers?
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		aic: interrupt-controller@23b100000 {
+			compatible = "AAPL,m1-aic", "AAPL,aic";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg = <0x2 0x3b100000 0x0 0x8000>;
+		};
+
+		serial0: serial@235200000 {
+			compatible = "AAPL,s5l-uart";
+			reg = <0x2 0x35200000 0x0 0x1000>;
+			reg-io-width = <4>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 605 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk24>, <&clk24>;
+			clock-names = "uart", "clk_uart_baud0";
+		};
+
No blank lines at end of blocks.

Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-08 11:23:34

On Mon, Feb 8, 2021 at 12:13 PM Hector Martin 'marcan' [off-list ref] wrote:
On 08/02/2021 19.29, Arnd Bergmann wrote:
quoted
On Mon, Feb 8, 2021 at 10:25 AM Marc Zyngier [off-list ref] wrote:
quoted
On Thu, 04 Feb 2021 20:39:48 +0000, Hector Martin [off-list ref] wrote:
quoted
quoted
+{
+     return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
MSI interrupts require serializing with DMA, so at the minimum I think there
needs to be something that ensures that DMA from device into memory
has completed before delivering the completion interrupt to a driver. This
may already be implied when the AIC is entered, but this is hard to know
without actual hardware specs.
I don't think this can be implied in any case, because if IRQ A fires
and then the CPU speculates its way through AIC into the IRQ B handler,
which reads DMA'd memory, then IRQ B fires and it has higher priority
and *that* is what ends up getting returned from the event register
first, the execution will commit with an ordering violation.

I'm pretty sure we need *some* level of explicit synchronization between
reading the event register and actually delivering IRQs downstream.
Using _relaxed might be okay, but we'd still need something where the
isb() currently is in aic_handle_irq (though I admit I don't have a
perfect picture of the memory ordering subtleties involved here yet).
The idea of the barriers in readl/writel is to avoid having to guess these
subtleties, so maybe it's easier to start with the normal readl() and no
other barrier for an initial merge, as that should be sufficient, and then
do any optimizations in a later patch after everyone agrees what the
specific requirements are and much much time can be saved this way.
Incidentally, just from the races and problems I've run into with
trivial tests in m1n1, these CPUs seem to be *very* eager to speculate
and I suspect they will help uncover race conditions in Linux...
Yes, that definitely helps.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-08 11:30:10

On 08/02/2021 19.29, Arnd Bergmann wrote:
On Mon, Feb 8, 2021 at 10:25 AM Marc Zyngier [off-list ref] wrote:
quoted
On Thu, 04 Feb 2021 20:39:48 +0000, Hector Martin [off-list ref] wrote:
quoted
quoted
+{
+     return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
MSI interrupts require serializing with DMA, so at the minimum I think there
needs to be something that ensures that DMA from device into memory
has completed before delivering the completion interrupt to a driver. This
may already be implied when the AIC is entered, but this is hard to know
without actual hardware specs.
I don't think this can be implied in any case, because if IRQ A fires 
and then the CPU speculates its way through AIC into the IRQ B handler, 
which reads DMA'd memory, then IRQ B fires and it has higher priority 
and *that* is what ends up getting returned from the event register 
first, the execution will commit with an ordering violation.

I'm pretty sure we need *some* level of explicit synchronization between 
reading the event register and actually delivering IRQs downstream. 
Using _relaxed might be okay, but we'd still need something where the 
isb() currently is in aic_handle_irq (though I admit I don't have a 
perfect picture of the memory ordering subtleties involved here yet).

Incidentally, just from the races and problems I've run into with 
trivial tests in m1n1, these CPUs seem to be *very* eager to speculate 
and I suspect they will help uncover race conditions in Linux...

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 08/18] arm64: cpufeature: Add a feature for FIQ support

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 11:30:18

On Sun, 07 Feb 2021 08:28:35 +0000,
Hector Martin 'marcan' [off-list ref] wrote:
On 06/02/2021 22.58, Marc Zyngier wrote:
quoted
Hector Martin [off-list ref] wrote:
quoted
+static void cpu_sync_irq_to_fiq(struct arm64_cpu_capabilities const *cap)
+{
+	u64 daif = read_sysreg(daif);
+
+	/*
+	 * By this point in the boot process IRQs are likely masked and FIOs
+	 * aren't, so we need to sync things to avoid spurious early FIQs.
+	 */
+
+	if (daif & PSR_I_BIT)
+		daif |= PSR_F_BIT;
+	else
+		daif &= ~PSR_F_BIT;
+
+	write_sysreg(daif, daif);
Could this happen too late? If, as explained above, we can get a FIQ
until we mask it here, what prevents something (a timer?) from kicking
and creating havoc just before the sync?
Nothing, other than timers not being enabled this early (hopefully the
bootloader doesn't leave a rogue timer running for us...)
I'm not sure we want to trust the FW on that particular front (no
offence intended...;-).
quoted
If the answer is "nothing", then it probably means that the default
behaviour should be to treat PSTATE.I and PSTATE.F as containing the
same value at all times, and not just as an afterthought when we
detect that we're on a CPU type or another.
I thought of this too. Originally I thought PSTATE.F was always set on
other systems, and thus unmasking FIQs could cause problems if there
is a pending rogue FIQ for some reason. However, while writing this
patch I realized that as part of normal process state changes we
already unmask FIQs anyway (see DAIF_PROCCTX).

Thus, in fact, this patch actually changes things (when the cpufeature
is set) to mask FIQs in some cases where they currently aren't, and
conversely to unmask them in some cases where they currently are. But
the fact that FIQ masking is somewhat inconsistent to begin with
suggests that we should be able to mess with it without causing
breakage for other systems.

So I guess in this case it would be legitimate to just make I==F on
every system, and if something breaks it should be fixed by making
whatever is causing a rogue FIQ not do that, right?
That is my current take on this patch. Nothing in the arm64 kernel
expects a FIQ today, so *when* a FIQ fires is pretty much irrelevant,
as long as we handle it properly (panic). Keeping the two bits in sync
is trivial, and shouldn't carry material overhead.
That would leave the vector switcheroo as the only thing the
cpufeature does, which would certainly simplify a lot of the patch.
quoted
This could expand into enabling Group-0 interrupts with GICv3 on
systems that have a single security state (such as virtual machines),
though I don't really see a good use case for it.
I could see having a separate vector path opening up the door for
performance hacks for very specific use cases that want really low
latency for *one* thing (e.g. the mess the Raspberry Pi folks do to
work around that braindead USB controller's performance issues),
though I imagine there would have to be very compelling reasons to
develop a framework to do this sanely upstream.
In general, this only works for single security state systems (systems
without EL3 and VMs), as FIQs are usually routed to the secure side
otherwise. If tied to a GIC, Group-0 interrupts aren't configurable
from NS either.
Incidentally, I have a personal interest in real-time performance
(especially audio); once the dust settles and we have a workable
kernel for normal use I do hope to spend some time taking a deep dive
into latencies and finding RT-unfriendly code, but that's pretty far
off right now. Maybe PREEMPT_RT will even be merged by then :-) (I
hope that without SMM to screw things up on these machines they might
make very nice RT-capable boxes...)
Aside from the lack of programmable priority, the lack of convenient
masking for per-CPU interrupts is a bit of an issue...

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 10/18] arm64: Introduce FIQ support

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 11:32:05

On Sun, 07 Feb 2021 08:47:23 +0000,
Hector Martin 'marcan' [off-list ref] wrote:
On 07/02/2021 00.37, Marc Zyngier wrote:
quoted
See my digression in patch 8. I really wonder what the benefit is to
treat FIQ independently of IRQ, and we might as well generalise
this. We could always panic on getting a FIQ on platforms that don't
expect one.

It'd be good to rope in the other interested parties (Mark for the
early entry code, James for RAS and SError handling).
CCing Mark and James: TL;DR what do you think about unconditionally
keeping DAIF.I == DAIF.F, would this break other platforms with
spurious FIQs or conversely mask FIQs when we don't want to in some
cases? The FIQ vector would remain a panic except on platforms that
require using it, via an alternatives patch.
quoted
quoted
  	kernel_ventry	1, sync				// Synchronous EL1h
  	kernel_ventry	1, irq				// IRQ EL1h
-	kernel_ventry	1, fiq_invalid			// FIQ EL1h
+							// FIQ EL1h
+	kernel_ventry	1, fiq_invalid, 64, irq, ARM64_NEEDS_FIQ
It could be better to create a set of first class FIQ handlers rather
than this alternative target macro. I quickly hacked this instead,
which I find more readable.
I think I ended up with the macro change to keep it 1:1 with IRQ, vs a
separate branch... but I didn't think of the fallthrough-with-nop
trick, neat. It is definitely is more readable. Are you OK with me
pulling this patch in for v2, with your name on it?
Up to you, I don't mind either way. This is just code! :D
quoted
-	kernel_ventry	0, fiq_invalid_compat, 32	// FIQ 32-bit EL0
+	kernel_ventry	0, fiq, 32			// FIQ 32-bit EL0
fiq_compat here, right?
Of course.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 11:37:21

On Mon, 08 Feb 2021 10:29:23 +0000,
Arnd Bergmann [off-list ref] wrote:
On Mon, Feb 8, 2021 at 10:25 AM Marc Zyngier [off-list ref] wrote:
quoted
On Thu, 04 Feb 2021 20:39:48 +0000, Hector Martin [off-list ref] wrote:
quoted
quoted
+{
+     return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
MSI interrupts require serializing with DMA, so at the minimum I think there
needs to be something that ensures that DMA from device into memory
has completed before delivering the completion interrupt to a driver. This
may already be implied when the AIC is entered, but this is hard to know
without actual hardware specs.
If there is a sync with memory required, it should happen at the point
where it is Acked, not when masked/unmasked or anything else. And
given that you want to sync with an external agent (the DMA producer),
the DMB generated by readl won't save you, as it only orders CPU
accesses AFAICT.

So if MSIs require some additional synchronisation we probably need a
DSB somewhere if the HW doesn't guarantee ordering of DMA vs
MSIs. Whether it does or not is anyone's bet.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 11/18] arm64: Kconfig: Require FIQ support for ARCH_APPLE

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 12:07:03

On 2021-02-07 09:23, Hector Martin 'marcan' wrote:
On 07/02/2021 00.46, Marc Zyngier wrote:
quoted
quoted
  config ARCH_APPLE
  	bool "Apple Silicon SoC family"
  	select GENERIC_IRQ_CHIP
+	select ARM64_FIQ_SUPPORT
Ah, this is what I was expecting in the previous patch. I guess the
initial ARCH_APPLE patch could be moved down the line and add all the
dependencies in one go.
I was trying to introduce the Kconfig before the code that depends on
it; is it kosher to have it in the other order, looking for CONFIG_
defines that don't exist yet?
Absolutely. The only requirement is to make sure that nothing breaks in
the middle of a series.
Though in this case the only user earlier in the series is the Samsung
stuff, which doesn't care about FIQs, so I can just sort things as
FIQ->ARCH_APPLE->samsung->AIC...
Seems fine to me. Sorting out the infrastructure first (FIQ, memory
attributes) first is a requirement anyway, so the ordering of the
series could reflect that priority.
I'm not sure about AIC vs. ARCH_APPLE though. Right now the pattern is
that AIC depends on ARCH_APPLE and also defaults to that. But then you
can build with ARCH_APPLE and AIC disabled if you so choose, which
does result in a broken system on these machines. AIC should build
without ARCH_APPLE (as long as we're on ARM64), so we could reverse
that.
As long as ARCH_APPLE selects AIC, you can make AIC selectable on
its own. What I'm trying to avoid is people ending up with an unbootable
system, and not having interrupts is one thing that makes it really hard
to debug...

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Hector Martin 'marcan' <hidden>
Date: 2021-02-08 12:17:07

On 08/02/2021 20.04, Krzysztof Kozlowski wrote:
apple

Don't make things different for this one platform (comparing to all
other platforms). Apple is not that special. :)
AAPL is the old vendor prefix used in the PowerPC era. I'm happy to use 
`apple`, as long as we're OK with having two different prefixes for the 
same vendor, one for PPC and one for ARM64. I've seen opinions go both 
ways on this one :)
quoted
+ * Copyright 2021 Hector Martin [off-list ref]
A lot here might be difficult to reverse-egineer or figure out by
ourself, so usually people rely on vendor sources (the open source
compliance package). Didn't you receive such for the iOS (or whatever
was on your Mac)?
Apple source drops are sparse (they don't even include things like the 
irqchip driver, only the very core OS code) and APSL licensed, which is 
a license incompatible with the GPL. Worse, they've moved to a 
partial-blob model with the M1; M1-compatible XNU source code drops now 
include a .a blob with startup and CPU-specific code, for which no 
source code is provided. (to be clear: Apple does not ship Linux for 
these machines)

Honestly, beyond what's in this patchset and a few more details about 
CPU registers like performance monitoring stuff that exist in public XNU 
drops but I haven't looked into yet, Apple's source code drops are going 
to be practically useless to us from here on out. It's all binaries 
after this.

Apple device trees are not open source at all; those are provided by 
iBoot and ship with device firmware, which is not openly licensed. Those 
device trees are OF-inspired, but otherwise in a different format and 
structure to Linux device trees.

Since there is zero Apple-published code or data with a license 
compatible with the Linux kernel to be used here, there can be zero 
copyright lines claiming any submissions are copyright Apple from us, 
because that would imply a license violation has occurred. I am treating 
this as I would any other no-source reverse engineering project, that 
is, ensuring that I only look at Apple code (binaries, source, 
devicetrees, whatever) to understand how the hardware functions, build 
documentation for it (at least in my head, but I am also trying to 
document things on our wiki as I go), and then write original code to 
drive it from Linux, unrelated to whatever Apple was doing.

We're also trying to avoid looking at any Apple stuff in general as much 
as possible, preferring black-box approaches where feasible, to minimize 
exposure. For example, I only looked at an (outdated, arm32 era) AIC 
register name list in XNU to write the AIC driver; there is no actual 
AIC driver code in the source, and instead of decompiling Apple's binary 
blob AIC driver module, I figured out how the hardware actually worked 
via probing and experimentation. The entire userspace GPU stack is being 
reverse engineered via a black-box approach, without any decompilation. 
I'm going to see what I can do about the kernel driver in the future, 
and prefer some kind of mmio tracing solution if I can get it all to 
work on macOS.

As for this file specifically: while I am obviously looking at Apple's 
DTs to figure out things like register offsets and what hardware exists, 
those are facts, and facts are not copyrightable, and thus Apple does 
not hold any copyright interest over this code as I submitted it. Short 
of verbatim copying and pasting of entire nodes with bespoke property 
names (which would never fly here anyway because Apple does things very 
differently from Linux DTs when you get down into the details), it would 
be extremely hard to argue that translating hardware information from 
decompiled Apple DTs to Linux DTs would constitute a copyright 
violation, since the entire purpose of DTs is to describe hardware facts.

You can read more about our reverse engineering and copyright policy at 
https://alx.sh/re - if you have any suggestions or spot anything 
problematic, please let me know.

(I'm actually probably going to change that copyright line to "The Asahi 
Linux Contributors" for v2, if that's okay with the kernel folks, to be 
in line with our other projects; I defaulted to my name since so far I'm 
the only contributor to these files, but I expect other people to throw 
PRs at me in the future and the history to end up with more names here)
I guess Rob will comment on the dt-bindings more... but for me a generic
"arm-platform" is too generic. What's the point of it? I didn't see any
of such generic compatibles in other platforms.
This is a hack for patches #11/#12 to use, and I expect it will go away 
once we figure out how to properly handle that problem (which needs 
further discussion). Sorry for the noise, this should not be there in 
the final version.
quoted
+		bootargs = "earlycon";
This should not be hard-coded in DTS. Pass it from bootloader.
My apologies, this was garbage left over from before I had bootargs 
support in the bootloader. Will be gone for v2.
quoted
+	clk24: clk24 {
Just "clock". Node names should be generic.
Really? Almost every other device device tree uses unique clock node names.
quoted
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "clk24";
What clock is it? Part of board or SoC? Isn't it a work-around for
missing clock drivers?
The clock topology isn't entirely known yet; I'm submitting this as an 
initial bring-up patchset and indeed there should be a clockchip driver 
in the future. The UART driver wants a clock to be able to calculate 
baud rates. I figured we can get away with a fixed-clock for now while 
that part of the SoC gets figured out.

Ack on all the other comments, will fix for v2.

Thanks for the review!

-- 
Hector Martin "marcan" (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 15/18] irqchip/apple-aic: Add support for the Apple Interrupt Controller

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-08 12:19:06

On Mon, Feb 8, 2021 at 12:36 PM Marc Zyngier [off-list ref] wrote:
On Mon, 08 Feb 2021 10:29:23 +0000, Arnd Bergmann [off-list ref] wrote:
quoted
On Mon, Feb 8, 2021 at 10:25 AM Marc Zyngier [off-list ref] wrote:
quoted
On Thu, 04 Feb 2021 20:39:48 +0000, Hector Martin [off-list ref] wrote:
quoted
quoted
+{
+     return readl(ic->base + reg);
Please consider using the _relaxed accessors, as I don't think any of
these interacts with memory (apart from IPIs, of course).
MSI interrupts require serializing with DMA, so at the minimum I think there
needs to be something that ensures that DMA from device into memory
has completed before delivering the completion interrupt to a driver. This
may already be implied when the AIC is entered, but this is hard to know
without actual hardware specs.
If there is a sync with memory required, it should happen at the point
where it is Acked, not when masked/unmasked or anything else. And
given that you want to sync with an external agent (the DMA producer),
the DMB generated by readl won't save you, as it only orders CPU
accesses AFAICT.
If the dmb in readl() is not sufficient for preventing the speculative read
on DMA data from a device that sent the MSI, why is it sufficient for
the case in which any device driver relies on readl() from a device
register to ensure that DMA is complete?

I had expected those two cases to be equivalent.
So if MSIs require some additional synchronisation we probably need a
DSB somewhere if the HW doesn't guarantee ordering of DMA vs
MSIs. Whether it does or not is anyone's bet.
Right, for all we know it could require a much more heavyweight barrier
as it does on certain broken SoCs, or nothing at all.

      Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Marc Zyngier <maz@kernel.org>
Date: 2021-02-08 12:28:57

On 2021-02-04 20:39, Hector Martin wrote:
This currently supports:

* SMP (via spin-tables)
* AIC IRQs
* Serial (with earlycon)
* Framebuffer

A number of properties are dynamic, and based on system firmware
decisions that vary from version to version. These are expected
to be filled in by the loader.

Signed-off-by: Hector Martin <redacted>
---
[...]
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&aic>;
+		interrupts = <AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 1 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_FIQ 0 IRQ_TYPE_LEVEL_HIGH>;
This unfortunately doesn't match the binding, which doesn't cater
for systems without a secure physical timer, nor allows the description
of the EL2 virtual timer.

You should also have *different* interrupts for EL1 and EL2 timers,
although this is all a lie...

Looking at the only similar case, XGene lies about the secure timer
(it doesn't have any), and of course doesn't have an EL2 virtual
timer (ARMv8.0 only).

A sensible course of action could be to update the binding to at least:

- tell the kernel that there is no secure physical timer (and that
   the interrupt should be ignored)
- introduce a 5th possible interrupt for the EL2 virtual timer.

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Krzysztof Kozlowski <krzk@kernel.org>
Date: 2021-02-08 12:29:40

On Mon, Feb 08, 2021 at 08:56:53PM +0900, Hector Martin 'marcan' wrote:
On 08/02/2021 20.04, Krzysztof Kozlowski wrote:
quoted
apple

Don't make things different for this one platform (comparing to all
other platforms). Apple is not that special. :)
AAPL is the old vendor prefix used in the PowerPC era. I'm happy to use
`apple`, as long as we're OK with having two different prefixes for the same
vendor, one for PPC and one for ARM64. I've seen opinions go both ways on
this one :)
Thanks for explanation. I propose to choose just "apple". Sticking to
old vendor name is not a requirement - we have few vendor prefixes which
were marked as deprecated because we switched to a better one.
quoted
quoted
+ * Copyright 2021 Hector Martin [off-list ref]
A lot here might be difficult to reverse-egineer or figure out by
ourself, so usually people rely on vendor sources (the open source
compliance package). Didn't you receive such for the iOS (or whatever
was on your Mac)?
Apple source drops are sparse (they don't even include things like the
irqchip driver, only the very core OS code) and APSL licensed, which is a
license incompatible with the GPL. Worse, they've moved to a partial-blob
model with the M1; M1-compatible XNU source code drops now include a .a blob
with startup and CPU-specific code, for which no source code is provided.
(to be clear: Apple does not ship Linux for these machines)

Honestly, beyond what's in this patchset and a few more details about CPU
registers like performance monitoring stuff that exist in public XNU drops
but I haven't looked into yet, Apple's source code drops are going to be
practically useless to us from here on out. It's all binaries after this.

Apple device trees are not open source at all; those are provided by iBoot
and ship with device firmware, which is not openly licensed. Those device
trees are OF-inspired, but otherwise in a different format and structure to
Linux device trees.

Since there is zero Apple-published code or data with a license compatible
with the Linux kernel to be used here, there can be zero copyright lines
claiming any submissions are copyright Apple from us, because that would
imply a license violation has occurred. I am treating this as I would any
other no-source reverse engineering project, that is, ensuring that I only
look at Apple code (binaries, source, devicetrees, whatever) to understand
how the hardware functions, build documentation for it (at least in my head,
but I am also trying to document things on our wiki as I go), and then write
original code to drive it from Linux, unrelated to whatever Apple was doing.
Makes sense. In such case it's indeed your work. Since you introduce it,
the DTSes are usually licensed with (GPL-2.0+ OR MIT).
We're also trying to avoid looking at any Apple stuff in general as much as
possible, preferring black-box approaches where feasible, to minimize
exposure. For example, I only looked at an (outdated, arm32 era) AIC
register name list in XNU to write the AIC driver; there is no actual AIC
driver code in the source, and instead of decompiling Apple's binary blob
AIC driver module, I figured out how the hardware actually worked via
probing and experimentation. The entire userspace GPU stack is being reverse
engineered via a black-box approach, without any decompilation. I'm going to
see what I can do about the kernel driver in the future, and prefer some
kind of mmio tracing solution if I can get it all to work on macOS.

As for this file specifically: while I am obviously looking at Apple's DTs
to figure out things like register offsets and what hardware exists, those
are facts, and facts are not copyrightable, and thus Apple does not hold any
copyright interest over this code as I submitted it. Short of verbatim
copying and pasting of entire nodes with bespoke property names (which would
never fly here anyway because Apple does things very differently from Linux
DTs when you get down into the details), it would be extremely hard to argue
that translating hardware information from decompiled Apple DTs to Linux DTs
would constitute a copyright violation, since the entire purpose of DTs is
to describe hardware facts.

You can read more about our reverse engineering and copyright policy at
https://alx.sh/re - if you have any suggestions or spot anything
problematic, please let me know.

(I'm actually probably going to change that copyright line to "The Asahi
Linux Contributors" for v2, if that's okay with the kernel folks, to be in
line with our other projects; I defaulted to my name since so far I'm the
only contributor to these files, but I expect other people to throw PRs at
me in the future and the history to end up with more names here)
The copyrights matter more in case the need to relicense the work or
some copyright-infringement cases. If you use generic alias - The Asahi
contributors - how it would be possible to find people with actual
copyrights? For example to ask them about relicense permission?  Unless
it's an official body (e.g. foundation or company).  Therefore I propose
to stick to real names and include other contributors once they
contribute.

However this are just my thoughts, not a really professional opinion
about copyright aspects.
quoted
I guess Rob will comment on the dt-bindings more... but for me a generic
"arm-platform" is too generic. What's the point of it? I didn't see any
of such generic compatibles in other platforms.
This is a hack for patches #11/#12 to use, and I expect it will go away once
we figure out how to properly handle that problem (which needs further
discussion). Sorry for the noise, this should not be there in the final
version.
quoted
quoted
+		bootargs = "earlycon";
This should not be hard-coded in DTS. Pass it from bootloader.
My apologies, this was garbage left over from before I had bootargs support
in the bootloader. Will be gone for v2.
quoted
quoted
+	clk24: clk24 {
Just "clock". Node names should be generic.
Really? Almost every other device device tree uses unique clock node names.
Yes, really, devicetree/ePAPR spec:
"The name of a node should be somewhat generic, reflecting the function
of the device and not its precise programming model. If appropriate, the
name should be one of the following choices:"

Multiple other boards and people (including myself...) made the same
mistake of adding specific names. Even some platform maintainers still
don't get it or never cared to look at DT spec. :)
quoted
quoted
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-output-names = "clk24";
What clock is it? Part of board or SoC? Isn't it a work-around for
missing clock drivers?
The clock topology isn't entirely known yet; I'm submitting this as an
initial bring-up patchset and indeed there should be a clockchip driver in
the future. The UART driver wants a clock to be able to calculate baud
rates. I figured we can get away with a fixed-clock for now while that part
of the SoC gets figured out.
Such workaround is ok, but maybe add a comment that it's a workaround so
far.

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Arnd Bergmann <arnd@kernel.org>
Date: 2021-02-08 12:42:11

On Mon, Feb 8, 2021 at 1:13 PM Krzysztof Kozlowski [off-list ref] wrote:
On Mon, Feb 08, 2021 at 08:56:53PM +0900, Hector Martin 'marcan' wrote:
quoted
On 08/02/2021 20.04, Krzysztof Kozlowski wrote:
quoted
apple

Don't make things different for this one platform (comparing to all
other platforms). Apple is not that special. :)
AAPL is the old vendor prefix used in the PowerPC era. I'm happy to use
`apple`, as long as we're OK with having two different prefixes for the same
vendor, one for PPC and one for ARM64. I've seen opinions go both ways on
this one :)
Thanks for explanation. I propose to choose just "apple". Sticking to
old vendor name is not a requirement - we have few vendor prefixes which
were marked as deprecated because we switched to a better one.
We've gone back and forth on this a few times already. My current
preference would also be to go with "apple", not because it's somehow
nicer or clearer but because it avoids the namespace conflict with
what the Apple firmware uses:

The point of the vendor prefix is to prevent two people from introducing
the same identifier with slightly different meanings. This used to be
the stock ticker symbol ("ibm", "SUNW", "AAPL", ...) back when the
only people making devices with firmware were large corporations.

In FDT, it's usually random contributors introducing the names to make
something work on Linux, with unique strings coming from code review.

The identifiers that Apple use are highly unlikely to cause clashes
with the ones we use in Linux, since you probably won't find much
software that has to deal with both formats, but the fact that Apple
still prefixes those strings with their stock ticker symbol tells me that
someone there still considers the namespace relevant, so it's more
polite to stay out of their lawn.
Makes sense. In such case it's indeed your work. Since you introduce it,
the DTSes are usually licensed with (GPL-2.0+ OR MIT).
Indeed, we do want other OSs to use our dts files, so the general
preference is to have a permissive license, unless you have a strong
reason yourself to require GPL-only.

       Arnd

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Re: [PATCH 18/18] arm64: apple: Add initial Mac Mini 2020 (M1) devicetree

From: Hector Martin <hidden>
Date: 2021-02-08 14:39:57

On 08/02/2021 21.40, Arnd Bergmann wrote:
On Mon, Feb 8, 2021 at 1:13 PM Krzysztof Kozlowski [off-list ref] wrote:
quoted
On Mon, Feb 08, 2021 at 08:56:53PM +0900, Hector Martin 'marcan' wrote:
quoted
On 08/02/2021 20.04, Krzysztof Kozlowski wrote:
quoted
apple

Don't make things different for this one platform (comparing to all
other platforms). Apple is not that special. :)
AAPL is the old vendor prefix used in the PowerPC era. I'm happy to use
`apple`, as long as we're OK with having two different prefixes for the same
vendor, one for PPC and one for ARM64. I've seen opinions go both ways on
this one :)
Thanks for explanation. I propose to choose just "apple". Sticking to
old vendor name is not a requirement - we have few vendor prefixes which
were marked as deprecated because we switched to a better one.
We've gone back and forth on this a few times already. My current
preference would also be to go with "apple", not because it's somehow
nicer or clearer but because it avoids the namespace conflict with
what the Apple firmware uses:
Ack, I'll use 'apple' for v2.

Amusingly, Apple actually use 'apple,firestorm' and 'apple,icestorm' for 
the CPUs in their devicetrees for these machines, so those will end up 
identical :) (they don't use apple-related prefixes for any other 
compatible strings at all, it's a mess). But we don't care about what 
their ADTs (Apple DTs) do in Linux anyway, the bootloader abstracts all 
that out and we'll be dealing with mantaining proper DTs ourselves.
quoted
Makes sense. In such case it's indeed your work. Since you introduce it,
the DTSes are usually licensed with (GPL-2.0+ OR MIT).
Indeed, we do want other OSs to use our dts files, so the general
preference is to have a permissive license, unless you have a strong
reason yourself to require GPL-only.
Thanks for pointing this out; this was actually unintentional. I based 
it off of an old dts I'd written ages ago and forgot to revisit the 
license. I even have it marked GPL-2.0+ in the copy in our bootloader 
repo, which is otherwise supposed to be MIT for original code...

-- 
Hector Martin (marcan@marcan.st)
Public Key: https://mrcn.st/pub

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Next 36 of 36 remaining
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help