From nobody Thu Apr 03 01:11:40 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4ZSkGN66cSz5sBx6; Thu, 03 Apr 2025 01:11:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZSkGN3GNJz3PHR; Thu, 03 Apr 2025 01:11:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743642700; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=XL2tajn4w1AstARqBMX7a3iWKiRGMlI7BKJwoov/4dc=; b=mlYLNYd4uaZ8uc3/iP+JOUAEUTryWT89M4RNba9mgNfEnmeopXsY1MK8/67f0K/TX0kKSs J0k4XqMBSucttXMJsvFXKG6DuzBPpqgWzAb1KMCI/8L6EzDQ60EsgW2tZUhL6nFcyMEcGY KKFY1naBaIqYc+PVmLnPDjupWVsDdhGsW0wj48TLi0bevw2J0vjI18xH1tauA09srA+Kw5 I6EgY1Rh6HkibfZHkdO6JHV4EtE+XqT+pVGbS9qgB6X23PufbVxKBYJCQ7mMwTa4422nR8 Cz8/ZHQafpeeHmr4CGbP+hP0yTJ5D25joDy8pMY4K0YOMa0W2yyoVxcgvuznXw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1743642700; a=rsa-sha256; cv=none; b=gKxK1mtaEDzckLZb2+/hEFSS05IXQwrdHx9/OanFlKB0rYCAKwmSfsrivybDaUVdyFChBT r4AJ5UBr2bN9MNG9TiJ42FgRu+m6N2sp/F3yvkQM3Xt/tRFMEQsKW6w0y63GncmaNbdMsi QqFPbxEZbA4QeNVwbQfpNLvzp9XBuWkhMlR3KWOBrLw9lm37IRsVvqeNNTdYOyXrfwwO2r 6u3LJDTiya5+3YxJCLg58vjht1nCgTTZF5UdUT8hqtlOgNl4N/Uoz2slcaBg/kLNcGnO/w IKGr7ZVfvLv0/a2M8P90cloidLvd6+2rb+BJDoolDJxpDXW7LwZzgy8JJUjm1w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743642700; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=XL2tajn4w1AstARqBMX7a3iWKiRGMlI7BKJwoov/4dc=; b=BIQS2sYCcixfv5KGgJ1L0v8+kQKn+vl7mGMDY9ZaNEciZc+U/O3DrxbPJQDlLxM0Ge3HOR h+Aw9yFo+VgHda7Vjf1OOAXXOruxyq8h+V3kkMVO3KQmu6vXjbcCoWvkQ97Pu15F3P7BAD HQNICFzna0v9QY6XpfiAbVjkwuu3uxdTG/kD/ghBxtk0YQtIgkiP6eOEvRqlASZ2BlFnGO Cn0H505F9Hikqtdc6e37Xih4MjcT9U9te/NIw5tyioSpdAxenYAnFCDlLVMy951rTWO9yc /IPRsCzYdVW8Q3vuDbihbW4UjXqvJrWz9j/t5vPep4uxOEtuPeYTb0ZujL7eOw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ZSkGN1vWGzgmF; Thu, 03 Apr 2025 01:11:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 5331Besu082345; Thu, 3 Apr 2025 01:11:40 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5331BeQ0082342; Thu, 3 Apr 2025 01:11:40 GMT (envelope-from git) Date: Thu, 3 Apr 2025 01:11:40 GMT Message-Id: <202504030111.5331BeQ0082342@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 0a91888870e2 - main - arm64: add a GPIO driver for Apple Silicon List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 0a91888870e2227d3b3576aaa949764929550b94 Auto-Submitted: auto-generated The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=0a91888870e2227d3b3576aaa949764929550b94 commit 0a91888870e2227d3b3576aaa949764929550b94 Author: Kyle Evans AuthorDate: 2025-04-03 01:11:26 +0000 Commit: Kyle Evans CommitDate: 2025-04-03 01:11:33 +0000 arm64: add a GPIO driver for Apple Silicon This is a ported version of OpenBSD's work, modulo interrupt functionality. We won't need GPIO interrupts until we start to get closer to audio support, and the existing version is sufficient for, e.g., pcie. Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D49630 --- sys/arm64/apple/apple_pinctrl.c | 469 ++++++++++++++++++++++++++++++++++++++++ sys/conf/files.arm64 | 1 + 2 files changed, 470 insertions(+) diff --git a/sys/arm64/apple/apple_pinctrl.c b/sys/arm64/apple/apple_pinctrl.c new file mode 100644 index 000000000000..ec2dd5907024 --- /dev/null +++ b/sys/arm64/apple/apple_pinctrl.c @@ -0,0 +1,469 @@ +/* $OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis + * Copyright (c) 2022 Kyle Evans + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "pic_if.h" +#include "gpio_if.h" + +#define APPLE_PIN(pinmux) ((pinmux) & 0xffff) +#define APPLE_FUNC(pinmux) ((pinmux) >> 16) + +#define GPIO_PIN(pin) ((pin) * 4) +#define GPIO_PIN_GROUP_MASK (7 << 16) +#define GPIO_PIN_INPUT_ENABLE (1 << 9) +#define GPIO_PIN_FUNC_MASK (3 << 5) +#define GPIO_PIN_FUNC_SHIFT 5 +#define GPIO_PIN_MODE_MASK (7 << 1) +#define GPIO_PIN_MODE_INPUT (0 << 1) +#define GPIO_PIN_MODE_OUTPUT (1 << 1) +#define GPIO_PIN_MODE_IRQ_HI (2 << 1) +#define GPIO_PIN_MODE_IRQ_LO (3 << 1) +#define GPIO_PIN_MODE_IRQ_UP (4 << 1) +#define GPIO_PIN_MODE_IRQ_DN (5 << 1) +#define GPIO_PIN_MODE_IRQ_ANY (6 << 1) +#define GPIO_PIN_MODE_IRQ_OFF (7 << 1) +#define GPIO_PIN_DATA (1 << 0) +#define GPIO_IRQ(grp, pin) (0x800 + (grp) * 64 + ((pin) >> 5) * 4) + +#define APPLE_PINCTRL_DEFAULT_CAPS \ + (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) + +#define HREAD4(sc, reg) \ + bus_read_4((sc)->sc_res[APPLE_PINCTRL_MEMRES], reg) +#define HWRITE4(sc, reg, val) \ + bus_write_4((sc)->sc_res[APPLE_PINCTRL_MEMRES], reg, val) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +struct apple_pinctrl_irqsrc { + struct intr_irqsrc isrc; + int irq; + int type; +}; + +enum { + APPLE_PINCTRL_MEMRES = 0, + APPLE_PINCTRL_IRQRES, + APPLE_PINCTRL_NRES, +}; + +struct apple_pinctrl_softc { + device_t sc_dev; + device_t sc_busdev; + struct mtx sc_mtx; + int sc_ngpios; + + void *sc_intrhand; + struct resource *sc_res[APPLE_PINCTRL_NRES]; + struct apple_pinctrl_irqsrc *sc_irqs; +}; + +#define APPLE_PINCTRL_LOCK(sc) mtx_lock_spin(&(sc)->sc_mtx) +#define APPLE_PINCTRL_UNLOCK(sc) mtx_unlock_spin(&(sc)->sc_mtx) +#define APPLE_PINCTRL_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) + +static struct ofw_compat_data compat_data[] = { + {"apple,pinctrl", 1}, + {NULL, 0}, +}; + +static struct resource_spec apple_pinctrl_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0, 0 }, +}; + +static int apple_pinctrl_probe(device_t dev); +static int apple_pinctrl_attach(device_t dev); +static int apple_pinctrl_detach(device_t dev); + +static int apple_pinctrl_configure(device_t, phandle_t); +static phandle_t apple_pinctrl_get_node(device_t, device_t); + +static int +apple_pinctrl_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "Apple Pinmux Controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +apple_pinctrl_attach(device_t dev) +{ + pcell_t gpio_ranges[4]; + phandle_t node; + struct apple_pinctrl_softc *sc; + int error; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + node = ofw_bus_get_node(dev); + + if (bus_alloc_resources(dev, apple_pinctrl_res_spec, sc->sc_res) != 0) { + device_printf(dev, "cannot allocate device resources\n"); + return (ENXIO); + } + + mtx_init(&sc->sc_mtx, "aapl gpio", "gpio", MTX_SPIN); + + error = OF_getencprop(node, "gpio-ranges", gpio_ranges, + sizeof(gpio_ranges)); + if (error == -1) { + device_printf(dev, "failed to get gpio-ranges\n"); + goto error; + } + + sc->sc_ngpios = gpio_ranges[3]; + if (sc->sc_ngpios == 0) { + device_printf(dev, "no GPIOs\n"); + goto error; + } + + sc->sc_busdev = gpiobus_attach_bus(dev); + if (sc->sc_busdev == NULL) { + device_printf(dev, "failed to attach gpiobus\n"); + goto error; + } + + fdt_pinctrl_register(dev, "pinmux"); + fdt_pinctrl_configure_tree(dev); + + if (!OF_hasprop(node, "interrupt-controller")) + return (0); + + sc->sc_irqs = mallocarray(sc->sc_ngpios, + sizeof(*sc->sc_irqs), M_DEVBUF, M_ZERO | M_WAITOK); + intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev))); + + return (0); +error: + mtx_destroy(&sc->sc_mtx); + bus_release_resources(dev, apple_pinctrl_res_spec, sc->sc_res); + return (ENXIO); +} + +static int +apple_pinctrl_detach(device_t dev) +{ + + return (EBUSY); +} + +static void +apple_pinctrl_pin_configure(struct apple_pinctrl_softc *sc, uint32_t pin, + uint32_t flags) +{ + uint32_t reg; + + APPLE_PINCTRL_LOCK_ASSERT(sc); + + MPASS(pin < sc->sc_ngpios); + + reg = HREAD4(sc, GPIO_PIN(pin)); + reg &= ~GPIO_PIN_FUNC_MASK; + reg &= ~GPIO_PIN_MODE_MASK; + + if ((flags & GPIO_PIN_PRESET_LOW) != 0) + reg &= ~GPIO_PIN_DATA; + else if ((flags & GPIO_PIN_PRESET_HIGH) != 0) + reg |= GPIO_PIN_DATA; + + if ((flags & GPIO_PIN_INPUT) != 0) + reg |= GPIO_PIN_MODE_INPUT; + else if ((flags & GPIO_PIN_OUTPUT) != 0) + reg |= GPIO_PIN_MODE_OUTPUT; + + HWRITE4(sc, GPIO_PIN(pin), reg); +} + +static device_t +apple_pinctrl_get_bus(device_t dev) +{ + struct apple_pinctrl_softc *sc; + + sc = device_get_softc(dev); + return (sc->sc_busdev); +} + +static int +apple_pinctrl_pin_max(device_t dev, int *maxpin) +{ + struct apple_pinctrl_softc *sc; + + sc = device_get_softc(dev); + *maxpin = sc->sc_ngpios - 1; + return (0); +} + +static int +apple_pinctrl_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct apple_pinctrl_softc *sc; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + snprintf(name, GPIOMAXNAME - 1, "gpio%c%d", + device_get_unit(dev) + 'a', pin); + + return (0); +} + +static int +apple_pinctrl_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct apple_pinctrl_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + *flags = 0; + + APPLE_PINCTRL_LOCK(sc); + + reg = HREAD4(sc, GPIO_PIN(pin)); + if ((reg & GPIO_PIN_MODE_INPUT) != 0) + *flags |= GPIO_PIN_INPUT; + else if ((reg & GPIO_PIN_MODE_OUTPUT) != 0) + *flags |= GPIO_PIN_OUTPUT; + + APPLE_PINCTRL_UNLOCK(sc); + + return (0); +} + +static int +apple_pinctrl_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + + *caps = APPLE_PINCTRL_DEFAULT_CAPS; + return (0); +} + +static int +apple_pinctrl_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + struct apple_pinctrl_softc *sc; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + APPLE_PINCTRL_LOCK(sc); + apple_pinctrl_pin_configure(sc, pin, flags); + APPLE_PINCTRL_UNLOCK(sc); + + return (0); +} + +static int +apple_pinctrl_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + struct apple_pinctrl_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + APPLE_PINCTRL_LOCK(sc); + reg = HREAD4(sc, GPIO_PIN(pin)); + *val = !!(reg & GPIO_PIN_DATA); + APPLE_PINCTRL_UNLOCK(sc); + + return (0); +} + +static int +apple_pinctrl_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct apple_pinctrl_softc *sc; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + APPLE_PINCTRL_LOCK(sc); + if (value) + HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA); + else + HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA); + device_printf(sc->sc_dev, "set pin %d to %x\n", + pin, HREAD4(sc, GPIO_PIN(pin))); + APPLE_PINCTRL_UNLOCK(sc); + return (0); +} + + +static int +apple_pinctrl_pin_toggle(device_t dev, uint32_t pin) +{ + struct apple_pinctrl_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (pin >= sc->sc_ngpios) + return (EINVAL); + + APPLE_PINCTRL_LOCK(sc); + reg = HREAD4(sc, GPIO_PIN(pin)); + if ((reg & GPIO_PIN_DATA) == 0) + reg |= GPIO_PIN_DATA; + else + reg &= ~GPIO_PIN_DATA; + HWRITE4(sc, GPIO_PIN(pin), reg); + APPLE_PINCTRL_UNLOCK(sc); + return (0); +} + + +static int +apple_pinctrl_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, + uint32_t *pin_flags) +{ + struct apple_pinctrl_softc *sc; + uint32_t pin; + + sc = device_get_softc(dev); + if (first_pin >= sc->sc_ngpios) + return (EINVAL); + + /* + * The configuration for a bank of pins is scattered among several + * registers; we cannot g'tee to simultaneously change the state of all + * the pins in the flags array. So just loop through the array + * configuring each pin for now. If there was a strong need, it might + * be possible to support some limited simultaneous config, such as + * adjacent groups of 8 pins that line up the same as the config regs. + */ + APPLE_PINCTRL_LOCK(sc); + for (pin = first_pin; pin < num_pins; ++pin) { + if (pin_flags[pin] & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) + apple_pinctrl_pin_configure(sc, pin, pin_flags[pin]); + } + APPLE_PINCTRL_UNLOCK(sc); + + return (0); +} + +static phandle_t +apple_pinctrl_get_node(device_t dev, device_t bus) +{ + + /* GPIO bus */ + return (ofw_bus_get_node(dev)); +} + +static int +apple_pinctrl_configure(device_t dev, phandle_t cfgxref) +{ + struct apple_pinctrl_softc *sc; + pcell_t *pinmux; + phandle_t node; + ssize_t len; + uint32_t reg; + uint16_t pin, func; + int i; + + sc = device_get_softc(dev); + node = OF_node_from_xref(cfgxref); + + len = OF_getencprop_alloc(node, "pinmux", (void **)&pinmux); + if (len <= 0) + return (-1); + + APPLE_PINCTRL_LOCK(sc); + for (i = 0; i < len / sizeof(pcell_t); i++) { + pin = APPLE_PIN(pinmux[i]); + func = APPLE_FUNC(pinmux[i]); + reg = HREAD4(sc, GPIO_PIN(pin)); + reg &= ~GPIO_PIN_FUNC_MASK; + reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK; + HWRITE4(sc, GPIO_PIN(pin), reg); + } + APPLE_PINCTRL_UNLOCK(sc); + + OF_prop_free(pinmux); + return 0; +} + +static device_method_t apple_pinctrl_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, apple_pinctrl_probe), + DEVMETHOD(device_attach, apple_pinctrl_attach), + DEVMETHOD(device_detach, apple_pinctrl_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_get_bus, apple_pinctrl_get_bus), + DEVMETHOD(gpio_pin_max, apple_pinctrl_pin_max), + DEVMETHOD(gpio_pin_getname, apple_pinctrl_pin_getname), + DEVMETHOD(gpio_pin_getflags, apple_pinctrl_pin_getflags), + DEVMETHOD(gpio_pin_getcaps, apple_pinctrl_pin_getcaps), + DEVMETHOD(gpio_pin_setflags, apple_pinctrl_pin_setflags), + DEVMETHOD(gpio_pin_get, apple_pinctrl_pin_get), + DEVMETHOD(gpio_pin_set, apple_pinctrl_pin_set), + DEVMETHOD(gpio_pin_toggle, apple_pinctrl_pin_toggle), + DEVMETHOD(gpio_pin_config_32, apple_pinctrl_pin_config_32), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, apple_pinctrl_get_node), + + /* fdt_pinctrl interface */ + DEVMETHOD(fdt_pinctrl_configure, apple_pinctrl_configure), + + DEVMETHOD_END +}; + +static driver_t apple_pinctrl_driver = { + "gpio", + apple_pinctrl_methods, + sizeof(struct apple_pinctrl_softc), +}; + +EARLY_DRIVER_MODULE(apple_pinctrl, simplebus, apple_pinctrl_driver, + 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 74387914043e..901da27e63f2 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -547,6 +547,7 @@ arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \ # Apple arm64/apple/apple_aic.c optional soc_apple_t8103 fdt +arm64/apple/apple_pinctrl.c optional soc_apple_t8103 fdt arm64/apple/apple_wdog.c optional soc_apple_t8103 fdt arm64/apple/exynos_uart.c optional soc_apple_t8103 fdt