Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] clk: imx: fix integer overflow in AV PLL round rate
From: Stephen Boyd @ 2016-10-28  1:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4d2e3a91dfb74209735c940b51d7efc9ba2ed69b.1476267249.git.emil@limesaudio.com>

On 10/12, Emil Lundmark wrote:
> Since 'parent_rate * mfn' may overflow 32 bits, the result should be
> stored using 64 bits.
> 
> The problem was discovered when trying to set the rate of the audio PLL
> (pll4_post_div) on an i.MX6Q. The desired rate was 196.608 MHz, but
> the actual rate returned was 192.000570 MHz. The round rate function should
> have been able to return 196.608 MHz, i.e., the desired rate.
> 
> Fixes: ba7f4f557eb6 ("clk: imx: correct AV PLL rate formula")
> Cc: Anson Huang <b20788@freescale.com>
> Signed-off-by: Emil Lundmark <emil@limesaudio.com>
> ---

Applied to clk-next

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v3 3/3] clk: stm32f469: Add QSPI clock
From: Stephen Boyd @ 2016-10-28  1:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477041810-12313-4-git-send-email-gabriel.fernandez@st.com>

On 10/21, gabriel.fernandez at st.com wrote:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
> 
> This patch adds the QSPI clock for stm32f469 discovery board.
> The gate mapping is a little bit different from stm32f429 soc.
> 
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---

Applied to clk-next + added Rob's ack from v2.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v3 2/3] clk: stm32f4: Add RTC clock
From: Stephen Boyd @ 2016-10-28  1:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477041810-12313-3-git-send-email-gabriel.fernandez@st.com>

On 10/21, gabriel.fernandez at st.com wrote:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
> 
> This patch introduces the support of the RTC clock.
> RTC clock can have 3 sources: lsi, lse and hse_rtc.
> 
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---

Applied to clk-next

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v3 1/3] clk: stm32f4: Add LSI & LSE clocks
From: Stephen Boyd @ 2016-10-28  1:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477041810-12313-2-git-send-email-gabriel.fernandez@st.com>

On 10/21, gabriel.fernandez at st.com wrote:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
> 
> This patch introduces the support of the LSI & LSE clocks.
> The clock drivers needs to disable the power domain write protection
> using syscon/regmap to enable these clocks.
> 
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---

Applied to clk-next + 

diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index c2661e28eeda..5eb05dbf59b8 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -224,7 +224,7 @@ static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
 						       0x0000000000000003ull,
 						       0x0c777f33f6fec9ffull };
 
-const u64 *stm32f4_gate_map;
+static const u64 *stm32f4_gate_map;
 
 static struct clk_hw **clks;
 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related

* [PATCH v14 1/4] clk: mediatek: Add MT2701 clock support
From: Stephen Boyd @ 2016-10-28  1:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477020742-13889-2-git-send-email-erin.lo@mediatek.com>

On 10/21, Erin Lo wrote:
> diff --git a/drivers/clk/mediatek/clk-mt2701-bdp.c b/drivers/clk/mediatek/clk-mt2701-bdp.c
> new file mode 100644
> index 0000000..dbf6ab2
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt2701-bdp.c
> @@ -0,0 +1,148 @@
> +
> +static int mtk_bdpsys_init(struct platform_device *pdev)
> +{
> +	struct clk_onecell_data *clk_data;
> +	int r;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	clk_data = mtk_alloc_clk_data(CLK_BDP_NR);
> +
> +	mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks),
> +						clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return r;
> +}
> +
> +static const struct of_device_id of_match_clk_mt2701_bdp[] = {
> +	{ .compatible = "mediatek,mt2701-bdpsys", },
> +	{}
> +};
> +
> +static int clk_mt2701_bdp_probe(struct platform_device *pdev)
> +{
> +	int r;
> +
> +	r = mtk_bdpsys_init(pdev);

Why not just put the contents of that function here? I don't see
the point of this.

> +	if (r) {
> +		dev_err(&pdev->dev,
> +			"could not register clock provider: %s: %d\n",
> +			pdev->name, r);
> +	}
> +
> +	return r;
> +}
> +
> +static struct platform_driver clk_mt2701_bdp_drv = {
> +	.probe = clk_mt2701_bdp_probe,
> +	.driver = {
> +		.name = "clk-mt2701-bdp",
> +		.of_match_table = of_match_clk_mt2701_bdp,
> +	},
> +};
> +
> +builtin_platform_driver(clk_mt2701_bdp_drv);
> diff --git a/drivers/clk/mediatek/clk-mt2701-eth.c b/drivers/clk/mediatek/clk-mt2701-eth.c
> new file mode 100644
> index 0000000..b2a71a4
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt2701-eth.c
> @@ -0,0 +1,90 @@
> +/*
> + * Copyright (c) 2014 MediaTek Inc.
> + * Author: Shunli Wang <shunli.wang@mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +
> +#include "clk-mtk.h"
> +#include "clk-gate.h"
> +
> +#include <dt-bindings/clock/mt2701-clk.h>
> +
> +static const struct mtk_gate_regs eth_cg_regs = {
> +	.sta_ofs = 0x0030,
> +};
> +
> +#define GATE_ETH(_id, _name, _parent, _shift) {		\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &eth_cg_regs,			\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\
> +	}
> +
> +static const struct mtk_gate eth_clks[] = {
> +	GATE_ETH(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5),
> +	GATE_ETH(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6),
> +	GATE_ETH(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7),
> +	GATE_ETH(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8),
> +	GATE_ETH(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11),
> +	GATE_ETH(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14),
> +	GATE_ETH(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17),
> +	GATE_ETH(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29),
> +};
> +
> +static int mtk_ethsys_init(struct platform_device *pdev)
> +{
> +	struct clk_onecell_data *clk_data;
> +	int r;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
> +
> +	mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
> +						clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return r;

Just return of_clk_add_provider() please.

> +}
> +
> +static const struct of_device_id of_match_clk_mt2701_eth[] = {
> +	{ .compatible = "mediatek,mt2701-ethsys", },
> +	{}
> +};
> +
> +static int clk_mt2701_eth_probe(struct platform_device *pdev)
> +{
> +	int r;
> +
> +	r = mtk_ethsys_init(pdev);

Same comment.

> +	if (r) {
> +		dev_err(&pdev->dev,
> +			"could not register clock provider: %s: %d\n",
> +			pdev->name, r);
> +	}
> +
> +	return r;
> +}
> +
> +static struct platform_driver clk_mt2701_eth_drv = {
> +	.probe = clk_mt2701_eth_probe,
> +	.driver = {
> +		.name = "clk-mt2701-eth",
> +		.of_match_table = of_match_clk_mt2701_eth,
> +	},
> +};
> +
> +builtin_platform_driver(clk_mt2701_eth_drv);
> diff --git a/drivers/clk/mediatek/clk-mt2701-hif.c b/drivers/clk/mediatek/clk-mt2701-hif.c
> new file mode 100644
> index 0000000..e2b0039
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt2701-hif.c
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright (c) 2014 MediaTek Inc.
> + * Author: Shunli Wang <shunli.wang@mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +
> +#include "clk-mtk.h"
> +#include "clk-gate.h"
> +
> +#include <dt-bindings/clock/mt2701-clk.h>
> +
> +static const struct mtk_gate_regs hif_cg_regs = {
> +	.sta_ofs = 0x0030,
> +};
> +
> +#define GATE_HIF(_id, _name, _parent, _shift) {		\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &hif_cg_regs,			\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\
> +	}
> +
> +static const struct mtk_gate hif_clks[] = {
> +	GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21),
> +	GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22),
> +	GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24),
> +	GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25),
> +	GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26),
> +};
> +
> +static int mtk_hifsys_init(struct platform_device *pdev)
> +{
> +	struct clk_onecell_data *clk_data;
> +	int r;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
> +
> +	mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks),
> +						clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return r;

Just return of_clk_add_provider() please.

> +}
> +
> +static const struct of_device_id of_match_clk_mt2701_hif[] = {
> +	{ .compatible = "mediatek,mt2701-hifsys", },
> +	{}
> +};
> +
> +static int clk_mt2701_hif_probe(struct platform_device *pdev)
> +{
> +	int r;
> +
> +	r = mtk_hifsys_init(pdev);

There's a pattern. Same comments apply for everything that uses
this style.

> +	if (r) {
> +		dev_err(&pdev->dev,
> +			"could not register clock provider: %s: %d\n",
> +			pdev->name, r);
> +	}
> +
> +	return r;
> +}
> +
> +static struct platform_driver clk_mt2701_hif_drv = {
> +	.probe = clk_mt2701_hif_probe,
> +	.driver = {
> +		.name = "clk-mt2701-hif",
> +		.of_match_table = of_match_clk_mt2701_hif,
> +	},
> +};
> +
> +builtin_platform_driver(clk_mt2701_hif_drv);
[cut a bunch of same drivers]
> diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
> new file mode 100644
> index 0000000..c225256
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt2701.c
> @@ -0,0 +1,1046 @@
> +/*
> + * Copyright (c) 2014 MediaTek Inc.
> + * Author: Shunli Wang <shunli.wang@mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +#include "clk-mtk.h"
> +#include "clk-gate.h"
> +
> +#include <dt-bindings/clock/mt2701-clk.h>
> +
> +/*
> + * For some clocks, we don't care what their actual rates are. And these
> + * clocks may change their rate on different products or different scenarios.
> + * So we model these clocks' rate as 0, to denote it's not an actual rate.
> + */
> +#define DUMMY_RATE		0
> +
> +static DEFINE_SPINLOCK(lock);

Please name this something more mtk specific. mt2701_clk_lock?

