2014-10-08 05:27:39

by Scott Branden

[permalink] [raw]
Subject: [PATCH V3 0/6] Add initial support for Broadcom Cygnus SoC

This patchset contains initial support for Broadcom's Cygnus SoC based on our
iProc architecture. Initial support is minimal and includes just the mach
platform code, clock driver, and a basic device tree configuration. Peripheral
drivers will be submitted soon, as will device tree configurations for other
Cygnus board variants.

Changes from v2:
- rebased to 3.17 kernel

Changes from v1:
- Address code review comments as per previous responses.
- Copyright headers updated to remove Broadcom URL.
- mach platform code still contains hard coded addresses. These address are
the same for all Cygnus variants. Could you please provide guidance on where
they should go if you would still like them changed. There does not seem to
be a reason to change them to device tree as they do not change.

Jonathan Richardson (6):
ARM: cygnus: Initial support for Broadcom Cygnus SoC
clk: Clock driver support for Broadcom Cygnus SoC
dt-bindings: Document Broadcom Cygnus SoC and clock driver
ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
ARM: dts: Enable Broadcom Cygnus SoC
MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
drivers

Documentation/devicetree/bindings/arm/cygnus.txt | 12 +
.../devicetree/bindings/clock/clk-cygnus.txt | 121 ++
.../devicetree/bindings/clock/clk-iproc.txt | 48 +
MAINTAINERS | 15 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/bcm-cygnus.dtsi | 349 ++++++
arch/arm/boot/dts/bcm911360_entphn.dts | 22 +
arch/arm/configs/bcm_cygnus_defconfig | 222 ++++
arch/arm/mach-bcm/Kconfig | 31 +
arch/arm/mach-bcm/Makefile | 3 +
arch/arm/mach-bcm/bcm_cygnus.c | 166 +++
drivers/clk/Makefile | 1 +
drivers/clk/bcm/Makefile | 2 +
drivers/clk/bcm/clk-cygnus.c | 1186 ++++++++++++++++++++
drivers/clk/bcm/clk-iproc.c | 451 ++++++++
15 files changed, 2630 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt
create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
create mode 100644 drivers/clk/bcm/clk-cygnus.c
create mode 100644 drivers/clk/bcm/clk-iproc.c

--
1.7.9.5


2014-10-08 05:27:53

by Scott Branden

