* [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845
@ 2018-07-12 17:09 Amit Nischal
2018-07-12 17:09 ` [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Amit Nischal @ 2018-07-12 17:09 UTC (permalink / raw)
To: Stephen Boyd, Michael Turquette
Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel,
Amit Nischal
Changes in v2:
Addressed review comments given by Stephen: https://lkml.org/lkml/2018/6/6/294
* Introduce clk_rcg2_gfx3d_determine_rate ops to return the best parent
as 'gpucc_pll0_even' and best parent rate as twice of the requested rate
always. This will eliminate the need of frequency table as source and
div-2 are fixed for gfx3d_clk_src.
Also modified the clk_rcg2_set_rate ops to configure the fixed source and
div.
* Add support to check if requested rate falls within allowed set_rate range.
This will not let the source gpucc_pll0 to go out of the supported range
and also client can request the rate within the range.
* Fixed comment text in probe function and added module description for GPUCC
driver.
The graphics clock driver depends upon the below change.
https://lkml.org/lkml/2018/6/23/108
Changes in v1:
This patch series adds support for graphics clock controller for SDM845.
Below is the brief description for each change:
1. For some of the GDSCs, there is requirement to enable/disable the
few clocks before turning on/off the gdsc power domain. This patch
will add support to enable/disable the clock associated with the
gdsc along with power domain on/off callbacks.
2. To turn on the gpu_gx_gdsc, there is a hardware requirement to
turn on the root clock (GFX3D RCG) first which would be the turn
on signal for the gdsc along with the SW_COLLAPSE. As per the
current implementation of clk_rcg2_shared_ops, it clears the
root_enable bit in the enable() clock ops. But due to the above
said requirement for GFX3D shared RCG, root_enable bit would be
already set by gdsc driver and rcg2_shared_ops should not clear
the root unless the disable() is called.
This patch add support for the same by reusing the existing
clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops
for GFX3D clock to take care of the root set/clear requirement.
3. Add device tree bindings for graphics clock controller for SDM845.
4. Add graphics clock controller (GPUCC) driver for SDM845.
[v1] : https://lkml.org/lkml/2018/6/6/294
Amit Nischal (4):
clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC
clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845
dt-bindings: clock: Introduce QCOM Graphics clock bindings
clk: qcom: Add graphics clock controller driver for SDM845
.../devicetree/bindings/clock/qcom,gpucc.txt | 18 +
drivers/clk/qcom/Kconfig | 9 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/clk-rcg.h | 1 +
drivers/clk/qcom/clk-rcg2.c | 87 +++-
drivers/clk/qcom/gdsc.c | 44 +++
drivers/clk/qcom/gdsc.h | 5 +
drivers/clk/qcom/gpucc-sdm845.c | 438 +++++++++++++++++++++
include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++
9 files changed, 639 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt
create mode 100644 drivers/clk/qcom/gpucc-sdm845.c
create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC 2018-07-12 17:09 [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal @ 2018-07-12 17:09 ` Amit Nischal 2018-07-12 17:09 ` [PATCH v2 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal ` (2 subsequent siblings) 3 siblings, 0 replies; 7+ messages in thread From: Amit Nischal @ 2018-07-12 17:09 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal For some of the GDSCs, there is a requirement to enable/disable the few clocks before turning on/off the gdsc power domain. Add support for the same by specifying a list of clk_hw pointers per gdsc and enable/disable them along with power domain on/off callbacks. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/gdsc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/gdsc.h | 5 +++++ 2 files changed, 49 insertions(+) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index a077133..b6adca1 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -12,6 +12,8 @@ */ #include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/jiffies.h> @@ -208,11 +210,41 @@ static inline void gdsc_assert_reset_aon(struct gdsc *sc) regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, GMEM_RESET_MASK, 0); } + +static int gdsc_clk_prepare_enable(struct gdsc *sc) +{ + int i, ret; + + for (i = 0; i < sc->clk_count; i++) { + ret = clk_prepare_enable(sc->clk_hws[i]->clk); + if (ret) { + for (i--; i >= 0; i--) + clk_disable_unprepare(sc->clk_hws[i]->clk); + return ret; + } + } + return 0; +} + +static void gdsc_clk_disable_unprepare(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->clk_count; i++) + clk_disable_unprepare(sc->clk_hws[i]->clk); +} + static int gdsc_enable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); int ret; + if (sc->clk_count) { + ret = gdsc_clk_prepare_enable(sc); + if (ret) + return ret; + } + if (sc->pwrsts == PWRSTS_ON) return gdsc_deassert_reset(sc); @@ -260,6 +292,9 @@ static int gdsc_enable(struct generic_pm_domain *domain) udelay(1); } + if (sc->clk_count) + gdsc_clk_disable_unprepare(sc); + return 0; } @@ -268,6 +303,12 @@ static int gdsc_disable(struct generic_pm_domain *domain) struct gdsc *sc = domain_to_gdsc(domain); int ret; + if (sc->clk_count) { + ret = gdsc_clk_prepare_enable(sc); + if (ret) + return ret; + } + if (sc->pwrsts == PWRSTS_ON) return gdsc_assert_reset(sc); @@ -299,6 +340,9 @@ static int gdsc_disable(struct generic_pm_domain *domain) if (sc->flags & CLAMP_IO) gdsc_assert_clamp_io(sc); + if (sc->clk_count) + gdsc_clk_disable_unprepare(sc); + return 0; } diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index bd1f2c7..59957d7 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/pm_domain.h> +struct clk_hw; struct regmap; struct reset_controller_dev; @@ -32,6 +33,8 @@ * @resets: ids of resets associated with this gdsc * @reset_count: number of @resets * @rcdev: reset controller + * @clk_count: number of associated clocks + * @clk_hws: clk_hw pointers for associated clocks with gdsc */ struct gdsc { struct generic_pm_domain pd; @@ -60,6 +63,8 @@ struct gdsc { struct reset_controller_dev *rcdev; unsigned int *resets; unsigned int reset_count; + unsigned int clk_count; + struct clk_hw *clk_hws[]; }; struct gdsc_desc { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 2018-07-12 17:09 [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-07-12 17:09 ` [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal @ 2018-07-12 17:09 ` Amit Nischal 2018-07-12 17:09 ` [PATCH v2 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal 2018-07-12 17:09 ` [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 3 siblings, 0 replies; 7+ messages in thread From: Amit Nischal @ 2018-07-12 17:09 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal To turn on the gpu_gx_gdsc, there is a hardware requirement to turn on the root clock (GFX3D RCG) first which would be the turn on signal for the gdsc along with the SW_COLLAPSE. As per the current implementation of clk_rcg2_shared_ops, it clears the root_enable bit in the enable() clock op. But due to the above said requirement for GFX3D shared RCG, root_enable bit would be already set by gdsc driver and clk_rcg2_shared_enable()should not clear the root unless the disable is called. Add support for the same by reusing the existing clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops for GFX3D clock to take care of the root set/clear requirement. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 87 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b209a2f..c8c9558 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -160,5 +160,6 @@ struct clk_rcg2 { extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +extern const struct clk_ops clk_rcg2_gfx3d_ops; #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..667edd9 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -866,7 +866,7 @@ static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw, return clk_rcg2_shared_set_rate(hw, rate, parent_rate); } -static int clk_rcg2_shared_enable(struct clk_hw *hw) +static int __clk_rcg2_shared_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret; @@ -879,7 +879,14 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw) if (ret) return ret; - ret = update_config(rcg); + return update_config(rcg); +} + +static int clk_rcg2_shared_enable(struct clk_hw *hw) +{ + int ret; + + ret = __clk_rcg2_shared_enable(hw); if (ret) return ret; @@ -929,3 +936,79 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +static int clk_rcg2_gfx3d_enable(struct clk_hw *hw) +{ + return __clk_rcg2_shared_enable(hw); +} + +static int clk_rcg2_gfx3d_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rate_request parent_req = { }; + struct clk_hw *p; + unsigned long rate = req->rate; + int ret; + + if (rate < req->min_rate || rate > req->max_rate) + return -EINVAL; + + /* Get fixed parent - GPU_CC_PLL0_OUT_EVEN */ + p = clk_hw_get_parent_by_index(hw, 1); + + /* Parent should always run at twice of the requested rate */ + parent_req.rate = 2 * req->rate; + + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; + + req->best_parent_hw = p; + req->best_parent_rate = parent_req.rate; + req->rate = parent_req.rate / 2; + + return 0; +} + +static int clk_rcg2_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; + u32 cfg; + + /* Configure fixed SRC and DIV */ + cfg = rcg->parent_map[1].cfg << CFG_SRC_SEL_SHIFT; + cfg |= 0x3 << CFG_SRC_DIV_SHIFT; + + ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg); + if (ret) + return ret; + + /* + * In case clock is disabled, update the SRC and DIV only + * and return without configuration update. + */ + if (!__clk_is_enabled(hw->clk)) + return 0; + + return update_config(rcg); +} + +static int clk_rcg2_gfx3d_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_rcg2_gfx3d_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_rcg2_gfx3d_ops = { + .enable = clk_rcg2_gfx3d_enable, + .disable = clk_rcg2_shared_disable, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_rcg2_gfx3d_determine_rate, + .set_rate = clk_rcg2_gfx3d_set_rate, + .set_rate_and_parent = clk_rcg2_gfx3d_set_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg2_gfx3d_ops); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings 2018-07-12 17:09 [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-07-12 17:09 ` [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal 2018-07-12 17:09 ` [PATCH v2 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal @ 2018-07-12 17:09 ` Amit Nischal 2018-07-12 17:09 ` [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 3 siblings, 0 replies; 7+ messages in thread From: Amit Nischal @ 2018-07-12 17:09 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Add device tree bindings for graphics clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- .../devicetree/bindings/clock/qcom,gpucc.txt | 18 ++++++++++ include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt new file mode 100644 index 0000000..93752db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -0,0 +1,18 @@ +Qualcomm Graphics Clock & Reset Controller Binding +-------------------------------------------------- + +Required properties : +- compatible : shall contain "qcom,sdm845-gpucc". +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + gpucc: clock-controller@5090000 { + compatible = "qcom,sdm845-gpucc"; + reg = <0x5090000 0x9000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h new file mode 100644 index 0000000..b9cbce5 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H +#define _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H + +/* GPU_CC clock registers */ +#define GPU_CC_CRC_AHB_CLK 0 +#define GPU_CC_CX_APB_CLK 1 +#define GPU_CC_CX_GFX3D_CLK 2 +#define GPU_CC_CX_GFX3D_SLV_CLK 3 +#define GPU_CC_CX_GMU_CLK 4 +#define GPU_CC_CX_SNOC_DVM_CLK 5 +#define GPU_CC_CXO_CLK 6 +#define GPU_CC_GMU_CLK_SRC 7 +#define GPU_CC_GX_GMU_CLK 8 +#define GPU_CC_GX_GFX3D_CLK_SRC 9 +#define GPU_CC_GX_GFX3D_CLK 10 +#define GPU_CC_PLL0 11 +#define GPU_CC_PLL0_OUT_EVEN 12 +#define GPU_CC_PLL1 13 + +/* GPU_CC Resets */ +#define GPUCC_GPU_CC_ACD_BCR 0 +#define GPUCC_GPU_CC_CX_BCR 1 +#define GPUCC_GPU_CC_GFX3D_AON_BCR 2 +#define GPUCC_GPU_CC_GMU_BCR 3 +#define GPUCC_GPU_CC_GX_BCR 4 +#define GPUCC_GPU_CC_SPDM_BCR 5 +#define GPUCC_GPU_CC_XO_BCR 6 + +/* GPU_CC GDSCRs */ +#define GPU_CX_GDSC 0 +#define GPU_GX_GDSC 1 + +#endif -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-07-12 17:09 [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal ` (2 preceding siblings ...) 2018-07-12 17:09 ` [PATCH v2 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal @ 2018-07-12 17:09 ` Amit Nischal 2018-07-14 0:46 ` kbuild test robot 2018-07-14 3:20 ` kbuild test robot 3 siblings, 2 replies; 7+ messages in thread From: Amit Nischal @ 2018-07-12 17:09 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Add support for the graphics clock controller found on SDM845 based devices. This would allow graphics drivers to probe and control their clocks. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sdm845.c | 438 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 448 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9c3480d..193c2f5 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -235,6 +235,15 @@ config SDM_GCC_845 Say Y if you want to use peripheral devices such as UART, SPI, i2C, USB, UFS, SDDC, PCIe, etc. +config SDM_GPUCC_845 + tristate "SDM845 Graphics Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the graphics clock controller on SDM845 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SDM_VIDEOCC_845 tristate "SDM845 Video Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 32d17c2..8aa2bc9 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c new file mode 100644 index 0000000..7a11b70 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,gpucc-sdm845.h> + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "gdsc.h" + +#define CX_GMU_CBCR_SLEEP_MASK 0xf +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xf +#define CX_GMU_CBCR_WAKE_SHIFT 8 +#define CLK_DIS_WAIT_SHIFT 12 +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll0", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_1[] = { + "bi_tcxo", + "gpu_cc_pll0_out_even", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x1d, + .alpha = 0x2aaa, +}; + +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x1a, + .alpha = 0xaab, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_even", + .parent_names = (const char *[]){ "gpu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_names = gpu_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_gfx3d_ops, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_slv_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x100c, + .clamp_io_ctrl = 0x1508, + .pd = { + .name = "gpu_gx_gdsc", + }, + .clk_hws = { + &gpu_cc_gx_gfx3d_clk_src.clkr.hw, + }, + .clk_count = 1, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *gpu_cc_sdm845_clocks[] = { + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, +}; + +static struct gdsc *gpu_cc_sdm845_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sdm845_desc = { + .config = &gpu_cc_sdm845_regmap_config, + .clks = gpu_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks), + .gdscs = gpu_cc_sdm845_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sdm845_gdscs), +}; + +static const struct of_device_id gpu_cc_sdm845_match_table[] = { + { .compatible = "qcom,sdm845-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table); + +static int gpu_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + unsigned int value, mask; + int ret; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* + * Configure gpu_cc_cx_gmu_clk with recommended + * wakeup/sleep settings + */ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, 0x1098, mask, value); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); + if (ret) + return ret; + + /* Configure clk_dis_wait for gpu_cx_gdsc */ + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, + 8 << CLK_DIS_WAIT_SHIFT); + + /* Set supported range of frequencies for gfx3d clock */ + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000, + 710000000); + + return 0; +} + +static struct platform_driver gpu_cc_sdm845_driver = { + .probe = gpu_cc_sdm845_probe, + .driver = { + .name = "sdm845-gpucc", + .of_match_table = gpu_cc_sdm845_match_table, + }, +}; + +static int __init gpu_cc_sdm845_init(void) +{ + return platform_driver_register(&gpu_cc_sdm845_driver); +} +subsys_initcall(gpu_cc_sdm845_init); + +static void __exit gpu_cc_sdm845_exit(void) +{ + platform_driver_unregister(&gpu_cc_sdm845_driver); +} +module_exit(gpu_cc_sdm845_exit); + +MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-07-12 17:09 ` [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal @ 2018-07-14 0:46 ` kbuild test robot 2018-07-14 3:20 ` kbuild test robot 1 sibling, 0 replies; 7+ messages in thread From: kbuild test robot @ 2018-07-14 0:46 UTC (permalink / raw) Cc: kbuild-all, Stephen Boyd, Michael Turquette, Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal [-- Attachment #1: Type: text/plain, Size: 2447 bytes --] Hi Amit, Thank you for the patch! Yet something to improve: [auto build test ERROR on agross/for-next] [also build test ERROR on v4.18-rc4 next-20180713] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Amit-Nischal/Add-QCOM-graphics-clock-controller-driver-for-SDM845/20180714-080708 base: https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git for-next config: xtensa-allyesconfig (attached as .config) compiler: xtensa-linux-gcc (GCC) 8.1.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree GCC_VERSION=8.1.0 make.cross ARCH=xtensa All error/warnings (new ones prefixed by >>): >> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: implicit declaration of function 'F' [-Werror=implicit-function-declaration] F(19200000, P_BI_TCXO, 1, 0, 0), ^ >> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: initializer element is not constant drivers/clk/qcom/gpucc-sdm845.c:136:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].freq') drivers/clk/qcom/gpucc-sdm845.c:137:2: error: initializer element is not constant F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), ^ drivers/clk/qcom/gpucc-sdm845.c:137:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].src') drivers/clk/qcom/gpucc-sdm845.c:138:2: error: initializer element is not constant F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), ^ drivers/clk/qcom/gpucc-sdm845.c:138:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].pre_div') >> drivers/clk/qcom/gpucc-sdm845.c:139:2: warning: braces around scalar initializer { } ^ drivers/clk/qcom/gpucc-sdm845.c:139:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].m') cc1: some warnings being treated as errors vim +/F +136 drivers/clk/qcom/gpucc-sdm845.c 134 135 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { > 136 F(19200000, P_BI_TCXO, 1, 0, 0), 137 F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), 138 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), > 139 { } 140 }; 141 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 54172 bytes --] ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-07-12 17:09 ` [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 2018-07-14 0:46 ` kbuild test robot @ 2018-07-14 3:20 ` kbuild test robot 1 sibling, 0 replies; 7+ messages in thread From: kbuild test robot @ 2018-07-14 3:20 UTC (permalink / raw) Cc: kbuild-all, Stephen Boyd, Michael Turquette, Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal [-- Attachment #1: Type: text/plain, Size: 2296 bytes --] Hi Amit, Thank you for the patch! Yet something to improve: [auto build test ERROR on agross/for-next] [also build test ERROR on v4.18-rc4 next-20180713] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Amit-Nischal/Add-QCOM-graphics-clock-controller-driver-for-SDM845/20180714-080708 base: https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git for-next config: i386-allmodconfig (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=i386 All errors (new ones prefixed by >>): >> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: implicit declaration of function 'F'; did you mean 'FS'? [-Werror=implicit-function-declaration] F(19200000, P_BI_TCXO, 1, 0, 0), ^ FS drivers/clk/qcom/gpucc-sdm845.c:136:2: error: initializer element is not constant drivers/clk/qcom/gpucc-sdm845.c:136:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].freq') drivers/clk/qcom/gpucc-sdm845.c:137:2: error: initializer element is not constant F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), ^ drivers/clk/qcom/gpucc-sdm845.c:137:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].src') drivers/clk/qcom/gpucc-sdm845.c:138:2: error: initializer element is not constant F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), ^ drivers/clk/qcom/gpucc-sdm845.c:138:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].pre_div') drivers/clk/qcom/gpucc-sdm845.c:139:2: warning: braces around scalar initializer { } ^ drivers/clk/qcom/gpucc-sdm845.c:139:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].m') cc1: some warnings being treated as errors vim +136 drivers/clk/qcom/gpucc-sdm845.c 134 135 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { > 136 F(19200000, P_BI_TCXO, 1, 0, 0), 137 F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), 138 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), 139 { } 140 }; 141 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 64139 bytes --] ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2018-07-14 3:20 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-07-12 17:09 [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-07-12 17:09 ` [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal 2018-07-12 17:09 ` [PATCH v2 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal 2018-07-12 17:09 ` [PATCH v2 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal 2018-07-12 17:09 ` [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 2018-07-14 0:46 ` kbuild test robot 2018-07-14 3:20 ` kbuild test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).