From patchwork Wed Jun 28 14:00:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113925 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8962862vqr; Wed, 28 Jun 2023 07:19:38 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ694EpWEriZ9uMz21pV9OLlbhO3BtIXNJMxY9IwWE7iwo/4vhOm5NUigPC7rWZvTXkN5VhE X-Received: by 2002:a05:6402:524e:b0:50c:79f:c693 with SMTP id t14-20020a056402524e00b0050c079fc693mr24340080edd.1.1687961978573; Wed, 28 Jun 2023 07:19:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687961978; cv=none; d=google.com; s=arc-20160816; b=dscMesbAL4J1KyRuZCvJI+TP+UOQZmexq4o7Evb8gQDuYMEqvIgDgKPYMkcg8CovLr chWqHU/k5yWyXYzWBfG4XLaTkW4IrIBwvaRn72JKZsLKCPiOra/ocUySueVOPgvIgPgM GLWLZDbyEQjZGqjGr82aSHq6DC9SM9QboGtzVdtSmHiDqv01KbWE29qNFN5Qj9i7Bp/n /wQ/cdwlmqAbfOzXJGVpuikDU+WJYXBNUSh/vKvqH+WR1zqx8xO8iBJGbVYi/is9xzQh EUyH2/kNDWF0vvxKv31MjXDVaZoRXZSpR6jEvcDET5mkas/hDYiCsBrjEeuLMYnn5g8V 2I+Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=4DpQvDzvuH0Xp0AMTMNqHsvMg7iKZVuGSaKcWrlJnAE=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=IdvDdhYLfSkGhpVuT5PSu1sN2MN1tFMVaeDCgL72ZLN1+ib3P65z3rrzo8Xq3XmIDQ CNw+d466Ub8HJ0qSen2vZAft/oVeytcNGcu1Z7gaH7DOr67t/Xl7BLgW4sRGi/z2DnC2 aKnrs3eE2KG93hPejipEr63vkmx5viiftbNA0q4P79O4m/Bh6RhR7+8zwINNqirCbt+T tOtuh+zpE5pa6sx/rZIzGftFuzANS7O/EkDi/69OX/ffi4qO5+UFJKNrBdmEmztTG6Z+ IcbpzJ/NCtrgmUXgxuO8Zm2lRSng9PwwvarGXJHHPVvaJ1GJJ0NUf87/R/lxREYsvW9D /AdQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=G3q5Teif; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l2-20020aa7c302000000b0051dd01ca4dbsi761950edq.15.2023.06.28.07.19.13; Wed, 28 Jun 2023 07:19:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=G3q5Teif; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232265AbjF1OA4 (ORCPT + 99 others); Wed, 28 Jun 2023 10:00:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232209AbjF1OAt (ORCPT ); Wed, 28 Jun 2023 10:00:49 -0400 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 441652947 for ; Wed, 28 Jun 2023 07:00:48 -0700 (PDT) Received: by mail-lf1-x12d.google.com with SMTP id 2adb3069b0e04-4f9fdb0ef35so6403355e87.0 for ; Wed, 28 Jun 2023 07:00:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960846; x=1690552846; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=4DpQvDzvuH0Xp0AMTMNqHsvMg7iKZVuGSaKcWrlJnAE=; b=G3q5Teif93C8ne/ojK7nfQFEznfIrUrYbQGo4q3+UgouYHEGj8yHk2GVYfJZfXKN9b psOZ82P7THTQlbAnOdDEpdSSBfHJHRUVHW3w4V/M0lfV7OnQha4t+867x5JVN2Io9zYJ QTdLkEOzGjScKJYZtxdxY1pBngCqkey4ov7w76AjBU7MneM+gjpWpXP75ikvmxIQ7v39 6ZammyiVyXyO97ZIN0lA3rjMraErrKJJHbcod1jAlaV9M9lw+tIU5cr3324ipwqiVIzb DQq5Ta9dYXk10Jjby76OOpeU5s86iwweel9N+0a8f1QnNSyGqlUt2kK9BY2RrhN/NuBd 7BbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960846; x=1690552846; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4DpQvDzvuH0Xp0AMTMNqHsvMg7iKZVuGSaKcWrlJnAE=; b=RSdab2DFWFiEOXfpeHEGPKtW+Rem/9BnpipJPayGeKVqXehtkT8VDj+/2Yrw1uARvJ Vtv8JnssPXuajqjvGspvNNbajdJB/0oSKIGgioCLx8B863bzUjzUlqaQvScbqg+kYFV9 WDD7UAaOXLTFMqinR/ZFGNFvjMdBb0drEIjSnlY9LUOd4yR3yEis2JayuZPZKaz0XuwO aAzaJSAvS7Eyq1f3Ft8QXTdiXNaTiNr/avh0f6fZf+Te3etB35QJVLW558/mb9JpzHex OssF4Ie2Ni0xOQUUFFdZZAQz+6lQSOkYqVbHy5YFpqWu599zSKNIM1EabUV/TBdhhSUU xrQw== X-Gm-Message-State: AC+VfDwwSCn7mIkDg0xWCo6y4yAbVj+TBWI+tLrYJKxtbzCYQhcP1gEv QblF6vYYe2zK4kOqE9qs99UF3g== X-Received: by 2002:a05:6512:3244:b0:4fb:8ff3:1f72 with SMTP id c4-20020a056512324400b004fb8ff31f72mr1312994lfr.1.1687960846367; Wed, 28 Jun 2023 07:00:46 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:46 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:40 +0200 Subject: [PATCH v12 01/10] cpufreq: blacklist MSM8998 in cpufreq-dt-platdev MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-1-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=855; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=FetjBqwyZiiZA33u+YRzjkX1LSPicSQMKKdZJvWwu44=; b=OHfcT+AKpFDpo67H/3dS4QYFlN1mIkNeaTwlXJzOUd3gWJdKt9nIYv7+5SdkCfVQmUgTzmDwO 5L/Ngk2Ru0oBreAIWws0NVM5CLgTAfYUeXjng/jvSchaPo6a7pYC24C X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956419610981846?= X-GMAIL-MSGID: =?utf-8?q?1769956419610981846?= From: AngeloGioacchino Del Regno Add the MSM8998 to the blacklist since the CPU scaling is handled out of this. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Konrad Dybcio --- drivers/cpufreq/cpufreq-dt-platdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index e2b20080de3a..adb3579a1fee 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -143,6 +143,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "qcom,apq8096", }, { .compatible = "qcom,msm8996", }, + { .compatible = "qcom,msm8998", }, { .compatible = "qcom,qcs404", }, { .compatible = "qcom,sa8155p" }, { .compatible = "qcom,sa8540p" }, From patchwork Wed Jun 28 14:00:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113926 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8963508vqr; Wed, 28 Jun 2023 07:20:29 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5I4JyeNxCrdv53ltQn0dQayiHZBxjUTKgcby6VFa7DULkg2IBS54fS3AgbKoqOvOjpVHc+ X-Received: by 2002:a05:6a21:6d9c:b0:125:6443:4eb8 with SMTP id wl28-20020a056a216d9c00b0012564434eb8mr24080498pzb.5.1687962028669; Wed, 28 Jun 2023 07:20:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687962028; cv=none; d=google.com; s=arc-20160816; b=mUH2hVZlRI8TNmweq7fnQ0hCSZrl9nJ1VOIEgm/j/ggFC0aVCS8eUPbJkLBsVNyRZu PIoT40H8q7/y7CQ/oOETvcmn3yZmEr+ut5G3IknGs9eGqrbJH0jqsVmhpM86KV+mnq+k w8A0qWnjn4DwkUhdojXQeqw1LM9p8uDIT8ONca9Lkm4Ns4MMFIYedMwIpYY/2pmk8GDv m19/eDg6TQ4bKir3wpgeG+2Rqn6SH42H+52cymfJ7EzdPnyevy8Ni7BoSci4PSRs8X/K AnD9h10D2g1tRxvjLmTcl+HOKSYSd1bTwvWDd0dvj1A0FM039TFPxWE2J9/loTF+TZXh WSRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=nPo5IxcZGqbsYAtBW/avfH07eeJrRORrjdw+dNFtBTI=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=STGb32rQKfKV8l6/hHqTrHqE3u80xD8gPstiq7SbRGUxQP2z3yiPqfGkOMUw76rTyL uN/ZJHqtUXaKyZl6+ehpqzM+w2VSslQkf9BlSVl2uzhl4pH72su0ePtF0pNa4XMT654F yQZFldNYU16at8yt2x0BGur31q0KPTY5go3346sCst7OIpJU25+pJ1jQ16hC2sQTs/GA Azaiy3J1wO2Vp6Mq123LdxCU2Pc6ca0pTLGi5JbmQxV2Z3zkJH8ZS5ruBAVKd1cupwkq N2a/gced7miVlYTu2RNX7BB2XDBXPE2MLkioR1wtTOzrSMOHLjMLBlRAUqmvnmpSC+iz wElQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=oCIoTeFp; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e5-20020a170902744500b001ac4f733007si8710213plt.549.2023.06.28.07.20.15; Wed, 28 Jun 2023 07:20:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=oCIoTeFp; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232310AbjF1OBC (ORCPT + 99 others); Wed, 28 Jun 2023 10:01:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232241AbjF1OAv (ORCPT ); Wed, 28 Jun 2023 10:00:51 -0400 Received: from mail-lf1-x12c.google.com (mail-lf1-x12c.google.com [IPv6:2a00:1450:4864:20::12c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE8E72690 for ; Wed, 28 Jun 2023 07:00:49 -0700 (PDT) Received: by mail-lf1-x12c.google.com with SMTP id 2adb3069b0e04-4f973035d60so8047390e87.3 for ; Wed, 28 Jun 2023 07:00:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960848; x=1690552848; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=nPo5IxcZGqbsYAtBW/avfH07eeJrRORrjdw+dNFtBTI=; b=oCIoTeFp554vyWqiLBoNJP5+Fkwpy0gW9Z42J7Q2pjF5cEZueHuqr/X+WNLn9/peMy WTZLFUE0MWglLkq1A0sd2tufzELezVVnh/CKim6ukUBIRBLWG2ekVbmF9v4mMs+KL5Ac q2qnCHUUFRNCxEKPlfJo4uh+DXU/zdi53ZWmhQhbkszwPmKBLeWeOzszuib9wWO0mtug TaxP5S5NJ53t6giDsrTQOF7oL+Fop1nik8+hMykUDWEKKc9c1aRMQ0rjkkg/GQRjNoS5 0LzQWSfCZsaUcjzAlK5X/h8v1j6LK7gBepaCGOL/5CkGdjCZi8T+r1eWgsVBNVclzWkF ICug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960848; x=1690552848; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=nPo5IxcZGqbsYAtBW/avfH07eeJrRORrjdw+dNFtBTI=; b=Z82SUY8LDYUF4heoBxp+kQk/rQO9bTlNBoSxRy3vwAJhDJUoIKKExT1FSrSYoCX08l u6gti6EpopK6jvb87w+47NBqR+vI/zA7s4vQjocB7UJvx8XgW9q6R70To6QYKBKNyJbm 3KZOhj2k3Na1ayme/OnEkw0lIxVIyMj7TqqoCUQt4p3Mm5zVZ6s1EtYd6qgq96z/2iKK pNmQI+DHodd3ZoIjEsFdqXbo+bTmhDvz2X1wv4OR0ZHikC/qF3K5TRC7tY4B+rOLOy4S N/B1fSG1babcwDLmz5Q0pDavi+xeN6vvveot/vAMNYMaGCwzgQyLXL6JfGBlQa8k5pco 9jEQ== X-Gm-Message-State: AC+VfDyAX6Nq3/SdBAS5aSjQMpoWV0+VM2Li4iLZ8vhFtw2RtRJpJPvp vzrhZup37cjZVR3CfVGLxbmRrg== X-Received: by 2002:a19:e612:0:b0:4f8:742f:3bed with SMTP id d18-20020a19e612000000b004f8742f3bedmr14519429lfh.37.1687960847988; Wed, 28 Jun 2023 07:00:47 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:47 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:41 +0200 Subject: [PATCH v12 02/10] MAINTAINERS: Add entry for Qualcomm CPRv3/v4/Hardened driver MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-2-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=932; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=dr0pvAH0vsRUz7z04jyiD7L2OFZkKiQQ83XjJTz9onM=; b=b/ssDcVoAb2/obulGNoHznAhiY6DgCz8kwBvR2rLPHheY1JoCazdSxhh7fJfNDzaAH3JrMRzR gk+BsCJXpQ2AKOCsgoxj/ryqQhUyxqWTYBHixAixlKCMVsXQE2tqklG X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956472135139712?= X-GMAIL-MSGID: =?utf-8?q?1769956472135139712?= From: AngeloGioacchino Del Regno Add maintainers entry for the Qualcomm CPR3/CPR4/CPRh driver. Signed-off-by: AngeloGioacchino Del Regno [Konrad: rebase, update AGdR's email] Signed-off-by: Konrad Dybcio --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4545d4287305..f4218f7a7c33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17581,6 +17581,12 @@ S: Maintained F: Documentation/devicetree/bindings/power/avs/qcom,cpr.yaml F: drivers/soc/qcom/cpr.c +QUALCOMM CORE POWER REDUCTION v3/v4/Hardened AVS DRIVER +M: AngeloGioacchino Del Regno +S: Maintained +F: Documentation/devicetree/bindings/soc/qcom/qcom,cpr3.yaml +F: drivers/soc/qcom/cpr3.c + QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096 M: Ilia Lin L: linux-pm@vger.kernel.org From patchwork Wed Jun 28 14:00:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113930 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8964715vqr; Wed, 28 Jun 2023 07:22:04 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4YBypHbp+DPYdIsUE4ZCr3yzhrXeRD6hDO86Xu1dqIL2/HDaCouAttErOGFMZ9oTzrBa7u X-Received: by 2002:a17:906:648e:b0:988:8e7a:d953 with SMTP id e14-20020a170906648e00b009888e7ad953mr4143182ejm.1.1687962123915; Wed, 28 Jun 2023 07:22:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687962123; cv=none; d=google.com; s=arc-20160816; b=f8XQq4ZKSUS4PpVr1KAtaXr8QfNr5Il61xgy429H9VZ2NAa06HDfXpghubdFlglovj ZOaW6XGi7d7rXhkAr8ndMkxwIKdTsS8Ai0jRr7z9SmWiq2ERr9ZpOX7cVQ82bjShOk1s 9lpmLvsisVsHlITFdNEeTBBkd0pKhqMEjXT1PN3rB7WjICev0MDSneky6qnDNFEvkglr fuIBSyRPLzHnpIuGBlH5f7f8d+/3s93bn/lHnamE1ioOsJw128WKRcLnp7rtoH/AU9Gd 0J0HWghpCZDQFMeBkqTq4dw28ophTn9Q+WFPfO+jJlfeFiGYkDxn4EMqePD7de8UHi5T iqWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=dAlp+yDxSxsRQptzR5NDOwv6iD3bpQxnIcoaRH90yZA=; fh=4QnxOa6B794SVIyocnOVG+x+vajOeIWtq2DTmRXKqj4=; b=JM/0d2qeIzPFs/BUtBagwr7o56hMwlGaMGa4U5WSauOvK2oaNe9VrUYxAhQYwgLvIB r4s7YCRIAUxW7HO/px7PWoyRWFVtJOvi32I21h0/JOqL/4hRtRTrwmVRL3uAJr4XB6yQ /40DMNnm7BUrsRXUxlOKvbra6LG4Xtl1MWMx2B6evxRAKqiGv1Wj6vmYtJ0P1xT5qtRB DcQ+VTL8XWosAqo/oIEBlL0u0+vFB+BoQpVbyk273Dv3QRRLz5S36npa00lKHxp1do/A hFxD3qfDuzTrWH63Ako+oHdYA+jFTEB/GQVQGGaAU3n0o1rxFSOpBJrdUUHmUpni5DOW YVOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=gYGMmZjQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id gl4-20020a170906e0c400b0099283fccb4fsi636113ejb.16.2023.06.28.07.21.29; Wed, 28 Jun 2023 07:22:03 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=gYGMmZjQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232347AbjF1OBG (ORCPT + 99 others); Wed, 28 Jun 2023 10:01:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232274AbjF1OAx (ORCPT ); Wed, 28 Jun 2023 10:00:53 -0400 Received: from mail-lf1-x132.google.com (mail-lf1-x132.google.com [IPv6:2a00:1450:4864:20::132]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 69C2326AB for ; Wed, 28 Jun 2023 07:00:51 -0700 (PDT) Received: by mail-lf1-x132.google.com with SMTP id 2adb3069b0e04-4fa16c6a85cso6587407e87.3 for ; Wed, 28 Jun 2023 07:00:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960849; x=1690552849; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=dAlp+yDxSxsRQptzR5NDOwv6iD3bpQxnIcoaRH90yZA=; b=gYGMmZjQMT2xQ+MvbxcKxMB+lwJeW4SP8q8Ud2ot95OfKdvkuSLkgy8NadKM9kXLXk dwxRfgCRNOakD32hgwNcO3Q+gsPVq1dSg/h87w1589V8HKD74zsOrJ6pc/a8ticZUbD1 +chhL/eqi5fHoxGSwfDChmx9LRPT9PI+XZOgPopzLbGXIGcugRrgEfDHNnDj1oelIdpd Csz4YnKeQGOF1is9KcJrXQ+C522wwQVIrp5UvwYp+iMSwRRgWMzGgvyemd93SFrG7xSg Rlq0ke9ztTGh34i89YSzj5iHR+3DT8mGuBOqLbapQyWoPGsFidQt6qyGV7Yk6Qd52T6Z agBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960849; x=1690552849; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dAlp+yDxSxsRQptzR5NDOwv6iD3bpQxnIcoaRH90yZA=; b=JmxszaQ1M0xiL/ZKm4nVIz+0luZoEXuN6q3kgUuOEatdA45goe4y7pJYD4vb+Z3pJx OC9t4pA43ctPf7Sh5nXceVr1OrjLHSUBgETzS0Jle6fq0sSDAi7e4AAjbaIHI+wxWxPb SILUchzefzhwT59wNvAsgFArExuoU1N4xhD7SOZyxojHF1OVvKCtOHTb5eSBKTZo2Y8A 5F/q49T2gMwvxz4WfNBKbKqVmi1zZUCGgLzyuJf/OlvnZsVMkq07ZRG8S2CxZ3AQOrR6 iNrS0oRuR2MVyk296hB512qnSHNqg183sOkrR+4pTgmCq0ZoP1OEpUyY2wP5RPEIke5R TYZw== X-Gm-Message-State: AC+VfDzpwKMuMEWZuj/6bEBNvepS49JPGgY4TWsjVYpfx6XOi60fGphA bmVUiasT0x+s4rQkRXHepdCT6g== X-Received: by 2002:a05:6512:74a:b0:4f9:b032:5361 with SMTP id c10-20020a056512074a00b004f9b0325361mr7259068lfs.10.1687960849612; Wed, 28 Jun 2023 07:00:49 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:49 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:42 +0200 Subject: [PATCH v12 03/10] dt-bindings: opp: v2-qcom-level: Document CPR3 open/closed loop volt adjustment MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-3-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=1423; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=WRqHzfry/bVzZ1IkMj1Q1p4NGE07AGHXQmZVGRY1FDM=; b=fmRAjhcXakJvteIMyPJ3dqzr/YpyAJd1sbA3FlZU+g97vJPUQvq4+nkL3Y9g27jcuZ6MD3hl3 c8VgaIzIBU/DVfcqSRYBj1Tp2NsHo25lyAmd/r63DUtB/OuralTt5Dr X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956572334801796?= X-GMAIL-MSGID: =?utf-8?q?1769956572334801796?= CPR3 and newer can be fed per-OPP voltage adjustment values for both open- and closed-loop paths to make better decisions about settling on the final voltage offset target. Document these properties. Signed-off-by: Konrad Dybcio Reviewed-by: AngeloGioacchino Del Regno --- .../devicetree/bindings/opp/opp-v2-qcom-level.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/opp/opp-v2-qcom-level.yaml b/Documentation/devicetree/bindings/opp/opp-v2-qcom-level.yaml index a30ef93213c0..b203ea01b17a 100644 --- a/Documentation/devicetree/bindings/opp/opp-v2-qcom-level.yaml +++ b/Documentation/devicetree/bindings/opp/opp-v2-qcom-level.yaml @@ -34,6 +34,20 @@ patternProperties: minItems: 1 maxItems: 2 + qcom,opp-cloop-vadj: + description: | + An array of per-thread values representing the closed-loop + voltage adjustment value associated with this OPP node. + $ref: /schemas/types.yaml#/definitions/int32-array + maxItems: 2 + + qcom,opp-oloop-vadj: + description: | + An array of per-thread values representing the open-loop + voltage adjustment value associated with this OPP node. + $ref: /schemas/types.yaml#/definitions/int32-array + maxItems: 2 + required: - opp-level - qcom,opp-fuse-level From patchwork Wed Jun 28 14:00:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113932 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8965289vqr; Wed, 28 Jun 2023 07:22:57 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4/lepL0uPcGTmqqP6WwSaR1SlbY0+r/KACFA+kQ58TNl+XUN3FngINftOEs1m6pps6/mMA X-Received: by 2002:a05:6a00:24cf:b0:676:2a5c:7bc5 with SMTP id d15-20020a056a0024cf00b006762a5c7bc5mr10944923pfv.1.1687962177448; Wed, 28 Jun 2023 07:22:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687962177; cv=none; d=google.com; s=arc-20160816; b=aZEovKa3JdsQKzrLaGuZ7JsnhfL6Ef5C4a22dALgtvwqjjoIl+KQgSeUEQYNmg0Fz2 y+89H4XKck4bP7OfFYUQhk6tvRz7HQL0t9xmPiI8SGkjF/DefGI9rsqSSoGr6xX9GFDd fRKMigz7554KlqjGUpiraKZ0XLTWCJACWTNZ5PnNb2QXVxMFvwv9o+7vOvFAR9OmMane cljEr5BVC+vf+qAV8SfFLkn3ZijxLO173SxR0TKUI3nVQRfjCdHZ72AWmGxKPbz5Tyy9 INyDoxTICu/N4Qzu6ZAnCVHSmNjucmRMWG6DYT2mmiomUPPyIo/zICOZXbFTG+hhLoUR lCdA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=/mDU0vzze/ov8lSvaXaSMAceWfhtBvQ2qAMt330k4/s=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=pcJk0s7ccb3Dm0KGUi4uUmvXaHRtQx3mhSrJywyfhSteUlAUmMeqypxtj+fQwws5a3 r9IVw2ZYYL9OyUzn4ZXi3bEe/QgpOO2FflkQaEgrWmCE4Bc1paeGCuCJPfoIgiIeW2AW kKi5AtVj08zMIRHNd0Q2ICL3f0zC6dGvbk6SDGY+jZTmWAlf7xJVgDfqWdt9wWaGwoB+ z4W4qee/UIYNaWFgMMqprjMo1vp+saX3uFDBwpnxFpMgY0VK1Qz3J91c2V3hD/20D+81 idc3m7+ZIoVGIxMe86wuNNmY3cQQNYV4zcW8+80H57Ckx8OnJoPOeQZBKaMU3SvHp4oj 6JPw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="J/nIApNP"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l5-20020a056a0016c500b0066882f939e4si9491428pfc.169.2023.06.28.07.22.43; Wed, 28 Jun 2023 07:22:57 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="J/nIApNP"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232444AbjF1OBT (ORCPT + 99 others); Wed, 28 Jun 2023 10:01:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51342 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232268AbjF1OA5 (ORCPT ); Wed, 28 Jun 2023 10:00:57 -0400 Received: from mail-lf1-x129.google.com (mail-lf1-x129.google.com [IPv6:2a00:1450:4864:20::129]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D51D8294E for ; Wed, 28 Jun 2023 07:00:54 -0700 (PDT) Received: by mail-lf1-x129.google.com with SMTP id 2adb3069b0e04-4fb960b7c9dso515338e87.0 for ; Wed, 28 Jun 2023 07:00:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960853; x=1690552853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=/mDU0vzze/ov8lSvaXaSMAceWfhtBvQ2qAMt330k4/s=; b=J/nIApNP/by2XHNLQELvkjSVb3C2GyyRDm0MtS7SarCGfx9aS7iejAAERTCM3Ck9hZ Bl4xijgVlIfWG29VXkjCVUCXrH73JPV8U/AbXqG2a2tCPX/Z7Hf5TczCNV7fmc7/wvEe if7o3vohiiA2D5LwBhOICox+dthgcaR4Qmuc7oEeeDRJxBpX5XHlj4fkMLBkRe22BG7l YasbPFEOY1ZoFvL6QK4pnhDXNITcFK6gz9A671a8OZ2yyeszgfY4nlhuW6PBRYkrdYdd yVp34J8p9N1EJh1ogURSL9BHBo7OE7snTxjTcfbCmGvAlKxCsFHL3cpvpw80LpUg/Kke dC9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960853; x=1690552853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/mDU0vzze/ov8lSvaXaSMAceWfhtBvQ2qAMt330k4/s=; b=gVongNEXypS4qFrcjbksse/SvLqGz3se18h/i6/rnNdDvAwj7D1aabb5ftcgqtY4vt JpKp6K1vZ3B38kErW7+oB3yrD7iLKHj/GLD8Wutf5WYBwxIB60b073KnzE4Bd6eGYOYy 9rveSiLg20+7tWJgDRcEpjeer8+wjoC4w4f9ylp9OSNhnFQJ6fhPJu4GWWbGiCzP0nHh v5rDLEJRL7cXz3A3YXVNbI6csgO1A+54gqf6Zd1X0P0ytS6SGzr1MKN9S6eAiH0be7XS y7xDp2y5Xvf6AmscPYe+p6ix52kgy6zD6TQ8ac51pzHuUE99NTZPnixae4GJ5FtANBUi AZOQ== X-Gm-Message-State: AC+VfDxUiBrscPabWeNWfiRU4BfDJ3cugxo0I5lK/S9gKVY/39hLfV/N aRL12JgH+fk7ugd27c9sAUBO2g== X-Received: by 2002:a05:6512:3b13:b0:4fb:8bea:f5f7 with SMTP id f19-20020a0565123b1300b004fb8beaf5f7mr2968861lfv.11.1687960851584; Wed, 28 Jun 2023 07:00:51 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:51 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:43 +0200 Subject: [PATCH v12 04/10] dt-bindings: soc: qcom: cpr3: Add bindings for CPR3 driver MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-4-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=10291; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=XsgCikCmVAkzuppoOZcUQl3FsJV4tSEV5u46Y3qt2EA=; b=Vng0cZmmheRsYEyIeZN8j35/zxj1ihRaw9Smess8c+jlXUt3vLeTrIiH73Romg1/wA3LeHNWm +6LBCxrK9SJD7/ASryNKMqeoe5Q9icGFmgzJbcHofdAh3j/FdkTz6K3 X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956628058509680?= X-GMAIL-MSGID: =?utf-8?q?1769956628058509680?= From: AngeloGioacchino Del Regno Add the bindings for the CPR3 driver to the documentation. Signed-off-by: AngeloGioacchino Del Regno [Konrad: Make binding check pass; update AGdR's email] Signed-off-by: Konrad Dybcio --- .../devicetree/bindings/soc/qcom/qcom,cpr3.yaml | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,cpr3.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,cpr3.yaml new file mode 100644 index 000000000000..46b94dffaf85 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,cpr3.yaml @@ -0,0 +1,289 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/qcom/qcom,cpr3.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Core Power Reduction v3/v4/Hardened (CPR3, CPR4, CPRh) + +description: + CPR (Core Power Reduction) is a technology to reduce core power of a CPU + (or another device). Each OPP of a device corresponds to a "corner" that + has a range of valid voltages for a particular frequency. + The CPR monitors dynamic factors such as temperature, etc. and suggests + or (in the CPR-hardened case) applies voltage adjustments to save power + and meet silicon characteristic requirements for a given chip unit. + +maintainers: + - AngeloGioacchino Del Regno + +properties: + compatible: + oneOf: + - description: CPRv3 controller + items: + - const: qcom,cpr3 + - description: CPRv4 controller + items: + - const: qcom,cpr4 + - description: CPRv4-Hardened controller + items: + - enum: + - qcom,msm8998-cprh + - qcom,sdm630-cprh + - const: qcom,cprh + + reg: + description: Base address and size of the CPR controller(s) + maxItems: 2 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: CPR reference clock + + vdd-supply: + description: Autonomous Phase Control (APC) or other power supply + + '#power-domain-cells': + const: 1 + + qcom,acc: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to syscon for writing ACC settings + + nvmem-cells: + description: Cells containing the fuse corners and revision data + maxItems: 32 + + nvmem-cell-names: + maxItems: 32 + + operating-points-v2: true + + power-domains: true + +required: + - compatible + - reg + - clocks + - operating-points-v2 + - "#power-domain-cells" + - nvmem-cells + - nvmem-cell-names + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-cprh + then: + properties: + nvmem-cell-names: + items: + - const: cpr_speed_bin + - const: cpr_fuse_revision + - const: cpr0_quotient1 + - const: cpr0_quotient2 + - const: cpr0_quotient3 + - const: cpr0_quotient4 + - const: cpr0_quotient_offset2 + - const: cpr0_quotient_offset3 + - const: cpr0_quotient_offset4 + - const: cpr0_init_voltage1 + - const: cpr0_init_voltage2 + - const: cpr0_init_voltage3 + - const: cpr0_init_voltage4 + - const: cpr0_ring_osc1 + - const: cpr0_ring_osc2 + - const: cpr0_ring_osc3 + - const: cpr0_ring_osc4 + - const: cpr1_quotient1 + - const: cpr1_quotient2 + - const: cpr1_quotient3 + - const: cpr1_quotient4 + - const: cpr1_quotient_offset2 + - const: cpr1_quotient_offset3 + - const: cpr1_quotient_offset4 + - const: cpr1_init_voltage1 + - const: cpr1_init_voltage2 + - const: cpr1_init_voltage3 + - const: cpr1_init_voltage4 + - const: cpr1_ring_osc1 + - const: cpr1_ring_osc2 + - const: cpr1_ring_osc3 + - const: cpr1_ring_osc4 + +examples: + - | + #include + #include + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,kryo280"; + device_type = "cpu"; + reg = <0x0 0x0>; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&apc_cprh 0>; + power-domain-names = "cprh"; + }; + + cpu@100 { + compatible = "qcom,kryo280"; + device_type = "cpu"; + reg = <0x0 0x100>; + operating-points-v2 = <&cpu4_opp_table>; + power-domains = <&apc_cprh 1>; + power-domain-names = "cprh"; + }; + }; + + cpu0_opp_table: opp-table-cpu0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1843200000 { + opp-hz = /bits/ 64 <1843200000>; + required-opps = <&cprh_opp3>; + }; + + opp-1094400000 { + opp-hz = /bits/ 64 <1094400000>; + required-opps = <&cprh_opp2>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&cprh_opp1>; + }; + }; + + cpu4_opp_table: opp-table-cpu4 { + compatible = "operating-points-v2"; + opp-shared; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + required-opps = <&cprh_opp3>; + }; + + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + required-opps = <&cprh_opp2>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&cprh_opp1>; + }; + }; + + cprh_opp_table: opp-table-cprh { + compatible = "operating-points-v2-qcom-level"; + + cprh_opp1: opp-1 { + opp-level = <1>; + qcom,opp-fuse-level = <1>; + qcom,opp-cloop-vadj = <0>; + qcom,opp-oloop-vadj = <0>; + }; + + cprh_opp2: opp-2 { + opp-level = <2>; + qcom,opp-fuse-level = <2>; + qcom,opp-cloop-vadj = <0>; + qcom,opp-oloop-vadj = <0>; + }; + + cprh_opp3: opp-3 { + opp-level = <3>; + qcom,opp-fuse-level = <2 3>; + qcom,opp-cloop-vadj = <0>; + qcom,opp-oloop-vadj = <0>; + }; + }; + + apc_cprh: power-controller@179c8000 { + compatible = "qcom,msm8998-cprh", "qcom,cprh"; + reg = <0x0179c8000 0x4000>, <0x0179c4000 0x4000>; + clocks = <&gcc GCC_HMSS_RBCPR_CLK>; + + operating-points-v2 = <&cprh_opp_table>; + #power-domain-cells = <1>; + + nvmem-cells = <&cpr_efuse_speedbin>, + <&cpr_fuse_revision>, + <&cpr_quot0_pwrcl>, + <&cpr_quot1_pwrcl>, + <&cpr_quot2_pwrcl>, + <&cpr_quot3_pwrcl>, + <&cpr_quot_offset1_pwrcl>, + <&cpr_quot_offset2_pwrcl>, + <&cpr_quot_offset3_pwrcl>, + <&cpr_init_voltage0_pwrcl>, + <&cpr_init_voltage1_pwrcl>, + <&cpr_init_voltage2_pwrcl>, + <&cpr_init_voltage3_pwrcl>, + <&cpr_ro_sel0_pwrcl>, + <&cpr_ro_sel1_pwrcl>, + <&cpr_ro_sel2_pwrcl>, + <&cpr_ro_sel3_pwrcl>, + <&cpr_quot0_perfcl>, + <&cpr_quot1_perfcl>, + <&cpr_quot2_perfcl>, + <&cpr_quot3_perfcl>, + <&cpr_quot_offset1_perfcl>, + <&cpr_quot_offset2_perfcl>, + <&cpr_quot_offset3_perfcl>, + <&cpr_init_voltage0_perfcl>, + <&cpr_init_voltage1_perfcl>, + <&cpr_init_voltage2_perfcl>, + <&cpr_init_voltage3_perfcl>, + <&cpr_ro_sel0_perfcl>, + <&cpr_ro_sel1_perfcl>, + <&cpr_ro_sel2_perfcl>, + <&cpr_ro_sel3_perfcl>; + nvmem-cell-names = "cpr_speed_bin", + "cpr_fuse_revision", + "cpr0_quotient1", + "cpr0_quotient2", + "cpr0_quotient3", + "cpr0_quotient4", + "cpr0_quotient_offset2", + "cpr0_quotient_offset3", + "cpr0_quotient_offset4", + "cpr0_init_voltage1", + "cpr0_init_voltage2", + "cpr0_init_voltage3", + "cpr0_init_voltage4", + "cpr0_ring_osc1", + "cpr0_ring_osc2", + "cpr0_ring_osc3", + "cpr0_ring_osc4", + "cpr1_quotient1", + "cpr1_quotient2", + "cpr1_quotient3", + "cpr1_quotient4", + "cpr1_quotient_offset2", + "cpr1_quotient_offset3", + "cpr1_quotient_offset4", + "cpr1_init_voltage1", + "cpr1_init_voltage2", + "cpr1_init_voltage3", + "cpr1_init_voltage4", + "cpr1_ring_osc1", + "cpr1_ring_osc2", + "cpr1_ring_osc3", + "cpr1_ring_osc4"; + }; +... From patchwork Wed Jun 28 14:00:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113923 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8961904vqr; Wed, 28 Jun 2023 07:18:24 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4yloybW+j+Gbx7e/OrfL1Q7I9H7JqfsfcjjpejeQZKC65VIzAxMFU9QCtkePdaJiW1SdWg X-Received: by 2002:a2e:b889:0:b0:2b6:9ebc:d8c4 with SMTP id r9-20020a2eb889000000b002b69ebcd8c4mr31289ljp.0.1687961904405; Wed, 28 Jun 2023 07:18:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687961904; cv=none; d=google.com; s=arc-20160816; b=ZawP+dMVlAjFgbfR2H5R0+3rZOaS2OY4ZIaJAtxh1ldBIlxCuCTKGUfKvR4gmHiJuG dlt05O6ZIYfLn/7KQvJqvq9kGUKO2DQkgjH+h28Pi1I2ZHyckx2aJXMk91tIedKrqP9M 09xf8QDCxTPCN1A86JULk5Co36+whlGWIS790Ak58BIQOus+sHSn2oyZDtVIV6Ha7pAc B+XbmsuHf3g+tabbsG0glCSDcjvE4IeC5K/RhuRjMGfe3vg80v8rJ7MvNXbu7JTGGnK5 u8eiA3418VoC7Mh774HXFGJKyxlMHb/paqSBH0gK6tsPdSlpq0B4xxiDnA0yqnoGkuRf MV+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=gSoFxDpo8ueVy/vAg4zKAz0XPpEp/jM8wg58zEJk7RM=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=OYJZHl4z1TIibRbOifg5reDkBevtLWPy3ighg1qw9ke1wcjOOifjZ/W6h5u4NKPCgQ S9UX2mcb/OD/VIIRqjx5NpvPUeM4ZO9++J3rIpDFTdvS6K4V/mzt4jf73Mg+QRVI6ihb VPX0RQiTa60q6bd5Sm21hL/70gsLGA7jXuWE0Ydq2ePfya86C5H/vQPlIaC4ine0JUZT AXX03Y0XTo03XVMY3XB2R7nnYTrKQGnh2Ya6zXjT41QvG/uRRiA8Ulc8x0QVP4J1HzeT IkAzCk2PMBGOE8U3fnhaTf63u3I95L5j12UTZVsd1CXVkd7Nzmkant2Y9scbfDs2m3Ev 2FgA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=wJOMn5FO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t26-20020a1709060c5a00b0098dfdc3f2e2si5230509ejf.745.2023.06.28.07.17.59; Wed, 28 Jun 2023 07:18:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=wJOMn5FO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232554AbjF1OBz (ORCPT + 99 others); Wed, 28 Jun 2023 10:01:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232372AbjF1OBJ (ORCPT ); Wed, 28 Jun 2023 10:01:09 -0400 Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F2812733 for ; Wed, 28 Jun 2023 07:00:55 -0700 (PDT) Received: by mail-lf1-x133.google.com with SMTP id 2adb3069b0e04-4f8775126d3so8344536e87.1 for ; Wed, 28 Jun 2023 07:00:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960853; x=1690552853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=gSoFxDpo8ueVy/vAg4zKAz0XPpEp/jM8wg58zEJk7RM=; b=wJOMn5FOzl+s7DSJXudsTrbTQrYOqAs++X6eRDBdCL/y/gKBsbMyege0j/nBmbC+sb OsrzEb7aOO4W7nMS/J0maT3X4MO866pqEwT6F0LmAx7fx5g7/fXRRrYOGv0c3ge0qGe3 sSntrd1wAq+/1yUm/I9ESUntcEO/xJBEuh1nKipw5nxsbpsj/iuJzxUcuFIyZC8gu/kN j0fTXQytuWcYXO9/VJZ9GKiuZ7mKJICmmCOZxmbj9xH4ENHpFQT8FtoXclKlmu6bFhtD KYRQvGVYCiTbK1KfmAsp3CfWCeHZd29c1+xX4X5ojRcExfB/fttfSdka+iRhMi9sEsI9 oOyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960853; x=1690552853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gSoFxDpo8ueVy/vAg4zKAz0XPpEp/jM8wg58zEJk7RM=; b=HgoE0sgSIQS8tYiKrHmc21QghiezMw8Lw4jfq2zRGlf461U4KdElHjSoRkpdcxuXbL lvDN4Oj7w4IVMTTIT4GDNYibQzSEbhXpLhEWhV8LN6+ruJEacgNGSXUO3oa89s+8Anch ts8HdK4hnv6tCSc7jdwfOOHD4yk/sHxUeOVTb+jfWCKM0R71l74YAqu/q+YjowJzSj+z yjPeAy14RcpZR2ZcmoJiDe9qyz2QpDqAMPj1tpZZxL6sh9Wng8owttB66JDEfjAlgqW0 lg2yexGL3SEGfhPHFnlAZshlet2M9ASepJFJ4ZAnoTo1vwXiZaXAQM1y6afKwox0FjR0 hfyw== X-Gm-Message-State: AC+VfDwbDp3Y9Y4vJ9AFVJZFPpuNYkmHWkbVdGENUGDQWiSr7Fe1yTHS q+rxyziXPBuubzMRp/T0joAwgezUo/U6zFZVHDw= X-Received: by 2002:a05:6512:32d3:b0:4f9:6528:fb1e with SMTP id f19-20020a05651232d300b004f96528fb1emr15446675lfg.51.1687960853525; Wed, 28 Jun 2023 07:00:53 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:53 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:44 +0200 Subject: [PATCH v12 05/10] soc: qcom: cpr: Move common functions to new file MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-5-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=27820; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=S/XhvP0zPz3smdIa7pQn2z1eb+cDi1RTa9d2k7I5tVo=; b=a6jI903qmjkBBZ8Sl0sgFQIZoMWnMS2BvN+IdHAA3PXAihgNyZdiTPemf3CyW5Kf+AJetZNif IuNJnLkZcsiBkRgQBuxBUfRgl6Df9uXUalGB1GrMinieTQWFp6lQYHH X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956342051693366?= X-GMAIL-MSGID: =?utf-8?q?1769956342051693366?= From: AngeloGioacchino Del Regno In preparation for implementing a new driver that will be handling CPRv3, CPRv4 and CPR-Hardened, format out common functions to a new file. Update cpr_get_fuses in preparation for CPR3 implementation, change parameters where necessary to not take cpr.c private data structures. Signed-off-by: AngeloGioacchino Del Regno [Konrad: rebase, apply review comments, improve msg, split] Signed-off-by: Konrad Dybcio --- drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/cpr-common.c | 350 ++++++++++++++++++++++++++++++++++++++ drivers/soc/qcom/cpr-common.h | 103 +++++++++++ drivers/soc/qcom/cpr.c | 384 +++--------------------------------------- 4 files changed, 475 insertions(+), 364 deletions(-) diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 99114c71092b..82b23743371b 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -3,7 +3,7 @@ CFLAGS_rpmh-rsc.o := -I$(src) obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_CPR) += cpr.o +obj-$(CONFIG_QCOM_CPR) += cpr-common.o cpr.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_OCMEM) += ocmem.o diff --git a/drivers/soc/qcom/cpr-common.c b/drivers/soc/qcom/cpr-common.c new file mode 100644 index 000000000000..ea85f6b4bef8 --- /dev/null +++ b/drivers/soc/qcom/cpr-common.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpr-common.h" + +int cpr_populate_ring_osc_idx(struct device *dev, + struct fuse_corner *fuse_corner, + const struct cpr_fuse *cpr_fuse, + int num_fuse_corners) +{ + struct fuse_corner *end = fuse_corner + num_fuse_corners; + u32 data; + int ret; + + for (; fuse_corner < end; fuse_corner++, cpr_fuse++) { + ret = nvmem_cell_read_variable_le_u32(dev, cpr_fuse->ring_osc, &data); + if (ret) + return ret; + fuse_corner->ring_osc_idx = data; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cpr_populate_ring_osc_idx); + +static int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV, + int step_volt, const char *init_v_efuse, + struct device *dev) +{ + int steps, uV; + u32 bits = 0; + int ret; + + ret = nvmem_cell_read_variable_le_u32(dev, init_v_efuse, &bits); + if (ret) + return ret; + + steps = bits & ~BIT(init_v_width - 1); + /* Not two's complement.. instead highest bit is sign bit */ + if (bits & BIT(init_v_width - 1)) + steps = -steps; + + uV = ref_uV + steps * step_size_uV; + + return DIV_ROUND_UP(uV, step_volt) * step_volt; +} + +const struct cpr_fuse *cpr_get_fuses(struct device *dev, + unsigned int num_fuse_corners) +{ + struct cpr_fuse *fuses; + int i; + + fuses = devm_kcalloc(dev, num_fuse_corners, sizeof(*fuses), GFP_KERNEL); + if (!fuses) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < num_fuse_corners; i++) { + char tbuf[32]; + + snprintf(tbuf, 32, "cpr_ring_osc%d", i + 1); + fuses[i].ring_osc = devm_kstrdup(dev, tbuf, GFP_KERNEL); + if (!fuses[i].ring_osc) + return ERR_PTR(-ENOMEM); + + snprintf(tbuf, 32, "cpr_init_voltage%d", i + 1); + fuses[i].init_voltage = devm_kstrdup(dev, tbuf, GFP_KERNEL); + if (!fuses[i].init_voltage) + return ERR_PTR(-ENOMEM); + + snprintf(tbuf, 32, "cpr_quotient%d", i + 1); + fuses[i].quotient = devm_kstrdup(dev, tbuf, GFP_KERNEL); + if (!fuses[i].quotient) + return ERR_PTR(-ENOMEM); + + snprintf(tbuf, 32, "cpr_quotient_offset%d", i + 1); + fuses[i].quotient_offset = devm_kstrdup(dev, tbuf, GFP_KERNEL); + if (!fuses[i].quotient_offset) + return ERR_PTR(-ENOMEM); + } + + return fuses; +} +EXPORT_SYMBOL_GPL(cpr_get_fuses); + +int cpr_populate_fuse_common(struct device *dev, + struct fuse_corner_data *fdata, + const struct cpr_fuse *cpr_fuse, + struct fuse_corner *fuse_corner, + int step_volt, int init_v_width, + int init_v_step) +{ + int uV, ret; + + /* Populate uV */ + uV = cpr_read_fuse_uV(init_v_width, init_v_step, + fdata->ref_uV, step_volt, + cpr_fuse->init_voltage, dev); + if (uV < 0) + return uV; + + /* + * Update SoC voltages: platforms might choose a different + * regulators than the one used to characterize the algorithms + * (ie, init_voltage_step). + */ + fdata->min_uV = roundup(fdata->min_uV, step_volt); + fdata->max_uV = roundup(fdata->max_uV, step_volt); + + fuse_corner->min_uV = fdata->min_uV; + fuse_corner->max_uV = fdata->max_uV; + fuse_corner->uV = clamp(uV, fuse_corner->min_uV, fuse_corner->max_uV); + + /* Populate target quotient by scaling */ + ret = nvmem_cell_read_variable_le_u32(dev, cpr_fuse->quotient, &fuse_corner->quot); + if (ret) + return ret; + + fuse_corner->quot *= fdata->quot_scale; + fuse_corner->quot += fdata->quot_offset; + fuse_corner->quot += fdata->quot_adjust; + + return 0; +} +EXPORT_SYMBOL_GPL(cpr_populate_fuse_common); + +int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk, + struct corner *corners, int num_corners) +{ + unsigned long rate; + struct corner *iter, *corner; + const struct corner *end; + unsigned int i = 0; + + if (!cpu_clk) { + dev_err(dev, "cannot get rate from NULL clk\n"); + return -EINVAL; + } + + end = &corners[num_corners - 1]; + rate = clk_get_rate(cpu_clk); + + /* + * Some bootloaders set a CPU clock frequency that is not defined + * in the OPP table. When running at an unlisted frequency, + * cpufreq_online() will change to the OPP which has the lowest + * frequency, at or above the unlisted frequency. + * Since cpufreq_online() always "rounds up" in the case of an + * unlisted frequency, this function always "rounds down" in case + * of an unlisted frequency. That way, when cpufreq_online() + * triggers the first ever call to cpr_set_performance_state(), + * it will correctly determine the direction as UP. + */ + for (iter = corners; iter <= end; iter++) { + if (iter->freq > rate) + break; + i++; + if (iter->freq == rate) { + corner = iter; + break; + } + if (iter->freq < rate) + corner = iter; + } + + if (!corner) { + dev_err(dev, "boot up corner not found\n"); + return -EINVAL; + } + + dev_dbg(dev, "boot up perf state: %u\n", i); + + return 0; +} +EXPORT_SYMBOL_GPL(cpr_find_initial_corner); + +unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp) +{ + struct device_node *np; + unsigned int fuse_corner = 0; + + np = dev_pm_opp_get_of_node(opp); + if (of_property_read_u32(np, "qcom,opp-fuse-level", &fuse_corner)) + pr_err("%s: missing 'qcom,opp-fuse-level' property\n", + __func__); + + of_node_put(np); + + return fuse_corner; +} +EXPORT_SYMBOL_GPL(cpr_get_fuse_corner); + +unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, + struct device *cpu_dev) +{ + u64 rate = 0; + struct device_node *ref_np; + struct device_node *desc_np; + struct device_node *child_np = NULL; + struct device_node *child_req_np = NULL; + + desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); + if (!desc_np) + return 0; + + ref_np = dev_pm_opp_get_of_node(ref); + if (!ref_np) + goto out_ref; + + do { + of_node_put(child_req_np); + child_np = of_get_next_available_child(desc_np, child_np); + child_req_np = of_parse_phandle(child_np, "required-opps", 0); + } while (child_np && child_req_np != ref_np); + + if (child_np && child_req_np == ref_np) + of_property_read_u64(child_np, "opp-hz", &rate); + + of_node_put(child_req_np); + of_node_put(child_np); + of_node_put(ref_np); +out_ref: + of_node_put(desc_np); + + return (unsigned long) rate; +} +EXPORT_SYMBOL_GPL(cpr_get_opp_hz_for_req); + +int cpr_calculate_scaling(struct device *dev, + const char *quot_offset, + const struct fuse_corner_data *fdata, + const struct corner *corner) +{ + u32 quot_diff = 0; + unsigned long freq_diff; + int scaling; + const struct fuse_corner *fuse, *prev_fuse; + int ret; + + fuse = corner->fuse_corner; + prev_fuse = fuse - 1; + + if (quot_offset) { + ret = nvmem_cell_read_variable_le_u32(dev, quot_offset, "_diff); + if (ret) + return ret; + + quot_diff *= fdata->quot_offset_scale; + quot_diff += fdata->quot_offset_adjust; + } else { + quot_diff = fuse->quot - prev_fuse->quot; + } + + freq_diff = fuse->max_freq - prev_fuse->max_freq; + freq_diff /= 1000000; /* Convert to MHz */ + scaling = 1000 * quot_diff / freq_diff; + return min(scaling, fdata->max_quot_scale); +} +EXPORT_SYMBOL_GPL(cpr_calculate_scaling); + +int cpr_interpolate(const struct corner *corner, int step_volt, + const struct fuse_corner_data *fdata) +{ + unsigned long f_high, f_low, f_diff; + int uV_high, uV_low, uV; + u64 temp, temp_limit; + const struct fuse_corner *fuse, *prev_fuse; + + fuse = corner->fuse_corner; + prev_fuse = fuse - 1; + + f_high = fuse->max_freq; + f_low = prev_fuse->max_freq; + uV_high = fuse->uV; + uV_low = prev_fuse->uV; + f_diff = fuse->max_freq - corner->freq; + + /* + * Don't interpolate in the wrong direction. This could happen + * if the adjusted fuse voltage overlaps with the previous fuse's + * adjusted voltage. + */ + if (f_high <= f_low || uV_high <= uV_low || f_high <= corner->freq) + return corner->uV; + + temp = f_diff * (uV_high - uV_low); + temp = div64_ul(temp, f_high - f_low); + + /* + * max_volt_scale has units of uV/MHz while freq values + * have units of Hz. Divide by 1000000 to convert to. + */ + temp_limit = f_diff * fdata->max_volt_scale; + do_div(temp_limit, 1000000); + + uV = uV_high - min(temp, temp_limit); + return roundup(uV, step_volt); +} +EXPORT_SYMBOL_GPL(cpr_interpolate); + +int cpr_check_vreg_constraints(struct device *dev, struct regulator *vreg, + struct fuse_corner *f) +{ + int ret; + + ret = regulator_is_supported_voltage(vreg, f->min_uV, f->min_uV); + if (!ret) { + dev_err(dev, "min uV: %d not supported by regulator\n", + f->min_uV); + return -EINVAL; + } + + ret = regulator_is_supported_voltage(vreg, f->max_uV, f->max_uV); + if (!ret) { + dev_err(dev, "max uV: %d not supported by regulator\n", + f->max_uV); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cpr_check_vreg_constraints); + +MODULE_DESCRIPTION("Core Power Reduction (CPR) common"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/cpr-common.h b/drivers/soc/qcom/cpr-common.h new file mode 100644 index 000000000000..1f2ebf9394cf --- /dev/null +++ b/drivers/soc/qcom/cpr-common.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include + +enum voltage_change_dir { + NO_CHANGE, + DOWN, + UP, +}; + +struct cpr_fuse { + char *ring_osc; + char *init_voltage; + char *quotient; + char *quotient_offset; +}; + +struct fuse_corner_data { + int ref_uV; + int max_uV; + int min_uV; + int max_volt_scale; + int max_quot_scale; + /* fuse quot */ + int quot_offset; + int quot_scale; + int quot_adjust; + /* fuse quot_offset */ + int quot_offset_scale; + int quot_offset_adjust; +}; + +struct fuse_corner { + int min_uV; + int max_uV; + int uV; + int quot; + int step_quot; + const struct reg_sequence *accs; + int num_accs; + unsigned long max_freq; + u8 ring_osc_idx; +}; + +struct corner { + int min_uV; + int max_uV; + int uV; + int last_uV; + int quot_adjust; + u32 save_ctl; + u32 save_irq; + unsigned long freq; + struct fuse_corner *fuse_corner; +}; + +struct corner_data { + unsigned int fuse_corner; + unsigned long freq; +}; + +struct acc_desc { + unsigned int enable_reg; + u32 enable_mask; + + struct reg_sequence *config; + struct reg_sequence *settings; + int num_regs_per_fuse; +}; + +struct cpr_acc_desc { + const struct cpr_desc *cpr_desc; + const struct acc_desc *acc_desc; +}; + +int cpr_populate_ring_osc_idx(struct device *dev, + struct fuse_corner *fuse_corner, + const struct cpr_fuse *cpr_fuse, + int num_fuse_corners); +const struct cpr_fuse *cpr_get_fuses(struct device *dev, + unsigned int num_fuse_corners); +int cpr_populate_fuse_common(struct device *dev, + struct fuse_corner_data *fdata, + const struct cpr_fuse *cpr_fuse, + struct fuse_corner *fuse_corner, + int step_volt, int init_v_width, + int init_v_step); +int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk, + struct corner *corners, int num_corners); +u32 cpr_get_fuse_corner(struct dev_pm_opp *opp); +unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, + struct device *cpu_dev); +int cpr_calculate_scaling(struct device *dev, + const char *quot_offset, + const struct fuse_corner_data *fdata, + const struct corner *corner); +int cpr_interpolate(const struct corner *corner, int step_volt, + const struct fuse_corner_data *fdata); +int cpr_check_vreg_constraints(struct device *dev, struct regulator *vreg, + struct fuse_corner *f); diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index 144ea68e0920..cc1e4c462d1f 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -26,6 +26,8 @@ #include #include +#include "cpr-common.h" + /* Register Offsets for RB-CPR and Bit Definitions */ /* RBCPR Version Register */ @@ -124,45 +126,12 @@ #define FUSE_REVISION_UNKNOWN (-1) -enum voltage_change_dir { - NO_CHANGE, - DOWN, - UP, -}; - -struct cpr_fuse { - char *ring_osc; - char *init_voltage; - char *quotient; - char *quotient_offset; -}; - -struct fuse_corner_data { - int ref_uV; - int max_uV; - int min_uV; - int max_volt_scale; - int max_quot_scale; - /* fuse quot */ - int quot_offset; - int quot_scale; - int quot_adjust; - /* fuse quot_offset */ - int quot_offset_scale; - int quot_offset_adjust; -}; - struct cpr_fuses { int init_voltage_step; int init_voltage_width; struct fuse_corner_data *fuse_corner_data; }; -struct corner_data { - unsigned int fuse_corner; - unsigned long freq; -}; - struct cpr_desc { unsigned int num_fuse_corners; int min_diff_quot; @@ -184,44 +153,6 @@ struct cpr_desc { bool reduce_to_corner_uV; }; -struct acc_desc { - unsigned int enable_reg; - u32 enable_mask; - - struct reg_sequence *config; - struct reg_sequence *settings; - int num_regs_per_fuse; -}; - -struct cpr_acc_desc { - const struct cpr_desc *cpr_desc; - const struct acc_desc *acc_desc; -}; - -struct fuse_corner { - int min_uV; - int max_uV; - int uV; - int quot; - int step_quot; - const struct reg_sequence *accs; - int num_accs; - unsigned long max_freq; - u8 ring_osc_idx; -}; - -struct corner { - int min_uV; - int max_uV; - int uV; - int last_uV; - int quot_adjust; - u32 save_ctl; - u32 save_irq; - unsigned long freq; - struct fuse_corner *fuse_corner; -}; - struct cpr_drv { unsigned int num_corners; unsigned int ref_clk_khz; @@ -801,50 +732,6 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain, return ret; } -static int -cpr_populate_ring_osc_idx(struct cpr_drv *drv) -{ - struct fuse_corner *fuse = drv->fuse_corners; - struct fuse_corner *end = fuse + drv->desc->num_fuse_corners; - const struct cpr_fuse *fuses = drv->cpr_fuses; - u32 data; - int ret; - - for (; fuse < end; fuse++, fuses++) { - ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->ring_osc, &data); - if (ret) - return ret; - fuse->ring_osc_idx = data; - } - - return 0; -} - -static int cpr_read_fuse_uV(const struct cpr_desc *desc, - const struct fuse_corner_data *fdata, - const char *init_v_efuse, - int step_volt, - struct cpr_drv *drv) -{ - int step_size_uV, steps, uV; - u32 bits = 0; - int ret; - - ret = nvmem_cell_read_variable_le_u32(drv->dev, init_v_efuse, &bits); - if (ret) - return ret; - - steps = bits & ~BIT(desc->cpr_fuses.init_voltage_width - 1); - /* Not two's complement.. instead highest bit is sign bit */ - if (bits & BIT(desc->cpr_fuses.init_voltage_width - 1)) - steps = -steps; - - step_size_uV = desc->cpr_fuses.init_voltage_step; - - uV = fdata->ref_uV + steps * step_size_uV; - return DIV_ROUND_UP(uV, step_volt) * step_volt; -} - static int cpr_fuse_corner_init(struct cpr_drv *drv) { const struct cpr_desc *desc = drv->desc; @@ -854,7 +741,6 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv) unsigned int step_volt; struct fuse_corner_data *fdata; struct fuse_corner *fuse, *end; - int uV; const struct reg_sequence *accs; int ret; @@ -870,23 +756,15 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv) fdata = desc->cpr_fuses.fuse_corner_data; for (i = 0; fuse <= end; fuse++, fuses++, i++, fdata++) { - /* - * Update SoC voltages: platforms might choose a different - * regulators than the one used to characterize the algorithms - * (ie, init_voltage_step). - */ - fdata->min_uV = roundup(fdata->min_uV, step_volt); - fdata->max_uV = roundup(fdata->max_uV, step_volt); + ret = cpr_populate_fuse_common(drv->dev, fdata, fuses, + fuse, step_volt, + desc->cpr_fuses.init_voltage_width, + desc->cpr_fuses.init_voltage_step); + if (ret) + return ret; - /* Populate uV */ - uV = cpr_read_fuse_uV(desc, fdata, fuses->init_voltage, - step_volt, drv); - if (uV < 0) - return uV; - fuse->min_uV = fdata->min_uV; - fuse->max_uV = fdata->max_uV; - fuse->uV = clamp(uV, fuse->min_uV, fuse->max_uV); + fuse->step_quot = desc->step_quot[fuse->ring_osc_idx]; if (fuse == end) { /* @@ -924,25 +802,9 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv) else if (fuse->uV < fuse->min_uV) fuse->uV = fuse->min_uV; - ret = regulator_is_supported_voltage(drv->vdd_apc, - fuse->min_uV, - fuse->min_uV); - if (!ret) { - dev_err(drv->dev, - "min uV: %d (fuse corner: %d) not supported by regulator\n", - fuse->min_uV, i); - return -EINVAL; - } - - ret = regulator_is_supported_voltage(drv->vdd_apc, - fuse->max_uV, - fuse->max_uV); - if (!ret) { - dev_err(drv->dev, - "max uV: %d (fuse corner: %d) not supported by regulator\n", - fuse->max_uV, i); - return -EINVAL; - } + ret = cpr_check_vreg_constraints(drv->dev, drv->vdd_apc, fuse); + if (ret) + return ret; dev_dbg(drv->dev, "fuse corner %d: [%d %d %d] RO%hhu quot %d squot %d\n", @@ -953,126 +815,6 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv) return 0; } -static int cpr_calculate_scaling(const char *quot_offset, - struct cpr_drv *drv, - const struct fuse_corner_data *fdata, - const struct corner *corner) -{ - u32 quot_diff = 0; - unsigned long freq_diff; - int scaling; - const struct fuse_corner *fuse, *prev_fuse; - int ret; - - fuse = corner->fuse_corner; - prev_fuse = fuse - 1; - - if (quot_offset) { - ret = nvmem_cell_read_variable_le_u32(drv->dev, quot_offset, "_diff); - if (ret) - return ret; - - quot_diff *= fdata->quot_offset_scale; - quot_diff += fdata->quot_offset_adjust; - } else { - quot_diff = fuse->quot - prev_fuse->quot; - } - - freq_diff = fuse->max_freq - prev_fuse->max_freq; - freq_diff /= 1000000; /* Convert to MHz */ - scaling = 1000 * quot_diff / freq_diff; - return min(scaling, fdata->max_quot_scale); -} - -static int cpr_interpolate(const struct corner *corner, int step_volt, - const struct fuse_corner_data *fdata) -{ - unsigned long f_high, f_low, f_diff; - int uV_high, uV_low, uV; - u64 temp, temp_limit; - const struct fuse_corner *fuse, *prev_fuse; - - fuse = corner->fuse_corner; - prev_fuse = fuse - 1; - - f_high = fuse->max_freq; - f_low = prev_fuse->max_freq; - uV_high = fuse->uV; - uV_low = prev_fuse->uV; - f_diff = fuse->max_freq - corner->freq; - - /* - * Don't interpolate in the wrong direction. This could happen - * if the adjusted fuse voltage overlaps with the previous fuse's - * adjusted voltage. - */ - if (f_high <= f_low || uV_high <= uV_low || f_high <= corner->freq) - return corner->uV; - - temp = f_diff * (uV_high - uV_low); - temp = div64_ul(temp, f_high - f_low); - - /* - * max_volt_scale has units of uV/MHz while freq values - * have units of Hz. Divide by 1000000 to convert to. - */ - temp_limit = f_diff * fdata->max_volt_scale; - do_div(temp_limit, 1000000); - - uV = uV_high - min(temp, temp_limit); - return roundup(uV, step_volt); -} - -static unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp) -{ - struct device_node *np; - unsigned int fuse_corner = 0; - - np = dev_pm_opp_get_of_node(opp); - if (of_property_read_u32(np, "qcom,opp-fuse-level", &fuse_corner)) - pr_err("%s: missing 'qcom,opp-fuse-level' property\n", - __func__); - - of_node_put(np); - - return fuse_corner; -} - -static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, - struct device *cpu_dev) -{ - u64 rate = 0; - struct device_node *ref_np; - struct device_node *desc_np; - struct device_node *child_np = NULL; - struct device_node *child_req_np = NULL; - - desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); - if (!desc_np) - return 0; - - ref_np = dev_pm_opp_get_of_node(ref); - if (!ref_np) - goto out_ref; - - do { - of_node_put(child_req_np); - child_np = of_get_next_available_child(desc_np, child_np); - child_req_np = of_parse_phandle(child_np, "required-opps", 0); - } while (child_np && child_req_np != ref_np); - - if (child_np && child_req_np == ref_np) - of_property_read_u64(child_np, "opp-hz", &rate); - - of_node_put(child_req_np); - of_node_put(child_np); - of_node_put(ref_np); -out_ref: - of_node_put(desc_np); - - return (unsigned long) rate; -} - static int cpr_corner_init(struct cpr_drv *drv) { const struct cpr_desc *desc = drv->desc; @@ -1186,7 +928,7 @@ static int cpr_corner_init(struct cpr_drv *drv) corner->uV = fuse->uV; if (prev_fuse && cdata[i - 1].freq == prev_fuse->max_freq) { - scaling = cpr_calculate_scaling(quot_offset, drv, + scaling = cpr_calculate_scaling(drv->dev, quot_offset, fdata, corner); if (scaling < 0) return scaling; @@ -1224,47 +966,6 @@ static int cpr_corner_init(struct cpr_drv *drv) return 0; } -static const struct cpr_fuse *cpr_get_fuses(struct cpr_drv *drv) -{ - const struct cpr_desc *desc = drv->desc; - struct cpr_fuse *fuses; - int i; - - fuses = devm_kcalloc(drv->dev, desc->num_fuse_corners, - sizeof(struct cpr_fuse), - GFP_KERNEL); - if (!fuses) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < desc->num_fuse_corners; i++) { - char tbuf[32]; - - snprintf(tbuf, 32, "cpr_ring_osc%d", i + 1); - fuses[i].ring_osc = devm_kstrdup(drv->dev, tbuf, GFP_KERNEL); - if (!fuses[i].ring_osc) - return ERR_PTR(-ENOMEM); - - snprintf(tbuf, 32, "cpr_init_voltage%d", i + 1); - fuses[i].init_voltage = devm_kstrdup(drv->dev, tbuf, - GFP_KERNEL); - if (!fuses[i].init_voltage) - return ERR_PTR(-ENOMEM); - - snprintf(tbuf, 32, "cpr_quotient%d", i + 1); - fuses[i].quotient = devm_kstrdup(drv->dev, tbuf, GFP_KERNEL); - if (!fuses[i].quotient) - return ERR_PTR(-ENOMEM); - - snprintf(tbuf, 32, "cpr_quotient_offset%d", i + 1); - fuses[i].quotient_offset = devm_kstrdup(drv->dev, tbuf, - GFP_KERNEL); - if (!fuses[i].quotient_offset) - return ERR_PTR(-ENOMEM); - } - - return fuses; -} - static void cpr_set_loop_allowed(struct cpr_drv *drv) { drv->loop_disabled = false; @@ -1296,54 +997,6 @@ static int cpr_init_parameters(struct cpr_drv *drv) return 0; } -static int cpr_find_initial_corner(struct cpr_drv *drv) -{ - unsigned long rate; - const struct corner *end; - struct corner *iter; - unsigned int i = 0; - - if (!drv->cpu_clk) { - dev_err(drv->dev, "cannot get rate from NULL clk\n"); - return -EINVAL; - } - - end = &drv->corners[drv->num_corners - 1]; - rate = clk_get_rate(drv->cpu_clk); - - /* - * Some bootloaders set a CPU clock frequency that is not defined - * in the OPP table. When running at an unlisted frequency, - * cpufreq_online() will change to the OPP which has the lowest - * frequency, at or above the unlisted frequency. - * Since cpufreq_online() always "rounds up" in the case of an - * unlisted frequency, this function always "rounds down" in case - * of an unlisted frequency. That way, when cpufreq_online() - * triggers the first ever call to cpr_set_performance_state(), - * it will correctly determine the direction as UP. - */ - for (iter = drv->corners; iter <= end; iter++) { - if (iter->freq > rate) - break; - i++; - if (iter->freq == rate) { - drv->corner = iter; - break; - } - if (iter->freq < rate) - drv->corner = iter; - } - - if (!drv->corner) { - dev_err(drv->dev, "boot up corner not found\n"); - return -EINVAL; - } - - dev_dbg(drv->dev, "boot up perf state: %u\n", i); - - return 0; -} - static const struct cpr_desc qcs404_cpr_desc = { .num_fuse_corners = 3, .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF, @@ -1531,7 +1184,8 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, if (ret) goto unlock; - ret = cpr_find_initial_corner(drv); + ret = cpr_find_initial_corner(drv->dev, drv->cpu_clk, drv->corners, + drv->num_corners); if (ret) goto unlock; @@ -1616,6 +1270,7 @@ static int cpr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cpr_drv *drv; + const struct cpr_desc *desc; int irq, ret; const struct cpr_acc_desc *data; struct device_node *np; @@ -1631,6 +1286,7 @@ static int cpr_probe(struct platform_device *pdev) drv->dev = dev; drv->desc = data->cpr_desc; drv->acc_desc = data->acc_desc; + desc = drv->desc; drv->fuse_corners = devm_kcalloc(dev, drv->desc->num_fuse_corners, sizeof(*drv->fuse_corners), @@ -1670,11 +1326,13 @@ static int cpr_probe(struct platform_device *pdev) if (ret) return ret; - drv->cpr_fuses = cpr_get_fuses(drv); + drv->cpr_fuses = cpr_get_fuses(drv->dev, desc->num_fuse_corners); if (IS_ERR(drv->cpr_fuses)) return PTR_ERR(drv->cpr_fuses); - ret = cpr_populate_ring_osc_idx(drv); + ret = cpr_populate_ring_osc_idx(drv->dev, drv->fuse_corners, + drv->cpr_fuses, + desc->num_fuse_corners); if (ret) return ret; From patchwork Wed Jun 28 14:00:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113916 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8950441vqr; Wed, 28 Jun 2023 07:04:32 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5b9vK1b8Cjwo8nXsXNukD/m1Tj2Y8sL4OP6jS7w5U/AXtznicwwYDSjCiH3BXLVTxNLIg1 X-Received: by 2002:a05:6402:27c8:b0:51d:9611:db3d with SMTP id c8-20020a05640227c800b0051d9611db3dmr8293396ede.2.1687961072502; Wed, 28 Jun 2023 07:04:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687961072; cv=none; d=google.com; s=arc-20160816; b=niX7t5vYFIDKnBvI0jluadPGRpa9KgKsNa5KapS1sB88frTcIcRJLLkCjW2KMtlgF/ IS1VKviGY10bY0xyAsw94YRODkldZWSNuYHaR6Uyr/oAjIfCMCqEov181MRRWhjFIro7 rYpCVR8d5PT3SIQPsMLGEh05M3roht3dzzebybgTboQ8v+jUlRABaEBMT7ZT5uRqJLua hmZ1Zcpz5gOvMBZ3GnaedyZOE4xDkKqP9g4xp1/LFax7rzKuNT7k6PZqHJ9/R3z2Ul4h /OiD/MqpwpRAoPKLo+l/24BR7OlTBNx0iGyBRAQg2UTKbb/tVc6QZET2/fjp2PZX5xby mdGg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=dlJNXwesiBvinVlCm08BsBVW76YCVdXRX2U7PUbcI/o=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=qhL614V1XC3h7fyVJ9DqqFD515M11wqaSGdbif8zGSNA6ehCZOqGKvSlacAa//hWjY Fx0bM5znSe2SW6/dqGJnszx7DDuWCNsnIn9C0TCQhXWxjhJClfrRcRBalf1X9tkAOgGv RO4tU8aEMSxOtPL378sEIxn4wUjTfC+y9nUTOeZdjIUw/xmiH0fN6AZYSBN2XClogaTl H47S39lJxcWKUnc4qG+L39PcYzWYFURWVzAWkOj/rcD5kTugnjgSZSenI031n7uxCKGB CiD2udZD6sMV6v7bodsmWk/P6BpFOjLC/RDKqc+VG4KnyQMZvqIrPxZkWxgBSONCp0a0 3xQA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=wjXkcSOY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id x2-20020aa7d6c2000000b0051bebea18f8si5156239edr.136.2023.06.28.07.04.07; Wed, 28 Jun 2023 07:04:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=wjXkcSOY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232373AbjF1OCI (ORCPT + 99 others); Wed, 28 Jun 2023 10:02:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232380AbjF1OBK (ORCPT ); Wed, 28 Jun 2023 10:01:10 -0400 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 908912D60 for ; Wed, 28 Jun 2023 07:00:58 -0700 (PDT) Received: by mail-lf1-x136.google.com with SMTP id 2adb3069b0e04-4f957a45b10so8155314e87.0 for ; Wed, 28 Jun 2023 07:00:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960857; x=1690552857; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=dlJNXwesiBvinVlCm08BsBVW76YCVdXRX2U7PUbcI/o=; b=wjXkcSOYLCmNXkLjTYyrJOKHBDMmFwmDnRDK0j1pFPFRb1ZM/pt7ICV1ZebjyLN71N hq4pmTJa7jqZGdNawj771dofrzaTLkJ4loY1+LX9R13tNYzcLaGRb5YW5c0Xh3ZV7X95 ibGz3ChPD290BemGem64XqAnYUTVOuy4z/3SvgN7QONaWMfX3TF9dpVFuoA4JufA3CgI wq486zch/B2BIFDGr/qZPWk6mFjbn1XH7DO1CDBzb5/MMoJrNFRYw2QKOvRBtzDG7wEB 04Hyx86s5pNRkQU258oxnYYiyMH5Hd3e3NJQwYH4YIqCcgWraub7tHvITlRmaAwVF2NO yOEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960857; x=1690552857; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dlJNXwesiBvinVlCm08BsBVW76YCVdXRX2U7PUbcI/o=; b=lYB9iyeoxGF+8i2Se7TVxMbpAi7Uy2OU3MWR8EC3421x8uQp38YW3WTKVRIAmNPTDc fLh1GjY7ZurNjKRIfGlxs9hYK9/3GBrp6zz8/hjcI94044iZtrZybNamcbvi0tk77uC5 etjePzmoC8WpueNK6T9xKlfgOLRXrsKmpqp7P0T7vxhp1vLECJicHqmkf4W6jOs/A2OL 2A5OA2AtYhXFlrDpyL7gn4sCxKXTj1reY5UCSvIDMDagHvM/2zRfTP/nGfdGks8tZXWn jK9OFcvJ+/KtZM+s4XB4Q4HgFwZoRnn2ZCtCiPpJ9PKn35IPgL8Je0lg99hX9CSJJitO eFTw== X-Gm-Message-State: AC+VfDyBRlEezO0oPf945X1iAF3j2qCeZjHnH6B8GaztyIcTSIUP2hsi dgXret9ktjIC8Ne7PU+Sx1HX9Q== X-Received: by 2002:a05:6512:2314:b0:4fa:21d4:b3ca with SMTP id o20-20020a056512231400b004fa21d4b3camr8000519lfu.2.1687960855394; Wed, 28 Jun 2023 07:00:55 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:54 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:45 +0200 Subject: [PATCH v12 06/10] soc: qcom: cpr-common: Add support for flat fuse adjustment MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-6-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=2032; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=PZkzlg9a1T62vJjNL6pym3+YcX1sRFAyVy3l058FxdA=; b=CyanBX6AWB/zukL+HolgU51mINIbt7hEOwCypuhVvimrPxwU46e7Yvm1wDX8Boj8j51vy/o4h a6uaPnYmV3NAKdMOR/wzDdlKRIUuYDrosGEBoxAFTaWXS38KH0cDGeS X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769955469368607116?= X-GMAIL-MSGID: =?utf-8?q?1769955469368607116?= From: AngeloGioacchino Del Regno CPR3 makes use of post-calculation flat value adjustments. Add the necessary bits to the common functions to support it. Signed-off-by: AngeloGioacchino Del Regno [Konrad: separate this patch out of a bigger one] Signed-off-by: Konrad Dybcio --- drivers/soc/qcom/cpr-common.c | 9 ++++++--- drivers/soc/qcom/cpr-common.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/cpr-common.c b/drivers/soc/qcom/cpr-common.c index ea85f6b4bef8..44c681bbbf13 100644 --- a/drivers/soc/qcom/cpr-common.c +++ b/drivers/soc/qcom/cpr-common.c @@ -49,7 +49,7 @@ int cpr_populate_ring_osc_idx(struct device *dev, EXPORT_SYMBOL_GPL(cpr_populate_ring_osc_idx); static int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV, - int step_volt, const char *init_v_efuse, + int adj, int step_volt, const char *init_v_efuse, struct device *dev) { int steps, uV; @@ -67,6 +67,9 @@ static int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV, uV = ref_uV + steps * step_size_uV; + /* Apply open-loop fixed adjustments to fused values */ + uV += adj; + return DIV_ROUND_UP(uV, step_volt) * step_volt; } @@ -119,8 +122,8 @@ int cpr_populate_fuse_common(struct device *dev, /* Populate uV */ uV = cpr_read_fuse_uV(init_v_width, init_v_step, - fdata->ref_uV, step_volt, - cpr_fuse->init_voltage, dev); + fdata->ref_uV, fdata->volt_oloop_adjust, + step_volt, cpr_fuse->init_voltage, dev); if (uV < 0) return uV; diff --git a/drivers/soc/qcom/cpr-common.h b/drivers/soc/qcom/cpr-common.h index 1f2ebf9394cf..0aa227617d2f 100644 --- a/drivers/soc/qcom/cpr-common.h +++ b/drivers/soc/qcom/cpr-common.h @@ -22,6 +22,7 @@ struct fuse_corner_data { int ref_uV; int max_uV; int min_uV; + int volt_oloop_adjust; int max_volt_scale; int max_quot_scale; /* fuse quot */ From patchwork Wed Jun 28 14:00:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113929 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8963923vqr; Wed, 28 Jun 2023 07:20:59 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5GpSqv4/zr1diuuATq8oQJZShu19TXqJ59aT8x34VwdpkhgY/YrgbYfSN+E1b1ttQ+62j5 X-Received: by 2002:a17:906:5198:b0:987:6960:36c8 with SMTP id y24-20020a170906519800b00987696036c8mr25581351ejk.7.1687962058853; Wed, 28 Jun 2023 07:20:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687962058; cv=none; d=google.com; s=arc-20160816; b=acHy0hmqOlHbGoaydFf24lzjSA1tXL+lFoXtkDdreoqYb9RNVIRHzlRWTcwmelcten C1FOJlo6/8Lzon4s0zevOy0CRb77yy8s47piol8T/Y1oRXUoGX8IpVWVw3Xsn4UcCXN5 P+fIhzJuv6C8Tx6SOAkoU10Y/juJ3vTRN8G0CuRvU5SRzqRawS5qsH7F4n9KmBP1rPx0 aj6+xaPy18lmSxpzKm7W8UEQA6OJdzTD/U3cOYDxZYz+iDgAycmXYpR0wOoJrn22m94w oR03U9IHh4BEkD5h30ooCcd1w7ZnSX+rQ6ofZMJQDDewP9AMNQe3FzRSOEPqU2lUFOgq J9fA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=8b95YyrPSuupI481LxGuPH0W0Ev0Q0xP5dP+IZGpzvg=; fh=4QnxOa6B794SVIyocnOVG+x+vajOeIWtq2DTmRXKqj4=; b=uMMDIBhceqLhioP6t/BymA9P3GBFd2zG8yopqLFoGuep0p0L3kKXIY/tYC/6Kfkak+ lAaxcOO12OMd7EOUVIIo3kbSk5ko6Av6ENyk5BOaZ9WTwP0LtL+xjBhSa5g35x1tRwnC kvegW/0Yx6tXN0uc7ZLdVlE24925MWVgo0nBhfR/BiRATjwXdrqfCEHPz86bPvrLaPo3 Xg3+lPlTUAL7iNdiXjavhrLMIw4Guemc6Cvv2VxUwATUccp4r0VWvUy/3teKAJmaFLO+ xcHSviNJNG1o588Nm+PdHpkMRggLrDtPA1EdzJWQnUsOP1irF1EToypDg1ToDIgFGJ8c bp2A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=GXyD7n9A; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t23-20020a170906179700b0097873b70a8bsi5473473eje.343.2023.06.28.07.20.32; Wed, 28 Jun 2023 07:20:58 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=GXyD7n9A; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232355AbjF1ODN (ORCPT + 99 others); Wed, 28 Jun 2023 10:03:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51672 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232353AbjF1OBr (ORCPT ); Wed, 28 Jun 2023 10:01:47 -0400 Received: from mail-lf1-x129.google.com (mail-lf1-x129.google.com [IPv6:2a00:1450:4864:20::129]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8A9E22D76 for ; Wed, 28 Jun 2023 07:00:59 -0700 (PDT) Received: by mail-lf1-x129.google.com with SMTP id 2adb3069b0e04-4f96d680399so8349945e87.0 for ; Wed, 28 Jun 2023 07:00:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960858; x=1690552858; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=8b95YyrPSuupI481LxGuPH0W0Ev0Q0xP5dP+IZGpzvg=; b=GXyD7n9AIosDIZkXLIVkkwaxQn6nxHqixAueYldTJN1tISQFqyIYcH57YvtWYC3kbK JFNXWiIvXhU2dOZ2Ro87B79Lm4eXi5XMAwt4MQ+CUGzXRu9IwgF4H2KG1EY9E9ARDMvC ifqfBiUOP8HIGfUq+iqpkIdGu/Nc7jFfGufDRPNRoWzmNi6C6lyLEh/6jmdbJQsIubSo mvCKss89EsyLvDBAmgTDjmDWvdjjMHsGd3CuzmkCRly75D4iCbkLPnsnA6mMh5/EG/Es RutCpk8IvwZsgoBdcihFhi3x/HjM2I9j8pa54xx/2iZNZm6Y92AkLN8F/ysKYEqKLeyj 15hQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960858; x=1690552858; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8b95YyrPSuupI481LxGuPH0W0Ev0Q0xP5dP+IZGpzvg=; b=CSeShb+07Gb6yiGqhxm+TDiMTssOQeRrSHmyYu18xuIxDN/wuywvVo7opBqWl3FHPV dLfY9hY6ajZR5Xv6sqVN+Gs6WBE93JbjCSofhDxLcXloJrvHrQDHJW8XGWB9uB2uySBy 6LSBd6Em25PRxRyM/WHDm52dMP8nRBWGn5VEZ9UFWMFt0vT4bdHF5z/ZtMwkKm1l0lMV oCj5BQ4/6t96iPuDYpozAoSJRZ7xARkVziyZTfiqW63XMlOdLo4czEMFVNOLGE+DM3A5 rlBAzsb/1B3R/1wMtHF6q8lXvnJ4rZHzAnMyWJk8wWdcoIGdulUimkuP9At3hiO3eBuf cElQ== X-Gm-Message-State: AC+VfDwRnbEnBYUKS0QjC997JKs8xn+S6yXqkpIxARsikWwnr5Tao/1Z nsPrZ+GrctS3hVdKUR9EltFVPA== X-Received: by 2002:a19:6445:0:b0:4f8:74b5:b4ec with SMTP id b5-20020a196445000000b004f874b5b4ecmr19101455lfj.41.1687960857816; Wed, 28 Jun 2023 07:00:57 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:56 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:46 +0200 Subject: [PATCH v12 07/10] soc: qcom: cpr: Use u64 for frequency MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-7-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=4633; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=PWlHXLBc6eYCIQOuwoDLOgk0BhchBWn8dDGTg2w8H7k=; b=0JGVm89AazNICKETJE/s/6QEfJQZxPuyLNjwGmBRqeDUB7YMT54OCVG2DBkRbJSa/IKpkdXDG sJwes9YByc7D03jP1ZTCHnRsUzgbIxYUFfDDYlOWc3uHwtWjuR9j3qn X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956504080819879?= X-GMAIL-MSGID: =?utf-8?q?1769956504080819879?= 32 bits is not enough for over-2.changeGHz frequencies. Move all variables that operate on Hz to u64 to avoid overflows. Signed-off-by: Konrad Dybcio Reviewed-by: AngeloGioacchino Del Regno --- drivers/soc/qcom/cpr-common.c | 13 +++++++------ drivers/soc/qcom/cpr-common.h | 9 ++++----- drivers/soc/qcom/cpr.c | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/soc/qcom/cpr-common.c b/drivers/soc/qcom/cpr-common.c index 44c681bbbf13..3e3a4a61cfde 100644 --- a/drivers/soc/qcom/cpr-common.c +++ b/drivers/soc/qcom/cpr-common.c @@ -218,7 +218,7 @@ unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp) } EXPORT_SYMBOL_GPL(cpr_get_fuse_corner); -unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, +u64 cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, struct device *cpu_dev) { u64 rate = 0; @@ -250,7 +250,7 @@ unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, out_ref: of_node_put(desc_np); - return (unsigned long) rate; + return rate; } EXPORT_SYMBOL_GPL(cpr_get_opp_hz_for_req); @@ -260,7 +260,7 @@ int cpr_calculate_scaling(struct device *dev, const struct corner *corner) { u32 quot_diff = 0; - unsigned long freq_diff; + u64 freq_diff; int scaling; const struct fuse_corner *fuse, *prev_fuse; int ret; @@ -280,8 +280,9 @@ int cpr_calculate_scaling(struct device *dev, } freq_diff = fuse->max_freq - prev_fuse->max_freq; - freq_diff /= 1000000; /* Convert to MHz */ - scaling = 1000 * quot_diff / freq_diff; + freq_diff = div_u64(freq_diff, 1000000); /* Convert to MHz */ + scaling = 1000 * quot_diff; + do_div(scaling, freq_diff); return min(scaling, fdata->max_quot_scale); } EXPORT_SYMBOL_GPL(cpr_calculate_scaling); @@ -289,7 +290,7 @@ EXPORT_SYMBOL_GPL(cpr_calculate_scaling); int cpr_interpolate(const struct corner *corner, int step_volt, const struct fuse_corner_data *fdata) { - unsigned long f_high, f_low, f_diff; + u64 f_high, f_low, f_diff; int uV_high, uV_low, uV; u64 temp, temp_limit; const struct fuse_corner *fuse, *prev_fuse; diff --git a/drivers/soc/qcom/cpr-common.h b/drivers/soc/qcom/cpr-common.h index 0aa227617d2f..1b2fa344eb09 100644 --- a/drivers/soc/qcom/cpr-common.h +++ b/drivers/soc/qcom/cpr-common.h @@ -42,7 +42,7 @@ struct fuse_corner { int step_quot; const struct reg_sequence *accs; int num_accs; - unsigned long max_freq; + u64 max_freq; u8 ring_osc_idx; }; @@ -54,13 +54,13 @@ struct corner { int quot_adjust; u32 save_ctl; u32 save_irq; - unsigned long freq; + u64 freq; struct fuse_corner *fuse_corner; }; struct corner_data { unsigned int fuse_corner; - unsigned long freq; + u64 freq; }; struct acc_desc { @@ -92,8 +92,7 @@ int cpr_populate_fuse_common(struct device *dev, int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk, struct corner *corners, int num_corners); u32 cpr_get_fuse_corner(struct dev_pm_opp *opp); -unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, - struct device *cpu_dev); +u64 cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, struct device *cpu_dev); int cpr_calculate_scaling(struct device *dev, const char *quot_offset, const struct fuse_corner_data *fdata, diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index cc1e4c462d1f..49c33b13b82b 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -827,8 +827,8 @@ static int cpr_corner_init(struct cpr_drv *drv) struct corner_data *cdata; const struct fuse_corner_data *fdata; bool apply_scaling; - unsigned long freq_diff, freq_diff_mhz; - unsigned long freq; + unsigned long freq_diff_mhz; + u64 freq, freq_diff; int step_volt = regulator_get_linear_step(drv->vdd_apc); struct dev_pm_opp *opp; @@ -867,7 +867,7 @@ static int cpr_corner_init(struct cpr_drv *drv) cdata[level - 1].freq = freq; fuse = &drv->fuse_corners[fnum]; - dev_dbg(drv->dev, "freq: %lu level: %u fuse level: %u\n", + dev_dbg(drv->dev, "freq: %llu level: %u fuse level: %u\n", freq, dev_pm_opp_get_level(opp) - 1, fnum); if (freq > fuse->max_freq) fuse->max_freq = freq; @@ -941,7 +941,7 @@ static int cpr_corner_init(struct cpr_drv *drv) if (apply_scaling) { freq_diff = fuse->max_freq - corner->freq; - freq_diff_mhz = freq_diff / 1000000; + freq_diff_mhz = (u32)div_u64(freq_diff, 1000000); corner->quot_adjust = scaling * freq_diff_mhz / 1000; corner->uV = cpr_interpolate(corner, step_volt, fdata); From patchwork Wed Jun 28 14:00:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113935 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8965555vqr; Wed, 28 Jun 2023 07:23:19 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6Yq6jSKe1Id5i4Rte3lEGnizenNafJIUqfO0rxpLp668r7k8ItvtCcpZk2NYgZ5c7VcV1v X-Received: by 2002:a17:906:77d5:b0:974:5de8:b5ce with SMTP id m21-20020a17090677d500b009745de8b5cemr4421931ejn.2.1687962199101; Wed, 28 Jun 2023 07:23:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687962199; cv=none; d=google.com; s=arc-20160816; b=i3Pfgbc4NOn1j9kQWBKUhwaP0Iuq51q22m782U2/5mUX7cBF97BMgrMNsYyOoNvc7o clxK5GVf8iwOzTWvUmLcpXsp/e3Ukc2eXdR+6uKgIemwo3EIPqF2/VO8ntCiNpcm190+ YzjYbf+aC1g4uIkPIb3VYOrApPepDQ/N8bRuEgoA8vjbHksJYw3ku/9ZxrhGmSXNipFI nKuBCsVKMVo/MeJAaw17QY+jjE6di+J3durgepWeQgSNI+jXpwMRc6pbzPzeqDOaxP/8 4dxslxPZ1Gtd8HfmyzbSwb4/AcLK0w8fs2BY4nCvoB/ioqBEGXIDansRUmbPYlFFTxIF 84WQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=OqEu13zU8yL/k2MIrt/7DelQ5S48Y7ED1AMrbjwM43Y=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=BAFWjBcdtWlRF07T3/N1fml65d07deD+SVORGmZpgjwGjrEdq1O9CXvnKtU1fovLfd jAtdEsc0i9kvcvfO6mT6qyzvlN1VXSGhyOCayy2sRcUnwWv+y8kU7sY7N5WHuUeKDRfB qcC52qchS8xjAJSVN1PVMX7AZcDMJ3cfnR6P7l8Kdw7vnsYBh6I08wJDK5wIauH7S1AA ugbEETLPKp8EiTkzS5Kuon2GxjBU0kx/Ul1ytvi2Sqn2qYpEqbm2wGIbn6agMovsOfFp vk2CloLt5ydiRvXOkwuHX/u42OloAfZ6wrnk80YYjsIV62d0Bz6YPBLMjDYFpIigurhF BHtQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nJAIiKuB; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id i26-20020a1709063c5a00b00991d54db2a6si3804634ejg.693.2023.06.28.07.22.54; Wed, 28 Jun 2023 07:23:19 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nJAIiKuB; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232471AbjF1ODQ (ORCPT + 99 others); Wed, 28 Jun 2023 10:03:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232281AbjF1OBs (ORCPT ); Wed, 28 Jun 2023 10:01:48 -0400 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61FE430D8 for ; Wed, 28 Jun 2023 07:01:01 -0700 (PDT) Received: by mail-lf1-x136.google.com with SMTP id 2adb3069b0e04-4fb77f21c63so4929057e87.2 for ; Wed, 28 Jun 2023 07:01:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960859; x=1690552859; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=OqEu13zU8yL/k2MIrt/7DelQ5S48Y7ED1AMrbjwM43Y=; b=nJAIiKuBS93A+kvHakGLMPDVP8j1gnHcuI+Xk1F1DhSvsHjTRgeF/oTMGQtZpHE38y 5s5e85igrMv71jxvnDWxIHfMrPXjAOoU8nFT6/aA8YajJFxZdNIHDySdSQ3GWqhJO8wi 2NlpmI85/gm2uU+9i1JJbQkCvTHmI1dvyo5qYdaol9FOKOD+EIuv5AT+fMU7KUkD6bow ADd1fvEMhmEW09b2jEDFetJwxeNVB0iXWO6iHJvwvyE26qfkQieGF/bXkIX7uW+r2rtS b9dLEvh8kCkcKob7aH8Uvvo1XPXIVe9EoBQfzLsip/4GBWwOHBGrvlo/JEdCQnweTtQH 5DEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960859; x=1690552859; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OqEu13zU8yL/k2MIrt/7DelQ5S48Y7ED1AMrbjwM43Y=; b=K4jaw2EKtqvRjYZ1CNAhQw4h/lXxNk5kWCqfD2YOB+RsP4Vr/oCrDUsGZ16cWJthIY rabjZUPaDiZRoA4dC1h3rQ8TN6fBDNsFWsbUz9+X0apiRlto/f96FEV9BlhHxawLmow5 +oFV7ymQVaT6wv+Jy436W6JGbh/KU1Z2a8fr8B0nOej2oJBoGV2X5c2f2OPiWS5XLQ1L nIlBhwclsIR+lU40P789WVSqqOH7E61ikwto5Qd6N/LP4zmcBeSF4MOdBsFKOYp9Af1I 2JPTR/3AKGRKBdvCLlruGqRALkxJz/JlIKrjuuf1UcdXPIlbGD38Sdrc6Ys7TiNsRYR9 EsbA== X-Gm-Message-State: AC+VfDwX3YvvnVynyipHKUtE3jRrl+rQJjIe08X+jFG576jPu8xbnn78 3BQENqjD7kAhwwMNBtjmaQ9phQ== X-Received: by 2002:a05:6512:ace:b0:4fb:8bad:1cdf with SMTP id n14-20020a0565120ace00b004fb8bad1cdfmr2863659lfu.42.1687960859575; Wed, 28 Jun 2023 07:00:59 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:00:59 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:47 +0200 Subject: [PATCH v12 08/10] soc: qcom: cpr-common: Add threads support MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-8-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=6300; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=AmdIHRQt1IfT1bayaE8b01VCVDroKAlvOlp4kw5cvQM=; b=FYKp7AAyjoGqHhecfuZyCDgIFWf0NWf6sV5qWWbi6BzZzhB6dc8ZgA5hLLINtqNzF/AKW3QU+ eqwpvTK239gDzxinCj3AuG4uVyQhp61m8yU0PPq9UPmEByfDf/zZZqO X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956651138740462?= X-GMAIL-MSGID: =?utf-8?q?1769956651138740462?= From: AngeloGioacchino Del Regno Add support for parsing per-CPR-thread data in preparation for introducing CPR3+ support. Signed-off-by: AngeloGioacchino Del Regno [Konrad: separate this patch out of a bigger one] Signed-off-by: Konrad Dybcio --- drivers/soc/qcom/cpr-common.c | 42 +++++++++++++++++++++++++----------------- drivers/soc/qcom/cpr-common.h | 8 ++++++-- drivers/soc/qcom/cpr.c | 4 ++-- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/soc/qcom/cpr-common.c b/drivers/soc/qcom/cpr-common.c index 3e3a4a61cfde..9001dccd4d95 100644 --- a/drivers/soc/qcom/cpr-common.c +++ b/drivers/soc/qcom/cpr-common.c @@ -73,35 +73,42 @@ static int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV, return DIV_ROUND_UP(uV, step_volt) * step_volt; } -const struct cpr_fuse *cpr_get_fuses(struct device *dev, +const struct cpr_fuse *cpr_get_fuses(struct device *dev, int tid, unsigned int num_fuse_corners) { struct cpr_fuse *fuses; - int i; + char cpr_name[11]; /* length of "cpr" + length of UINT_MAX (7) + \0 */ + unsigned int i; fuses = devm_kcalloc(dev, num_fuse_corners, sizeof(*fuses), GFP_KERNEL); if (!fuses) return ERR_PTR(-ENOMEM); + /* Support legacy bindings */ + if (tid == UINT_MAX) + snprintf(cpr_name, sizeof(cpr_name), "cpr"); + else + snprintf(cpr_name, sizeof(cpr_name), "cpr%d", tid); + for (i = 0; i < num_fuse_corners; i++) { - char tbuf[32]; + char tbuf[50]; - snprintf(tbuf, 32, "cpr_ring_osc%d", i + 1); + snprintf(tbuf, sizeof(tbuf), "%s_ring_osc%d", cpr_name, i + 1); fuses[i].ring_osc = devm_kstrdup(dev, tbuf, GFP_KERNEL); if (!fuses[i].ring_osc) return ERR_PTR(-ENOMEM); - snprintf(tbuf, 32, "cpr_init_voltage%d", i + 1); + snprintf(tbuf, sizeof(tbuf), "%s_init_voltage%d", cpr_name, i + 1); fuses[i].init_voltage = devm_kstrdup(dev, tbuf, GFP_KERNEL); if (!fuses[i].init_voltage) return ERR_PTR(-ENOMEM); - snprintf(tbuf, 32, "cpr_quotient%d", i + 1); + snprintf(tbuf, sizeof(tbuf), "%s_quotient%d", cpr_name, i + 1); fuses[i].quotient = devm_kstrdup(dev, tbuf, GFP_KERNEL); if (!fuses[i].quotient) return ERR_PTR(-ENOMEM); - snprintf(tbuf, 32, "cpr_quotient_offset%d", i + 1); + snprintf(tbuf, sizeof(tbuf), "%s_quotient_offset%d", cpr_name, i + 1); fuses[i].quotient_offset = devm_kstrdup(dev, tbuf, GFP_KERNEL); if (!fuses[i].quotient_offset) return ERR_PTR(-ENOMEM); @@ -202,15 +209,15 @@ int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk, } EXPORT_SYMBOL_GPL(cpr_find_initial_corner); -unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp) +unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp, u32 tid) { struct device_node *np; unsigned int fuse_corner = 0; np = dev_pm_opp_get_of_node(opp); - if (of_property_read_u32(np, "qcom,opp-fuse-level", &fuse_corner)) - pr_err("%s: missing 'qcom,opp-fuse-level' property\n", - __func__); + if (of_property_read_u32_index(np, "qcom,opp-fuse-level", tid, &fuse_corner)) + pr_err("%s: missing 'qcom,opp-fuse-level[%u]' property\n", + __func__, tid); of_node_put(np); @@ -235,15 +242,16 @@ u64 cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, if (!ref_np) goto out_ref; - do { - of_node_put(child_req_np); - child_np = of_get_next_available_child(desc_np, child_np); + for_each_available_child_of_node(desc_np, child_np) { child_req_np = of_parse_phandle(child_np, "required-opps", 0); - } while (child_np && child_req_np != ref_np); - if (child_np && child_req_np == ref_np) - of_property_read_u64(child_np, "opp-hz", &rate); + if (child_np && child_req_np == ref_np) { + of_property_read_u64(child_np, "opp-hz", &rate); + goto out; + } + } +out: of_node_put(child_req_np); of_node_put(child_np); of_node_put(ref_np); diff --git a/drivers/soc/qcom/cpr-common.h b/drivers/soc/qcom/cpr-common.h index 1b2fa344eb09..2c5bb81ab713 100644 --- a/drivers/soc/qcom/cpr-common.h +++ b/drivers/soc/qcom/cpr-common.h @@ -22,6 +22,9 @@ struct fuse_corner_data { int ref_uV; int max_uV; int min_uV; + int range_uV; + /* fuse volt: closed/open loop */ + int volt_cloop_adjust; int volt_oloop_adjust; int max_volt_scale; int max_quot_scale; @@ -55,6 +58,7 @@ struct corner { u32 save_ctl; u32 save_irq; u64 freq; + bool is_open_loop; struct fuse_corner *fuse_corner; }; @@ -81,7 +85,7 @@ int cpr_populate_ring_osc_idx(struct device *dev, struct fuse_corner *fuse_corner, const struct cpr_fuse *cpr_fuse, int num_fuse_corners); -const struct cpr_fuse *cpr_get_fuses(struct device *dev, +const struct cpr_fuse *cpr_get_fuses(struct device *dev, int tid, unsigned int num_fuse_corners); int cpr_populate_fuse_common(struct device *dev, struct fuse_corner_data *fdata, @@ -91,7 +95,7 @@ int cpr_populate_fuse_common(struct device *dev, int init_v_step); int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk, struct corner *corners, int num_corners); -u32 cpr_get_fuse_corner(struct dev_pm_opp *opp); +u32 cpr_get_fuse_corner(struct dev_pm_opp *opp, u32 tid); u64 cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, struct device *cpu_dev); int cpr_calculate_scaling(struct device *dev, const char *quot_offset, diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index 49c33b13b82b..bd94e19fc0fb 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -852,7 +852,7 @@ static int cpr_corner_init(struct cpr_drv *drv) opp = dev_pm_opp_find_level_exact(&drv->pd.dev, level); if (IS_ERR(opp)) return -EINVAL; - fc = cpr_get_fuse_corner(opp); + fc = cpr_get_fuse_corner(opp, 0); if (!fc) { dev_pm_opp_put(opp); return -EINVAL; @@ -1326,7 +1326,7 @@ static int cpr_probe(struct platform_device *pdev) if (ret) return ret; - drv->cpr_fuses = cpr_get_fuses(drv->dev, desc->num_fuse_corners); + drv->cpr_fuses = cpr_get_fuses(drv->dev, UINT_MAX, desc->num_fuse_corners); if (IS_ERR(drv->cpr_fuses)) return PTR_ERR(drv->cpr_fuses); From patchwork Wed Jun 28 14:00:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113924 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8962788vqr; Wed, 28 Jun 2023 07:19:31 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4jKZ2lxmAyw6k77GbEQX28lV86MTJdgjH8FQoSj9a7qEZ9z0GsYVplx9mm3IJMSTxluuhY X-Received: by 2002:a17:906:18:b0:992:c9d:fa6e with SMTP id 24-20020a170906001800b009920c9dfa6emr4510196eja.0.1687961971379; Wed, 28 Jun 2023 07:19:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687961971; cv=none; d=google.com; s=arc-20160816; b=MBf05HfH8rvF2/AtzM84KexMSBt5C0PYcV1XjLwXjD4uNgQbrqnmg5njJiSRsRJ4px Lc1yQatnaJA/bTSR8cdF8u97a+upsYUbl+0NTj7BpUgtBN8eO9MLtPOKNqPi5VmpcVsp uqRlxLJjd53wLSEo034Fq2iDLAX8dM4uO3Py3E/U0aNMkhN3fJ0Hixm07MQrXIWiPYwx H6lKkPTvycqymXi4vfaoCh3YAPepphd9ebyD8MIsv4+cNXI7qW6lZXTxQzIiN8mPL8uo M25glS/Cpt+DFtyRPcSNlkQf9+4cPXT/QwyqdSYrgKUD9OWiA2nEpIxXgWTc2VGLo0+z G1RQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=F3YuZOnVZKkbUkZRg/Yp7QG9oBBS//egYLuQF3x343c=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=ob5gxoyVEKlcwWlYl7Sr68bs2+wIstJip9OAHrkOzrNIqltYKaQ6MTvwuibvKAtV6x DkunaZcBMC+4FmWi5TyUN8W29RRRV9AJ56NOiy2DrsGjNjYjfta2DVBoybnJlBGpeGTj mH59zK3FNzFsU7OmT70B4mnzzEL8WhpFGfvn1KPaetjejRSblwjxpVIRjXKiN7EcFGyx 8Mx3/PYdaILFgNzFZ0Ny7uAR0nCcAyL8bQsUQpTOM5zi8sjDZjM/4dPj44nr3J74lf2Y Ywar/VjorUQGpUcoBaCm4YmU6ePKxAVTDt6X1C4YtCTyu7s6f+leIkhQmA2kvbJ+6eDm OszA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YJm9oKOK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id r20-20020a170906281400b00987d66e6d26si5867946ejc.250.2023.06.28.07.19.05; Wed, 28 Jun 2023 07:19:31 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YJm9oKOK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232579AbjF1OES (ORCPT + 99 others); Wed, 28 Jun 2023 10:04:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51672 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232323AbjF1ODK (ORCPT ); Wed, 28 Jun 2023 10:03:10 -0400 Received: from mail-lf1-x130.google.com (mail-lf1-x130.google.com [IPv6:2a00:1450:4864:20::130]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BF36530F3 for ; Wed, 28 Jun 2023 07:01:04 -0700 (PDT) Received: by mail-lf1-x130.google.com with SMTP id 2adb3069b0e04-4f76a0a19d4so8314257e87.2 for ; Wed, 28 Jun 2023 07:01:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960863; x=1690552863; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=F3YuZOnVZKkbUkZRg/Yp7QG9oBBS//egYLuQF3x343c=; b=YJm9oKOKcysdMqJTVMthaUWBDTOIxQqIyFh7jSk5/sw+DiZP/qCDRzAYdksuqimilZ h/Oq2QL1zdz5XF4oFJT8u6sriBvExEtAlxtoXTqGUAiHyaQGmTbHjutsepzrQhHEZRcv iIPPz9WYGcZ1eEzUXhOPHquw/tQ+B/0XRpALipRsUADbdWHKDpRqeFkBoZyhgcToFpcM CR1jR/g26IxUdNhqfGZFjC4khNJlX0a8y+DZkY/q/m+Uv1uFPA0nGvroPA6EO9V0u+9G U9z6ivgazcUFkWAxu9P27LPtnVgDMRatF5BQlt/CjCJlQpumt3AIc1pYs2CshpXWtVnS SEJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960863; x=1690552863; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=F3YuZOnVZKkbUkZRg/Yp7QG9oBBS//egYLuQF3x343c=; b=V9hPYI6C/JxfBOMUqdzP/lNsLUyaZpVx+TfGgxZ3pR3GB4AIEUfufbf/Y9pjhDgOG+ e0hiIa5yRwlCbHdimSExWaf7vD8aI8vnUwxgcrNAT6JgVJvTHhmolg3SelVSJdqJ1CJY PhPhOI4VhU6/KSvJ1+MHPdC5graIHv9YP8SdD+/vXdFR9eRcUDQpTjkTEaeA3oywR7hM EW+p8wY+pw/5ciZzO17EfITtWm10kqDyiBD7tZFFFNkduPRNntJVoZxtaDuLFALNB0bl 3GkhD75Z3qYFebm3uSnyAQqa71O8sA58V4B2IR83x/zeqa8knrAsyxWZw4ZJ1dSmbbW+ W18w== X-Gm-Message-State: AC+VfDy+2iRhq+hnL3FLPYcdUPtdYHAAoDpuyPXX0rHXx4BaJ6PcqRK0 WPNzRz+7zX49JzOV3QBsZLLxMg== X-Received: by 2002:a19:771d:0:b0:4f9:5404:af5 with SMTP id s29-20020a19771d000000b004f954040af5mr13667293lfc.46.1687960862100; Wed, 28 Jun 2023 07:01:02 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.00.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:01:01 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:48 +0200 Subject: [PATCH v12 09/10] soc: qcom: Add support for Core Power Reduction v3, v4 and Hardened MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-9-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960842; l=92801; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=scB40BS5TQAEsmaHkR7MBEIqVkGH5qnINHUw2ELq/4s=; b=dFEiVYOQpX1VnqcT0BzC/19BVO/X628Y1cBXgARWsAuWiLXPdFYQyU4XuqQ2KrtRMlitecEnE pNKDbzGNVgqBt4YAqjjUHmDEEA4CSrGrEpUS82/5+Fs3Tz3BkE+VJmV X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956412228176380?= X-GMAIL-MSGID: =?utf-8?q?1769956412228176380?= From: AngeloGioacchino Del Regno This commit introduces a new driver, based on the one for cpr v1, to enable support for the newer Qualcomm Core Power Reduction hardware, known downstream as CPR3, CPR4 and CPRh, and support for MSM8998 and SDM630 CPU power reduction. In these new versions of the hardware, support for various new features was introduced, including voltage reduction for the GPU, security hardening and a new way of controlling CPU DVFS, consisting in internal communication between microcontrollers, specifically the CPR-Hardened and the Operating State Manager. The CPR v3, v4 and CPRh are present in a broad range of SoCs, from the mid-range to the high end ones including, but not limited to, MSM8953/8996/8998, SDM630/636/660/845. Signed-off-by: AngeloGioacchino Del Regno [Konrad: rebase, apply review comments] Signed-off-by: Konrad Dybcio --- drivers/soc/qcom/Kconfig | 22 + drivers/soc/qcom/Makefile | 4 +- drivers/soc/qcom/cpr-common.h | 2 + drivers/soc/qcom/cpr3.c | 2855 +++++++++++++++++++++++++++++++++++++++++ include/soc/qcom/cpr.h | 17 + 5 files changed, 2899 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e597799e8121..0e62827523ad 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -29,6 +29,7 @@ config QCOM_COMMAND_DB config QCOM_CPR tristate "QCOM Core Power Reduction (CPR) support" depends on ARCH_QCOM && HAS_IOMEM + select QCOM_CPR_COMMON select PM_OPP select REGMAP help @@ -42,6 +43,27 @@ config QCOM_CPR To compile this driver as a module, choose M here: the module will be called qcom-cpr +config QCOM_CPR_COMMON + tristate + +config QCOM_CPR3 + tristate "QCOM Core Power Reduction (CPR v3/v4/Hardened) support" + depends on ARCH_QCOM && HAS_IOMEM + select QCOM_CPR_COMMON + select PM_OPP + select REGMAP + help + Say Y here to enable support for the CPR hardware found on a broad + variety of Qualcomm SoCs like MSM8996, MSM8998, SDM630, SDM660, + SDM845 and others. + + This driver populates OPP tables and makes adjustments to them + based on feedback from the CPR hardware. If you want to do CPU + and/or GPU frequency scaling say Y here. + + To compile this driver as a module, choose M here: the module will + be called qcom-cpr3 + config QCOM_GENI_SE tristate "QCOM GENI Serial Engine Driver" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 82b23743371b..f2878f451fb0 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -3,7 +3,9 @@ CFLAGS_rpmh-rsc.o := -I$(src) obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -obj-$(CONFIG_QCOM_CPR) += cpr-common.o cpr.o +obj-$(CONFIG_QCOM_CPR) += cpr.o +obj-$(CONFIG_QCOM_CPR_COMMON) += cpr-common.o +obj-$(CONFIG_QCOM_CPR3) += cpr3.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_OCMEM) += ocmem.o diff --git a/drivers/soc/qcom/cpr-common.h b/drivers/soc/qcom/cpr-common.h index 2c5bb81ab713..17f55bbc4a11 100644 --- a/drivers/soc/qcom/cpr-common.h +++ b/drivers/soc/qcom/cpr-common.h @@ -65,6 +65,8 @@ struct corner { struct corner_data { unsigned int fuse_corner; u64 freq; + int oloop_vadj; + int cloop_vadj; }; struct acc_desc { diff --git a/drivers/soc/qcom/cpr3.c b/drivers/soc/qcom/cpr3.c new file mode 100644 index 000000000000..6ee74f80d2cb --- /dev/null +++ b/drivers/soc/qcom/cpr3.c @@ -0,0 +1,2855 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019 Linaro Limited + * Copyright (c) 2021, AngeloGioacchino Del Regno + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpr-common.h" + +#define CPR3_RO_COUNT 16 +#define CPR3_RO_MASK GENMASK(CPR3_RO_COUNT - 1, 0) + +/* CPR3 registers */ +#define CPR3_REG_CPR_VERSION 0x0 +#define CPRH_CPR_VERSION_4P5 0x40050000 + +#define CPR3_REG_CPR_CTL 0x4 +#define CPR3_CPR_CTL_LOOP_EN_MASK BIT(0) +#define CPR3_CPR_CTL_IDLE_CLOCKS_MASK GENMASK(5, 1) +#define CPR3_CPR_CTL_COUNT_MODE_MASK GENMASK(7, 6) + #define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN 0 + #define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MAX 1 + #define CPR3_CPR_CTL_COUNT_MODE_STAGGERED 2 + #define CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_AGE 3 +#define CPR3_CPR_CTL_COUNT_REPEAT_MASK GENMASK(31, 9) + +#define CPR3_REG_CPR_STATUS 0x8 +#define CPR3_CPR_STATUS_BUSY_MASK BIT(0) + +/* + * This register is not present on controllers that support HW closed-loop + * except CPR4 APSS controller. + */ +#define CPR3_REG_CPR_TIMER_AUTO_CONT 0xC + +#define CPR3_REG_CPR_STEP_QUOT 0x14 +#define CPR3_CPR_STEP_QUOT_MIN_MASK GENMASK(5, 0) +#define CPR3_CPR_STEP_QUOT_MAX_MASK GENMASK(11, 6) +#define CPRH_DELTA_QUOT_STEP_FACTOR 4 + +#define CPR3_REG_GCNT(ro) (0xA0 + 0x4 * (ro)) +#define CPR3_REG_SENSOR_OWNER(sensor) (0x200 + 0x4 * (sensor)) + +#define CPR3_REG_CONT_CMD 0x800 +#define CPR3_CONT_CMD_ACK 0x1 +#define CPR3_CONT_CMD_NACK 0x0 + +#define CPR3_REG_THRESH(thread) (0x808 + 0x440 * (thread)) +#define CPR3_THRESH_CONS_DOWN_MASK GENMASK(3, 0) +#define CPR3_THRESH_CONS_UP_MASK GENMASK(7, 4) +#define CPR3_THRESH_DOWN_THRESH_MASK GENMASK(12, 8) +#define CPR3_THRESH_UP_THRESH_MASK GENMASK(17, 13) + +#define CPR3_REG_RO_MASK(thread) (0x80C + 0x440 * (thread)) + +#define CPR3_REG_RESULT0(thread) (0x810 + 0x440 * (thread)) +#define CPR3_RESULT0_BUSY_MASK BIT(0) +#define CPR3_RESULT0_STEP_DN_MASK BIT(1) +#define CPR3_RESULT0_STEP_UP_MASK BIT(2) +#define CPR3_RESULT0_ERROR_STEPS_MASK GENMASK(7, 3) +#define CPR3_RESULT0_ERROR_MASK GENMASK(19, 8) +#define CPR3_RESULT0_NEG_MASK BIT(20) + +#define CPR3_REG_RESULT1(thread) (0x814 + 0x440 * (thread)) +#define CPR3_RESULT1_QUOT_MIN_MASK GENMASK(11, 0) +#define CPR3_RESULT1_QUOT_MAX_MASK GENMASK(23, 12) +#define CPR3_RESULT1_RO_MIN_MASK GENMASK(27, 24) +#define CPR3_RESULT1_RO_MAX_MASK GENMASK(31, 28) + +#define CPR3_REG_RESULT2(thread) (0x818 + 0x440 * (thread)) +#define CPR3_RESULT2_STEP_QUOT_MIN_MASK GENMASK(5, 0) +#define CPR3_RESULT2_STEP_QUOT_MAX_MASK GENMASK(11, 6) +#define CPR3_RESULT2_SENSOR_MIN_MASK GENMASK(23, 16) +#define CPR3_RESULT2_SENSOR_MAX_MASK GENMASK(31, 24) + +#define CPR3_REG_IRQ_EN 0x81C +#define CPR3_REG_IRQ_CLEAR 0x820 +#define CPR3_REG_IRQ_STATUS 0x824 +#define CPR3_IRQ_UP BIT(3) +#define CPR3_IRQ_MID BIT(2) +#define CPR3_IRQ_DOWN BIT(1) +#define CPR3_IRQ_ALL (CPR3_IRQ_UP | CPR3_IRQ_MID | CPR3_IRQ_DOWN) + +#define CPR3_REG_TARGET_QUOT(thread, ro) (0x840 + 0x440 * (thread) + 0x4 * (ro)) + +/* Registers found only on controllers that support HW closed-loop. */ +#define CPR3_REG_PD_THROTTLE 0xE8 + +#define CPR3_REG_HW_CLOSED_LOOP_DISABLED 0x3000 +#define CPR3_REG_CPR_TIMER_MID_CONT 0x3004 +#define CPR3_REG_CPR_TIMER_UP_DN_CONT 0x3008 + +/* CPR4 controller specific registers and bit definitions */ +#define CPR4_REG_CPR_TIMER_CLAMP 0x10 +#define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN BIT(27) + +#define CPR4_REG_MISC 0x700 +#define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN BIT(2) +#define CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN BIT(3) + +#define CPR4_REG_SAW_ERROR_STEP_LIMIT 0x7A4 +#define CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK GENMASK(4, 0) +#define CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT 0 +#define CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK GENMASK(9, 5) +#define CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT 5 + +#define CPR4_REG_MARGIN_TEMP_CORE_TIMERS 0x7A8 +#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK GENMASK(28, 18) +#define CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHFT 18 + +#define CPR4_REG_MARGIN_ADJ_CTL 0x7F8 +#define CPR4_MARGIN_ADJ_HW_CLOSED_LOOP_EN BIT(4) +#define CPR4_MARGIN_ADJ_PER_RO_KV_MARGIN_EN BIT(7) +#define CPR4_MARGIN_ADJ_PMIC_STEP_SIZE_MASK GENMASK(16, 12) +#define CPR4_MARGIN_ADJ_PMIC_STEP_SIZE_SHIFT 12 +#define CPR4_MARGIN_ADJ_KV_MARGIN_ADJ_STEP_QUOT_MASK GENMASK(31, 26) +#define CPR4_MARGIN_ADJ_KV_MARGIN_ADJ_STEP_QUOT_SHIFT 26 + +#define CPR4_REG_CPR_MASK_THREAD(thread) (0x80C + 0x440 * (thread)) +#define CPR4_CPR_MASK_THREAD_DISABLE_THREAD BIT(31) +#define CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK GENMASK(15, 0) + +/* CPRh controller specific registers and bit definitions */ +#define __CPRH_REG_CORNER(rbase, tbase, tid, cnum) (rbase + (tbase * tid) + (0x4 * cnum)) +#define CPRH_REG_CORNER(d, t, c) __CPRH_REG_CORNER(d->reg_corner, d->reg_corner_tid, t, c) + +#define CPRH_CTL_OSM_ENABLED BIT(0) +#define CPRH_CTL_BASE_VOLTAGE_MASK GENMASK(10, 1) +#define CPRH_CTL_BASE_VOLTAGE_SHIFT 1 +#define CPRH_CTL_MODE_SWITCH_DELAY_MASK GENMASK(24, 17) +#define CPRH_CTL_MODE_SWITCH_DELAY_SHIFT 17 +#define CPRH_CTL_VOLTAGE_MULTIPLIER_MASK GENMASK(28, 25) +#define CPRH_CTL_VOLTAGE_MULTIPLIER_SHIFT 25 + +#define CPRH_CORNER_INIT_VOLTAGE_MASK GENMASK(7, 0) +#define CPRH_CORNER_FLOOR_VOLTAGE_MASK GENMASK(15, 8) +#define CPRH_CORNER_QUOT_DELTA_MASK GENMASK(24, 16) +#define CPRH_CORNER_RO_SEL_MASK GENMASK(28, 25) +#define CPRH_CORNER_CPR_CL_DISABLE BIT(29) + +#define CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE 255 +#define CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE 255 +#define CPRH_CORNER_QUOT_DELTA_MAX_VALUE 511 + +enum cpr_type { + CTRL_TYPE_CPR3, + CTRL_TYPE_CPR4, + CTRL_TYPE_CPRH, + CTRL_TYPE_MAX, +}; + +/* + * struct cpr_thread_desc - CPR Thread-specific parameters + * + * @controller_id: Identifier of the CPR controller expected by the HW + * @hw_tid: Identifier of the CPR thread expected by the HW + * @ro_scaling_factor: Scaling factor for each ring oscillator entry + * @ro_scaling_factor_common: Whether the ro_scaling_factor value is common for all fuses + * @init_voltage_step: Voltage in uV for number of steps read from fuse array + * @init_voltage_width: Bit-width of the voltage read from the fuse array + * @sensor_range_start: First sensor ID used by a thread + * @sensor_range_end: Last sensor ID used by a thread + * @step_quot_init_min: Minimum achievable step quotient for this corner + * @step_quot_init_max: Maximum achievable step quotient for this corner + * @num_fuse_corners: Number of valid entries in fuse_corner_data + * @fuse_corner_data: Parameters for calculation of each fuse corner + */ +struct cpr_thread_desc { + u8 controller_id; + u8 hw_tid; + const int (*ro_scaling_factor)[CPR3_RO_COUNT]; + bool ro_scaling_factor_common; + int init_voltage_step; + int init_voltage_width; + u8 sensor_range_start; + u8 sensor_range_end; + u8 step_quot_init_min; + u8 step_quot_init_max; + unsigned int num_fuse_corners; + struct fuse_corner_data *fuse_corner_data; +}; + +/* + * struct cpr_desc - Driver instance-wide CPR parameters + * + * @cpr_type: Type (base version) of the CPR controller + * @num_threads: Max. number of threads supported by this controller + * @timer_delay_us: Loop delay time in uS + * @timer_updn_delay_us: Voltage after-up/before-down delay time in uS + * @timer_cons_up: Wait between consecutive up requests in uS + * @timer_cons_down: Wait between consecutive down requests in uS + * @up_threshold: Generic corner up threshold + * @down_threshold: Generic corner down threshold + * @idle_clocks: CPR Sensor: idle timer in cpr clocks unit + * @count_mode: CPR Sensor: counting mode + * @count_repeat: CPR Sensor: number of times to repeat reading + * @gcnt_us: CPR measurement interval in uS + * @vreg_step_fixed: Regulator voltage per step (if vreg unusable) + * @vreg_step_up_limit: Num. of steps up at once before re-measuring sensors + * @vreg_step_down_limit: Num. of steps dn at once before re-measuring sensors + * @vdd_settle_time_us: Settling timer to account for one VDD supply step + * @corner_settle_time_us: Settle time for corner switch request + * @mem_acc_threshold: Memory Accelerator (MEM-ACC) voltage threshold + * @apm_threshold: Array Power Mux (APM) voltage threshold + * @apm_crossover: Array Power Mux (APM) corner crossover voltage + * @apm_hysteresis: Hysteresis for APM V-threshold related calculations + * @cpr_base_voltage: Safety: Absolute minimum voltage (uV) on this CPR + * @cpr_max_voltage: Safety: Absolute maximum voltage (uV) on this CPR + * @pd_throttle_val: CPR Power Domain throttle during voltage switch + * @threads: Array containing "CPR Thread" specific parameters + * @reduce_to_fuse_uV: Reduce corner max volts (if higher) to fuse ceiling + * @reduce_to_corner_uV: Reduce corner max volts (if higher) to corner ceil. + * @hw_closed_loop_en: Enable CPR HW Closed-Loop voltage auto-adjustment + */ +struct cpr_desc { + enum cpr_type cpr_type; + unsigned int num_threads; + unsigned int timer_delay_us; + u8 timer_updn_delay_us; + u8 timer_cons_up; + u8 timer_cons_down; + u8 up_threshold; + u8 down_threshold; + u8 idle_clocks; + u8 count_mode; + u8 count_repeat; + u8 gcnt_us; + u16 vreg_step_fixed; + u8 vreg_step_up_limit; + u8 vreg_step_down_limit; + u8 vdd_settle_time_us; + u8 corner_settle_time_us; + int mem_acc_threshold; + int apm_threshold; + int apm_crossover; + int apm_hysteresis; + u32 cpr_base_voltage; + u32 cpr_max_voltage; + u32 pd_throttle_val; + + const struct cpr_thread_desc **threads; + bool reduce_to_fuse_uV; + bool reduce_to_corner_uV; + bool hw_closed_loop_en; +}; + +struct cpr_drv; +struct cpr_thread { + int num_corners; + int id; + bool enabled; + void __iomem *base; + struct clk *cpu_clk; + struct corner *corner; + struct corner *corners; + struct fuse_corner *fuse_corners; + struct cpr_drv *drv; + struct cpr_ext_data ext_data; + struct generic_pm_domain pd; + struct device *attached_cpu_dev; + struct work_struct restart_work; + bool restarting; + + const struct cpr_fuse *cpr_fuses; + const struct cpr_thread_desc *desc; +}; + +struct cpr_drv { + int irq; + unsigned int ref_clk_khz; + struct device *dev; + struct mutex lock; + struct regulator *vreg; + struct regmap *tcsr; + u32 gcnt; + u32 speed_bin; + u32 fusing_rev; + u32 last_uV; + u32 cpr_hw_rev; + u32 reg_corner; + u32 reg_corner_tid; + u32 reg_ctl; + u32 reg_status; + int fuse_level_set; + int extra_corners; + unsigned int vreg_step; + bool enabled; + + struct cpr_thread *threads; + struct genpd_onecell_data cell_data; + + const struct cpr_desc *desc; + const struct acc_desc *acc_desc; + struct dentry *debugfs; +}; + +/** + * cpr_get_corner_post_vadj() - Get corner post-voltage adjustment values + * @opp: Pointer to the corresponding OPP struct + * @tid: CPR thread ID + * @open_loop: Pointer to the closed-loop adjustment value + * @closed_loop: Pointer to the open-loop adjustment value + * + * Return: 0 on success, negative errno on failure + */ +static int cpr_get_corner_post_vadj(struct dev_pm_opp *opp, u32 tid, + s32 *open_loop, s32 *closed_loop) +{ + struct device_node *np; + int ret; + + /* + * There is no of_property_read_s32_index, so we just store the + * result into a s32 variable. After all, the OF API is doing + * the exact same for of_property_read_s32... + */ + np = dev_pm_opp_get_of_node(opp); + + ret = of_property_read_u32_index(np, "qcom,opp-oloop-vadj", + tid, open_loop); + if (ret) + goto out; + + ret = of_property_read_u32_index(np, "qcom,opp-cloop-vadj", + tid, closed_loop); + +out: + of_node_put(np); + return ret; +} + +static void cpr_write(struct cpr_thread *thread, u32 offset, u32 value) +{ + writel(value, thread->base + offset); +} + +static u32 cpr_read(struct cpr_thread *thread, u32 offset) +{ + return readl(thread->base + offset); +} + +static void +cpr_masked_write(struct cpr_thread *thread, u32 offset, u32 mask, u32 value) +{ + u32 val; + + val = readl(thread->base + offset); + val &= ~mask; + val |= value & mask; + writel(val, thread->base + offset); +} + +static void cpr_irq_clr(struct cpr_thread *thread) +{ + cpr_write(thread, CPR3_REG_IRQ_CLEAR, CPR3_IRQ_ALL); +} + +static void cpr_irq_clr_nack(struct cpr_thread *thread) +{ + cpr_irq_clr(thread); + cpr_write(thread, CPR3_REG_CONT_CMD, CPR3_CONT_CMD_NACK); +} + +static void cpr_irq_clr_ack(struct cpr_thread *thread) +{ + cpr_irq_clr(thread); + cpr_write(thread, CPR3_REG_CONT_CMD, CPR3_CONT_CMD_ACK); +} + +static void cpr_irq_set(struct cpr_thread *thread, u32 int_bits) +{ + /* On CPR-hardened, interrupts are managed by and on firmware */ + if (thread->drv->desc->cpr_type == CTRL_TYPE_CPRH) + return; + + cpr_write(thread, CPR3_REG_IRQ_EN, int_bits); +} + +/** + * cpr_ctl_enable() - Enable CPR thread + * @thread: Structure holding CPR thread-specific parameters + */ +static void cpr_ctl_enable(struct cpr_thread *thread) +{ + if (thread->drv->enabled && !thread->restarting) { + cpr_masked_write(thread, CPR3_REG_CPR_CTL, + CPR3_CPR_CTL_LOOP_EN_MASK, + CPR3_CPR_CTL_LOOP_EN_MASK); + } +} + +/** + * cpr_ctl_disable() - Disable CPR thread + * @thread: Structure holding CPR thread-specific parameters + */ +static void cpr_ctl_disable(struct cpr_thread *thread) +{ + const struct cpr_desc *desc = thread->drv->desc; + + if (desc->cpr_type != CTRL_TYPE_CPRH) { + cpr_irq_set(thread, 0); + cpr_irq_clr(thread); + } + + cpr_masked_write(thread, CPR3_REG_CPR_CTL, + CPR3_CPR_CTL_LOOP_EN_MASK, 0); +} + +/** + * cpr_ctl_is_enabled() - Check if thread is enabled + * @thread: Structure holding CPR thread-specific parameters + * + * Return: true if the CPR is enabled, false if it is disabled. + */ +static bool cpr_ctl_is_enabled(struct cpr_thread *thread) +{ + u32 reg_val; + + reg_val = cpr_read(thread, CPR3_REG_CPR_CTL); + return reg_val & CPR3_CPR_CTL_LOOP_EN_MASK; +} + +/** + * cpr_check_any_thread_busy() - Check if HW is done processing + * @thread: Structure holding CPR thread-specific parameters + * + * Return: true if the CPR is busy, false if it is ready. + */ +static bool cpr_check_any_thread_busy(struct cpr_thread *thread) +{ + int i; + + for (i = 0; i < thread->drv->desc->num_threads; i++) + if (cpr_read(thread, CPR3_REG_RESULT0(i)) & + CPR3_RESULT0_BUSY_MASK) + return true; + + return false; +} + +static void cpr_restart_worker(struct work_struct *work) +{ + struct cpr_thread *thread = container_of(work, struct cpr_thread, + restart_work); + struct cpr_drv *drv = thread->drv; + int i; + + mutex_lock(&drv->lock); + + thread->restarting = true; + cpr_ctl_disable(thread); + disable_irq(drv->irq); + + mutex_unlock(&drv->lock); + + for (i = 0; i < 20; i++) { + u32 cpr_status = cpr_read(thread, CPR3_REG_CPR_STATUS); + u32 ctl = cpr_read(thread, CPR3_REG_CPR_CTL); + + if ((cpr_status & CPR3_CPR_STATUS_BUSY_MASK) && + !(ctl & CPR3_CPR_CTL_LOOP_EN_MASK)) + break; + + udelay(10); + } + + cpr_irq_clr(thread); + + for (i = 0; i < 20; i++) { + u32 status = cpr_read(thread, CPR3_REG_IRQ_STATUS); + + if (!(status & CPR3_IRQ_ALL)) + break; + udelay(10); + } + + mutex_lock(&drv->lock); + + thread->restarting = false; + enable_irq(drv->irq); + cpr_ctl_enable(thread); + + mutex_unlock(&drv->lock); +} + +/** + * cpr_corner_restore() - Restore saved corner level + * @thread: Structure holding CPR thread-specific parameters + * @corner: Structure holding the saved corner level + */ +static void cpr_corner_restore(struct cpr_thread *thread, + struct corner *corner) +{ + struct cpr_drv *drv = thread->drv; + struct fuse_corner *fuse = corner->fuse_corner; + const struct cpr_thread_desc *tdesc = thread->desc; + u32 ro_sel = fuse->ring_osc_idx; + + cpr_write(thread, CPR3_REG_GCNT(ro_sel), drv->gcnt); + + cpr_write(thread, CPR3_REG_RO_MASK(tdesc->hw_tid), + CPR3_RO_MASK & ~BIT(ro_sel)); + + cpr_write(thread, CPR3_REG_TARGET_QUOT(tdesc->hw_tid, ro_sel), + fuse->quot - corner->quot_adjust); + + if (drv->desc->cpr_type == CTRL_TYPE_CPR4) + cpr_masked_write(thread, + CPR4_REG_CPR_MASK_THREAD(tdesc->hw_tid), + CPR4_CPR_MASK_THREAD_DISABLE_THREAD | + CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK, 0); + + thread->corner = corner; + corner->last_uV = corner->uV; +} + +/** + * cpr_set_acc() - Set fuse level to the mem-acc + * @drv: Main driver structure + * @f: Fuse level + */ +static void cpr_set_acc(struct cpr_drv *drv, int f) +{ + const struct acc_desc *desc = drv->acc_desc; + struct reg_sequence *s = desc->settings; + int n = desc->num_regs_per_fuse; + + if (!s || f == drv->fuse_level_set) + return; + + regmap_multi_reg_write(drv->tcsr, s + (n * f), n); + drv->fuse_level_set = f; +} + +/** + * cpr_pre_voltage() - Actions to execute before setting voltage + * @thread: Structure holding CPR thread-specific parameters + * @dir: Enumeration for voltage change direction + * @fuse_level: Fuse corner for mem-acc, if supported. + * + * Return: Zero for success or negative number on errors. + */ +static int cpr_pre_voltage(struct cpr_thread *thread, + enum voltage_change_dir dir, + int fuse_level) +{ + struct cpr_drv *drv = thread->drv; + + if (drv->desc->cpr_type == CTRL_TYPE_CPR3 && + drv->desc->pd_throttle_val) + cpr_write(thread, CPR3_REG_PD_THROTTLE, + drv->desc->pd_throttle_val); + + if (drv->tcsr && dir == DOWN) + cpr_set_acc(drv, fuse_level); + + return 0; +} + +/** + * cpr_post_voltage() - Actions to execute after setting voltage + * @thread: Structure holding CPR thread-specific parameters + * @dir: Enumeration for voltage change direction + * @fuse_level: Fuse corner for mem-acc, if supported. + * + * Return: Zero for success or negative number on errors. + */ +static int cpr_post_voltage(struct cpr_thread *thread, + enum voltage_change_dir dir, + int fuse_level) +{ + struct cpr_drv *drv = thread->drv; + + if (drv->tcsr && dir == UP) + cpr_set_acc(drv, fuse_level); + + if (drv->desc->cpr_type == CTRL_TYPE_CPR3) + cpr_write(thread, CPR3_REG_PD_THROTTLE, 0); + + return 0; +} + +/** + * cpr_commit_state() - Set the newly requested voltage + * @thread: Structure holding CPR thread-specific parameters + * + * Return: IRQ_SUCCESS for success, IRQ_NONE if the CPR is disabled. + */ +static int cpr_commit_state(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + int min_uV = 0, max_uV = 0, new_uV = 0, fuse_level = 0; + enum voltage_change_dir dir; + u32 next_irqmask = 0; + int ret, i; + + /* On CPRhardened, control states are managed in firmware */ + if (drv->desc->cpr_type == CTRL_TYPE_CPRH) + return 0; + + for (i = 0; i < drv->desc->num_threads; i++) { + struct cpr_thread *thread = &drv->threads[i]; + + if (!thread->corner) + continue; + + fuse_level = max(fuse_level, + (int) (thread->corner->fuse_corner - + &thread->fuse_corners[0])); + + max_uV = max(max_uV, thread->corner->max_uV); + min_uV = max(min_uV, thread->corner->min_uV); + new_uV = max(new_uV, thread->corner->last_uV); + } + dev_vdbg(drv->dev, "%s: new uV: %d, last uV: %d\n", + __func__, new_uV, drv->last_uV); + + /* + * Safety measure: if the voltage is out of the globally allowed + * range, then go out and warn the user. + * This should *never* happen. + */ + if (new_uV > drv->desc->cpr_max_voltage || + new_uV < drv->desc->cpr_base_voltage) { + dev_warn(drv->dev, "Voltage (%u uV) out of range.", new_uV); + return -EINVAL; + } + + if (new_uV == drv->last_uV || fuse_level == drv->fuse_level_set) + goto out; + + if (fuse_level > drv->fuse_level_set) + dir = UP; + else + dir = DOWN; + + ret = cpr_pre_voltage(thread, fuse_level, dir); + if (ret) + return ret; + + dev_vdbg(drv->dev, "setting voltage: %d\n", new_uV); + + ret = regulator_set_voltage(drv->vreg, new_uV, new_uV); + if (ret) { + dev_err_ratelimited(drv->dev, "failed to set voltage %d: %d\n", new_uV, ret); + return ret; + } + + ret = cpr_post_voltage(thread, fuse_level, dir); + if (ret) + return ret; + + drv->last_uV = new_uV; +out: + if (new_uV > min_uV) + next_irqmask |= CPR3_IRQ_DOWN; + if (new_uV < max_uV) + next_irqmask |= CPR3_IRQ_UP; + + cpr_irq_set(thread, next_irqmask); + + return 0; +} + +static unsigned int cpr_get_cur_perf_state(struct cpr_thread *thread) +{ + return thread->corner ? thread->corner - thread->corners + 1 : 0; +} + +/** + * cpr_scale() - Calculate new voltage for the received direction + * @thread: Structure holding CPR thread-specific parameters + * @dir: Enumeration for voltage change direction + * + * The CPR scales one by one: this function calculates the new + * voltage to set when a voltage-UP or voltage-DOWN request comes + * and stores it into the per-thread structure that gets passed. + */ +static void cpr_scale(struct cpr_thread *thread, enum voltage_change_dir dir) +{ + struct cpr_drv *drv = thread->drv; + const struct cpr_thread_desc *tdesc = thread->desc; + u32 val, error_steps; + int last_uV, new_uV; + struct corner *corner; + + if (dir != UP && dir != DOWN) + return; + + corner = thread->corner; + val = cpr_read(thread, CPR3_REG_RESULT0(tdesc->hw_tid)); + error_steps = FIELD_GET(CPR3_RESULT0_ERROR_STEPS_MASK, val); + + last_uV = corner->last_uV; + + if (dir == UP) { + if (!(val & CPR3_RESULT0_STEP_UP_MASK)) + return; + + /* Calculate new voltage */ + new_uV = last_uV + drv->vreg_step; + new_uV = min(new_uV, corner->max_uV); + + dev_vdbg(drv->dev, "[T%u] UP - new_uV=%d last_uV=%d p-state=%u st=%u\n", + thread->id, new_uV, last_uV, + cpr_get_cur_perf_state(thread), error_steps); + } else { + if (!(val & CPR3_RESULT0_STEP_DN_MASK)) + return; + + /* Calculate new voltage */ + new_uV = last_uV - drv->vreg_step; + new_uV = max(new_uV, corner->min_uV); + dev_vdbg(drv->dev, "[T%u] DOWN - new_uV=%d last_uV=%d p-state=%u st=%u\n", + thread->id, new_uV, last_uV, + cpr_get_cur_perf_state(thread), error_steps); + } + corner->last_uV = new_uV; +} + +/** + * cpr_irq_handler() - Handle CPR3/CPR4 status interrupts + * @irq: Number of the interrupt + * @dev: Pointer to the cpr_thread structure + * + * Handle the interrupts coming from non-hardened CPR HW as to get + * an ok to scale voltages immediately, or to pass error status to + * the hardware (either success/ACK or failure/NACK). + * + * Return: IRQ_SUCCESS for success, IRQ_NONE if the CPR is disabled. + */ +static irqreturn_t cpr_irq_handler(int irq, void *dev) +{ + struct cpr_thread *thread = dev; + struct cpr_drv *drv = thread->drv; + irqreturn_t ret = IRQ_HANDLED; + int i, rc; + enum voltage_change_dir dir = NO_CHANGE; + u32 val; + + mutex_lock(&drv->lock); + + val = cpr_read(thread, CPR3_REG_IRQ_STATUS); + + dev_vdbg(drv->dev, "IRQ_STATUS = 0x%x\n", val); + + if (!cpr_ctl_is_enabled(thread)) { + dev_vdbg(drv->dev, "CPR is disabled\n"); + ret = IRQ_NONE; + } else if (cpr_check_any_thread_busy(thread)) { + cpr_irq_clr_nack(thread); + dev_dbg(drv->dev, "CPR measurement is not ready\n"); + } else { + /* + * Following sequence of handling is as per each IRQ's + * priority + */ + if (val & CPR3_IRQ_UP) + dir = UP; + else if (val & CPR3_IRQ_DOWN) + dir = DOWN; + + if (dir != NO_CHANGE) { + for (i = 0; i < drv->desc->num_threads; i++) { + thread = &drv->threads[i]; + cpr_scale(thread, dir); + } + + rc = cpr_commit_state(thread); + if (rc) + cpr_irq_clr_nack(thread); + else + cpr_irq_clr_ack(thread); + } else if (val & CPR3_IRQ_MID) { + dev_dbg(drv->dev, "IRQ occurred for Mid Flag\n"); + } else { + dev_warn(drv->dev, "IRQ occurred for unknown flag (%#08x)\n", val); + schedule_work(&thread->restart_work); + } + } + + mutex_unlock(&drv->lock); + + return ret; +} + +static int cpr_switch(struct cpr_drv *drv) +{ + int i, ret; + bool enabled = false; + + if (drv->desc->cpr_type == CTRL_TYPE_CPRH) + return 0; + + for (i = 0; i < drv->desc->num_threads && !enabled; i++) + enabled = drv->threads[i].enabled; + + dev_vdbg(drv->dev, "%s: enabled = %d\n", __func__, enabled); + + if (enabled == drv->enabled) + return 0; + + if (enabled) { + ret = regulator_enable(drv->vreg); + if (ret) + return ret; + + drv->enabled = enabled; + + for (i = 0; i < drv->desc->num_threads; i++) + if (drv->threads[i].corner) + break; + + if (i < drv->desc->num_threads) { + cpr_irq_clr(&drv->threads[i]); + + cpr_commit_state(&drv->threads[i]); + cpr_ctl_enable(&drv->threads[i]); + } + } else { + for (i = 0; i < drv->desc->num_threads && !enabled; i++) + cpr_ctl_disable(&drv->threads[i]); + + drv->enabled = enabled; + + ret = regulator_disable(drv->vreg); + if (ret < 0) + return ret; + } + + return 0; +} + +/** + * cpr_enable() - Enables a CPR thread + * @thread: Structure holding CPR thread-specific parameters + * + * Return: Zero for success or negative number on errors. + */ +static int cpr_enable(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + int ret; + + dev_dbg(drv->dev, "Enabling thread %d\n", thread->id); + + mutex_lock(&drv->lock); + + thread->enabled = true; + ret = cpr_switch(thread->drv); + + mutex_unlock(&drv->lock); + + return ret; +} + +/** + * cpr_disable() - Disables a CPR thread + * @thread: Structure holding CPR thread-specific parameters + * + * Return: Zero for success or negative number on errors. + */ +static int cpr_disable(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + int ret; + + dev_dbg(drv->dev, "Disabling thread %d\n", thread->id); + + mutex_lock(&drv->lock); + + thread->enabled = false; + ret = cpr_switch(thread->drv); + + mutex_unlock(&drv->lock); + + return ret; +} + +/** + * cpr_configure() - Configure main HW parameters + * @thread: Structure holding CPR thread-specific parameters + * + * This function configures the main CPR hardware parameters, such as + * internal timers (and delays), sensor ownerships, activates and/or + * deactivates cpr-threads and others, as one sequence for all of the + * versions supported in this driver. By design, the function may + * return a success earlier if the sequence for "a previous version" + * has ended. + * + * Context: The CPR must be clocked before calling this function! + * + * Return: Zero for success or negative number on errors. + */ +static int cpr_configure(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + const struct cpr_desc *desc = drv->desc; + const struct cpr_thread_desc *tdesc = thread->desc; + u32 val; + int i; + + /* Disable interrupt and CPR */ + cpr_irq_set(thread, 0); + cpr_write(thread, CPR3_REG_CPR_CTL, 0); + + /* Init and save gcnt */ + drv->gcnt = drv->ref_clk_khz * desc->gcnt_us; + do_div(drv->gcnt, 1000); + + /* Program the delay count for the timer */ + val = drv->ref_clk_khz * desc->timer_delay_us; + do_div(val, 1000); + if (desc->cpr_type == CTRL_TYPE_CPR3) { + cpr_write(thread, CPR3_REG_CPR_TIMER_MID_CONT, val); + + val = drv->ref_clk_khz * desc->timer_updn_delay_us; + do_div(val, 1000); + cpr_write(thread, CPR3_REG_CPR_TIMER_UP_DN_CONT, val); + } else { + cpr_write(thread, CPR3_REG_CPR_TIMER_AUTO_CONT, val); + } + dev_dbg(drv->dev, "Timer count: %#0x (for %d us)\n", val, + desc->timer_delay_us); + + /* Program the control register */ + val = FIELD_PREP(CPR3_CPR_CTL_IDLE_CLOCKS_MASK, desc->idle_clocks) | + FIELD_PREP(CPR3_CPR_CTL_COUNT_MODE_MASK, desc->count_mode) | + FIELD_PREP(CPR3_CPR_CTL_COUNT_REPEAT_MASK, desc->count_repeat); + cpr_write(thread, CPR3_REG_CPR_CTL, val); + + /* Configure CPR default step quotients */ + val = FIELD_PREP(CPR3_CPR_STEP_QUOT_MIN_MASK, tdesc->step_quot_init_min) | + FIELD_PREP(CPR3_CPR_STEP_QUOT_MAX_MASK, tdesc->step_quot_init_max); + + cpr_write(thread, CPR3_REG_CPR_STEP_QUOT, val); + + /* + * Configure the CPR sensor ownership always on thread 0 + * TODO: SDM845 has different ownership for sensors!! + */ + for (i = tdesc->sensor_range_start; i < tdesc->sensor_range_end; i++) + cpr_write(thread, CPR3_REG_SENSOR_OWNER(i), 0); + + /* Program Consecutive Up & Down */ + val = FIELD_PREP(CPR3_THRESH_CONS_DOWN_MASK, desc->timer_cons_down) | + FIELD_PREP(CPR3_THRESH_CONS_UP_MASK, desc->timer_cons_up) | + FIELD_PREP(CPR3_THRESH_DOWN_THRESH_MASK, desc->down_threshold) | + FIELD_PREP(CPR3_THRESH_UP_THRESH_MASK, desc->up_threshold); + cpr_write(thread, CPR3_REG_THRESH(tdesc->hw_tid), val); + + /* Mask all ring oscillators for all threads initially */ + cpr_write(thread, CPR3_REG_RO_MASK(tdesc->hw_tid), CPR3_RO_MASK); + + /* HW Closed-loop control */ + if (desc->cpr_type == CTRL_TYPE_CPR3) { + cpr_write(thread, CPR3_REG_HW_CLOSED_LOOP_DISABLED, + !desc->hw_closed_loop_en); + } else { + cpr_masked_write(thread, CPR4_REG_MARGIN_ADJ_CTL, + CPR4_MARGIN_ADJ_HW_CLOSED_LOOP_EN, + desc->hw_closed_loop_en ? + CPR4_MARGIN_ADJ_HW_CLOSED_LOOP_EN : 0); + } + + /* Additional configuration for CPR4 and beyond */ + if (desc->cpr_type < CTRL_TYPE_CPR4) + return 0; + + /* Disable threads initially only on non-hardened CPR4 */ + if (desc->cpr_type == CTRL_TYPE_CPR4) + cpr_masked_write(thread, CPR4_REG_CPR_MASK_THREAD(1), + CPR4_CPR_MASK_THREAD_DISABLE_THREAD | + CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK, + CPR4_CPR_MASK_THREAD_DISABLE_THREAD | + CPR4_CPR_MASK_THREAD_RO_MASK4THREAD_MASK); + + if (tdesc->hw_tid > 0) + cpr_masked_write(thread, CPR4_REG_MISC, + CPR4_MISC_RESET_STEP_QUOT_LOOP_EN | + CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN, + CPR4_MISC_RESET_STEP_QUOT_LOOP_EN | + CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN); + + val = drv->vreg_step; + do_div(val, 1000); + cpr_masked_write(thread, CPR4_REG_MARGIN_ADJ_CTL, + CPR4_MARGIN_ADJ_PMIC_STEP_SIZE_MASK, + val << CPR4_MARGIN_ADJ_PMIC_STEP_SIZE_SHIFT); + + cpr_masked_write(thread, CPR4_REG_SAW_ERROR_STEP_LIMIT, + CPR4_SAW_ERROR_STEP_LIMIT_DN_MASK, + desc->vreg_step_down_limit << + CPR4_SAW_ERROR_STEP_LIMIT_DN_SHIFT); + + cpr_masked_write(thread, CPR4_REG_SAW_ERROR_STEP_LIMIT, + CPR4_SAW_ERROR_STEP_LIMIT_UP_MASK, + desc->vreg_step_up_limit << + CPR4_SAW_ERROR_STEP_LIMIT_UP_SHIFT); + + cpr_masked_write(thread, CPR4_REG_MARGIN_ADJ_CTL, + CPR4_MARGIN_ADJ_PER_RO_KV_MARGIN_EN, + CPR4_MARGIN_ADJ_PER_RO_KV_MARGIN_EN); + + if (tdesc->hw_tid > 0) + cpr_masked_write(thread, CPR4_REG_CPR_TIMER_CLAMP, + CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN, + CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN); + + /* Settling timer to account for one VDD supply step */ + if (desc->vdd_settle_time_us > 0) { + u32 m = CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_MASK; + u32 s = CPR4_MARGIN_TEMP_CORE_TIMERS_SETTLE_VOLTAGE_COUNT_SHFT; + + cpr_masked_write(thread, CPR4_REG_MARGIN_TEMP_CORE_TIMERS, + m, desc->vdd_settle_time_us << s); + } + + /* Additional configuration for CPR-hardened */ + if (desc->cpr_type < CTRL_TYPE_CPRH) + return 0; + + /* Settling timer to account for one corner-switch request */ + if (desc->corner_settle_time_us > 0) + cpr_masked_write(thread, drv->reg_ctl, + CPRH_CTL_MODE_SWITCH_DELAY_MASK, + desc->corner_settle_time_us << + CPRH_CTL_MODE_SWITCH_DELAY_SHIFT); + + /* Base voltage and multiplier values for CPRh internal calculations */ + cpr_masked_write(thread, drv->reg_ctl, + CPRH_CTL_BASE_VOLTAGE_MASK, + (DIV_ROUND_UP(desc->cpr_base_voltage, + drv->vreg_step) << + CPRH_CTL_BASE_VOLTAGE_SHIFT)); + + cpr_masked_write(thread, drv->reg_ctl, + CPRH_CTL_VOLTAGE_MULTIPLIER_MASK, + DIV_ROUND_UP(drv->vreg_step, 1000) << + CPRH_CTL_VOLTAGE_MULTIPLIER_SHIFT); + + return 0; +} + +static int cprh_dummy_set_performance_state(struct generic_pm_domain *domain, + unsigned int state) +{ + return 0; +} + +static int cpr_set_performance_state(struct generic_pm_domain *domain, + unsigned int state) +{ + struct cpr_thread *thread = container_of(domain, struct cpr_thread, pd); + struct cpr_drv *drv = thread->drv; + struct corner *corner, *end; + int ret = 0; + + mutex_lock(&drv->lock); + + dev_dbg(drv->dev, "setting perf state: %u (prev state: %u thread: %u)\n", + state, cpr_get_cur_perf_state(thread), thread->id); + + /* + * Determine new corner we're going to. + * Remove one since lowest performance state is 1. + */ + corner = thread->corners + state - 1; + end = &thread->corners[thread->num_corners - 1]; + if (corner > end || corner < thread->corners) { + ret = -EINVAL; + goto unlock; + } + + cpr_ctl_disable(thread); + + cpr_irq_clr(thread); + if (thread->corner != corner) + cpr_corner_restore(thread, corner); + + ret = cpr_commit_state(thread); + if (ret) + goto unlock; + + cpr_ctl_enable(thread); +unlock: + mutex_unlock(&drv->lock); + + dev_dbg(drv->dev, "set perf state %u on thread %u\n", state, thread->id); + + return ret; +} + +/** + * cpr3_adjust_quot - Adjust the closed-loop quotients + * @ring_osc_factor: Ring oscillator adjustment factor + * @volt_closed_loop: Closed-loop voltage adjustment factor + * + * Calculates the quotient adjustment factor based on closed-loop + * quotients and ring oscillator factor. + * + * Return: Adjusted quotient + */ +static int cpr3_adjust_quot(int ring_osc_factor, int volt_closed_loop) +{ + s64 temp; + + if (ring_osc_factor == 0 || volt_closed_loop == 0) + return 0; + + temp = (s64)(ring_osc_factor * volt_closed_loop); + return (int)div_s64(temp, 1000000); +} + +/** + * cpr_fuse_corner_init() - Calculate fuse corner table + * @thread: Structure holding CPR thread-specific parameters + * + * This function populates the fuse corners table by reading the + * values from the fuses, eventually adjusting them with a fixed + * per-corner offset and doing basic checks about them being + * supported by the regulator that is assigned to this CPR - if + * it is available (on CPR-Hardened, there is no usable vreg, as + * that is protected by the hypervisor). + * + * Return: Zero for success, negative number on error + */ +static int cpr_fuse_corner_init(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + const struct cpr_thread_desc *desc = thread->desc; + const struct cpr_fuse *cpr_fuse = thread->cpr_fuses; + struct fuse_corner_data *fdata; + struct fuse_corner *fuse, *prev_fuse, *end; + int i, ret; + + /* Populate fuse_corner members */ + fuse = thread->fuse_corners; + prev_fuse = &fuse[0]; + end = &fuse[desc->num_fuse_corners - 1]; + fdata = desc->fuse_corner_data; + + for (i = 0; fuse <= end; fuse++, cpr_fuse++, i++, fdata++) { + int sf_idx = desc->ro_scaling_factor_common ? 0 : i; + int factor = desc->ro_scaling_factor[sf_idx][fuse->ring_osc_idx]; + + ret = cpr_populate_fuse_common(drv->dev, fdata, cpr_fuse, + fuse, drv->vreg_step, + desc->init_voltage_width, + desc->init_voltage_step); + if (ret) + return ret; + + /* + * Adjust the fuse quot with per-fuse-corner closed-loop + * voltage adjustment parameters. + */ + fuse->quot += cpr3_adjust_quot(factor, fdata->volt_cloop_adjust); + + /* CPRh: no regulator access... */ + if (drv->desc->cpr_type == CTRL_TYPE_CPRH) + goto skip_pvs_restrict; + + /* Re-check if corner voltage range is supported by regulator */ + ret = cpr_check_vreg_constraints(drv->dev, drv->vreg, fuse); + if (ret) + return ret; + +skip_pvs_restrict: + if (fuse->uV < prev_fuse->uV) + fuse->uV = prev_fuse->uV; + prev_fuse = fuse; + dev_dbg(drv->dev, "fuse corner %d: [%d %d %d] RO%u quot %d\n", + i, fuse->min_uV, fuse->uV, fuse->max_uV, + fuse->ring_osc_idx, fuse->quot); + + /* Check if constraints are valid */ + if (fuse->uV < fuse->min_uV || fuse->uV > fuse->max_uV) { + dev_err(drv->dev, "fuse corner %d: Bad voltage range.\n", i); + return -EINVAL; + } + } + + return 0; +} + +static void cpr3_restrict_corner(struct corner *corner, int threshold, + int hysteresis, int step) +{ + if (threshold > corner->min_uV && threshold <= corner->max_uV) { + if (corner->uV >= threshold) { + corner->min_uV = max(corner->min_uV, + threshold - hysteresis); + if (corner->min_uV > corner->uV) + corner->uV = corner->min_uV; + } else { + corner->max_uV = threshold; + corner->max_uV -= step; + } + } +} + +/* + * cprh_corner_adjust_opps() - Set voltage on each CPU OPP table entry + * + * On CPR-Hardened, the voltage level is controlled internally through + * the OSM hardware: in order to initialize the latter, we have to + * communicate the voltage to its driver, so that it will be able to + * write the right parameters (as they have to be set both on the CPRh + * and on the OSM) on it. + * This function is called only for CPRh. + * + * Return: Zero for success, negative number for error. + */ +static int cprh_corner_adjust_opps(struct cpr_thread *thread) +{ + struct corner *corner = thread->corners; + struct cpr_drv *drv = thread->drv; + int i, ret; + + for (i = 0; i < thread->num_corners; i++) { + ret = dev_pm_opp_adjust_voltage(thread->attached_cpu_dev, + corner[i].freq, + corner[i].uV, + corner[i].min_uV, + corner[i].max_uV); + if (ret) + break; + + dev_dbg(drv->dev, "OPP voltage adjusted for %llu Hz, %d uV\n", + corner[i].freq, corner[i].uV); + } + + /* If we couldn't adjust voltage for all corners, something went wrong */ + if (i < thread->num_corners) + return -EINVAL; + + return ret; +} + +/** + * cpr3_corner_init() - Calculate and set-up corners for the CPR HW + * @thread: Structure holding CPR thread-specific parameters + * + * This function calculates all the corner parameters by comparing + * and interpolating the values read from the various set-points + * read from the fuses (also called "fuse corners") to generate and + * program to the CPR a lookup table that describes each voltage + * step, mapped to a performance level (or corner number). + * + * It also programs other essential parameters on the CPR and - if + * we are dealing with CPR-Hardened, it will also enable the internal + * interface between the Operating State Manager (OSM) and the CPRh + * in order to achieve CPU DVFS. + * + * Return: Zero for success, negative number on error + */ +static int cpr3_corner_init(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + const struct cpr_desc *desc = drv->desc; + const struct cpr_thread_desc *tdesc = thread->desc; + const struct cpr_fuse *fuses = thread->cpr_fuses; + int i, ret, total_corners, extra_corners, level, scaling = 0; + unsigned int fnum, fc; + const char *quot_offset; + const struct fuse_corner_data *fdata; + struct fuse_corner *fuse, *prev_fuse; + struct corner *corner, *prev_corner, *end; + struct corner_data *cdata; + struct dev_pm_opp *opp; + u32 ring_osc_mask = CPR3_RO_MASK, min_quotient = U32_MAX; + u64 freq; + + corner = thread->corners; + prev_corner = &thread->corners[0]; + end = &corner[thread->num_corners - 1]; + + cdata = devm_kcalloc(drv->dev, thread->num_corners + drv->extra_corners, + sizeof(struct corner_data), GFP_KERNEL); + if (!cdata) + return -ENOMEM; + + for (level = 1; level <= thread->num_corners; level++) { + opp = dev_pm_opp_find_level_exact(&thread->pd.dev, level); + if (IS_ERR(opp)) + return -EINVAL; + + fc = cpr_get_fuse_corner(opp, thread->id); + if (!fc) { + dev_pm_opp_put(opp); + return -EINVAL; + } + fnum = fc - 1; + + freq = cpr_get_opp_hz_for_req(opp, thread->attached_cpu_dev); + if (!freq) { + thread->num_corners = max(level - 1, 0); + end = &thread->corners[thread->num_corners - 1]; + break; + } + + ret = cpr_get_corner_post_vadj(opp, thread->id, + &cdata[level - 1].oloop_vadj, + &cdata[level - 1].cloop_vadj); + if (ret) { + dev_pm_opp_put(opp); + return ret; + } + + cdata[level - 1].fuse_corner = fnum; + cdata[level - 1].freq = freq; + + fuse = &thread->fuse_corners[fnum]; + dev_dbg(drv->dev, "freq: %llu level: %u fuse level: %u\n", + freq, dev_pm_opp_get_level(opp) - 1, fnum); + if (freq > fuse->max_freq) + fuse->max_freq = freq; + dev_pm_opp_put(opp); + + /* + * Make sure that the frequencies in the table are in ascending + * order, as this is critical for the algorithm to work. + */ + if (cdata[level - 2].freq > freq) { + dev_err(drv->dev, "Frequency table not in ascending order.\n"); + return -EINVAL; + } + } + + if (thread->num_corners < 2) { + dev_err(drv->dev, "need at least 2 OPPs to use CPR\n"); + return -EINVAL; + } + + /* + * Get the quotient adjustment scaling factor, according to: + * + * scaling = min(1000 * (QUOT(corner_N) - QUOT(corner_N-1)) + * / (freq(corner_N) - freq(corner_N-1)), max_factor) + * + * QUOT(corner_N): quotient read from fuse for fuse corner N + * QUOT(corner_N-1): quotient read from fuse for fuse corner (N - 1) + * freq(corner_N): max frequency in MHz supported by fuse corner N + * freq(corner_N-1): max frequency in MHz supported by fuse corner + * (N - 1) + * + * Then walk through the corners mapped to each fuse corner + * and calculate the quotient adjustment for each one using the + * following formula: + * + * quot_adjust = (freq_max - freq_corner) * scaling / 1000 + * + * freq_max: max frequency in MHz supported by the fuse corner + * freq_corner: frequency in MHz corresponding to the corner + * scaling: calculated from above equation + * + * + * + + + * | v | + * q | f c o | f c + * u | c l | c + * o | f t | f + * t | c a | c + * | c f g | c f + * | e | + * +--------------- +---------------- + * 0 1 2 3 4 5 6 0 1 2 3 4 5 6 + * corner corner + * + * c = corner + * f = fuse corner + * + */ + for (i = 0; corner <= end; corner++, i++) { + int ro_fac, sf_idx, vadj, prev_quot; + u64 freq_diff_mhz; + + fnum = cdata[i].fuse_corner; + fdata = &tdesc->fuse_corner_data[fnum]; + quot_offset = fuses[fnum].quotient_offset; + fuse = &thread->fuse_corners[fnum]; + ring_osc_mask &= (u16)(~BIT(fuse->ring_osc_idx)); + if (fnum) + prev_fuse = &thread->fuse_corners[fnum - 1]; + else + prev_fuse = NULL; + + corner->fuse_corner = fuse; + corner->freq = cdata[i].freq; + corner->uV = fuse->uV; + + if (prev_fuse) { + if (prev_fuse->ring_osc_idx == fuse->ring_osc_idx) + quot_offset = NULL; + + scaling = cpr_calculate_scaling(drv->dev, quot_offset, + fdata, corner); + if (scaling < 0) + return scaling; + + freq_diff_mhz = fuse->max_freq - corner->freq; + do_div(freq_diff_mhz, 1000000); /* now in MHz */ + + corner->quot_adjust = scaling * freq_diff_mhz; + do_div(corner->quot_adjust, 1000); + + /* Fine-tune QUOT (closed-loop) based on fixed values */ + sf_idx = tdesc->ro_scaling_factor_common ? 0 : fnum; + ro_fac = tdesc->ro_scaling_factor[sf_idx][fuse->ring_osc_idx]; + vadj = cdata[i].cloop_vadj; + corner->quot_adjust -= cpr3_adjust_quot(ro_fac, vadj); + dev_vdbg(drv->dev, "Quot fine-tuning to %d for post-vadj=%d\n", + corner->quot_adjust, vadj); + + /* + * Make sure that we scale (up) monotonically. + * P.S.: Fuse quots can never be descending. + */ + prev_quot = prev_corner->fuse_corner->quot; + prev_quot -= prev_corner->quot_adjust; + if (fuse->quot - corner->quot_adjust < prev_quot) { + int new_adj = prev_corner->fuse_corner->quot; + + new_adj -= fuse->quot; + dev_vdbg(drv->dev, "Monotonic increase forced: %d->%d\n", + corner->quot_adjust, new_adj); + corner->quot_adjust = new_adj; + } + + corner->uV = cpr_interpolate(corner, + drv->vreg_step, fdata); + } + /* Negative fuse quotients are nonsense. */ + if (fuse->quot < corner->quot_adjust) + return -EINVAL; + + min_quotient = min(min_quotient, + (u32)(fuse->quot - corner->quot_adjust)); + + /* Fine-tune voltages (open-loop) based on fixed values */ + corner->uV += cdata[i].oloop_vadj; + dev_dbg(drv->dev, "Voltage fine-tuning to %d for post-vadj=%d\n", + corner->uV, cdata[i].oloop_vadj); + + corner->max_uV = fuse->max_uV; + corner->min_uV = fuse->min_uV; + corner->uV = clamp(corner->uV, corner->min_uV, corner->max_uV); + dev_vdbg(drv->dev, "Clamped after interpolation: [%d %d %d]\n", + corner->min_uV, corner->uV, corner->max_uV); + + /* Make sure that we scale monotonically here, too. */ + if (corner->uV < prev_corner->uV) + corner->uV = prev_corner->uV; + + corner->last_uV = corner->uV; + + /* Reduce the ceiling voltage if needed */ + if (desc->reduce_to_corner_uV && corner->uV < corner->max_uV) + corner->max_uV = corner->uV; + else if (desc->reduce_to_fuse_uV && fuse->uV < corner->max_uV) + corner->max_uV = max(corner->min_uV, fuse->uV); + + corner->min_uV = max(corner->max_uV - fdata->range_uV, + corner->min_uV); + + /* + * Adjust per-corner floor and ceiling voltages so that + * they do not overlap the memory Array Power Mux (APM) + * nor the Memory Accelerator (MEM-ACC) threshold voltages. + */ + if (desc->apm_threshold) + cpr3_restrict_corner(corner, desc->apm_threshold, + desc->apm_hysteresis, + drv->vreg_step); + if (desc->mem_acc_threshold) + cpr3_restrict_corner(corner, desc->mem_acc_threshold, + 0, drv->vreg_step); + + prev_corner = corner; + dev_dbg(drv->dev, "corner %d: [%d %d %d] scaling %d quot %d\n", i, + corner->min_uV, corner->uV, corner->max_uV, scaling, + fuse->quot - corner->quot_adjust); + } + + /* Additional setup for CPRh only */ + if (desc->cpr_type < CTRL_TYPE_CPRH) + return 0; + + /* If the OPPs can't be adjusted, programming the CPRh is useless */ + ret = cprh_corner_adjust_opps(thread); + if (ret) { + dev_err(drv->dev, "Cannot adjust CPU OPP voltages: %d\n", ret); + return ret; + } + + total_corners = thread->num_corners; + extra_corners = drv->extra_corners; + + /* If the APM extra corner exists, add it now. */ + if (desc->apm_crossover && desc->apm_threshold && extra_corners) { + /* Program the APM crossover corner on the CPR-Hardened */ + thread->corners[total_corners].uV = desc->apm_crossover; + thread->corners[total_corners].min_uV = desc->apm_crossover; + thread->corners[total_corners].max_uV = desc->apm_crossover; + thread->corners[total_corners].is_open_loop = true; + + /* + * We have calculated the APM parameters for this clock plan: + * make the APM *threshold* available to external callers. + * The crossover is used only internally in the CPR. + */ + thread->ext_data.apm_threshold_uV = desc->apm_threshold; + + dev_dbg(drv->dev, "corner %d (APM): [%d %d %d] Open-Loop\n", + total_corners, desc->apm_crossover, + desc->apm_crossover, desc->apm_crossover); + + total_corners++; + extra_corners--; + } + + if (desc->mem_acc_threshold && extra_corners) { + /* Program the Memory Accelerator threshold corner to CPRh */ + thread->corners[total_corners].uV = desc->mem_acc_threshold; + thread->corners[total_corners].min_uV = desc->mem_acc_threshold; + thread->corners[total_corners].max_uV = desc->mem_acc_threshold; + thread->corners[total_corners].is_open_loop = true; + + /* + * We have calculated a mem-acc threshold for this clock plan: + * make it available to external callers. + */ + thread->ext_data.mem_acc_threshold_uV = desc->mem_acc_threshold; + + dev_dbg(drv->dev, "corner %d (MEMACC): [%d %d %d] Open-Loop\n", + total_corners, desc->mem_acc_threshold, + desc->mem_acc_threshold, desc->mem_acc_threshold); + + total_corners++; + extra_corners--; + } + + /* + * If there are any extra corners left, it means that even though we + * expect to fill in both APM and MEM-ACC crossovers, one couldn't + * satisfy requirements, which means that the specified parameters + * are wrong: in this case, inform the user and bail out, otherwise + * if we go on writing the (invalid) table to the CPR-Hardened, the + * hardware (in this case, the CPU) will surely freeze and crash. + */ + if (unlikely(extra_corners)) { + dev_err(drv->dev, "APM/MEM-ACC corners: bad parameters.\n"); + return -EINVAL; + } + /* Reassign extra_corners, as we have to exclude delta_quot for them */ + extra_corners = drv->extra_corners; + + /* Disable the interface between OSM and CPRh */ + cpr_masked_write(thread, drv->reg_ctl, + CPRH_CTL_OSM_ENABLED, 0); + + /* Program the GCNT before unmasking ring oscillator(s) */ + for (i = 0; i < CPR3_RO_COUNT; i++) { + if (!(ring_osc_mask & BIT(i))) { + cpr_write(thread, CPR3_REG_GCNT(i), drv->gcnt); + dev_vdbg(drv->dev, "RO%d gcnt=%d\n", i, drv->gcnt); + } + } + + /* + * Unmask the ring oscillator(s) that we're going to use: it seems + * to be mandatory to do this *before* sending the rest of the + * CPRhardened specific configuration. + */ + dev_dbg(drv->dev, "Unmasking ring oscillators with mask 0x%x\n", ring_osc_mask); + cpr_write(thread, CPR3_REG_RO_MASK(tdesc->hw_tid), ring_osc_mask); + + /* Setup minimum quotients for ring oscillators */ + for (i = 0; i < CPR3_RO_COUNT; i++) { + u32 tgt_quot_reg = CPR3_REG_TARGET_QUOT(tdesc->hw_tid, i); + u32 tgt_quot_val = 0; + + if (!(ring_osc_mask & BIT(i))) + tgt_quot_val = min_quotient; + + cpr_write(thread, tgt_quot_reg, tgt_quot_val); + dev_vdbg(drv->dev, "Programmed min quotient %u for Ring Oscillator %d\n", + tgt_quot_val, tgt_quot_reg); + } + + for (i = 0; i < total_corners; i++) { + int volt_oloop_steps, volt_floor_steps, delta_quot_steps; + int ring_osc; + u32 val; + + fnum = cdata[i].fuse_corner; + fuse = &thread->fuse_corners[fnum]; + + val = thread->corners[i].uV - desc->cpr_base_voltage; + volt_oloop_steps = DIV_ROUND_UP(val, drv->vreg_step); + + val = thread->corners[i].min_uV - desc->cpr_base_voltage; + volt_floor_steps = DIV_ROUND_UP(val, drv->vreg_step); + + /* + * If we are accessing corners that are not used as + * an active DCVS set-point, then always select RO 0 + * and zero out the delta quotient. + */ + if (i >= thread->num_corners) { + ring_osc = 0; + delta_quot_steps = 0; + } else { + ring_osc = fuse->ring_osc_idx; + val = fuse->quot - thread->corners[i].quot_adjust; + val -= min_quotient; + delta_quot_steps = DIV_ROUND_UP(val, + CPRH_DELTA_QUOT_STEP_FACTOR); + } + + if (volt_oloop_steps > CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE || + volt_floor_steps > CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE || + delta_quot_steps > CPRH_CORNER_QUOT_DELTA_MAX_VALUE) { + dev_err(drv->dev, "Invalid cfg: oloop=%d, floor=%d, delta=%d\n", + volt_oloop_steps, volt_floor_steps, + delta_quot_steps); + return -EINVAL; + } + /* Green light: Go, Go, Go! */ + + /* Set number of open-loop steps */ + val = FIELD_PREP(CPRH_CORNER_INIT_VOLTAGE_MASK, volt_oloop_steps); + + /* Set number of floor voltage steps */ + val |= FIELD_PREP(CPRH_CORNER_FLOOR_VOLTAGE_MASK, volt_floor_steps); + + /* Set number of target quotient delta steps */ + val |= FIELD_PREP(CPRH_CORNER_QUOT_DELTA_MASK, delta_quot_steps); + + /* Select ring oscillator for this corner */ + val |= FIELD_PREP(CPRH_CORNER_RO_SEL_MASK, ring_osc); + + /* Open loop corner is usually APM/ACC crossover */ + if (thread->corners[i].is_open_loop) { + dev_dbg(drv->dev, "Disabling Closed-Loop on corner %d\n", i); + val |= CPRH_CORNER_CPR_CL_DISABLE; + } + cpr_write(thread, CPRH_REG_CORNER(drv, tdesc->hw_tid, i), val); + + dev_dbg(drv->dev, "steps [%d]: open-loop %d, floor %d, delta_quot %d\n", + i, volt_oloop_steps, volt_floor_steps, + delta_quot_steps); + } + + /* YAY! Setup is done! Enable the internal loop to start CPR. */ + cpr_masked_write(thread, CPR3_REG_CPR_CTL, + CPR3_CPR_CTL_LOOP_EN_MASK, + CPR3_CPR_CTL_LOOP_EN_MASK); + + /* + * All the writes are going through before enabling internal + * communication between the OSM and the CPRh controllers + * because we are never using relaxed accessors, but should + * we use them, it would be critical to issue a barrier here, + * otherwise there is a high risk of hardware lockups due to + * under-voltage for the selected CPU clock. + * + * Please note that the CPR-hardened gets set-up in Linux but + * then gets actually used in firmware (and only by the OSM); + * after handing it off we will have no more control on it. + */ + + /* Enable the interface between OSM and CPRh */ + cpr_masked_write(thread, drv->reg_ctl, + CPRH_CTL_OSM_ENABLED, + CPRH_CTL_OSM_ENABLED); + + /* On success, free cdata manually */ + devm_kfree(drv->dev, cdata); + return 0; +} + +/** + * cpr3_init_parameters() - Initialize CPR global parameters + * @drv: Main driver structure + * + * Initial "integrity" checks and setup for the thread-independent parameters. + * + * Return: Zero for success, negative number on error + */ +static int cpr3_init_parameters(struct cpr_drv *drv) +{ + const struct cpr_desc *desc = drv->desc; + struct clk *clk; + + clk = devm_clk_get(drv->dev, NULL); + if (IS_ERR(clk)) { + dev_err(drv->dev, "Couldn't get the reference clock: %ld\n", PTR_ERR(clk)); + return PTR_ERR(clk); + } + + drv->ref_clk_khz = clk_get_rate(clk); + do_div(drv->ref_clk_khz, 1000); + + /* On CPRh this clock is not always-on... */ + if (desc->cpr_type == CTRL_TYPE_CPRH) + clk_prepare_enable(clk); + else + devm_clk_put(drv->dev, clk); + + if (desc->timer_cons_up > CPR3_THRESH_CONS_UP_MASK || + desc->timer_cons_down > CPR3_THRESH_CONS_DOWN_MASK || + desc->up_threshold > CPR3_THRESH_UP_THRESH_MASK || + desc->down_threshold > CPR3_THRESH_DOWN_THRESH_MASK || + desc->idle_clocks > CPR3_CPR_CTL_IDLE_CLOCKS_MASK || + desc->count_mode > CPR3_CPR_CTL_COUNT_MODE_MASK || + desc->count_repeat > CPR3_CPR_CTL_COUNT_REPEAT_MASK) + return -EINVAL; + + /* + * Read the CPR version register only from CPR3 onwards: + * this is needed to get the additional register offsets. + * + * Note: When threaded, even if multi-controller, there + * is no chance to have different versions at the + * same time in the same domain, so it is safe to + * check this only on the first controller/thread. + */ + drv->cpr_hw_rev = cpr_read(&drv->threads[0], + CPR3_REG_CPR_VERSION); + dev_dbg(drv->dev, "CPR hardware revision: 0x%x\n", drv->cpr_hw_rev); + + if (drv->cpr_hw_rev >= CPRH_CPR_VERSION_4P5) { + drv->reg_corner = 0x3500; + drv->reg_corner_tid = 0xa0; + drv->reg_ctl = 0x3a80; + drv->reg_status = 0x3a84; + } else { + drv->reg_corner = 0x3a00; + drv->reg_corner_tid = 0; + drv->reg_ctl = 0x3aa0; + drv->reg_status = 0x3aa4; + } + + dev_dbg(drv->dev, "up threshold = %u, down threshold = %u\n", + desc->up_threshold, desc->down_threshold); + + return 0; +} + +/** + * cpr3_find_initial_corner() - Finds boot-up p-state and enables CPR + * @thread: Structure holding CPR thread-specific parameters + * + * Differently from CPRv1, from CPRv3 onwards when we successfully find + * the target boot-up performance state, we must refresh the HW + * immediately to guarantee system stability and to avoid overheating + * during the boot process, thing that would more likely happen without + * this driver doing its job. + * + * Return: Zero for success, negative number on error + */ +static int cpr3_find_initial_corner(struct cpr_thread *thread) +{ + struct cpr_drv *drv = thread->drv; + struct corner *corner; + int uV, idx; + + idx = cpr_find_initial_corner(drv->dev, thread->cpu_clk, + thread->corners, + thread->num_corners); + if (idx < 0) + return idx; + + cpr_ctl_disable(thread); + + corner = &thread->corners[idx]; + cpr_corner_restore(thread, corner); + + uV = regulator_get_voltage(drv->vreg); + uV = clamp(uV, corner->min_uV, corner->max_uV); + + corner->last_uV = uV; + if (!drv->last_uV) + drv->last_uV = uV; + + cpr_commit_state(thread); + thread->enabled = true; + cpr_switch(drv); + + return 0; +} + +static const int msm8998_gold_scaling_factor[][CPR3_RO_COUNT] = { + /* Fuse Corner 0 */ + { + 2857, 3057, 2828, 2952, 2699, 2798, 2446, 2631, + 2629, 2578, 2244, 3344, 3289, 3137, 3164, 2655 + }, + /* Fuse Corner 1 */ + { + 2857, 3057, 2828, 2952, 2699, 2798, 2446, 2631, + 2629, 2578, 2244, 3344, 3289, 3137, 3164, 2655 + }, + /* Fuse Corner 2 */ + { + 2603, 2755, 2676, 2777, 2573, 2685, 2465, 2610, + 2312, 2423, 2243, 3104, 3022, 3036, 2740, 2303 + }, + /* Fuse Corner 3 */ + { + 1901, 2016, 2096, 2228, 2034, 2161, 2077, 2188, + 1565, 1870, 1925, 2235, 2205, 2413, 1762, 1478 + } +}; + +static const int msm8998_silver_scaling_factor[][CPR3_RO_COUNT] = { + /* Fuse Corner 0 */ + { + 2595, 2794, 2577, 2762, 2471, 2674, 2199, 2553, + 3189, 3255, 3192, 2962, 3054, 2982, 2042, 2945 + }, + /* Fuse Corner 1 */ + { + 2595, 2794, 2577, 2762, 2471, 2674, 2199, 2553, + 3189, 3255, 3192, 2962, 3054, 2982, 2042, 2945 + }, + /* Fuse Corner 2 */ + { + 2391, 2550, 2483, 2638, 2382, 2564, 2259, 2555, + 2766, 3041, 2988, 2935, 2873, 2688, 2013, 2784 + }, + /* Fuse Corner 3 */ + { + 2066, 2153, 2300, 2434, 2220, 2386, 2288, 2465, + 2028, 2511, 2487, 2734, 2554, 2117, 1892, 2377 + } +}; + +static const struct cpr_thread_desc msm8998_thread_gold = { + .controller_id = 1, + .hw_tid = 0, + .ro_scaling_factor = msm8998_gold_scaling_factor, + .sensor_range_start = 0, + .sensor_range_end = 9, + .init_voltage_step = 10000, + .init_voltage_width = 6, + .step_quot_init_min = 9, + .step_quot_init_max = 14, + .num_fuse_corners = 4, + .fuse_corner_data = (struct fuse_corner_data[]){ + /* fuse corner 0 */ + { + .ref_uV = 756000, + .max_uV = 828000, + .min_uV = 568000, + .range_uV = 32000, + .volt_cloop_adjust = 0, + .volt_oloop_adjust = 8000, + .max_volt_scale = 4, + .max_quot_scale = 10, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 1 */ + { + .ref_uV = 756000, + .max_uV = 900000, + .min_uV = 624000, + .range_uV = 32000, + .volt_cloop_adjust = 0, + .volt_oloop_adjust = 0, + .max_volt_scale = 320, + .max_quot_scale = 350, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 2 */ + { + .ref_uV = 828000, + .max_uV = 952000, + .min_uV = 632000, + .range_uV = 32000, + .volt_cloop_adjust = 12000, + .volt_oloop_adjust = 12000, + .max_volt_scale = 620, + .max_quot_scale = 750, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 3 */ + { + .ref_uV = 1056000, + .max_uV = 1136000, + .min_uV = 772000, + .range_uV = 40000, + .volt_cloop_adjust = 50000, + .volt_oloop_adjust = 52000, + .max_volt_scale = 580, + .max_quot_scale = 1040, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + }, +}; + +static const struct cpr_thread_desc msm8998_thread_silver = { + .controller_id = 0, + .hw_tid = 0, + .ro_scaling_factor = msm8998_silver_scaling_factor, + .sensor_range_start = 0, + .sensor_range_end = 6, + .init_voltage_step = 10000, + .init_voltage_width = 6, + .step_quot_init_min = 11, + .step_quot_init_max = 12, + .num_fuse_corners = 4, + .fuse_corner_data = (struct fuse_corner_data[]){ + /* fuse corner 0 */ + { + .ref_uV = 688000, + .max_uV = 828000, + .min_uV = 568000, + .range_uV = 32000, + .volt_cloop_adjust = 20000, + .volt_oloop_adjust = 40000, + .max_volt_scale = 4, + .max_quot_scale = 10, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 1 */ + { + .ref_uV = 756000, + .max_uV = 900000, + .min_uV = 632000, + .range_uV = 32000, + .volt_cloop_adjust = 26000, + .volt_oloop_adjust = 24000, + .max_volt_scale = 500, + .max_quot_scale = 800, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 2 */ + { + .ref_uV = 828000, + .max_uV = 952000, + .min_uV = 664000, + .range_uV = 32000, + .volt_cloop_adjust = 12000, + .volt_oloop_adjust = 12000, + .max_volt_scale = 280, + .max_quot_scale = 650, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + + }, + /* fuse corner 3 */ + { + .ref_uV = 1056000, + .max_uV = 1056000, + .min_uV = 772000, + .range_uV = 40000, + .volt_cloop_adjust = 30000, + .volt_oloop_adjust = 30000, + .max_volt_scale = 430, + .max_quot_scale = 800, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + }, +}; + +static const struct cpr_desc msm8998_cpr_desc = { + .cpr_type = CTRL_TYPE_CPRH, + .num_threads = 2, + .mem_acc_threshold = 852000, + .apm_threshold = 800000, + .apm_crossover = 880000, + .apm_hysteresis = 0, + .cpr_base_voltage = 352000, + .cpr_max_voltage = 1200000, + .timer_delay_us = 5000, + .timer_cons_up = 0, + .timer_cons_down = 2, + .up_threshold = 2, + .down_threshold = 2, + .idle_clocks = 15, + .count_mode = CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN, + .count_repeat = 14, + .gcnt_us = 1, + .vreg_step_fixed = 4000, + .vreg_step_up_limit = 1, + .vreg_step_down_limit = 1, + .vdd_settle_time_us = 34, + .corner_settle_time_us = 6, + .reduce_to_corner_uV = true, + .hw_closed_loop_en = true, + .threads = (const struct cpr_thread_desc *[]) { + &msm8998_thread_silver, + &msm8998_thread_gold, + }, +}; + +static const struct cpr_acc_desc msm8998_cpr_acc_desc = { + .cpr_desc = &msm8998_cpr_desc, +}; + +static const int sdm630_gold_scaling_factor[][CPR3_RO_COUNT] = { + /* Same RO factors for all fuse corners */ + { + 4040, 3230, 0, 2210, 2560, 2450, 2230, 2220, + 2410, 2300, 2560, 2470, 1600, 3120, 2620, 2280 + } +}; + +static const int sdm630_silver_scaling_factor[][CPR3_RO_COUNT] = { + /* Same RO factors for all fuse corners */ + { + 3600, 3600, 3830, 2430, 2520, 2700, 1790, 1760, + 1970, 1880, 2110, 2010, 2510, 4900, 4370, 4780, + } +}; + +static const struct cpr_thread_desc sdm630_thread_gold = { + .controller_id = 0, + .hw_tid = 0, + .ro_scaling_factor = sdm630_gold_scaling_factor, + .ro_scaling_factor_common = true, + .sensor_range_start = 0, + .sensor_range_end = 6, + .init_voltage_step = 10000, + .init_voltage_width = 6, + .step_quot_init_min = 12, + .step_quot_init_max = 14, + .num_fuse_corners = 5, + .fuse_corner_data = (struct fuse_corner_data[]){ + /* fuse corner 0 */ + { + .ref_uV = 644000, + .max_uV = 724000, + .min_uV = 588000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 15000, + .max_volt_scale = 10, + .max_quot_scale = 300, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 1 */ + { + .ref_uV = 788000, + .max_uV = 788000, + .min_uV = 652000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 5000, + .max_volt_scale = 320, + .max_quot_scale = 275, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 2 */ + { + .ref_uV = 868000, + .max_uV = 868000, + .min_uV = 712000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 5000, + .max_volt_scale = 350, + .max_quot_scale = 800, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 3 */ + { + .ref_uV = 988000, + .max_uV = 988000, + .min_uV = 784000, + .range_uV = 66000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 0, + .max_volt_scale = 868, + .max_quot_scale = 980, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 4 */ + { + .ref_uV = 1068000, + .max_uV = 1068000, + .min_uV = 844000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 0, + .max_volt_scale = 868, + .max_quot_scale = 980, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + }, +}; + +static const struct cpr_thread_desc sdm630_thread_silver = { + .controller_id = 1, + .hw_tid = 0, + .ro_scaling_factor = sdm630_silver_scaling_factor, + .ro_scaling_factor_common = true, + .sensor_range_start = 0, + .sensor_range_end = 6, + .init_voltage_step = 10000, + .init_voltage_width = 6, + .step_quot_init_min = 12, + .step_quot_init_max = 14, + .num_fuse_corners = 3, + .fuse_corner_data = (struct fuse_corner_data[]){ + /* fuse corner 0 */ + { + .ref_uV = 644000, + .max_uV = 724000, + .min_uV = 588000, + .range_uV = 32000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 0, + .max_volt_scale = 10, + .max_quot_scale = 360, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 1 */ + { + .ref_uV = 788000, + .max_uV = 788000, + .min_uV = 652000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 0, + .max_volt_scale = 500, + .max_quot_scale = 550, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + /* fuse corner 2 */ + { + .ref_uV = 1068000, + .max_uV = 1068000, + .min_uV = 800000, + .range_uV = 40000, + .volt_cloop_adjust = -30000, + .volt_oloop_adjust = 0, + .max_volt_scale = 2370, + .max_quot_scale = 550, + .quot_offset = 0, + .quot_scale = 1, + .quot_adjust = 0, + .quot_offset_scale = 5, + .quot_offset_adjust = 0, + }, + }, +}; + +static const struct cpr_desc sdm630_cpr_desc = { + .cpr_type = CTRL_TYPE_CPRH, + .num_threads = 2, + .apm_threshold = 872000, + .apm_crossover = 872000, + .apm_hysteresis = 20000, + .cpr_base_voltage = 400000, + .cpr_max_voltage = 1300000, + .timer_delay_us = 5000, + .timer_cons_up = 0, + .timer_cons_down = 2, + .up_threshold = 2, + .down_threshold = 2, + .idle_clocks = 15, + .count_mode = CPR3_CPR_CTL_COUNT_MODE_ALL_AT_ONCE_MIN, + .count_repeat = 14, + .gcnt_us = 1, + .vreg_step_fixed = 4000, + .vreg_step_up_limit = 1, + .vreg_step_down_limit = 1, + .vdd_settle_time_us = 34, + .corner_settle_time_us = 5, + .reduce_to_corner_uV = true, + .hw_closed_loop_en = true, + .threads = (const struct cpr_thread_desc *[]) { + &sdm630_thread_gold, + &sdm630_thread_silver, + }, +}; + +static const struct cpr_acc_desc sdm630_cpr_acc_desc = { + .cpr_desc = &sdm630_cpr_desc, +}; + +static unsigned int cpr_get_performance_state(struct generic_pm_domain *genpd, + struct dev_pm_opp *opp) +{ + return dev_pm_opp_get_level(opp); +} + +static int cpr_power_off(struct generic_pm_domain *domain) +{ + struct cpr_thread *thread = container_of(domain, struct cpr_thread, pd); + + return cpr_disable(thread); +} + +static int cpr_power_on(struct generic_pm_domain *domain) +{ + struct cpr_thread *thread = container_of(domain, struct cpr_thread, pd); + + return cpr_enable(thread); +} + +static void cpr_pd_detach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct cpr_thread *thread = container_of(domain, struct cpr_thread, pd); + struct cpr_drv *drv = thread->drv; + + mutex_lock(&drv->lock); + + dev_dbg(drv->dev, "detach callback for: %s\n", dev_name(dev)); + thread->attached_cpu_dev = NULL; + + mutex_unlock(&drv->lock); +} + +static int cpr_pd_attach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct cpr_thread *thread = container_of(domain, struct cpr_thread, pd); + struct cpr_drv *drv = thread->drv; + const struct acc_desc *acc_desc = drv->acc_desc; + bool cprh_opp_remove_table = false; + int ret = 0; + + mutex_lock(&drv->lock); + + dev_dbg(drv->dev, "attach callback for: %s\n", dev_name(dev)); + + /* + * This driver only supports scaling voltage for a CPU cluster + * where all CPUs in the cluster share a single regulator. + * Therefore, save the struct device pointer only for the first + * CPU device that gets attached. There is no need to do any + * additional initialization when further CPUs get attached. + * This is not an error condition. + */ + if (thread->attached_cpu_dev) + goto unlock; + + /* + * cpr_scale_voltage() requires the direction (if we are changing + * to a higher or lower OPP). The first time + * cpr_set_performance_state() is called, there is no previous + * performance state defined. Therefore, we call + * cpr_find_initial_corner() that gets the CPU clock frequency + * set by the bootloader, so that we can determine the direction + * the first time cpr_set_performance_state() is called. + */ + thread->cpu_clk = devm_clk_get(dev, NULL); + if (drv->desc->cpr_type < CTRL_TYPE_CPRH && IS_ERR(thread->cpu_clk)) { + ret = PTR_ERR(thread->cpu_clk); + if (ret != -EPROBE_DEFER) + dev_err(drv->dev, "could not get cpu clk: %d\n", ret); + goto unlock; + } + thread->attached_cpu_dev = dev; + + /* + * We are exporting the APM and MEM-ACC thresholds to the caller; + * while APM is necessary in the CPU CPR case, MEM-ACC may not be, + * depending on the SoC and on fuses. + * Initialize both to an invalid value, so that the caller can check + * if they got calculated or read from fuses in this driver. + */ + thread->ext_data.apm_threshold_uV = -1; + thread->ext_data.mem_acc_threshold_uV = -1; + dev_set_drvdata(thread->attached_cpu_dev, &thread->ext_data); + + dev_dbg(drv->dev, "using cpu clk from: %s\n", + dev_name(thread->attached_cpu_dev)); + + /* + * Everything related to (virtual) corners has to be initialized + * here, when attaching to the power domain, since we need to know + * the maximum frequency for each fuse corner, and this is only + * available after the cpufreq driver has attached to us. + * The reason for this is that we need to know the highest + * frequency associated with each fuse corner. + */ + ret = dev_pm_opp_get_opp_count(&thread->pd.dev); + if (ret < 0) { + dev_err(drv->dev, "could not get OPP count\n"); + thread->attached_cpu_dev = NULL; + goto unlock; + } + thread->num_corners = ret; + + thread->corners = devm_kcalloc(drv->dev, + thread->num_corners + + drv->extra_corners, + sizeof(*thread->corners), + GFP_KERNEL); + if (!thread->corners) { + ret = -ENOMEM; + goto unlock; + } + + /* + * If we are on CPR-Hardened we have to make sure that the attached + * device has a OPP table installed, as we're going to modify it here + * with our calculations based on qfprom values. + */ + if (drv->desc->cpr_type == CTRL_TYPE_CPRH) { + ret = dev_pm_opp_of_add_table(dev); + if (ret && ret != -EEXIST) { + dev_err(drv->dev, "Cannot add table: %d\n", ret); + goto unlock; + } + cprh_opp_remove_table = true; + } + + ret = cpr3_corner_init(thread); + if (ret) + goto exit; + + if (drv->desc->cpr_type < CTRL_TYPE_CPRH) { + ret = cpr3_find_initial_corner(thread); + if (ret) + goto exit; + + if (acc_desc->config) + regmap_multi_reg_write(drv->tcsr, acc_desc->config, + acc_desc->num_regs_per_fuse); + + /* Enable ACC if required */ + if (acc_desc->enable_mask) + regmap_update_bits(drv->tcsr, acc_desc->enable_reg, + acc_desc->enable_mask, + acc_desc->enable_mask); + } + dev_info(drv->dev, "thread %d initialized with %u OPPs\n", + thread->id, thread->num_corners); +exit: + /* + * If we are on CPRh and we reached an error condition, we installed + * the OPP table but we haven't done any setup on it, nor we ever will. + * In order to leave a clean state, remove the table. + */ + if (ret && cprh_opp_remove_table) + dev_pm_opp_of_remove_table(thread->attached_cpu_dev); +unlock: + mutex_unlock(&drv->lock); + + return ret; +} + +static int cpr3_debug_info_show(struct seq_file *s, void *unused) +{ + struct cpr_thread *thread = s->private; + struct fuse_corner *fuse = thread->fuse_corners; + struct corner *corner = thread->corners; + u32 tid = thread->desc->hw_tid; + u32 ctl, irq_status, reg; + unsigned int i; + + if (thread->drv->desc->cpr_type < CTRL_TYPE_CPRH) { + seq_printf(s, "current_volt = %d uV\n", thread->drv->last_uV); + seq_printf(s, "requested voltage: %d uV\n", thread->corner->last_uV); + } + + irq_status = cpr_read(thread, CPR3_REG_IRQ_STATUS); + seq_printf(s, "irq_status = 0x%x\n", irq_status); + + ctl = cpr_read(thread, CPR3_REG_CPR_CTL); + seq_printf(s, "cpr_ctl = 0x%x\n", ctl); + + seq_printf(s, "thread %d - hw tid: %u - enabled: %d:\n", + thread->id, thread->desc->hw_tid, thread->enabled); + seq_printf(s, "%d corners, derived from %d fuse corners\n", + thread->num_corners, thread->desc->num_fuse_corners); + + + /* The corners have not been initialized yet. */ + if (!thread->num_corners) + return 0; + + for (i = 0; i < thread->num_corners; i++, corner++) + seq_printf(s, "corner %d - uV=[%d %d %d] quot=%d freq=%llu\n", + i, corner->min_uV, corner->uV, corner->max_uV, + corner->quot_adjust, corner->freq); + + for (i = 0; i < thread->desc->num_fuse_corners; i++, fuse++) + seq_printf(s, "fuse %d - uV=[%d %d %d] quot=%d freq=%llu\n", + i, fuse->min_uV, fuse->uV, fuse->max_uV, + fuse->quot, corner->freq); + + reg = cpr_read(thread, CPR3_REG_RESULT0(tid)); + seq_printf(s, "cpr_result_0 = 0x%x\n [", reg); + seq_printf(s, "busy = %lu, ", FIELD_GET(CPR3_RESULT0_BUSY_MASK, reg)); + seq_printf(s, "step_dn = %lu, ", FIELD_GET(CPR3_RESULT0_STEP_DN_MASK, reg)); + seq_printf(s, "step_up = %lu, ", FIELD_GET(CPR3_RESULT0_STEP_UP_MASK, reg)); + seq_printf(s, "error_steps = %lu, ", FIELD_GET(CPR3_RESULT0_ERROR_STEPS_MASK, reg)); + seq_printf(s, "error = %lu, ", FIELD_GET(CPR3_RESULT0_ERROR_MASK, reg)); + seq_printf(s, "negative = %lu", FIELD_GET(CPR3_RESULT0_NEG_MASK, reg)); + seq_puts(s, "]\n"); + + reg = cpr_read(thread, CPR3_REG_RESULT1(tid)); + seq_printf(s, "cpr_result_1 = 0x%x\n [", reg); + seq_printf(s, "quot_min = %lu, ", FIELD_GET(CPR3_RESULT1_QUOT_MIN_MASK, reg)); + seq_printf(s, "quot_max = %lu, ", FIELD_GET(CPR3_RESULT1_QUOT_MAX_MASK, reg)); + seq_printf(s, "ro_min = %lu, ", FIELD_GET(CPR3_RESULT1_RO_MIN_MASK, reg)); + seq_printf(s, "ro_max = %lu", FIELD_GET(CPR3_RESULT1_RO_MAX_MASK, reg)); + seq_puts(s, "]\n"); + + reg = cpr_read(thread, CPR3_REG_RESULT2(tid)); + seq_printf(s, "cpr_result_2 = 0x%x\n [", reg); + seq_printf(s, "qout_step_min = %lu, ", FIELD_GET(CPR3_RESULT2_STEP_QUOT_MIN_MASK, reg)); + seq_printf(s, "qout_step_max = %lu, ", FIELD_GET(CPR3_RESULT2_STEP_QUOT_MAX_MASK, reg)); + seq_printf(s, "sensor_min = %lu, ", FIELD_GET(CPR3_RESULT2_SENSOR_MIN_MASK, reg)); + seq_printf(s, "sensor_max = %lu", FIELD_GET(CPR3_RESULT2_SENSOR_MAX_MASK, reg)); + seq_puts(s, "]\n"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(cpr3_debug_info); + +static void cpr3_debugfs_init(struct cpr_drv *drv) +{ + int i; + + drv->debugfs = debugfs_create_dir("qcom_cpr3", NULL); + + for (i = 0; i < drv->desc->num_threads; i++) { + char buf[50]; + + snprintf(buf, sizeof(buf), "thread%d", i); + + debugfs_create_file(buf, 0444, drv->debugfs, &drv->threads[i], + &cpr3_debug_info_fops); + } +} + +/** + * cpr_thread_init() - Initialize CPR thread related parameters + * @drv: Main driver structure + * @tid: Thread ID + * + * Return: Zero for success, negative number on error + */ +static int cpr_thread_init(struct cpr_drv *drv, int tid) +{ + const struct cpr_desc *desc = drv->desc; + const struct cpr_thread_desc *tdesc = desc->threads[tid]; + struct cpr_thread *thread = &drv->threads[tid]; + bool pd_registered = false; + int ret, i; + + if (tdesc->step_quot_init_min > CPR3_CPR_STEP_QUOT_MIN_MASK || + tdesc->step_quot_init_max > CPR3_CPR_STEP_QUOT_MAX_MASK) + return -EINVAL; + + thread->id = tid; + thread->drv = drv; + thread->desc = tdesc; + thread->fuse_corners = devm_kcalloc(drv->dev, + tdesc->num_fuse_corners + + drv->extra_corners, + sizeof(*thread->fuse_corners), + GFP_KERNEL); + if (!thread->fuse_corners) + return -ENOMEM; + + thread->cpr_fuses = cpr_get_fuses(drv->dev, tid, + tdesc->num_fuse_corners); + if (IS_ERR(thread->cpr_fuses)) + return PTR_ERR(thread->cpr_fuses); + + ret = cpr_populate_ring_osc_idx(thread->drv->dev, thread->fuse_corners, + thread->cpr_fuses, + tdesc->num_fuse_corners); + if (ret) + return ret; + + ret = cpr_fuse_corner_init(thread); + if (ret) + return ret; + + thread->pd.name = devm_kasprintf(drv->dev, GFP_KERNEL, + "%s_thread%d", + drv->dev->of_node->full_name, + thread->id); + if (!thread->pd.name) + return -EINVAL; + + thread->pd.power_off = cpr_power_off; + thread->pd.power_on = cpr_power_on; + thread->pd.opp_to_performance_state = cpr_get_performance_state; + thread->pd.attach_dev = cpr_pd_attach_dev; + thread->pd.detach_dev = cpr_pd_detach_dev; + + /* CPR-Hardened performance states are managed in firmware */ + if (desc->cpr_type == CTRL_TYPE_CPRH) + thread->pd.set_performance_state = cprh_dummy_set_performance_state; + else + thread->pd.set_performance_state = cpr_set_performance_state; + + /* Anything later than CPR1 must be always-on for now */ + thread->pd.flags = GENPD_FLAG_ALWAYS_ON; + + drv->cell_data.domains[tid] = &thread->pd; + + ret = pm_genpd_init(&thread->pd, NULL, false); + if (ret < 0) + goto fail; + else + pd_registered = true; + + /* On CPRhardened, the interrupts are managed in firmware */ + if (desc->cpr_type < CTRL_TYPE_CPRH) { + INIT_WORK(&thread->restart_work, cpr_restart_worker); + + ret = devm_request_threaded_irq(drv->dev, drv->irq, + NULL, cpr_irq_handler, + IRQF_ONESHOT | + IRQF_TRIGGER_RISING, + "cpr", drv); + if (ret) + goto fail; + } + + return 0; + +fail: + /* Unregister all previously registered genpds */ + for (i = tid - pd_registered; i >= 0; i--) + pm_genpd_remove(&drv->threads[i].pd); + + return ret; +} + +/** + * cpr3_resources_init() - Initialize resources used by this driver + * @pdev: Platform device + * @drv: Main driver structure + * + * Return: Zero for success, negative number on error + */ +static int cpr3_resources_init(struct platform_device *pdev, + struct cpr_drv *drv) +{ + const struct cpr_desc *desc = drv->desc; + struct cpr_thread *threads = drv->threads; + unsigned int i; + u8 cid_mask = 0; + + /* + * Here, we are accounting for the following usecases: + * - One controller + * - One or multiple threads on the same iospace + * + * - Multiple controllers + * - Each controller has its own iospace and each + * may have one or multiple threads in their + * parent controller's iospace + * + * Then, to avoid complicating the code for no reason, + * this also needs a mandatory order in the list of + * threads which implies that all of them from the same + * controllers are specified sequentially. As an example: + * + * C0-T0, C0-T1...C0-Tn, C1-T0, C1-T1...C1-Tn + */ + for (i = 0; i < desc->num_threads; i++) { + u8 cid = desc->threads[i]->controller_id; + + if (cid_mask & BIT(cid)) { + if (desc->threads[i - 1]->controller_id != cid) { + dev_err(drv->dev, "Bad threads order. Please fix!\n"); + return -EINVAL; + } + threads[i].base = threads[i - 1].base; + continue; + } + threads[i].base = devm_platform_ioremap_resource(pdev, cid); + if (IS_ERR(threads[i].base)) + return PTR_ERR(threads[i].base); + cid_mask |= BIT(cid); + } + return 0; +} + +static int cpr_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cpr_drv *drv; + const struct cpr_desc *desc; + const struct cpr_acc_desc *data; + struct device_node *np; + unsigned int i; + int ret; + + data = of_device_get_match_data(dev); + if (!data || !data->cpr_desc) + return -EINVAL; + + desc = data->cpr_desc; + + /* CPRh disallows MEM-ACC access from the HLOS */ + if (!data->acc_desc && desc->cpr_type < CTRL_TYPE_CPRH) + return -EINVAL; + + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + + drv->dev = dev; + drv->desc = desc; + drv->threads = devm_kcalloc(dev, desc->num_threads, + sizeof(*drv->threads), GFP_KERNEL); + if (!drv->threads) + return -ENOMEM; + + drv->cell_data.num_domains = desc->num_threads; + drv->cell_data.domains = devm_kcalloc(drv->dev, + drv->cell_data.num_domains, + sizeof(*drv->cell_data.domains), + GFP_KERNEL); + if (!drv->cell_data.domains) + return -ENOMEM; + + if (data->acc_desc) + drv->acc_desc = data->acc_desc; + + mutex_init(&drv->lock); + + if (desc->cpr_type < CTRL_TYPE_CPRH) { + np = of_parse_phandle(dev->of_node, "qcom,acc", 0); + if (!np) + return -ENODEV; + + drv->tcsr = syscon_node_to_regmap(np); + of_node_put(np); + if (IS_ERR(drv->tcsr)) + return PTR_ERR(drv->tcsr); + } + + ret = cpr3_resources_init(pdev, drv); + if (ret) + return ret; + + drv->irq = platform_get_irq_optional(pdev, 0); + if (desc->cpr_type != CTRL_TYPE_CPRH && drv->irq < 0) + return -EINVAL; + + /* On CPRhardened, vreg access it not allowed */ + drv->vreg = devm_regulator_get_optional(dev, "vdd"); + if (desc->cpr_type != CTRL_TYPE_CPRH && IS_ERR(drv->vreg)) + return PTR_ERR(drv->vreg); + + /* + * On at least CPRhardened, vreg is unaccessible and there is no + * way to read linear step from that regulator, hence it is hardcoded + * in the driver; + * When the vreg_step is not declared in the cpr data (or is zero), + * then having access to the vreg regulator is mandatory, as this + * will be retrieved through the regulator API. + */ + if (desc->vreg_step_fixed) + drv->vreg_step = desc->vreg_step_fixed; + else + drv->vreg_step = regulator_get_linear_step(drv->vreg); + + if (!drv->vreg_step) + return -EINVAL; + + /* + * Initialize fuse corners, since it simply depends + * on data in efuses. + * Everything related to (virtual) corners has to be + * initialized after attaching to the power domain, + * since it depends on the CPU's OPP table. + */ + ret = nvmem_cell_read_variable_le_u32(dev, "cpr_fuse_revision", &drv->fusing_rev); + if (ret) + return ret; + + ret = nvmem_cell_read_variable_le_u32(dev, "cpr_speed_bin", &drv->speed_bin); + if (ret) + return ret; + + /* + * Some SoCs require extra corners for MEM-ACC or APM: if + * the related parameters have been specified, then reserve + * a corner for the APM and/or MEM-ACC crossover, used by + * OSM and CPRh HW to set the supply voltage during the APM + * and/or MEM-ACC switch routine. + */ + if (desc->cpr_type == CTRL_TYPE_CPRH) { + if (desc->apm_crossover && desc->apm_hysteresis >= 0) + drv->extra_corners++; + + if (desc->mem_acc_threshold) + drv->extra_corners++; + } + + /* Initialize all threads */ + for (i = 0; i < desc->num_threads; i++) { + ret = cpr_thread_init(drv, i); + if (ret) + return ret; + } + + /* Initialize global parameters */ + ret = cpr3_init_parameters(drv); + if (ret) + goto unreg_genpd; + + /* Write initial configuration on all threads */ + for (i = 0; i < desc->num_threads; i++) { + ret = cpr_configure(&drv->threads[i]); + if (ret) + goto unreg_genpd; + } + + ret = of_genpd_add_provider_onecell(dev->of_node, &drv->cell_data); + if (ret) + goto unreg_genpd; + + platform_set_drvdata(pdev, drv); + cpr3_debugfs_init(drv); + + return 0; + +unreg_genpd: + /* Clean up genpds */ + for (i = desc->num_threads - 1; i >= 0; i--) + pm_genpd_remove(&drv->threads[i].pd); + + return ret; +} + +static int cpr_remove(struct platform_device *pdev) +{ + struct cpr_drv *drv = platform_get_drvdata(pdev); + int i; + + of_genpd_del_provider(pdev->dev.of_node); + + for (i = 0; i < drv->desc->num_threads; i++) { + cpr_ctl_disable(&drv->threads[i]); + cpr_irq_set(&drv->threads[i], 0); + pm_genpd_remove(&drv->threads[i].pd); + } + + debugfs_remove_recursive(drv->debugfs); + + return 0; +} + +static const struct of_device_id cpr3_match_table[] = { + { .compatible = "qcom,msm8998-cprh", .data = &msm8998_cpr_acc_desc }, + { .compatible = "qcom,sdm630-cprh", .data = &sdm630_cpr_acc_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, cpr3_match_table); + +static struct platform_driver cpr3_driver = { + .probe = cpr_probe, + .remove = cpr_remove, + .driver = { + .name = "qcom-cpr3", + .of_match_table = cpr3_match_table, + }, +}; +module_platform_driver(cpr3_driver) + +MODULE_DESCRIPTION("Core Power Reduction (CPR) v3/v4 driver"); +MODULE_LICENSE("GPL"); diff --git a/include/soc/qcom/cpr.h b/include/soc/qcom/cpr.h new file mode 100644 index 000000000000..2ba4324d18f6 --- /dev/null +++ b/include/soc/qcom/cpr.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019 Linaro Limited + * Copyright (c) 2021, AngeloGioacchino Del Regno + * + */ + +#ifndef __CPR_H__ +#define __CPR_H__ + +struct cpr_ext_data { + int mem_acc_threshold_uV; + int apm_threshold_uV; +}; + +#endif /* __CPR_H__ */ From patchwork Wed Jun 28 14:00:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Dybcio X-Patchwork-Id: 113921 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8960888vqr; Wed, 28 Jun 2023 07:17:05 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7dLNH6igf5UCGDqqThvETjh+rK4WSS0rbgmZ565xPKhD/VqbzarjTMPi8zBjJY3bC29SZf X-Received: by 2002:a05:6402:4407:b0:51d:d2f3:fa95 with SMTP id y7-20020a056402440700b0051dd2f3fa95mr895307eda.2.1687961825380; Wed, 28 Jun 2023 07:17:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687961825; cv=none; d=google.com; s=arc-20160816; b=0GSDm6eL+ROiKYhfjXiDPlpjYB/fjEWsakn9t5rJpRavg/UN1BD6N/OO6Y3Izr3SPP uzi4zhEkxyPjII1HWdUOzX3vmO2QEtXnh/e9yyi5e4vlUouRXlqZaLt1Za7TAH67sE9g z/rxpDuA0MVRXmt0JqMUOsu4w22zDcUV0YwqOf2CSLtzTC+Im6LK9r4FEHioxynJi865 YS55vJwii/op6c8UzqAC4dgAk5AoIBzWL+8EgcLPXITBwvRGvSsqj1jK5fxj75zlz0Ne D/t/lH+XGFUvMGxYan2TIFCMsPgLO9SuUbja1xyJ4AxWu7Hnq01oczF+lvh1MLDDtZvb iSXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=MPAidhx6gb0MzSkeNv0f96g3+quO0syJDIwE973x+Fc=; fh=S8/9DkMJ+4w60oR6r4rB6LSoaBTEwLAws8O+AnmOA2I=; b=0Dz03EnoayVulY3j5uIBvu/+Uonnzt2CBpdPjAnA41y4b5Apt5sfJQ61X5+T/jCdxT ATx9gw+rxess/LLwmh+VVPnszz5461bG58cC6AwBGUmKCjL8CT9nIJiMb1AGpG2Od+RS DmB7n5Q/EAR2otIGdDcShLQHstrar476+tP4qWqXDe8zY68WUWUabVqUKRw0ivS47i/v JXAqZjxu6Vog0jhw6Eue7YoM7dt+BO2rMDWTwcIlFcAfNp8rlLJ/eZwxdVz5Tmh2gIWL XUR2bWE2DUN1GxaWOX56vLweVms92Os80q2TpG+xlUHHJActo72LzjqYD9+GizH3ciyg aVdQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=d2YedIZq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k22-20020aa7d8d6000000b0051d8a648b68si4849535eds.404.2023.06.28.07.16.40; Wed, 28 Jun 2023 07:17:05 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=d2YedIZq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232462AbjF1OEX (ORCPT + 99 others); Wed, 28 Jun 2023 10:04:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51866 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232324AbjF1ODK (ORCPT ); Wed, 28 Jun 2023 10:03:10 -0400 Received: from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com [IPv6:2a00:1450:4864:20::22c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CF1A830FC for ; Wed, 28 Jun 2023 07:01:05 -0700 (PDT) Received: by mail-lj1-x22c.google.com with SMTP id 38308e7fff4ca-2b6afc1ceffso32241961fa.0 for ; Wed, 28 Jun 2023 07:01:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1687960864; x=1690552864; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=MPAidhx6gb0MzSkeNv0f96g3+quO0syJDIwE973x+Fc=; b=d2YedIZqPbp3kWPXCASHOEWcCdlm1wmqrAsDV6BW4xy4ONU3uWRQQII69j0zKzC6E7 L+XxCWx/qv5guu3d7edJ52aNTNoybzyJ9dUHpMpc0/WZxgHNCFv+TpjOR0ry3MXAM9D7 frjK8MsRmhSQHhhJsSvOKjiGYl2AoVoZZmyZgBDVpOl3uHy3x1uzEwu0cGcCNOuHVOQ6 0epW0beHwgB8L2bMSupBQLZaDNup3rlpSjf/+qR6l4/a6/nGs1teMIlmP5xhOQ8zSgFV wW4Jnkn1jirm8TeAotbd/cUJDcO7QgVeCxSnph7HjB99oUPEzbPAKib9q/RtFMbj2+Sd sa5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687960864; x=1690552864; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MPAidhx6gb0MzSkeNv0f96g3+quO0syJDIwE973x+Fc=; b=lHLi/h+IQEBCuRYyKTXSaeRBlbfurDH5I0MAkBzZyg8r+ScgVdvyJieCTnLgHkyHVN 9mmi8S3qZeBK73z78D6oWywFh66yVM8XgrNzSSW8bEtrPEdjrbEhUMSAbxN4md1G9QJa QhDMh0C5SYiTFqYwxWuL1iPGRHaJdBC5tL4UaDg4nHg8jEIQ6SkJHPGlSwxPiafizT5x e+Pf7phUqlOCtF7WC8SJkFjzEx4BZ62tBXmHmjUXhQAw9LC0K163BA49pww5hSfU2ve3 YNfrfg/vfUi+iRnVE08l1yqb9/uNslxA4DxIv2NizxIdV+1Zu6uM8IvSkLZt4H8JYeWS OSUw== X-Gm-Message-State: AC+VfDxrk//skokH+4Jm3tYeivn9IgkwgcUOZzykIlD9lbJR7hjDQtdG Yf6LDiheoLEssN2E1fy6/H+QSQ== X-Received: by 2002:a05:6512:3a82:b0:4fb:8c27:4def with SMTP id q2-20020a0565123a8200b004fb8c274defmr2768026lfu.8.1687960864037; Wed, 28 Jun 2023 07:01:04 -0700 (PDT) Received: from [192.168.1.101] (abyk82.neoplus.adsl.tpnet.pl. [83.9.30.82]) by smtp.gmail.com with ESMTPSA id w2-20020a05651204c200b004f8586ab633sm1941359lfq.279.2023.06.28.07.01.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jun 2023 07:01:03 -0700 (PDT) From: Konrad Dybcio Date: Wed, 28 Jun 2023 16:00:49 +0200 Subject: [PATCH v12 10/10] arm64: dts: qcom: msm8998: Configure CPRh MIME-Version: 1.0 Message-Id: <20230217-topic-cpr3h-v12-10-1a4d050e1e67@linaro.org> References: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> In-Reply-To: <20230217-topic-cpr3h-v12-0-1a4d050e1e67@linaro.org> To: AngeloGioacchino Del Regno , Andy Gross , Bjorn Andersson , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Stephen Boyd , Niklas Cassel , Liam Girdwood , Mark Brown , Conor Dooley Cc: Robert Marko , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, Jeffrey Hugo , Marijn Suijten , Konrad Dybcio , AngeloGioacchino Del Regno X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1687960843; l=20911; i=konrad.dybcio@linaro.org; s=20230215; h=from:subject:message-id; bh=R/ZHDpIuNb7dxERiX7ReT3OE+b76z4GsY9Jbl995rIo=; b=TfdmurTC3aQbPLM6BwdIXmrBwgnSlBIaWhEV2zo6twfRjMm/32hyOEKH1dImKO/90AGcWJHy5 ZcF15A/yB/BAftojVV/yUZfEOJ0inQzOOQc+0xSzznLpGRVCm2De5zN X-Developer-Key: i=konrad.dybcio@linaro.org; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769956259259600979?= X-GMAIL-MSGID: =?utf-8?q?1769956259259600979?= From: AngeloGioacchino Del Regno Now that the CPR v3/v4/Hardened is ready, enable it on MSM8998. Signed-off-by: AngeloGioacchino Del Regno [Konrad: separate from adding cpufreq, sort nodes, use lowercase hex, update for driver changes] Signed-off-by: Konrad Dybcio --- arch/arm64/boot/dts/qcom/msm8998.dtsi | 757 ++++++++++++++++++++++++++++++++++ 1 file changed, 757 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index f0e943ff0046..9a53396e13ff 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -143,6 +143,9 @@ CPU0: cpu@0 { capacity-dmips-mhz = <1024>; cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; next-level-cache = <&L2_0>; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&apc_cprh 0>; + power-domain-names = "cprh"; L2_0: l2-cache { compatible = "cache"; cache-level = <2>; @@ -158,6 +161,9 @@ CPU1: cpu@1 { capacity-dmips-mhz = <1024>; cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; next-level-cache = <&L2_0>; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&apc_cprh 0>; + power-domain-names = "cprh"; }; CPU2: cpu@2 { @@ -168,6 +174,9 @@ CPU2: cpu@2 { capacity-dmips-mhz = <1024>; cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; next-level-cache = <&L2_0>; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&apc_cprh 0>; + power-domain-names = "cprh"; }; CPU3: cpu@3 { @@ -178,6 +187,9 @@ CPU3: cpu@3 { capacity-dmips-mhz = <1024>; cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; next-level-cache = <&L2_0>; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&apc_cprh 0>; + power-domain-names = "cprh"; }; CPU4: cpu@100 { @@ -188,6 +200,9 @@ CPU4: cpu@100 { capacity-dmips-mhz = <1536>; cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; next-level-cache = <&L2_1>; + operating-points-v2 = <&cpu4_opp_table>; + power-domains = <&apc_cprh 1>; + power-domain-names = "cprh"; L2_1: l2-cache { compatible = "cache"; cache-level = <2>; @@ -203,6 +218,9 @@ CPU5: cpu@101 { capacity-dmips-mhz = <1536>; cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; next-level-cache = <&L2_1>; + operating-points-v2 = <&cpu4_opp_table>; + power-domains = <&apc_cprh 1>; + power-domain-names = "cprh"; }; CPU6: cpu@102 { @@ -213,6 +231,9 @@ CPU6: cpu@102 { capacity-dmips-mhz = <1536>; cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; next-level-cache = <&L2_1>; + operating-points-v2 = <&cpu4_opp_table>; + power-domains = <&apc_cprh 1>; + power-domain-names = "cprh"; }; CPU7: cpu@103 { @@ -223,6 +244,9 @@ CPU7: cpu@103 { capacity-dmips-mhz = <1536>; cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; next-level-cache = <&L2_1>; + operating-points-v2 = <&cpu4_opp_table>; + power-domains = <&apc_cprh 1>; + power-domain-names = "cprh"; }; cpu-map { @@ -316,6 +340,490 @@ scm { }; }; + cprh_opp_table: opp-table-cprh { + compatible = "operating-points-v2-qcom-level"; + + cprh_opp1: opp-1 { + opp-level = <1>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp2: opp-2 { + opp-level = <2>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp3: opp-3 { + opp-level = <3>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp4: opp-4 { + opp-level = <4>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp5: opp-5 { + opp-level = <5>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp6: opp-6 { + opp-level = <6>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp7: opp-7 { + opp-level = <7>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp8: opp-8 { + opp-level = <8>; + qcom,opp-fuse-level = <1 1>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp9: opp-9 { + opp-level = <9>; + qcom,opp-fuse-level = <2 2>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp10: opp-10 { + opp-level = <10>; + qcom,opp-fuse-level = <2 2>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp11: opp-11 { + opp-level = <11>; + qcom,opp-fuse-level = <2 2>; + qcom,opp-cloop-vadj = <0 0>; + qcom,opp-oloop-vadj = <0 0>; + }; + + cprh_opp12: opp-12 { + opp-level = <12>; + qcom,opp-fuse-level = <3 2>; + qcom,opp-cloop-vadj = <(-10000) (-10000)>; + qcom,opp-oloop-vadj = <(-12000) (-8000)>; + }; + + cprh_opp13: opp-13 { + opp-level = <13>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-11000) (-10000)>; + qcom,opp-oloop-vadj = <(-16000) (-16000)>; + }; + + cprh_opp14: opp-14 { + opp-level = <14>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-12000) (-11000)>; + qcom,opp-oloop-vadj = <(-16000) (-12000)>; + }; + + cprh_opp15: opp-15 { + opp-level = <15>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-13000) (-12000)>; + qcom,opp-oloop-vadj = <(-12000) (-16000)>; + }; + + cprh_opp16: opp-16 { + opp-level = <16>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-14000) (-12000)>; + qcom,opp-oloop-vadj = <(-12000) (-16000)>; + }; + + cprh_opp17: opp-17 { + opp-level = <17>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-14000) (-13000)>; + qcom,opp-oloop-vadj = <(-16000) (-12000)>; + }; + + cprh_opp18: opp-18 { + opp-level = <18>; + qcom,opp-fuse-level = <3 3>; + qcom,opp-cloop-vadj = <(-15000) (-14000)>; + qcom,opp-oloop-vadj = <(-16000) (-16000)>; + }; + + cprh_opp19: opp-19 { + opp-level = <19>; + qcom,opp-fuse-level = <4 3>; + qcom,opp-cloop-vadj = <(-21000) (-14000)>; + qcom,opp-oloop-vadj = <(-20000) (-16000)>; + }; + + cprh_opp20: opp-20 { + opp-level = <20>; + qcom,opp-fuse-level = <4 3>; + qcom,opp-cloop-vadj = <(-24000) (-15000)>; + qcom,opp-oloop-vadj = <(-24000) (-16000)>; + }; + + cprh_opp21: opp-21 { + opp-level = <21>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <(-26000) (-16000)>; + qcom,opp-oloop-vadj = <(-28000) (-24000)>; + }; + + cprh_opp22: opp-22 { + opp-level = <22>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <(-28000) (-16000)>; + qcom,opp-oloop-vadj = <(-28000) (-16000)>; + }; + + cprh_opp23: opp-23 { + opp-level = <23>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-17000)>; + qcom,opp-oloop-vadj = <0 (-20000)>; + }; + + cprh_opp24: opp-24 { + opp-level = <24>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-15000)>; + qcom,opp-oloop-vadj = <0 (-16000)>; + }; + + cprh_opp25: opp-25 { + opp-level = <25>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-14000)>; + qcom,opp-oloop-vadj = <0 (-12000)>; + }; + + cprh_opp26: opp-26 { + opp-level = <26>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-27000)>; + qcom,opp-oloop-vadj = <0 (-28000)>; + }; + + cprh_opp27: opp-27 { + opp-level = <27>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-27000)>; + qcom,opp-oloop-vadj = <0 (-28000)>; + }; + + cprh_opp28: opp-28 { + opp-level = <28>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-28000)>; + qcom,opp-oloop-vadj = <0 (-28000)>; + }; + + cprh_opp29: opp-29 { + opp-level = <29>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-28000)>; + qcom,opp-oloop-vadj = <0 (-28000)>; + }; + + cprh_opp30: opp-30 { + opp-level = <30>; + qcom,opp-fuse-level = <4 4>; + qcom,opp-cloop-vadj = <0 (-28000)>; + qcom,opp-oloop-vadj = <0 (-28000)>; + }; + }; + + cpu0_opp_table: opp-table-cpu0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1900800000 { + opp-hz = /bits/ 64 <1900800000>; + required-opps = <&cprh_opp22>; + }; + + opp-1824000000 { + opp-hz = /bits/ 64 <1824000000>; + required-opps = <&cprh_opp21>; + }; + + opp-1747200000 { + opp-hz = /bits/ 64 <1747200000>; + required-opps = <&cprh_opp20>; + }; + + opp-1670400000 { + opp-hz = /bits/ 64 <1670400000>; + required-opps = <&cprh_opp19>; + }; + + opp-1555200000 { + opp-hz = /bits/ 64 <1555200000>; + required-opps = <&cprh_opp18>; + }; + + opp-1478400000 { + opp-hz = /bits/ 64 <1478400000>; + required-opps = <&cprh_opp17>; + }; + + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + required-opps = <&cprh_opp16>; + }; + + opp-1324800000 { + opp-hz = /bits/ 64 <1324800000>; + required-opps = <&cprh_opp15>; + }; + + opp-1248000000 { + opp-hz = /bits/ 64 <1248000000>; + required-opps = <&cprh_opp14>; + }; + + opp-1171200000 { + opp-hz = /bits/ 64 <1171200000>; + required-opps = <&cprh_opp13>; + }; + + opp-1094400000 { + opp-hz = /bits/ 64 <1094400000>; + required-opps = <&cprh_opp12>; + }; + + opp-1036800000 { + opp-hz = /bits/ 64 <1036800000>; + required-opps = <&cprh_opp11>; + }; + + opp-960000000 { + opp-hz = /bits/ 64 <960000000>; + required-opps = <&cprh_opp10>; + }; + + opp-883200000 { + opp-hz = /bits/ 64 <883200000>; + required-opps = <&cprh_opp9>; + }; + + opp-825600000 { + opp-hz = /bits/ 64 <825600000>; + required-opps = <&cprh_opp8>; + }; + + opp-748800000 { + opp-hz = /bits/ 64 <748800000>; + required-opps = <&cprh_opp7>; + }; + + opp-672000000 { + opp-hz = /bits/ 64 <672000000>; + required-opps = <&cprh_opp6>; + }; + + opp-595200000 { + opp-hz = /bits/ 64 <595200000>; + required-opps = <&cprh_opp5>; + }; + + opp-518400000 { + opp-hz = /bits/ 64 <518400000>; + required-opps = <&cprh_opp4>; + }; + + opp-441600000 { + opp-hz = /bits/ 64 <441600000>; + required-opps = <&cprh_opp3>; + }; + + opp-364800000 { + opp-hz = /bits/ 64 <364800000>; + required-opps = <&cprh_opp2>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&cprh_opp1>; + }; + }; + + cpu4_opp_table: opp-table-cpu4 { + compatible = "operating-points-v2"; + opp-shared; + + opp-2361600000 { + opp-hz = /bits/ 64 <2361600000>; + required-opps = <&cprh_opp30>; + }; + + opp-2342400000 { + opp-hz = /bits/ 64 <2342400000>; + required-opps = <&cprh_opp29>; + }; + + opp-2323200000 { + opp-hz = /bits/ 64 <2323200000>; + required-opps = <&cprh_opp28>; + }; + + opp-2265600000 { + opp-hz = /bits/ 64 <2265600000>; + required-opps = <&cprh_opp27>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + required-opps = <&cprh_opp26>; + }; + + opp-2112000000 { + opp-hz = /bits/ 64 <2112000000>; + required-opps = <&cprh_opp25>; + }; + + opp-2035200000 { + opp-hz = /bits/ 64 <2035200000>; + required-opps = <&cprh_opp24>; + }; + + opp-1958400000 { + opp-hz = /bits/ 64 <1958400000>; + required-opps = <&cprh_opp23>; + }; + + opp-1881600000 { + opp-hz = /bits/ 64 <1881600000>; + required-opps = <&cprh_opp22>; + }; + + opp-1804800000 { + opp-hz = /bits/ 64 <1804800000>; + required-opps = <&cprh_opp21>; + }; + + opp-1728000000 { + opp-hz = /bits/ 64 <1728000000>; + required-opps = <&cprh_opp20>; + }; + + opp-1651200000 { + opp-hz = /bits/ 64 <1651200000>; + required-opps = <&cprh_opp19>; + }; + + opp-1574400000 { + opp-hz = /bits/ 64 <1574400000>; + required-opps = <&cprh_opp18>; + }; + + opp-1497600000 { + opp-hz = /bits/ 64 <1497600000>; + required-opps = <&cprh_opp17>; + }; + + opp-1420800000 { + opp-hz = /bits/ 64 <1420800000>; + required-opps = <&cprh_opp16>; + }; + + opp-1344000000 { + opp-hz = /bits/ 64 <1344000000>; + required-opps = <&cprh_opp15>; + }; + + opp-1267200000 { + opp-hz = /bits/ 64 <1267200000>; + required-opps = <&cprh_opp14>; + }; + + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + required-opps = <&cprh_opp13>; + }; + + opp-1132800000 { + opp-hz = /bits/ 64 <1132800000>; + required-opps = <&cprh_opp12>; + }; + + opp-1056000000 { + opp-hz = /bits/ 64 <1056000000>; + required-opps = <&cprh_opp11>; + }; + + opp-979200000 { + opp-hz = /bits/ 64 <979200000>; + required-opps = <&cprh_opp10>; + }; + + opp-902400000 { + opp-hz = /bits/ 64 <902400000>; + required-opps = <&cprh_opp9>; + }; + + opp-806400000 { + opp-hz = /bits/ 64 <806400000>; + required-opps = <&cprh_opp8>; + }; + + opp-729600000 { + opp-hz = /bits/ 64 <729600000>; + required-opps = <&cprh_opp7>; + }; + + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + required-opps = <&cprh_opp6>; + }; + + opp-576000000 { + opp-hz = /bits/ 64 <576000000>; + required-opps = <&cprh_opp5>; + }; + + opp-499200000 { + opp-hz = /bits/ 64 <499200000>; + required-opps = <&cprh_opp4>; + }; + + opp-422400000 { + opp-hz = /bits/ 64 <422400000>; + required-opps = <&cprh_opp3>; + }; + + opp-345600000 { + opp-hz = /bits/ 64 <345600000>; + required-opps = <&cprh_opp2>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&cprh_opp1>; + }; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -845,6 +1353,174 @@ qfprom: qfprom@784000 { #address-cells = <1>; #size-cells = <1>; + cpr_efuse_speedbin: speedbin@133 { + reg = <0x133 0x8>; + bits = <5 3>; + }; + + cpr_fuse_revision: cpr-fusing-rev@13e { + reg = <0x13e 0x1>; + bits = <3 3>; + }; + + /* CPR Ring Oscillator: Power Cluster */ + cpr_ro_sel3_pwrcl: rosel3-pwrcl@218 { + reg = <0x218 0x1>; + bits = <0 4>; + }; + + cpr_ro_sel2_pwrcl: rosel2-pwrcl@218 { + reg = <0x218 0x1>; + bits = <4 4>; + }; + + cpr_ro_sel1_pwrcl: rosel1-pwrcl@219 { + reg = <0x219 0x1>; + bits = <0 4>; + }; + + cpr_ro_sel0_pwrcl: rosel0-pwrcl@219 { + reg = <0x219 0x1>; + bits = <4 4>; + }; + + /* CPR Init Voltage: Power Cluster */ + cpr_init_voltage3_pwrcl: ivolt3-pwrcl@21a { + reg = <0x21a 0x1>; + bits = <0 6>; + }; + + cpr_init_voltage2_pwrcl: ivolt2-pwrcl@21a { + reg = <0x21a 0x2>; + bits = <6 6>; + }; + + cpr_init_voltage1_pwrcl: ivolt1-pwrcl@21b { + reg = <0x21b 0x2>; + bits = <4 6>; + }; + + cpr_init_voltage0_pwrcl: ivolt0-pwrcl@21c { + reg = <0x21c 0x1>; + bits = <2 6>; + }; + + /* CPR Target Quotients: Power Cluster */ + cpr_quot3_pwrcl: quot3-pwrcl@21d { + reg = <0x21d 0x3>; + bits = <6 12>; + }; + + cpr_quot2_pwrcl: quot2-pwrcl@21f { + reg = <0x21f 0x2>; + bits = <2 11>; + }; + + cpr_quot1_pwrcl: quot1-pwrcl@220 { + reg = <0x220 0x3>; + bits = <6 12>; + }; + + cpr_quot0_pwrcl: quot0-pwrcl@222 { + reg = <0x222 0x2>; + bits = <2 12>; + }; + + /* CPR Quotient Offsets: Power Cluster */ + cpr_quot_offset3_pwrcl: qoff3-pwrcl@226 { + reg = <0x226 0x1>; + bits = <1 7>; + }; + + cpr_quot_offset2_pwrcl: qoff2-pwrcl@227 { + reg = <0x227 0x1>; + bits = <0 7>; + }; + + cpr_quot_offset1_pwrcl: qoff1-pwrcl@227 { + reg = <0x227 0x2>; + bits = <7 6>; + }; + + /* CPR Ring Oscillator: Performance Cluster */ + cpr_ro_sel3_perfcl: rosel3-perfcl@229 { + reg = <0x229 0x2>; + bits = <6 4>; + }; + + cpr_ro_sel2_perfcl: rosel2-perfcl@22a { + reg = <0x22a 0x1>; + bits = <2 4>; + }; + + cpr_ro_sel1_perfcl: rosel1-perfcl@22a { + reg = <0x22a 0x2>; + bits = <6 4>; + }; + + cpr_ro_sel0_perfcl: rosel0-perfcl@22b { + reg = <0x22b 0x1>; + bits = <2 4>; + }; + + /* CPR Init Voltage: Performance Cluster */ + cpr_init_voltage3_perfcl: ivolt3-perfcl@22b { + reg = <0x22b 0x2>; + bits = <6 6>; + }; + + cpr_init_voltage2_perfcl: ivolt2-perfcl@22c { + reg = <0x22c 0x2>; + bits = <4 6>; + }; + + cpr_init_voltage1_perfcl: ivolt1-perfcl@22d { + reg = <0x22d 0x1>; + bits = <2 6>; + }; + + cpr_init_voltage0_perfcl: ivolt0-perfcl@22e { + reg = <0x22e 0x1>; + bits = <0 6>; + }; + + /* CPR Target Quotients: Performance Cluster */ + cpr_quot3_perfcl: quot3-perfcl@22f { + reg = <0x22f 0x2>; + bits = <4 11>; + }; + + cpr_quot2_perfcl: quot2-perfcl@231 { + reg = <0x231 0x2>; + bits = <0 12>; + }; + + cpr_quot1_perfcl: quot1-perfcl@232 { + reg = <0x232 0x2>; + bits = <4 12>; + }; + + cpr_quot0_perfcl: quot0-perfcl@234 { + reg = <0x234 0x2>; + bits = <0 12>; + }; + + /* CPR Quotient Offsets: Performance Cluster */ + cpr_quot_offset3_perfcl: qoff3-perfcl@237 { + reg = <0x237 0x2>; + bits = <7 6>; + }; + + cpr_quot_offset2_perfcl: qoff2-perfcl@238 { + reg = <0x238 0x2>; + bits = <6 7>; + }; + + cpr_quot_offset1_perfcl: qoff1-perfcl@239 { + reg = <0x239 0x1>; + bits = <5 3>; + }; + qusb2_hstx_trim: hstx-trim@23a { reg = <0x23a 0x1>; bits = <0 4>; @@ -2865,6 +3541,87 @@ frame@17928000 { }; }; + apc_cprh: power-controller@179c8000 { + compatible = "qcom,msm8998-cprh", "qcom,cprh"; + reg = <0x179c8000 0x4000>, + <0x179c4000 0x4000>; + + clocks = <&gcc GCC_HMSS_RBCPR_CLK>; + + /* Set the CPR clock here, it needs to match XO */ + assigned-clocks = <&gcc GCC_HMSS_RBCPR_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&cprh_opp_table>; + power-domains = <&rpmpd MSM8998_VDDCX_AO>; + #power-domain-cells = <1>; + + nvmem-cells = <&cpr_efuse_speedbin>, + <&cpr_fuse_revision>, + <&cpr_quot0_pwrcl>, + <&cpr_quot1_pwrcl>, + <&cpr_quot2_pwrcl>, + <&cpr_quot3_pwrcl>, + <&cpr_quot_offset1_pwrcl>, + <&cpr_quot_offset2_pwrcl>, + <&cpr_quot_offset3_pwrcl>, + <&cpr_init_voltage0_pwrcl>, + <&cpr_init_voltage1_pwrcl>, + <&cpr_init_voltage2_pwrcl>, + <&cpr_init_voltage3_pwrcl>, + <&cpr_ro_sel0_pwrcl>, + <&cpr_ro_sel1_pwrcl>, + <&cpr_ro_sel2_pwrcl>, + <&cpr_ro_sel3_pwrcl>, + <&cpr_quot0_perfcl>, + <&cpr_quot1_perfcl>, + <&cpr_quot2_perfcl>, + <&cpr_quot3_perfcl>, + <&cpr_quot_offset1_perfcl>, + <&cpr_quot_offset2_perfcl>, + <&cpr_quot_offset3_perfcl>, + <&cpr_init_voltage0_perfcl>, + <&cpr_init_voltage1_perfcl>, + <&cpr_init_voltage2_perfcl>, + <&cpr_init_voltage3_perfcl>, + <&cpr_ro_sel0_perfcl>, + <&cpr_ro_sel1_perfcl>, + <&cpr_ro_sel2_perfcl>, + <&cpr_ro_sel3_perfcl>; + nvmem-cell-names = "cpr_speed_bin", + "cpr_fuse_revision", + "cpr0_quotient1", + "cpr0_quotient2", + "cpr0_quotient3", + "cpr0_quotient4", + "cpr0_quotient_offset2", + "cpr0_quotient_offset3", + "cpr0_quotient_offset4", + "cpr0_init_voltage1", + "cpr0_init_voltage2", + "cpr0_init_voltage3", + "cpr0_init_voltage4", + "cpr0_ring_osc1", + "cpr0_ring_osc2", + "cpr0_ring_osc3", + "cpr0_ring_osc4", + "cpr1_quotient1", + "cpr1_quotient2", + "cpr1_quotient3", + "cpr1_quotient4", + "cpr1_quotient_offset2", + "cpr1_quotient_offset3", + "cpr1_quotient_offset4", + "cpr1_init_voltage1", + "cpr1_init_voltage2", + "cpr1_init_voltage3", + "cpr1_init_voltage4", + "cpr1_ring_osc1", + "cpr1_ring_osc2", + "cpr1_ring_osc3", + "cpr1_ring_osc4"; + }; + intc: interrupt-controller@17a00000 { compatible = "arm,gic-v3"; reg = <0x17a00000 0x10000>, /* GICD */