[permalink] [raw]
Subject: [PATCH 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers

From: Jonathan Richardson <[email protected]>

Acked-by: Jonathan Richardson <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
MAINTAINERS | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index a12edf2..9024bac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2071,6 +2071,21 @@ L: [email protected]
S: Supported
F: drivers/scsi/bnx2i/

+BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+M: Jonathan Richardson <[email protected]>
+M: Scott Branden <[email protected]>
+L: [email protected] (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/arm/cygnus.txt
+F: arch/arm/boot/dts/bcm-cygnus.dtsi
+F: arch/arm/boot/dts/bcm911360_entphn.dts
+F: arch/arm/configs/bcm_cygnus_defconfig
+F: arch/arm/mach-bcm/board_bcm_cygnus.c
+F: Documentation/devicetree/bindings/clock/clk-cygnus.txt
+F: Documentation/devicetree/bindings/clock/clk-iproc.txt
+F: drivers/clk/bcm/clk-cygnus.c
+F: drivers/clk/bcm/clk-iproc.c
+
BROADCOM KONA GPIO DRIVER
M: Ray Jui <[email protected]>
L: [email protected]
--
1.7.9.5

2014-10-08 05:27:51

by Scott Branden

[permalink] [raw]
Subject: [PATCH 2/6] clk: Clock driver support for Broadcom Cygnus SoC

From: Jonathan Richardson <[email protected]>

The iProc clock driver controls PLLs common across iProc chips. The
cygnus driver controls cygnus specific features and variations.

Reviewed-by: Ray Jui <[email protected]>
Tested-by: Jonathan Richardson <[email protected]>
Reviewed-by: JD (Jiandong) Zheng <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
drivers/clk/Makefile | 1 +
drivers/clk/bcm/Makefile | 2 +
drivers/clk/bcm/clk-cygnus.c | 1186 ++++++++++++++++++++++++++++++++++++++++++
drivers/clk/bcm/clk-iproc.c | 451 ++++++++++++++++
4 files changed, 1640 insertions(+)
create mode 100644 drivers/clk/bcm/clk-cygnus.c
create mode 100644 drivers/clk/bcm/clk-iproc.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f537a0b..8ac0a31 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
+obj-$(CONFIG_ARCH_BCM_IPROC) += bcm/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 6297d05..f803919 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -2,3 +2,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+obj-$(CONFIG_ARCH_BCM_IPROC) += clk-iproc.o
+obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c
new file mode 100644
index 0000000..2a4f976
--- /dev/null
+++ b/drivers/clk/bcm/clk-cygnus.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+/*
+ * The CRU contains two similar PLLs: LCPLL and GENPLL,
+ * both with several output channels divided from the PLL
+ * output.
+ */
+
+#define CRU_LCPLL_CONTROL1_OFFSET 0x04
+#define CRU_LCPLL_STATUS_OFFSET 0x18
+
+#define LCPLL0_PDIV_SHIFT 26
+#define LCPLL0_PDIV_MASK 0xf
+#define LCPLL0_NDIV_SHIFT 16
+#define LCPLL0_NDIV_MASK 0x3ff
+#define LCPLL_ENABLEB_CH_SHIFT 7
+#define LCPLL_ENABLEB_CH_MASK 0x3f
+#define LCPLL_MDIV_MASK 0xff
+#define LCPLL_STATUS_LOCK_SHIFT 12
+
+#define LCPLL0_CONTROL0_OFFSET 0x00
+#define LCPLL0_CONTROL1_OFFSET 0x04
+#define LCPLL0_CONTROL2_OFFSET 0x08
+#define LCPLL0_CONTROL3_OFFSET 0x0c
+
+#define GENPLL_CONTROL0_OFFSET 0x00
+#define GENPLL_CONTROL1_OFFSET 0x04
+#define GENPLL_CONTROL2_OFFSET 0x08
+#define GENPLL_CONTROL3_OFFSET 0x0c
+#define GENPLL_CONTROL4_OFFSET 0x10
+#define GENPLL_CONTROL5_OFFSET 0x14
+#define GENPLL_CONTROL6_OFFSET 0x18
+#define GENPLL_CONTROL7_OFFSET 0x1c
+#define GENPLL_CONTROL8_OFFSET 0x20
+#define GENPLL_CONTROL9_OFFSET 0x24
+#define GENPLL_STATUS_OFFSET 0x28
+
+#define GENPLL_ENABLEB_CH_SHIFT 0x6
+#define GENPLL_ENABLEB_CH_MASK 0x3f
+
+#define GENPLL_STATUS_LOCK_SHIFT 12
+#define GENPLL_STATUS_LOCK_MASK 1
+#define GENPLL_CONTROL4_NDIV_INT_SHIFT 20
+#define GENPLL_CONTROL4_NDIV_INT_MASK 0x3FF
+#define GENPLL_CONTROL4_NDIV_FRAC_SHIFT 0
+#define GENPLL_CONTROL4_NDIV_FRAC_MASK 0xFFFFF
+#define GENPLL_CONTROL5_PDIV_SHIFT 0
+#define GENPLL_CONTROL5_PDIV_MASK 0xF
+#define GENPLL_MDIV_MASK 0xff
+
+#define MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT 12
+#define NDIV_FRAC_DIVISOR 0x100000
+
+#define ASIU_MIPI_GENPLL_PWRON_SHIFT 20
+#define ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT 19
+#define ASIU_MIPI_GENPLL_PWRON_BG_SHIFT 18
+#define ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT 17
+#define ASIU_MIPI_GENPLL_ISO_IN_SHIFT 16
+#define ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT 11
+#define ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT 10
+#define ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT 9
+#define ASIU_AUDIO_GENPLL_ISO_IN 8
+
+#define CLK_RATE_NO_DIV -1
+
+/*
+ * The clock framework may call recalc even if a clock is is unused, and
+ * therefore before being prepared/enabled. State checking is done for the
+ * MIPI PLL to prevent reading from a MIPI DSI register before the PLL is
+ * powered up because it will cause corruption (imprecise external aborts)
+ * sometimer later on.
+ */
+enum clock_state {
+ CLK_ENABLED,
+ CLK_PREPARED,
+ CLK_DISABLED
+};
+
+struct cygnus_clk {
+ struct clk_hw hw;
+ void __iomem *regs_base;
+ void __iomem *pll_ctrl_reg;
+ void __iomem *clock_gate_ctrl_reg;
+ int chan;
+ int internal_div;
+ unsigned long rate;
+ enum clock_state state;
+};
+
+#define to_cygnus_clk(p) container_of(p, struct cygnus_clk, hw)
+
+/* Identifies LCPLL clock channels. */
+enum cygnus_lcpll_clk_chan {
+ LCPLL_CH0_PCIE_PHY_REF_CLK = 0,
+ LCPLL_CH1_DDR_CLK = 1,
+ LCPLL_CH2_SDIO_CLK = 2,
+ LCPLL_CH3_USB_PHY_REF_CLK = 3,
+ LCPLL_CH4_ASIU_SMART_CARD_CLK = 4,
+ LCPLL_CH5 = 5
+};
+
+/* Identifies GENPLL clock channels. */
+enum cygnus_genpll_clk_chan {
+ GENPLL_CH0_AXI21_CLK = 0,
+ GENPLL_CH1_25MHZ_CLK = 1,
+ GENPLL_CH2_SYS_CLK = 2,
+ GENPLL_CH3_ETHERNET_CLK = 3,
+ GENPLL_CH4_ASIU_AUDIO_CLK = 4,
+ GENPLL_CH5_ASIU_CAN_CLK = 5
+};
+
+/*
+ * Channels for Oscillator dervived clocks are values used to determine
+ * which clock to enable/disable from the top clock gating control.
+ */
+enum cygnus_osc_derived_clk_chan {
+ OSC_DERIVED_CH0_KEYPAD_CLK = 0,
+ OSC_DERIVED_CH1_ADC_CLK = 1,
+ OSC_DERIVED_CH2_PWM_CLK = 2,
+};
+
+enum cygnus_mipi_pll_clk_chan {
+ MIPI_PLL_CH0_MIPI_PHY_CLK = 0,
+ MIPI_PLL_CH1_LCD_CLK = 1,
+ MIPI_PLL_CH2_3D_GRAPHICS_CLK = 2,
+};
+
+/* Order of registers defined in DT. */
+enum cygnus_clk_dt_regs {
+ CYGNUS_CLK_BASE_REG = 0,
+ CYGNUS_CLK_GATE_CTRL_REG,
+ CYGNUS_PLL_CTRL_REG
+};
+
+enum cygnus_top_clk_gating_ctrl_offsets {
+ GFX_CLK_GATE_EN = 0,
+ AUD_CLK_GATE_EN,
+ CAM_CLK_GATE_EN,
+ MIPI_DSI_CLK_GATE_EN,
+ LCD_CLK_GATE_EN,
+ D1W_CLK_GATE_EN,
+ CAN_CLK_GATE_EN,
+ KEYPAD_CLK_GATE_EN,
+ SMARTCARD_CLK_GATE_EN,
+ ADC_CLK_GATE_EN,
+ CRYPTO_CLK_GATE_EN
+};
+
+/*
+ * Enable clocks controlled through the top clock gating control.
+ *
+ * @param enable true = enable clock, false = disable clock
+ */
+static void cygnus_clkgate_enable_disable(void __iomem *clkgate_reg,
+ enum cygnus_top_clk_gating_ctrl_offsets offset, bool enable)
+{
+ u32 val = readl(clkgate_reg);
+
+ /* Enable or disable the clock. */
+ if (enable)
+ val |= 1 << offset;
+ else
+ val &= ~(1 << offset);
+
+ writel(val, clkgate_reg);
+}
+
+/*
+ * Powers on/off the MIPI GENPLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param power_on true to power on PLL, false to power off
+ */
+static void cygnus_mipi_genpll_power_on_off(void __iomem *pll_ctrl_reg,
+ bool power_on)
+{
+ u32 val;
+ u32 pll_ldo_on = ((1 << ASIU_MIPI_GENPLL_PWRON_SHIFT) |
+ (1 << ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT) |
+ (1 << ASIU_MIPI_GENPLL_PWRON_BG_SHIFT) |
+ (1 << ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT));
+
+ val = readl(pll_ctrl_reg);
+
+ /*
+ * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+ * enabled.
+ */
+ if (power_on) {
+ val |= pll_ldo_on;
+ val &= ~(1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT);
+ } else {
+ val &= ~pll_ldo_on;
+ val |= 1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT;
+ }
+
+ writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Powers on/off the audio PLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param power_on true to power on PLL, false to power off
+ */
+static void cygnus_audio_genpll_power_on_off(void __iomem *pll_ctrl_reg,
+ bool power_on)
+{
+ u32 val;
+ u32 pll_ldo_on = ((1 << ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT) |
+ (1 << ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT) |
+ (1 << ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT));
+
+ val = readl(pll_ctrl_reg);
+
+ /*
+ * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+ * enabled.
+ */
+ if (power_on) {
+ val |= pll_ldo_on;
+ val &= ~(1 << ASIU_AUDIO_GENPLL_ISO_IN);
+ } else {
+ val &= ~pll_ldo_on;
+ val |= 1 << ASIU_AUDIO_GENPLL_ISO_IN;
+ }
+
+ writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_lcpll_status(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ u32 reg;
+ unsigned pdiv, ndiv;
+
+ /* read status register */
+ reg = readl(clk->regs_base + CRU_LCPLL_STATUS_OFFSET);
+
+ /* Must be locked for proper PLL operation. */
+ if ((reg & (1 << LCPLL_STATUS_LOCK_SHIFT)) == 0) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /*
+ * Calculate PLL frequency based on LCPLL divider values:
+ * pdiv = LCPLL pre-divider ratio
+ * ndiv = LCPLL feedback divider
+ *
+ * The frequency is calculated by:
+ * ndiv * (parent clock rate / pdiv)
+ */
+
+ reg = readl(clk->regs_base + CRU_LCPLL_CONTROL1_OFFSET);
+
+ /* feedback divider integer and fraction parts */
+ pdiv = (reg >> LCPLL0_PDIV_SHIFT) & LCPLL0_PDIV_MASK;
+ ndiv = (reg >> LCPLL0_NDIV_SHIFT) & LCPLL0_NDIV_MASK;
+
+ if (pdiv == 0)
+ return -EIO;
+
+ clk->rate = ndiv * (parent_rate / pdiv);
+
+ return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_clk_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_lcpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_ops = {
+ .recalc_rate = cygnus_lcpll_clk_recalc_rate,
+};
+
+static int cygnus_lcpll_chan_status(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ void * __iomem base;
+ u32 reg;
+ unsigned enable;
+ unsigned mdiv;
+ int offset = 0;
+ int shift = 0;
+
+ /* Register address is only stored in PLL structure */
+ base = clk->regs_base;
+ BUG_ON(base == NULL);
+
+ /* enable bit is in enableb_ch[] inversed */
+ enable = ((readl(base + LCPLL0_CONTROL0_OFFSET) >>
+ LCPLL_ENABLEB_CH_SHIFT) & LCPLL_ENABLEB_CH_MASK) ^
+ LCPLL_ENABLEB_CH_MASK;
+
+ if ((enable & (1 << clk->chan)) == 0) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /* MDIV for the 6 channels is spread over two registers. */
+ switch (clk->chan) {
+ case LCPLL_CH0_PCIE_PHY_REF_CLK:
+ offset = LCPLL0_CONTROL2_OFFSET; shift = 0;
+ break;
+
+ case LCPLL_CH1_DDR_CLK:
+ offset = LCPLL0_CONTROL2_OFFSET; shift = 10;
+ break;
+
+ case LCPLL_CH2_SDIO_CLK:
+ offset = LCPLL0_CONTROL2_OFFSET; shift = 20;
+ break;
+
+ case LCPLL_CH3_USB_PHY_REF_CLK:
+ offset = LCPLL0_CONTROL3_OFFSET; shift = 0;
+ break;
+
+ case LCPLL_CH4_ASIU_SMART_CARD_CLK:
+ offset = LCPLL0_CONTROL3_OFFSET; shift = 10;
+ break;
+
+ case LCPLL_CH5:
+ offset = LCPLL0_CONTROL3_OFFSET; shift = 20;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Read MDIV for requested channel. */
+ reg = readl(base + offset);
+ mdiv = (reg >> shift) & LCPLL_MDIV_MASK;
+
+ /* when divisor is 0, it behaves as max+1 */
+ if (mdiv == 0)
+ mdiv = 256;
+
+ clk->rate = parent_rate / mdiv;
+
+ pr_debug("LCPLL[%d] mdiv=%u Prate=%lu rate=%lu\n",
+ clk->chan, mdiv, parent_rate, clk->rate);
+
+ return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_chan_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_lcpll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_chan_ops = {
+ .recalc_rate = cygnus_lcpll_chan_recalc_rate,
+};
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_genpll_status(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ u32 reg;
+ unsigned pdiv;
+ unsigned ndiv_int;
+ unsigned ndiv_frac;
+
+ /* Read PLL status register. It must be locked. */
+ reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+ if ((reg & (1 << GENPLL_STATUS_LOCK_SHIFT)) == 0) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /* Calculate PLL frequency */
+
+ /* Get PLL feedback divider values. */
+ reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+ /* feedback divider integer and fraction parts */
+ ndiv_int = reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT;
+ ndiv_frac = reg & GENPLL_CONTROL4_NDIV_INT_MASK;
+ ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+ /* Get pdiv - first 4 bits. */
+ reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+ pdiv = reg & GENPLL_CONTROL5_PDIV_MASK;
+ if (pdiv == 0)
+ return -EIO;
+
+ clk->rate = (parent_rate / pdiv) * ndiv_int;
+
+ return clk->rate;
+}
+
+static unsigned long cygnus_genpll_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_genpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_genpll_ops = {
+ .recalc_rate = cygnus_genpll_recalc_rate,
+};
+
+/*
+ * Calculates clock rate of the GENPLL channel requested. The clock rate is
+ * calculated as: the configured clock rate
+ * Parent clock rate / mdiv
+ */
+static unsigned long cygnus_genpll_chan_get_rate(struct cygnus_clk *clk,
+ unsigned long parent_rate, int enableb_ch_shift)
+{
+ u32 reg;
+ unsigned enable;
+ unsigned mdiv;
+ unsigned offset = 0;
+ unsigned shift = 0;
+
+ /*
+ * Read ENABLEB_CH to determine which channels are enabled. The enable
+ * bits are inversed: 0 = channel enabled, 1 = channel disabled.
+ */
+ reg = readl(clk->regs_base + GENPLL_CONTROL1_OFFSET);
+ enable = ((reg >> enableb_ch_shift) &
+ GENPLL_ENABLEB_CH_MASK) ^ GENPLL_ENABLEB_CH_MASK;
+
+ /* If channel is disabled the rate is 0. */
+ if ((enable & (1 << clk->chan)) == 0) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /* MDIV for the 6 channels is spread over two registers. */
+ switch (clk->chan) {
+ case 0:
+ offset = GENPLL_CONTROL8_OFFSET; shift = 0;
+ break;
+
+ case 1:
+ offset = GENPLL_CONTROL8_OFFSET; shift = 10;
+ break;
+
+ case 2:
+ offset = GENPLL_CONTROL8_OFFSET; shift = 20;
+ break;
+
+ case 3:
+ offset = GENPLL_CONTROL9_OFFSET; shift = 0;
+ break;
+
+ case 4:
+ offset = GENPLL_CONTROL9_OFFSET; shift = 10;
+ break;
+
+ case 5:
+ offset = GENPLL_CONTROL9_OFFSET; shift = 20;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Read MDIV (post divider ratio) for requested channel. */
+ reg = readl(clk->regs_base + offset);
+ mdiv = (reg >> shift) & GENPLL_MDIV_MASK;
+
+ /* When divisor is 0, it behaves as max+1. */
+ if (mdiv == 0)
+ mdiv = 256;
+
+ clk->rate = parent_rate / mdiv;
+
+ pr_debug("GENPLL[%d] mdiv=%u parent rate=%lu rate=%lu\n",
+ clk->chan, mdiv, parent_rate, clk->rate);
+
+ return clk->rate;
+}
+
+/*
+ * Powers on the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering on.
+ */
+static int cygnus_genpll_chan_prepare(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ struct cygnus_clk *cyg_parent_clk =
+ to_cygnus_clk(__clk_get_hw(parent_clk));
+
+ if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+ return -EIO;
+
+ if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+ pr_debug("GENPLL[%d]: Powering on audio PLL/LDO\n", clk->chan);
+ cygnus_audio_genpll_power_on_off(
+ cyg_parent_clk->pll_ctrl_reg, true);
+ }
+
+ return 0;
+}
+
+/*
+ * Powers off the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering off.
+ */
+static void cygnus_genpll_chan_unprepare(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ struct cygnus_clk *cyg_parent_clk =
+ to_cygnus_clk(__clk_get_hw(parent_clk));
+
+ if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+ return;
+
+ if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+ pr_debug("GENPLL[%d]: Powering down audio PLL and LDO\n",
+ clk->chan);
+ cygnus_audio_genpll_power_on_off(cyg_parent_clk->pll_ctrl_reg,
+ false);
+ }
+}
+
+static unsigned long cygnus_genpll_chan_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_genpll_chan_get_rate(bcm_clk, parent_rate,
+ GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables GENPLL channels. The only PLL channel that is controlled through
+ * the top clock gating control is the audio clock which requires enabling.
+ *
+ * Individual channels aren't enabled/disabled on the PLL because they are
+ * enabled by default and drivers don't always refer to them, meaning the
+ * clock framework would disable them. This can be added later when power
+ * saving is a concern.
+ */
+static int cygnus_genpll_chan_enable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ struct cygnus_clk *cyg_parent_clk =
+ to_cygnus_clk(__clk_get_hw(parent_clk));
+ int parent_rate;
+
+ if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+ return -EIO;
+
+ pr_debug("Enable GENPLL chan %d\n", clk->chan);
+
+ if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+ cygnus_clkgate_enable_disable(
+ cyg_parent_clk->clock_gate_ctrl_reg,
+ AUD_CLK_GATE_EN, true);
+
+ /* Ensure parent's clock rate is calculated. */
+ parent_rate = clk_get_rate(parent_clk);
+ if (WARN_ON(!parent_rate))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void cygnus_genpll_chan_disable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ struct cygnus_clk *cyg_parent_clk =
+ to_cygnus_clk(__clk_get_hw(parent_clk));
+
+ if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+ return;
+
+ pr_debug("GENPLL: disable chan %d\n", clk->chan);
+
+ /* Enable audio clock. */
+ if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK)
+ cygnus_clkgate_enable_disable(
+ cyg_parent_clk->clock_gate_ctrl_reg,
+ AUD_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_genpll_chan_ops = {
+ .prepare = cygnus_genpll_chan_prepare,
+ .unprepare = cygnus_genpll_chan_unprepare,
+ .enable = cygnus_genpll_chan_enable,
+ .disable = cygnus_genpll_chan_disable,
+ .recalc_rate = cygnus_genpll_chan_recalc_rate,
+};
+
+static __init struct clk *cygnus_clock_init(struct device_node *node,
+ const struct clk_ops *ops)
+{
+ u32 channel = 0;
+ struct clk *clk;
+ struct cygnus_clk *cygnus_clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct clk_init_data init;
+ int rc;
+
+ pr_debug("Clock name %s\n", node->name);
+
+ cygnus_clk = kzalloc(sizeof(*cygnus_clk), GFP_KERNEL);
+ if (WARN_ON(!cygnus_clk))
+ return NULL;
+
+ cygnus_clk->state = CLK_DISABLED;
+
+ /* Read base address from device tree and map to virtual address. */
+ cygnus_clk->regs_base = of_iomap(node, CYGNUS_CLK_BASE_REG);
+ if (WARN_ON(!cygnus_clk->regs_base))
+ goto err_alloc;
+
+ /* Read optional base addresses for PLL control and clock gating. */
+ cygnus_clk->clock_gate_ctrl_reg = of_iomap(node,
+ CYGNUS_CLK_GATE_CTRL_REG);
+ cygnus_clk->pll_ctrl_reg = of_iomap(node, CYGNUS_PLL_CTRL_REG);
+
+ of_property_read_u32(node, "channel", &channel);
+ cygnus_clk->chan = channel;
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /*
+ * Internal divider is optional and used for PLL derived clocks with
+ * hardcoded dividers.
+ */
+ cygnus_clk->internal_div = CLK_RATE_NO_DIV;
+ of_property_read_u32(node, "div", &cygnus_clk->internal_div);
+
+ init.name = clk_name;
+ init.ops = ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ cygnus_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &cygnus_clk->hw);
+ if (WARN_ON(IS_ERR(clk)))
+ goto err_unmap;
+
+ rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (WARN_ON(IS_ERR_VALUE(rc)))
+ goto err_unregister;
+
+ rc = clk_register_clkdev(clk, clk_name, NULL);
+ if (WARN_ON(IS_ERR_VALUE(rc)))
+ goto err_provider;
+
+ return clk;
+
+err_provider:
+ of_clk_del_provider(node);
+
+err_unregister:
+ clk_unregister(clk);
+
+err_unmap:
+ iounmap(cygnus_clk->regs_base);
+ iounmap(cygnus_clk->clock_gate_ctrl_reg);
+ iounmap(cygnus_clk->pll_ctrl_reg);
+
+err_alloc:
+ kfree(cygnus_clk);
+
+ return NULL;
+}
+
+static void __init cygnus_lcpll_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_lcpll_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll, "brcm,cygnus-lcpll-clk", cygnus_lcpll_init);
+
+static void __init cygnus_genpll_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_genpll_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll-clk", cygnus_genpll_init);
+
+static void __init cygnus_lcpll_ch_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_lcpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll_ch, "brcm,cygnus-lcpll-ch", cygnus_lcpll_ch_init);
+
+static void __init cygnus_genpll_ch_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_genpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll_ch, "brcm,cygnus-genpll-ch",
+ cygnus_genpll_ch_init);
+
+/*
+ * Some clocks on Cygnus are derived from the oscillator directly without
+ * going through either the GENPLL or LCPLL. These clocks have specific
+ * registers for their dividers. The clocks included are: keypad, ADC, PWM.
+ */
+
+#define ASIU_CLK_DIV_ENABLE_SHIFT 31
+#define ASIU_CLK_DIV_ENABLE_MASK 0x1
+#define ASIU_CLK_DIV_HIGH_SHIFT 16
+#define ASIU_CLK_DIV_HIGH_MASK 0x3ff
+#define ASIU_CLK_DIV_LOW_SHIFT 0
+#define ASIU_CLK_DIV_LOW_MASK 0x3ff
+
+/*
+ * Calculate clock frequency for clocks derived from oscillator.
+ *
+ * @return The clock rate in Hz
+ */
+static int cygnus_osc_derived_clk_get_rate(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ int reg_val;
+ int enabled;
+ int clk_div_high;
+ int clk_div_low;
+ unsigned long rate = 0;
+
+ reg_val = readl(clk->regs_base);
+
+ /* Ensure clock is enabled. */
+ enabled = (reg_val >> ASIU_CLK_DIV_ENABLE_SHIFT) &
+ ASIU_CLK_DIV_ENABLE_MASK;
+ if (!enabled)
+ return rate;
+
+ clk_div_high = (reg_val >> ASIU_CLK_DIV_HIGH_SHIFT) &
+ ASIU_CLK_DIV_HIGH_MASK;
+ clk_div_high += 1;
+
+ clk_div_low = (reg_val >> ASIU_CLK_DIV_LOW_SHIFT) &
+ ASIU_CLK_DIV_LOW_MASK;
+ clk_div_low += 1;
+
+ /*
+ * Rate calculated as:
+ * (oscillator rate) / ((clk high + 1) + (clk_low + 1))
+ */
+ rate = parent_rate / (clk_div_high + clk_div_low);
+
+ pr_debug("Osc derived clk: Prate=%lu div_high=%d div_low=%d rate=%lu\n",
+ parent_rate, clk_div_high, clk_div_low, rate);
+
+ return rate;
+}
+
+static unsigned long cygnus_osc_derived_clk_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_osc_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the top clock gating control for clocks that require it.
+ */
+static int cygnus_osc_derived_clk_enable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ int parent_rate;
+ u32 val;
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return 0;
+
+ pr_debug("OSC derived clk enable chan %d\n", clk->chan);
+
+ /* Enable top clock gating control if necessary. */
+ if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ KEYPAD_CLK_GATE_EN, true);
+ else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ ADC_CLK_GATE_EN, true);
+
+ /* Set and enable divider if specified. */
+ if (clk->internal_div != CLK_RATE_NO_DIV) {
+ val = (1 << ASIU_CLK_DIV_ENABLE_SHIFT) |
+ ((clk->internal_div & ASIU_CLK_DIV_HIGH_MASK) <<
+ ASIU_CLK_DIV_HIGH_SHIFT) |
+ ((clk->internal_div & ASIU_CLK_DIV_LOW_MASK) <<
+ ASIU_CLK_DIV_LOW_SHIFT);
+ writel(val, clk->regs_base);
+ }
+
+ /* Ensure parent's clock rate is calculated. */
+ parent_rate = clk_get_rate(parent_clk);
+ if (WARN_ON(!parent_rate))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Disables top clock gating control for clocks that were enabled.
+ */
+static void cygnus_osc_derived_clk_disable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return;
+
+ pr_debug("OSC derived clk disable chan %d\n", clk->chan);
+
+ /* Disable top clock gating control if necessary. */
+ if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ KEYPAD_CLK_GATE_EN, false);
+ else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ ADC_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_osc_derived_clk_ops = {
+ .enable = cygnus_osc_derived_clk_enable,
+ .disable = cygnus_osc_derived_clk_disable,
+ .recalc_rate = cygnus_osc_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_osc_derived_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_osc_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_osc_derived, "brcm,cygnus-osc-derived",
+ cygnus_osc_derived_init);
+
+/*
+ * Some clocks are derived from a PLL. The dividers are internal and can't
+ * be read from a register. If the parent clock rate changes then the derived
+ * clock rates scale accordingly.
+ */
+
+ /*
+ * Calculate clock frequency for clocks derived from oscillator.
+ * Rate calculated as: parent rate / internal divider
+ * The internal divider must be specified in DT.
+ *
+ * @return The clock rate in Hz.
+ */
+static unsigned long cygnus_pll_derived_clk_get_rate(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ unsigned long rate = parent_rate / clk->internal_div;
+
+ pr_debug("PLL derived clk: Prate=%lu rate=%lu\n", parent_rate, rate);
+
+ return rate;
+}
+
+static unsigned long cygnus_pll_derived_clk_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ return cygnus_pll_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_pll_derived_clk_ops = {
+ .recalc_rate = cygnus_pll_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_pll_derived_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_pll_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_pll_derived, "brcm,cygnus-pll-derived",
+ cygnus_pll_derived_init);
+
+/*
+ * MIPI DSI GENPLL
+ */
+
+/*
+ * Get PLL running status and calculate output frequency.
+ */
+static unsigned long cygnus_mipipll_get_rate(struct cygnus_clk *clk,
+ unsigned long parent_rate)
+{
+ u32 reg;
+ u32 rate;
+ u32 pdiv;
+ u32 ndiv_int;
+ u32 ndiv_frac;
+ int pll_locked;
+
+ /* Read lock field from PLL status register. It must be unlocked. */
+ reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+
+ pll_locked = (reg >> GENPLL_STATUS_LOCK_SHIFT) &
+ GENPLL_STATUS_LOCK_MASK;
+ if (pll_locked) {
+ clk->rate = 0;
+ return -EIO;
+ }
+ /*
+ * Calculate PLL frequency:
+ * PLL freq = ((crystal clock / pdiv) * ndiv ) / mdiv
+ */
+
+ /* Get PLL feedback divider values. */
+ reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+ /* Feedback divider integer and fractional parts. */
+ ndiv_int = (reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT) &
+ GENPLL_CONTROL4_NDIV_INT_MASK;
+ ndiv_frac = (reg >> GENPLL_CONTROL4_NDIV_FRAC_SHIFT) &
+ GENPLL_CONTROL4_NDIV_FRAC_MASK;
+ ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+ /* Get pdiv. */
+ reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+ pdiv = (reg >> GENPLL_CONTROL5_PDIV_SHIFT) &
+ GENPLL_CONTROL5_PDIV_MASK;
+
+ /* If pdiv is 0, divide by 0.5 - doubler. */
+ if (pdiv == 0)
+ rate = parent_rate * 2;
+ else
+ rate = parent_rate / pdiv;
+
+ clk->rate = rate * ndiv_int;
+
+ pr_debug("[MIPI PLL] parent rate=%lu, ndiv int=%d, pdiv=%d, rate=%lu\n",
+ parent_rate, ndiv_int, pdiv, clk->rate);
+
+ return clk->rate;
+}
+
+/*
+ * Powers on the necessary PLL's and LDO for MIPI GEN PLL.
+ */
+static int cygnus_mipipll_prepare(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->pll_ctrl_reg))
+ return -EIO;
+
+ pr_debug("Powering up MIPI PLL and LDO\n");
+
+ /* Power on the PLL. */
+ cygnus_mipi_genpll_power_on_off(clk->pll_ctrl_reg, true);
+
+ clk->state = CLK_PREPARED;
+
+ return 0;
+}
+
+/*
+ * Powers off the PLL's and LDO for MIPI GEN PLL.
+ */
+static void cygnus_mipipll_unprepare(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->pll_ctrl_reg))
+ return;
+
+ pr_debug("Powering down MIPI PLL and LDO\n");
+
+ /* Power off the PLL. */
+ cygnus_mipi_genpll_power_on_off(clk->pll_ctrl_reg, false);
+
+ clk->state = CLK_DISABLED;
+}
+
+static unsigned long cygnus_mipipll_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+ if (bcm_clk->state != CLK_ENABLED)
+ return 0;
+
+ return cygnus_mipipll_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the MIPI DSI clock gate through the top clock gating control.
+ */
+static int cygnus_mipipll_enable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return -EIO;
+
+ pr_debug("Enable MIPI PLL\n");
+
+ /* Enable MIPI DSI clock. */
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ MIPI_DSI_CLK_GATE_EN, true);
+
+ clk->state = CLK_ENABLED;
+
+ return 0;
+}
+
+/*
+ * Turns off the MIPI PLL clock.
+ */
+static void cygnus_mipipll_disable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return;
+
+ pr_debug("Disabling MIPI PLL and LDO\n");
+
+ /* Disable MIPI DSI clock through top clock gating control. */
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ MIPI_DSI_CLK_GATE_EN, false);
+
+ clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_ops = {
+ .prepare = cygnus_mipipll_prepare,
+ .unprepare = cygnus_mipipll_unprepare,
+ .enable = cygnus_mipipll_enable,
+ .disable = cygnus_mipipll_disable,
+ .recalc_rate = cygnus_mipipll_recalc_rate,
+};
+
+static void __init cygnus_mipipll_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_mipipll_ops);
+}
+CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll-clk", cygnus_mipipll_init);
+
+/*
+ * MIPI PLL clock channel management.
+ */
+
+/*
+ * Enables a MIPI PLL channel.
+ */
+static void mipi_pll_enable_chan(void __iomem *base, int chan, bool state)
+{
+ u32 val;
+
+ val = readl(base + GENPLL_CONTROL1_OFFSET);
+
+ /* ENABLEB_CH bit set to 0 to enable channel, 1 to disable. */
+ if (state)
+ val &= ~(1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+ else
+ val |= (1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+
+ writel(val, base + GENPLL_CONTROL1_OFFSET);
+}
+
+static unsigned long cygnus_mipipll_chan_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return 0;
+
+ if (clk->state != CLK_ENABLED)
+ return 0;
+
+ return cygnus_genpll_chan_get_rate(clk, parent_rate,
+ MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables the PLL channel and the top clock gating control for clocks that
+ * are controlled through it.
+ */
+static int cygnus_mipipll_chan_enable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+ struct clk *parent_clk = clk_get_parent(hwclk->clk);
+ int parent_rate;
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return -EIO;
+
+ pr_debug("Enable MIPI PLL chan %d\n", clk->chan);
+
+ /*
+ * Some MIPI PLL channels have to be enabled through the top clock
+ * gating ctrl. Add support for other channels here.
+ */
+ if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ LCD_CLK_GATE_EN, true);
+ }
+
+ /* Enable the PLL channel. */
+ mipi_pll_enable_chan(clk->regs_base, clk->chan, true);
+
+ clk->state = CLK_ENABLED;
+
+ /* Ensure parent's clock rate is calculated. */
+ parent_rate = clk_get_rate(parent_clk);
+ if (WARN_ON(!parent_rate))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Disables the PLL channel. Some channels also have to be shut down through
+ * the top clock gating control.
+ */
+static void cygnus_mipipll_chan_disable(struct clk_hw *hwclk)
+{
+ struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+ if (WARN_ON(!clk->clock_gate_ctrl_reg))
+ return;
+
+ pr_debug("Disable MIPI PLL chan %d\n", clk->chan);
+
+ /* Disable LCD clock through top clock gating control. */
+ if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+ cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+ LCD_CLK_GATE_EN, false);
+ }
+
+ /* Disable the PLL channel. */
+ mipi_pll_enable_chan(clk->regs_base, clk->chan, false);
+
+ clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_chan_ops = {
+ .enable = cygnus_mipipll_chan_enable,
+ .disable = cygnus_mipipll_chan_disable,
+ .recalc_rate = cygnus_mipipll_chan_recalc_rate,
+};
+
+static void __init cygnus_mipipll_ch_init(struct device_node *node)
+{
+ cygnus_clock_init(node, &cygnus_mipipll_chan_ops);
+}
+
+CLK_OF_DECLARE(cygnus_mipipll_ch, "brcm,cygnus-mipipll-ch",
+ cygnus_mipipll_ch_init);
diff --git a/drivers/clk/bcm/clk-iproc.c b/drivers/clk/bcm/clk-iproc.c
new file mode 100644
index 0000000..aca4851
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+#define IPROC_CLK_POLICY_FREQ_OFFSET 0x008
+#define IPROC_CLK_POLICY0_MSK_OFFSET 0x010
+#define IPROC_CLK_APB_SW_DIV_OFFSET 0xA10
+#define IPROC_CLK_PLL_ARMA_OFFSET 0xC00
+#define IPROC_CLK_PLL_ARMB_OFFSET 0xC04
+#define IPROC_CLK_PLL_ARMC_OFFSET 0xC08
+#define IPROC_CLK_PLL_ARMCTL5_OFFSET 0xC20
+#define IPROC_CLK_PLL_ARM_OFFSET_OFFSET 0xC24
+#define IPROC_CLK_ARM_DIV_OFFSET 0xE00
+#define IPROC_CLK_POLICY_DBG_OFFSET 0xEC0
+
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT 4
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK 0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK 0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT 8
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT 12
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK 7
+#define IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT 29
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET 20
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK 0xff
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET 0xfffff
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT 8
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK 0x3ff
+#define CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK 0xfffff
+#define CLK_PLL_ARMC_PLLARM_MDIV_MASK 0xff
+#define CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK 0xff
+#define CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT 8
+#define CLK_PLL_ARMA_PLLARM_PDIV_SHIFT 24
+#define CLK_PLL_ARMA_PLLARM_PDIV_MASK 0xf
+#define CLK_PLL_ARMA_PLLARM_LOCK_SHIFT 28
+#define CLK_ARM_DIV_APB0_FREE_DIV_SHIFT 8
+#define CLK_ARM_DIV_APB0_FREE_DIV_MASK 0x7
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT 8
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_MASK 0x3
+#define CLK_APB_SW_DIV_APB_CLK_DIV_MASK 0x3
+
+struct brcm_clk {
+ struct clk_hw hw;
+ void __iomem *regs_base;
+ int chan;
+ unsigned long rate;
+};
+
+/* Identifies derived clocks from ARM PLL. */
+enum {
+ ARMPLL_APB0_FREE_CLK = 0,
+ ARMPLL_ARM_SWITCH_CLK = 1,
+ ARMPLL_ARM_APB_CLK = 2,
+ ARMPLL_ARM_PERIPH_CLK = 3
+};
+
+/* Frequency id's from policy0_freq field of POLICY_FREQ register. */
+enum a9pll_policy_freq {
+ PLL_CRYSTAL_CLK = 0,
+ PLL_SYS_CLK = 2,
+ PLL_CH0_SLOW_CLK = 6,
+ PLL_CH1_FAST_CLK = 7
+};
+
+#define to_brcm_clk(p) container_of(p, struct brcm_clk, hw)
+
+static int iproc_cru_arm_freq_id(void __iomem *regs_base)
+{
+ u32 reg_f, reg;
+ unsigned policy = 0;
+ unsigned fid;
+ unsigned active_freq;
+
+ /* Read policy frequency. */
+ reg_f = readl(regs_base + IPROC_CLK_POLICY_FREQ_OFFSET);
+
+ /* Check for PLL policy software override. */
+ reg = readl(regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+ if (reg & (1 << IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT))
+ policy = reg & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
+
+ /* Get frequency ID based on policy. */
+ fid = (reg_f >>
+ (IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT * policy)) &
+ IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK;
+
+ /* Verify freq id from debug register. */
+ reg = readl(regs_base + IPROC_CLK_POLICY_DBG_OFFSET);
+ /* Read current active frequency id. */
+ active_freq = IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK &
+ (reg >> IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT);
+
+ if (fid != active_freq) {
+ pr_debug("IPROC CRU clock frequency id override %d->%d\n",
+ fid, active_freq);
+
+ fid = active_freq;
+ }
+
+ pr_debug("Active frequency ID %d\n", fid);
+
+ return fid;
+}
+
+/*
+ * Get ndiv integer and combine with fractional part to create 64 bit
+ * value.
+ */
+static u64 a9pll_get_ndiv(struct brcm_clk *clk)
+{
+ u32 arm_offset_reg;
+ u32 pllarma_reg;
+ u32 pllarmb_reg;
+ u32 ndiv_int;
+ u32 ndiv_frac;
+ u64 ndiv;
+
+ arm_offset_reg = readl(clk->regs_base +
+ IPROC_CLK_PLL_ARM_OFFSET_OFFSET);
+
+ /*
+ * Check if offset mode is active to determine which register to
+ * get ndiv from.
+ */
+ if (arm_offset_reg &
+ (1 << IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT)) {
+ /* Offset mode active. Get integer divide from offset reg. */
+ ndiv_int = (arm_offset_reg >>
+ CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET) &
+ CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK;
+
+ if (ndiv_int == 0)
+ ndiv_int = 256;
+
+ /* Get ndiv fractional divider. */
+ ndiv_frac = arm_offset_reg &
+ CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET;
+ } else {
+ /* Offset mode not active so read PLL ndiv from PLLARMA. */
+ pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+ ndiv_int = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT) &
+ CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK;
+
+ if (ndiv_int == 0)
+ ndiv_int = 1024;
+
+ /* Get ndiv fractional divider. */
+ pllarmb_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMB_OFFSET);
+ ndiv_frac = pllarmb_reg & CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK;
+ }
+
+ ndiv = ((u64) ndiv_int << 20) | ndiv_frac;
+
+ return ndiv;
+}
+
+/*
+ * Determine mdiv (post divider) based on the frequency id being used.
+ * There are 4 clocks that can be used to derive the output clock rate:
+ * - 25 MHz crystal
+ * - sys_clk
+ * - channel 0 (slow clock)
+ * - channel 1 (fast clock)
+ *
+ * If the slow clock is being used then mdiv is read from PLLARMC. If
+ * the fast clock is being used then the channel 1 mdiv is used.
+ * Otherwise there is no post divider.
+ *
+ * @return The mdiv value. -EIO if an error occurred.
+ */
+static int a9pll_get_mdiv(struct brcm_clk *clk)
+{
+ u32 mdiv;
+ u32 pllarmc_reg;
+ u32 armctl5_reg;
+ u32 freq_id;
+
+ /* Get the policy frequency. */
+ freq_id = iproc_cru_arm_freq_id(clk->regs_base);
+
+ switch (freq_id) {
+ /* There is no divider for these frequency id's. */
+ case PLL_CRYSTAL_CLK:
+ case PLL_SYS_CLK:
+ mdiv = 1;
+ break;
+
+ case PLL_CH0_SLOW_CLK: {
+ /* Read mdiv (post-divider) from PLLARMC bits 0:7 */
+ pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+ mdiv = pllarmc_reg & CLK_PLL_ARMC_PLLARM_MDIV_MASK;
+ if (mdiv == 0)
+ mdiv = 256;
+ break;
+ }
+
+ case PLL_CH1_FAST_CLK: {
+ /* Post divider for channel 1 is in CTL5 (pllarm_h_mdiv). */
+ armctl5_reg = readl(clk->regs_base +
+ IPROC_CLK_PLL_ARMCTL5_OFFSET);
+ mdiv = armctl5_reg & CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK;
+ if (mdiv == 0)
+ mdiv = 256;
+ break;
+ }
+
+ default:
+ return -EIO;
+ }
+
+ return mdiv;
+}
+
+/*
+ * Calculate the output frequency of the ARM PLL. The main output clock
+ * is 'arm_clk'.
+ *
+ * The frequency is calculated based on the ARM PLL divider values:
+ * pdiv = ARM PLL input pre-divider
+ * ndiv = ARM PLL feedback divider
+ * mdiv = ARM PLL post divider
+ *
+ * The frequency is calculated by:
+ * ((ndiv * parent clock rate) / pdiv) / mdiv
+ */
+static int a9pll_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+ u32 pllarma_reg;
+ u32 pllarmc_reg;
+ u32 pdiv;
+ u32 mdiv;
+ u64 ndiv;
+ u32 arm_clk_freq;
+
+ pr_debug("a9pll_status: clk 0x%x\n", (unsigned int)clk);
+
+ BUG_ON(!clk->regs_base);
+
+ pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+ pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+
+ /* Check if PLL is in bypass mode - input frequency to output */
+ if (pllarmc_reg & (1 << CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT)) {
+ clk->rate = parent_rate;
+ return 0;
+ }
+
+ /* Check if PLL is locked. It must be unlocked. */
+ if ((pllarma_reg &
+ (1 << CLK_PLL_ARMA_PLLARM_LOCK_SHIFT)) == 0) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /* Read pdiv from PLLARMA. */
+ pdiv = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_PDIV_SHIFT) &
+ CLK_PLL_ARMA_PLLARM_PDIV_MASK;
+ if (pdiv == 0)
+ pdiv = 16;
+
+ /* Determine ndiv. */
+ ndiv = a9pll_get_ndiv(clk);
+
+ /* Determine mdiv (post divider). */
+ mdiv = a9pll_get_mdiv(clk);
+ if (mdiv == -EIO) {
+ clk->rate = 0;
+ return -EIO;
+ }
+
+ /* Calculate clock frequency. */
+ arm_clk_freq = (ndiv * parent_rate) >> 20;
+ arm_clk_freq = (arm_clk_freq / pdiv) / mdiv;
+
+ clk->rate = arm_clk_freq;
+
+ pr_debug("ARM PLL (arm_clk) rate %lu. parent rate = %lu, ",
+ clk->rate, parent_rate);
+ pr_debug("ndiv_int = %d, pdiv = %d, mdiv = %d\n",
+ (u32)ndiv >> 20, pdiv, mdiv);
+
+ return clk->rate;
+}
+
+static unsigned long clk_a9pll_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+ return a9pll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_ops = {
+ .recalc_rate = clk_a9pll_recalc_rate,
+};
+
+/*
+ * Get status of any of the ARMPLL output channels
+ */
+static int a9pll_chan_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+ u32 reg;
+ unsigned div;
+
+ BUG_ON(!clk->regs_base);
+
+ reg = readl(clk->regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+ pr_debug("Clock Div = %#x\n", reg);
+
+ switch (clk->chan) {
+ case ARMPLL_APB0_FREE_CLK:
+ /* apb0_free_div bits 10:8 */
+ div = (reg >> CLK_ARM_DIV_APB0_FREE_DIV_SHIFT) &
+ CLK_ARM_DIV_APB0_FREE_DIV_MASK;
+ div++;
+ break;
+
+ case ARMPLL_ARM_SWITCH_CLK:
+ /* arm_switch_div bits 6:5 */
+ div = (reg >> CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT) &
+ CLK_ARM_DIV_ARM_SWITCH_DIV_MASK;
+ div++;
+ break;
+
+ case ARMPLL_ARM_APB_CLK:
+ /* IPROC_CLK_APB_SW_DIV_REG apb_clk_div bits 1:0 */
+ reg = readl(clk->regs_base + IPROC_CLK_APB_SW_DIV_OFFSET);
+ div = reg & CLK_APB_SW_DIV_APB_CLK_DIV_MASK;
+ div++;
+ break;
+
+ case ARMPLL_ARM_PERIPH_CLK: /* periph_clk */
+ div = 2;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ clk->rate = parent_rate / div;
+ pr_debug("Clock rate A9PLL chan 0x%x: %lu, div: %d\n",
+ clk->chan, clk->rate, div);
+
+ return clk->rate;
+}
+
+static unsigned long clk_a9pll_chan_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+ return a9pll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_chan_ops = {
+ .recalc_rate = clk_a9pll_chan_recalc_rate,
+};
+
+static __init struct clk *iproc_clock_init(struct device_node *node,
+ const struct clk_ops *ops)
+{
+ u32 channel = 0;
+ struct clk *clk;
+ struct brcm_clk *brcm_clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct clk_init_data init;
+ int rc;
+
+ pr_debug("Clock name %s\n", node->name);
+
+ rc = of_property_read_u32(node, "channel", &channel);
+ brcm_clk = kzalloc(sizeof(*brcm_clk), GFP_KERNEL);
+ if (WARN_ON(!brcm_clk))
+ return NULL;
+
+ /* Read base address from device tree and map to virtual address. */
+ brcm_clk->regs_base = of_iomap(node, 0);
+ if (WARN_ON(!brcm_clk->regs_base))
+ goto err_alloc;
+
+ brcm_clk->chan = channel;
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = ops;
+ init.flags = 0;
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ brcm_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &brcm_clk->hw);
+ if (WARN_ON(IS_ERR(clk)))
+ goto err_unmap;
+
+ rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (WARN_ON(IS_ERR_VALUE(rc)))
+ goto err_unregister;
+
+ rc = clk_register_clkdev(clk, clk_name, NULL);
+ if (WARN_ON(IS_ERR_VALUE(rc)))
+ goto err_provider;
+
+ return clk;
+
+err_provider:
+ of_clk_del_provider(node);
+
+err_unregister:
+ clk_unregister(clk);
+
+err_unmap:
+ iounmap(brcm_clk->regs_base);
+
+err_alloc:
+ kfree(brcm_clk);
+
+ return NULL;
+}
+
+static void __init iproc_armpll_init(struct device_node *node)
+{
+ iproc_clock_init(node, &a9pll_ops);
+}
+CLK_OF_DECLARE(iproc_armpllx, "brcm,iproc-arm-a9pll", iproc_armpll_init);
+
+static void __init iproc_arm_ch_init(struct device_node *node)
+{
+ iproc_clock_init(node, &a9pll_chan_ops);
+}
+CLK_OF_DECLARE(iproc_arm_ch, "brcm,iproc-arm-ch", iproc_arm_ch_init);
--
1.7.9.5

