From patchwork Sun Mar 19 18:59:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 740741 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3vmT9b6jZSz9s3l for ; Mon, 20 Mar 2017 06:07:47 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="aC+h7oO7"; dkim-atps=neutral Received: by lists.denx.de (Postfix, from userid 105) id A47E5C21C71; Sun, 19 Mar 2017 19:01:20 +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_H3, RCVD_IN_MSPIKE_WL, 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 AA0A0C21C79; Sun, 19 Mar 2017 19:00:29 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 7A171C21C70; Sun, 19 Mar 2017 19:00:01 +0000 (UTC) Received: from mail-ot0-f176.google.com (mail-ot0-f176.google.com [74.125.82.176]) by lists.denx.de (Postfix) with ESMTPS id BD18BC21C66 for ; Sun, 19 Mar 2017 18:59:57 +0000 (UTC) Received: by mail-ot0-f176.google.com with SMTP id x37so121466198ota.2 for ; Sun, 19 Mar 2017 11:59:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=Z5eNVV6epVEt+8o+2VcRNQAndaltdG3w6PY2Kp1Tykw=; b=aC+h7oO7kOJGRHeH1uxSVs6+r1RlP+eoidgYLtEaacIXgX2vU1SKK+3ul3KIzcPQJz xyBXK9Pm7HhGAox8ROAQmdHTcyFv9M1FlFINBt1KZcx2WmySut/4t0oycTOyy//G46qI EAkLq1g4DnqluVcOXjo6/IZQEOoG19fNTOvc3IDm12ZvK5Q0T92vUvyQSPF9u4p3doXW Vs7rzFNDZJImTc458a0eRcuvAwCVB/6a07sPCNVVSXNIWW34qj006+iHVxB16DdSA3eQ xRlwLonNTScJflv3BcjttuN4mnojncisj4CgYqvebWuTtIGBcOJvAEPwup1KkB4PRmmt wKzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=Z5eNVV6epVEt+8o+2VcRNQAndaltdG3w6PY2Kp1Tykw=; b=rANbe+QC6m0A8dZlhYQNCW2bBUkOWvflpk5lnoJWjnmBysnoFgAnP42ClcNhsKENkj E6ZyY7VG0soo4Wg/SNu/GKzB7LzlvUYPgaHtB71FLxma8tbCnSoWUlcHYMNG6+NGi+iD 4JP2KnuCtfsgpgITfozeyFJAVMTFDMd5aUTDJTfiwg3O6xTfnuJ4WP7PNeFpYvXG0JWD 2j8pZCufxEEAJS5USx1upGGnZVWlKA/1Zs2gp5wR6HOeE+gjR5bpij11xkXG+umH7WT6 0fbFyHxrMn2N9/xQLWwjy/+Y2cNmTHsVEpiLPFyhh+Nhx7UWCybU+paOEp/OMTICXBaI vKIQ== X-Gm-Message-State: AFeK/H1WrJ/I7avzlPoRWgdnQAPdUADgvhg5OKp9KZxCJ4QxGu8hkgPWl0lFT6YWZEZudJor X-Received: by 10.157.12.209 with SMTP id o17mr12159732otd.94.1489949996352; Sun, 19 Mar 2017 11:59:56 -0700 (PDT) Received: from kaki.bld.corp.google.com ([100.100.184.105]) by smtp.gmail.com with ESMTPSA id o6sm6602652oig.8.2017.03.19.11.59.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 19 Mar 2017 11:59:55 -0700 (PDT) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 1F9FF40083; Sun, 19 Mar 2017 12:59:55 -0600 (MDT) From: Simon Glass To: U-Boot Mailing List Date: Sun, 19 Mar 2017 12:59:23 -0600 Message-Id: <20170319185935.20950-5-sjg@chromium.org> X-Mailer: git-send-email 2.12.0.367.g23dc2f6d3c-goog In-Reply-To: <20170319185935.20950-1-sjg@chromium.org> References: <20170319185935.20950-1-sjg@chromium.org> Cc: Tom Rini , Michal Simek , Jagan Teki Subject: [U-Boot] [PATCH 04/16] dm: board: Add a uclass for init functions 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: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add a uclass to handle board init. This allows drivers to be provided to perform the various phases of init. Functions are provided to call all devices that can handle a particular phase. Signed-off-by: Simon Glass --- common/Kconfig | 31 +++++++ common/init/Makefile | 1 + common/init/board-uclass.c | 108 ++++++++++++++++++++++++ include/asm-generic/global_data.h | 5 ++ include/board.h | 170 ++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 6 files changed, 316 insertions(+) create mode 100644 common/init/board-uclass.c create mode 100644 include/board.h diff --git a/common/Kconfig b/common/Kconfig index 8f73c8f757..7d2bd15371 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -395,6 +395,36 @@ config DISPLAY_BOARDINFO menu "Start-up hooks" +config BOARD + bool "Support using driver model for board start-up hooks, etc." + help + This adds support for the board uclass and associated functions. With + this you can create and use BOARD drivers. However unless + BOARD_ENABLE is also set, the existing init sequence will continue + to be used. This is designed to ease migration of boards, since + support for both methods can be provided during the transition + period. + +config SPL_BOARD + bool "Support using driver model for board start-up hooks, etc. in SPL" + help + This adds support for the board uclass and associated functions in + SPL. With this you can create and use BOARD drivers. However unless + BOARD_ENABLE is also set, the existing init sequence will continue + to be used. This is designed to ease migration of boards, since + support for both methods can be provided during the transition + period. + +config BOARD_ENABLE + bool "Use driver model instead of ad-hoc board init functions" + depends on BOARD + help + This replaces the ad-hoc start-up functions like board_early_init_f() + with a driver-model-based interface. With this enabled, boards + provide one or more drivers which implement these phases of init as + well as access to the board decription. Existing init functions are + no-longer called. + config ARCH_EARLY_INIT_R bool "Call arch-specific init soon after relocation" default y if X86 @@ -414,6 +444,7 @@ config ARCH_MISC_INIT config BOARD_EARLY_INIT_F bool "Call board-specific init before relocation" + depends on !BOARD_ENABLE default y if X86 help Some boards need to perform initialisation as soon as possible diff --git a/common/init/Makefile b/common/init/Makefile index 4902635f53..923ce8e139 100644 --- a/common/init/Makefile +++ b/common/init/Makefile @@ -5,3 +5,4 @@ # obj-y += board_init.o +obj-$(CONFIG_$(SPL_)BOARD) += board-uclass.o diff --git a/common/init/board-uclass.c b/common/init/board-uclass.c new file mode 100644 index 0000000000..2ca65f44da --- /dev/null +++ b/common/init/board-uclass.c @@ -0,0 +1,108 @@ +/* + * Board driver interface + * + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int board_phase(struct udevice *dev, enum board_phase_t phase) +{ + struct board_uc_priv *priv = dev_get_uclass_priv(dev); + struct board_ops *ops = board_get_ops(dev); + + if (!ops->phase) + return -ENOSYS; + if (!priv->phase_mask && phase == BOARD_PHASE_FIRST) { + printf("Device '%s' supports no phases\n", dev->name); + return -EINVAL; + } + if (!(priv->phase_mask & board_phase_mask(phase))) + return -ENOSYS; + + return ops->phase(dev, phase); +} + +int board_walk_phase_count(enum board_phase_t phase, bool verbose) +{ + struct udevice *dev; + int count = 0; + int ret; + + for (ret = uclass_first_device(UCLASS_BOARD, &dev); + dev; + uclass_next_device(&dev)) { + ret = board_phase(dev, phase); + if (ret == 0) { + count++; + } else if (ret == BOARD_PHASE_CLAIMED) { + count++; + debug("Phase %d claimed by '%s'\n", phase, dev->name); + break; + } else if (ret != -ENOSYS) { + gd->phase_count[phase] += count; + return ret; + } + } + + if (!count) { + if (verbose) + printf("Unable to find driver for phase %d\n", phase); + return -ENOSYS; + } + gd->phase_count[phase] += count; + + return count; +} + +int board_walk_phase(enum board_phase_t phase) +{ + int ret; + + ret = board_walk_phase_count(phase, true); + if (ret < 0) + return ret; + + return 0; +} + +int board_walk_opt_phase(enum board_phase_t phase) +{ + int ret; + + ret = board_walk_phase_count(phase, false); + if (ret < 0 && ret != -ENOSYS) + return ret; + + return 0; +} + +int board_support_phase(struct udevice *dev, enum board_phase_t phase) +{ + struct board_uc_priv *priv = dev_get_uclass_priv(dev); + + priv->phase_mask |= board_phase_mask(phase); + + return 0; +} + +int board_support_phase_mask(struct udevice *dev, ulong phase_mask) +{ + struct board_uc_priv *priv = dev_get_uclass_priv(dev); + + priv->phase_mask = phase_mask; + + return 0; +} + +UCLASS_DRIVER(board) = { + .id = UCLASS_BOARD, + .name = "board", + .per_device_auto_alloc_size = sizeof(struct board_uc_priv), +}; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 5b356dd231..fea1e916ed 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -21,6 +21,7 @@ */ #ifndef __ASSEMBLY__ +#include #include #include @@ -107,6 +108,10 @@ typedef struct global_data { ulong video_top; /* Top of video frame buffer area */ ulong video_bottom; /* Bottom of video frame buffer area */ #endif +#ifdef CONFIG_BOARD + /* number of drivers which handled each phase */ + uint8_t phase_count[BOARD_PHASE_COUNT]; +#endif } gd_t; #endif diff --git a/include/board.h b/include/board.h new file mode 100644 index 0000000000..0975f5ac12 --- /dev/null +++ b/include/board.h @@ -0,0 +1,170 @@ +/* + * Board driver interface + * + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BOARD_H +#define __BOARD_H + +/* Include dm.h here because board.h comes before dm.h in include order */ +#include + +/* + * This file provides access to board drivers, which are responsible for + * initing the board as well as (in future) querying its state. + */ + +/* Phases of init - please update phase_name also */ +enum board_phase_t { + /* + * Pre-relocation phases. + * TODO(sjg@chromium.org): At present these are named the same as the + * functions they replace to avoid confusion. However this naming is + * not very consistent. At some point once enough boards uses this + * interface, we could rename some of these. + * + * TODO(sjg@chromium.org): arch_cpu_init() and mach_cpu_init() are + * called before driver model is ready so we cannot yet add them to + * this interface. Hopefully this can be adjusted later: + * BOARD_F_ARCH_CPU_INIT, + * BOARD_F_MACH_CPU_INIT, + */ + BOARD_PHASE_FIRST, + BOARD_F_ARCH_CPU_INIT_DM = BOARD_PHASE_FIRST, + BOARD_F_EARLY_INIT_F, + BOARD_F_CHECKCPU, + BOARD_F_MISC_INIT_F, + BOARD_F_DRAM_INIT, + BOARD_F_RESERVE_ARCH, + + /* + * Post-relocation phases go here: + * + * BOARD_R_... + */ + + BOARD_PHASE_TEST, /* For sandbox testing */ + BOARD_PHASE_COUNT, + BOARD_PHASE_INVALID, /* For sandbox testing */ +}; + +static inline ulong board_phase_mask(enum board_phase_t phase) +{ + return 1UL << (ulong)phase; +} + +/* + * Return this from phase() to indicate that no more devices should handle this + * phase + */ +#define BOARD_PHASE_CLAIMED EUSERS + +/* Operations for the board driver */ +struct board_ops { + /** + * phase() - Execute a phase of board init + * + * @dev: Device to use + * @phase: Phase to execute + * @return 0 if done, -ENOSYS if not supported (which is often fine), + BOARD_PHASE_CLAIMED if this was handled and that processing + of this phase should stop (i.e. do not send it to other + devices), other error if something went wrong + */ + int (*phase)(struct udevice *dev, enum board_phase_t phase); + + /** + * get_desc() - Get a description string for a board + * + * @dev: Device to check (UCLASS_BOARD) + * @buf: Buffer to place string + * @size: Size of string space + * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error + */ + int (*get_desc)(struct udevice *dev, char *buf, int size); +}; + +#define board_get_ops(dev) ((struct board_ops *)(dev)->driver->ops) + +/* Private uclass information about each device */ +struct board_uc_priv { + ulong phase_mask; /* Mask of phases supported by this device */ +}; + +/** + * board_phase() - Execute a phase of board init on a device + * + * @phase: Phase to execute + * @return 0 if done, -ENOSYS if not supported by this device, other error if + * something went wrong + */ +int board_phase(struct udevice *dev, enum board_phase_t phase); + +/** + * board_walk_phase() - Execute a phase of board init + * + * This works through the available board devices asking each one to perform + * the requested init phase. The process continues until there are no more + * board devices. + * + * If no board device provides the phase, this function returns -ENOSYS. + * + * @phase: Phase to execute + * @return 0 if done, -ENOSYS if not supported, other error if something went + * wrong + */ +int board_walk_phase(enum board_phase_t phase); + +/** + * board_opt_walk_phase() - Execute an optional phase of board init + * + * This works through the available board devices asking each one to perform + * the requested init phase. The process continues until there are no more + * board devices. + * + * If no board device provides the phase, this function returns 0. + * + * @phase: Phase to execute + * @return 0 if done, other error if something went wrong + */ +int board_walk_opt_phase(enum board_phase_t phase); + +/** + * board_walk_phase_count() - Execute an optional phase of board init + * + * This works through the available board devices asking each one to perform + * the requested init phase. The process continues until there are no more + * board devices. + * + * If no board provides the phase, this function returns -ENOSYS. + * + * @phase: Phase to execute + * @return number of devices which handled this phase if done, -ve error if + * something went wrong + */ +int board_walk_phase_count(enum board_phase_t phase, bool verbose); + +/** + * board_support_phase() - Mark a board device as supporting the given phase + * + * @dev: Board device + * @phase: Phase to execute + * @return 0 + */ +int board_support_phase(struct udevice *dev, enum board_phase_t phase); + +/** + * board_support_phase_mask() - Mark a board device as supporting given phases + * + * @dev: Board device + * @phase_mask: Mask of phases to execute, built up by ORing board_phase_mask() + * values together + * @return 0 + */ +int board_support_phase_mask(struct udevice *dev, ulong phase_mask); + +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 8c92d0b030..166194fead 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -27,6 +27,7 @@ enum uclass_id { /* U-Boot uclasses start here - in alphabetical order */ UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_AHCI, /* SATA disk controller */ + UCLASS_BOARD, /* Board-specific driver */ UCLASS_BLK, /* Block device */ UCLASS_CLK, /* Clock source, e.g. used by peripherals */ UCLASS_CPU, /* CPU, typically part of an SoC */