From patchwork Mon Oct 21 03:38:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1180243 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="RLgEX1Qh"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 46xNRF44sPz9sP6 for ; Mon, 21 Oct 2019 15:08:25 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id E0890C21C93; Mon, 21 Oct 2019 04:03:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_MSPIKE_H2, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id D480AC21DD7; Mon, 21 Oct 2019 04:03:19 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id EE47FC21C51; Mon, 21 Oct 2019 03:40:50 +0000 (UTC) Received: from mail-il1-f193.google.com (mail-il1-f193.google.com [209.85.166.193]) by lists.denx.de (Postfix) with ESMTPS id 0355BC21D83 for ; Mon, 21 Oct 2019 03:40:50 +0000 (UTC) Received: by mail-il1-f193.google.com with SMTP id f13so10675405ils.11 for ; Sun, 20 Oct 2019 20:40:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JeDyOfmGS20u+u4KTQJryj6jAqZT+7rqCIiBC5FGa6o=; b=RLgEX1Qh4rHQ/B6htwBVmjgXk12TddS/ehNYfqE0JcKosaWDsfb7Vq3/JyNx6und6u nre91u32JtvDn/DwYfCYA8dmovikNUvjIbQ0Spj51kKYv9UT2gy07x+fW+oOqEKXKFyA hnMCH48F1Wlv2DQw0pbc23lZdJGPAfCDilH2g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=JeDyOfmGS20u+u4KTQJryj6jAqZT+7rqCIiBC5FGa6o=; b=lLTSZtJw4tGabHmn+s4wKzaWEwPRR6RUjZCeXBisJa5cIjvzd9FhX+FDmf6Pvo90gN zHRNoBmrScvh9l/iv5RQ2SaAlgddy3qmTd2tbGBYl7Njq97hYICdZ+ZNV/ntNVOABWVV wfQfJ7dz52vKaxYD62KFsFOvx5ETco9tigI0bEjeJWX5HP5636jUb9dYaTi3Ab4r3YjA w+DXewbVJgcroX19fZKLFWsx5rJ+90AmG289crQ/GEXOoq1CXOHYFkZEf4xbNPIoWEzX awlKSEsdYWSj1ziEZTtJeltAMmZruVEmTcti32hhmCKoic2CPhB4/2nc14Ge1muw8h4L RsVA== X-Gm-Message-State: APjAAAWrYNEtvzzGJxRS8I/l5+/954JKu0MvIDfvEzRPO5vdr0p/xY8A KEYXOn7pB4j+Ro4EFEgtV5wdHCZOGFa8FA== X-Google-Smtp-Source: APXvYqw5ZaKAduGCNIpoCWR9/xrr0F1r1WlOxEg3Y5amiDelLOmvmg9JEFZk+jIXsZjYx6BSk20vng== X-Received: by 2002:a05:6e02:6c2:: with SMTP id p2mr23476217ils.295.1571629248678; Sun, 20 Oct 2019 20:40:48 -0700 (PDT) Received: from kiwi.bld.corp.google.com ([2620:15c:183:0:8223:87c:a681:66aa]) by smtp.gmail.com with ESMTPSA id x14sm1947028ion.67.2019.10.20.20.40.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 20 Oct 2019 20:40:48 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Date: Sun, 20 Oct 2019 21:38:57 -0600 Message-Id: <20191021033913.220758-87-sjg@chromium.org> X-Mailer: git-send-email 2.23.0.866.gb869b98d4c-goog In-Reply-To: <20191021033913.220758-22-sjg@chromium.org> References: <20191021033913.220758-22-sjg@chromium.org> MIME-Version: 1.0 Subject: [U-Boot] [PATCH v3 092/108] x86: apollolake: Add UART driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add a driver for the apollolake UART. It uses the standard ns16550 device but also sets up the input clock with LPSS and supports configuration via of-platdata. Signed-off-by: Simon Glass --- Changes in v3: - Use the LPSS code from a separate file Changes in v2: None arch/x86/cpu/apollolake/Makefile | 1 + arch/x86/cpu/apollolake/uart.c | 141 ++++++++++++++++++++ arch/x86/include/asm/arch-apollolake/uart.h | 17 +++ 3 files changed, 159 insertions(+) create mode 100644 arch/x86/cpu/apollolake/uart.c create mode 100644 arch/x86/include/asm/arch-apollolake/uart.h diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile index b58ef8e019c..ff42d0fd619 100644 --- a/arch/x86/cpu/apollolake/Makefile +++ b/arch/x86/cpu/apollolake/Makefile @@ -4,3 +4,4 @@ obj-y += lpss.o obj-y += pmc.o +obj-y += uart.o diff --git a/arch/x86/cpu/apollolake/uart.c b/arch/x86/cpu/apollolake/uart.c new file mode 100644 index 00000000000..66744937dcb --- /dev/null +++ b/arch/x86/cpu/apollolake/uart.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Special driver to handle of-platdata + * + * Copyright 2019 Google LLC + * + * Some code from coreboot lpss.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Low-power Subsystem (LPSS) clock register */ +enum { + LPSS_CLOCK_CTL_REG = 0x200, + LPSS_CNT_CLOCK_EN = 1, + LPSS_CNT_CLK_UPDATE = 1U << 31, + LPSS_CLOCK_DIV_N_SHIFT = 16, + LPSS_CLOCK_DIV_N_MASK = 0x7fff << LPSS_CLOCK_DIV_N_SHIFT, + LPSS_CLOCK_DIV_M_SHIFT = 1, + LPSS_CLOCK_DIV_M_MASK = 0x7fff << LPSS_CLOCK_DIV_M_SHIFT, + + /* These set the UART input clock speed */ + LPSS_UART_CLK_M_VAL = 0x25a, + LPSS_UART_CLK_N_VAL = 0x7fff, +}; + +static void lpss_clk_update(void *regs, u32 clk_m_val, u32 clk_n_val) +{ + u32 clk_sel; + + clk_sel = clk_n_val << LPSS_CLOCK_DIV_N_SHIFT | + clk_m_val << LPSS_CLOCK_DIV_M_SHIFT; + clk_sel |= LPSS_CNT_CLK_UPDATE | LPSS_CNT_CLOCK_EN; + + writel(clk_sel, regs + LPSS_CLOCK_CTL_REG); +} + +static void uart_lpss_init(void *regs) +{ + /* Take UART out of reset */ + lpss_reset_release(regs); + + /* Set M and N divisor inputs and enable clock */ + lpss_clk_update(regs, LPSS_UART_CLK_M_VAL, LPSS_UART_CLK_N_VAL); +} + +void apl_uart_init(pci_dev_t bdf, ulong base) +{ + /* Set UART base address */ + pci_x86_write_config(bdf, PCI_BASE_ADDRESS_0, base, PCI_SIZE_32); + + /* Enable memory access and bus master */ + pci_x86_write_config(bdf, PCI_COMMAND, PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER, PCI_SIZE_32); + + uart_lpss_init((void *)base); +} + +/* + * This driver uses its own compatible string but almost everything else from + * the standard ns16550 driver. This allows us to provide an of-platdata + * implementation, since the platdata produced by of-platdata does not match + * struct ns16550_platdata. + * + * When running with of-platdata (generally TPL), the platdata is converted to + * something that ns16550 expects. When running withoutof-platdata (SPL, U-Boot + * proper), we use ns16550's ofdata_to_platdata routine. + */ + +static int apl_ns16550_probe(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + + if (!CONFIG_IS_ENABLED(PCI)) + apl_uart_init(plat->bdf, plat->base); + + return ns16550_serial_probe(dev); +} + +static int apl_ns16550_ofdata_to_platdata(struct udevice *dev) +{ + struct ns16550_platdata *plat; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_intel_apl_ns16550 *dtplat = dev_get_platdata(dev); + + /* + * Convert our platdata to the ns16550's platdata, so we can just use + * that driver + */ + plat = malloc(sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->base = dtplat->early_regs[0]; + plat->reg_width = 1; + plat->reg_shift = dtplat->reg_shift; + plat->reg_offset = 0; + plat->clock = dtplat->clock_frequency; + plat->fcr = UART_FCR_DEFVAL; + plat->bdf = pci_x86_ofplat_get_devfn(dtplat->reg[0]); + dev->platdata = plat; +#else + int ret; + + ret = ns16550_serial_ofdata_to_platdata(dev); + if (ret) + return ret; + if (!CONFIG_IS_ENABLED(OF_TRANSLATE)) { + /* + * Without address translation we cannot get correct PCI + * address, so just read the BAR manually. + */ + plat = dev_get_platdata(dev); + plat->base = dm_pci_read_bar32(dev, 0); + } +#endif /* OF_PLATDATA */ + + return 0; +} + +static const struct udevice_id apl_ns16550_serial_ids[] = { + { .compatible = "intel,apl-ns16550" }, + { }, +}; + +U_BOOT_DRIVER(apl_ns16550) = { + .name = "intel_apl_ns16550", + .id = UCLASS_SERIAL, + .of_match = apl_ns16550_serial_ids, + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .ops = &ns16550_serial_ops, + .ofdata_to_platdata = apl_ns16550_ofdata_to_platdata, + .probe = apl_ns16550_probe, +}; diff --git a/arch/x86/include/asm/arch-apollolake/uart.h b/arch/x86/include/asm/arch-apollolake/uart.h new file mode 100644 index 00000000000..521316d0a93 --- /dev/null +++ b/arch/x86/include/asm/arch-apollolake/uart.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __ASM_ARCH_UART_H +#define __ASM_ARCH_UART_H + +/** + * apl_uart_init() - Set up the APL UART device and clock + * + * The UART won't actually work unless the GPIO settings are correct and the + * signals actually exit the SoC. See init_for_uart() for that. + */ +int apl_uart_init(pci_dev_t bdf, ulong base); + +#endif