2014-10-08 05:27:49

by Scott Branden

[permalink] [raw]
Subject: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

From: Jonathan Richardson <[email protected]>

Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.

Reviewed-by: Ray Jui <[email protected]>
Reviewed-by: Desmond Liu <[email protected]>
Reviewed-by: JD (Jiandong) Zheng <[email protected]>
Tested-by: Jonathan Richardson <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
arch/arm/mach-bcm/Kconfig | 31 ++++++++
arch/arm/mach-bcm/Makefile | 3 +
arch/arm/mach-bcm/bcm_cygnus.c | 166 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 200 insertions(+)
create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c

diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index fc93800..2dd3f78 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -5,6 +5,37 @@ menuconfig ARCH_BCM

if ARCH_BCM

+config ARCH_BCM_IPROC
+ bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
+ select ARM_GIC
+ select CACHE_L2X0
+ select HAVE_ARM_TWD if LOCAL_TIMERS
+ select HAVE_CLK
+ select CLKSRC_OF
+ select CLKSRC_MMIO
+ select GENERIC_CLOCKEVENTS
+ select ARM_GLOBAL_TIMER
+ select ARCH_REQUIRE_GPIOLIB
+ select ARM_AMBA
+ select PINCTRL
+ select DEBUG_UART_8250
+ help
+ This enables support for systems based on Broadcom IPROC architected SoCs.
+ The IPROC complex contains one or more ARM CPUs along with common
+ core periperals. Application specific SoCs are created by adding a
+ uArchitecture containing peripherals outside of the IPROC complex.
+ Currently supported SoCs are Cygnus.
+
+menu "iProc SoC based Machine types"
+ depends on ARCH_BCM_IPROC
+
+ config ARCH_BCM_CYGNUS
+ bool "Support Broadcom Cygnus board"
+ select USB_ARCH_HAS_EHCI if USB_SUPPORT
+ help
+ Support for Broadcom Cygnus SoC.
+endmenu
+
config ARCH_BCM_MOBILE
bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index b19a396..46e092a 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -10,6 +10,9 @@
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

