From patchwork Mon Aug 6 12:49:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 10557057 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 338FA13B4 for ; Mon, 6 Aug 2018 12:49:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 20C722918E for ; Mon, 6 Aug 2018 12:49:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 12AA529280; Mon, 6 Aug 2018 12:49:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 82D782918E for ; Mon, 6 Aug 2018 12:49:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=p4+uQ806HHzKHh0wAJbWT0RZwRyz+tLpwAAKZtecSmk=; b=FGlXc5y7JPO17BNRvYZ67clUGW w36SCqQkuDlB4gZEiWbSwqYhuPPBmgjj0pvSg/DNe4YMVQXkWIt+MPq0SJLuBF8Qy8r8qK+YLdNCe y/HpHQsyqngwMIcRhlts2M0xQB9S++yfvPW/7ivmEL8SIdUsr3iAxurbBzRAIm7j19cLGHq/xlPdQ InDniKpsLHarKLwnm4gWQOldoXVF/H3v4YpXYcw2I3+ss+rSwPBxCp5tM6//KSEePBgEuzWb6mY6L 6HGgyQq7r8RWi+7QGzLeM7MQxOEYhf+PsokbSLLzwWgDtPB8nYT6az6cRh6OwKuxkKdZ31vypD46V D3VJnndg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmexD-00075B-PZ; Mon, 06 Aug 2018 12:49:43 +0000 Received: from mail-wm0-x22f.google.com ([2a00:1450:400c:c09::22f]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmexA-0006zD-As for linux-amlogic@lists.infradead.org; Mon, 06 Aug 2018 12:49:42 +0000 Received: by mail-wm0-x22f.google.com with SMTP id f21-v6so13698947wmc.5 for ; Mon, 06 Aug 2018 05:49:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8of67RqeE57hm8y3PpsKe9js5TdvlFOkK5ZkLeJXIfI=; b=vBqHu/PMhUQ3ecbWry3h33im1oyw//SGSytqEYynYsFnsKse5sJpripOJ9q6v1Gi8t nqvHx9xk3dGQ/jqELh2sQlgqjmNSnhYO1/ZP85LqA4q6+M9oTG4LQUgxghjNelnJmaVQ jE8aDcVSNqsnxj0ei1+QopDZWfdcHUkAU7nnUVuoeR1m+absbLzDRIUMFP0dmuhcaj43 Y/YaY5cejIah0eMsrTmiz6TApBYAwMmgrKv0NhoMjE/xH9adqTJaT+kiUVxfgq4rQ20O poIU48A0qdgoHTgJ82n2NMjTg9M6VGMIaMm82MwluOKKWi+7oYWxnJ22gz2YwprvWzgE oW9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8of67RqeE57hm8y3PpsKe9js5TdvlFOkK5ZkLeJXIfI=; b=bVgJ6N3+2MnidNF5adUq/fP8dhiUPQPJ3jvcKPHzXSJr+oCzLOXeFz8HhZm1upQn53 RsMo/lIS0R+xRqi4nvj3rrJbqvyHXuCMX9EDuG39yUTQG5d70qz42RoFOM5GviJ5475N yN8AzpgBvub2xilnP/STybHkq6hFq49puH2+sbONud7l64gLt/IBjn0FYlQpvCjHL31d TOvlto5V/XJCcxlkSrtDiZXcHQOvAL9R/Fu+iRQ4MNq6YfXuQyQMAJg5MhMmssSHyfuL VkUQfwREVNt7LulSOVOm/1ZTJl6nlpALYu1Ncie+LDFyCxLK67xmv5NVgEWj/9U0aNHy rGKg== X-Gm-Message-State: AOUpUlF7H4m+59vc0qwgfy+xfLWtc1Y00mHxnUuJUg6BqdyWdmj57hvB t2lnanUWCyDKwKiVkA9JGlt4QQ== X-Google-Smtp-Source: AAOMgpe3WFNbBnit8+njDeWjc1gpBPwZ0SWFkF6quMHm64ibiA9r8keEfABLK+RWzW/GLDS7hR7SJA== X-Received: by 2002:a1c:6d9a:: with SMTP id b26-v6mr10853671wmi.74.1533559765151; Mon, 06 Aug 2018 05:49:25 -0700 (PDT) Received: from bender.baylibre.local ([90.63.244.31]) by smtp.gmail.com with ESMTPSA id s7-v6sm13102530wru.96.2018.08.06.05.49.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 06 Aug 2018 05:49:23 -0700 (PDT) From: Neil Armstrong To: jh80.chung@samsung.com, sjg@chromium.org Subject: [PATCH v2 u-boot 1/2] power: domain: Add the VPU Power Domain driver Date: Mon, 6 Aug 2018 14:49:19 +0200 Message-Id: <1533559760-32136-2-git-send-email-narmstrong@baylibre.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533559760-32136-1-git-send-email-narmstrong@baylibre.com> References: <1533559760-32136-1-git-send-email-narmstrong@baylibre.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180806_054940_387154_A6F1076E X-CRM114-Status: GOOD ( 18.59 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, linux-amlogic@lists.infradead.org, Neil Armstrong MIME-Version: 1.0 Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+patchwork-linux-amlogic=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The Amlogic Meson SoCs embeds a specific Power Domain dedicated to the Video Processing Unit. This patch implements support for this power domain in preparation of the future support for the Video display support in U-Boot. This driver will depend on changes in the clock driver to handle the setup of the VPU and VAPB clocks configured from DT using assigned-clocks entries. Reviewed-by: Simon Glass Signed-off-by: Neil Armstrong --- drivers/power/domain/Kconfig | 7 ++ drivers/power/domain/Makefile | 1 + drivers/power/domain/meson-gx-pwrc-vpu.c | 198 +++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 drivers/power/domain/meson-gx-pwrc-vpu.c diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 7cfa761..4618847 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -16,6 +16,13 @@ config BCM6328_POWER_DOMAIN Enable support for manipulating BCM6345 power domains via MMIO mapped registers. +config MESON_GX_VPU_POWER_DOMAIN + bool "Enable Amlogic Meson GX VPU power domain driver" + depends on ARCH_MESON + help + Enable support for manipulating Amlogic Meson GX Video Processing + Unit power domain. + config SANDBOX_POWER_DOMAIN bool "Enable the sandbox power domain test driver" depends on POWER_DOMAIN && SANDBOX diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index c7d7644..4a3282b 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o +obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o diff --git a/drivers/power/domain/meson-gx-pwrc-vpu.c b/drivers/power/domain/meson-gx-pwrc-vpu.c new file mode 100644 index 0000000..d631d3e --- /dev/null +++ b/drivers/power/domain/meson-gx-pwrc-vpu.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Amlogic Meson VPU Power Domain Controller driver + * + * Copyright (c) 2018 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include + +/* AO Offsets */ + +#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2) + +#define GEN_PWR_VPU_HDMI BIT(8) +#define GEN_PWR_VPU_HDMI_ISO BIT(9) + +/* HHI Offsets */ + +#define HHI_MEM_PD_REG0 (0x40 << 2) +#define HHI_VPU_MEM_PD_REG0 (0x41 << 2) +#define HHI_VPU_MEM_PD_REG1 (0x42 << 2) + +struct meson_gx_pwrc_vpu_priv { + struct regmap *regmap_ao; + struct regmap *regmap_hhi; + struct reset_ctl_bulk resets; + struct clk_bulk clks; +}; + +static int meson_gx_pwrc_vpu_request(struct power_domain *power_domain) +{ + return 0; +} + +static int meson_gx_pwrc_vpu_free(struct power_domain *power_domain) +{ + return 0; +} + +static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain) +{ + struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev); + int i, ret; + + regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI, 0); + udelay(20); + + /* Power Up Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0, + 0x3 << i, 0); + udelay(5); + } + + for (i = 0; i < 32; i += 2) { + regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1, + 0x3 << i, 0); + udelay(5); + } + + for (i = 8; i < 16; i++) { + regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0, + BIT(i), 0); + udelay(5); + } + udelay(20); + + ret = reset_assert_bulk(&priv->resets); + if (ret) + return ret; + + regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI_ISO, 0); + + ret = reset_deassert_bulk(&priv->resets); + if (ret) + return ret; + + ret = clk_enable_bulk(&priv->clks); + if (ret) + return ret; + + return 0; +} + +static int meson_gx_pwrc_vpu_off(struct power_domain *power_domain) +{ + struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev); + int i; + + regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); + udelay(20); + + /* Power Down Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG0, + 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 0; i < 32; i += 2) { + regmap_update_bits(priv->regmap_hhi, HHI_VPU_MEM_PD_REG1, + 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 8; i < 16; i++) { + regmap_update_bits(priv->regmap_hhi, HHI_MEM_PD_REG0, + BIT(i), BIT(i)); + udelay(5); + } + udelay(20); + + regmap_update_bits(priv->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); + mdelay(20); + + clk_disable_bulk(&priv->clks); + + return 0; +} + +static int meson_gx_pwrc_vpu_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + /* #power-domain-cells is 0 */ + + if (args->args_count != 0) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + return 0; +} + +struct power_domain_ops meson_gx_pwrc_vpu_ops = { + .free = meson_gx_pwrc_vpu_free, + .off = meson_gx_pwrc_vpu_off, + .on = meson_gx_pwrc_vpu_on, + .request = meson_gx_pwrc_vpu_request, + .of_xlate = meson_gx_pwrc_vpu_of_xlate, +}; + +static const struct udevice_id meson_gx_pwrc_vpu_ids[] = { + { .compatible = "amlogic,meson-gx-pwrc-vpu" }, + { } +}; + +static int meson_gx_pwrc_vpu_probe(struct udevice *dev) +{ + struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev); + u32 hhi_phandle; + ofnode hhi_node; + int ret; + + priv->regmap_ao = syscon_node_to_regmap(dev_get_parent(dev)->node); + if (IS_ERR(priv->regmap_ao)) + return PTR_ERR(priv->regmap_ao); + + ret = ofnode_read_u32(dev->node, "amlogic,hhi-sysctrl", + &hhi_phandle); + if (ret) + return ret; + + hhi_node = ofnode_get_by_phandle(hhi_phandle); + if (!ofnode_valid(hhi_node)) + return -EINVAL; + + priv->regmap_hhi = syscon_node_to_regmap(hhi_node); + if (IS_ERR(priv->regmap_hhi)) + return PTR_ERR(priv->regmap_hhi); + + ret = reset_get_bulk(dev, &priv->resets); + if (ret) + return ret; + + ret = clk_get_bulk(dev, &priv->clks); + if (ret) + return ret; + + return 0; +} + +U_BOOT_DRIVER(meson_gx_pwrc_vpu) = { + .name = "meson_gx_pwrc_vpu", + .id = UCLASS_POWER_DOMAIN, + .of_match = meson_gx_pwrc_vpu_ids, + .probe = meson_gx_pwrc_vpu_probe, + .ops = &meson_gx_pwrc_vpu_ops, + .priv_auto_alloc_size = sizeof(struct meson_gx_pwrc_vpu_priv), +}; From patchwork Mon Aug 6 12:49:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 10557055 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B318715A6 for ; Mon, 6 Aug 2018 12:49:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F30427F86 for ; Mon, 6 Aug 2018 12:49:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 938112918E; Mon, 6 Aug 2018 12:49:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9B47B27F86 for ; Mon, 6 Aug 2018 12:49:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=M9R9/Ptkbfi0ma0mAFwNkG9dmokIB2anZAeoRFZFhl4=; b=e6oRAmhlgT3VEMMUZerJ+5PgDq Eevx2qEdAq4B3vc9TDFa+MUmCkJzWCi0YEKpfJ/BvjvSq+OeL70EPwYHxZXBRrRdr3cAGO6Nupc/V cySnPB5AlevBzsnpR2Q3ICohm79NthqnmGTF0VhYYzpRutmqp7U0NIKzmjaUSvWJClnw2n84L5TgT yYgCf6aMMlt8Ccbhg3rCaoJNxNi5JHp7AULOLfbhdEioJWnXuU0GCRD9EFj/3PG+dMEqVk8SGrfOl pzQbb82yN2KHhwJWY9SXnoTw9l5I9/m2gzQaxmhbuiAkYs2gF3n3CuKNyG9u/AoklXPTWJe3Veqyu XcNjgBmA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmex9-000720-43; Mon, 06 Aug 2018 12:49:39 +0000 Received: from mail-wm0-x244.google.com ([2a00:1450:400c:c09::244]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmex4-0006zL-QX for linux-amlogic@lists.infradead.org; Mon, 06 Aug 2018 12:49:36 +0000 Received: by mail-wm0-x244.google.com with SMTP id q8-v6so14255486wmq.4 for ; Mon, 06 Aug 2018 05:49:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=KSbfodyLEh/xkpRsTnb6aS2tpkLa28+29ROLru0hc34=; b=y2XINqkFzvaZ1BUvL2Djj7DDKfVWf+T/zsFTNrUajZYnAKPMYuekWUXlqxaLZ3gT/2 0oB4BEXpKv82IG6Yw0Y/V0QYtZCNlq9ucRZQ15p6aURrgYAAZml8/7F6+7Tl3qFF5ju9 YB1sYcse1wNBsDEbq1HklK7cVPSQaNyOe2a6c9fp0653S3c8EKcWaAaMehidzEL+Mu2H YJfe7plOO+dCKIz1d1aQUJKUBeQkjmc6XSkLeORp9CNtX/j33DdUjhvN+l92ZejuyBtD sFzr7sGtnkd37PqftztNkwZdps2OkGt6GUCrAB0in1icpKq6ZwWkAdisk3iKCaIBk7Ik MHFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=KSbfodyLEh/xkpRsTnb6aS2tpkLa28+29ROLru0hc34=; b=kbYWusaskl4h0PhuoELO9D0NglCIwuN2CDjBsOINRykCA3Gn8O41WQq1TOZGelxG4P nQzwRyYmkNvpiAMN976SKsakWoBqDuZvDF+2Ct1yDQph6QHMdfZjZsEac7Bc/CJTPX1P Feq8tUeviM/ONmq5SZ/srx2HCaN18YC/WA5HuEfJqGXC278ZCOvGiKCa0Yker2Ab9Omj 1DmKsBlnbxcSTrgJmDkwXPxGxJ1O7NSkE3+Orn/RgHQ4GkdmGXTQCnf8HPjREtk31k4n EiqmVH8cNIDhWQaVWYShYzJ/QrrVFKcR4k4PqBnLcNOyuB0G+aO+8+AGm50s+AMf3G5z dF8A== X-Gm-Message-State: AOUpUlHZ4M6r0nEu5XNI0bUIKiyY3DyxPTRP9jgeBKNDLr4hrpH2BMNM 8O1lSNKU2OAZ4ohnGDAJck9EQw== X-Google-Smtp-Source: AAOMgpccIGvP2xfDrIxhVhY0PXX2GiMAlLTzchUXgIo0XnlDhE7Q7RadYJ/4lKZeOEnPOoYSorg0Tw== X-Received: by 2002:a1c:1609:: with SMTP id 9-v6mr11383727wmw.12.1533559769474; Mon, 06 Aug 2018 05:49:29 -0700 (PDT) Received: from bender.baylibre.local ([90.63.244.31]) by smtp.gmail.com with ESMTPSA id s7-v6sm13102530wru.96.2018.08.06.05.49.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 06 Aug 2018 05:49:28 -0700 (PDT) From: Neil Armstrong To: jh80.chung@samsung.com, sjg@chromium.org Subject: [PATCH v2 u-boot 2/2] clk: clk_meson: Add mux and div support for reparent and rate setting Date: Mon, 6 Aug 2018 14:49:20 +0200 Message-Id: <1533559760-32136-3-git-send-email-narmstrong@baylibre.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533559760-32136-1-git-send-email-narmstrong@baylibre.com> References: <1533559760-32136-1-git-send-email-narmstrong@baylibre.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180806_054934_868147_DE4706E3 X-CRM114-Status: GOOD ( 16.64 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: b.galvani@gmail.com, u-boot@lists.denx.de, linux-amlogic@lists.infradead.org, Neil Armstrong MIME-Version: 1.0 Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+patchwork-linux-amlogic=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for : - Rate calculation through muxes and generic dividers - Basic gate setting propagation - Reparenting for muxes - Clock rate setting through generic dividers without reparenting Support is only added to the Composite VPU and VAPB clocks in order to support the Video Processing Unit Power Domain clock setup. Reviewed-by: Simon Glass Signed-off-by: Neil Armstrong --- drivers/clk/clk_meson.c | 533 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 528 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk_meson.c b/drivers/clk/clk_meson.c index 3850128..236d734 100644 --- a/drivers/clk/clk_meson.c +++ b/drivers/clk/clk_meson.c @@ -14,12 +14,69 @@ #include #include "clk_meson.h" +/* This driver support only basic clock tree operations : + * - Can calculate clock frequency on a limited tree + * - Can Read muxes and basic dividers (0-based only) + * - Can enable/disable gates with limited propagation + * - Can reparent without propagation, only on muxes + * - Can set rates without reparenting + * This driver is adapted to what is actually supported by U-Boot + */ + +/* Only the clocks ids we don't want to expose, such as the internal muxes + * and dividers of composite clocks, will remain defined here. + */ +#define CLKID_MPEG_SEL 10 +#define CLKID_MPEG_DIV 11 +#define CLKID_SAR_ADC_DIV 99 +#define CLKID_MALI_0_DIV 101 +#define CLKID_MALI_1_DIV 104 +#define CLKID_CTS_AMCLK_SEL 108 +#define CLKID_CTS_AMCLK_DIV 109 +#define CLKID_CTS_MCLK_I958_SEL 111 +#define CLKID_CTS_MCLK_I958_DIV 112 +#define CLKID_32K_CLK_SEL 115 +#define CLKID_32K_CLK_DIV 116 +#define CLKID_SD_EMMC_A_CLK0_SEL 117 +#define CLKID_SD_EMMC_A_CLK0_DIV 118 +#define CLKID_SD_EMMC_B_CLK0_SEL 120 +#define CLKID_SD_EMMC_B_CLK0_DIV 121 +#define CLKID_SD_EMMC_C_CLK0_SEL 123 +#define CLKID_SD_EMMC_C_CLK0_DIV 124 +#define CLKID_VPU_0_DIV 127 +#define CLKID_VPU_1_DIV 130 +#define CLKID_VAPB_0_DIV 134 +#define CLKID_VAPB_1_DIV 137 +#define CLKID_HDMI_PLL_PRE_MULT 141 +#define CLKID_MPLL0_DIV 142 +#define CLKID_MPLL1_DIV 143 +#define CLKID_MPLL2_DIV 144 +#define CLKID_MPLL_PREDIV 145 +#define CLKID_FCLK_DIV2_DIV 146 +#define CLKID_FCLK_DIV3_DIV 147 +#define CLKID_FCLK_DIV4_DIV 148 +#define CLKID_FCLK_DIV5_DIV 149 +#define CLKID_FCLK_DIV7_DIV 150 +#define CLKID_VDEC_1_SEL 151 +#define CLKID_VDEC_1_DIV 152 +#define CLKID_VDEC_HEVC_SEL 154 +#define CLKID_VDEC_HEVC_DIV 155 + #define XTAL_RATE 24000000 struct meson_clk { void __iomem *addr; }; +static ulong meson_div_get_rate(struct clk *clk, unsigned long id); +static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, + ulong current_rate); +static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, + unsigned long parent_id); +static ulong meson_mux_get_rate(struct clk *clk, unsigned long id); +static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, + ulong rate, ulong current_rate); +static ulong meson_mux_get_parent(struct clk *clk, unsigned long id); static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); struct meson_gate gates[] = { @@ -126,34 +183,387 @@ struct meson_gate gates[] = { MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7), MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), + MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8), + MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24), + MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8), + MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24), + MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30), }; -static int meson_set_gate(struct clk *clk, bool on) +static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) { struct meson_clk *priv = dev_get_priv(clk->dev); struct meson_gate *gate; - if (clk->id >= ARRAY_SIZE(gates)) + debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id); + + /* Propagate through muxes */ + switch (id) { + case CLKID_VPU: + return meson_set_gate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VPU), on); + case CLKID_VAPB_SEL: + return meson_set_gate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VAPB_SEL), on); + } + + if (id >= ARRAY_SIZE(gates)) return -ENOENT; - gate = &gates[clk->id]; + gate = &gates[id]; if (gate->reg == 0) return 0; + debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id); + clrsetbits_le32(priv->addr + gate->reg, BIT(gate->bit), on ? BIT(gate->bit) : 0); + + /* Propagate to next gate(s) */ + switch (id) { + case CLKID_VAPB: + return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on); + } + return 0; } static int meson_clk_enable(struct clk *clk) { - return meson_set_gate(clk, true); + return meson_set_gate_by_id(clk, clk->id, true); } static int meson_clk_disable(struct clk *clk) { - return meson_set_gate(clk, false); + return meson_set_gate_by_id(clk, clk->id, false); +} + +static struct parm meson_vpu_0_div_parm = { + HHI_VPU_CLK_CNTL, 0, 7, +}; + +int meson_vpu_0_div_parent = CLKID_VPU_0_SEL; + +static struct parm meson_vpu_1_div_parm = { + HHI_VPU_CLK_CNTL, 16, 7, +}; + +int meson_vpu_1_div_parent = CLKID_VPU_1_SEL; + +static struct parm meson_vapb_0_div_parm = { + HHI_VAPBCLK_CNTL, 0, 7, +}; + +int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL; + +static struct parm meson_vapb_1_div_parm = { + HHI_VAPBCLK_CNTL, 16, 7, +}; + +int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL; + +static ulong meson_div_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int rate, parent_rate; + struct parm *parm; + int parent; + u32 reg; + + switch (id) { + case CLKID_VPU_0_DIV: + parm = &meson_vpu_0_div_parm; + parent = meson_vpu_0_div_parent; + break; + case CLKID_VPU_1_DIV: + parm = &meson_vpu_1_div_parm; + parent = meson_vpu_1_div_parent; + break; + case CLKID_VAPB_0_DIV: + parm = &meson_vapb_0_div_parm; + parent = meson_vapb_0_div_parent; + break; + case CLKID_VAPB_1_DIV: + parm = &meson_vapb_1_div_parm; + parent = meson_vapb_1_div_parent; + break; + default: + return -ENOENT; + } + + reg = readl(priv->addr + parm->reg_off); + reg = PARM_GET(parm->width, parm->shift, reg); + + debug("%s: div of %ld is %d\n", __func__, id, reg + 1); + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate); + + rate = parent_rate / (reg + 1); + + debug("%s: rate of %ld is %d\n", __func__, id, rate); + + return rate; +} + +static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, + ulong current_rate) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int new_div = -EINVAL; + unsigned long parent_rate; + struct parm *parm; + int parent; + u32 reg; + int ret; + + if (current_rate == rate) + return 0; + + debug("%s: setting rate of %ld from %ld to %ld\n", + __func__, id, current_rate, rate); + + switch (id) { + case CLKID_VPU_0_DIV: + parm = &meson_vpu_0_div_parm; + parent = meson_vpu_0_div_parent; + break; + case CLKID_VPU_1_DIV: + parm = &meson_vpu_1_div_parm; + parent = meson_vpu_1_div_parent; + break; + case CLKID_VAPB_0_DIV: + parm = &meson_vapb_0_div_parm; + parent = meson_vapb_0_div_parent; + break; + case CLKID_VAPB_1_DIV: + parm = &meson_vapb_1_div_parm; + parent = meson_vapb_1_div_parent; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate); + + /* If can't divide, set parent instead */ + if (!parent_rate || rate > parent_rate) + return meson_clk_set_rate_by_id(clk, parent, rate, + current_rate); + + new_div = DIV_ROUND_CLOSEST(parent_rate, rate); + + debug("%s: new div of %ld is %d\n", __func__, id, new_div); + + /* If overflow, try to set parent rate and retry */ + if (!new_div || new_div > (1 << parm->width)) { + ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate); + if (IS_ERR_VALUE(ret)) + return ret; + + parent_rate = meson_clk_get_rate_by_id(clk, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + new_div = DIV_ROUND_CLOSEST(parent_rate, rate); + + debug("%s: new new div of %ld is %d\n", __func__, id, new_div); + + if (!new_div || new_div > (1 << parm->width)) + return -EINVAL; + } + + debug("%s: setting div of %ld to %d\n", __func__, id, new_div); + + reg = readl(priv->addr + parm->reg_off); + writel(PARM_SET(parm->width, parm->shift, reg, new_div - 1), + priv->addr + parm->reg_off); + + debug("%s: new rate of %ld is %ld\n", + __func__, id, meson_div_get_rate(clk, id)); + + return 0; +} + +static struct parm meson_vpu_mux_parm = { + HHI_VPU_CLK_CNTL, 31, 1, +}; + +int meson_vpu_mux_parents[] = { + CLKID_VPU_0, + CLKID_VPU_1, +}; + +static struct parm meson_vpu_0_mux_parm = { + HHI_VPU_CLK_CNTL, 9, 2, +}; + +static struct parm meson_vpu_1_mux_parm = { + HHI_VPU_CLK_CNTL, 25, 2, +}; + +static int meson_vpu_0_1_mux_parents[] = { + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5, + CLKID_FCLK_DIV7, +}; + +static struct parm meson_vapb_sel_mux_parm = { + HHI_VAPBCLK_CNTL, 31, 1, +}; + +int meson_vapb_sel_mux_parents[] = { + CLKID_VAPB_0, + CLKID_VAPB_1, +}; + +static struct parm meson_vapb_0_mux_parm = { + HHI_VAPBCLK_CNTL, 9, 2, +}; + +static struct parm meson_vapb_1_mux_parm = { + HHI_VAPBCLK_CNTL, 25, 2, +}; + +static int meson_vapb_0_1_mux_parents[] = { + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5, + CLKID_FCLK_DIV7, +}; + +static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *parm; + int *parents; + u32 reg; + + switch (id) { + case CLKID_VPU: + parm = &meson_vpu_mux_parm; + parents = meson_vpu_mux_parents; + break; + case CLKID_VPU_0_SEL: + parm = &meson_vpu_0_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VPU_1_SEL: + parm = &meson_vpu_1_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VAPB_SEL: + parm = &meson_vapb_sel_mux_parm; + parents = meson_vapb_sel_mux_parents; + break; + case CLKID_VAPB_0_SEL: + parm = &meson_vapb_0_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + case CLKID_VAPB_1_SEL: + parm = &meson_vapb_1_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + default: + return -ENOENT; + } + + reg = readl(priv->addr + parm->reg_off); + reg = PARM_GET(parm->width, parm->shift, reg); + + debug("%s: parent of %ld is %d (%d)\n", + __func__, id, parents[reg], reg); + + return parents[reg]; +} + +static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, + unsigned long parent_id) +{ + unsigned long cur_parent = meson_mux_get_parent(clk, id); + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned int new_index = -EINVAL; + struct parm *parm; + int *parents; + u32 reg; + int i; + + if (IS_ERR_VALUE(cur_parent)) + return cur_parent; + + debug("%s: setting parent of %ld from %ld to %ld\n", + __func__, id, cur_parent, parent_id); + + if (cur_parent == parent_id) + return 0; + + switch (id) { + case CLKID_VPU: + parm = &meson_vpu_mux_parm; + parents = meson_vpu_mux_parents; + break; + case CLKID_VPU_0_SEL: + parm = &meson_vpu_0_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VPU_1_SEL: + parm = &meson_vpu_1_mux_parm; + parents = meson_vpu_0_1_mux_parents; + break; + case CLKID_VAPB_SEL: + parm = &meson_vapb_sel_mux_parm; + parents = meson_vapb_sel_mux_parents; + break; + case CLKID_VAPB_0_SEL: + parm = &meson_vapb_0_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + case CLKID_VAPB_1_SEL: + parm = &meson_vapb_1_mux_parm; + parents = meson_vapb_0_1_mux_parents; + break; + default: + /* Not a mux */ + return -ENOENT; + } + + for (i = 0 ; i < (1 << parm->width) ; ++i) { + if (parents[i] == parent_id) + new_index = i; + } + + if (IS_ERR_VALUE(new_index)) + return new_index; + + debug("%s: new index of %ld is %d\n", __func__, id, new_index); + + reg = readl(priv->addr + parm->reg_off); + writel(PARM_SET(parm->width, parm->shift, reg, new_index), + priv->addr + parm->reg_off); + + debug("%s: new parent of %ld is %ld\n", + __func__, id, meson_mux_get_parent(clk, id)); + + return 0; +} + +static ulong meson_mux_get_rate(struct clk *clk, unsigned long id) +{ + int parent = meson_mux_get_parent(clk, id); + + if (IS_ERR_VALUE(parent)) + return parent; + + return meson_clk_get_rate_by_id(clk, parent); } static unsigned long meson_clk81_get_rate(struct clk *clk) @@ -342,6 +752,35 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) case CLKID_CLK81: rate = meson_clk81_get_rate(clk); break; + case CLKID_VPU_0: + rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV); + break; + case CLKID_VPU_1: + rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV); + break; + case CLKID_VAPB: + rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL); + break; + case CLKID_VAPB_0: + rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV); + break; + case CLKID_VAPB_1: + rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); + break; + case CLKID_VPU_0_DIV: + case CLKID_VPU_1_DIV: + case CLKID_VAPB_0_DIV: + case CLKID_VAPB_1_DIV: + rate = meson_div_get_rate(clk, id); + break; + case CLKID_VPU: + case CLKID_VPU_0_SEL: + case CLKID_VPU_1_SEL: + case CLKID_VAPB_SEL: + case CLKID_VAPB_0_SEL: + case CLKID_VAPB_1_SEL: + rate = meson_mux_get_rate(clk, id); + break; default: if (gates[id].reg != 0) { /* a clock gate */ @@ -360,6 +799,88 @@ static ulong meson_clk_get_rate(struct clk *clk) return meson_clk_get_rate_by_id(clk, clk->id); } +static int meson_clk_set_parent(struct clk *clk, struct clk *parent) +{ + return meson_mux_set_parent(clk, clk->id, parent->id); +} + +static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, + ulong rate, ulong current_rate) +{ + if (current_rate == rate) + return 0; + + switch (id) { + /* Fixed clocks */ + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + case CLKID_FCLK_DIV2: + case CLKID_FCLK_DIV3: + case CLKID_FCLK_DIV4: + case CLKID_FCLK_DIV5: + case CLKID_FCLK_DIV7: + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + case CLKID_CLK81: + if (current_rate != rate) + return -EINVAL; + + return 0; + case CLKID_VPU: + return meson_clk_set_rate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VPU), rate, + current_rate); + case CLKID_VAPB: + case CLKID_VAPB_SEL: + return meson_clk_set_rate_by_id(clk, + meson_mux_get_parent(clk, CLKID_VAPB_SEL), + rate, current_rate); + case CLKID_VPU_0: + return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate, + current_rate); + case CLKID_VPU_1: + return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate, + current_rate); + case CLKID_VAPB_0: + return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate, + current_rate); + case CLKID_VAPB_1: + return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate, + current_rate); + case CLKID_VPU_0_DIV: + case CLKID_VPU_1_DIV: + case CLKID_VAPB_0_DIV: + case CLKID_VAPB_1_DIV: + return meson_div_set_rate(clk, id, rate, current_rate); + default: + return -ENOENT; + } + + return -EINVAL; +} + +static ulong meson_clk_set_rate(struct clk *clk, ulong rate) +{ + ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id); + int ret; + + if (IS_ERR_VALUE(current_rate)) + return current_rate; + + debug("%s: setting rate of %ld from %ld to %ld\n", + __func__, clk->id, current_rate, rate); + + ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate); + if (IS_ERR_VALUE(ret)) + return ret; + + printf("clock %lu has new rate %lu\n", clk->id, + meson_clk_get_rate_by_id(clk, clk->id)); + + return 0; +} + static int meson_clk_probe(struct udevice *dev) { struct meson_clk *priv = dev_get_priv(dev); @@ -375,6 +896,8 @@ static struct clk_ops meson_clk_ops = { .disable = meson_clk_disable, .enable = meson_clk_enable, .get_rate = meson_clk_get_rate, + .set_parent = meson_clk_set_parent, + .set_rate = meson_clk_set_rate, }; static const struct udevice_id meson_clk_ids[] = {