> +
> +static const struct mtk_fixed_clk top_fixed_clks[] = {
> +	FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m",
> +		108 * MHZ),
> +	FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m",
> +		400 * MHZ),
> +	FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m",
> +		295750000),
> +	FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m",
> +		340 * MHZ),
> +	FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m",
> +		340 * MHZ),
> +	FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m",
> +		340 * MHZ),
> +	FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m",
> +		300 * MHZ),
> +	FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m",
> +		27 * MHZ),
> +	FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m",
> +		416 * MHZ),
> +	FIXED_CLK(CLK_TOP_DSI0_LNTC_DSI, "dsi0_lntc_dsi", "clk26m",
> +		143 * MHZ),
> +	FIXED_CLK(CLK_TOP_HDMI_SCL_RX, "hdmi_scl_rx", "clk26m",
> +		27 * MHZ),
> +	FIXED_CLK(CLK_TOP_AUD_EXT1, "aud_ext1", "clk26m",
> +		DUMMY_RATE),
> +	FIXED_CLK(CLK_TOP_AUD_EXT2, "aud_ext2", "clk26m",
> +		DUMMY_RATE),
> +	FIXED_CLK(CLK_TOP_NFI1X_PAD, "nfi1x_pad", "clk26m",
> +		DUMMY_RATE),
> +};
> +
> +static const struct mtk_fixed_factor top_fixed_divs[] = {
> +	FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1),
> +	FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
> +	FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3),
> +	FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
> +	FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7),
> +	FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2),
> +	FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4),
> +	FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8),
> +	FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16),
> +	FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2),
> +	FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4),
> +	FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8),
> +	FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2),
> +	FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4),
> +	FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2),
> +	FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4),
> +
> +	FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1),
> +	FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
> +	FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
> +	FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
> +	FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
> +	FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26),
> +	FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52),
> +	FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108),
> +	FACTOR(CLK_TOP_USB_PHY48M, "usb_phy48m_ck", "univpll", 1, 26),
> +	FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2),
> +	FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4),
> +	FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8),
> +	FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1),
> +	FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2),
> +	FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4),
> +	FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8),
> +	FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16),
> +	FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32),
> +	FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2),
> +	FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4),
> +	FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8),
> +
> +	FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
> +	FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
> +	FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
> +	FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8),
> +
> +	FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
> +	FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
> +
> +	FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2),
> +	FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4),
> +	FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1),
> +
> +	FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1),
> +	FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2),
> +	FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4),
> +
> +	FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1),
> +	FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1),
> +	FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2),
> +
> +	FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1),
> +	FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2),
> +	FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4),
> +
> +	FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1),
> +	FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2),
> +	FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3),
> +
> +	FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1),
> +
> +	FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1),
> +	FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4),
> +	FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8),
> +	FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16),
> +	FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24),
> +
> +	FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3),
> +	FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3),
> +	FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3),
> +	FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1),
> +	FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1),
> +	FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8),
> +	FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793),
> +	FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1),
> +};
> +
> +static const char * const axi_parents[] = {
> +	"clk26m",
> +	"syspll1_d2",
> +	"syspll_d5",
> +	"syspll1_d4",
> +	"univpll_d5",
> +	"univpll2_d2",
> +	"mmpll_d2",
> +	"dmpll_d2"
> +};
> +
> +static const char * const mem_parents[] = {
> +	"clk26m",
> +	"dmpll_ck"
> +};
> +
> +static const char * const ddrphycfg_parents[] = {
> +	"clk26m",
> +	"syspll1_d8"
> +};
> +
> +static const char * const mm_parents[] = {
> +	"clk26m",
> +	"vencpll_ck",
> +	"syspll1_d2",
> +	"syspll1_d4",
> +	"univpll_d5",
> +	"univpll1_d2",
> +	"univpll2_d2",
> +	"dmpll_ck"
> +};
> +
> +static const char * const pwm_parents[] = {
> +	"clk26m",
> +	"univpll2_d4",
> +	"univpll3_d2",
> +	"univpll1_d4",
> +};
> +
> +static const char * const vdec_parents[] = {
> +	"clk26m",
> +	"vdecpll_ck",
> +	"syspll_d5",
> +	"syspll1_d4",
> +	"univpll_d5",
> +	"univpll2_d2",
> +	"vencpll_ck",
> +	"msdcpll_d2",
> +	"mmpll_d2"
> +};
> +
> +static const char * const mfg_parents[] = {
> +	"clk26m",
> +	"mmpll_ck",
> +	"dmpll_x2_ck",
> +	"msdcpll_ck",
> +	"clk26m",
> +	"syspll_d3",
> +	"univpll_d3",
> +	"univpll1_d2"
> +};
> +
> +static const char * const camtg_parents[] = {
> +	"clk26m",
> +	"univpll_d26",
> +	"univpll2_d2",
> +	"syspll3_d2",
> +	"syspll3_d4",
> +	"msdcpll_d2",
> +	"mmpll_d2"
> +};
> +
> +static const char * const uart_parents[] = {
> +	"clk26m",
> +	"univpll2_d8"
> +};
> +
> +static const char * const spi_parents[] = {
> +	"clk26m",
> +	"syspll3_d2",
> +	"syspll4_d2",
> +	"univpll2_d4",
> +	"univpll1_d8"
> +};
> +
> +static const char * const usb20_parents[] = {
> +	"clk26m",
> +	"univpll1_d8",
> +	"univpll3_d4"
> +};
> +
> +static const char * const msdc30_parents[] = {
> +	"clk26m",
> +	"msdcpll_d2",
> +	"syspll2_d2",
> +	"syspll1_d4",
> +	"univpll1_d4",
> +	"univpll2_d4"
> +};
> +
> +static const char * const audio_parents[] = {
> +	"clk26m",
> +	"syspll1_d16"
> +};
> +
> +static const char * const aud_intbus_parents[] = {
> +	"clk26m",
> +	"syspll1_d4",
> +	"syspll3_d2",
> +	"syspll4_d2",
> +	"univpll3_d2",
> +	"univpll2_d4"
> +};
> +
> +static const char * const pmicspi_parents[] = {
> +	"clk26m",
> +	"syspll1_d8",
> +	"syspll2_d4",
> +	"syspll4_d2",
> +	"syspll3_d4",
> +	"syspll2_d8",
> +	"syspll1_d16",
> +	"univpll3_d4",
> +	"univpll_d26",
> +	"dmpll_d2",
> +	"dmpll_d4"
> +};
> +
> +static const char * const scp_parents[] = {
> +	"clk26m",
> +	"syspll1_d8",
> +	"dmpll_d2",
> +	"dmpll_d4"
> +};
> +
> +static const char * const dpi0_parents[] = {
> +	"clk26m",
> +	"mipipll",
> +	"mipipll_d2",
> +	"mipipll_d4",
> +	"clk26m",
> +	"tvdpll_ck",
> +	"tvdpll_d2",
> +	"tvdpll_d4"
> +};
> +
> +static const char * const dpi1_parents[] = {
> +	"clk26m",
> +	"tvdpll_ck",
> +	"tvdpll_d2",
> +	"tvdpll_d4"
> +};
> +
> +static const char * const tve_parents[] = {
> +	"clk26m",
> +	"mipipll",
> +	"mipipll_d2",
> +	"mipipll_d4",
> +	"clk26m",
> +	"tvdpll_ck",
> +	"tvdpll_d2",
> +	"tvdpll_d4"
> +};
> +
> +static const char * const hdmi_parents[] = {
> +	"clk26m",
> +	"hdmipll_ck",
> +	"hdmipll_d2",
> +	"hdmipll_d3"
> +};
> +
> +static const char * const apll_parents[] = {
> +	"clk26m",
> +	"audpll",
> +	"audpll_d4",
> +	"audpll_d8",
> +	"audpll_d16",
> +	"audpll_d24",
> +	"clk26m",
> +	"clk26m"
> +};
> +
> +static const char * const rtc_parents[] = {
> +	"32k_internal",
> +	"32k_external",
> +	"clk26m",
> +	"univpll3_d8"
> +};
> +
> +static const char * const nfi2x_parents[] = {
> +	"clk26m",
> +	"syspll2_d2",
> +	"syspll_d7",
> +	"univpll3_d2",
> +	"syspll2_d4",
> +	"univpll3_d4",
> +	"syspll4_d4",
> +	"clk26m"
> +};
> +
> +static const char * const emmc_hclk_parents[] = {
> +	"clk26m",
> +	"syspll1_d2",
> +	"syspll1_d4",
> +	"syspll2_d2"
> +};
> +
> +static const char * const flash_parents[] = {
> +	"clk26m_d8",
> +	"clk26m",
> +	"syspll2_d8",
> +	"syspll3_d4",
> +	"univpll3_d4",
> +	"syspll4_d2",
> +	"syspll2_d4",
> +	"univpll2_d4"
> +};
> +
> +static const char * const di_parents[] = {
> +	"clk26m",
> +	"tvd2pll_ck",
> +	"tvd2pll_d2",
> +	"clk26m"
> +};
> +
> +static const char * const nr_osd_parents[] = {
> +	"clk26m",
> +	"vencpll_ck",
> +	"syspll1_d2",
> +	"syspll1_d4",
> +	"univpll_d5",
> +	"univpll1_d2",
> +	"univpll2_d2",
> +	"dmpll_ck"
> +};
> +
> +static const char * const hdmirx_bist_parents[] = {
> +	"clk26m",
> +	"syspll_d3",
> +	"clk26m",
> +	"syspll1_d16",
> +	"syspll4_d2",
> +	"syspll1_d4",
> +	"vencpll_ck",
> +	"clk26m"
> +};
> +
> +static const char * const intdir_parents[] = {
> +	"clk26m",
> +	"mmpll_ck",
> +	"syspll_d2",
> +	"univpll_d2"
> +};
> +
> +static const char * const asm_parents[] = {
> +	"clk26m",
> +	"univpll2_d4",
> +	"univpll2_d2",
> +	"syspll_d5"
> +};
> +
> +static const char * const ms_card_parents[] = {
> +	"clk26m",
> +	"univpll3_d8",
> +	"syspll4_d4"
> +};
> +
> +static const char * const ethif_parents[] = {
> +	"clk26m",
> +	"syspll1_d2",
> +	"syspll_d5",
> +	"syspll1_d4",
> +	"univpll_d5",
> +	"univpll1_d2",
> +	"dmpll_ck",
> +	"dmpll_d2"
> +};
> +
> +static const char * const hdmirx_parents[] = {
> +	"clk26m",
> +	"univpll_d52"
> +};
> +
> +static const char * const cmsys_parents[] = {
> +	"clk26m",
> +	"syspll1_d2",
> +	"univpll1_d2",
> +	"univpll_d5",
> +	"syspll_d5",
> +	"syspll2_d2",
> +	"syspll1_d4",
> +	"syspll3_d2",
> +	"syspll2_d4",
> +	"syspll1_d8",
> +	"clk26m",
> +	"clk26m",
> +	"clk26m",
> +	"clk26m",
> +	"clk26m"
> +};
> +
> +static const char * const clk_8bdac_parents[] = {
> +	"32k_internal",
> +	"8bdac_ck",
> +	"clk26m",
> +	"clk26m"
> +};
> +
> +static const char * const aud2dvd_parents[] = {
> +	"a1sys_hp_ck",
> +	"a2sys_hp_ck"
> +};
> +
> +static const char * const padmclk_parents[] = {
> +	"clk26m",
> +	"univpll_d26",
> +	"univpll_d52",
> +	"univpll_d108",
> +	"univpll2_d8",
> +	"univpll2_d16",
> +	"univpll2_d32"
> +};
> +
> +static const char * const aud_mux_parents[] = {
> +	"clk26m",
> +	"aud1pll_98m_ck",
> +	"aud2pll_90m_ck",
> +	"hadds2pll_98m",
> +	"audio_ext1_ck",
> +	"audio_ext2_ck"
> +};
> +
> +static const char * const aud_src_parents[] = {
> +	"aud_mux1_sel",
> +	"aud_mux2_sel"
> +};
> +
> +static const char * const cpu_parents[] = {
> +	"clk26m",
> +	"armpll",
> +	"mainpll",
> +	"mmpll"
> +};
> +
> +static const struct mtk_composite top_muxes[] = {
> +	MUX_GATE_FLAGS(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
> +		0x0040, 0, 3, 7, CLK_IS_CRITICAL),
> +	MUX_GATE_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents,
> +		0x0040, 8, 1, 15, CLK_IS_CRITICAL),
> +	MUX_GATE_FLAGS(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel",
> +		ddrphycfg_parents, 0x0040, 16, 1, 23, CLK_IS_CRITICAL),
> +	MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents,
> +		0x0040, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents,
> +		0x0050, 0, 2, 7),
> +	MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents,
> +		0x0050, 8, 4, 15),
> +	MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents,
> +		0x0050, 16, 3, 23),
> +	MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents,
> +		0x0050, 24, 3, 31),
> +	MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents,
> +		0x0060, 0, 1, 7),
> +
> +	MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents,
> +		0x0060, 8, 3, 15),
> +	MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents,
> +		0x0060, 16, 2, 23),
> +	MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents,
> +		0x0060, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents,
> +		0x0070, 0, 3, 7),
> +	MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents,
> +		0x0070, 8, 3, 15),
> +	MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents,
> +		0x0070, 16, 1, 23),
> +	MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents,
> +		0x0070, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents,
> +		0x0080, 0, 4, 7),
> +	MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents,
> +		0x0080, 8, 2, 15),
> +	MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents,
> +		0x0080, 16, 3, 23),
> +	MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents,
> +		0x0080, 24, 2, 31),
> +
> +	MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents,
> +		0x0090, 0, 3, 7),
> +	MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents,
> +		0x0090, 8, 2, 15),
> +	MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents,
> +		0x0090, 16, 3, 23),
> +
> +	MUX_GATE_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents,
> +		0x00A0, 0, 2, 7, CLK_IS_CRITICAL),
> +	MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents,
> +		0x00A0, 8, 3, 15),
> +	MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents,
> +		0x00A0, 24, 2, 31),
> +
> +	MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents,
> +		0x00B0, 0, 3, 7),
> +	MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents,
> +		0x00B0, 8, 2, 15),
> +	MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents,
> +		0x00B0, 16, 3, 23),
> +	MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents,
> +		0x00B0, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel",
> +		hdmirx_bist_parents, 0x00C0, 0, 3, 7),
> +	MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents,
> +		0x00C0, 8, 2, 15),
> +	MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents,
> +		0x00C0, 16, 2, 23),
> +	MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents,
> +		0x00C0, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents,
> +		0x00D0, 0, 2, 7),
> +	MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents,
> +		0x00D0, 16, 2, 23),
> +	MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents,
> +		0x00D0, 24, 3, 31),
> +
> +	MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents,
> +		0x00E0, 0, 1, 7),
> +	MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents,
> +		0x00E0, 8, 3, 15),
> +	MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents,
> +		0x00E0, 16, 4, 23),
> +
> +	MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents,
> +		0x00E0, 24, 3, 31),
> +	MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents,
> +		0x00F0, 0, 3, 7),
> +	MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents,
> +		0x00F0, 8, 2, 15),
> +	MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents,
> +		0x00F0, 16, 1, 23),
> +
> +	MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents,
> +		0x0100, 0, 3),
> +
> +	MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents,
> +		0x012c, 0, 3),
> +	MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents,
> +		0x012c, 3, 3),
> +	MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents,
> +		0x012c, 6, 3),
> +	MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents,
> +		0x012c, 15, 1, 23),
> +	MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents,
> +		0x012c, 16, 1, 24),
> +	MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents,
> +		0x012c, 17, 1, 25),
> +	MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents,
> +		0x012c, 18, 1, 26),
> +	MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents,
> +		0x012c, 19, 1, 27),
> +	MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents,
> +		0x012c, 20, 1, 28),
> +};
> +
> +static const struct mtk_clk_divider top_adj_divs[] = {
> +	DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext1",
> +		0x0120, 0, 8),
> +	DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext2",
> +		0x0120, 8, 8),
> +	DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel",
> +		0x0120, 16, 8),
> +	DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel",
> +		0x0120, 24, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel",
> +		0x0124, 0, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel",
> +		0x0124, 8, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel",
> +		0x0124, 16, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel",
> +		0x0124, 24, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel",
> +		0x0128, 0, 8),
> +	DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel",
> +		0x0128, 8, 8),
> +};
> +
> +static const struct mtk_gate_regs top_aud_cg_regs = {
> +	.sta_ofs = 0x012C,
> +};
> +
> +#define GATE_TOP_AUD(_id, _name, _parent, _shift) {	\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &top_aud_cg_regs,		\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_no_setclr,	\
> +	}
> +
> +static const struct mtk_gate top_clks[] = {
> +	GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div",
> +		21),
> +	GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div",
> +		22),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div",
> +		23),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div",
> +		24),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div",
> +		25),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div",
> +		26),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div",
> +		27),
> +	GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div",
> +		28),
> +};
> +
> +void __iomem *devm_of_iomap(struct device *dev, int index)

Sorry what is this?

> +{
> +	struct resource res;
> +
> +	if (!dev)
> +		return NULL;
> +
> +	if (of_address_to_resource(dev->of_node, index, &res))
> +		return NULL;
> +
> +	return devm_ioremap(dev, res.start, resource_size(&res));

Can't we just use platform_get_resouce() and
devm_ioremap_resource() here? It looks like we always have a
platform device.

> +}
> +
> +static int mtk_topckgen_init(struct platform_device *pdev)
> +{
> +	struct clk_onecell_data *clk_data;
> +	void __iomem *base;
> +	int r;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	base = devm_of_iomap(&pdev->dev, 0);
> +	if (!base)
> +		return -ENOMEM;
> +
> +	clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
> +
> +	mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
> +								clk_data);
> +
> +	mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
> +								clk_data);
> +
> +	mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
> +				base, &lock, clk_data);
> +
> +	mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
> +				base, &lock, clk_data);
> +
> +	mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
> +						clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return r;
> +}
> +
> +static const struct mtk_gate_regs infra_cg_regs = {
> +	.set_ofs = 0x0040,
> +	.clr_ofs = 0x0044,
> +	.sta_ofs = 0x0048,
> +};
> +
> +#define GATE_ICG(_id, _name, _parent, _shift) {		\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &infra_cg_regs,			\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_setclr,	\
> +	}
> +
> +static const struct mtk_gate infra_clks[] = {
> +	GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0),
> +	GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1),
> +	GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2),
> +	GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2pll_294m", 4),
> +	GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk26m", 5),
> +	GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6),
> +	GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7),
> +	GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
> +	GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12),
> +	GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13),
> +	GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14),
> +	GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15),
> +	GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16),
> +	GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18),
> +	GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19),
> +	GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22),
> +	GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23),
> +	GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24),
> +};
> +
> +static const struct mtk_fixed_factor infra_fixed_divs[] = {
> +	FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2),
> +};
> +
> +static struct clk_onecell_data *infra_clk_data;
> +
> +static void mtk_infrasys_init_early(struct device_node *node)
> +{
> +	int r, i;
> +
> +	if (!infra_clk_data) {
> +		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
> +
> +		for (i = 0; i < CLK_INFRA_NR; i++)
> +			infra_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER);
> +	}
> +
> +	mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
> +						infra_clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data);
> +	if (r)
> +		pr_err("%s(): could not register clock provider: %d\n",
> +			__func__, r);
> +}
> +CLK_OF_DECLARE_DRIVER(mtk_infra, "mediatek,mt2701-infracfg",
> +			mtk_infrasys_init_early);
> +
> +static int mtk_infrasys_init(struct platform_device *pdev)
> +{
> +	int r, i;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	if (!infra_clk_data) {
> +		infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
> +	} else {
> +		for (i = 0; i < CLK_INFRA_NR; i++) {
> +			if (infra_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER))
> +				infra_clk_data->clks[i] = ERR_PTR(-ENOENT);
> +		}
> +	}
> +
> +	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
> +						infra_clk_data);
> +	mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
> +						infra_clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data);
> +
> +	return r;
> +}
> +
> +static const struct mtk_gate_regs peri0_cg_regs = {
> +	.set_ofs = 0x0008,
> +	.clr_ofs = 0x0010,
> +	.sta_ofs = 0x0018,
> +};
> +
> +static const struct mtk_gate_regs peri1_cg_regs = {
> +	.set_ofs = 0x000c,
> +	.clr_ofs = 0x0014,
> +	.sta_ofs = 0x001c,
> +};
> +
> +#define GATE_PERI0(_id, _name, _parent, _shift) {	\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &peri0_cg_regs,			\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_setclr,	\
> +	}
> +
> +#define GATE_PERI1(_id, _name, _parent, _shift) {	\
> +		.id = _id,				\
> +		.name = _name,				\
> +		.parent_name = _parent,			\
> +		.regs = &peri1_cg_regs,			\
> +		.shift = _shift,			\
> +		.ops = &mtk_clk_gate_ops_setclr,	\
> +	}
> +
> +static const struct mtk_gate peri_clks[] = {
> +	GATE_PERI0(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31),
> +	GATE_PERI0(CLK_PERI_ETH, "eth_ck", "clk26m", 30),
> +	GATE_PERI0(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29),
> +	GATE_PERI0(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28),
> +	GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27),
> +	GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26),
> +	GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25),
> +	GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24),
> +	GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23),
> +	GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22),
> +	GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21),
> +	GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20),
> +	GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19),
> +	GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18),
> +	GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17),
> +	GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16),
> +	GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15),
> +	GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14),
> +	GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13),
> +	GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
> +	GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
> +	GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
> +	GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
> +	GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
> +	GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
> +	GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
> +	GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
> +	GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
> +	GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
> +	GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
> +	GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
> +	GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0),
> +
> +	GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card_sel", 11),
> +	GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10),
> +	GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9),
> +	GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8),
> +	GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7),
> +	GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6),
> +	GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5),
> +	GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi1x_pad", 4),
> +	GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi1x_pad", 3),
> +	GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2),
> +	GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1),
> +	GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0),
> +};
> +
> +static const char * const uart_ck_sel_parents[] = {
> +	"clk26m",
> +	"uart_sel",
> +};
> +
> +static const struct mtk_composite peri_muxs[] = {
> +	MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents,
> +		0x40c, 0, 1),
> +	MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents,
> +		0x40c, 1, 1),
> +	MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents,
> +		0x40c, 2, 1),
> +	MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents,
> +		0x40c, 3, 1),
> +};
> +
> +static int mtk_pericfg_init(struct platform_device *pdev)
> +{
> +	struct clk_onecell_data *clk_data;
> +	void __iomem *base;
> +	int r;
> +	struct device_node *node = pdev->dev.of_node;
> +
> +	base = devm_of_iomap(&pdev->dev, 0);
> +	if (!base)
> +		return -ENOMEM;
> +
> +	clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
> +
> +	mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
> +						clk_data);
> +
> +	mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
> +			&lock, clk_data);
> +
> +	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return r;