+# Cygnus
+obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
+
# BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o

diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c
new file mode 100644
index 0000000..8e430ed
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm_cygnus.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CRMU_MAIL_BOX1 0x03024028
+#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
+
+/* CRU_RESET register */
+static void * __iomem crmu_mail_box1_reg;
+
+#ifdef CONFIG_NEON
+
+#define CRU_BASE 0x1800e000
+#define CRU_SIZE 0x34
+#define CRU_CONTROL_OFFSET 0x0
+#define CRU_PWRDWN_EN_OFFSET 0x4
+#define CRU_PWRDWN_STATUS_OFFSET 0x8
+#define CRU_NEON0_HW_RESET 6
+#define CRU_CLAMP_ON_NEON0 20
+#define CRU_PWRONIN_NEON0 21
+#define CRU_PWRONOUT_NEON0 21
+#define CRU_PWROKIN_NEON0 22
+#define CRU_PWROKOUT_NEON0 22
+#define CRU_STATUS_DELAY_NS 500
+#define CRU_MAX_RETRY_COUNT 10
+#define CRU_RETRY_INTVL_US 1
+
+/* Power up the NEON/VFPv3 block. */
+static void bcm_cygnus_powerup_neon(void)
+{
+ void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
+ u32 reg, i;
+
+ if (WARN_ON(!cru_base))
+ return;
+
+ /* De-assert the neon hardware block reset */
+ reg = readl(cru_base + CRU_CONTROL_OFFSET);
+ reg &= ~(1 << CRU_NEON0_HW_RESET);
+ writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+ /* Assert the power ON register bit */
+ reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+ reg |= (1 << CRU_PWRONIN_NEON0);
+ writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+ /*
+ * Wait up to 10 usec in 1 usec increments for the
+ * status register to acknowledge the power ON assert
+ */
+ for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+ reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+ if (reg & CRU_PWRONOUT_NEON0)
+ break;
+
+ udelay(CRU_RETRY_INTVL_US);
+ }
+
+ if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
+ goto neon_unmap;
+
+ /* Wait 0.5 usec = 500 nsec */
+ ndelay(CRU_STATUS_DELAY_NS);
+
+ /* Assert the power OK register bit */
+ reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+ reg |= (1 << CRU_PWROKIN_NEON0);
+ writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+ /*
+ * Wait up to 10 usec in 1 usec increments for the
+ * status register to acknowledge the power OK assert
+ */
+ for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+ reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+ if (reg & CRU_PWROKOUT_NEON0)
+ break;
+
+ udelay(CRU_RETRY_INTVL_US);
+ }
+
+ if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
+ goto neon_unmap;
+
+ /* Wait 0.5 usec = 500 nsec */
+ ndelay(CRU_STATUS_DELAY_NS);
+
+ /* Set the logic clamp for the neon block */
+ reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+ reg &= ~(1 << CRU_CLAMP_ON_NEON0);
+ writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+ /* Wait 0.5 usec = 500 nsec */
+ ndelay(CRU_STATUS_DELAY_NS);
+
+ /* Reset the neon hardware block */
+ reg = readl(cru_base + CRU_CONTROL_OFFSET);
+ reg |= (1 << CRU_NEON0_HW_RESET);
+ writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+neon_unmap:
+ iounmap(cru_base);
+}
+#endif /* CONFIG_NEON */
+
+static void __init bcm_cygnus_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ l2x0_of_init(0, ~0UL);
+
+ crmu_mail_box1_reg = ioremap(CRMU_MAIL_BOX1, SZ_4);
+ WARN_ON(!crmu_mail_box1_reg);
+
+#ifdef CONFIG_NEON
+ bcm_cygnus_powerup_neon();
+#endif
+}
+
+/*
+ * Reset the system
+ */
+void bcm_cygnus_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Send reset command to M0 via Mailbox. */
+ if (crmu_mail_box1_reg) {
+ writel(CRMU_SOFT_RESET_CMD, crmu_mail_box1_reg);
+ iounmap(crmu_mail_box1_reg);
+ }
+
+ /* Wait for M0 to reset the chip. */
+ while (1)
+ cpu_do_idle();
+}
+
+static const char const *bcm_cygnus_dt_compat[] = {
+ "brcm,cygnus",
+ NULL,
+};
+
+DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
+ .init_machine = bcm_cygnus_init,
+ .map_io = debug_ll_io_init,
+ .dt_compat = bcm_cygnus_dt_compat,
+ .restart = bcm_cygnus_restart
+MACHINE_END
--
1.7.9.5

2014-10-08 05:28:38

by Scott Branden

[permalink] [raw]
Subject: [PATCH 5/6] ARM: dts: Enable Broadcom Cygnus SoC

From: Jonathan Richardson <[email protected]>

DT files to enable cygnus consisting of the enterprise phone board variant and
cygnus core configuration.

