From patchwork Sun Sep 6 21:43:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1358469 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=2a01:238:438b:c500:173d:9f52:ddab:ee01; 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=NhLwSmKf; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (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 4Bl4ky2XRQz9sSn for ; Mon, 7 Sep 2020 07:47:22 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0AEA382428; Sun, 6 Sep 2020 23:44:47 +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="NhLwSmKf"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 96024823F8; Sun, 6 Sep 2020 23:44:34 +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-il1-x142.google.com (mail-il1-x142.google.com [IPv6:2607:f8b0:4864:20::142]) (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 28906823D9 for ; Sun, 6 Sep 2020 23:44:31 +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-il1-x142.google.com with SMTP id a8so5174876ilk.1 for ; Sun, 06 Sep 2020 14:44:31 -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=BUXDAl+iRy2ezSIGHCyCuD6/G7ExXpWPTmDLWKnatAc=; b=NhLwSmKfnicDt+chH1AUy2c2zEHmnCgCZGl09schlueZ3eouqyR3Z6BkGci1p2TisG BkAFcd9/V0FdY2t04IJSt+S/Wl8DqWAbIRj0L/SAlxsCQiKDEukEDzMtoKGa4mDgSGU/ EfmDfqotbQVfxkBqOU8Y7Ahygejt6OjCpPRlg= 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=BUXDAl+iRy2ezSIGHCyCuD6/G7ExXpWPTmDLWKnatAc=; b=OK0IQGyv5VVQqhHGJ4nbICiA5k3CISa4qeDmASDZGGiRUdLEfX9YC2bLOZ8KDjiwVy ttispRk6PTgcRfRJk3ydczgJ16p+eu4IM8kKDHdkJPtKQKeJ1vL22IjDHeNNhnFJeWhZ REriro+hLob42585C7pWcC7Z0xvntc4+NygJVda31B5BoevlOmVO1SnHRDPHgmMfvFmC tmW3dHguQtBZfLL5oagR/giCFs4k7qhTJaGnBNE1jxWeAD0vA8/zVZ4ZHNV1yZkY4NnT tapbrK5Px5lI6m6LvLtmWDj52H6E0MzmIFzxcFliAmCQnaeOZ52gCh4T6CZ+Of762xZM n0Dg== X-Gm-Message-State: AOAM532TDkTyg7BMKgq8bgTf+7Jd2gHAfdB52kfKPxinL0hE2at0O3ue IGcLnsdvtZ1YjbAh6zgqSbd0JGWHeE2w1eqh X-Google-Smtp-Source: ABdhPJwPxeCRnkiZR1ZwXZ/bW1uqV7TEHtkA+ga+8QJJELXv2cje8q+WNknqEGYTUE20xaIql8i8Dg== X-Received: by 2002:a92:ba45:: with SMTP id o66mr14476175ili.38.1599428669818; Sun, 06 Sep 2020 14:44:29 -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 w13sm6232663iox.10.2020.09.06.14.44.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Sep 2020 14:44:29 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Wolfgang Wallner , Bin Meng , Bernhard Messerklinger , Andy Shevchenko , Simon Glass Subject: [PATCH v3 13/57] acpi: Support generating a multi-function _DSM for devices Date: Sun, 6 Sep 2020 15:43:21 -0600 Message-Id: <20200906214405.71632-4-sjg@chromium.org> X-Mailer: git-send-email 2.28.0.526.ge36021eeef-goog In-Reply-To: <20200906214405.71632-1-sjg@chromium.org> References: <20200906214405.71632-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 generate ACPI code for a _DSM method for a device. This includes functions for starting and ending each part of the _DSM. Signed-off-by: Simon Glass --- (no changes since v1) include/acpi/acpi_device.h | 14 +++++ include/acpi/acpigen.h | 99 +++++++++++++++++++++++++++++ lib/acpi/acpi_device.c | 43 +++++++++++++ lib/acpi/acpigen.c | 54 ++++++++++++++++ test/dm/acpigen.c | 126 +++++++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h index 11461e168d3..a5b12217820 100644 --- a/include/acpi/acpi_device.h +++ b/include/acpi/acpi_device.h @@ -28,6 +28,9 @@ struct udevice; /* Length of a full path to an ACPI device */ #define ACPI_PATH_MAX 30 +/* UUID for an I2C _DSM method */ +#define ACPI_DSM_I2C_HID_UUID "3cdff6f7-4267-4555-ad05-b30a3d8938de" + /* Values that can be returned for ACPI device _STA method */ enum acpi_dev_status { ACPI_DSTATUS_PRESENT = BIT(0), @@ -319,6 +322,17 @@ 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_dsm_i2c_hid() - Write a device-specific method for HID + * + * This writes a DSM for an I2C Human-Interface Device based on the config + * provided + * + * @hid_desc_reg_offset: HID register offset + */ +int acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx, + int hid_desc_reg_offset); + /** * acpi_device_write_i2c_dev() - Write an I2C device to ACPI * diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h index fa9409e3528..34b3115bc9c 100644 --- a/include/acpi/acpigen.h +++ b/include/acpi/acpigen.h @@ -666,4 +666,103 @@ void acpigen_write_return_singleton_buffer(struct acpi_ctx *ctx, uint arg); */ void acpigen_write_return_byte(struct acpi_ctx *ctx, uint arg); +/** + * acpigen_write_dsm_start() - Start a _DSM method + * + * Generate ACPI AML code to start the _DSM method. + * + * The functions need to be called in the correct sequence as below. + * + * Within the region, Local0 and Local1 must be are left + * untouched, but Local2-Local7 can be used + * + * Arguments passed into _DSM method: + * Arg0 = UUID + * Arg1 = Revision + * Arg2 = Function index + * Arg3 = Function-specific arguments + * + * AML code generated looks like this: + * Method (_DSM, 4, Serialized) { -- acpigen_write_dsm_start) + * ToBuffer (Arg0, Local0) + * If (LEqual (Local0, ToUUID(uuid))) { -- acpigen_write_dsm_uuid_start + * ToInteger (Arg2, Local1) + * If (LEqual (Local1, 0)) { -- acpigen_write_dsm_uuid_start_cond + * + * } -- acpigen_write_dsm_uuid_end_cond + * ... + * If (LEqual (Local1, n)) { -- acpigen_write_dsm_uuid_start_cond + * + * } -- acpigen_write_dsm_uuid_end_cond + * Return (Buffer (One) { 0x0 }) + * } -- acpigen_write_dsm_uuid_end + * ... + * If (LEqual (Local0, ToUUID(uuidn))) { + * ... + * } + * Return (Buffer (One) { 0x0 }) -- acpigen_write_dsm_end + * } + * + * @ctx: ACPI context pointer + */ +void acpigen_write_dsm_start(struct acpi_ctx *ctx); + +/** + * acpigen_write_dsm_uuid_start() - Start a new UUID block + * + * This starts generation of code to handle a particular UUID: + * + * If (LEqual (Local0, ToUUID(uuid))) { + * ToInteger (Arg2, Local1) + * + * @ctx: ACPI context pointer + */ +int acpigen_write_dsm_uuid_start(struct acpi_ctx *ctx, const char *uuid); + +/** + * acpigen_write_dsm_uuid_start_cond() - Start a new condition block + * + * This starts generation of condition-checking code to handle a particular + * function: + * + * If (LEqual (Local1, i)) + * + * @ctx: ACPI context pointer + */ +void acpigen_write_dsm_uuid_start_cond(struct acpi_ctx *ctx, int seq); + +/** + * acpigen_write_dsm_uuid_end_cond() - Start a new condition block + * + * This ends generation of condition-checking code to handle a particular + * function: + * + * } + * + * @ctx: ACPI context pointer + */ +void acpigen_write_dsm_uuid_end_cond(struct acpi_ctx *ctx); + +/** + * acpigen_write_dsm_uuid_end() - End a UUID block + * + * This ends generation of code to handle a particular UUID: + * + * Return (Buffer (One) { 0x0 }) + * + * @ctx: ACPI context pointer + */ +void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx); + +/** + * acpigen_write_dsm_end() - End a _DSM method + * + * This ends generates of the _DSM block: + * + * Return (Buffer (One) { 0x0 }) + * + * @ctx: ACPI context pointer + */ +void acpigen_write_dsm_end(struct acpi_ctx *ctx); + #endif diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c index 3c75b6d9629..8248664a10a 100644 --- a/lib/acpi/acpi_device.c +++ b/lib/acpi/acpi_device.c @@ -487,6 +487,49 @@ int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val, return 0; } +int acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx, + int hid_desc_reg_offset) +{ + int ret; + + acpigen_write_dsm_start(ctx); + ret = acpigen_write_dsm_uuid_start(ctx, ACPI_DSM_I2C_HID_UUID); + if (ret) + return log_ret(ret); + + acpigen_write_dsm_uuid_start_cond(ctx, 0); + /* ToInteger (Arg1, Local2) */ + acpigen_write_to_integer(ctx, ARG1_OP, LOCAL2_OP); + /* If (LEqual (Local2, 0x0)) */ + acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x0); + /* Return (Buffer (One) { 0x1f }) */ + acpigen_write_return_singleton_buffer(ctx, 0x1f); + acpigen_pop_len(ctx); /* Pop : If */ + /* Else */ + acpigen_write_else(ctx); + /* If (LEqual (Local2, 0x1)) */ + acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x1); + /* Return (Buffer (One) { 0x3f }) */ + acpigen_write_return_singleton_buffer(ctx, 0x3f); + acpigen_pop_len(ctx); /* Pop : If */ + /* Else */ + acpigen_write_else(ctx); + /* Return (Buffer (One) { 0x0 }) */ + acpigen_write_return_singleton_buffer(ctx, 0x0); + acpigen_pop_len(ctx); /* Pop : Else */ + acpigen_pop_len(ctx); /* Pop : Else */ + acpigen_write_dsm_uuid_end_cond(ctx); + + acpigen_write_dsm_uuid_start_cond(ctx, 1); + acpigen_write_return_byte(ctx, hid_desc_reg_offset); + acpigen_write_dsm_uuid_end_cond(ctx); + + acpigen_write_dsm_uuid_end(ctx); + acpigen_write_dsm_end(ctx); + + return 0; +} + /* 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) diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c index 2518bf83dda..d859f378413 100644 --- a/lib/acpi/acpigen.c +++ b/lib/acpi/acpigen.c @@ -609,6 +609,60 @@ void acpigen_write_return_byte(struct acpi_ctx *ctx, uint arg) acpigen_write_byte(ctx, arg); } +void acpigen_write_dsm_start(struct acpi_ctx *ctx) +{ + /* Method (_DSM, 4, Serialized) */ + acpigen_write_method_serialized(ctx, "_DSM", 4); + + /* ToBuffer (Arg0, Local0) */ + acpigen_write_to_buffer(ctx, ARG0_OP, LOCAL0_OP); +} + +int acpigen_write_dsm_uuid_start(struct acpi_ctx *ctx, const char *uuid) +{ + int ret; + + /* If (LEqual (Local0, ToUUID(uuid))) */ + acpigen_write_if(ctx); + acpigen_emit_byte(ctx, LEQUAL_OP); + acpigen_emit_byte(ctx, LOCAL0_OP); + ret = acpigen_write_uuid(ctx, uuid); + if (ret) + return log_msg_ret("uuid", ret); + + /* ToInteger (Arg2, Local1) */ + acpigen_write_to_integer(ctx, ARG2_OP, LOCAL1_OP); + + return 0; +} + +void acpigen_write_dsm_uuid_start_cond(struct acpi_ctx *ctx, int seq) +{ + /* If (LEqual (Local1, i)) */ + acpigen_write_if_lequal_op_int(ctx, LOCAL1_OP, seq); +} + +void acpigen_write_dsm_uuid_end_cond(struct acpi_ctx *ctx) +{ + acpigen_pop_len(ctx); /* If */ +} + +void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx) +{ + /* Default case: Return (Buffer (One) { 0x0 }) */ + acpigen_write_return_singleton_buffer(ctx, 0x0); + + acpigen_pop_len(ctx); /* If (LEqual (Local0, ToUUID(uuid))) */ +} + +void acpigen_write_dsm_end(struct acpi_ctx *ctx) +{ + /* Return (Buffer (One) { 0x0 }) */ + acpigen_write_return_singleton_buffer(ctx, 0x0); + + acpigen_pop_len(ctx); /* Method _DSM */ +} + /** * acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5 * diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c index cce19f11209..381fcb97022 100644 --- a/test/dm/acpigen.c +++ b/test/dm/acpigen.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1218,3 +1219,128 @@ static int dm_test_acpi_write_return(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_write_return, 0); + +/* Test emitting a DSM for an I2C HID */ +static int dm_test_acpi_write_i2c_dsm(struct unit_test_state *uts) +{ + char uuid_str[UUID_STR_LEN + 1]; + const int reg_offset = 0x20; + struct acpi_ctx *ctx; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_device_write_dsm_i2c_hid(ctx, reg_offset)); + + /* acpigen_write_dsm_start() */ + ut_asserteq(METHOD_OP, *ptr++); + ut_asserteq(0x78, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq_strn("_DSM", (char *)ptr); + ptr += 4; + ut_asserteq(ACPI_METHOD_SERIALIZED_MASK | 4, *ptr++); + + ut_asserteq(TO_BUFFER_OP, *ptr++); + ut_asserteq(ARG0_OP, *ptr++); + ut_asserteq(LOCAL0_OP, *ptr++); + + /* acpigen_write_dsm_uuid_start() */ + ut_asserteq(IF_OP, *ptr++); + ut_asserteq(0x65, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(LEQUAL_OP, *ptr++); + ut_asserteq(LOCAL0_OP, *ptr++); + + ut_asserteq(BUFFER_OP, *ptr++); + ut_asserteq(UUID_BIN_LEN + 6, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(WORD_PREFIX, *ptr++); + ut_asserteq(UUID_BIN_LEN, get_unaligned((u16 *)ptr)); + ptr += 2; + uuid_bin_to_str(ptr, uuid_str, UUID_STR_FORMAT_GUID); + ut_asserteq_str(ACPI_DSM_I2C_HID_UUID, uuid_str); + ptr += UUID_BIN_LEN; + + ut_asserteq(TO_INTEGER_OP, *ptr++); + ut_asserteq(ARG2_OP, *ptr++); + ut_asserteq(LOCAL1_OP, *ptr++); + + /* acpigen_write_dsm_uuid_start_cond() */ + ut_asserteq(IF_OP, *ptr++); + ut_asserteq(0x34, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(LEQUAL_OP, *ptr++); + ut_asserteq(LOCAL1_OP, *ptr++); + ut_asserteq(ZERO_OP, *ptr++); + + /* + * See code from acpi_device_write_dsm_i2c_hid(). We don't check every + * piece + */ + ut_asserteq(TO_INTEGER_OP, *ptr++); + ut_asserteq(ARG1_OP, *ptr++); + ut_asserteq(LOCAL2_OP, *ptr++); + + ut_asserteq(IF_OP, *ptr++); + ut_asserteq(0xd, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(LEQUAL_OP, *ptr++); + ut_asserteq(LOCAL2_OP, *ptr++); + ut_asserteq(ZERO_OP, *ptr++); /* function 0 */ + + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BUFFER_OP, *ptr++); + ptr += 5; + + ut_asserteq(ELSE_OP, *ptr++); + ptr += 3; + + ut_asserteq(IF_OP, *ptr++); + ut_asserteq(0xd, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(LEQUAL_OP, *ptr++); + ut_asserteq(LOCAL2_OP, *ptr++); + ut_asserteq(ONE_OP, *ptr++); + + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BUFFER_OP, *ptr++); + ptr += 5; + + ut_asserteq(ELSE_OP, *ptr++); + ptr += 3; + + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BUFFER_OP, *ptr++); + ptr += 5; + + /* acpigen_write_dsm_uuid_start_cond() */ + ut_asserteq(IF_OP, *ptr++); + ut_asserteq(9, acpi_test_get_length(ptr)); + ptr += 3; + ut_asserteq(LEQUAL_OP, *ptr++); + ut_asserteq(LOCAL1_OP, *ptr++); + ut_asserteq(ONE_OP, *ptr++); /* function 1 */ + + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BYTE_PREFIX, *ptr++); + ut_asserteq(reg_offset, *ptr++); + + /* acpigen_write_dsm_uuid_end() */ + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BUFFER_OP, *ptr++); + ptr += 5; + + /* acpigen_write_dsm_end */ + ut_asserteq(RETURN_OP, *ptr++); + ut_asserteq(BUFFER_OP, *ptr++); + ptr += 5; + + ut_asserteq_ptr(ptr, ctx->current); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_write_i2c_dsm, 0); +