Just return of_clk_add_provider()?

> +}
[...]
> +
> +static int clk_mt2701_probe(struct platform_device *pdev)
> +{
> +	int (*clk_init)(struct platform_device *);
> +	int r;
> +
> +	clk_init = of_device_get_match_data(&pdev->dev);
> +	if (!clk_init)
> +		return -EINVAL;
> +
> +	r = clk_init(pdev);
> +	if (r) {
> +		dev_err(&pdev->dev,
> +			"could not register clock provider: %s: %d\n",
> +			pdev->name, r);
> +	}

Braces are unnecessary.

> +
> +	return r;
> +}
> +
> +static struct platform_driver clk_mt2701_drv = {
> +	.probe = clk_mt2701_probe,
> +	.driver = {
> +		.name = "clk-mt2701",
> +		.owner = THIS_MODULE,

This is unnecessary because platform_driver_register() already
does it.

> +		.of_match_table = of_match_clk_mt2701,
> +	},
> +};
> +
> +static int __init clk_mt2701_init(void)
> +{
> +	return platform_driver_register(&clk_mt2701_drv);
> +}
> +
> +arch_initcall(clk_mt2701_init);
> diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
> index bb30f70..0541df7 100644
> --- a/drivers/clk/mediatek/clk-mtk.c
> +++ b/drivers/clk/mediatek/clk-mtk.c
> @@ -58,6 +58,9 @@ void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
>  	for (i = 0; i < num; i++) {
>  		const struct mtk_fixed_clk *rc = &clks[i];
>  
> +		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
> +			continue;
> +
>  		clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
>  					      rc->rate);
>  
> @@ -81,6 +84,9 @@ void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
>  	for (i = 0; i < num; i++) {
>  		const struct mtk_fixed_factor *ff = &clks[i];
>  
> +		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
> +			continue;
> +
>  		clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
>  				CLK_SET_RATE_PARENT, ff->mult, ff->div);
>  
> @@ -116,6 +122,9 @@ int mtk_clk_register_gates(struct device_node *node,
>  	for (i = 0; i < num; i++) {
>  		const struct mtk_gate *gate = &clks[i];
>  
> +		if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
> +			continue;
> +
>  		clk = mtk_clk_register_gate(gate->name, gate->parent_name,
>  				regmap,
>  				gate->regs->set_ofs,
> @@ -232,6 +241,9 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs,
>  	for (i = 0; i < num; i++) {
>  		const struct mtk_composite *mc = &mcs[i];
>  
> +		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
> +			continue;
> +
>  		clk = mtk_clk_register_composite(mc, base, lock);
>  
>  		if (IS_ERR(clk)) {
> @@ -244,3 +256,31 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs,
>  			clk_data->clks[mc->id] = clk;
>  	}
>  }
> +
> +void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
> +			int num, void __iomem *base, spinlock_t *lock,
> +				struct clk_onecell_data *clk_data)
> +{
> +	struct clk *clk;
> +	int i;
> +
> +	for (i = 0; i <  num; i++) {
> +		const struct mtk_clk_divider *mcd = &mcds[i];
> +
> +		if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))

NULL is a valid clk. IS_ERR_OR_NULL is usually wrong.

> +			continue;
> +
> +		clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
> +			mcd->flags, base +  mcd->div_reg, mcd->div_shift,
> +			mcd->div_width, mcd->clk_divider_flags, lock);
> +
> +		if (IS_ERR(clk)) {
> +			pr_err("Failed to register clk %s: %ld\n",
> +				mcd->name, PTR_ERR(clk));
> +			continue;
> +		}
> +
> +		if (clk_data)
> +			clk_data->clks[mcd->id] = clk;
> +	}
> +}
> diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
> index 9f24fcf..f5d6b70 100644
> --- a/drivers/clk/mediatek/clk-mtk.h
> +++ b/drivers/clk/mediatek/clk-mtk.h
> @@ -87,7 +87,8 @@ struct mtk_composite {
>   * In case the rate change propagation to parent clocks is undesirable,
>   * this macro allows to specify the clock flags manually.
>   */
> -#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, _flags) {	\
> +#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width,	\
> +			_gate, _flags) {				\
>  		.id = _id,						\
>  		.name = _name,						\
>  		.mux_reg = _reg,					\
> @@ -106,7 +107,8 @@ struct mtk_composite {
>   * parent clock by default.
>   */
>  #define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate)	\
> -	MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, CLK_SET_RATE_PARENT)
> +	MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width,	\
> +		_gate, CLK_SET_RATE_PARENT)
>  
>  #define MUX(_id, _name, _parents, _reg, _shift, _width) {		\
>  		.id = _id,						\
> @@ -121,7 +123,8 @@ struct mtk_composite {
>  		.flags = CLK_SET_RATE_PARENT,				\
>  	}
>  
> -#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) {	\
> +#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,	\
> +					_div_width, _div_shift) {	\

Did anything actually change? Checkpatch fix?

>  		.id = _id,						\
>  		.parent = _parent,					\
>  		.name = _name,						\
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCHv4 00/15] clk: ti: add support for hwmod clocks
From: Stephen Boyd @ 2016-10-28  0:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476805568-19264-1-git-send-email-t-kristo@ti.com>

On 10/18, Tero Kristo wrote:
> Hi,
> 
> As a recap, this series is part of the ongoing work to get rid of the
> hwmod database under mach-omap2 folder. This series converts the
> existing clock related functionality to a new clock type, which will
> allow removing all the .clkctrl related items from hwmod database.
> This series adds sample solution for OMAP4 only, rest of the SoCs can
> be converted automatically once the approach is acceptable.
> 
> v4 has the following high level changes compared to v3:
> - Clock data is now statically built-in to the driver
> - Adds clockdomain provider support, which can be used to fetch
>   clocks based on clockdomain relation. Only clockdomains need to be
>   registered within DT.
> - Added some automatic clock alias generation support to the TI clock
>   drivers, if this is not acceptable, I can change this to add all the
>   aliases under the individual drivers/clk/ti/clk-xyz.c files

Is there a plan to get rid of the aliases entirely? Or we can't
do that because DT is not fully supported on these platforms? I'm
mostly wondering how long that sort of code is going to stick
around and if it's better to fully compartmentalize it to the
SoCs that are affected or if it should be a core feature of TI
driver.

> - As a sample, only omap4 clock data is available with this set
> 
> After this series, the clock data can be dropped from the hwmod database
> for OMAP4, I have working patches for this for anybody interested. Also,
> the DT files require some modifications to add proper support for
> clockdomain providers, and drop some unnecessary clock nodes.

Can this be shared as a git tree on the web? Hopefully I can see
the resulting DTS and understand what's going on better.

> 
> Boot + simple PM test seems to be working on OMAP4 with this set, and
> boot test with other boards I have access to don't seem to cause any
> issues. Applies on top of 4.9-rc1.
> 

Awesome!

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCHv4 11/15] clk: ti: clockdomain: add clock provider support to clockdomains
From: Stephen Boyd @ 2016-10-28  0:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476805568-19264-12-git-send-email-t-kristo@ti.com>

On 10/18, Tero Kristo wrote:
> Clockdomains can now be used as clock providers in the system. This
> patch initializes the provider data during init, and parses the clocks
> while they are being registered. An xlate function for the provider
> is also given.
> 
> Signed-off-by: Tero Kristo <t-kristo@ti.com>

Please Cc dt reviewers on binding updates. I suppose a PRCM is
like an MFD that has clocks and resets under it? On other
platforms we've combined that all into one node and just had
#clock-cells and #reset-cells in that node. Is there any reason
we can't do that here?

