From patchwork Tue Jun 29 02:32:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng Fan \(OSS\)" X-Patchwork-Id: 468289 Delivered-To: patch@linaro.org Received: by 2002:a02:c94a:0:0:0:0:0 with SMTP id u10csp4510312jao; Mon, 28 Jun 2021 19:07:45 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxqL6mdbTZi051Yx+545lMv+kx5eKJ+WRU3a2+QPyPEqqUbFbNKIMPCOOpENXp6ogX7oCPW X-Received: by 2002:a17:907:98fa:: with SMTP id ke26mr26924558ejc.309.1624932465693; Mon, 28 Jun 2021 19:07:45 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1624932465; cv=pass; d=google.com; s=arc-20160816; b=PTs+JNtnYP1pi7eZ0barRKTH288hPxRvi6SV7LythX14Li3Y1+VXWMOG3cKc/1vHHt ztYn5oDFlbMDF2ojFYcxchkGCbHWgHEDZBSoU7pE0LLwudRxg15QdsXnNRxpGd+rfX0B 6uGIdZil/0efDum5ZImnHnHXrQJZx+jVTVW8K9X0WF7KsWWvUK6ITYR/u2DiuG87InBC ztU8uHuqlE/CVCre4hGJcA1Bs7KPp4R9BDEI7blbUuE1ql+IPEGSDOMsHIE39FzhNfrY LqcxPHxAMSxX2UGNxezTCoFUKGoGCEHcsChhbqxibfCJivcDP+e+srMrsuwpF5m+4s1T 9dKg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mime-version :content-transfer-encoding:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=Tzh443fN23JW65+0ZKNPTPvcMTJ1syY3CeOsdRCtvvs=; b=mI7OXCTVfG0JHGVp5uz9f7NGl4vE07BMxTKBVAKHC2Wm5IIYsDG3splvUosttIJopK W/oeKP9r5wDBGL00uKIFDrRHvveCGdsPGbdNT6W8p595xQKj+ON82iAjp0WeoojITi/K p7xea4VDloEe3i9RX/UlsmItBAgOF8nch0JrZSxusjNSx3t/3rzfwWLNbHUxgptyzsg0 y2SuWA34TwsH6zFxhsLmpr5bw7TF0pZJJY3lrXJ/OFUSVXqS5sMTnnLJDrAXGHNSkccK VQGEb8XTnHq6uWbBnoznyp1ewNOyJE0EBsF/5Bnljz6GaXfPA+RzTWV+9Eiq4TxgU0J/ EzTQ== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@NXP1.onmicrosoft.com header.s=selector2-NXP1-onmicrosoft-com header.b=Zl9PFreZ; arc=pass (i=1 spf=pass spfdomain=oss.nxp.com dkim=pass dkdomain=oss.nxp.com dmarc=pass fromdomain=oss.nxp.com); spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id g3si15532740eds.538.2021.06.28.19.07.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Jun 2021 19:07:45 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@NXP1.onmicrosoft.com header.s=selector2-NXP1-onmicrosoft-com header.b=Zl9PFreZ; arc=pass (i=1 spf=pass spfdomain=oss.nxp.com dkim=pass dkdomain=oss.nxp.com dmarc=pass fromdomain=oss.nxp.com); spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 17F1E831A8; Tue, 29 Jun 2021 04:01:57 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=oss.nxp.com 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=NXP1.onmicrosoft.com header.i=@NXP1.onmicrosoft.com header.b="Zl9PFreZ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8529483147; Tue, 29 Jun 2021 04:01:12 +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=-0.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FORGED_SPF_HELO,MSGID_FROM_MTA_HEADER,SPF_HELO_PASS autolearn=no autolearn_force=no version=3.4.2 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on20617.outbound.protection.outlook.com [IPv6:2a01:111:f400:7d00::617]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C50E883142 for ; Tue, 29 Jun 2021 04:01:03 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=oss.nxp.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=peng.fan@oss.nxp.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=a+IAK9xLEdmaHOiCvYtIiUexLJALVe50JT726NWzzcan0LjHbMVsU1somqhZkbBLsptHhEM2PN39km90Nxqt2b2Lawz/kuf1ZKjmTwwvwgf7oFw2aXfjoi3rCj0eQS7hMi0i3mbdzmwbVwzdBwGWnwe0Mod41RZ2h0OPENM5zj1m9rIiF+eY/jsm5nOiw+SInsJRUM7i4Zbw98y3duxfh7W1m8F6yCIpoM2Gh2R0UgjLzpJaBF/dXuW1+M8uJBCiteSoSD/QK7OQi3QpKi7q2iopcYY0PgL9VPs3TWXc+M/HLunsc7cG5ryETgav1Jvv7uiogBKM5PN1T9SsxYoqCw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Tzh443fN23JW65+0ZKNPTPvcMTJ1syY3CeOsdRCtvvs=; b=NkGYCli/ZTCw5qKaswXzzF+20zIQptQQzySZW6UtFeyN8NtWT9eIfgK9vzONQCosaIRIUCTkpQphzRXt6QzwCbQj2oz/9YCpIsZsnBcbtV6LGLZdmulVra3b7vqWYcHcC6AMkzMMjgp2GNFssD4mxHYbnSc9PaRaCoTPyAbU6s9PNg18AzK+wd/zcwOb94GcRsh7IOr041PZRAPl1JJNljDca8p1BCE1kPdwmdhEXTco//PFSTsMj29DO/nXd1WK9n9tOPT9HbVfzUf1x/xrmCOKjJj9N6oze3XWlNAf29EJlZQ+sp5/hKjNQ8phwDBLBDS2U5Choh2UbBK7rdFsbQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oss.nxp.com; dmarc=pass action=none header.from=oss.nxp.com; dkim=pass header.d=oss.nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=NXP1.onmicrosoft.com; s=selector2-NXP1-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Tzh443fN23JW65+0ZKNPTPvcMTJ1syY3CeOsdRCtvvs=; b=Zl9PFreZFgNz6rmsOo9xn6hcFlclZmKJcActM+82Xqpclc2BXQ8gCZ9rAEtKNIvqd1s9Z6+gVYEOYwe+xcEAKU5uh2DxQ+m08yBS72cfLd02GtFIKZlYw/n1NWNv0zuwmFWWPG4vNlG3nkzNNX/7mVAoNEXT4ghqh1zTlzzPDMI= Authentication-Results: denx.de; dkim=none (message not signed) header.d=none; denx.de; dmarc=none action=none header.from=oss.nxp.com; Received: from DB6PR0402MB2760.eurprd04.prod.outlook.com (2603:10a6:4:a1::14) by DB3PR0402MB3657.eurprd04.prod.outlook.com (2603:10a6:8:b::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4264.20; Tue, 29 Jun 2021 02:01:01 +0000 Received: from DB6PR0402MB2760.eurprd04.prod.outlook.com ([fe80::c445:d742:eb76:86dd]) by DB6PR0402MB2760.eurprd04.prod.outlook.com ([fe80::c445:d742:eb76:86dd%9]) with mapi id 15.20.4264.026; Tue, 29 Jun 2021 02:01:01 +0000 From: "Peng Fan (OSS)" To: sbabic@denx.de, festevam@gmail.com Cc: uboot-imx@nxp.com, u-boot@lists.denx.de, Peng Fan Subject: [PATCH V2 43/46] imx8ulp: add upower api support Date: Tue, 29 Jun 2021 10:32:37 +0800 Message-Id: <20210629023240.22394-44-peng.fan@oss.nxp.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210629023240.22394-1-peng.fan@oss.nxp.com> References: <20210629023240.22394-1-peng.fan@oss.nxp.com> X-Originating-IP: [119.31.174.71] X-ClientProxiedBy: SG2PR06CA0088.apcprd06.prod.outlook.com (2603:1096:3:14::14) To DB6PR0402MB2760.eurprd04.prod.outlook.com (2603:10a6:4:a1::14) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from linux-1xn6.ap.freescale.net (119.31.174.71) by SG2PR06CA0088.apcprd06.prod.outlook.com (2603:1096:3:14::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4264.19 via Frontend Transport; Tue, 29 Jun 2021 02:00:58 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: dbb4cd8d-1c67-4d53-8e5b-08d93aa1be32 X-MS-TrafficTypeDiagnostic: DB3PR0402MB3657: X-MS-Exchange-SharedMailbox-RoutingAgent-Processed: True X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:612; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: pTrX2nSVjpRVGG+fHdbepw+Y9TO5xvwtcbeR9JmNBXfYiwGy65oTcqIPH+wJMzbV48itUEhSMqwOFqzupJxQmwCLOJBjLACHS19LbSmkBgIrpPbBUp87mdmZ7MGoIIsywTHvawOIpivBy2TITJ0APYuOmgqaRote3rvytGvW+jqjtxB1VRs4XQbjHRFT17QUD9PjEdheAcvGCbo3k2YozUgJ5u2w8fmmpmwrQdKEAOEPH3XUVeQUEm6cXPJy14kyG1rw6RlJbW2LQIyMbU8FikPH7yMd3ziisfDXTTIjpdwAy9UMKyRAI0vpXhb8MtvpyJ6AGEI+5OnuoODXeRDwk21m6bLUA8eMTxG0kEz+i9qP3jwBuh59iJCDXue5os97VZD1DQ6DDqkS/KMqq+VazCpYqHg9H+Xo/uoXsTiH/vYM/pNsiDCAk7HMxGEZYE+kVjvpjo7qwGTsjwLLrXMFyxFfA/kh38WEMIe9FK8v0e9dY1zSdriyHnBQcftxevDYDmFrCup3n2eKxLgS/V5pk2eu1M5OPWsV05p0hCcqB0Jz4xXNL06z07YDIfNKgFGBWslq5Yv9F7csj06/W7uPhkFz066tbg6hYwcEOsMn8SJ0CTmNXkRuTqLmp1AyS66DZqPGLZ3kUa10cN0MQUXVmLZZbQ2rCknE8hxZ4LmwTiWPvgYAGTI9i9t8b0GWQnMVh1f7bLulZPh1DYbsGaVvu6nzOaqILEraf+s26HXHSPU= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DB6PR0402MB2760.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(366004)(39860400002)(136003)(396003)(346002)(376002)(478600001)(26005)(83380400001)(6506007)(30864003)(38350700002)(66946007)(5660300002)(66476007)(66556008)(38100700002)(6486002)(2906002)(16526019)(8676002)(52116002)(6512007)(4326008)(6666004)(956004)(186003)(8936002)(86362001)(316002)(2616005)(1076003)(32563001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: f6hI4WFdmid5A/lZyH8Zi9rQnnLoVG3zkyhTeCR4UrJcO1mt2anGRp7lHh8MsSjRxIjqwE53aJyJfaQ660AWkI96lqTlXgfk4+QbepYpCgNBN6wrj0Uy3Mm029TLGEBJ5sCdv6mvL/kezw71cAku21QATKPjGKom4AWH5G62hqf50XaY2bOpuM8cpqAkdkvhaY4kXpIh/jBdgXZwIOr7l2Uwi9LVtwc6FXnU/cuRQmm7VfP1J1IdpKYgWlxlWNLHIjRor1vfbgSQa+kvMooOz04UwADHmGb4dsfkFg95pn3UpRTlMdvZiFV4z92c6yLEcCOUcknq4FsK0svmAq8nkpiK4e8Socd9AlnSUnOZxEe2PTQzPdHYbNgVKua/nkJaDcrZ1pDTOc93aEfUvVgoY/8iDOsR9Nj86sjNE0tKhU5n3CcOyn7dI8cA1BI2zaSTJa2o5ZTalf+kWmFDuRRc/8yggdSZar0WOLmqiR0RU1iJTdlXU5ZrH5+Pi9liRuPP5kHoaPUiS8rFEJDSHeG1rUNp77GvobelQZLtRSti/JBEVUGSm7eX1z5S2O4E67EQfdbJaOq3GzCi3y2fc0iQ3bUqUpdP758GbqRV4iKl9jxWM3cPigf1FOn4CMgXyr4hkwXmFyxIT9LYuJYF7TX2xdRCO4iKqhClwr5RBpjiDvEy+rvtscPY3G7kKBay1e3oId0dueQlLdabCvSEIc2ZXEzZo5URC9YHYteJl6DwtHGwNZ69Lrdkx7xZpfQjqslrg4hAkKR8KNH8ooaIiA8A1F41X22HrfCRSaytScehSDqVxtUfNYbSy5Ol3heQwj56AsbRhQR50YJD8jyn1hOlNna4VLiU2qC9T9qs7ZWOMbxpUtSnQZJu6TcIfVAiN5EJmVia2z1gDO0BFK8r9CYdWgUwkwBhkCCi3sROBlzloB5DgMy/tYwBvsAlt9qpNvQz/W3NtUFfSoO9PT0VkuiMF+8jR1+I+i9Kq+tTr6JG5tXvu4Plum/9Zm6nkQMiPMz3edb6mnXaZ5ZBeYkc+c6TRTR977pwpu3DoNM+kL5NzYX73HchCfSVi6ImMjvUCPEiJKxqb4zqPZvdz/JimW3W6BK3eXVOiZAOMDCngrRxMFz3/YcDtigDFAaCGWJN31p2pM9bgeyJJfp+MM5jMZRzHzdsRyBhv092k3rRX+LeG0Wzc5Q2zNu5ALwEgtB4mFL3atjAfCpdZqN5xiYB0pTpBXMVm/igvZ3fnepOH8zjiVbBb0gkeiqg/xYGAIDDO1d54XzqQshD7NzvSTNORz1c9nu1UuQy+vrJzWfsgiWEjrSY4V0xIPgMuFkooOWvWbbZ X-OriginatorOrg: oss.nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: dbb4cd8d-1c67-4d53-8e5b-08d93aa1be32 X-MS-Exchange-CrossTenant-AuthSource: DB6PR0402MB2760.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Jun 2021 02:01:01.3321 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: qVL2gTbSC/90Pj05s53V/Kg+PEN0GI9DtoUkwPhl1dts2bpk3YkqmZSnGbSL4pxG5cRMqj4T87zYA0jLS/zqvw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB3PR0402MB3657 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.103.2 at phobos.denx.de X-Virus-Status: Clean From: Peng Fan Add upower api support, this is modified from upower firmware exported package. Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/upower.h | 15 + arch/arm/mach-imx/imx8ulp/Makefile | 4 + arch/arm/mach-imx/imx8ulp/upower/Makefile | 6 + arch/arm/mach-imx/imx8ulp/upower/upower_api.c | 486 ++++++++++++++++++ arch/arm/mach-imx/imx8ulp/upower/upower_api.h | 258 ++++++++++ arch/arm/mach-imx/imx8ulp/upower/upower_hal.c | 179 +++++++ 6 files changed, 948 insertions(+) create mode 100644 arch/arm/include/asm/arch-imx8ulp/upower.h create mode 100644 arch/arm/mach-imx/imx8ulp/upower/Makefile create mode 100644 arch/arm/mach-imx/imx8ulp/upower/upower_api.c create mode 100644 arch/arm/mach-imx/imx8ulp/upower/upower_api.h create mode 100644 arch/arm/mach-imx/imx8ulp/upower/upower_hal.c -- 2.30.0 diff --git a/arch/arm/include/asm/arch-imx8ulp/upower.h b/arch/arm/include/asm/arch-imx8ulp/upower.h new file mode 100644 index 0000000000..0f1875bbd6 --- /dev/null +++ b/arch/arm/include/asm/arch-imx8ulp/upower.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 NXP + */ + +#ifndef __ASM_ARCH_IMX8ULP_UPOWER_H +#define __ASM_ARCH_IMX8ULP_UPOWER_H + +#include + +int upower_init(void); +int upower_pmic_i2c_write(u32 reg_addr, u32 reg_val); +int upower_pmic_i2c_read(u32 reg_addr, u32 *reg_val); + +#endif diff --git a/arch/arm/mach-imx/imx8ulp/Makefile b/arch/arm/mach-imx/imx8ulp/Makefile index 1ef6cd5c91..2c9938fcdf 100644 --- a/arch/arm/mach-imx/imx8ulp/Makefile +++ b/arch/arm/mach-imx/imx8ulp/Makefile @@ -5,3 +5,7 @@ obj-y += lowlevel_init.o obj-y += soc.o clock.o iomux.o pcc.o cgc.o rdc.o + +ifeq ($(CONFIG_SPL_BUILD),y) +obj-y += upower/ +endif diff --git a/arch/arm/mach-imx/imx8ulp/upower/Makefile b/arch/arm/mach-imx/imx8ulp/upower/Makefile new file mode 100644 index 0000000000..f8b5da2ad3 --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/upower/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2020 NXP +# + +obj-y += upower_api.o upower_hal.o diff --git a/arch/arm/mach-imx/imx8ulp/upower/upower_api.c b/arch/arm/mach-imx/imx8ulp/upower/upower_api.c new file mode 100644 index 0000000000..98781d3d5d --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/upower/upower_api.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2021 NXP + */ + +#include +#include +#include +#include +#include "upower_api.h" + +enum upwr_api_state api_state; +enum soc_domain pwr_domain; +void *sh_buffer[UPWR_SG_COUNT]; +struct upwr_code_vers fw_rom_version; +struct upwr_code_vers fw_ram_version; +u32 fw_launch_option; +u32 sg_busy; +struct mu_type *mu; +upwr_up_max_msg sg_rsp_msg[UPWR_SG_COUNT]; +upwr_callb user_callback[UPWR_SG_COUNT]; +UPWR_RX_CALLB_FUNC_T sgrp_callback[UPWR_SG_COUNT]; +u32 sg_rsp_siz[UPWR_SG_COUNT]; + +#define UPWR_MU_MSG_SIZE (2) +#define UPWR_SG_BUSY(sg) (sg_busy & (1 << (sg))) +#define UPWR_USR_CALLB(sg, cb) \ + do { \ + user_callback[sg] = cb; \ + } while (0) +#define UPWR_MSG_HDR(hdr, sg, fn) \ + (hdr).domain = (u32)pwr_domain; \ + (hdr).srvgrp = sg; \ + (hdr).function = fn + +static u32 upwr_ptr2offset(u64 ptr, enum upwr_sg sg, size_t siz, size_t offset, const void *vptr) +{ + if (ptr >= UPWR_DRAM_SHARED_BASE_ADDR && + ((ptr - UPWR_DRAM_SHARED_BASE_ADDR) < UPWR_DRAM_SHARED_SIZE)) { + return (u32)(ptr - UPWR_DRAM_SHARED_BASE_ADDR); + } + + /* pointer is outside the shared memory, copy the struct to buffer */ + memcpy(offset + (char *)sh_buffer[sg], (void *)vptr, siz); + + return (u32)((u64)sh_buffer[sg] + offset - UPWR_DRAM_SHARED_BASE_ADDR); +} + +enum upwr_req_status upwr_req_status(enum upwr_sg sg, u32 *sgfptr, enum upwr_resp *errptr, + int *retptr) +{ + enum upwr_req_status status; + + status = (sg_rsp_msg[sg].hdr.errcode == UPWR_RESP_OK) ? UPWR_REQ_OK : UPWR_REQ_ERR; + + return status; +} + +void upwr_copy2tr(struct mu_type *mu, const u32 *msg, u32 size) +{ + int i; + + for (i = size - 1; i > -1; i--) + writel(msg[i], &mu->tr[i]); +} + +int upwr_tx(const u32 *msg, u32 size) +{ + if (size > UPWR_MU_MSG_SIZE) + return -2; + if (!size) + return -2; + + if (readl(&mu->tsr) != UPWR_MU_TSR_EMPTY) + return -1; /* not all TE bits in 1: some data to send still */ + + upwr_copy2tr(mu, msg, size); + writel(1 << (size - 1), &mu->tcr); + + return 0; +} + +void upwr_srv_req(enum upwr_sg sg, u32 *msg, u32 size) +{ + sg_busy |= 1 << sg; + + upwr_tx(msg, size); +} + +int upwr_pwm_power_on(const u32 swton[], const u32 memon[], upwr_callb callb) +{ + upwr_pwm_pwron_msg txmsg; + u64 ptrval; /* needed for X86, ARM64 */ + size_t stsize = 0; + + if (api_state != UPWR_API_READY) + return -3; + if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) + return -1; + + UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); + + UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PWR_ON); + + if (!swton) + txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */ + else + txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval, UPWR_SG_PWRMGMT, + (stsize = UPWR_PMC_SWT_WORDS * 4), 0, swton); + + if (!memon) + txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */ + else + txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval, UPWR_SG_PWRMGMT, UPWR_PMC_MEM_WORDS * 4, + stsize, memon); + + upwr_srv_req(UPWR_SG_PWRMGMT, (u32 *)&txmsg, sizeof(txmsg) / 4); + + return 0; +} + +enum upwr_req_status upwr_poll_req_status(enum upwr_sg sg, u32 *sgfptr, + enum upwr_resp *errptr, int *retptr, + u32 attempts) +{ + u32 i; + enum upwr_req_status ret; + + if (!attempts) { + ret = UPWR_REQ_BUSY; + while (ret == UPWR_REQ_BUSY) + ret = upwr_req_status(sg, sgfptr, errptr, retptr); + return ret; + } + + for (i = 0; i < attempts; i++) { + ret = upwr_req_status(sg, sgfptr, errptr, retptr); + if (ret != UPWR_REQ_BUSY) + break; + } + + return ret; +} + +int upwr_xcp_i2c_access(u16 addr, int8_t data_size, uint8_t subaddr_size, u32 subaddr, + u32 wdata, const upwr_callb callb) +{ + u64 ptrval = (u64)sh_buffer[UPWR_SG_EXCEPT]; + struct upwr_i2c_access *i2c_acc_ptr = (struct upwr_i2c_access *)ptrval; + struct upwr_pointer_msg txmsg; + + if (api_state != UPWR_API_READY) + return -3; + if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) + return -1; + + UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); + + UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_I2C); + + i2c_acc_ptr->addr = addr; + i2c_acc_ptr->subaddr = subaddr; + i2c_acc_ptr->subaddr_size = subaddr_size; + i2c_acc_ptr->data = wdata; + i2c_acc_ptr->data_size = data_size; + + txmsg.ptr = upwr_ptr2offset(ptrval, + UPWR_SG_EXCEPT, + (size_t)sizeof(struct upwr_i2c_access), + 0, + i2c_acc_ptr); + + upwr_srv_req(UPWR_SG_EXCEPT, (u32 *)&txmsg, sizeof(txmsg) / 4); + + return 0; +} + +int upwr_xcp_set_ddr_retention(enum soc_domain domain, u32 enable, const upwr_callb callb) +{ + union upwr_down_1w_msg txmsg; + + if (api_state != UPWR_API_READY) + return -3; + if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) + return -1; + + UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); + + UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_DDR_RETN); + txmsg.hdr.domain = (u32)domain; + txmsg.hdr.arg = (u32)enable; + + upwr_srv_req(UPWR_SG_EXCEPT, (u32 *)&txmsg, sizeof(txmsg) / 4); + + return 0; +} + +int upwr_rx(u32 *msg, u32 *size) +{ + u32 len = readl(&mu->rsr); + + len = (len == 0x0) ? 0 : + (len == 0x1) ? 1 : + #if UPWR_MU_MSG_SIZE > 1 + (len == 0x3) ? 2 : + #if UPWR_MU_MSG_SIZE > 2 + (len == 0x7) ? 3 : + #if UPWR_MU_MSG_SIZE > 3 + (len == 0xF) ? 4 : + #endif + #endif + #endif + 0xFFFFFFFF; /* something wrong */ + + if (len == 0xFFFFFFFF) + return -3; + + *size = len; + if (!len) + return -1; + + /* copy the received message to the rx queue, so the interrupts are cleared; */ + for (u32 i = 0; i < len; i++) + msg[i] = readl(&mu->rr[i]); + + return 0; +} + +void msg_copy(u32 *dest, u32 *src, u32 size) +{ + *dest = *src; + if (size > 1) + *(dest + 1) = *(src + 1); +} + +void upwr_mu_int_callback(void) +{ + enum upwr_sg sg; /* service group number */ + UPWR_RX_CALLB_FUNC_T sg_callb; /* service group callback */ + struct upwr_up_2w_msg rxmsg; + u32 size; /* in words */ + + if (upwr_rx((u32 *)&rxmsg, &size) < 0) { + UPWR_API_ASSERT(0); + return; + } + + sg = (enum upwr_sg)rxmsg.hdr.srvgrp; + + /* copy msg to the service group buffer */ + msg_copy((u32 *)&sg_rsp_msg[sg], (u32 *)&rxmsg, size); + sg_rsp_siz[sg] = size; + sg_busy &= ~(1 << sg); + + sg_callb = sgrp_callback[sg]; + if (!sg_callb) { + upwr_callb user_callb = user_callback[sg]; + + /* no service group callback; call the user callback if any */ + if (!user_callb) + goto done; /* no user callback */ + + /* make the user callback */ + user_callb(sg, rxmsg.hdr.function, (enum upwr_resp)rxmsg.hdr.errcode, + (int)(size == 2) ? rxmsg.word2 : rxmsg.hdr.ret); + goto done; + } + + /* finally make the group callback */ + sg_callb(); + /* don't uninstall the group callback, it's permanent */ +done: + if (rxmsg.hdr.errcode == UPWR_RESP_SHUTDOWN) /* shutdown error: */ + api_state = UPWR_API_INITLZED; +} + +void upwr_txrx_isr(void) +{ + if (readl(&mu->rsr)) + upwr_mu_int_callback(); +} + +void upwr_start_callb(void) +{ + switch (api_state) { + case UPWR_API_START_WAIT: + { + upwr_rdy_callb start_callb = (upwr_rdy_callb)user_callback[UPWR_SG_EXCEPT]; + + union upwr_ready_msg *msg = (union upwr_ready_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; + + /* message sanity check */ + UPWR_API_ASSERT(msg->hdr.srvgrp == UPWR_SG_EXCEPT); + UPWR_API_ASSERT(msg->hdr.function == UPWR_XCP_START); + UPWR_API_ASSERT(msg->hdr.errcode == UPWR_RESP_OK); + + fw_ram_version.soc_id = fw_rom_version.soc_id; + fw_ram_version.vmajor = msg->args.vmajor; + fw_ram_version.vminor = msg->args.vminor; + fw_ram_version.vfixes = msg->args.vfixes; + + /* + * vmajor == vminor == vfixes == 0 indicates start error + * in this case, go back to the INITLZED state + */ + + if (fw_ram_version.vmajor || fw_ram_version.vminor || fw_ram_version.vfixes) { + api_state = UPWR_API_READY; + + /* initialization is over: uninstall the callbacks just in case */ + UPWR_USR_CALLB(UPWR_SG_EXCEPT, NULL); + sgrp_callback[UPWR_SG_EXCEPT] = NULL; + + if (!fw_launch_option) { + /* launched ROM firmware: RAM fw versions must be all 0s */ + fw_ram_version.vmajor = + fw_ram_version.vminor = + fw_ram_version.vfixes = 0; + } + } else { + api_state = UPWR_API_INITLZED; + } + + start_callb(msg->args.vmajor, msg->args.vminor, msg->args.vfixes); + } + break; + + default: + UPWR_API_ASSERT(0); + break; + } +} + +int upwr_init(enum soc_domain domain, struct mu_type *muptr) +{ + u32 dom_buffer_base = ((UPWR_API_BUFFER_ENDPLUS + UPWR_API_BUFFER_BASE) / 2); + union upwr_init_msg *msg = (union upwr_init_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; + enum upwr_sg sg; /* service group number */ + u32 size; /* in words */ + int j; + + mu = muptr; + writel(0, &mu->tcr); + writel(0, &mu->rcr); + + api_state = UPWR_API_INIT_WAIT; + pwr_domain = domain; + sg_busy = 0; + + /* initialize the versions, in case they are polled */ + fw_rom_version.soc_id = + fw_rom_version.vmajor = + fw_rom_version.vminor = + fw_rom_version.vfixes = 0; + + fw_ram_version.soc_id = + fw_ram_version.vmajor = + fw_ram_version.vminor = + fw_ram_version.vfixes = 0; + + sh_buffer[UPWR_SG_EXCEPT] = (void *)(ulong)dom_buffer_base; + sh_buffer[UPWR_SG_PWRMGMT] = (void *)(ulong)(dom_buffer_base + + sizeof(union upwr_xcp_union)); + sh_buffer[UPWR_SG_DELAYM] = NULL; + sh_buffer[UPWR_SG_VOLTM] = NULL; + sh_buffer[UPWR_SG_CURRM] = NULL; + sh_buffer[UPWR_SG_TEMPM] = NULL; + sh_buffer[UPWR_SG_DIAG] = NULL; + /* (no buffers service groups other than xcp and pwm for now) */ + + for (j = 0; j < UPWR_SG_COUNT; j++) { + user_callback[j] = NULL; + /* service group Exception gets the initialization callbacks */ + sgrp_callback[j] = (j == UPWR_SG_EXCEPT) ? upwr_start_callb : NULL; + + /* response messages with an initial consistent content */ + sg_rsp_msg[j].hdr.errcode = UPWR_RESP_SHUTDOWN; + } + + if (readl(&mu->fsr) & BIT(0)) { + /* send a ping message down to get the ROM version back */ + upwr_xcp_ping_msg ping_msg; + + ping_msg.hdr.domain = pwr_domain; + ping_msg.hdr.srvgrp = UPWR_SG_EXCEPT; + ping_msg.hdr.function = UPWR_XCP_PING; + + if (readl(&mu->rsr) & BIT(0)) /* first clean any Rx message left over */ + upwr_rx((u32 *)msg, &size); + + while (readl(&mu->tsr) != UPWR_MU_TSR_EMPTY) + ; + + /* + * now send the ping message; + * do not use upwr_tx, which needs API initilized; + * just write to the MU TR register(s) + */ + setbits_le32(&mu->fcr, BIT(0)); /* flag urgency status */ + upwr_copy2tr(mu, (u32 *)&ping_msg, sizeof(ping_msg) / 4); + } + + do { + /* poll for the MU Rx status: wait for an init message, either + * 1st sent from uPower after reset or as a response to a ping + */ + while (!readl(&mu->rsr) & BIT(0)) + ; + + clrbits_le32(&mu->fcr, BIT(0)); + + if (upwr_rx((u32 *)msg, &size) < 0) + return -4; + + if (size != (sizeof(union upwr_init_msg) / 4)) { + if (readl(&mu->fsr) & BIT(0)) + continue; /* discard left over msg */ + else + return -4; + } + + sg = (enum upwr_sg)msg->hdr.srvgrp; + if (sg != UPWR_SG_EXCEPT) { + if (readl(&mu->fsr) & BIT(0)) + continue; + else + return -4; + } + + if ((enum upwr_xcp_f)msg->hdr.function != UPWR_XCP_INIT) { + if (readl(&mu->fsr) & BIT(0)) + continue; + else + return -4; + } + + break; + } while (true); + + fw_rom_version.soc_id = msg->args.soc; + fw_rom_version.vmajor = msg->args.vmajor; + fw_rom_version.vminor = msg->args.vminor; + fw_rom_version.vfixes = msg->args.vfixes; + + api_state = UPWR_API_INITLZED; + + return 0; +} /* upwr_init */ + +int upwr_start(u32 launchopt, const upwr_rdy_callb rdycallb) +{ + upwr_start_msg txmsg; + + if (api_state != UPWR_API_INITLZED) + return -3; + + UPWR_USR_CALLB(UPWR_SG_EXCEPT, (upwr_callb)rdycallb); + + UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_START); + + txmsg.hdr.arg = launchopt; + fw_launch_option = launchopt; + + if (upwr_tx((u32 *)&txmsg, sizeof(txmsg) / 4) < 0) { + /* catastrophic error, but is it possible to happen? */ + UPWR_API_ASSERT(0); + return -1; + } + + api_state = UPWR_API_START_WAIT; + + return 0; +} + +u32 upwr_rom_version(u32 *vmajor, u32 *vminor, u32 *vfixes) +{ + u32 soc; + + soc = fw_rom_version.soc_id; + *vmajor = fw_rom_version.vmajor; + *vminor = fw_rom_version.vminor; + *vfixes = fw_rom_version.vfixes; + + return soc; +} + diff --git a/arch/arm/mach-imx/imx8ulp/upower/upower_api.h b/arch/arm/mach-imx/imx8ulp/upower/upower_api.h new file mode 100644 index 0000000000..c35455a262 --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/upower/upower_api.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright 2020 NXP + */ + +enum soc_domain { + RTD_DOMAIN = 0, + APD_DOMAIN = 1, + UPWR_MAIN_DOMAINS, /* RTD, AVD */ + AVD_DOMAIN = UPWR_MAIN_DOMAINS, + UPWR_DOMAIN_COUNT, /* RTD, APD, AVD */ + PSD_DOMAIN = UPWR_DOMAIN_COUNT, + UPWR_ALL_DOMAINS /* RTD, APD, AVD, PSD */ +}; + +enum upwr_api_state { + UPWR_API_INIT_WAIT, /* waiting for ROM firmware initialization */ + UPWR_API_INITLZED, /* ROM firmware initialized */ + UPWR_API_START_WAIT, /* waiting for start services */ + UPWR_API_READY /* ready to receive service requests */ +}; + +enum upwr_sg { /* Service Groups in priority order, high to low */ + UPWR_SG_EXCEPT, /* 0 = exception */ + UPWR_SG_PWRMGMT, /* 1 = power management */ + UPWR_SG_DELAYM, /* 2 = delay measurement */ + UPWR_SG_VOLTM, /* 3 = voltage measurement */ + UPWR_SG_CURRM, /* 4 = current measurement */ + UPWR_SG_TEMPM, /* 5 = temperature measurement */ + UPWR_SG_DIAG, /* 6 = diagnostic */ + UPWR_SG_COUNT +}; + +enum upwr_xcp_f { /* Exception Functions */ + /* 0 = init msg (not a service request itself) */ + UPWR_XCP_INIT, + /* 0 = also ping request, since its response is an init msg */ + UPWR_XCP_PING = UPWR_XCP_INIT, + UPWR_XCP_START, /* 1 = service start: upwr_start (not a service request itself) */ + UPWR_XCP_SHUTDOWN, /* 2 = service shutdown: upwr_xcp_shutdown */ + UPWR_XCP_CONFIG, /* 3 = uPower configuration: upwr_xcp_config */ + UPWR_XCP_SW_ALARM, /* 4 = uPower software alarm: upwr_xcp_sw_alarm */ + UPWR_XCP_I2C, /* 5 = I2C access: upwr_xcp_i2c_access */ + UPWR_XCP_SPARE_6, /* 6 = spare */ + UPWR_XCP_SET_DDR_RETN, /* 7 = set/clear ddr retention */ + UPWR_XCP_SPARE_8, /* 8 = spare */ + UPWR_XCP_SPARE_9, /* 9 = spare */ + UPWR_XCP_SPARE_10, /* 10 = spare */ + UPWR_XCP_SPARE_11, /* 11 = spare */ + UPWR_XCP_SPARE_12, /* 12 = spare */ + UPWR_XCP_SPARE_13, /* 13 = spare */ + UPWR_XCP_SPARE_14, /* 14 = spare */ + UPWR_XCP_SPARE_15, /* 15 = spare */ + UPWR_XCP_F_COUNT +}; + +enum upwr_resp { /* response error codes */ + UPWR_RESP_OK = 0, /* no error */ + UPWR_RESP_SG_BUSY, /* service group is busy */ + UPWR_RESP_SHUTDOWN, /* services not up or shutting down */ + UPWR_RESP_BAD_REQ, /* invalid request */ + UPWR_RESP_BAD_STATE, /* system state doesn't allow perform the request */ + UPWR_RESP_UNINSTALLD, /* service or function not installed */ + UPWR_RESP_UNINSTALLED = + UPWR_RESP_UNINSTALLD, /* service or function not installed (alias) */ + UPWR_RESP_RESOURCE, /* resource not available */ + UPWR_RESP_TIMEOUT, /* service timeout */ + UPWR_RESP_COUNT +}; + +#define UPWR_SRVGROUP_BITS (4) +#define UPWR_FUNCTION_BITS (4) +#define UPWR_PWDOMAIN_BITS (4) +#define UPWR_HEADER_BITS (UPWR_SRVGROUP_BITS + UPWR_FUNCTION_BITS + UPWR_PWDOMAIN_BITS) +#define UPWR_ARG_BITS (32 - UPWR_HEADER_BITS) + +#define UPWR_DUAL_OFFSET_BITS ((UPWR_ARG_BITS + 32) >> 1) + +struct upwr_msg_hdr { + u32 domain :UPWR_PWDOMAIN_BITS; /* power domain */ + u32 srvgrp :UPWR_SRVGROUP_BITS; /* service group */ + u32 function :UPWR_FUNCTION_BITS; /* function */ + u32 arg :UPWR_ARG_BITS; /* function-specific argument */ +}; + +union upwr_down_1w_msg { + struct upwr_msg_hdr hdr; + u32 word; /* message first word */ +}; + +#define upwr_start_msg union upwr_down_1w_msg +#define upwr_xcp_ping_msg union upwr_down_1w_msg + +#define UPWR_RESP_ERR_BITS (4) +#define UPWR_RESP_HDR_BITS (UPWR_RESP_ERR_BITS + \ + UPWR_SRVGROUP_BITS + UPWR_FUNCTION_BITS) +#define UPWR_RESP_RET_BITS (32 - UPWR_RESP_HDR_BITS) + +struct upwr_resp_hdr { + u32 errcode :UPWR_RESP_ERR_BITS; + u32 srvgrp :UPWR_SRVGROUP_BITS; /* service group */ + u32 function:UPWR_FUNCTION_BITS; + u32 ret :UPWR_RESP_RET_BITS; /* return value, if any */ +}; + +struct upwr_up_2w_msg { + struct upwr_resp_hdr hdr; + u32 word2; /* message second word */ +}; + +#define upwr_up_max_msg struct upwr_up_2w_msg + +union upwr_2pointer_msg { + struct upwr_msg_hdr hdr; + struct { + u64 : UPWR_HEADER_BITS; + u64 ptr0 : UPWR_DUAL_OFFSET_BITS; + u64 ptr1 : UPWR_DUAL_OFFSET_BITS; + } ptrs; +}; + +#define upwr_pwm_pwron_msg union upwr_2pointer_msg + +struct upwr_pointer_msg { + struct upwr_msg_hdr hdr; + u32 ptr; /* config struct offset */ +}; + +struct upwr_i2c_access { /* structure pointed by message upwr_xcp_i2c_msg */ + u16 addr; + s8 data_size; + u8 subaddr_size; + u32 subaddr; + u32 data; +}; + +enum upwr_req_status { + UPWR_REQ_OK, /* request succeeded */ + UPWR_REQ_ERR, /* request failed */ + UPWR_REQ_BUSY /* request execution ongoing */ +}; + +#define UPWR_SOC_BITS (7) +#define UPWR_VMINOR_BITS (4) +#define UPWR_VFIXES_BITS (4) +#define UPWR_VMAJOR_BITS \ + (32 - UPWR_HEADER_BITS - UPWR_SOC_BITS - UPWR_VMINOR_BITS - UPWR_VFIXES_BITS) +union upwr_init_msg { + struct upwr_resp_hdr hdr; + struct { + u32 rsv:UPWR_RESP_HDR_BITS; + u32 soc:UPWR_SOC_BITS; /* SoC identification */ + u32 vmajor:UPWR_VMAJOR_BITS; /* firmware major version */ + u32 vminor:UPWR_VMINOR_BITS; /* firmware minor version */ + u32 vfixes:UPWR_VFIXES_BITS; /* firmware fixes version */ + } args; +}; + +#define UPWR_RAM_VMINOR_BITS (7) +#define UPWR_RAM_VFIXES_BITS (6) +#define UPWR_RAM_VMAJOR_BITS (32 - UPWR_HEADER_BITS - UPWR_RAM_VFIXES_BITS - UPWR_RAM_VMINOR_BITS) + +union upwr_ready_msg { + struct upwr_resp_hdr hdr; + struct { + u32 rsv:UPWR_RESP_HDR_BITS; + u32 vmajor:UPWR_RAM_VMAJOR_BITS; /* RAM fw major version */ + u32 vminor:UPWR_RAM_VMINOR_BITS; /* RAM fw minor version */ + u32 vfixes:UPWR_RAM_VFIXES_BITS; /* RAM fw fixes version */ + } args; +}; + +struct upwr_reg_access_t { + u32 addr; + u32 data; + u32 mask; /* mask=0 commands read */ +}; + +union upwr_xcp_union { + struct upwr_reg_access_t reg_access; +}; + +enum { /* Power Management Functions */ + UPWR_PWM_REGCFG, /* 0 = regulator config: upwr_pwm_reg_config */ + UPWR_PWM_DEVMODE = UPWR_PWM_REGCFG, /* deprecated, for old compile */ + UPWR_PWM_VOLT, /* 1 = voltage change: upwr_pwm_chng_reg_voltage */ + UPWR_PWM_SWITCH, /* 2 = switch control: upwr_pwm_chng_switch_mem */ + UPWR_PWM_PWR_ON, /* 3 = switch/RAM/ROM power on: upwr_pwm_power_on */ + UPWR_PWM_PWR_OFF, /* 4 = switch/RAM/ROM power off: upwr_pwm_power_off */ + UPWR_PWM_RETAIN, /* 5 = retain memory array: upwr_pwm_mem_retain */ + UPWR_PWM_DOM_BIAS, /* 6 = Domain bias control: upwr_pwm_chng_dom_bias */ + UPWR_PWM_MEM_BIAS, /* 7 = Memory bias control: upwr_pwm_chng_mem_bias */ + UPWR_PWM_PMICCFG, /* 8 = PMIC configuration: upwr_pwm_pmic_config */ + UPWR_PWM_PMICMOD = UPWR_PWM_PMICCFG, /* deprecated, for old compile */ + UPWR_PWM_PES, /* 9 = Power Event Sequencer */ + UPWR_PWM_CONFIG, /* 10= apply power mode defined configuration */ + UPWR_PWM_CFGPTR, /* 11= configuration pointer */ + UPWR_PWM_DOM_PWRON, /* 12 = domain power on: upwr_pwm_dom_power_on */ + UPWR_PWM_BOOT, /* 13 = boot start: upwr_pwm_boot_start */ + UPWR_PWM_FREQ, /* 14 = domain frequency setup */ + UPWR_PWM_PARAM, /* 15 = power management parameters */ + UPWR_PWM_F_COUNT +}; + +#ifndef UPWR_PMC_SWT_WORDS +#define UPWR_PMC_SWT_WORDS (1) +#endif + +#ifndef UPWR_PMC_MEM_WORDS +#define UPWR_PMC_MEM_WORDS (2) +#endif + +#define UPWR_API_ASSERT(c) do { } while (0) + +struct upwr_code_vers { + u32 soc_id; + u32 vmajor; + u32 vminor; + u32 vfixes; +}; + +#define UPWR_MU_MSG_SIZE (2) + +#define UPWR_MU_TSR_EMPTY ((u32)((1 << UPWR_MU_MSG_SIZE) - 1)) + +#ifndef UPWR_DRAM_SHARED_BASE_ADDR +#define UPWR_DRAM_SHARED_BASE_ADDR (0x28330000) +#endif + +#ifndef UPWR_DRAM_SHARED_SIZE +#define UPWR_DRAM_SHARED_SIZE (2048) +#endif + +#define UPWR_DRAM_SHARED_ENDPLUS (UPWR_DRAM_SHARED_BASE_ADDR + UPWR_DRAM_SHARED_SIZE) + +#ifndef UPWR_API_BUFFER_BASE +#define UPWR_API_BUFFER_BASE (0x28330600) +#endif + +#ifndef UPWR_API_BUFFER_ENDPLUS +#define UPWR_API_BUFFER_ENDPLUS (UPWR_DRAM_SHARED_ENDPLUS - 64) +#endif + +typedef void (*upwr_rdy_callb)(u32 vmajor, u32 vminor, u32 vfixes); +typedef void (*upwr_callb)(enum upwr_sg sg, u32 func, enum upwr_resp errcode, int ret); +int upwr_init(enum soc_domain domain, struct mu_type *muptr); +int upwr_start(u32 launchopt, const upwr_rdy_callb rdycallb); +u32 upwr_rom_version(u32 *vmajor, u32 *vminor, u32 *vfixes); +typedef void (*UPWR_RX_CALLB_FUNC_T)(void); + +int upwr_xcp_set_ddr_retention(enum soc_domain domain, u32 enable, const upwr_callb callb); +int upwr_pwm_power_on(const u32 swton[], const u32 memon[], upwr_callb callb); +int upwr_xcp_i2c_access(u16 addr, s8 data_size, u8 subaddr_size, u32 subaddr, + u32 wdata, const upwr_callb callb); +enum upwr_req_status upwr_poll_req_status(enum upwr_sg sg, u32 *sgfptr, + enum upwr_resp *errptr, int *retptr, + u32 attempts); +void upwr_txrx_isr(void); diff --git a/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c b/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c new file mode 100644 index 0000000000..97bb20b2bb --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2021 NXP + */ + +#include +#include +#include +#include + +#include "upower_api.h" + +#define UPOWER_AP_MU1_ADDR 0x29280000 +static struct mu_type *muptr = (struct mu_type *)UPOWER_AP_MU1_ADDR; + +void upower_wait_resp(void) +{ + while (!(readl(&muptr->rsr) & BIT(0))) { + debug("%s: poll the mu:%x\n", __func__, readl(&muptr->rsr)); + udelay(100); + } + + upwr_txrx_isr(); +} + +u32 upower_status(int status) +{ + u32 ret = -1; + switch (status) { + case 0: + debug("%s: finished successfully!\n", __func__); + ret = 0; + break; + case -1: + printf("%s: memory allocation or resource failed!\n", __func__); + break; + case -2: + printf("%s: invalid argument!\n", __func__); + break; + case -3: + printf("%s: called in an invalid API state!\n", __func__); + break; + default: + printf("%s: invalid return status\n", __func__); + break; + } + return ret; +} + +void user_upwr_rdy_callb(u32 soc, u32 vmajor, u32 vminor) +{ + printf("%s: soc=%x\n", __func__, soc); + printf("%s: RAM version:%d.%d\n", __func__, vmajor, vminor); +} + +int upower_pmic_i2c_write(u32 reg_addr, u32 reg_val) +{ + int ret, ret_val; + enum upwr_resp err_code; + + ret = upwr_xcp_i2c_access(0x32, 1, 1, reg_addr, reg_val, NULL); + if (ret) { + printf("pmic i2c write failed ret %d\n", ret); + return ret; + } + + upower_wait_resp(); + ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000); + if (ret != UPWR_REQ_OK) { + printf("i2c poll Failure %d, err_code %d, ret_val 0x%x\n", ret, err_code, ret_val); + return ret; + } + + debug("PMIC write reg[0x%x], val[0x%x]\n", reg_addr, reg_val); + + return 0; +} + +int upower_pmic_i2c_read(u32 reg_addr, u32 *reg_val) +{ + int ret, ret_val; + enum upwr_resp err_code; + + if (!reg_val) + return -1; + + ret = upwr_xcp_i2c_access(0x32, -1, 1, reg_addr, 0, NULL); + if (ret) { + printf("pmic i2c read failed ret %d\n", ret); + return ret; + } + + upower_wait_resp(); + ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000); + if (ret != UPWR_REQ_OK) { + printf("i2c poll Failure %d, err_code %d, ret_val 0x%x\n", ret, err_code, ret_val); + return ret; + } + + *reg_val = ret_val; + + debug("PMIC read reg[0x%x], val[0x%x]\n", reg_addr, *reg_val); + + return 0; +} + +int upower_init(void) +{ + u32 fw_major, fw_minor, fw_vfixes; + u32 soc_id; + int status; + + u32 swton; + u64 memon; + int ret, ret_val; + + do { + status = upwr_init(1, muptr); + if (upower_status(status)) { + printf("%s: upower init failure\n", __func__); + break; + } + + soc_id = upwr_rom_version(&fw_major, &fw_minor, &fw_vfixes); + if (!soc_id) { + printf("%s:, soc_id not initialized\n", __func__); + break; + } + + printf("%s: soc_id=%d\n", __func__, soc_id); + printf("%s: version:%d.%d.%d\n", __func__, fw_major, fw_minor, fw_vfixes); + + printf("%s: start uPower RAM service\n", __func__); + status = upwr_start(1, user_upwr_rdy_callb); + upower_wait_resp(); + if (upower_status(status)) { + printf("%s: upower init failure\n", __func__); + break; + } + } while(0); + + swton = 0xfff80; + ret = upwr_pwm_power_on(&swton, NULL, NULL); + if (ret) + printf("Turn on switches fail %d\n", ret); + else + printf("Turn on switches ok\n"); + upower_wait_resp(); + ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000); + if (ret != UPWR_REQ_OK) + printf("Faliure %d\n", ret); + + memon = 0x3FFFFFFFFFFFFCUL; + ret = upwr_pwm_power_on(NULL, (const u32 *)&memon, NULL); + if (ret) + printf("Turn on memories fail %d\n", ret); + else + printf("Turn on memories ok\n"); + upower_wait_resp(); + ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000); + if (ret != UPWR_REQ_OK) + printf("Faliure %d\n", ret); + + mdelay(1); + + ret = upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL); + if (ret) + printf("Clear DDR retention fail %d\n", ret); + else + printf("Clear DDR retention ok\n"); + + upower_wait_resp(); + + ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, NULL, &ret_val, 1000); + if (ret != UPWR_REQ_OK) + printf("Faliure %d\n", ret); + + return 0; +}