Reviewed-by: Ray Jui <[email protected]>
Reviewed-by: Arun Parameswaran <[email protected]>
Tested-by: Jonathan Richardson <[email protected]>
Reviewed-by: JD (Jiandong) Zheng <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/bcm-cygnus.dtsi | 349 ++++++++++++++++++++++++++++++++
arch/arm/boot/dts/bcm911360_entphn.dts | 22 ++
3 files changed, 372 insertions(+)
create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b8c5cd3..b95d41d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -52,6 +52,7 @@ dtb-$(CONFIG_ARCH_AT91) += sama5d36ek.dtb
dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
+dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb
dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb
dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
bcm21664-garnet.dtb
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
new file mode 100644
index 0000000..81da0d8
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "brcm,cygnus";
+ model = "Broadcom Cygnus SoC";
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart3;
+ serial1 = &uart0;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlyprintk debug";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x0>;
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ lcpll: lcpll@0301d02c {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-lcpll-clk";
+ reg = <0x0301d02c 0x1c>;
+ clocks = <&osc>;
+ };
+
+ genpll: genpll@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-clk";
+ reg = <0x0301d000 0x2c>,
+ <0x180AA024 0x4>,
+ <0x0301C020 0x4>;
+ clocks = <&osc>;
+ };
+
+ axi21_clk: genpll_ch0@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <0>;
+ };
+
+ clk_25MHz: genpll_ch1@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <1>;
+ };
+
+ sys_clk: genpll_ch2@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <2>;
+ };
+
+ ethernet_clk: genpll_ch3@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <3>;
+ };
+
+ asiu_audio_clk: genpll_ch4@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <4>;
+ };
+
+ asiu_can_clk: genpll_ch5@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <5>;
+ };
+
+ pcie_clk: lcpll_ch0@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <0>;
+ };
+
+ ddr_clk: lcpll_ch1@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <1>;
+ };
+
+ sdio_clk: lcpll_ch2@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <2>;
+ };
+
+ usb_clk: lcpll_ch3@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <3>;
+ };
+
+ smart_card_clk: lcpll_ch4@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <4>;
+ };
+
+ ch5_unknown_clk: lcpll_ch5@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <5>;
+ };
+
+ /*
+ * There are 2 clocks derived from genpll ch0 (axi21) which are
+ * divided internally by 2 and 4. If axi21 clock rate changes, these
+ * derived clock rates scale accordingly.
+ */
+
+ axi41_clk: axi41_clk {
+ reg = <0x0301d000 0x2c>;
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-pll-derived";
+ clocks = <&axi21_clk>;
+ div = <2>;
+ };
+
+ axi81_clk: axi81_clk {
+ reg = <0x0301d000 0x2c>;
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-pll-derived";
+ clocks = <&axi21_clk>;
+ div = <4>;
+ };
+
+ /*
+ * The main output of the ARM PLL is arm_clk with several derived
+ * child clocks:
+ * periph_clk
+ * apb_clk
+ * arm_switch
+ * apb0_free
+ */
+ a9pll: arm_clk@19000000 {
+ compatible = "brcm,iproc-arm-a9pll";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ };
+
+ periph_clk: periph_clk@19000000 {
+ compatible = "brcm,iproc-arm-ch";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&a9pll>;
+ channel = <3>;
+ };
+
+ apb0_free: apb0_free@19000000 {
+ compatible = "brcm,iproc-arm-ch";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&a9pll>;
+ channel = <0>;
+ };
+
+ arm_switch: arm_switch@19000000 {
+ compatible = "brcm,iproc-arm-ch";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&a9pll>;
+ channel = <1>;
+ };
+
+ apb_clk: apb_clk@19000000 {
+ compatible = "brcm,iproc-arm-ch";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&a9pll>;
+ channel = <2>;
+ };
+
+ /*
+ * Clocks derived from oscillator.
+ */
+ keypad_clk: keypad_clk@0301D048 {
+ compatible = "brcm,cygnus-osc-derived";
+ reg = <0x0301D048 0x4>,
+ <0x180AA024 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ channel = <0>;
+ div = <392>;
+ };
+
+ adc_clk: adc_clk@0301D04C {
+ compatible = "brcm,cygnus-osc-derived";
+ reg = <0x0301D04C 0x4>,
+ <0x180AA024 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ channel = <1>;
+ };
+
+ pwm_clk: pwm_clk@0301D050 {
+ compatible = "brcm,cygnus-osc-derived";
+ reg = <0x0301D050 0x4>,
+ <0x180AA024 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ channel = <2>;
+ };
+
+ mipipll: mipipll@180a9800 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-mipipll-clk";
+ reg = <0x180a9800 0x2c>,
+ top_clk_gating_ctrl: <0x180AA024 0x4>,
+ crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+ clocks = <&osc>;
+ };
+
+ lcd_clk: mipipll_ch1@180a9800 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-mipipll-ch";
+ reg = <0x180a9800 0x2c>,
+ <0x180AA024 0x4>;
+ clocks = <&mipipll>;
+ channel = <1>;
+ };
+ };
+
+ amba {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,amba-bus", "simple-bus";
+ interrupt-parent = <&gic>;
+ ranges;
+
+ wdt@18009000 {
+ compatible = "arm,sp805" , "arm,primecell";
+ reg = <0x18009000 0x1000>;
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-names = "apb_pclk";
+ };
+ };
+
+ uart3: serial@18023000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18023000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <100000000>;
+ clocks = <&axi81_clk>;
+ status = "okay";
+ };
+
+ uart0: serial@18020000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18020000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "okay";
+ };
+
+ gic: interrupt-controller@19021000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x19021000 0x1000>,
+ <0x19020100 0x100>;
+ };
+
+ L2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0x19022000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ timer@19020200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x19020200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
new file mode 100644
index 0000000..cee4aff
--- /dev/null
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+ model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
+ compatible = "brcm,bcm911360_entphn", "brcm,cygnus";
+};
--
1.7.9.5

2014-10-08 05:28:59

by Scott Branden