> ---
>  .../devicetree/bindings/arm/omap/prcm.txt          |  13 ++
>  .../devicetree/bindings/clock/ti/clockdomain.txt   |  12 +-
>  arch/arm/mach-omap2/io.c                           |   2 +
>  drivers/clk/ti/clock.h                             |   1 +
>  drivers/clk/ti/clockdomain.c                       | 147 +++++++++++++++++++++
>  include/linux/clk/ti.h                             |   3 +
>  6 files changed, 177 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/arm/omap/prcm.txt b/Documentation/devicetree/bindings/arm/omap/prcm.txt
> index 3eb6d7a..301f576 100644
> --- a/Documentation/devicetree/bindings/arm/omap/prcm.txt
> +++ b/Documentation/devicetree/bindings/arm/omap/prcm.txt
> @@ -47,6 +47,19 @@ cm: cm at 48004000 {
>  	};
>  }
>  
> +cm2: cm2 at 8000 {
> +	compatible = "ti,omap4-cm2";
> +	reg = <0x8000 0x3000>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	ranges = <0 0x8000 0x3000>;
> +
> +	l4_per_clkdm: l4_per_clkdm {
> +		compatible = "ti,clockdomain";
> +		reg = <0x1400 0x200>;

Should there be #clock-cells = <1> here? Also node name should
have an @1400 after it?

> +	};
> +};
> +
>  &cm_clocks {
>  	omap2_32k_fck: omap_32k_fck {
>  		#clock-cells = <0>;
> diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
> index cb76b3f..5d8ca61 100644
> --- a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
> +++ b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
> @@ -14,11 +14,21 @@ hardware hierarchy.
>  
>  Required properties:
>  - compatible : shall be "ti,clockdomain"
> -- #clock-cells : from common clock binding; shall be set to 0.
> +- #clock-cells : from common clock binding; shall be set to 1 if this
> +		 clockdomain acts as a clock provider.
> +
> +Optional properties:
>  - clocks : link phandles of clocks within this domain
> +- reg : address for the clockdomain
>  
>  Examples:
>  	dss_clkdm: dss_clkdm {
>  		compatible = "ti,clockdomain";
>  		clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
>  	};
> +
> +	l4_per_clkdm: l4_per_clkdm {

add an @1400?

> +		compatible = "ti,clockdomain";
> +		#clock-cells = <1>;
> +		reg = <0x1400 0x200>;
> +	};
> diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
> index 0e9acdd..c1a5cfb 100644
> --- a/arch/arm/mach-omap2/io.c
> +++ b/arch/arm/mach-omap2/io.c
> @@ -794,6 +794,8 @@ int __init omap_clk_init(void)
>  		if (ret)
>  			return ret;
>  
> +		ti_dt_clockdomains_early_setup();
> +
>  		of_clk_init(NULL);
>  
>  		ti_dt_clk_init_retry_clks();
> diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
> index 9b8a5f2..f6383ab 100644
> --- a/drivers/clk/ti/clock.h
> +++ b/drivers/clk/ti/clock.h
> @@ -205,6 +205,7 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw,
>  
>  int ti_clk_get_memmap_index(struct device_node *node);
>  void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
> +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset);
>  void ti_dt_clocks_register(struct ti_dt_clk *oclks);
>  int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
>  		      ti_of_clk_init_cb_t func);
> diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c
> index 704157d..7b0a6c3 100644
> --- a/drivers/clk/ti/clockdomain.c
> +++ b/drivers/clk/ti/clockdomain.c
> @@ -28,6 +28,23 @@
>  #define pr_fmt(fmt) "%s: " fmt, __func__
>  
>  /**
> + * struct ti_clkdm - TI clockdomain data structure
> + * @name: name of the clockdomain
> + * @index: index of the clk_iomap struct for this clkdm
> + * @offset: clockdomain offset from the beginning of the iomap
> + * @link: link to the list
> + */
> +struct ti_clkdm {
> +	const char *name;
> +	int index;
> +	u32 offset;
> +	struct list_head link;
> +	struct list_head clocks;
> +};
> +
> +static LIST_HEAD(clkdms);
> +
> +/**
>   * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
>   * @hw: struct clk_hw * of the clock being enabled
>   *
> @@ -116,6 +133,8 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
>  	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
>  	struct clockdomain *clkdm;
>  	const char *clk_name;
> +	struct ti_clkdm *ti_clkdm;
> +	bool match = false;
>  
>  	if (!clk->clkdm_name)
>  		return;
> @@ -130,7 +149,21 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
>  	} else {
>  		pr_debug("clock: could not associate clk %s to clkdm %s\n",
>  			 clk_name, clk->clkdm_name);
> +		return;
>  	}
> +
> +	list_for_each_entry(ti_clkdm, &clkdms, link) {
> +		if (!strcmp(ti_clkdm->name, clk->clkdm_name)) {
> +			match = true;
> +			break;

Or just goto found and then drop the match bool thing.

> +		}
> +	}
> +
> +	if (!match)
> +		return;
> +
> +	/* Add clock to the list of provided clocks */
> +	list_add(&clk->clkdm_link, &ti_clkdm->clocks);
>  }
>  
>  static void __init of_ti_clockdomain_setup(struct device_node *node)
> @@ -161,11 +194,125 @@ static void __init of_ti_clockdomain_setup(struct device_node *node)
>  	}
>  }
>  
> +static struct clk_hw *clkdm_clk_xlate(struct of_phandle_args *clkspec,
> +				      void *data)
> +{
> +	struct ti_clkdm *clkdm = data;
> +	struct clk_hw_omap *clk;
> +	u16 offset = clkspec->args[0];
> +
> +	list_for_each_entry(clk, &clkdm->clocks, clkdm_link)
> +		if (((u32)clk->enable_reg & 0xffff) - clkdm->offset == offset)

This looks scary.

> +			return &clk->hw;
> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static int ti_clk_register_clkdm(struct device_node *node)
> +{
> +	u64 clkdm_addr;
> +	u64 inst_addr;
> +	const __be32 *reg;
> +	u32 offset;
> +	int idx;
> +	struct ti_clkdm *clkdm;
> +	int ret;
> +
> +	reg = of_get_address(node, 0, NULL, NULL);
> +	if (!reg)
> +		return -ENOENT;
> +
> +	clkdm_addr = of_translate_address(node, reg);
> +
> +	reg = of_get_address(node->parent, 0, NULL, NULL);
> +	if (!reg)
> +		return -EINVAL;
> +
> +	inst_addr = of_translate_address(node->parent, reg);
> +
> +	offset = clkdm_addr - inst_addr;
> +

I guess the usual offset tricks are still going on in the TI clk
driver? Is there a plan to stop doing that at some point?

> +	idx = ti_clk_get_memmap_index(node->parent);
> +
> +	if (idx < 0) {
> +		pr_err("bad memmap index for %s\n", node->name);
> +		return idx;
> +	}
> +
> +	clkdm = kzalloc(sizeof(*clkdm), GFP_KERNEL);
> +	if (!clkdm)
> +		return -ENOMEM;
> +
> +	clkdm->name = node->name;
> +	clkdm->index = idx;
> +	clkdm->offset = offset;
> +
> +	INIT_LIST_HEAD(&clkdm->clocks);
> +
> +	list_add(&clkdm->link, &clkdms);
> +
> +	ret = of_clk_add_hw_provider(node, clkdm_clk_xlate, clkdm);
> +	if (ret) {
> +		list_del(&clkdm->link);
> +		kfree(clkdm);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ti_clk_get_reg_addr_clkdm - get register address relative to clockdomain
> + * @clkdm_name: parent clockdomain
> + * @offset: offset from the clockdomain
> + *
> + * Gets a register address relative to parent clockdomain. Searches the
> + * list of available clockdomain, and if match is found, calculates the
> + * register address from the iomap relative to the clockdomain.
> + * Returns the register address, or NULL if not found.
> + */
> +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset)
> +{
> +	u32 reg;
> +	struct clk_omap_reg *reg_setup;
> +	struct ti_clkdm *clkdm;
> +	bool match = false;
> +
> +	reg_setup = (struct clk_omap_reg *)&reg;
> +
> +	/* XXX: get offset from clkdm, get base for instance */
> +	list_for_each_entry(clkdm, &clkdms, link) {
> +		if (!strcmp(clkdm->name, clkdm_name)) {
> +			match = true;
> +			break;
> +		}
> +	}
> +
> +	if (!match) {
> +		pr_err("%s: no entry for %s\n", __func__, clkdm_name);
> +		return NULL;
> +	}
> +
> +	reg_setup->offset = clkdm->offset + offset;
> +	reg_setup->index = clkdm->index;
> +
> +	return (void __iomem *)reg;
> +}
> +
>  static const struct of_device_id ti_clkdm_match_table[] __initconst = {
>  	{ .compatible = "ti,clockdomain" },
>  	{ }
>  };
>  
> +void __init ti_dt_clockdomains_early_setup(void)
> +{
> +	struct device_node *np;
> +
> +	for_each_matching_node(np, ti_clkdm_match_table) {
> +		ti_clk_register_clkdm(np);
> +	}

Nitpick: drop braces please.

> +}
> +
>  /**
>   * ti_dt_clockdomains_setup - setup device tree clockdomains
>   *
> diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
> index 626ae94..afccb48 100644
> --- a/include/linux/clk/ti.h
> +++ b/include/linux/clk/ti.h
> @@ -125,6 +125,7 @@ struct clk_hw_omap_ops {
>  /**
>   * struct clk_hw_omap - OMAP struct clk
>   * @node: list_head connecting this clock into the full clock list
> + * @clkdm_link: list_head connecting this clock into the clockdomain
>   * @enable_reg: register to write to enable the clock (see @enable_bit)
>   * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
>   * @flags: see "struct clk.flags possibilities" above
> @@ -137,6 +138,7 @@ struct clk_hw_omap_ops {
>  struct clk_hw_omap {
>  	struct clk_hw		hw;
>  	struct list_head	node;
> +	struct list_head	clkdm_link;
>  	unsigned long		fixed_rate;
>  	u8			fixed_div;
>  	void __iomem		*enable_reg;
> @@ -251,6 +253,7 @@ int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate,
>  unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
>  
>  void ti_dt_clk_init_retry_clks(void);
> +void ti_dt_clockdomains_early_setup(void);
>  void ti_dt_clockdomains_setup(void);
>  int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops);
>  
> -- 
> 1.9.1
> 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH RESEND 1/3] clk: imx6: Mask mmdc_ch1 handshake for periph2_sel and mmdc_ch1_axi_podf
From: Stephen Boyd @ 2016-10-28  0:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOMZO5BQHKv7dxJTq2C1qdvhhRRRW8bafaXoQW77AKLNTWggAg@mail.gmail.com>

On 10/26, Fabio Estevam wrote:
> Shawn,
> 
> Are you collecting the imx clk patches in this cycle?
> 
> I see no response from Stephen on this series from a long time.
> 
> We missed 4.9, so hopefully this can land in 4.10.
> 

These patches are in the queue. If Shawn wants to pick up patches
and send pull requests that's fine too.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v2] ARM: dts: socfpga: Add Macnica sodia board
From: Olof Johansson @ 2016-10-28  0:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160924235945.32128-1-iwamatsu@nigauri.org>

Hi,

Saw this when looking at the patch when merging it.

Please fix up with incremental patch. Dinh, this goes for other
platforms under socfpga too, several have this problem:

On Sat, Sep 24, 2016 at 4:59 PM, Nobuhiro Iwamatsu <iwamatsu@nigauri.org> wrote:
> diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
> new file mode 100644
> index 0000000..9aaf413
> --- /dev/null
> +++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
> @@ -0,0 +1,123 @@
> +/*
> + *  Copyright (C) 2016 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "socfpga_cyclone5.dtsi"
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +
> +/ {
> +       model = "Altera SOCFPGA Cyclone V SoC Macnica Sodia board";
> +       compatible = "altr,socfpga-cyclone5", "altr,socfpga";

You should add a compatible entry for your specific board. Compatible
goes from specific to generic, so something like:

compatible = "altr,macnica-sodia", "latr,socfpga-cyclone5", "altr,socfpga";

You can even add entries for the specific rev (if there are
differences). But at the very least, add one for the board.


Dinh, please follow up for other boards as well. I've still merged the
pull request you sent (email about that separately).


Regards,

-Olof

^ permalink raw reply

* [RFC][PATCH] arm64: Add support for CONFIG_DEBUG_VIRTUAL
From: Laura Abbott @ 2016-10-28  0:18 UTC (permalink / raw)
  To: linux-arm-kernel

x86 has an option CONFIG_DEBUG_VIRTUAL to do additional checks
on virt_to_phys calls. The goal is to catch users who are calling
virt_to_phys on non-linear addresses immediately. As features
such as CONFIG_VMAP_STACK get enabled for arm64, this becomes
increasingly important. Add checks to catch bad virt_to_phys
usage.

Signed-off-by: Laura Abbott <labbott@redhat.com>
---
This has been on my TODO list for a while. It caught a few bugs with
CONFIG_VMAP_STACK on x86 so when that eventually gets added
for arm64 it will be useful to have. This caught one driver calling __pa on an
ioremapped address already. RFC for a couple of reasons:

1) This is basically a direct port of the x86 approach.
2) I needed some #ifndef __ASSEMBLY__ which I don't like to throw around.
3) I'm not quite sure about the bounds check for the VIRTUAL_BUG_ON with KASLR,
specifically the _end check.
4) Is it worth actually keeping this as DEBUG_VIRTUAL vs. folding it into
another option?

---
 arch/arm64/include/asm/memory.h | 11 ++++++++++-
 arch/arm64/mm/Makefile          |  2 +-
 arch/arm64/mm/physaddr.c        | 17 +++++++++++++++++
 lib/Kconfig.debug               |  2 +-
 mm/cma.c                        |  2 +-
 5 files changed, 30 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/mm/physaddr.c

diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index ba62df8..9805adc 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -106,11 +106,19 @@
  * private definitions which should NOT be used outside memory.h
  * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
  */
-#define __virt_to_phys(x) ({						\
+#define __virt_to_phys_nodebug(x) ({					\
 	phys_addr_t __x = (phys_addr_t)(x);				\
 	__x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET :	\
 				 (__x - kimage_voffset); })
 
+#ifdef CONFIG_DEBUG_VIRTUAL
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_phys(unsigned long x);
+#endif
+#else
+#define __virt_to_phys(x)	__virt_to_phys_nodebug(x)
+#endif
+
 #define __phys_to_virt(x)	((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
 #define __phys_to_kimg(x)	((unsigned long)((x) + kimage_voffset))
 
@@ -202,6 +210,7 @@ static inline void *phys_to_virt(phys_addr_t x)
  * Drivers should NOT use these either.
  */
 #define __pa(x)			__virt_to_phys((unsigned long)(x))
+#define __pa_nodebug(x)		__virt_to_phys_nodebug((unsigned long)(x))
 #define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 #define virt_to_pfn(x)      __phys_to_pfn(__virt_to_phys(x))
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 54bb209..bcea84e 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -5,6 +5,6 @@ obj-y				:= dma-mapping.o extable.o fault.o init.o \
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
 obj-$(CONFIG_ARM64_PTDUMP)	+= dump.o
 obj-$(CONFIG_NUMA)		+= numa.o
-
+obj-$(CONFIG_DEBUG_VIRTUAL)	+= physaddr.o
 obj-$(CONFIG_KASAN)		+= kasan_init.o
 KASAN_SANITIZE_kasan_init.o	:= n
diff --git a/arch/arm64/mm/physaddr.c b/arch/arm64/mm/physaddr.c
new file mode 100644
index 0000000..6c271e2
--- /dev/null
+++ b/arch/arm64/mm/physaddr.c
@@ -0,0 +1,17 @@
+#include <linux/mm.h>
+
+#include <asm/memory.h>
+
+unsigned long __virt_to_phys(unsigned long x)
+{
+	phys_addr_t __x = (phys_addr_t)x;
+
+	if (__x & BIT(VA_BITS - 1)) {
+		/* The bit check ensures this is the right range */
+		return (__x & ~PAGE_OFFSET) + PHYS_OFFSET;
+	} else {
+		VIRTUAL_BUG_ON(x < kimage_vaddr || x > (unsigned long)_end);
+		return (__x - kimage_voffset);
+	}
+}
+EXPORT_SYMBOL(__virt_to_phys);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 33bc56c..e5634bb 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -604,7 +604,7 @@ config DEBUG_VM_PGFLAGS
 
 config DEBUG_VIRTUAL
 	bool "Debug VM translations"
-	depends on DEBUG_KERNEL && X86
+	depends on DEBUG_KERNEL && (X86 || ARM64)
 	help
 	  Enable some costly sanity checks in virtual to page code. This can
 	  catch mistakes with virt_to_page() and friends.
