From patchwork Tue Jul 7 19:11:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1324668 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=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=GSyd7ZEh; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4B1XGh2RQyz9s1x for ; Wed, 8 Jul 2020 05:16:12 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0CF5A821AC; Tue, 7 Jul 2020 21:13:13 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="GSyd7ZEh"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8685582013; Tue, 7 Jul 2020 21:12:54 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd43.google.com (mail-io1-xd43.google.com [IPv6:2607:f8b0:4864:20::d43]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E3FDA81D39 for ; Tue, 7 Jul 2020 21:12:50 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd43.google.com with SMTP id e64so39464270iof.12 for ; Tue, 07 Jul 2020 12:12:50 -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=Yp9zWJUis5/CPjbjl7HzNURJpx5l/lsdcF8CvoRenb0=; b=GSyd7ZEhFHZXrIr+o8lLUdhw57tYoxNyl98szWdxODVqdUbtyyfhVv2wySM9pXSW6g oOMFvdQ0F/ep+D9BJ6SmIRnl/EqkkWXrBox6CHZdU30TTpXFcLqD6Pv8vdF68UM6bVtl m9kzNfCB8gJYGA1KatJTBOtmlrmU8jyoWNxQo= 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=Yp9zWJUis5/CPjbjl7HzNURJpx5l/lsdcF8CvoRenb0=; b=caWkgzkTGgrsB0WXLtVYKL+aOi0tn3aFT3CjrGHgZU+HIbIV7FKONqdLIEpcHFrSq9 ZoWjTCbNIX48to/JpW3hqW2+DwbZFei5zJoNp/Qx3i+qWmsJPEucMaYsZgt4Tey3/oZU zueSipvjfTOuimdkw30/VvcWTbTUpVykPpp5Q74K0GOV38ReXdt/JkhQu2y+EPwXbv3F 9C6IAp3nqLWaulKz8twSa8Esh2E2bCA1JcFawieNuSbywsNCzdhIUkra7UzYhkMbUjrP WnRbi6H9ebjJju/2M/G549B1P2Up03MVecytmj48vXgvRv5gQ9dAaGVqZwovNJea39SZ 2/sg== X-Gm-Message-State: AOAM5331P/Fdivazf5BucuNUDl7xKYk33TJHlmNNxF79os1FVj0NI9LU jaRJKpjTurtnnaDs/CIri9FJpoMkiL/ADg== X-Google-Smtp-Source: ABdhPJynjAUTIZqwAylRsAYDMM4HXHHJX0YNLWRWr4H53YheI/g0bhN1icNayTpE74lAtqrt+VtAgw== X-Received: by 2002:a6b:1885:: with SMTP id 127mr17017808ioy.17.1594149169539; Tue, 07 Jul 2020 12:12:49 -0700 (PDT) Received: from localhost.localdomain (c-73-14-175-90.hsd1.co.comcast.net. [73.14.175.90]) by smtp.gmail.com with ESMTPSA id 186sm9584320iow.26.2020.07.07.12.12.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Jul 2020 12:12:49 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Andy Shevchenko , Bin Meng , Wolfgang Wallner , Simon Glass Subject: [PATCH v4 11/35] acpi: Support generation of I2C descriptor Date: Tue, 7 Jul 2020 13:11:48 -0600 Message-Id: <20200707131135.v4.11.I9a92f5e4d3361484afce57b3afff40a3119a6103@changeid> X-Mailer: git-send-email 2.27.0.383.g050319c2ae-goog In-Reply-To: <20200707191212.2542638-1-sjg@chromium.org> References: <20200707191212.2542638-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 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" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Add a function to write a GPIO descriptor to the generated ACPI code. Reviewed-by: Wolfgang Wallner Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- Changes in v4: - Move SPI macros to next patch - Rename the length-writing functions to indicate they are for large - Update functions to return GPIO/IRQ pin number Changes in v3: - Update comment in acpi_device_set_i2c() to talk about scope parameter Changes in v2: - Fix memset of I2C descriptor drivers/i2c/sandbox_i2c.c | 11 ++++ drivers/rtc/sandbox_rtc.c | 13 +++++ include/acpi/acpi_device.h | 33 ++++++++++++ lib/acpi/acpi_device.c | 107 +++++++++++++++++++++++++++++++++++++ test/dm/acpigen.c | 32 +++++++++++ 5 files changed, 196 insertions(+) diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index f4ae2397a0..125026da90 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,15 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, return ops->xfer(emul, msg, nmsgs); } +static int sandbox_i2c_get_name(const struct udevice *dev, char *out_name) +{ + return acpi_copy_name(out_name, "SI2C"); +} + +struct acpi_ops sandbox_i2c_acpi_ops = { + .get_name = sandbox_i2c_get_name, +}; + static const struct dm_i2c_ops sandbox_i2c_ops = { .xfer = sandbox_i2c_xfer, }; @@ -98,4 +108,5 @@ U_BOOT_DRIVER(i2c_sandbox) = { .of_match = sandbox_i2c_ids, .ops = &sandbox_i2c_ops, .priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv), + ACPI_OPS_PTR(&sandbox_i2c_acpi_ops) }; diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c index b08d758a74..f2906c3397 100644 --- a/drivers/rtc/sandbox_rtc.c +++ b/drivers/rtc/sandbox_rtc.c @@ -9,6 +9,7 @@ #include #include #include +#include #define REG_COUNT 0x80 @@ -84,6 +85,17 @@ static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val) return dm_i2c_reg_write(dev, reg, val); } +#if CONFIG_IS_ENABLED(ACPIGEN) +static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name) +{ + return acpi_copy_name(out_name, "RTCC"); +} + +struct acpi_ops sandbox_rtc_acpi_ops = { + .get_name = sandbox_rtc_get_name, +}; +#endif + static const struct rtc_ops sandbox_rtc_ops = { .get = sandbox_rtc_get, .set = sandbox_rtc_set, @@ -102,4 +114,5 @@ U_BOOT_DRIVER(rtc_sandbox) = { .id = UCLASS_RTC, .of_match = sandbox_rtc_ids, .ops = &sandbox_rtc_ops, + ACPI_OPS_PTR(&sandbox_rtc_acpi_ops) }; diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h index c8b72e0d75..9ba395771e 100644 --- a/include/acpi/acpi_device.h +++ b/include/acpi/acpi_device.h @@ -9,6 +9,7 @@ #ifndef __ACPI_DEVICE_H #define __ACPI_DEVICE_H +#include #include struct acpi_ctx; @@ -183,6 +184,26 @@ struct acpi_gpio { enum acpi_gpio_polarity polarity; }; +/* ACPI Descriptors for Serial Bus interfaces */ +#define ACPI_SERIAL_BUS_TYPE_I2C 1 +#define ACPI_I2C_SERIAL_BUS_REVISION_ID 1 /* TODO: upgrade to 2 */ +#define ACPI_I2C_TYPE_SPECIFIC_REVISION_ID 1 + +/** + * struct acpi_i2c - representation of an ACPI I2C device + * + * @address: 7-bit or 10-bit I2C address + * @mode_10bit: Which address size is used + * @speed: Bus speed in Hz + * @resource: Resource name for the I2C controller + */ +struct acpi_i2c { + u16 address; + enum i2c_address_mode mode_10bit; + enum i2c_speed_rate speed; + const char *resource; +}; + /** * acpi_device_path() - Get the full path to an ACPI device * @@ -270,4 +291,16 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx, int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx, struct udevice *dev, const char *prop); +/** + * acpi_device_write_i2c_dev() - Write an I2C device to ACPI + * + * This creates a I2cSerialBus descriptor for an I2C device, including + * information ACPI needs to use it. + * + * @ctx: ACPI context pointer + * @dev: I2C device to write + * @return I2C address of device if OK, -ve on error + */ +int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev); + #endif diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c index c93af2e583..c0d5a9acae 100644 --- a/lib/acpi/acpi_device.c +++ b/lib/acpi/acpi_device.c @@ -385,3 +385,110 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx, return pin; } + +/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */ +static void acpi_device_write_i2c(struct acpi_ctx *ctx, + const struct acpi_i2c *i2c) +{ + void *desc_length, *type_length; + + /* Byte 0: Descriptor Type */ + acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_SERIAL_BUS); + + /* Byte 1+2: Length (filled in later) */ + desc_length = largeres_write_len_f(ctx); + + /* Byte 3: Revision ID */ + acpigen_emit_byte(ctx, ACPI_I2C_SERIAL_BUS_REVISION_ID); + + /* Byte 4: Resource Source Index is Reserved */ + acpigen_emit_byte(ctx, 0); + + /* Byte 5: Serial Bus Type is I2C */ + acpigen_emit_byte(ctx, ACPI_SERIAL_BUS_TYPE_I2C); + + /* + * Byte 6: Flags + * [7:2]: 0 => Reserved + * [1]: 1 => ResourceConsumer + * [0]: 0 => ControllerInitiated + */ + acpigen_emit_byte(ctx, 1 << 1); + + /* + * Byte 7-8: Type Specific Flags + * [15:1]: 0 => Reserved + * [0]: 0 => 7bit, 1 => 10bit + */ + acpigen_emit_word(ctx, i2c->mode_10bit); + + /* Byte 9: Type Specific Revision ID */ + acpigen_emit_byte(ctx, ACPI_I2C_TYPE_SPECIFIC_REVISION_ID); + + /* Byte 10-11: I2C Type Data Length */ + type_length = largeres_write_len_f(ctx); + + /* Byte 12-15: I2C Bus Speed */ + acpigen_emit_dword(ctx, i2c->speed); + + /* Byte 16-17: I2C Slave Address */ + acpigen_emit_word(ctx, i2c->address); + + /* Fill in Type Data Length */ + largeres_fill_len(ctx, type_length); + + /* Byte 18+: ResourceSource */ + acpigen_emit_string(ctx, i2c->resource); + + /* Fill in I2C Descriptor Length */ + largeres_fill_len(ctx, desc_length); +} + +/** + * acpi_device_set_i2c() - Set up an ACPI I2C struct from a device + * + * The value of @scope is not copied, but only referenced. This implies the + * caller has to ensure it stays valid for the lifetime of @i2c. + * + * @dev: I2C device to convert + * @i2c: Place to put the new structure + * @scope: Scope of the I2C device (this is the controller path) + * @return chip address of device + */ +static int acpi_device_set_i2c(const struct udevice *dev, struct acpi_i2c *i2c, + const char *scope) +{ + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + struct udevice *bus = dev_get_parent(dev); + + memset(i2c, '\0', sizeof(*i2c)); + i2c->address = chip->chip_addr; + i2c->mode_10bit = 0; + + /* + * i2c_bus->speed_hz is set if this device is probed, but if not we + * must use the device tree + */ + i2c->speed = dev_read_u32_default(bus, "clock-frequency", + I2C_SPEED_STANDARD_RATE); + i2c->resource = scope; + + return i2c->address; +} + +int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev) +{ + char scope[ACPI_PATH_MAX]; + struct acpi_i2c i2c; + int ret; + + ret = acpi_device_scope(dev, scope, sizeof(scope)); + if (ret) + return log_msg_ret("scope", ret); + ret = acpi_device_set_i2c(dev, &i2c, scope); + if (ret < 0) + return log_msg_ret("set", ret); + acpi_device_write_i2c(ctx, &i2c); + + return ret; +} diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c index 7d81652295..c210ceb404 100644 --- a/test/dm/acpigen.c +++ b/test/dm/acpigen.c @@ -276,3 +276,35 @@ static int dm_test_acpi_interrupt_or_gpio(struct unit_test_state *uts) } DM_TEST(dm_test_acpi_interrupt_or_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test emitting an I2C descriptor */ +static int dm_test_acpi_i2c(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct udevice *dev; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + ptr = acpigen_get_current(ctx); + + ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev)); + ut_asserteq(0x43, acpi_device_write_i2c_dev(ctx, dev)); + ut_asserteq(28, acpigen_get_current(ctx) - ptr); + ut_asserteq(ACPI_DESCRIPTOR_SERIAL_BUS, ptr[0]); + ut_asserteq(25, get_unaligned((u16 *)(ptr + 1))); + ut_asserteq(ACPI_I2C_SERIAL_BUS_REVISION_ID, ptr[3]); + ut_asserteq(0, ptr[4]); + ut_asserteq(ACPI_SERIAL_BUS_TYPE_I2C, ptr[5]); + ut_asserteq(0, get_unaligned((u16 *)(ptr + 7))); + ut_asserteq(ACPI_I2C_TYPE_SPECIFIC_REVISION_ID, ptr[9]); + ut_asserteq(6, get_unaligned((u16 *)(ptr + 10))); + ut_asserteq(100000, get_unaligned((u32 *)(ptr + 12))); + ut_asserteq(0x43, get_unaligned((u16 *)(ptr + 16))); + ut_asserteq_str("\\_SB.I2C0", (char *)ptr + 18); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_i2c, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);