[permalink] [raw]
Subject: [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver

From: Jonathan Richardson <[email protected]>

Reviewed-by: Arun Parameswaran <[email protected]>
Tested-by: Jonathan Richardson <[email protected]>
Reviewed-by: JD (Jiandong) Zheng <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
Documentation/devicetree/bindings/arm/cygnus.txt | 12 ++
.../devicetree/bindings/clock/clk-cygnus.txt | 121 ++++++++++++++++++++
.../devicetree/bindings/clock/clk-iproc.txt | 48 ++++++++
3 files changed, 181 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt

diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
new file mode 100644
index 0000000..a210377
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cygnus.txt
@@ -0,0 +1,12 @@
+Broadcom Cygnus device tree bindings
+------------------------------------
+
+All Cygnus boards shall have the following properties:
+
+Required root node property:
+ - compatible = "brcm,cygnus";
+
+Boards variants shall have the following additional properties:
+
+Required root node property for the BCM911360_ENTPHN board:
+ - compatible = "brcm,bcm911360_entphn";
diff --git a/Documentation/devicetree/bindings/clock/clk-cygnus.txt b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
new file mode 100644
index 0000000..7e03837
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
@@ -0,0 +1,121 @@
+Broadcom Cygnus Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The Cygnus clock controller manages several PLL's and their channels, found only
+on the Cygnus chip. Clocks that are common to iProc can be found in the iProc
+clock controller. The controllers are split into a parent-child relationship
+where the parent is the PLL and the child controls the PLL's channels.
+
+All PLL's are derived from a 25MHz oscillator. The PLL's controlled are the
+GENPLL, LCPLL, the MIPI PLL. In addition, there are two clocks derived from
+GENPLL channel 0, and three that are derived directly from the oscillator.
+
+Required properties:
+- compatible: Must be one of the following:
+ "brcm,cygnus-lcpll-clk" - Controls LCPLL.
+ "brcm,cygnus-lcpll-ch" - Controls LCPLL (parent) channels
+ "brcm,cygnus-genpll-clk" - Controls parent GENPLL
+ "brcm,cygnus-genpll-ch" - Controls GENPLL (parent) channels
+ "brcm,cygnus-mipipll-clk" - Controls MIPI PLL
+ "brcm,cygnus-mipipll-ch" - Controls parent MIPI PLL (parent) channels
+ "brcm,cygnus-osc-derived" - Controls oscillator (parent) derived channels
+ not controlled by any PLL.
+ "brcm,cygnus-pll-derived" - Controls clocks derived from GENPLL channel 0.
+ These clocks have hard wired internal dividers and their clock rates
+ scale according to the GENPLL channel.
+
+- reg: First register is the base address of the PLL. Register 2 and 3 are
+ required by some clocks. They are the top clock gating control used to
+ enable/disable clocks (ch 1), and the CRMU PLL AON CONTROL register which
+ powers on PLL/LDO's (ch 2).
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+ oscillator, or GENPLL channel 0.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+ "brcm,cygnus-lcpll-ch", "brcm,cygnus-genpll-ch", "brcm,cygnus-mipipll-ch",
+ "brcm,cygnus-osc-derived" only.
+
+- div: Used by "brcm,cygnus-pll-derived" to define the hard coded internal
+ divider value. Used by "brcm,cygnus-osc-derived" to specify the programmable
+ divider.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Examples:
+
+ osc: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ lcpll: lcpll@0301d02c {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-lcpll-clk";
+ reg = <0x0301d02c 0x1c>;
+ clocks = <&osc>;
+ };
+
+ genpll: genpll@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-clk";
+ reg = <0x0301d000 0x2c>,
+ <0x180AA024 0x4>,
+ <0x0301C020 0x4>;
+ clocks = <&osc>;
+ };
+
+ axi21_clk: genpll_ch0@0301d000 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-genpll-ch";
+ reg = <0x0301d000 0x2c>;
+ clocks = <&genpll>;
+ channel = <0>;
+ };
+
+ pcie_clk: lcpll_ch0@0301d02c {
+ compatible = "brcm,cygnus-lcpll-ch";
+ reg = <0x0301d02c 0x1c>;
+ #clock-cells = <0>;
+ clocks = <&lcpll>;
+ channel = <0>;
+ };
+
+ axi41_clk: axi41_clk {
+ reg = <0x0301d000 0x2c>;
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-pll-derived";
+ clocks = <&axi21_clk>;
+ div = <2>;
+ };
+
+ keypad_clk: keypad_clk@0301D048 {
+ compatible = "brcm,cygnus-osc-derived";
+ reg = <0x0301D048 0x4>,
+ <0x180AA024 0x4>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ channel = <0>;
+ div = <392>;
+ };
+
+ mipipll: mipipll@180a9800 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-mipipll-clk";
+ reg = <0x180a9800 0x2c>,
+ top_clk_gating_ctrl: <0x180AA024 0x4>,
+ crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+ clocks = <&osc>;
+ };
+
+ lcd_clk: mipipll_ch1@180a9800 {
+ #clock-cells = <0>;
+ compatible = "brcm,cygnus-mipipll-ch";
+ reg = <0x180a9800 0x2c>,
+ <0x180AA024 0x4>;
+ clocks = <&mipipll>;
+ channel = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/clk-iproc.txt b/Documentation/devicetree/bindings/clock/clk-iproc.txt
new file mode 100644
index 0000000..b5d4f08
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-iproc.txt
@@ -0,0 +1,48 @@
+Broadcom iProc Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The iProc clock controller manages clocks that are common to iProc chips.
+The controllers are split into a parent-child relationship where the parent is
+the PLL and the child controls the PLL's channels.
+
+The only PLL controlled is the ARM PLL which is derived from a 25MHz crystal.
+
+Required properties:
+- compatible: Must be one of the following:
+ "brcm,iproc-arm-a9pll" - Controls ARM PLL.
+ "brcm,iproc-arm-ch" - Controls ARM PLL (parent) channels
+
+- reg: The base address of the PLL.
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+ or oscillator.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+ "brcm,iproc-arm-ch" only.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Example:
+
+ osc: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ a9pll: arm_clk@19000000 {
+ compatible = "brcm,iproc-arm-a9pll";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&osc>;
+ };
+
+ periph_clk: periph_clk@19000000 {
+ compatible = "brcm,iproc-arm-ch";
+ reg = <0x19000000 0x1000>;
+ #clock-cells = <0>;
+ clocks = <&a9pll>;
+ channel = <3>;
+ };
--
1.7.9.5

2014-10-08 05:28:57

by Scott Branden

[permalink] [raw]
Subject: [PATCH 4/6] ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC

From: Jonathan Richardson <[email protected]>

Tested-by: Jonathan Richardson <[email protected]>
Reviewed-by: JD (Jiandong) Zheng <[email protected]>
Signed-off-by: Scott Branden <[email protected]>
---
arch/arm/configs/bcm_cygnus_defconfig | 222 +++++++++++++++++++++++++++++++++
1 file changed, 222 insertions(+)
create mode 100644 arch/arm/configs/bcm_cygnus_defconfig

diff --git a/arch/arm/configs/bcm_cygnus_defconfig b/arch/arm/configs/bcm_cygnus_defconfig
new file mode 100644
index 0000000..d148f2d
--- /dev/null
+++ b/arch/arm/configs/bcm_cygnus_defconfig
@@ -0,0 +1,222 @@
+CONFIG_KERNEL_XZ=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM_IPROC=y
+CONFIG_ARCH_BCM_CYGNUS=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+# CONFIG_COMPACTION is not set
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CONNTRACK_PROCFS is not set
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_EUI64=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_UBI=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_BROADCOM_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_PWM=y
+CONFIG_EXT4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=110
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_UART_8250=y
+CONFIG_DEBUG_UART_PHYS=0x18023000
+CONFIG_DEBUG_UART_VIRT=0xf1023000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
--
1.7.9.5

2014-10-08 07:55:13

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Tuesday 07 October 2014 22:27:00 Scott Branden wrote:
> From: Jonathan Richardson <[email protected]>
>
> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
>
> Reviewed-by: Ray Jui <[email protected]>
> Reviewed-by: Desmond Liu <[email protected]>
> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
> Tested-by: Jonathan Richardson <[email protected]>
> Signed-off-by: Scott Branden <[email protected]>
> ---
> arch/arm/mach-bcm/Kconfig | 31 ++++++++
> arch/arm/mach-bcm/Makefile | 3 +
> arch/arm/mach-bcm/bcm_cygnus.c | 166 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 200 insertions(+)
> create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>
> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
> index fc93800..2dd3f78 100644
> --- a/arch/arm/mach-bcm/Kconfig
> +++ b/arch/arm/mach-bcm/Kconfig
> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
>
> if ARCH_BCM
>
> +config ARCH_BCM_IPROC
> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
> + select ARM_GIC
> + select CACHE_L2X0
> + select HAVE_ARM_TWD if LOCAL_TIMERS
> + select HAVE_CLK
> + select CLKSRC_OF
> + select CLKSRC_MMIO
> + select GENERIC_CLOCKEVENTS
> + select ARM_GLOBAL_TIMER
> + select ARCH_REQUIRE_GPIOLIB
> + select ARM_AMBA
> + select PINCTRL
> + select DEBUG_UART_8250

A lot of these are implied by ARCH_MULTI_V7, just drop them here.

Some others like DEBUG_UART_8250 should remain user-selectable, if
the platform works without them.

> + help
> + This enables support for systems based on Broadcom IPROC architected SoCs.
> + The IPROC complex contains one or more ARM CPUs along with common
> + core periperals. Application specific SoCs are created by adding a
> + uArchitecture containing peripherals outside of the IPROC complex.
> + Currently supported SoCs are Cygnus.
> +
> +menu "iProc SoC based Machine types"
> + depends on ARCH_BCM_IPROC
> +
> + config ARCH_BCM_CYGNUS
> + bool "Support Broadcom Cygnus board"
> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
> + help
> + Support for Broadcom Cygnus SoC.
> +endmenu

I don't think you need per-board config options. The main option
above should be enough.

> +
> +#define CRMU_MAIL_BOX1 0x03024028
> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF

Never hardcode physical register locations in source. This should come
from DT, and get moved into a regular 'reset' device driver.

You probably want to use drivers/power/reset/syscon-reboot.c

> +/* CRU_RESET register */
> +static void * __iomem crmu_mail_box1_reg;
> +
> +#ifdef CONFIG_NEON
> +
> +#define CRU_BASE 0x1800e000
> +#define CRU_SIZE 0x34
> +#define CRU_CONTROL_OFFSET 0x0
> +#define CRU_PWRDWN_EN_OFFSET 0x4
> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
> +#define CRU_NEON0_HW_RESET 6
> +#define CRU_CLAMP_ON_NEON0 20
> +#define CRU_PWRONIN_NEON0 21
> +#define CRU_PWRONOUT_NEON0 21
> +#define CRU_PWROKIN_NEON0 22
> +#define CRU_PWROKOUT_NEON0 22
> +#define CRU_STATUS_DELAY_NS 500
> +#define CRU_MAX_RETRY_COUNT 10
> +#define CRU_RETRY_INTVL_US 1
> +
> +/* Power up the NEON/VFPv3 block. */
> +static void bcm_cygnus_powerup_neon(void)
> +{
> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
> + u32 reg, i;

Same thing here: this should really use the device node for CRU.

Can you describe what the CRU is? Is this specific to NEON or is
it some general-purpose power management unit?

> +static void __init bcm_cygnus_init(void)
> +{
> + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +
> + l2x0_of_init(0, ~0UL);

The l2x0_of_init can be removed now, just move the arguments into the
respective fields of the machine descriptor.

> + crmu_mail_box1_reg = ioremap(CRMU_MAIL_BOX1, SZ_4);
> + WARN_ON(!crmu_mail_box1_reg);
> +
> +#ifdef CONFIG_NEON
> + bcm_cygnus_powerup_neon();
> +#endif
> +}

In general, try to avoid #ifdef, use

if (IS_ENABLED(CONFIG_NEON))
bcm_cygnus_powerup_neon();

instead.

> +
> +static const char const *bcm_cygnus_dt_compat[] = {
> + "brcm,cygnus",
> + NULL,
> +};
> +
> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
> + .init_machine = bcm_cygnus_init,
> + .map_io = debug_ll_io_init,
> + .dt_compat = bcm_cygnus_dt_compat,
> + .restart = bcm_cygnus_restart
> +MACHINE_END

The map_io pointer is unnecessary, and the restart pointer should get
set by the reset driver. I hope we can find a way to avoid the
bcm_cygnus_init callback as well.

Arnd

2014-10-08 07:57:53

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver

On Tuesday 07 October 2014 22:27:02 Scott Branden wrote:
> diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
> new file mode 100644
> index 0000000..a210377
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/cygnus.txt
> @@ -0,0 +1,12 @@
> +Broadcom Cygnus device tree bindings
> +------------------------------------
> +
> +All Cygnus boards shall have the following properties:
> +
> +Required root node property:
> + - compatible = "brcm,cygnus";

Can you add a more specific model number for the soc as well?
I assume that cygnus refers to more than one model, so you
should probably list both the family and the individual
SoC type here.

> +Boards variants shall have the following additional properties:
> +
> +Required root node property for the BCM911360_ENTPHN board:
> + - compatible = "brcm,bcm911360_entphn";
>

We normally don't list specific boards here, since it's hard to
keep up.

Arnd

2014-10-08 07:58:38

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 4/6] ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC

On Tuesday 07 October 2014 22:27:03 Scott Branden wrote:
> From: Jonathan Richardson <[email protected]>
>
> Tested-by: Jonathan Richardson <[email protected]>
> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
> Signed-off-by: Scott Branden <[email protected]>

Do you actually need a separate defconfig?

If possible, just add your drivers to multi_v7_defconfig, otherwise
include a justification in the patch changelog why your platform
should have its own defconfig file.

Arnd

2014-10-08 08:11:51

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Tue, Oct 07, 2014 at 10:27:00PM -0700, Scott Branden wrote:
> +static void __init bcm_cygnus_init(void)
> +{
> + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +
> + l2x0_of_init(0, ~0UL);

Please don't explicitly call l2x0 initialisation. Instead, set the
appropriate l2c members here:

> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
> + .init_machine = bcm_cygnus_init,
> + .map_io = debug_ll_io_init,
> + .dt_compat = bcm_cygnus_dt_compat,
> + .restart = bcm_cygnus_restart
> +MACHINE_END

and let the core code call it at the appropriate time. Thanks.

--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

2014-10-08 10:58:20

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver

On 14-10-08 12:57 AM, Arnd Bergmann wrote:
> On Tuesday 07 October 2014 22:27:02 Scott Branden wrote:
>> diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
>> new file mode 100644
>> index 0000000..a210377
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/cygnus.txt
>> @@ -0,0 +1,12 @@
>> +Broadcom Cygnus device tree bindings
>> +------------------------------------
>> +
>> +All Cygnus boards shall have the following properties:
>> +
>> +Required root node property:
>> + - compatible = "brcm,cygnus";
>
> Can you add a more specific model number for the soc as well?
> I assume that cygnus refers to more than one model, so you
> should probably list both the family and the individual
> SoC type here.
Add specific model numbers does not seem necessary because they are not
needed to be specified in the device tree for compatible purposes for
the kernel to work. Plus, the list of model numbers will continue to
grow over time and compatible strings would need to be added to the
kernel for no apparent reason?
>
>> +Boards variants shall have the following additional properties:
>> +
>> +Required root node property for the BCM911360_ENTPHN board:
>> + - compatible = "brcm,bcm911360_entphn";
>>
>
> We normally don't list specific boards here, since it's hard to
> keep up.
Thanks - removed specific boards from file and moved the cygnus.txt file
to devicetree/bindings/arm/bcm/cygnus.txt in next version. This seems
to be like the appropriate place to put this document. We will need to
add back in board specific bindings when ALSA support is added. But
that will be a later commit to deal with.
>
> Arnd
>

2014-10-08 11:01:12

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 4/6] ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC

On 14-10-08 12:58 AM, Arnd Bergmann wrote:
> On Tuesday 07 October 2014 22:27:03 Scott Branden wrote:
>> From: Jonathan Richardson <[email protected]>
>>
>> Tested-by: Jonathan Richardson <[email protected]>
>> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
>> Signed-off-by: Scott Branden <[email protected]>
>
> Do you actually need a separate defconfig?
>
> If possible, just add your drivers to multi_v7_defconfig, otherwise
> include a justification in the patch changelog why your platform
> should have its own defconfig file.
We need a separate defconfig so that customers and developers have some
chance of understanding what kernel drivers apply to their SoC. That
way they can optimize kernel size if desired. Will update patch
changelog in next version.
>
> Arnd
>

2014-10-08 11:17:33

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On 14-10-08 01:11 AM, Russell King - ARM Linux wrote:
> On Tue, Oct 07, 2014 at 10:27:00PM -0700, Scott Branden wrote:
>> +static void __init bcm_cygnus_init(void)
>> +{
>> + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>> +
>> + l2x0_of_init(0, ~0UL);
>
> Please don't explicitly call l2x0 initialisation. Instead, set the
> appropriate l2c members here:
>
>> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
>> + .init_machine = bcm_cygnus_init,
>> + .map_io = debug_ll_io_init,
>> + .dt_compat = bcm_cygnus_dt_compat,
>> + .restart = bcm_cygnus_restart
>> +MACHINE_END
>
> and let the core code call it at the appropriate time. Thanks.
>
Thanks - was unaware of this functionality. Will add .l2c_aux_val and
.l2c_aux mask to DT_MATCHINE_START. BUT, what happens when we need to
add trustzone support and make SMC call to secure monitor?

2014-10-08 11:41:50

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Wed, Oct 08, 2014 at 04:17:29AM -0700, Scott Branden wrote:
> Thanks - was unaware of this functionality. Will add .l2c_aux_val and
> .l2c_aux mask to DT_MATCHINE_START. BUT, what happens when we need to
> add trustzone support and make SMC call to secure monitor?

You will then need to implement the .l2c_write_sec initialiser in the
same place.

Note that there's work to revise the trustzone support in this area
which will probably be merged for 3.19.

--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.

2014-10-08 12:27:42

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

Thanks for the review - comments inline.

On 14-10-08 12:54 AM, Arnd Bergmann wrote:
> On Tuesday 07 October 2014 22:27:00 Scott Branden wrote:
>> From: Jonathan Richardson <[email protected]>
>>
>> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
>>
>> Reviewed-by: Ray Jui <[email protected]>
>> Reviewed-by: Desmond Liu <[email protected]>
>> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
>> Tested-by: Jonathan Richardson <[email protected]>
>> Signed-off-by: Scott Branden <[email protected]>
>> ---
>> arch/arm/mach-bcm/Kconfig | 31 ++++++++
>> arch/arm/mach-bcm/Makefile | 3 +
>> arch/arm/mach-bcm/bcm_cygnus.c | 166 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 200 insertions(+)
>> create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>>
>> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
>> index fc93800..2dd3f78 100644
>> --- a/arch/arm/mach-bcm/Kconfig
>> +++ b/arch/arm/mach-bcm/Kconfig
>> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
>>
>> if ARCH_BCM
>>
>> +config ARCH_BCM_IPROC
>> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
>> + select ARM_GIC
>> + select CACHE_L2X0
>> + select HAVE_ARM_TWD if LOCAL_TIMERS
>> + select HAVE_CLK
>> + select CLKSRC_OF
>> + select CLKSRC_MMIO
>> + select GENERIC_CLOCKEVENTS
>> + select ARM_GLOBAL_TIMER
>> + select ARCH_REQUIRE_GPIOLIB
>> + select ARM_AMBA
>> + select PINCTRL
>> + select DEBUG_UART_8250
>
> A lot of these are implied by ARCH_MULTI_V7, just drop them here.
>
> Some others like DEBUG_UART_8250 should remain user-selectable, if
> the platform works without them.
>
Will review. It looks like DEBUG_UART_8250 actually has to move to
Kconfig.debug as that is where everyone else selects it.
>> + help
>> + This enables support for systems based on Broadcom IPROC architected SoCs.
>> + The IPROC complex contains one or more ARM CPUs along with common
>> + core periperals. Application specific SoCs are created by adding a
>> + uArchitecture containing peripherals outside of the IPROC complex.
>> + Currently supported SoCs are Cygnus.
>> +
>> +menu "iProc SoC based Machine types"
>> + depends on ARCH_BCM_IPROC
>> +
>> + config ARCH_BCM_CYGNUS
>> + bool "Support Broadcom Cygnus board"
>> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
>> + help
>> + Support for Broadcom Cygnus SoC.
>> +endmenu
>
> I don't think you need per-board config options. The main option
> above should be enough.
This is not a per-board config option. This is actually a per-SoC
uArchtecture selection. More major uArchectures will be added to the
IPROC. Will Change comment to "Support Broadcom Cygnus SoC"
>
>> +
>> +#define CRMU_MAIL_BOX1 0x03024028
>> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
>
> Never hardcode physical register locations in source. This should come
> from DT, and get moved into a regular 'reset' device driver.
>
> You probably want to use drivers/power/reset/syscon-reboot.c
>
OK, thanks for advice on where to put reset device driver. Will
investigate.
>> +/* CRU_RESET register */
>> +static void * __iomem crmu_mail_box1_reg;
>> +
>> +#ifdef CONFIG_NEON
>> +
>> +#define CRU_BASE 0x1800e000
>> +#define CRU_SIZE 0x34
>> +#define CRU_CONTROL_OFFSET 0x0
>> +#define CRU_PWRDWN_EN_OFFSET 0x4
>> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
>> +#define CRU_NEON0_HW_RESET 6
>> +#define CRU_CLAMP_ON_NEON0 20
>> +#define CRU_PWRONIN_NEON0 21
>> +#define CRU_PWRONOUT_NEON0 21
>> +#define CRU_PWROKIN_NEON0 22
>> +#define CRU_PWROKOUT_NEON0 22
>> +#define CRU_STATUS_DELAY_NS 500
>> +#define CRU_MAX_RETRY_COUNT 10
>> +#define CRU_RETRY_INTVL_US 1
>> +
>> +/* Power up the NEON/VFPv3 block. */
>> +static void bcm_cygnus_powerup_neon(void)
>> +{
>> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
>> + u32 reg, i;
>
> Same thing here: this should really use the device node for CRU.
>
> Can you describe what the CRU is? Is this specific to NEON or is
> it some general-purpose power management unit?
>
It's a central resource unit with a lot of random registers to perform
various operations. To reduce confusion I'll probably move this out of
the kernel init and into the bootloader. This will simplify the kernel
init.
>> +static void __init bcm_cygnus_init(void)
>> +{
>> + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>> +
>> + l2x0_of_init(0, ~0UL);
>
> The l2x0_of_init can be removed now, just move the arguments into the
> respective fields of the machine descriptor.
>
Yes, thanks for pointing this out.
>> + crmu_mail_box1_reg = ioremap(CRMU_MAIL_BOX1, SZ_4);
>> + WARN_ON(!crmu_mail_box1_reg);
>> +
>> +#ifdef CONFIG_NEON
>> + bcm_cygnus_powerup_neon();
>> +#endif
>> +}
>
> In general, try to avoid #ifdef, use
>
> if (IS_ENABLED(CONFIG_NEON))
> bcm_cygnus_powerup_neon();
>
> instead.
>
>> +
>> +static const char const *bcm_cygnus_dt_compat[] = {
>> + "brcm,cygnus",
>> + NULL,
>> +};
>> +
>> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
>> + .init_machine = bcm_cygnus_init,
>> + .map_io = debug_ll_io_init,
>> + .dt_compat = bcm_cygnus_dt_compat,
>> + .restart = bcm_cygnus_restart
>> +MACHINE_END
>
> The map_io pointer is unnecessary, and the restart pointer should get
> set by the reset driver. I hope we can find a way to avoid the
> bcm_cygnus_init callback as well.
bcm_cygnus_init callback can be removed by moving initialization to
bootloader.
>
> Arnd
>

2014-10-08 13:10:50

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Wed, Oct 8, 2014 at 12:27 AM, Scott Branden <[email protected]> wrote:
> From: Jonathan Richardson <[email protected]>
>
> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
>
> Reviewed-by: Ray Jui <[email protected]>
> Reviewed-by: Desmond Liu <[email protected]>
> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
> Tested-by: Jonathan Richardson <[email protected]>
> Signed-off-by: Scott Branden <[email protected]>
> ---
> arch/arm/mach-bcm/Kconfig | 31 ++++++++
> arch/arm/mach-bcm/Makefile | 3 +
> arch/arm/mach-bcm/bcm_cygnus.c | 166 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 200 insertions(+)
> create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>
> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
> index fc93800..2dd3f78 100644
> --- a/arch/arm/mach-bcm/Kconfig
> +++ b/arch/arm/mach-bcm/Kconfig
> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
>
> if ARCH_BCM
>
> +config ARCH_BCM_IPROC
> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
> + select ARM_GIC
> + select CACHE_L2X0
> + select HAVE_ARM_TWD if LOCAL_TIMERS

LOCAL_TIMERS does not exist anymore.

> + select HAVE_CLK

Selected already by multi-platform.

> + select CLKSRC_OF
> + select CLKSRC_MMIO

These should be selected by the timers that need these rather than the platform.

> + select GENERIC_CLOCKEVENTS

Selected already by multi-platform.

> + select ARM_GLOBAL_TIMER
> + select ARCH_REQUIRE_GPIOLIB
> + select ARM_AMBA
> + select PINCTRL
> + select DEBUG_UART_8250

This entry should not be a select. It will break multi-platform.

Sort the select entries alphabetically.

> + help
> + This enables support for systems based on Broadcom IPROC architected SoCs.
> + The IPROC complex contains one or more ARM CPUs along with common
> + core periperals. Application specific SoCs are created by adding a
> + uArchitecture containing peripherals outside of the IPROC complex.
> + Currently supported SoCs are Cygnus.
> +
> +menu "iProc SoC based Machine types"
> + depends on ARCH_BCM_IPROC
> +
> + config ARCH_BCM_CYGNUS
> + bool "Support Broadcom Cygnus board"
> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
> + help
> + Support for Broadcom Cygnus SoC.
> +endmenu
> +
> config ARCH_BCM_MOBILE
> bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
> select ARCH_REQUIRE_GPIOLIB
> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
> index b19a396..46e092a 100644
> --- a/arch/arm/mach-bcm/Makefile
> +++ b/arch/arm/mach-bcm/Makefile
> @@ -10,6 +10,9 @@
> # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> # GNU General Public License for more details.
>
> +# Cygnus
> +obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
> +
> # BCM281XX
> obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
>
> diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c
> new file mode 100644
> index 0000000..8e430ed
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm_cygnus.c
> @@ -0,0 +1,166 @@
> +/*
> + * Copyright 2014 Broadcom Corporation. All rights reserved.
> + *
> + * Unless you and Broadcom execute a separate written software license
> + * agreement governing use of this software, this software is licensed to you
> + * under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/clocksource.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <asm/mach/arch.h>
> +#include <asm/mach/map.h>
> +#include <asm/proc-fns.h>
> +#include <asm/hardware/cache-l2x0.h>
> +
> +#define CRMU_MAIL_BOX1 0x03024028
> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
> +
> +/* CRU_RESET register */
> +static void * __iomem crmu_mail_box1_reg;
> +
> +#ifdef CONFIG_NEON
> +
> +#define CRU_BASE 0x1800e000
> +#define CRU_SIZE 0x34
> +#define CRU_CONTROL_OFFSET 0x0
> +#define CRU_PWRDWN_EN_OFFSET 0x4
> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
> +#define CRU_NEON0_HW_RESET 6
> +#define CRU_CLAMP_ON_NEON0 20
> +#define CRU_PWRONIN_NEON0 21
> +#define CRU_PWRONOUT_NEON0 21
> +#define CRU_PWROKIN_NEON0 22
> +#define CRU_PWROKOUT_NEON0 22
> +#define CRU_STATUS_DELAY_NS 500
> +#define CRU_MAX_RETRY_COUNT 10
> +#define CRU_RETRY_INTVL_US 1
> +
> +/* Power up the NEON/VFPv3 block. */
> +static void bcm_cygnus_powerup_neon(void)
> +{
> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
> + u32 reg, i;
> +
> + if (WARN_ON(!cru_base))
> + return;
> +
> + /* De-assert the neon hardware block reset */
> + reg = readl(cru_base + CRU_CONTROL_OFFSET);
> + reg &= ~(1 << CRU_NEON0_HW_RESET);
> + writel(reg, cru_base + CRU_CONTROL_OFFSET);
> +
> + /* Assert the power ON register bit */
> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
> + reg |= (1 << CRU_PWRONIN_NEON0);
> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
> +
> + /*
> + * Wait up to 10 usec in 1 usec increments for the
> + * status register to acknowledge the power ON assert
> + */
> + for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
> + reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
> + if (reg & CRU_PWRONOUT_NEON0)
> + break;
> +
> + udelay(CRU_RETRY_INTVL_US);
> + }
> +
> + if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
> + goto neon_unmap;
> +
> + /* Wait 0.5 usec = 500 nsec */
> + ndelay(CRU_STATUS_DELAY_NS);
> +
> + /* Assert the power OK register bit */
> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
> + reg |= (1 << CRU_PWROKIN_NEON0);
> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
> +
> + /*
> + * Wait up to 10 usec in 1 usec increments for the
> + * status register to acknowledge the power OK assert
> + */
> + for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
> + reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
> + if (reg & CRU_PWROKOUT_NEON0)
> + break;
> +
> + udelay(CRU_RETRY_INTVL_US);
> + }
> +
> + if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
> + goto neon_unmap;
> +
> + /* Wait 0.5 usec = 500 nsec */
> + ndelay(CRU_STATUS_DELAY_NS);
> +
> + /* Set the logic clamp for the neon block */
> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
> + reg &= ~(1 << CRU_CLAMP_ON_NEON0);
> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
> +
> + /* Wait 0.5 usec = 500 nsec */
> + ndelay(CRU_STATUS_DELAY_NS);
> +
> + /* Reset the neon hardware block */
> + reg = readl(cru_base + CRU_CONTROL_OFFSET);
> + reg |= (1 << CRU_NEON0_HW_RESET);
> + writel(reg, cru_base + CRU_CONTROL_OFFSET);
> +
> +neon_unmap:
> + iounmap(cru_base);
> +}
> +#endif /* CONFIG_NEON */

Is this a single core chip? If not, it seems like all this would
change when you add SMP support.

Rob

2014-10-08 13:29:38

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Wednesday 08 October 2014 05:27:24 Scott Branden wrote:
> >> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
> >> index fc93800..2dd3f78 100644
> >> --- a/arch/arm/mach-bcm/Kconfig
> >> +++ b/arch/arm/mach-bcm/Kconfig
> >> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
> >>
> >> if ARCH_BCM
> >>
> >> +config ARCH_BCM_IPROC
> >> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
> >> + select ARM_GIC
> >> + select CACHE_L2X0
> >> + select HAVE_ARM_TWD if LOCAL_TIMERS
> >> + select HAVE_CLK
> >> + select CLKSRC_OF
> >> + select CLKSRC_MMIO
> >> + select GENERIC_CLOCKEVENTS
> >> + select ARM_GLOBAL_TIMER
> >> + select ARCH_REQUIRE_GPIOLIB
> >> + select ARM_AMBA
> >> + select PINCTRL
> >> + select DEBUG_UART_8250
> >
> > A lot of these are implied by ARCH_MULTI_V7, just drop them here.
> >
> > Some others like DEBUG_UART_8250 should remain user-selectable, if
> > the platform works without them.
> >
> Will review. It looks like DEBUG_UART_8250 actually has to move to
> Kconfig.debug as that is where everyone else selects it.

Actually I think you also need to use DEBUG_LL_UART_8250 rather than
DEBUG_UART_8250.

> >> + help
> >> + This enables support for systems based on Broadcom IPROC architected SoCs.
> >> + The IPROC complex contains one or more ARM CPUs along with common
> >> + core periperals. Application specific SoCs are created by adding a
> >> + uArchitecture containing peripherals outside of the IPROC complex.
> >> + Currently supported SoCs are Cygnus.
> >> +
> >> +menu "iProc SoC based Machine types"
> >> + depends on ARCH_BCM_IPROC
> >> +
> >> + config ARCH_BCM_CYGNUS
> >> + bool "Support Broadcom Cygnus board"
> >> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
> >> + help
> >> + Support for Broadcom Cygnus SoC.
> >> +endmenu
> >
> > I don't think you need per-board config options. The main option
> > above should be enough.
> This is not a per-board config option. This is actually a per-SoC
> uArchtecture selection. More major uArchectures will be added to the
> IPROC. Will Change comment to "Support Broadcom Cygnus SoC"

Ok, sounds fine, but remove ARCH_BCM_IPROC then. There should be
no need for a three-level deep hierarchy (BCM -> IPROC -> CYGNUS)


> >> +/* CRU_RESET register */
> >> +static void * __iomem crmu_mail_box1_reg;
> >> +
> >> +#ifdef CONFIG_NEON
> >> +
> >> +#define CRU_BASE 0x1800e000
> >> +#define CRU_SIZE 0x34
> >> +#define CRU_CONTROL_OFFSET 0x0
> >> +#define CRU_PWRDWN_EN_OFFSET 0x4
> >> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
> >> +#define CRU_NEON0_HW_RESET 6
> >> +#define CRU_CLAMP_ON_NEON0 20
> >> +#define CRU_PWRONIN_NEON0 21
> >> +#define CRU_PWRONOUT_NEON0 21
> >> +#define CRU_PWROKIN_NEON0 22
> >> +#define CRU_PWROKOUT_NEON0 22
> >> +#define CRU_STATUS_DELAY_NS 500
> >> +#define CRU_MAX_RETRY_COUNT 10
> >> +#define CRU_RETRY_INTVL_US 1
> >> +
> >> +/* Power up the NEON/VFPv3 block. */
> >> +static void bcm_cygnus_powerup_neon(void)
> >> +{
> >> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
> >> + u32 reg, i;
> >
> > Same thing here: this should really use the device node for CRU.
> >
> > Can you describe what the CRU is? Is this specific to NEON or is
> > it some general-purpose power management unit?
> >
> It's a central resource unit with a lot of random registers to perform
> various operations. To reduce confusion I'll probably move this out of
> the kernel init and into the bootloader. This will simplify the kernel
> init.

That would help too, yes.

> >> +
> >> +static const char const *bcm_cygnus_dt_compat[] = {
> >> + "brcm,cygnus",
> >> + NULL,
> >> +};
> >> +
> >> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
> >> + .init_machine = bcm_cygnus_init,
> >> + .map_io = debug_ll_io_init,
> >> + .dt_compat = bcm_cygnus_dt_compat,
> >> + .restart = bcm_cygnus_restart
> >> +MACHINE_END
> >
> > The map_io pointer is unnecessary, and the restart pointer should get
> > set by the reset driver. I hope we can find a way to avoid the
> > bcm_cygnus_init callback as well.
> bcm_cygnus_init callback can be removed by moving initialization to
> bootloader.

Ok, perfect!

Arnd

2014-10-08 13:36:26

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver

On Wednesday 08 October 2014 03:58:15 Scott Branden wrote:
> On 14-10-08 12:57 AM, Arnd Bergmann wrote:
> > On Tuesday 07 October 2014 22:27:02 Scott Branden wrote:
> >> diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
> >> new file mode 100644
> >> index 0000000..a210377
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/arm/cygnus.txt
> >> @@ -0,0 +1,12 @@
> >> +Broadcom Cygnus device tree bindings
> >> +------------------------------------
> >> +
> >> +All Cygnus boards shall have the following properties:
> >> +
> >> +Required root node property:
> >> + - compatible = "brcm,cygnus";
> >
> > Can you add a more specific model number for the soc as well?
> > I assume that cygnus refers to more than one model, so you
> > should probably list both the family and the individual
> > SoC type here.
> Add specific model numbers does not seem necessary because they are not
> needed to be specified in the device tree for compatible purposes for
> the kernel to work. Plus, the list of model numbers will continue to
> grow over time and compatible strings would need to be added to the
> kernel for no apparent reason?

It's always helpful to have them in the DT though, in case you ever
need to add a workaround for one of the SoCs.

You can change the description to just state the format of the
more specific model number so you don't need to add the particular
type to the binding, but I'd definitely recommend listing both
a generic and a more specific name here, such as

compatible = "brcm,bcm123456", "brcm,cygnus";

> >> +Boards variants shall have the following additional properties:
> >> +
> >> +Required root node property for the BCM911360_ENTPHN board:
> >> + - compatible = "brcm,bcm911360_entphn";
> >>
> >
> > We normally don't list specific boards here, since it's hard to
> > keep up.
> Thanks - removed specific boards from file and moved the cygnus.txt file
> to devicetree/bindings/arm/bcm/cygnus.txt in next version. This seems
> to be like the appropriate place to put this document. We will need to
> add back in board specific bindings when ALSA support is added. But
> that will be a later commit to deal with.

I believe most new alsa drivers can now use the binding from
Documentation/devicetree/bindings/sound/simple-card.txt
so you should no longer need a board specific driver or binding
for those.

Arnd

2014-10-08 16:27:14

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On 14-10-08 06:28 AM, Arnd Bergmann wrote:
> On Wednesday 08 October 2014 05:27:24 Scott Branden wrote:
>>>> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
>>>> index fc93800..2dd3f78 100644
>>>> --- a/arch/arm/mach-bcm/Kconfig
>>>> +++ b/arch/arm/mach-bcm/Kconfig
>>>> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
>>>>
>>>> if ARCH_BCM
>>>>
>>>> +config ARCH_BCM_IPROC
>>>> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
>>>> + select ARM_GIC
>>>> + select CACHE_L2X0
>>>> + select HAVE_ARM_TWD if LOCAL_TIMERS
>>>> + select HAVE_CLK
>>>> + select CLKSRC_OF
>>>> + select CLKSRC_MMIO
>>>> + select GENERIC_CLOCKEVENTS
>>>> + select ARM_GLOBAL_TIMER
>>>> + select ARCH_REQUIRE_GPIOLIB
>>>> + select ARM_AMBA
>>>> + select PINCTRL
>>>> + select DEBUG_UART_8250
>>>
>>> A lot of these are implied by ARCH_MULTI_V7, just drop them here.
>>>
>>> Some others like DEBUG_UART_8250 should remain user-selectable, if
>>> the platform works without them.
>>>
>> Will review. It looks like DEBUG_UART_8250 actually has to move to
>> Kconfig.debug as that is where everyone else selects it.
>
> Actually I think you also need to use DEBUG_LL_UART_8250 rather than
> DEBUG_UART_8250.
>
>>>> + help
>>>> + This enables support for systems based on Broadcom IPROC architected SoCs.
>>>> + The IPROC complex contains one or more ARM CPUs along with common
>>>> + core periperals. Application specific SoCs are created by adding a
>>>> + uArchitecture containing peripherals outside of the IPROC complex.
>>>> + Currently supported SoCs are Cygnus.
>>>> +
>>>> +menu "iProc SoC based Machine types"
>>>> + depends on ARCH_BCM_IPROC
>>>> +
>>>> + config ARCH_BCM_CYGNUS
>>>> + bool "Support Broadcom Cygnus board"
>>>> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
>>>> + help
>>>> + Support for Broadcom Cygnus SoC.
>>>> +endmenu
>>>
>>> I don't think you need per-board config options. The main option
>>> above should be enough.
>> This is not a per-board config option. This is actually a per-SoC
>> uArchtecture selection. More major uArchectures will be added to the
>> IPROC. Will Change comment to "Support Broadcom Cygnus SoC"
>
> Ok, sounds fine, but remove ARCH_BCM_IPROC then. There should be
> no need for a three-level deep hierarchy (BCM -> IPROC -> CYGNUS)
>
I do not need a 3-deep hierarchy, I need a 2-deep hierarchy for IPROC
and CYGNUS (and future SoCs that have IPROC Architecture in common). I
can move IPROC out of the mach-bcm directory if you like a create a new
directory? But it looks like the purpose of mach-bcm is to consolidate
all Broadcom chipsets in it?
>
>>>> +/* CRU_RESET register */
>>>> +static void * __iomem crmu_mail_box1_reg;
>>>> +
>>>> +#ifdef CONFIG_NEON
>>>> +
>>>> +#define CRU_BASE 0x1800e000
>>>> +#define CRU_SIZE 0x34
>>>> +#define CRU_CONTROL_OFFSET 0x0
>>>> +#define CRU_PWRDWN_EN_OFFSET 0x4
>>>> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
>>>> +#define CRU_NEON0_HW_RESET 6
>>>> +#define CRU_CLAMP_ON_NEON0 20
>>>> +#define CRU_PWRONIN_NEON0 21
>>>> +#define CRU_PWRONOUT_NEON0 21
>>>> +#define CRU_PWROKIN_NEON0 22
>>>> +#define CRU_PWROKOUT_NEON0 22
>>>> +#define CRU_STATUS_DELAY_NS 500
>>>> +#define CRU_MAX_RETRY_COUNT 10
>>>> +#define CRU_RETRY_INTVL_US 1
>>>> +
>>>> +/* Power up the NEON/VFPv3 block. */
>>>> +static void bcm_cygnus_powerup_neon(void)
>>>> +{
>>>> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
>>>> + u32 reg, i;
>>>
>>> Same thing here: this should really use the device node for CRU.
>>>
>>> Can you describe what the CRU is? Is this specific to NEON or is
>>> it some general-purpose power management unit?
>>>
>> It's a central resource unit with a lot of random registers to perform
>> various operations. To reduce confusion I'll probably move this out of
>> the kernel init and into the bootloader. This will simplify the kernel
>> init.
>
> That would help too, yes.
>
>>>> +
>>>> +static const char const *bcm_cygnus_dt_compat[] = {
>>>> + "brcm,cygnus",
>>>> + NULL,
>>>> +};
>>>> +
>>>> +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
>>>> + .init_machine = bcm_cygnus_init,
>>>> + .map_io = debug_ll_io_init,
>>>> + .dt_compat = bcm_cygnus_dt_compat,
>>>> + .restart = bcm_cygnus_restart
>>>> +MACHINE_END
>>>
>>> The map_io pointer is unnecessary, and the restart pointer should get
>>> set by the reset driver. I hope we can find a way to avoid the
>>> bcm_cygnus_init callback as well.
>> bcm_cygnus_init callback can be removed by moving initialization to
>> bootloader.
>
> Ok, perfect!
>
> Arnd
>

2014-10-08 16:34:05

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

Thanks for comments - inline.

On 14-10-08 06:10 AM, Rob Herring wrote:
> On Wed, Oct 8, 2014 at 12:27 AM, Scott Branden <[email protected]> wrote:
>> From: Jonathan Richardson <[email protected]>
>>
>> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
>>
>> Reviewed-by: Ray Jui <[email protected]>
>> Reviewed-by: Desmond Liu <[email protected]>
>> Reviewed-by: JD (Jiandong) Zheng <[email protected]>
>> Tested-by: Jonathan Richardson <[email protected]>
>> Signed-off-by: Scott Branden <[email protected]>
>> ---
>> arch/arm/mach-bcm/Kconfig | 31 ++++++++
>> arch/arm/mach-bcm/Makefile | 3 +
>> arch/arm/mach-bcm/bcm_cygnus.c | 166 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 200 insertions(+)
>> create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>>
>> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
>> index fc93800..2dd3f78 100644
>> --- a/arch/arm/mach-bcm/Kconfig
>> +++ b/arch/arm/mach-bcm/Kconfig
>> @@ -5,6 +5,37 @@ menuconfig ARCH_BCM
>>
>> if ARCH_BCM
>>
>> +config ARCH_BCM_IPROC
>> + bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
>> + select ARM_GIC
>> + select CACHE_L2X0
>> + select HAVE_ARM_TWD if LOCAL_TIMERS
>
> LOCAL_TIMERS does not exist anymore.
Will change to if SMP so it will work for other iproc chips that have
SMP going forward.
>
>> + select HAVE_CLK
>
> Selected already by multi-platform.
>
>> + select CLKSRC_OF
>> + select CLKSRC_MMIO
>
> These should be selected by the timers that need these rather than the platform.
>
OK
>> + select GENERIC_CLOCKEVENTS
>
> Selected already by multi-platform.
>
>> + select ARM_GLOBAL_TIMER
>> + select ARCH_REQUIRE_GPIOLIB
>> + select ARM_AMBA
>> + select PINCTRL
>> + select DEBUG_UART_8250
>
> This entry should not be a select. It will break multi-platform.
Yes, this select will be removed from here in next version and moved to
kconfig.debug as other platforms do.
>
> Sort the select entries alphabetically.
>
>> + help
>> + This enables support for systems based on Broadcom IPROC architected SoCs.
>> + The IPROC complex contains one or more ARM CPUs along with common
>> + core periperals. Application specific SoCs are created by adding a
>> + uArchitecture containing peripherals outside of the IPROC complex.
>> + Currently supported SoCs are Cygnus.
>> +
>> +menu "iProc SoC based Machine types"
>> + depends on ARCH_BCM_IPROC
>> +
>> + config ARCH_BCM_CYGNUS
>> + bool "Support Broadcom Cygnus board"
>> + select USB_ARCH_HAS_EHCI if USB_SUPPORT
>> + help
>> + Support for Broadcom Cygnus SoC.
>> +endmenu
>> +
>> config ARCH_BCM_MOBILE
>> bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
>> select ARCH_REQUIRE_GPIOLIB
>> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
>> index b19a396..46e092a 100644
>> --- a/arch/arm/mach-bcm/Makefile
>> +++ b/arch/arm/mach-bcm/Makefile
>> @@ -10,6 +10,9 @@
>> # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> # GNU General Public License for more details.
>>
>> +# Cygnus
>> +obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
>> +
>> # BCM281XX
>> obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
>>
>> diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c
>> new file mode 100644
>> index 0000000..8e430ed
>> --- /dev/null
>> +++ b/arch/arm/mach-bcm/bcm_cygnus.c
>> @@ -0,0 +1,166 @@
>> +/*
>> + * Copyright 2014 Broadcom Corporation. All rights reserved.
>> + *
>> + * Unless you and Broadcom execute a separate written software license
>> + * agreement governing use of this software, this software is licensed to you
>> + * under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/delay.h>
>> +#include <asm/mach/arch.h>
>> +#include <asm/mach/map.h>
>> +#include <asm/proc-fns.h>
>> +#include <asm/hardware/cache-l2x0.h>
>> +
>> +#define CRMU_MAIL_BOX1 0x03024028
>> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
>> +
>> +/* CRU_RESET register */
>> +static void * __iomem crmu_mail_box1_reg;
>> +
>> +#ifdef CONFIG_NEON
>> +
>> +#define CRU_BASE 0x1800e000
>> +#define CRU_SIZE 0x34
>> +#define CRU_CONTROL_OFFSET 0x0
>> +#define CRU_PWRDWN_EN_OFFSET 0x4
>> +#define CRU_PWRDWN_STATUS_OFFSET 0x8
>> +#define CRU_NEON0_HW_RESET 6
>> +#define CRU_CLAMP_ON_NEON0 20
>> +#define CRU_PWRONIN_NEON0 21
>> +#define CRU_PWRONOUT_NEON0 21
>> +#define CRU_PWROKIN_NEON0 22
>> +#define CRU_PWROKOUT_NEON0 22
>> +#define CRU_STATUS_DELAY_NS 500
>> +#define CRU_MAX_RETRY_COUNT 10
>> +#define CRU_RETRY_INTVL_US 1
>> +
>> +/* Power up the NEON/VFPv3 block. */
>> +static void bcm_cygnus_powerup_neon(void)
>> +{
>> + void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
>> + u32 reg, i;
>> +
>> + if (WARN_ON(!cru_base))
>> + return;
>> +
>> + /* De-assert the neon hardware block reset */
>> + reg = readl(cru_base + CRU_CONTROL_OFFSET);
>> + reg &= ~(1 << CRU_NEON0_HW_RESET);
>> + writel(reg, cru_base + CRU_CONTROL_OFFSET);
>> +
>> + /* Assert the power ON register bit */
>> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
>> + reg |= (1 << CRU_PWRONIN_NEON0);
>> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
>> +
>> + /*
>> + * Wait up to 10 usec in 1 usec increments for the
>> + * status register to acknowledge the power ON assert
>> + */
>> + for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
>> + reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
>> + if (reg & CRU_PWRONOUT_NEON0)
>> + break;
>> +
>> + udelay(CRU_RETRY_INTVL_US);
>> + }
>> +
>> + if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
>> + goto neon_unmap;
>> +
>> + /* Wait 0.5 usec = 500 nsec */
>> + ndelay(CRU_STATUS_DELAY_NS);
>> +
>> + /* Assert the power OK register bit */
>> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
>> + reg |= (1 << CRU_PWROKIN_NEON0);
>> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
>> +
>> + /*
>> + * Wait up to 10 usec in 1 usec increments for the
>> + * status register to acknowledge the power OK assert
>> + */
>> + for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
>> + reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
>> + if (reg & CRU_PWROKOUT_NEON0)
>> + break;
>> +
>> + udelay(CRU_RETRY_INTVL_US);
>> + }
>> +
>> + if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
>> + goto neon_unmap;
>> +
>> + /* Wait 0.5 usec = 500 nsec */
>> + ndelay(CRU_STATUS_DELAY_NS);
>> +
>> + /* Set the logic clamp for the neon block */
>> + reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
>> + reg &= ~(1 << CRU_CLAMP_ON_NEON0);
>> + writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
>> +
>> + /* Wait 0.5 usec = 500 nsec */
>> + ndelay(CRU_STATUS_DELAY_NS);
>> +
>> + /* Reset the neon hardware block */
>> + reg = readl(cru_base + CRU_CONTROL_OFFSET);
>> + reg |= (1 << CRU_NEON0_HW_RESET);
>> + writel(reg, cru_base + CRU_CONTROL_OFFSET);
>> +
>> +neon_unmap:
>> + iounmap(cru_base);
>> +}
>> +#endif /* CONFIG_NEON */
>
> Is this a single core chip? If not, it seems like all this would
> change when you add SMP support.
Cygnus is a single core chip. There are other chips in the IPROC family
that are multi-core. But they are not part of the Cygnus
sub-architecture and would have different ways of powering up. These
will be added in a different patch in the future.
>
> Rob
>

2014-10-08 18:13:35

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Wednesday 08 October 2014 09:27:08 Scott Branden wrote:
> On 14-10-08 06:28 AM, Arnd Bergmann wrote:
> > On Wednesday 08 October 2014 05:27:24 Scott Branden wrote:
> >>>
> >>> I don't think you need per-board config options. The main option
> >>> above should be enough.
> >> This is not a per-board config option. This is actually a per-SoC
> >> uArchtecture selection. More major uArchectures will be added to the
> >> IPROC. Will Change comment to "Support Broadcom Cygnus SoC"
> >
> > Ok, sounds fine, but remove ARCH_BCM_IPROC then. There should be
> > no need for a three-level deep hierarchy (BCM -> IPROC -> CYGNUS)
> >
> I do not need a 3-deep hierarchy, I need a 2-deep hierarchy for IPROC
> and CYGNUS (and future SoCs that have IPROC Architecture in common). I
> can move IPROC out of the mach-bcm directory if you like a create a new
> directory? But it looks like the purpose of mach-bcm is to consolidate
> all Broadcom chipsets in it?

Yes, better leave it all in mach-bcm. You really shouldn't need much
code at all that is soc specific, so adding new directories is not
encouraged. We have some platforms that need no code at all, and on
arm64 that is required.

Isn't Northstar also IPROC? That one didn't seem to need the symbol.

Could you make ARCH_BCM_IPROC a silent symbol that is just selected
by each SoC family specific symbol?

Arnd

2014-10-08 18:45:50

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On 14-10-08 11:12 AM, Arnd Bergmann wrote:
> On Wednesday 08 October 2014 09:27:08 Scott Branden wrote:
>> On 14-10-08 06:28 AM, Arnd Bergmann wrote:
>>> On Wednesday 08 October 2014 05:27:24 Scott Branden wrote:
>>>>>
>>>>> I don't think you need per-board config options. The main option
>>>>> above should be enough.
>>>> This is not a per-board config option. This is actually a per-SoC
>>>> uArchtecture selection. More major uArchectures will be added to the
>>>> IPROC. Will Change comment to "Support Broadcom Cygnus SoC"
>>>
>>> Ok, sounds fine, but remove ARCH_BCM_IPROC then. There should be
>>> no need for a three-level deep hierarchy (BCM -> IPROC -> CYGNUS)
>>>
>> I do not need a 3-deep hierarchy, I need a 2-deep hierarchy for IPROC
>> and CYGNUS (and future SoCs that have IPROC Architecture in common). I
>> can move IPROC out of the mach-bcm directory if you like a create a new
>> directory? But it looks like the purpose of mach-bcm is to consolidate
>> all Broadcom chipsets in it?
>
> Yes, better leave it all in mach-bcm. You really shouldn't need much
> code at all that is soc specific, so adding new directories is not
> encouraged. We have some platforms that need no code at all, and on
> arm64 that is required.
>
> Isn't Northstar also IPROC? That one didn't seem to need the symbol.
Yes, Northstar is an older version of IPROC. We may be able to
consolidate it under the IPROC family as we upstream additional SoCs and
drivers. Have the commonality with ARCH_BCM_IPROC will allow this.
>
> Could you make ARCH_BCM_IPROC a silent symbol that is just selected
> by each SoC family specific symbol?
OK, I will make ARCH_BCM_IPROC a silent symbol.
>
> Arnd
>

2014-10-08 22:17:01

by Scott Branden

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On 14-10-08 11:12 AM, Arnd Bergmann wrote:
> On Wednesday 08 October 2014 09:27:08 Scott Branden wrote:
>> On 14-10-08 06:28 AM, Arnd Bergmann wrote:
>>> On Wednesday 08 October 2014 05:27:24 Scott Branden wrote:
>>>>>
>>>>> I don't think you need per-board config options. The main option
>>>>> above should be enough.
>>>> This is not a per-board config option. This is actually a per-SoC
>>>> uArchtecture selection. More major uArchectures will be added to the
>>>> IPROC. Will Change comment to "Support Broadcom Cygnus SoC"
>>>
>>> Ok, sounds fine, but remove ARCH_BCM_IPROC then. There should be
>>> no need for a three-level deep hierarchy (BCM -> IPROC -> CYGNUS)
>>>
>> I do not need a 3-deep hierarchy, I need a 2-deep hierarchy for IPROC
>> and CYGNUS (and future SoCs that have IPROC Architecture in common). I
>> can move IPROC out of the mach-bcm directory if you like a create a new
>> directory? But it looks like the purpose of mach-bcm is to consolidate
>> all Broadcom chipsets in it?
>
> Yes, better leave it all in mach-bcm. You really shouldn't need much
> code at all that is soc specific, so adding new directories is not
> encouraged. We have some platforms that need no code at all, and on
> arm64 that is required.
>
> Isn't Northstar also IPROC? That one didn't seem to need the symbol.
>
> Could you make ARCH_BCM_IPROC a silent symbol that is just selected
> by each SoC family specific symbol?
It looks like I will also be able to add Northstar under the
ARCH_BCM_IPROC. This will be good momentum to cleaning up and
consolidate support going forward.
I will change the Kconfig such that ARCH_BCM_5301X selects ARCH_BCM_IPROC.

Thanks.
>
> Arnd
>

2014-10-09 07:34:06

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC

On Wednesday 08 October 2014 15:16:55 Scott Branden wrote:
> It looks like I will also be able to add Northstar under the
> ARCH_BCM_IPROC. This will be good momentum to cleaning up and
> consolidate support going forward.
> I will change the Kconfig such that ARCH_BCM_5301X selects ARCH_BCM_IPROC.
>
>

Ok, sounds good.

Arnd