diff --git a/mm/cma.c b/mm/cma.c
index 384c2cb..2345803 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -235,7 +235,7 @@ int __init cma_declare_contiguous(phys_addr_t base,
 	phys_addr_t highmem_start;
 	int ret = 0;
 
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_ARM64)
 	/*
 	 * high_memory isn't direct mapped memory so retrieving its physical
 	 * address isn't appropriate.  But it would be useful to check the
-- 
2.7.4

^ permalink raw reply related

* [GIT PULL] SoCFPGA DTS updates for v4.10, part 1
From: Olof Johansson @ 2016-10-28  0:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161024141654.19832-1-dinguyen@kernel.org>

On Mon, Oct 24, 2016 at 09:16:54AM -0500, Dinh Nguyen wrote:
> Hi Arnd, Kevin, Olof:
> 
> Please pull in these DTS updates for SoCFPGA for v4.10.
> 
> Thanks,
> Dinh
> 
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git tags/socfpga_dts_for_v4.10_part_1
> 
> for you to fetch changes up to c96f5919e6b0d132aa9afe9f1adc872fc107d5bb:
> 
>   ARM: dts: socfpga: socrates: enable qspi (2016-10-18 22:18:14 -0500)

Merged, thanks.


-Olof

^ permalink raw reply

* [GIT PULL] STi DT update for v4.10 round 1
From: Olof Johansson @ 2016-10-28  0:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1a44f1ef-906a-798a-a60b-9d8212209aaa@st.com>

Hi,

On Thu, Oct 20, 2016 at 04:27:10PM +0200, Patrice Chotard wrote:
> Hi Arnd, Kevin, Olof
> 
> PLease consider this first round of STi dts update for v4.10 :
> 
> 
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/pchotard/sti.git 

The tag specification fell off. Maybe because it hadn't been mirrored out by
the time you generated the config, since I seem to have found it there
(st-dt-for-4.10).

> 
> for you to fetch changes up to 97a0b97f9e8197429eee5f87ce14373f73dbd9d3:
> 
>   ARM: dts: stih410-clocks: Add PROC_STFE as a critical clock (2016-10-20 16:20:26 +0200)

Merged into next/dt. Thanks!


-Olof

^ permalink raw reply

* [GIT PULL] STi defconfig updates for v4.10
From: Olof Johansson @ 2016-10-28  0:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50be6ab2-2af8-b21e-770c-d141d6396179@st.com>

On Thu, Oct 20, 2016 at 05:20:27PM +0200, Patrice Chotard wrote:
> Hi Olof, Arnd and Kevin,
> 
> Please consider this first round of multi_v7_defconfig updates for v4.10 :
> 
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/pchotard/sti.git tags/sti-defconfig-for-4.10
> 
> for you to fetch changes up to 620c52f4db4d47e1f33c64e641392fe575d5397f:
> 
>   ARM: multi_v7_defconfig: Remove stih41x phy Kconfig symbol. (2016-10-20 17:05:08 +0200)


Thanks, merged.


-Olof

^ permalink raw reply

* [PATCH] arm64: Enable HIBERNATION in defconfig
From: Olof Johansson @ 2016-10-28  0:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476896392-28106-1-git-send-email-catalin.marinas@arm.com>

On Wed, Oct 19, 2016 at 05:59:52PM +0100, Catalin Marinas wrote:
> This patch adds CONFIG_HIBERNATION to the arm64 defconfig.
> 
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
> 
> Re-sent post 4.9-rc1 as it was missed during the merging window.

Thanks, applied to next/arm64 for 4.10.


-Olof

^ permalink raw reply

* [PATCH] ARM: defconfig: update U8500 defconfig
From: Olof Johansson @ 2016-10-28  0:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476696229-1964-1-git-send-email-linus.walleij@linaro.org>

On Mon, Oct 17, 2016 at 11:23:49AM +0200, Linus Walleij wrote:
> Some config options like perf events and PM are now implicit,
> we have an upstream driver for the AK8974, and we really
> want the HRTIMER software triggers from configfs with some
> of the sensors.
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ARM SoC folks: please apply this wherever your usual batch of
> defconfig changes go.

Thanks, applied!


-Olof

^ permalink raw reply

* [PATCH v3 1/3] PM / OPP: Expose _of_get_opp_desc_node as dev_pm_opp API
From: kbuild test robot @ 2016-10-27 23:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027214131.1725-2-d-gerlach@ti.com>

Hi Dave,

[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.9-rc2]
[cannot apply to pm/linux-next next-20161027]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Dave-Gerlach/cpufreq-Introduce-TI-CPUFreq-OPP-Driver/20161028-054633
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All errors (new ones prefixed by >>):

   drivers/base/power/opp/of.c:184:6: error: redefinition of 'dev_pm_opp_of_remove_table'
    void dev_pm_opp_of_remove_table(struct device *dev)
         ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:218:20: note: previous definition of 'dev_pm_opp_of_remove_table' was here
    static inline void dev_pm_opp_of_remove_table(struct device *dev)
                       ^
>> drivers/base/power/opp/of.c:191:21: error: redefinition of 'dev_pm_opp_of_get_opp_desc_node'
    struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
                        ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:236:35: note: previous definition of 'dev_pm_opp_of_get_opp_desc_node' was here
    static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
                                      ^
   drivers/base/power/opp/of.c:434:5: error: redefinition of 'dev_pm_opp_of_add_table'
    int dev_pm_opp_of_add_table(struct device *dev)
        ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:213:19: note: previous definition of 'dev_pm_opp_of_add_table' was here
    static inline int dev_pm_opp_of_add_table(struct device *dev)
                      ^
   drivers/base/power/opp/of.c:474:6: error: redefinition of 'dev_pm_opp_of_cpumask_remove_table'
    void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
         ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:227:20: note: previous definition of 'dev_pm_opp_of_cpumask_remove_table' was here
    static inline void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
                       ^
   drivers/base/power/opp/of.c:492:5: error: redefinition of 'dev_pm_opp_of_cpumask_add_table'
    int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
        ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:222:19: note: previous definition of 'dev_pm_opp_of_cpumask_add_table' was here
    static inline int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
                      ^
   drivers/base/power/opp/of.c:545:5: error: redefinition of 'dev_pm_opp_of_get_sharing_cpus'
    int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
        ^
   In file included from drivers/base/power/opp/opp.h:21:0,
                    from drivers/base/power/opp/of.c:22:
   include/linux/pm_opp.h:231:19: note: previous definition of 'dev_pm_opp_of_get_sharing_cpus' was here
    static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
                      ^

vim +/dev_pm_opp_of_get_opp_desc_node +191 drivers/base/power/opp/of.c

   178	 * Locking: The internal opp_table and opp structures are RCU protected.
   179	 * Hence this function indirectly uses RCU updater strategy with mutex locks
   180	 * to keep the integrity of the internal data structures. Callers should ensure
   181	 * that this function is *NOT* called under RCU protection or in contexts where
   182	 * mutex cannot be locked.
   183	 */
 > 184	void dev_pm_opp_of_remove_table(struct device *dev)
   185	{
   186		_dev_pm_opp_remove_table(dev, false);
   187	}
   188	EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
   189	
   190	/* Returns opp descriptor node for a device, caller must do of_node_put() */
 > 191	struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
   192	{
   193		/*
   194		 * TODO: Support for multiple OPP tables.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 46043 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161028/0c934d6a/attachment-0001.gz>

^ permalink raw reply

* [PATCH] ARM: dts: msm8974: Remove "unused" reserved region
From: Stephen Boyd @ 2016-10-27 23:23 UTC (permalink / raw)
  To: linux-arm-kernel

>From what I can tell by looking at the android 3.10 kernel
sources for msm8974, this isn't actually a reserved region.
Instead it's marked as "unused" for reserved regions. Let's
remove it so we get back a good chunk of memory.

Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 561d4d136762..5f4752696171 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -58,11 +58,6 @@
 			reg = <0x0fd80000 0x180000>;
 			no-map;
 		};
-
-		unused at 0ff00000 {
-			reg = <0x0ff00000 0x10100000>;
-			no-map;
-		};
 	};
 
 	cpus {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related

* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Alexandre Belloni @ 2016-10-27 23:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027180229.5faqrvxa2a4pos7i@pengutronix.de>

On 27/10/2016 at 20:02:29 +0200, Uwe Kleine-K?nig wrote :
> Hello Richard,
> 
> On Thu, Oct 27, 2016 at 06:04:06PM +0200, Richard Genoud wrote:
> > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> > index fd8aa1f4ba78..168b10cad47b 100644
> > --- a/drivers/tty/serial/atmel_serial.c
> > +++ b/drivers/tty/serial/atmel_serial.c
> > @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> >  		mode |= ATMEL_US_USMODE_RS485;
> >  	} else if (termios->c_cflag & CRTSCTS) {
> >  		/* RS232 with hardware handshake (RTS/CTS) */
> > -		if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
> > -			dev_info(port->dev, "not enabling hardware flow control because DMA is used");
> > -			termios->c_cflag &= ~CRTSCTS;
> > -		} else {
> > +		if (atmel_use_fifo(port) &&
> > +		    !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
> > +			/*
> > +			 * with ATMEL_US_USMODE_HWHS set, the controller will
> > +			 * be able to drive the RTS pin high/low when the RX
> > +			 * FIFO is above RXFTHRES/below RXFTHRES2.
> > +			 * It will also disable the transmitter when the CTS
> > +			 * pin is high.
> > +			 * This mode is not activated if CTS pin is a GPIO
> > +			 * because in this case, the transmitter is always
> > +			 * disabled (there must be an internal pull-up
> > +			 * responsible for this behaviour).
> > +			 * If the RTS pin is a GPIO, the controller won't be
> > +			 * able to drive it according to the FIFO thresholds,
> > +			 * but it will be handled by the driver.
> > +			 */
> >  			mode |= ATMEL_US_USMODE_HWHS;
> 
> You use
> 
> 	!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)
> 
> as indicator that the cts mode of the respective pin is used. Is this
> reliable? (It's not if there are machines that don't use CTS, neither as
> gpio nor using the hardware function.) Maybe this needs a dt property to
> indicate that there is no (hw)handshaking available?
> 

We had a call today were we agreed that this should be added in a future
patch. Let's fix the regression for now.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v7] spi: sun4i: Allow transfers larger than FIFO size
From: Mark Brown @ 2016-10-27 22:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027212727.leqg3gvwhd3u64er@lukather>

On Thu, Oct 27, 2016 at 11:27:27PM +0200, Maxime Ripard wrote:
> On Thu, Oct 27, 2016 at 12:14:19PM +0100, Mark Brown wrote:

> > but since I'm not turning up anything with this subject line I've no
> > idea what that might have been (and that's very concerning in itself
> > given that this is apparently v7...).

> v4 was here: https://patchwork.kernel.org/patch/3893371/
> v5: https://patchwork.kernel.org/patch/5455381/
> v6: https://patchwork.kernel.org/patch/6975871/

> So basically, I really have no idea why, but it really seems like it
> was just falling through the cracks, repeatedly (I'm not puting the
> blame on anyone though, it just happened). Maybe it was just because
> of the lack of comments :)

Oh, those subject lines were all starting ARM: rather than spi: -
there's a good chance I didn't look at the patches if I was busy
thinking they were changes for arch/arm rather than the SPI driver.

> > I'm also concerned that there isn't a version of this for sun6i,
> > it's going to make all the cut'n'pasting between the two drivers
> > harder if we make changes in one and not the other.

> I think I'll give reg_field a shot though, and try to merge the sun6i
> driver into this one and see the results. If it can help your
> decision.

It would definitely be nice given the level of duplication.

> > If the concern from the previous reviews to do with not using DMA is
> > there some reason it's hard to do DMA?

> I think just like Alexandru that it is orthogonal. But to really
> answer, no, it's not difficult. There's just been some fundamental
> disagreement on whether DMA was supposed to be optional or not that
> stalled everything I guess.

Oh, I seem to remember some patches adding DMA support that were doing
some strange special snowflake thing with ignoring errors now that I
think about it but that's not this one...  why did nobody ever follow up
on those?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161027/f8c15ff9/attachment.sig>

^ permalink raw reply

* [PATCH 1/5] net: phy: broadcom: Add BCM54810 phy entry
From: Jon Mason @ 2016-10-27 22:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027091505.GB12841@lunn.ch>

On Thu, Oct 27, 2016 at 11:15:05AM +0200, Andrew Lunn wrote:
> On Wed, Oct 26, 2016 at 03:35:57PM -0400, Jon Mason wrote:
> > From: Vikas Soni <vsoni@broadcom.com>
> > 
> > Add BCM54810 phy entry
> 
> Hi Jon, Vikis
> 
> The subject line is a bit misleading. It does more than add a PHY ID
> entry.

All of the parts are related to adding the BCM54810 Phy, but I agree it
could be more verbose about what is happening.

> > Signed-off-by: Vikas Soni <vsoni@broadcom.com>
> > Signed-off-by: Jon Mason <jon.mason@broadcom.com>
> > ---
> >  drivers/net/phy/Kconfig    |  2 +-
> >  drivers/net/phy/broadcom.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/brcmphy.h    |  7 +++++
> >  3 files changed, 73 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> > index 45f68ea..31967ca 100644
> > --- a/drivers/net/phy/Kconfig
> > +++ b/drivers/net/phy/Kconfig
> > @@ -217,7 +217,7 @@ config BROADCOM_PHY
> >  	select BCM_NET_PHYLIB
> >  	---help---
> >  	  Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
> > -	  BCM5481 and BCM5482 PHYs.
> > +	  BCM5481, BCM54810 and BCM5482 PHYs.
> >  
> >  config CICADA_PHY
> >  	tristate "Cicada PHYs"
> > diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
> > index 870327e..cdce761 100644
> > --- a/drivers/net/phy/broadcom.c
> > +++ b/drivers/net/phy/broadcom.c
> > @@ -35,6 +35,35 @@ static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
> >  	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
> >  }
> >  
> > +static int bcm54810_config(struct phy_device *phydev)
> > +{
> > +	int rc;
> > +
> > +	/* Disable BroadR-Reach */
> > +	rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 0);
> > +	if (rc < 0)
> > +		return rc;
> > +
> > +	/* SKEW DISABLE */
> > +	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
> > +				  0xF0E0);
> > +	if (rc < 0)
> > +		return rc;
> > +
> > +	/* DELAY DISABLE */
> > +	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
> > +				  0x7000);
> 
> This driver mostly uses symbolic names, not #defines. Please can you
> use #defines here and else were in this patch.

