Received: by 2002:a05:6a10:9afc:0:0:0:0 with SMTP id t28csp1753835pxm; Thu, 24 Feb 2022 08:45:11 -0800 (PST) X-Google-Smtp-Source: ABdhPJyThMZ/thjqflaMwgiM4WohwEHALaxHlLlNq2okTt81pyouZbOzKrfAabJN4hiXKLLZSYzb X-Received: by 2002:a05:6a00:22ce:b0:4f0:ed5c:7166 with SMTP id f14-20020a056a0022ce00b004f0ed5c7166mr3614583pfj.79.1645721111140; Thu, 24 Feb 2022 08:45:11 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1645721111; cv=none; d=google.com; s=arc-20160816; b=YiO2G5rtUVkXrxKbdSU3Xf8iFI2Fuq0bPbMZvw6LB1LVxntK9vosLdyNukB8GRIQ0e RMkXc8cnw58Xp5+L59Z4kUEDSoto7r7Y7+PvluSJzV+zUb8OlcseIPxIec1Pc3zW2suL MO2J95ds076zTSXnk/kFaviTwt6zOwm80kuXRD4T8BofbcUlgT99P1ufvDvm2i0btFPp kRG9hM/hYzrAbUI9gAmQkAMXRsoeeDV9sEuXmEm4vcgT2EVG6qnOzpXnaOwlmXH5+KSI Lt4Bt5S/xpsiKA6a/gGZvSV8AIVTzZyChfTGQw+KxVZA928DrwHjHweg+fuQo+R2ntTy MBrg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=SzLXOSkhzGzN5m22rAwAREfKfOZltcH16yNIJ5ynJA4=; b=SZDsI/H+dRXd50BW6CPEj28OGn0yFhTOz5/LUgYI0LS+yyXAZ074SvbCu6H5G3XHzh 1IWcbsg1myMyDdFTt+a7K/qJOkyw4p9P39Z6Ddy5DLKtVmCRAODtjmTTD5WNEvbejWAI gBJFYo7dFusoFAKNoTbritpDZkaWFVf3ugtU4LJfFOstDJH0610fm5b+0iWGchdqLKl3 BiOu7V6acv8yzbY9Wz/eg4WrAdeRhjlEF1DjMu8inwmQFfLP2uGsyF8/KvZxMz2LfSh+ 6IMwCm62Wya+LKLkr28gM9Q+TkCjrdjNl6L2/h6n8NtHeOf+d1tZUSAwzawbdk8zMuyH FJ0Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@foss.st.com header.s=selector1 header.b=CeNdvLBb; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=foss.st.com Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [23.128.96.19]) by mx.google.com with ESMTPS id s21si2918192pgs.540.2022.02.24.08.45.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Feb 2022 08:45:11 -0800 (PST) Received-SPF: softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) client-ip=23.128.96.19; Authentication-Results: mx.google.com; dkim=pass header.i=@foss.st.com header.s=selector1 header.b=CeNdvLBb; spf=softfail (google.com: domain of transitioning linux-kernel-owner@vger.kernel.org does not designate 23.128.96.19 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=foss.st.com Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6083422BEA5; Thu, 24 Feb 2022 08:24:27 -0800 (PST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233869AbiBXQDi (ORCPT + 99 others); Thu, 24 Feb 2022 11:03:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231127AbiBXQD2 (ORCPT ); Thu, 24 Feb 2022 11:03:28 -0500 Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2152A1A2776; Thu, 24 Feb 2022 08:02:45 -0800 (PST) Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 21OA8vWN025634; Thu, 24 Feb 2022 17:02:12 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=selector1; bh=SzLXOSkhzGzN5m22rAwAREfKfOZltcH16yNIJ5ynJA4=; b=CeNdvLBbxuctOZ70LCN8qZZjW9KkY0eln+yrX+wMCQnXRe/JOSjj1mN91ria2wODCRJC w7tqyWXOtYBq2/5y4zplNVgtUMtzZDh6yZW/D/o5/lkiV+v0bn3dBUhAeYL0V6y3oU7E /YqiuwM3lxWEjciIZulwf0WIQetrCgVHB7l5trHxvzCed4qX3DkaxPClKEFXG+NyA82e +gKfkZj2BXUjpOHGJGTiCR8Bj3R4uysrlv9j1z/HkalWM0NjNZXlAYiP5XBFBsuMm138 LmO4MVAggsyjjjJk7jpX/io/l6DoaASFr3rEmgrMUnLDvCwaSvCp8RhV0Io6nw9bQlWn nA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3ee2sh47xn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 24 Feb 2022 17:02:12 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 2037C10002A; Thu, 24 Feb 2022 17:02:12 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 144E622A6FC; Thu, 24 Feb 2022 17:02:12 +0100 (CET) Received: from localhost (10.75.127.50) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Thu, 24 Feb 2022 17:02:11 +0100 From: To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Maxime Coquelin , Alexandre Torgue , Philipp Zabel , Gabriel Fernandez CC: , , , , Subject: [PATCH 05/13] clk: stm32mp13: add stm32 divider clock Date: Thu, 24 Feb 2022 17:01:33 +0100 Message-ID: <20220224160141.455881-6-gabriel.fernandez@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220224160141.455881-1-gabriel.fernandez@foss.st.com> References: <20220224160141.455881-1-gabriel.fernandez@foss.st.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Originating-IP: [10.75.127.50] X-ClientProxiedBy: SFHDAG2NODE1.st.com (10.75.127.4) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-02-24_03,2022-02-24_01,2022-02-23_01 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no 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 From: Gabriel Fernandez Just to introduce management of a stm32 divider clock Signed-off-by: Gabriel Fernandez --- drivers/clk/stm32/clk-stm32-core.c | 161 +++++++++++++++++++++++++++++ drivers/clk/stm32/clk-stm32-core.h | 36 +++++++ drivers/clk/stm32/clk-stm32mp13.c | 7 ++ 3 files changed, 204 insertions(+) diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c index 91eae0386e5e..57d039168779 100644 --- a/drivers/clk/stm32/clk-stm32-core.c +++ b/drivers/clk/stm32/clk-stm32-core.c @@ -195,6 +195,146 @@ const struct clk_ops clk_stm32_gate_ops = { .disable_unused = clk_stm32_gate_disable_unused, }; +static unsigned int _get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int _get_div(const struct clk_div_table *table, + unsigned int val, unsigned long flags, u8 width) +{ + if (flags & CLK_DIVIDER_ONE_BASED) + return val; + if (flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << val; + if (table) + return _get_table_div(table, val); + return val + 1; +} + +unsigned long clk_stm32_get_rate_divider(void __iomem *base, + struct clk_stm32_clock_data *data, + u16 div_id, unsigned long parent_rate) +{ + const struct stm32_div_cfg *divider = &data->dividers[div_id]; + unsigned int val; + unsigned int div; + + val = readl(base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + div = _get_div(divider->table, val, divider->flags, divider->width); + + if (!div) { + WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), + "%d: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + div_id); + return parent_rate; + } + + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + +int clk_stm32_set_rate_divider(void __iomem *base, + struct clk_stm32_clock_data *data, + u16 div_id, + unsigned long rate, + unsigned long parent_rate) +{ + const struct stm32_div_cfg *divider = &data->dividers[div_id]; + int value; + u32 val; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = clk_div_mask(divider->width) << (divider->shift + 16); + } else { + val = readl(base + divider->offset); + val &= ~(clk_div_mask(divider->width) << divider->shift); + } + + val |= (u32)value << divider->shift; + + writel(val, base + divider->offset); + + return 0; +} + +int clk_stm32_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_stm32_div *div = to_clk_stm32_divider(hw); + unsigned long flags = 0; + int ret; + + if (div->div_id == NO_STM32_DIV) + return rate; + + spin_lock_irqsave(div->lock, flags); + + ret = clk_stm32_set_rate_divider(div->base, div->clock_data, div->div_id, + rate, parent_rate); + + spin_unlock_irqrestore(div->lock, flags); + + return ret; +} + +long clk_stm32_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_stm32_div *div = to_clk_stm32_divider(hw); + const struct stm32_div_cfg *divider; + + if (div->div_id == NO_STM32_DIV) + return rate; + + divider = &div->clock_data->dividers[div->div_id]; + + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + u32 val; + + val = readl(div->base + divider->offset) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); + } + + return divider_round_rate_parent(hw, clk_hw_get_parent(hw), + rate, prate, divider->table, + divider->width, divider->flags); +} + +unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_stm32_div *div = to_clk_stm32_divider(hw); + + if (div->div_id == NO_STM32_DIV) + return parent_rate; + + return clk_stm32_get_rate_divider(div->base, div->clock_data, + div->div_id, parent_rate); +} + +const struct clk_ops clk_stm32_divider_ops = { + .recalc_rate = clk_stm32_divider_recalc_rate, + .round_rate = clk_stm32_divider_round_rate, + .set_rate = clk_stm32_divider_set_rate, +}; + u8 clk_stm32_get_parent_mux(void __iomem *base, struct clk_stm32_clock_data *data, u16 mux_id) @@ -274,6 +414,27 @@ struct clk_hw *clk_stm32_gate_register(struct device *dev, return hw; } +struct clk_hw *clk_stm32_div_register(struct device *dev, + const struct stm32_rcc_match_data *data, + void __iomem *base, + spinlock_t *lock, + const struct clock_config *cfg) +{ + struct clk_stm32_div *div = cfg->clock_cfg; + struct clk_hw *hw = &div->hw; + int err; + + div->base = base; + div->lock = lock; + div->clock_data = data->clock_data; + + err = clk_hw_register(dev, hw); + if (err) + return ERR_PTR(err); + + return hw; +} + struct clk_hw *clk_stm32_mux_register(struct device *dev, const struct stm32_rcc_match_data *data, void __iomem *base, diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h index 1b4a73556512..833a3d4a064f 100644 --- a/drivers/clk/stm32/clk-stm32-core.h +++ b/drivers/clk/stm32/clk-stm32-core.h @@ -94,6 +94,16 @@ struct clk_stm32_gate { #define to_clk_stm32_gate(_hw) container_of(_hw, struct clk_stm32_gate, hw) +struct clk_stm32_div { + u16 div_id; + struct clk_hw hw; + void __iomem *base; + struct clk_stm32_clock_data *clock_data; + spinlock_t *lock; /* spin lock */ +}; + +#define to_clk_stm32_divider(_hw) container_of(_hw, struct clk_stm32_div, hw) + struct clk_stm32_mux { u16 mux_id; struct clk_hw hw; @@ -121,6 +131,21 @@ void clk_stm32_gate_disable(struct clk_hw *hw); int clk_stm32_gate_is_enabled(struct clk_hw *hw); void clk_stm32_gate_disable_unused(struct clk_hw *hw); +int clk_stm32_set_rate_divider(void __iomem *base, + struct clk_stm32_clock_data *data, + u16 div_id, unsigned long rate, + unsigned long parent_rate); +unsigned long clk_stm32_get_rate_divider(void __iomem *base, + struct clk_stm32_clock_data *data, + u16 div_id, unsigned long parent_rate); + +int clk_stm32_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +long clk_stm32_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate); +unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); + u8 clk_stm32_get_parent_mux(void __iomem *base, struct clk_stm32_clock_data *data, u16 mux_id); @@ -132,6 +157,7 @@ u8 clk_stm32_mux_get_parent(struct clk_hw *hw); int clk_stm32_mux_set_parent(struct clk_hw *hw, u8 index); extern const struct clk_ops clk_stm32_gate_ops; +extern const struct clk_ops clk_stm32_divider_ops; extern const struct clk_ops clk_stm32_mux_ops; /* Clock registering */ @@ -141,6 +167,12 @@ struct clk_hw *clk_stm32_gate_register(struct device *dev, spinlock_t *lock, const struct clock_config *cfg); +struct clk_hw *clk_stm32_div_register(struct device *dev, + const struct stm32_rcc_match_data *data, + void __iomem *base, + spinlock_t *lock, + const struct clock_config *cfg); + struct clk_hw *clk_stm32_mux_register(struct device *dev, const struct stm32_rcc_match_data *data, void __iomem *base, @@ -158,6 +190,10 @@ struct clk_hw *clk_stm32_mux_register(struct device *dev, STM32_CLOCK_CFG(_binding, &(_clk), struct clk_stm32_gate *,\ &clk_stm32_gate_register) +#define STM32_DIV_CFG(_binding, _clk)\ + STM32_CLOCK_CFG(_binding, &(_clk), struct clk_stm32_div *,\ + &clk_stm32_div_register) + #define STM32_MUX_CFG(_binding, _clk)\ STM32_CLOCK_CFG(_binding, &(_clk), struct clk_stm32_mux *,\ &clk_stm32_mux_register) diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c index 24c0c9ff3602..66ebfe810b08 100644 --- a/drivers/clk/stm32/clk-stm32mp13.c +++ b/drivers/clk/stm32/clk-stm32mp13.c @@ -415,9 +415,16 @@ static struct clk_stm32_gate eth1ck_k = { .hw.init = CLK_HW_INIT_HW("eth1ck_k", &ck_ker_eth1.hw, &clk_stm32_gate_ops, 0), }; +static struct clk_stm32_div eth1ptp_k = { + .div_id = DIV_ETH1PTP, + .hw.init = CLK_HW_INIT_HW("eth1ptp_k", &ck_ker_eth1.hw, &clk_stm32_divider_ops, + CLK_SET_RATE_NO_REPARENT), +}; + static const struct clock_config stm32mp13_clock_cfg[] = { STM32_MUX_CFG(NO_ID, ck_ker_eth1), STM32_GATE_CFG(ETH1CK_K, eth1ck_k), + STM32_DIV_CFG(ETH1PTP_K, eth1ptp_k), }; u16 stm32mp13_cpt_gate[GATE_NB]; -- 2.25.1