Will do.  After looking at this, this appears to be setup for a read
that doesn't follow.  I'll audit this, clean it up and resend.

 
> > +	if (rc < 0)
> > +		return rc;
> > +
> > +	/* DELAY DISABLE */
> > +	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, 0);
> > +	if (rc < 0)
> > +		return rc;
> 
> Twice the same comment?
>
> > +
> > +	return 0;
> > +}
> > +
> >  /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
> >  static int bcm50610_a0_workaround(struct phy_device *phydev)
> >  {
> > @@ -207,6 +236,20 @@ static int bcm54xx_config_init(struct phy_device *phydev)
> >  	    (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
> >  		bcm54xx_adjust_rxrefclk(phydev);
> >  
> > +	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
> > +		err = bcm54810_config(phydev);
> > +		if (err)
> > +			return err;
> > +
> > +		reg = phy_read(phydev, MII_BMCR);
> > +		if (reg < 0)
> > +			return reg;
> > +
> > +		err = phy_write(phydev, MII_BMCR, reg & ~BMCR_PDOWN);
> > +		if (err)
> > +			return err;
> 
> This seems a bit odd. I would expect the PHY core correctly handles
> the PHY being powered down. Can you explain this a bit more, why it is
> needed.

I believe it was needed in earlier versions of the code, but doesn't
seem to be needed anymore.  Removing.

> 
> 	Thanks
> 		Andrew

^ permalink raw reply

* [PATCH] [media] media: fix platform_no_drv_owner.cocci warnings
From: kbuild test robot @ 2016-10-27 22:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201610280623.yEQ4DZSc%fengguang.wu@intel.com>

drivers/media/platform/mtk-mdp/mtk_mdp_core.c:284:3-8: No need to set .owner here. The core will do it.

 Remove .owner field if calls are used which set it automatically

Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci

CC: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 mtk_mdp_core.c |    1 -
 1 file changed, 1 deletion(-)

--- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
@@ -281,7 +281,6 @@ static struct platform_driver mtk_mdp_dr
 	.remove		= mtk_mdp_remove,
 	.driver = {
 		.name	= MTK_MDP_MODULE_NAME,
-		.owner	= THIS_MODULE,
 		.pm	= &mtk_mdp_pm_ops,
 		.of_match_table = mtk_mdp_of_ids,
 	}

^ permalink raw reply

* [PATCH 4/5] net: ethernet: bgmac: add NS2 support
From: Ray Jui @ 2016-10-27 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <ccbaf726-b1fc-975a-215c-17e2870328a6@broadcom.com>



On 10/27/2016 3:21 PM, Ray Jui wrote:
> 
> 
> On 10/27/2016 1:51 PM, Jon Mason wrote:
>> On Wed, Oct 26, 2016 at 02:50:39PM -0700, Florian Fainelli wrote:
>>> On 10/26/2016 12:36 PM, Jon Mason wrote:
>>>> Add support for the variant of amac hardware present in the Broadcom
>>>> Northstar2 based SoCs.  Northstar2 requires an additional register to be
>>>> configured with the port speed/duplexity (NICPM).  This can be added to
>>>> the link callback to hide it from the instances that do not use this.
>>>> Also, the bgmac_chip_reset() was intentionally removed to prevent the
>>>> resetting of the chip to the default values on open.  Finally, clearing
>>>> of the pending interrupts on init is required due to observed issues on
>>>> some platforms.
>>>>
>>>> Signed-off-by: Jon Mason <jon.mason@broadcom.com>
>>>> ---
>>>
>>>> +static void bgmac_nicpm_speed_set(struct net_device *net_dev)
>>>> +{
>>>> +	struct bgmac *bgmac = netdev_priv(net_dev);
>>>> +	u32 val;
>>>> +
>>>> +	if (!bgmac->plat.nicpm_base)
>>>> +		return;
>>>> +
>>>> +	val = NICPM_IOMUX_CTRL_INIT_VAL;
>>>> +	switch (bgmac->net_dev->phydev->speed) {
>>>> +	default:
>>>> +		pr_err("Unsupported speed.  Defaulting to 1000Mb\n");
>>>> +	case SPEED_1000:
>>>> +		val |= NICPM_IOMUX_CTRL_SPD_1000M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>>> +		break;
>>>> +	case SPEED_100:
>>>> +		val |= NICPM_IOMUX_CTRL_SPD_100M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>>> +		break;
>>>> +	case SPEED_10:
>>>> +		val |= NICPM_IOMUX_CTRL_SPD_10M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>>> +		break;
>>>> +	}
>>>> +
>>>> +	writel(val, bgmac->plat.nicpm_base + NICPM_IOMUX_CTRL);
>>>> +
>>>> +	usleep_range(10, 100);
>>>
>>> Does not seem like a good idea, do you need that sleep?
>>
>> Oops, that's not supposed to be there.  Removed.
>>
>>
>>>> +
>>>> +	bgmac_adjust_link(bgmac->net_dev);
>>>> +}
>>>> +
>>>>  static int platform_phy_connect(struct bgmac *bgmac)
>>>>  {
>>>>  	struct phy_device *phy_dev;
>>>>  
>>>> -	phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node,
>>>> -					 bgmac_adjust_link);
>>>> +	if (bgmac->plat.nicpm_base)
>>>> +		phy_dev = of_phy_get_and_connect(bgmac->net_dev,
>>>> +						 bgmac->dev->of_node,
>>>> +						 bgmac_nicpm_speed_set);
>>>> +	else
>>>> +		phy_dev = of_phy_get_and_connect(bgmac->net_dev,
>>>> +						 bgmac->dev->of_node,
>>>> +						 bgmac_adjust_link);
>>>>  	if (!phy_dev) {
>>>>  		dev_err(bgmac->dev, "Phy connect failed\n");
>>>>  		return -ENODEV;
>>>>  	}
>>>>  
>>>> +	if (bgmac->feature_flags & BGMAC_FEAT_LANE_SWAP)
>>>> +		phy_dev->dev_flags |= PHY_BRCM_EXP_LANE_SWAP;
>>>> +
>>>>  	return 0;
>>>>  }
>>>>  
>>>> @@ -140,6 +188,9 @@ static int bgmac_probe(struct platform_device *pdev)
>>>>  
>>>>  	platform_set_drvdata(pdev, bgmac);
>>>>  
>>>> +	if (of_property_read_bool(np, "brcm,enet-phy-lane-swap"))
>>>> +		bgmac->feature_flags |= BGMAC_FEAT_LANE_SWAP;
>>>> +
>>>>  	/* Set the features of the 4707 family */
>>>>  	bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
>>>>  	bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
>>>> @@ -182,6 +233,14 @@ static int bgmac_probe(struct platform_device *pdev)
>>>>  	if (IS_ERR(bgmac->plat.idm_base))
>>>>  		return PTR_ERR(bgmac->plat.idm_base);
>>>>  
>>>> +	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
>>>> +	if (regs) {
>>>> +		bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
>>>> +							       regs);
>>>> +		if (IS_ERR(bgmac->plat.nicpm_base))
>>>> +			return PTR_ERR(bgmac->plat.nicpm_base);
>>>> +	}
>>>> +
>>>>  	bgmac->read = platform_bgmac_read;
>>>>  	bgmac->write = platform_bgmac_write;
>>>>  	bgmac->idm_read = platform_bgmac_idm_read;
>>>> @@ -213,6 +272,7 @@ static int bgmac_remove(struct platform_device *pdev)
>>>>  static const struct of_device_id bgmac_of_enet_match[] = {
>>>>  	{.compatible = "brcm,amac",},
>>>>  	{.compatible = "brcm,nsp-amac",},
>>>> +	{.compatible = "brcm,ns2-amac",},
>>>>  	{},
>>>>  };
>>>>  
>>>> diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
>>>> index 38876ec..1796208 100644
>>>> --- a/drivers/net/ethernet/broadcom/bgmac.c
>>>> +++ b/drivers/net/ethernet/broadcom/bgmac.c
>>>> @@ -1082,6 +1082,9 @@ static void bgmac_enable(struct bgmac *bgmac)
>>>>  /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
>>>>  static void bgmac_chip_init(struct bgmac *bgmac)
>>>>  {
>>>> +	/* Clear any erroneously pending interrupts */
>>>> +	bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
>>>> +
>>>>  	/* 1 interrupt per received frame */
>>>>  	bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
>>>>  
>>>> @@ -1158,8 +1161,6 @@ static int bgmac_open(struct net_device *net_dev)
>>>>  	struct bgmac *bgmac = netdev_priv(net_dev);
>>>>  	int err = 0;
>>>>  
>>>> -	bgmac_chip_reset(bgmac);
>>>> -
>>>
>>> Is this removal intentional? Maybe it should be special cased with
>>> checking for a NS2 BGMAC instance and not do it in that case?
>>
>> The reset seems completely unnecessary.  There is already 2 resets in
>> the probe routine, another reset serves no purpose.  I can add it
>> back, as it does not seem to have the negative effect I was seeing
>> before.
> 
> After repeated ifconfig down/up, does Ethernet still work with this
> reset removed?
> 
> Thanks.
> 

Sorry, I meant to say, after removing both reset calls in the open and
close functions, does Ethernet still work after repeated ifconfig
down/up with data traffic in the background?

I would guess this reset is required, to flush out and clean up the
internal memories and state machine of the AMAC core each time before
you bring up the interface. It might also be required in the close
function, such that after the interface bring down, there's no staled
data coming out of the AMAC core. But I cannot say for sure since I do
not try this out myself.

Thanks.

>>
>> Of course, if I remove this one I should remove the reset in the close
>> too (which seems even more unnecessary, but I didn't remove it).
>>
>> Thanks,
>> Jon
>>
>>> -- 
>>> Florian

^ permalink raw reply

* [PATCH 4/5] net: ethernet: bgmac: add NS2 support
From: Ray Jui @ 2016-10-27 22:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027205117.GA24397@broadcom.com>



On 10/27/2016 1:51 PM, Jon Mason wrote:
> On Wed, Oct 26, 2016 at 02:50:39PM -0700, Florian Fainelli wrote:
>> On 10/26/2016 12:36 PM, Jon Mason wrote:
>>> Add support for the variant of amac hardware present in the Broadcom
>>> Northstar2 based SoCs.  Northstar2 requires an additional register to be
>>> configured with the port speed/duplexity (NICPM).  This can be added to
>>> the link callback to hide it from the instances that do not use this.
>>> Also, the bgmac_chip_reset() was intentionally removed to prevent the
>>> resetting of the chip to the default values on open.  Finally, clearing
>>> of the pending interrupts on init is required due to observed issues on
>>> some platforms.
>>>
>>> Signed-off-by: Jon Mason <jon.mason@broadcom.com>
>>> ---
>>
>>> +static void bgmac_nicpm_speed_set(struct net_device *net_dev)
>>> +{
>>> +	struct bgmac *bgmac = netdev_priv(net_dev);
>>> +	u32 val;
>>> +
>>> +	if (!bgmac->plat.nicpm_base)
>>> +		return;
>>> +
>>> +	val = NICPM_IOMUX_CTRL_INIT_VAL;
>>> +	switch (bgmac->net_dev->phydev->speed) {
>>> +	default:
>>> +		pr_err("Unsupported speed.  Defaulting to 1000Mb\n");
>>> +	case SPEED_1000:
>>> +		val |= NICPM_IOMUX_CTRL_SPD_1000M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>> +		break;
>>> +	case SPEED_100:
>>> +		val |= NICPM_IOMUX_CTRL_SPD_100M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>> +		break;
>>> +	case SPEED_10:
>>> +		val |= NICPM_IOMUX_CTRL_SPD_10M << NICPM_IOMUX_CTRL_SPD_SHIFT;
>>> +		break;
>>> +	}
>>> +
>>> +	writel(val, bgmac->plat.nicpm_base + NICPM_IOMUX_CTRL);
>>> +
>>> +	usleep_range(10, 100);
>>
>> Does not seem like a good idea, do you need that sleep?
> 
> Oops, that's not supposed to be there.  Removed.
> 
> 
>>> +
>>> +	bgmac_adjust_link(bgmac->net_dev);
>>> +}
>>> +
>>>  static int platform_phy_connect(struct bgmac *bgmac)
>>>  {
>>>  	struct phy_device *phy_dev;
>>>  
>>> -	phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node,
>>> -					 bgmac_adjust_link);
>>> +	if (bgmac->plat.nicpm_base)
>>> +		phy_dev = of_phy_get_and_connect(bgmac->net_dev,
>>> +						 bgmac->dev->of_node,
>>> +						 bgmac_nicpm_speed_set);
>>> +	else
>>> +		phy_dev = of_phy_get_and_connect(bgmac->net_dev,
>>> +						 bgmac->dev->of_node,
>>> +						 bgmac_adjust_link);
>>>  	if (!phy_dev) {
>>>  		dev_err(bgmac->dev, "Phy connect failed\n");
>>>  		return -ENODEV;
>>>  	}
>>>  
>>> +	if (bgmac->feature_flags & BGMAC_FEAT_LANE_SWAP)
>>> +		phy_dev->dev_flags |= PHY_BRCM_EXP_LANE_SWAP;
>>> +
>>>  	return 0;
>>>  }
>>>  
>>> @@ -140,6 +188,9 @@ static int bgmac_probe(struct platform_device *pdev)
>>>  
>>>  	platform_set_drvdata(pdev, bgmac);
>>>  
>>> +	if (of_property_read_bool(np, "brcm,enet-phy-lane-swap"))
>>> +		bgmac->feature_flags |= BGMAC_FEAT_LANE_SWAP;
>>> +
>>>  	/* Set the features of the 4707 family */
>>>  	bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
>>>  	bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
>>> @@ -182,6 +233,14 @@ static int bgmac_probe(struct platform_device *pdev)
>>>  	if (IS_ERR(bgmac->plat.idm_base))
>>>  		return PTR_ERR(bgmac->plat.idm_base);
>>>  
>>> +	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
>>> +	if (regs) {
>>> +		bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
>>> +							       regs);
>>> +		if (IS_ERR(bgmac->plat.nicpm_base))
>>> +			return PTR_ERR(bgmac->plat.nicpm_base);
>>> +	}
>>> +
>>>  	bgmac->read = platform_bgmac_read;
>>>  	bgmac->write = platform_bgmac_write;
>>>  	bgmac->idm_read = platform_bgmac_idm_read;
>>> @@ -213,6 +272,7 @@ static int bgmac_remove(struct platform_device *pdev)
>>>  static const struct of_device_id bgmac_of_enet_match[] = {
>>>  	{.compatible = "brcm,amac",},
>>>  	{.compatible = "brcm,nsp-amac",},
>>> +	{.compatible = "brcm,ns2-amac",},
>>>  	{},
>>>  };
>>>  
>>> diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
>>> index 38876ec..1796208 100644
>>> --- a/drivers/net/ethernet/broadcom/bgmac.c
>>> +++ b/drivers/net/ethernet/broadcom/bgmac.c
>>> @@ -1082,6 +1082,9 @@ static void bgmac_enable(struct bgmac *bgmac)
>>>  /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
>>>  static void bgmac_chip_init(struct bgmac *bgmac)
>>>  {
>>> +	/* Clear any erroneously pending interrupts */
>>> +	bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
>>> +
>>>  	/* 1 interrupt per received frame */
>>>  	bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
>>>  
>>> @@ -1158,8 +1161,6 @@ static int bgmac_open(struct net_device *net_dev)
>>>  	struct bgmac *bgmac = netdev_priv(net_dev);
>>>  	int err = 0;
>>>  
>>> -	bgmac_chip_reset(bgmac);
>>> -
>>
>> Is this removal intentional? Maybe it should be special cased with
>> checking for a NS2 BGMAC instance and not do it in that case?
> 
> The reset seems completely unnecessary.  There is already 2 resets in
> the probe routine, another reset serves no purpose.  I can add it
> back, as it does not seem to have the negative effect I was seeing
> before.

After repeated ifconfig down/up, does Ethernet still work with this
reset removed?

Thanks.

> 
> Of course, if I remove this one I should remove the reset in the close
> too (which seems even more unnecessary, but I didn't remove it).
> 
> Thanks,
> Jon
> 
>> -- 
>> Florian

^ permalink raw reply

* [PATCH v5 1/7] drm: sunxi: Add a basic DRM driver for Allwinner DE2
From: Maxime Ripard @ 2016-10-27 22:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161025161441.6b248efe9229bd80e3f7a33c@free.fr>

On Tue, Oct 25, 2016 at 04:14:41PM +0200, Jean-Francois Moine wrote:
> > > +Display controller
> > > +==================
> > > +
> > > +Required properties:
> > > +
> > > +- compatible: value should be one of the following
> > > +		"allwinner,sun8i-a83t-display-engine"
> > > +		"allwinner,sun8i-h3-display-engine"
> > > +
> > > +- clocks: must include clock specifiers corresponding to entries in the
> > > +		clock-names property.
> > > +
> > > +- clock-names: must contain
> > > +		"gate": for DE activation
> > > +		"clock": DE clock
> > 
> > We've been calling them bus and mod.
> 
> I can understand "bus" (which is better than "apb"), but why "mod"?

Allwinner has been calling the clocks that are supposed to generate
the external signals (depending on where you were looking) module or
mod clocks (which is also why we have mod in the clock
compatibles). The module 1 clocks being used for the audio and the
module 0 for the rest (SPI, MMC, NAND, display, etc.)

> > > +
> > > +- resets: phandle to the reset of the device
> > > +
> > > +- ports: phandle's to the LCD ports
> > 
> > Please use the OF graph.
> 
> These ports are references to the graph of nodes. See
> 	http://www.kernelhub.org/?msg=911825&p=2

In an OF-graph, your phandle to the LCD controller would be replaced
by an output endpoint.

> 
> 	[snip]
> > > +struct tcon {
> > > +	u32 gctl;
> > > +#define		TCON_GCTL_TCON_En BIT(31)
> > > +	u32 gint0;
> > > +#define		TCON_GINT0_TCON1_Vb_Int_En BIT(30)
> > > +#define		TCON_GINT0_TCON1_Vb_Int_Flag BIT(14)
> > > +	u32 gint1;
> > > +	u32 dum0[13];
> > > +	u32 tcon0_ctl;				/* 0x40 */
> > > +#define		TCON0_CTL_TCON_En BIT(31)
> > > +	u32 dum1[19];
> > > +	u32 tcon1_ctl;				/* 0x90 */
> > > +#define		TCON1_CTL_TCON_En BIT(31)
> > > +#define		TCON1_CTL_Interlace_En BIT(20)
> > > +#define		TCON1_CTL_Start_Delay_SHIFT 4
> > > +#define		TCON1_CTL_Start_Delay_MASK GENMASK(8, 4)
> > > +	u32 basic0;			/* XI/YI */
> > > +	u32 basic1;			/* LS_XO/LS_YO */
> > > +	u32 basic2;			/* XO/YO */
> > > +	u32 basic3;			/* HT/HBP */
> > > +	u32 basic4;			/* VT/VBP */
> > > +	u32 basic5;			/* HSPW/VSPW */
> > > +	u32 dum2;
> > > +	u32 ps_sync;				/* 0xb0 */
> > > +	u32 dum3[15];
> > > +	u32 io_pol;				/* 0xf0 */
> > > +#define		TCON1_IO_POL_IO0_inv BIT(24)
> > > +#define		TCON1_IO_POL_IO1_inv BIT(25)
> > > +#define		TCON1_IO_POL_IO2_inv BIT(26)
> > > +	u32 io_tri;
> > > +	u32 dum4[2];
> > > +
> > > +	u32 ceu_ctl;				/* 0x100 */
> > > +#define     TCON_CEU_CTL_ceu_en BIT(31)
> > > +	u32 dum5[3];
> > > +	u32 ceu_rr;
> > > +	u32 ceu_rg;
> > > +	u32 ceu_rb;
> > > +	u32 ceu_rc;
> > > +	u32 ceu_gr;
> > > +	u32 ceu_gg;
> > > +	u32 ceu_gb;
> > > +	u32 ceu_gc;
> > > +	u32 ceu_br;
> > > +	u32 ceu_bg;
> > > +	u32 ceu_bb;
> > > +	u32 ceu_bc;
> > > +	u32 ceu_rv;
> > > +	u32 ceu_gv;
> > > +	u32 ceu_bv;
> > > +	u32 dum6[45];
> > > +
> > > +	u32 mux_ctl;				/* 0x200 */
> > > +	u32 dum7[63];
> > > +
> > > +	u32 fill_ctl;				/* 0x300 */
> > > +	u32 fill_start0;
> > > +	u32 fill_end0;
> > > +	u32 fill_data0;
> > > +};
> > 
> > Please use defines instead of the structures.
> 
> I think that structures are more readable.

That's not really the point. No one in the kernel uses it (and even
you use defines for registers offset in some places of that
patch). And then you have Andr? arguments.

> > > +void de2_disable_vblank(struct drm_device *drm, unsigned crtc)
> > > +{
> > > +	struct priv *priv = drm->dev_private;
> > > +	struct lcd *lcd = priv->lcds[crtc];
> > > +
> > > +	tcon_write(lcd->mmio, gint0,
> > > +			 tcon_read(lcd->mmio, gint0) &
> > > +					~TCON_GINT0_TCON1_Vb_Int_En);
> > > +}
> > > +
> > > +/* panel functions */
> > 
> > Panel functions? In the CRTC driver?
> 
> Yes, dumb panel.

What do you mean by that? Using a Parallel/RGB interface?

> 
> > > +static void de2_set_frame_timings(struct lcd *lcd)
> > > +{
> > > +	struct drm_crtc *crtc = &lcd->crtc;
> > > +	const struct drm_display_mode *mode = &crtc->mode;
> > > +	int interlace = mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 1;
> > > +	int start_delay;
> > > +	u32 data;
> > > +
> > > +	data = XY(mode->hdisplay - 1, mode->vdisplay / interlace - 1);
> > > +	tcon_write(lcd->mmio, basic0, data);
> > > +	tcon_write(lcd->mmio, basic1, data);
> > > +	tcon_write(lcd->mmio, basic2, data);
> > > +	tcon_write(lcd->mmio, basic3,
> > > +			XY(mode->htotal - 1,
> > > +				mode->htotal - mode->hsync_start - 1));
> > > +	tcon_write(lcd->mmio, basic4,
> > > +			XY(mode->vtotal * (3 - interlace),
> > > +				mode->vtotal - mode->vsync_start - 1));
> > > +	tcon_write(lcd->mmio, basic5,
> > > +			 XY(mode->hsync_end - mode->hsync_start - 1,
> > > +				mode->vsync_end - mode->vsync_start - 1));
> > > +
> > > +	tcon_write(lcd->mmio, ps_sync, XY(1, 1));
> > > +
> > > +	data = TCON1_IO_POL_IO2_inv;
> > > +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> > > +		data |= TCON1_IO_POL_IO0_inv;
> > > +	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
> > > +		data |= TCON1_IO_POL_IO1_inv;
> > > +	tcon_write(lcd->mmio, io_pol, data);
> > > +
> > > +	tcon_write(lcd->mmio, ceu_ctl,
> > > +		tcon_read(lcd->mmio, ceu_ctl) & ~TCON_CEU_CTL_ceu_en);
> > > +
> > > +	data = tcon_read(lcd->mmio, tcon1_ctl);
> > > +	if (interlace == 2)
> > > +		data |= TCON1_CTL_Interlace_En;
> > > +	else
> > > +		data &= ~TCON1_CTL_Interlace_En;
> > > +	tcon_write(lcd->mmio, tcon1_ctl, data);
> > > +
> > > +	tcon_write(lcd->mmio, fill_ctl, 0);
> > > +	tcon_write(lcd->mmio, fill_start0, mode->vtotal + 1);
> > > +	tcon_write(lcd->mmio, fill_end0, mode->vtotal);
> > > +	tcon_write(lcd->mmio, fill_data0, 0);
> > > +
> > > +	start_delay = (mode->vtotal - mode->vdisplay) / interlace - 5;
> > > +	if (start_delay > 31)
> > > +		start_delay = 31;
> > > +	data = tcon_read(lcd->mmio, tcon1_ctl);
> > > +	data &= ~TCON1_CTL_Start_Delay_MASK;
> > > +	data |= start_delay << TCON1_CTL_Start_Delay_SHIFT;
> > > +	tcon_write(lcd->mmio, tcon1_ctl, data);
> > > +
> > > +	tcon_write(lcd->mmio, io_tri, 0x0fffffff);
> > > +}
> > 
> > Some comments here would be nice, there's a lot of non trivial things.
> 
> ... and no documentation. I just set the values I saw in the I/O memory
> when running the legacy driver.

That's bad (but definitely not your fault) :/

> > > +	lcd->gate = devm_clk_get(dev, "gate");		/* optional */
> > 
> > Having some kind of error checking would still be nice.
> 
> And cancel the device creation?

Well, yes. If it cannot enable it, it will at best not work properly,
at worst be reset, so it won't be very useful anyway.

> > > +	if (!IS_ERR(lcd->rstc)) {
> > > +		ret = reset_control_deassert(lcd->rstc);
> > > +		if (ret) {
> > > +			dev_err(dev, "reset deassert err %d\n", ret);
> > > +			goto err;
> > > +		}
> > > +	}
> > > +
> > > +	if (!IS_ERR(lcd->gate)) {
> > > +		ret = clk_prepare_enable(lcd->gate);
> > > +		if (ret)
> > > +			goto err2;
> > > +	}
> > > +
> > > +	ret = clk_prepare_enable(lcd->clk);
> > > +	if (ret)
> > > +		goto err2;
> > 
> > Is there any reason not to do that in the enable / disable? Leaving
> > clocks running while the device has no guarantee that it's going to be
> > used seems like a waste of resources.
> 
> If the machine does not need video (network server, router..), it is simpler
> to prevent the video driver to be loaded (DT, module black list...).

You might not have control on any of it, or you might just have no
monitor attached for example. Recompiling the kernel or updating the
DT when you want to plug an HDMI monitor seems like a poor UX :)

> > > +static const struct {
> > > +	char chan;
> > > +	char layer;
> > > +	char pipe;
> > > +} plane2layer[DE2_N_PLANES] = {
> > > +	[DE2_PRIMARY_PLANE] =	{0, 0, 0},
> > > +	[DE2_CURSOR_PLANE] =	{1, 0, 1},
> > > +	[DE2_VI_PLANE] =	{0, 1, 0},
> > > +};
> > 
> > Comments?
> 
> This
> 	primary plane is channel 0 (VI), layer 0, pipe 0
> 	cursor plane is channel 1 (UI), layer 0, pipe 1
> 	overlay plane is channel 0 (VI), layer 1, pipe 0
> or the full explanation:
>     Constraints:
> 	The VI channels can do RGB or YUV, while UI channels can do RGB
> 	only.
> 	The LCD 0 has 1 VI channel and 4 UI channels, while
> 	LCD 1 has only 1 VI channel and 1 UI channel.
> 	The cursor must go to a channel bigger than the primary channel,
> 	otherwise it is not transparent.
>     First try:
> 	Letting the primary plane (usually RGB) in the 2nd channel (UI),
> 	as this is done in the legacy driver, asks for the cursor to go
> 	to the next channel (UI), but this one does not exist in LCD1.
>     Retained layout:
> 	So, we must use only 2 channels for the same behaviour on LCD0
> 	(H3) and LCD1 (A83T)
> 	The retained combination is:
> 		- primary plane in the first channel (VI),
> 		- cursor plane inthe 2nd channel (UI), and
> 		- overlay plane in the 1st channel (VI).
> 
> 	Note that there could be 3 overlay planes (a channel has 4
> 	layers), but I am not sure that the A83T or the H3 could
> 	support 3 simultaneous video streams...

Do you know if the pipe works in the old display engine?

Especially about the two-steps composition that wouldn't allow you to
have alpha on all the planes?

If it is similar, I think hardcoding the pipe number is pretty bad,
because that would restrict the combination of planes and formats,
while some other might have worked.

> > > +static inline void de_write(struct priv *priv, int reg, u32 data)
> > > +{
> > > +	writel_relaxed(data, priv->mmio + reg);
> > > +}
> > > +
> > > +static inline u32 de_read(struct priv *priv, int reg)
> > > +{
> > > +	return readl_relaxed(priv->mmio + reg);
> > > +}
> > > +
> > > +static void de_lcd_select(struct priv *priv,
> > > +			int lcd_num,
> > > +			void __iomem *mux_o)
> > > +{
> > > +	u32 data;
> > > +
> > > +	/* select the LCD */
> > > +	data = de_read(priv, DE_SEL_REG);
> > > +	data &= ~1;
> > > +	de_write(priv, DE_SEL_REG, data);
> > > +
> > > +	/* double register switch */
> > > +	glb_write(mux_o + DE_MUX_GLB_REGS, dbuff, 1);
> > > +}
> > > +
> > > +void de2_de_plane_update(struct priv *priv,
> > > +			int lcd_num, int plane_ix,
> > > +			struct drm_plane_state *state,
> > > +			struct drm_plane_state *old_state)
> > > +{
> > > +	struct drm_framebuffer *fb = state->fb;
> > > +	struct drm_gem_cma_object *gem;
> > > +	void __iomem *mux_o = priv->mmio;
> > > +	void __iomem *chan_o;
> > > +	u32 size = WH(state->crtc_w, state->crtc_h);
> > > +	u32 coord;
> > > +	u32 screen_size;
> > > +	u32 data, fcolor;
> > > +	u32 ui_sel, alpha_glob;
> > > +	int chan, layer, x, y;
> > > +	unsigned fmt;
> > > +	unsigned long flags;
> > > +
> > > +	chan = plane2layer[plane_ix].chan;
> > > +	layer = plane2layer[plane_ix].layer;
> > > +
> > > +	mux_o += (lcd_num == 0) ? DE_MUX0_BASE : DE_MUX1_BASE;
> > > +	chan_o = mux_o;
> > > +	chan_o += DE_MUX_CHAN_REGS + DE_MUX_CHAN_SZ * chan;
> > > +
> > > +	x = state->crtc_x >= 0 ? state->crtc_x : 0;
> > > +	y = state->crtc_y >= 0 ? state->crtc_y : 0;
> > > +	coord = XY(x, y);
> > > +
> > > +	/* handle the cursor move */
> > > +	if (plane_ix == DE2_CURSOR_PLANE
> > > +	 && fb == old_state->fb) {
> > > +		spin_lock_irqsave(&de_lock, flags);
> > > +		de_lcd_select(priv, lcd_num, mux_o);
> > > +		if (chan == 0)
> > > +			vi_write(chan_o, cfg[layer].coord, coord);
> > > +		else
> > > +			ui_write(chan_o, cfg[layer].coord, coord);
> > > +		spin_unlock_irqrestore(&de_lock, flags);
> > > +		return;
> > > +	}
> > > +
> > > +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> > > +
> > > +	ui_sel = alpha_glob = 0;
> > > +	switch (fb->pixel_format) {
> > > +	case DRM_FORMAT_ARGB8888:
> > > +		fmt = DE2_FORMAT_ARGB_8888;
> > > +		ui_sel = VI_CFG_ATTR_ui_sel;
> > > +		break;
> > > +	case DRM_FORMAT_BGRA8888:
> > > +		fmt = DE2_FORMAT_BGRA_8888;
> > > +		ui_sel = VI_CFG_ATTR_ui_sel;
> > > +		break;
> > > +	case DRM_FORMAT_XRGB8888:
> > > +		fmt = DE2_FORMAT_XRGB_8888;
> > > +		ui_sel = VI_CFG_ATTR_ui_sel;
> > > +		alpha_glob = (1 << UI_CFG_ATTR_alpmod_SHIFT) |
> > > +				(0xff << UI_CFG_ATTR_alpha_SHIFT);
> > > +		break;
> > > +	case DRM_FORMAT_RGB888:
> > > +		fmt = DE2_FORMAT_RGB_888;
> > > +		ui_sel = VI_CFG_ATTR_ui_sel;
> > > +		break;
> > > +	case DRM_FORMAT_BGR888:
> > > +		fmt = DE2_FORMAT_BGR_888;
> > > +		ui_sel = VI_CFG_ATTR_ui_sel;
> > > +		break;
> > > +	case DRM_FORMAT_YUYV:
> > > +		fmt = DE2_FORMAT_YUV422_I_YUYV;
> > > +		break;
> > > +	case DRM_FORMAT_YVYU:
> > > +		fmt = DE2_FORMAT_YUV422_I_YVYU;
> > > +		break;
> > > +	case DRM_FORMAT_YUV422:
> > > +		fmt = DE2_FORMAT_YUV422_P;
> > > +		break;
> > > +	case DRM_FORMAT_YUV420:
> > > +		fmt = DE2_FORMAT_YUV420_P;
> > > +		break;
> > > +	case DRM_FORMAT_UYVY:
> > > +		fmt = DE2_FORMAT_YUV422_I_UYVY;
> > > +		break;
> > > +	default:
> > > +		pr_err("format %.4s not yet treated\n",
> > > +			(char *) &fb->pixel_format);
> > > +		return;
> > > +	}
> > > +
> > > +	spin_lock_irqsave(&de_lock, flags);
> > > +
> > > +	screen_size = plane_ix == DE2_PRIMARY_PLANE ?
> > > +			size :
> > > +			glb_read(mux_o + DE_MUX_GLB_REGS, size);
> > > +
> > > +	/* prepare the activation of alpha blending (1 bit per plane) */
> > > +	fcolor = bld_read(mux_o + DE_MUX_BLD_REGS, fcolor_ctl)
> > > +			| (0x100 << plane2layer[plane_ix].pipe);
> > > +
> > > +	de_lcd_select(priv, lcd_num, mux_o);
> > > +
> > > +	if (chan == 0) {	/* VI channel */
> > > +		int i;
> > > +
> > > +		data = VI_CFG_ATTR_en | (fmt << VI_CFG_ATTR_fmt_SHIFT) |
> > > +					ui_sel;
> > > +		vi_write(chan_o, cfg[layer].attr, data);
> > > +		vi_write(chan_o, cfg[layer].size, size);
> > > +		vi_write(chan_o, cfg[layer].coord, coord);
> > > +		for (i = 0; i < VI_N_PLANES; i++) {
> > > +			vi_write(chan_o, cfg[layer].pitch[i],
> > > +					fb->pitches[i] ? fb->pitches[i] :
> > > +							fb->pitches[0]);
> > > +			vi_write(chan_o, cfg[layer].top_laddr[i],
> > > +				gem->paddr + fb->offsets[i]);
> > > +			vi_write(chan_o, fcolor[layer], 0xff000000);
> > > +		}
> > > +		if (layer == 0)
> > > +			vi_write(chan_o, ovl_size[0], screen_size);
> > > +
> > > +	} else {		/* UI channel */
> > > +		data = UI_CFG_ATTR_en | (fmt << UI_CFG_ATTR_fmt_SHIFT) |
> > > +			alpha_glob;
> > > +		ui_write(chan_o, cfg[layer].attr, data);
> > > +		ui_write(chan_o, cfg[layer].size, size);
> > > +		ui_write(chan_o, cfg[layer].coord, coord);
> > > +		ui_write(chan_o, cfg[layer].pitch, fb->pitches[0]);
> > > +		ui_write(chan_o, cfg[layer].top_laddr,
> > > +				gem->paddr + fb->offsets[0]);
> > > +		if (layer == 0)
> > > +			ui_write(chan_o, ovl_size, screen_size);
> > > +	}
> > > +	bld_write(mux_o + DE_MUX_BLD_REGS, fcolor_ctl, fcolor);
> > > +
> > > +	spin_unlock_irqrestore(&de_lock, flags);
> > > +}
> > 
> > Splitting that into functions would make it a bit more trivial and
> > readable.
> 
> Not sure: there is a lot of common data and different I/O accesses.

You could still have different ones to set the buffers, formats and
coordinates for example.

> > > +void de2_de_plane_disable(struct priv *priv,
> > > +			int lcd_num, int plane_ix)
> > > +{
> > > +	void __iomem *mux_o = priv->mmio;
> > > +	void __iomem *chan_o;
> > > +	u32 fcolor;
> > > +	int chan, layer, chan_disable = 0;
> > > +	unsigned long flags;
> > > +
> > > +	chan = plane2layer[plane_ix].chan;
> > > +	layer = plane2layer[plane_ix].layer;
> > > +
> > > +	mux_o += (lcd_num == 0) ? DE_MUX0_BASE : DE_MUX1_BASE;
> > > +	chan_o = mux_o;
> > > +	chan_o += DE_MUX_CHAN_REGS + DE_MUX_CHAN_SZ * chan;
> > > +
> > > +	/* (only 2 layers) */
> > > +	if (chan == 0) {
> > > +		if (vi_read(chan_o, cfg[1 - layer].attr) == 0)
> > > +			chan_disable = 1;
> > > +	} else {
> > > +		if (ui_read(chan_o, cfg[1 - layer].attr) == 0)
> > > +			chan_disable = 1;
> > > +	}
> > > +
> > > +	spin_lock_irqsave(&de_lock, flags);
> > > +
> > > +	fcolor = bld_read(mux_o + DE_MUX_BLD_REGS, fcolor_ctl);
> > > +
> > > +	de_lcd_select(priv, lcd_num, mux_o);
> > > +
> > > +	if (chan == 0)
> > > +		vi_write(chan_o, cfg[layer].attr, 0);
> > > +	else
> > > +		ui_write(chan_o, cfg[layer].attr, 0);
> > > +
> > > +	if (chan_disable)
> > > +		bld_write(mux_o + DE_MUX_BLD_REGS, fcolor_ctl,
> > > +			fcolor & ~(0x100 << plane2layer[plane_ix].pipe));
> > > +
> > > +	spin_unlock_irqrestore(&de_lock, flags);
> > > +}
> > 
> > Can't you just disable it?
> 
> Which 'it'? A layer must be disabled and it is not useful to let the
> DE2 processor to scan a pipe (channel) without any layer.

Oh, so that's what it does.

I really think that you should put as much comments as possible on
what you found out working on this, especially because of the lack of
documentation.

> > > +static int __init de2_drm_init(void)
> > > +{
> > > +	int ret;
> > > +
> > > +/* uncomment to activate the drm traces at startup time */
> > > +/*	drm_debug = DRM_UT_CORE | DRM_UT_DRIVER | DRM_UT_KMS |
> > > +			DRM_UT_PRIME | DRM_UT_ATOMIC; */
> > 
> > That's useless.
> 
> Right, but it seems that some people don't know how to debug a DRM
> driver. This is only a reminder.
> 
> > > +	DRM_DEBUG_DRIVER("\n");
> > > +
> > > +	ret = platform_driver_register(&de2_lcd_platform_driver);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	ret = platform_driver_register(&de2_drm_platform_driver);
> > > +	if (ret < 0)
> > > +		platform_driver_unregister(&de2_lcd_platform_driver);
> > > +
> > > +	return ret;
> > > +}
> > 
> > And that really shouldn't be done that way.
> 
> May you explain?

This goes against the whole idea of the device and driver
model. Drivers should only register themselves, device should be
created by buses (or by using some external components if the bus
can't: DT, ACPI, etc.). If there's a match, you get probed.

A driver that creates its own device just to probe itself violates
that.

> > > +int de2_plane_init(struct drm_device *drm, struct lcd *lcd)
> > > +{
> > > +	int ret, possible_crtcs = 1 << lcd->crtc_idx;
> > > +
> > > +	ret = de2_one_plane_init(drm, &lcd->planes[DE2_PRIMARY_PLANE],
> > > +				DRM_PLANE_TYPE_PRIMARY, possible_crtcs,
> > > +				ui_formats, ARRAY_SIZE(ui_formats));
> > > +	if (ret >= 0)
> > > +		ret = de2_one_plane_init(drm, &lcd->planes[DE2_CURSOR_PLANE],
> > > +				DRM_PLANE_TYPE_CURSOR, possible_crtcs,
> > > +				ui_formats, ARRAY_SIZE(ui_formats));
> > 
> > Nothing looks really special about that cursor plane. Any reasion not
> > to make it an overlay?
> 
> As explained above (channel/layer/pipe plane definitions), the cursor
> cannot go in a channel lower or equal to the one of the primary plane.
> Then, it must be known and, so, have an explicit plane.

If you were to make it a plane, you could use atomic_check to check
this and make sure this doesn't happen. And you would gain a generic
plane that can be used for other purposes if needed.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161028/82ba1eba/attachment-0001.sig>

^ permalink raw reply

* [PATCH v3 3/3] cpufreq: ti: Add cpufreq driver to determine available OPPs at runtime
From: Dave Gerlach @ 2016-10-27 21:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027214131.1725-1-d-gerlach@ti.com>

Some TI SoCs, like those in the AM335x, AM437x, DRA7x, and AM57x families,
have different OPPs available for the MPU depending on which specific
variant of the SoC is in use. This can be determined through use of the
revision and an eFuse register present in the silicon. Introduce a
ti-cpufreq driver that can read the aformentioned values and provide
them as version matching data to the opp framework. Through this the
opp-supported-hw dt binding that is part of the operating-points-v2
table can be used to indicate availability of OPPs for each device.

This driver also creates the "cpufreq-dt" platform_device after passing
the version matching data to the OPP framework so that the cpufreq-dt
handles the actual cpufreq implementation. Even without the necessary
data to pass the version matching data the driver will still create this
device to maintain backwards compatibility with operating-points v1
tables.

Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
---
v2-v3:
 - Use common ti compatible as described in binding and then match
   against machine type for platform data.
 - Use newly exposed dev_pm_opp_of_get_opp_desc_node to get
   operating-points-v2 table now that properties needed by driver are
   there.
 - Parse syscon properties from operating-points-v2 node rather
   than cpu node.
 - Do not make ti-cpufreq a module-platform-driver and do not allow
   building as module.

 drivers/cpufreq/Kconfig.arm  |  11 ++
 drivers/cpufreq/Makefile     |   1 +
 drivers/cpufreq/ti-cpufreq.c | 288 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 300 insertions(+)
 create mode 100644 drivers/cpufreq/ti-cpufreq.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index d89b8afe23b6..665f11dbdaef 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -234,6 +234,17 @@ config ARM_TEGRA124_CPUFREQ
 	help
 	  This adds the CPUFreq driver support for Tegra124 SOCs.
 
+config ARM_TI_CPUFREQ
+	bool "Texas Instruments CPUFreq support"
+	depends on ARCH_OMAP2PLUS
+	help
+	  This driver enables valid OPPs on the running platform based on
+	  values contained within the SoC in use. Enable this in order to
+	  use the cpufreq-dt driver on all Texas Instruments platforms that
+	  provide dt based operating-points-v2 tables with opp-supported-hw
+	  data provided. Required for cpufreq support on AM335x, AM437x,
+	  DRA7x, and AM57x platforms.
+
 config ARM_PXA2xx_CPUFREQ
 	tristate "Intel PXA2xx CPUfreq driver"
 	depends on PXA27x || PXA25x
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 0a9b6a093646..5b1b6ec0a9f0 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
 obj-$(CONFIG_ARM_STI_CPUFREQ)		+= sti-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)	+= tegra20-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)	+= tegra124-cpufreq.o
+obj-$(CONFIG_ARM_TI_CPUFREQ)		+= ti-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)	+= vexpress-spc-cpufreq.o
 obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
 obj-$(CONFIG_MACH_MVEBU_V7)		+= mvebu-cpufreq.o
diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
new file mode 100644
index 000000000000..afbaef967b65
--- /dev/null
+++ b/drivers/cpufreq/ti-cpufreq.c
@@ -0,0 +1,288 @@
+/*
+ * TI CPUFreq/OPP hw-supported driver
+ *
+ * Copyright (C) 2016 Texas Instruments, Inc.
+ *	 Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define REVISION_MASK				0xF
+#define REVISION_SHIFT				28
+
+#define AM33XX_800M_ARM_MPU_MAX_FREQ		0x1E2F
+#define AM43XX_600M_ARM_MPU_MAX_FREQ		0xFFA
+
+#define DRA7_EFUSE_HAS_OD_MPU_OPP		11
+#define DRA7_EFUSE_HAS_HIGH_MPU_OPP		15
+#define DRA7_EFUSE_HAS_ALL_MPU_OPP		23
+
+#define DRA7_EFUSE_NOM_MPU_OPP			BIT(0)
+#define DRA7_EFUSE_OD_MPU_OPP			BIT(1)
+#define DRA7_EFUSE_HIGH_MPU_OPP			BIT(2)
+
+#define VERSION_COUNT				2
+
+struct ti_cpufreq_data;
+
+struct ti_cpufreq_soc_data {
+	unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data,
+				     unsigned long efuse);
+	unsigned long efuse_fallback;
+};
+
+struct ti_cpufreq_data {
+	struct device *cpu_dev;
+	struct device_node *opp_node;
+	struct regmap *opp_efuse;
+	struct regmap *revision;
+	const struct ti_cpufreq_soc_data *soc_data;
+};
+
+static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
+				      unsigned long efuse)
+{
+	if (!efuse)
+		efuse = opp_data->soc_data->efuse_fallback;
+	/* AM335x and AM437x use "OPP disable" bits, so invert */
+	return ~efuse;
+}
+
+static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
+				      unsigned long efuse)
+{
+	unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP;
+
+	/*
+	 * The efuse on dra7 and am57 parts contains a specific
+	 * value indicating the highest available OPP.
+	 */
+
+	switch (efuse) {
+	case DRA7_EFUSE_HAS_ALL_MPU_OPP:
+	case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
+		calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
+	case DRA7_EFUSE_HAS_OD_MPU_OPP:
+		calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP;
+	}
+
+	return calculated_efuse;
+}
+
+static struct ti_cpufreq_soc_data am3x_soc_data = {
+	.efuse_xlate = amx3_efuse_xlate,
+	.efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ,
+};
+
+static struct ti_cpufreq_soc_data am4x_soc_data = {
+	.efuse_xlate = amx3_efuse_xlate,
+	.efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ,
+};
+
+static struct ti_cpufreq_soc_data dra7_soc_data = {
+	.efuse_xlate = dra7_efuse_xlate,
+};
+
+/**
+ * ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC
+ * @opp_data: pointer to ti_cpufreq_data context
+ * @efuse_value: Set to the value parsed from efuse
+ *
+ * Returns error code if efuse not read properly.
+ */
+static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data,
+				u32 *efuse_value)
+{
+	struct device *dev = opp_data->cpu_dev;
+	struct device_node *np = opp_data->opp_node;
+	unsigned int efuse_offset;
+	u32 efuse, efuse_mask, efuse_shift, vals[4];
+	int ret;
+
+	ret = of_property_read_u32_array(np, "ti,syscon-efuse", vals, 4);
+	if (ret) {
+		dev_err(dev, "ti,syscon-efuse cannot be read %s: %d\n",
+			np->full_name, ret);
+		return ret;
+	}
+
+	efuse_offset = vals[1];
+	efuse_mask = vals[2];
+	efuse_shift = vals[3];
+
+	ret = regmap_read(opp_data->opp_efuse, efuse_offset, &efuse);
+	if (ret) {
+		dev_err(dev,
+			"Failed to read the efuse value from syscon: %d\n",
+			ret);
+		return ret;
+	}
+
+	efuse = (efuse & efuse_mask) >> efuse_shift;
+
+	*efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse);
+
+	return 0;
+}
+
+/**
+ * ti_cpufreq_get_rev() - Parse and return rev value present on SoC
+ * @opp_data: pointer to ti_cpufreq_data context
+ * @revision_value: Set to the value parsed from revision register
+ *
+ * Returns error code if revision not read properly.
+ */
+static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
+			      u32 *revision_value)
+{
+	struct device *dev = opp_data->cpu_dev;
+	struct device_node *np = opp_data->opp_node;
+	unsigned int revision_offset;
+	u32 revision;
+	int ret;
+
+	ret = of_property_read_u32_index(np, "ti,syscon-rev",
+					 1, &revision_offset);
+	if (ret) {
+		dev_err(dev,
+			"No revision offset provided %s [%d]\n",
+			np->full_name, ret);
+		return ret;
+	}
+
+	ret = regmap_read(opp_data->revision, revision_offset, &revision);
+	if (ret) {
+		dev_err(dev,
+			"Failed to read the revision number from syscon: %d\n",
+			ret);
+		return ret;
+	}
+
+	*revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
+
+	return 0;
+}
+
+static int ti_cpufreq_setup_syscon_registers(struct ti_cpufreq_data *opp_data)
+{
+	struct device *dev = opp_data->cpu_dev;
+	struct device_node *np = opp_data->opp_node;
+
+	opp_data->opp_efuse = syscon_regmap_lookup_by_phandle(np,
+							"ti,syscon-efuse");
+	if (IS_ERR(opp_data->opp_efuse)) {
+		dev_err(dev,
+			"\"ti,syscon-efuse\" is missing, cannot use OPPv2 table.\n");
+		return PTR_ERR(opp_data->opp_efuse);
+	}
+
+	opp_data->revision = syscon_regmap_lookup_by_phandle(np,
+							"ti,syscon-rev");
+	if (IS_ERR(opp_data->revision)) {
+		dev_err(dev,
+			"\"ti,syscon-rev\" is missing, cannot use OPPv2 table.\n");
+		return PTR_ERR(opp_data->revision);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id ti_cpufreq_of_match[] = {
+	{ .compatible = "ti,am33xx", .data = &am3x_soc_data, },
+	{ .compatible = "ti,am4372", .data = &am4x_soc_data, },
+	{ .compatible = "ti,dra7", .data = &dra7_soc_data },
+	{},
+};
+
+static int ti_cpufreq_init(void)
+{
+	u32 version[VERSION_COUNT];
+	struct device_node *np;
+	const struct of_device_id *match;
+	struct ti_cpufreq_data *opp_data;
+	int ret;
+
+	np = of_find_node_by_path("/");
+	match = of_match_node(ti_cpufreq_of_match, np);
+	if (!match)
+		return -ENODEV;
+
+	opp_data = kzalloc(sizeof(*opp_data), GFP_KERNEL);
+	if (!opp_data)
+		return -ENOMEM;
+
+	opp_data->soc_data = match->data;
+
+	opp_data->cpu_dev = get_cpu_device(0);
+	if (!opp_data->cpu_dev) {
+		pr_err("%s: Failed to get device for CPU0\n", __func__);
+		return -ENODEV;
+	}
+
+	opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
+	if (!opp_data->opp_node) {
+		dev_info(opp_data->cpu_dev,
+			 "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n");
+		goto register_cpufreq_dt;
+	}
+
+	ret = ti_cpufreq_setup_syscon_registers(opp_data);
+	if (ret)
+		goto fail_put_node;
+
+	/*
+	 * OPPs determine whether or not they are supported based on
+	 * two metrics:
+	 *	0 - SoC Revision
+	 *	1 - eFuse value
+	 */
+	ret = ti_cpufreq_get_rev(opp_data, &version[0]);
+	if (ret)
+		goto fail_put_node;
+
+	ret = ti_cpufreq_get_efuse(opp_data, &version[1]);
+	if (ret)
+		goto fail_put_node;
+
+	of_node_put(opp_data->opp_node);
+
+	ret = dev_pm_opp_set_supported_hw(opp_data->cpu_dev, version,
+					  VERSION_COUNT);
+	if (ret) {
+		dev_err(opp_data->cpu_dev,
+			"Failed to set supported hardware\n");
+		goto fail_put_node;
+	}
+
+register_cpufreq_dt:
+	platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+
+	return 0;
+
+fail_put_node:
+	of_node_put(opp_data->opp_node);
+
+	return ret;
+}
+module_init(ti_cpufreq_init);
+
+MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver");
+MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.9.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox