* [PATCH v2 03/12] Document: dt: binding: imx: update clock doc for imx6sll
From: Bai Ping @ 2016-12-27 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482832070-22668-1-git-send-email-ping.bai@nxp.com>
Add clock binding doc uppdate for imx6sll.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
---
.../devicetree/bindings/clock/imx6sll-clock.txt | 37 ++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/imx6sll-clock.txt
diff --git a/Documentation/devicetree/bindings/clock/imx6sll-clock.txt b/Documentation/devicetree/bindings/clock/imx6sll-clock.txt
new file mode 100644
index 0000000..3a46787
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/imx6sll-clock.txt
@@ -0,0 +1,37 @@
+* Clock bindings for Freescale i.MX6 SLL
+
+Required properties:
+- compatible: Should be "fsl,imx6sll-ccm"
+- reg: Address and length of the register set
+- #clock-cells: Should be <1>
+- clocks: list of clock specifiers, must contain an entry for each required
+ entry in clock-names
+- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1"
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sll-clock.h
+for the full list of i.MX6 SLL clock IDs.
+
+Examples:
+
+#include <dt-bindings/clock/imx6sll-clock.h>
+
+clks: ccm at 020c4000 {
+ compatible = "fsl,imx6sll-ccm";
+ reg = <0x020c4000 0x4000>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ #clock-cells = <1>;
+ clocks = <&ckil>, <&osc>, <&ipp_di0>, <&ipp_di1>;
+ clock-names = "ckil", "osc", "ipp_di0", "ipp_di1";
+};
+
+uart1: serial at 02020000 {
+ compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart";
+ reg = <0x02020000 0x4000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6SLL_CLK_UART1_IPG>,
+ <&clks IMX6SLL_CLK_UART1_SERIAL>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 02/12] driver: clocksource: add gpt timer for imx6sll
From: Bai Ping @ 2016-12-27 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482832070-22668-1-git-send-email-ping.bai@nxp.com>
Add gpt timer support for i.MX6SLL.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
---
drivers/clocksource/timer-imx-gpt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c
index f595460..f71822d 100644
--- a/drivers/clocksource/timer-imx-gpt.c
+++ b/drivers/clocksource/timer-imx-gpt.c
@@ -556,4 +556,5 @@ static int __init imx6dl_timer_init_dt(struct device_node *np)
CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sll_timer, "fsl,imx6sll-gpt", imx6dl_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
--
1.9.1
^ permalink raw reply related
* [PATCH v2 01/12] ARM: imx: Add basic msl support for imx6sll
From: Bai Ping @ 2016-12-27 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482832070-22668-1-git-send-email-ping.bai@nxp.com>
Add basic MSL support for i.MX6SLL.
The i.MX 6SoloLiteLite application processors are NXP's latest
additions to a growing family of multimedia-focused products
offering high-performance processing optimized for lowest power
consumption. The i.MX 6SoloLiteLite processors feature NXP's advanced
implementation of the ARM Cortex-A9 core, which can be interfaced
with LPDDR3 and LPDDR2 DRAM memory devices.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
---
arch/arm/mach-imx/Kconfig | 7 +++++++
arch/arm/mach-imx/Makefile | 1 +
arch/arm/mach-imx/cpu.c | 3 +++
arch/arm/mach-imx/cpuidle-imx6sl.c | 7 +++++--
arch/arm/mach-imx/gpc.c | 8 ++++++++
arch/arm/mach-imx/mach-imx6sl.c | 10 ++++++++--
arch/arm/mach-imx/mxc.h | 6 ++++++
7 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 936c59d..33bcfda 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -512,6 +512,13 @@ config SOC_IMX6SL
help
This enables support for Freescale i.MX6 SoloLite processor.
+config SOC_IMX6SLL
+ bool "i.MX6 SoloLiteLite support"
+ select SOC_IMX6
+
+ help
+ This enables support for Freescale i.MX6 SoloLiteLite processor.
+
config SOC_IMX6SX
bool "i.MX6 SoloX support"
select PINCTRL_IMX6SX
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index cab1289..f2bf650 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
endif
obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o
+obj-$(CONFIG_SOC_IMX6SLL) += mach-imx6sl.o
obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o
obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index b3347d3..62e8c0f 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -131,6 +131,9 @@ struct device * __init imx_soc_device_init(void)
case MXC_CPU_IMX6UL:
soc_id = "i.MX6UL";
break;
+ case MXC_CPU_IMX6SLL:
+ soc_id = "i.MX6SLL";
+ break;
case MXC_CPU_IMX7D:
soc_id = "i.MX7D";
break;
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index 8d866fb..124f982 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -11,6 +11,7 @@
#include <asm/cpuidle.h>
#include "common.h"
+#include "hardware.h"
#include "cpuidle.h"
static int imx6sl_enter_wait(struct cpuidle_device *dev,
@@ -21,9 +22,11 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev,
* Software workaround for ERR005311, see function
* description for details.
*/
- imx6sl_set_wait_clk(true);
+ if (cpu_is_imx6sl())
+ imx6sl_set_wait_clk(true);
cpu_do_idle();
- imx6sl_set_wait_clk(false);
+ if (cpu_is_imx6sl())
+ imx6sl_set_wait_clk(false);
imx6_set_lpm(WAIT_CLOCKED);
return index;
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 1dc2a34..4ed8a63 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -26,6 +26,7 @@
#include "hardware.h"
#define GPC_CNTR 0x000
+#define GPC_CNTR_L2_PGE 22
#define GPC_IMR1 0x008
#define GPC_PGC_GPU_PDN 0x260
#define GPC_PGC_GPU_PUPSCR 0x264
@@ -243,6 +244,7 @@ static int __init imx_gpc_init(struct device_node *node,
{
struct irq_domain *parent_domain, *domain;
int i;
+ u32 val;
if (!parent) {
pr_err("%s: no parent, giving up\n", node->full_name);
@@ -271,6 +273,12 @@ static int __init imx_gpc_init(struct device_node *node,
for (i = 0; i < IMR_NUM; i++)
writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
+ /* clear the L2_PGE bit on i.MX6SLL */
+ if (cpu_is_imx6sll()) {
+ val = readl_relaxed(gpc_base + GPC_CNTR);
+ val &= ~(1 << GPC_CNTR_L2_PGE);
+ writel_relaxed(val, gpc_base + GPC_CNTR);
+ }
/*
* Clear the OF_POPULATED flag set in of_irq_init so that
* later the GPC power domain driver will not be skipped.
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index 0408490..462ed9c 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -17,6 +17,7 @@
#include <asm/mach/map.h>
#include "common.h"
+#include "hardware.h"
#include "cpuidle.h"
static void __init imx6sl_fec_init(void)
@@ -54,7 +55,8 @@ static void __init imx6sl_init_machine(void)
of_platform_default_populate(NULL, NULL, parent);
- imx6sl_fec_init();
+ if (cpu_is_imx6sl())
+ imx6sl_fec_init();
imx_anatop_init();
imx6sl_pm_init();
}
@@ -66,11 +68,15 @@ static void __init imx6sl_init_irq(void)
imx_init_l2cache();
imx_src_init();
irqchip_init();
- imx6_pm_ccm_init("fsl,imx6sl-ccm");
+ if (cpu_is_imx6sl())
+ imx6_pm_ccm_init("fsl,imx6sl-ccm");
+ else
+ imx6_pm_ccm_init("fsl,imx6sll-ccm");
}
static const char * const imx6sl_dt_compat[] __initconst = {
"fsl,imx6sl",
+ "fsl,imx6sll",
NULL,
};
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 34f2ff6..e047611 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -39,6 +39,7 @@
#define MXC_CPU_IMX6SX 0x62
#define MXC_CPU_IMX6Q 0x63
#define MXC_CPU_IMX6UL 0x64
+#define MXC_CPU_IMX6SLL 0x67
#define MXC_CPU_IMX7D 0x72
#define IMX_DDR_TYPE_LPDDR2 1
@@ -73,6 +74,11 @@ static inline bool cpu_is_imx6ul(void)
return __mxc_cpu_type == MXC_CPU_IMX6UL;
}
+static inline bool cpu_is_imx6sll(void)
+{
+ return __mxc_cpu_type == MXC_CPU_IMX6SLL;
+}
+
static inline bool cpu_is_imx6q(void)
{
return __mxc_cpu_type == MXC_CPU_IMX6Q;
--
1.9.1
^ permalink raw reply related
* [PATCH v2 00/12] Add basic code support for imx6sll
From: Bai Ping @ 2016-12-27 9:47 UTC (permalink / raw)
To: linux-arm-kernel
The i.MX 6SoloLiteLite application processors are NXP's
latest additions to a growing family of multimedia-focused
products offering high-performance processing optimized for
lowest power consumption. The i.MX 6SoloLiteLite processors
feature NXP's advanced implementation of the ARM Cortex-A9 core,
which can be interfaced with LPDDR3 and LPDDR2 DRAM memory devices.
i.MX6SLL is a new SOC of the i.MX6 family, shares many common modules,
so most of the MSL code can be resued from i.MX6 serious SOC.
change for V2:
- address comments in dts and dtsi from Fabio.
- split the doc update into two patch, fix typo.
- address comments in clock driver, add necessary 'const'qualifier.
Bai Ping (12):
ARM: imx: Add basic msl support for imx6sll
driver: clocksource: add gpt timer for imx6sll
Document: dt: binding: imx: update clock doc for imx6sll
driver: clk: imx: Add clock driver for imx6sll
Document: dt: binding: imx: update pinctrl doc for imx6sll
driver: pinctrl: imx: Add pinctrl driver support for imx6sll
ARM: dts: imx: Add basic dtsi for imx6sll
ARM: dts: imx: Add imx6sll EVK board dts support
ARM: debug: Add low level debug support for imx6sll
ARM: imx: Add suspend/resume support for imx6sll
ARM: imx: correct i.mx6sll dram io low power mode
ARM: configs: enable imx6sll support in defconfig
.../devicetree/bindings/clock/imx6sll-clock.txt | 37 +
.../bindings/pinctrl/fsl,imx6sll-pinctrl.txt | 37 +
arch/arm/Kconfig.debug | 9 +
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6sll-evk.dts | 474 +++++++++++
arch/arm/boot/dts/imx6sll-pinfunc.h | 882 +++++++++++++++++++++
arch/arm/boot/dts/imx6sll.dtsi | 843 ++++++++++++++++++++
arch/arm/configs/imx_v6_v7_defconfig | 1 +
arch/arm/include/debug/imx-uart.h | 10 +
arch/arm/mach-imx/Kconfig | 8 +
arch/arm/mach-imx/Makefile | 1 +
arch/arm/mach-imx/cpu.c | 3 +
arch/arm/mach-imx/cpuidle-imx6sl.c | 7 +-
arch/arm/mach-imx/gpc.c | 8 +
arch/arm/mach-imx/mach-imx6sl.c | 10 +-
arch/arm/mach-imx/mxc.h | 6 +
arch/arm/mach-imx/pm-imx6.c | 49 +-
arch/arm/mach-imx/suspend-imx6.S | 29 +-
drivers/clk/imx/Makefile | 1 +
drivers/clk/imx/clk-imx6sll.c | 369 +++++++++
drivers/clocksource/timer-imx-gpt.c | 1 +
drivers/pinctrl/freescale/Kconfig | 7 +
drivers/pinctrl/freescale/Makefile | 1 +
drivers/pinctrl/freescale/pinctrl-imx6sll.c | 385 +++++++++
include/dt-bindings/clock/imx6sll-clock.h | 204 +++++
25 files changed, 3352 insertions(+), 32 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/imx6sll-clock.txt
create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx6sll-pinctrl.txt
create mode 100644 arch/arm/boot/dts/imx6sll-evk.dts
create mode 100644 arch/arm/boot/dts/imx6sll-pinfunc.h
create mode 100644 arch/arm/boot/dts/imx6sll.dtsi
create mode 100644 drivers/clk/imx/clk-imx6sll.c
create mode 100644 drivers/pinctrl/freescale/pinctrl-imx6sll.c
create mode 100644 include/dt-bindings/clock/imx6sll-clock.h
--
1.9.1
^ permalink raw reply
* [PATCH 9/9] irqchip/ls-scfg-msi: add MSI affinity support
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
For LS1046a and LS1043a v1.1, the MSI controller has 4 MSIRs and 4
CPUs. A GIC SPI interrupt of MSIR can be associated with a CPU.
When changing MSI interrupt affinity, this MSI will be moved to the
corresponding MSIR and MSI message data will be changed according to
MSIR. when requesting a MSI, the bits of all 4 MSIR will be reserved.
The parameter 'msi_affinity_flag' is provide to change this mode.
"lsmsi=no-affinity" will disable affinity, all MSI can only be
associated with CPU 0.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
drivers/irqchip/irq-ls-scfg-msi.c | 75 ++++++++++++++++++++++++++++++++++++---
1 file changed, 70 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index dc19569..753fe39 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -40,6 +40,7 @@ struct ls_scfg_msir {
unsigned int gic_irq;
unsigned int bit_start;
unsigned int bit_end;
+ unsigned int srs; /* Shared interrupt register select */
void __iomem *reg;
};
@@ -70,6 +71,19 @@ struct ls_scfg_msi {
.chip = &ls_scfg_msi_irq_chip,
};
+static int msi_affinity_flag = 1;
+
+static int __init early_parse_ls_scfg_msi(char *p)
+{
+ if (p && strncmp(p, "no-affinity", 11) == 0)
+ msi_affinity_flag = 0;
+ else
+ msi_affinity_flag = 1;
+
+ return 0;
+}
+early_param("lsmsi", early_parse_ls_scfg_msi);
+
static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data);
@@ -77,12 +91,43 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
msg->address_hi = upper_32_bits(msi_data->msiir_addr);
msg->address_lo = lower_32_bits(msi_data->msiir_addr);
msg->data = data->hwirq;
+
+ if (msi_affinity_flag) {
+ u32 msir_index;
+
+ msir_index = cpumask_first(data->common->affinity);
+ if (msir_index >= msi_data->msir_num)
+ msir_index = 0;
+
+ msg->data |= msir_index;
+ }
}
static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
const struct cpumask *mask, bool force)
{
- return -EINVAL;
+ struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data);
+ u32 cpu;
+
+ if (!msi_affinity_flag)
+ return -EINVAL;
+
+ if (!force)
+ cpu = cpumask_any_and(mask, cpu_online_mask);
+ else
+ cpu = cpumask_first(mask);
+
+ if (cpu >= msi_data->msir_num)
+ return -EINVAL;
+
+ if (msi_data->msir[cpu].gic_irq <= 0) {
+ pr_warn("cannot bind the irq to cpu%d\n", cpu);
+ return -EINVAL;
+ }
+
+ cpumask_copy(irq_data->common->affinity, mask);
+
+ return IRQ_SET_MASK_OK;
}
static struct irq_chip ls_scfg_msi_parent_chip = {
@@ -158,7 +203,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
for_each_set_bit_from(pos, &val, size) {
hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
- msir->index;
+ msir->srs;
virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
@@ -221,10 +266,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
ls_scfg_msi_irq_handler,
msir);
+ if (msi_affinity_flag) {
+ /* Associate MSIR interrupt to the cpu */
+ irq_set_affinity(msir->gic_irq, get_cpu_mask(index));
+ msir->srs = 0; /* This value is determined by the CPU */
+ } else
+ msir->srs = index;
+
/* Release the hwirqs corresponding to this MSIR */
- for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
- hwirq = i << msi_data->cfg->ibs_shift | msir->index;
- bitmap_clear(msi_data->used, hwirq, 1);
+ if (!msi_affinity_flag || msir->index == 0) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_clear(msi_data->used, hwirq, 1);
+ }
}
return 0;
@@ -316,6 +370,17 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
bitmap_set(msi_data->used, 0, msi_data->irqs_num);
msi_data->msir_num = of_irq_count(pdev->dev.of_node);
+
+ if (msi_affinity_flag) {
+ u32 cpu_num;
+
+ cpu_num = num_possible_cpus();
+ if (msi_data->msir_num >= cpu_num)
+ msi_data->msir_num = cpu_num;
+ else
+ msi_affinity_flag = 0;
+ }
+
msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
sizeof(*msi_data->msir),
GFP_KERNEL);
--
1.9.1
^ permalink raw reply related
* [PATCH 8/9] irqchip/ls-scfg-msi: add LS1043a v1.1 MSI support
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
A MSI controller of LS1043a v1.0 only includes one MSIR and
is assigned one GIC interrupt. In order to support affinity,
LS1043a v1.1 MSI is assigned 4 MSIRs and 4 GIC interrupts.
But the MSIR has the different offset and only supports 8 MSIs.
The bits between variable bit_start and bit_end in structure
ls_scfg_msir are used to show 8 MSI interrupts. msir_irqs and
msir_base are added to describe the difference of MSI between
LS1043a v1.1 and other SoCs.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
.../interrupt-controller/fsl,ls-scfg-msi.txt | 1 +
drivers/irqchip/irq-ls-scfg-msi.c | 45 +++++++++++++++++++---
2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index dde4552..49ccabb 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -7,6 +7,7 @@ Required properties:
"fsl,ls1021a-msi"
"fsl,ls1043a-msi"
"fsl,ls1046a-msi"
+ "fsl,ls1043a-v1.1-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 67547bd..dc19569 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -25,14 +25,21 @@
#define MSI_IRQS_PER_MSIR 32
#define MSI_MSIR_OFFSET 4
+#define MSI_LS1043V1_1_IRQS_PER_MSIR 8
+#define MSI_LS1043V1_1_MSIR_OFFSET 0x10
+
struct ls_scfg_msi_cfg {
u32 ibs_shift; /* Shift of interrupt bit select */
+ u32 msir_irqs; /* The irq number per MSIR */
+ u32 msir_base; /* The base address of MSIR */
};
struct ls_scfg_msir {
struct ls_scfg_msi *msi_data;
unsigned int index;
unsigned int gic_irq;
+ unsigned int bit_start;
+ unsigned int bit_end;
void __iomem *reg;
};
@@ -140,13 +147,18 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
struct ls_scfg_msi *msi_data = msir->msi_data;
unsigned long val;
- int pos, virq, hwirq;
+ int pos, size, virq, hwirq;
chained_irq_enter(irq_desc_get_chip(desc), desc);
val = ioread32be(msir->reg);
- for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) {
- hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index;
+
+ pos = msir->bit_start;
+ size = msir->bit_end + 1;
+
+ for_each_set_bit_from(pos, &val, size) {
+ hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
+ msir->index;
virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
@@ -193,14 +205,24 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
msir->index = index;
msir->msi_data = msi_data;
msir->gic_irq = virq;
- msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index;
+ msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index;
+
+ if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) {
+ msir->bit_start = 32 - ((msir->index + 1) *
+ MSI_LS1043V1_1_IRQS_PER_MSIR);
+ msir->bit_end = msir->bit_start +
+ MSI_LS1043V1_1_IRQS_PER_MSIR - 1;
+ } else {
+ msir->bit_start = 0;
+ msir->bit_end = msi_data->cfg->msir_irqs - 1;
+ }
irq_set_chained_handler_and_data(msir->gic_irq,
ls_scfg_msi_irq_handler,
msir);
/* Release the hwirqs corresponding to this MSIR */
- for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
hwirq = i << msi_data->cfg->ibs_shift | msir->index;
bitmap_clear(msi_data->used, hwirq, 1);
}
@@ -216,7 +238,7 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
if (msir->gic_irq > 0)
irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
- for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
hwirq = i << msi_data->cfg->ibs_shift | msir->index;
bitmap_set(msi_data->used, hwirq, 1);
}
@@ -226,15 +248,26 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
.ibs_shift = 3,
+ .msir_irqs = MSI_IRQS_PER_MSIR,
+ .msir_base = MSI_MSIR_OFFSET,
};
static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
.ibs_shift = 2,
+ .msir_irqs = MSI_IRQS_PER_MSIR,
+ .msir_base = MSI_MSIR_OFFSET,
+};
+
+static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = {
+ .ibs_shift = 2,
+ .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR,
+ .msir_base = MSI_LS1043V1_1_MSIR_OFFSET,
};
static const struct of_device_id ls_scfg_msi_id[] = {
{ .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
{ .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg },
{ .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
{},
};
--
1.9.1
^ permalink raw reply related
* [PATCH 7/9] irqchip/ls-scfg-msi: add LS1046a MSI support
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
LS1046a includes 4 MSIRs, each MSIR is assigned a dedicate GIC
SPI interrupt and provides 32 MSI interrupts. Compared to previous
MSI, LS1046a's IBS(interrupt bit select) shift is changed to 2 and
total MSI interrupt number is changed to 128.
The patch adds structure 'ls_scfg_msir' to describe MSIR setting and
'ibs_shift' to store the different value between the SoCs.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
.../interrupt-controller/fsl,ls-scfg-msi.txt | 2 +-
drivers/irqchip/irq-ls-scfg-msi.c | 161 ++++++++++++++++-----
2 files changed, 127 insertions(+), 36 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index 54597b0..dde4552 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -6,7 +6,7 @@ Required properties:
Layerscape PCIe MSI controller block such as:
"fsl,ls1021a-msi"
"fsl,ls1043a-msi"
- "fsl,ls1046a-msi"
+ "fsl,ls1046a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index cef67cc..67547bd 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -17,13 +17,24 @@
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/spinlock.h>
-#define MSI_MAX_IRQS 32
-#define MSI_IBS_SHIFT 3
-#define MSIR 4
+#define MSI_IRQS_PER_MSIR 32
+#define MSI_MSIR_OFFSET 4
+
+struct ls_scfg_msi_cfg {
+ u32 ibs_shift; /* Shift of interrupt bit select */
+};
+
+struct ls_scfg_msir {
+ struct ls_scfg_msi *msi_data;
+ unsigned int index;
+ unsigned int gic_irq;
+ void __iomem *reg;
+};
struct ls_scfg_msi {
spinlock_t lock;
@@ -32,8 +43,11 @@ struct ls_scfg_msi {
struct irq_domain *msi_domain;
void __iomem *regs;
phys_addr_t msiir_addr;
- int irq;
- DECLARE_BITMAP(used, MSI_MAX_IRQS);
+ struct ls_scfg_msi_cfg *cfg;
+ u32 msir_num;
+ struct ls_scfg_msir *msir;
+ u32 irqs_num;
+ unsigned long *used;
};
static struct irq_chip ls_scfg_msi_irq_chip = {
@@ -55,7 +69,7 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
msg->address_hi = upper_32_bits(msi_data->msiir_addr);
msg->address_lo = lower_32_bits(msi_data->msiir_addr);
- msg->data = data->hwirq << MSI_IBS_SHIFT;
+ msg->data = data->hwirq;
}
static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
@@ -81,8 +95,8 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
WARN_ON(nr_irqs != 1);
spin_lock(&msi_data->lock);
- pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS);
- if (pos < MSI_MAX_IRQS)
+ pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num);
+ if (pos < msi_data->irqs_num)
__set_bit(pos, msi_data->used);
else
err = -ENOSPC;
@@ -106,7 +120,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain,
int pos;
pos = d->hwirq;
- if (pos < 0 || pos >= MSI_MAX_IRQS) {
+ if (pos < 0 || pos >= msi_data->irqs_num) {
pr_err("failed to teardown msi. Invalid hwirq %d\n", pos);
return;
}
@@ -123,15 +137,17 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain,
static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
{
- struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc);
+ struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
+ struct ls_scfg_msi *msi_data = msir->msi_data;
unsigned long val;
- int pos, virq;
+ int pos, virq, hwirq;
chained_irq_enter(irq_desc_get_chip(desc), desc);
- val = ioread32be(msi_data->regs + MSIR);
- for_each_set_bit(pos, &val, MSI_MAX_IRQS) {
- virq = irq_find_mapping(msi_data->parent, (31 - pos));
+ val = ioread32be(msir->reg);
+ for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) {
+ hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index;
+ virq = irq_find_mapping(msi_data->parent, hwirq);
if (virq)
generic_handle_irq(virq);
}
@@ -143,7 +159,7 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data)
{
/* Initialize MSI domain parent */
msi_data->parent = irq_domain_add_linear(NULL,
- MSI_MAX_IRQS,
+ msi_data->irqs_num,
&ls_scfg_msi_domain_ops,
msi_data);
if (!msi_data->parent) {
@@ -164,16 +180,83 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data)
return 0;
}
+static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
+{
+ struct ls_scfg_msir *msir;
+ int virq, i, hwirq;
+
+ virq = platform_get_irq(msi_data->pdev, index);
+ if (virq <= 0)
+ return -ENODEV;
+
+ msir = &msi_data->msir[index];
+ msir->index = index;
+ msir->msi_data = msi_data;
+ msir->gic_irq = virq;
+ msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index;
+
+ irq_set_chained_handler_and_data(msir->gic_irq,
+ ls_scfg_msi_irq_handler,
+ msir);
+
+ /* Release the hwirqs corresponding to this MSIR */
+ for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_clear(msi_data->used, hwirq, 1);
+ }
+
+ return 0;
+}
+
+static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
+{
+ struct ls_scfg_msi *msi_data = msir->msi_data;
+ int i, hwirq;
+
+ if (msir->gic_irq > 0)
+ irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
+
+ for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
+ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+ bitmap_set(msi_data->used, hwirq, 1);
+ }
+
+ return 0;
+}
+
+static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
+ .ibs_shift = 3,
+};
+
+static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
+ .ibs_shift = 2,
+};
+
+static const struct of_device_id ls_scfg_msi_id[] = {
+ { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
+ { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
+
static int ls_scfg_msi_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
struct ls_scfg_msi *msi_data;
struct resource *res;
- int ret;
+ int i, ret;
+
+ match = of_match_device(ls_scfg_msi_id, &pdev->dev);
+ if (!match)
+ return -ENODEV;
msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
if (!msi_data)
return -ENOMEM;
+ msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msi_data->regs)) {
@@ -182,23 +265,37 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
}
msi_data->msiir_addr = res->start;
- msi_data->irq = platform_get_irq(pdev, 0);
- if (msi_data->irq <= 0) {
- dev_err(&pdev->dev, "failed to get MSI irq\n");
- return -ENODEV;
- }
-
msi_data->pdev = pdev;
spin_lock_init(&msi_data->lock);
+ msi_data->irqs_num = MSI_IRQS_PER_MSIR *
+ (1 << msi_data->cfg->ibs_shift);
+ msi_data->used = devm_kcalloc(&pdev->dev,
+ BITS_TO_LONGS(msi_data->irqs_num),
+ sizeof(*msi_data->used),
+ GFP_KERNEL);
+ if (!msi_data->used)
+ return -ENOMEM;
+ /*
+ * Reserve all the hwirqs
+ * The available hwirqs will be released in ls1_msi_setup_hwirq()
+ */
+ bitmap_set(msi_data->used, 0, msi_data->irqs_num);
+
+ msi_data->msir_num = of_irq_count(pdev->dev.of_node);
+ msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
+ sizeof(*msi_data->msir),
+ GFP_KERNEL);
+ if (!msi_data->msir)
+ return -ENOMEM;
+
+ for (i = 0; i < msi_data->msir_num; i++)
+ ls_scfg_msi_setup_hwirq(msi_data, i);
+
ret = ls_scfg_msi_domains_init(msi_data);
if (ret)
return ret;
- irq_set_chained_handler_and_data(msi_data->irq,
- ls_scfg_msi_irq_handler,
- msi_data);
-
platform_set_drvdata(pdev, msi_data);
return 0;
@@ -207,8 +304,10 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
static int ls_scfg_msi_remove(struct platform_device *pdev)
{
struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev);
+ int i;
- irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL);
+ for (i = 0; i < msi_data->msir_num; i++)
+ ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]);
irq_domain_remove(msi_data->msi_domain);
irq_domain_remove(msi_data->parent);
@@ -218,14 +317,6 @@ static int ls_scfg_msi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id ls_scfg_msi_id[] = {
- { .compatible = "fsl,1s1021a-msi", }, /* a typo */
- { .compatible = "fsl,1s1043a-msi", }, /* a typo */
- { .compatible = "fsl,ls1021a-msi", },
- { .compatible = "fsl,ls1043a-msi", },
- {},
-};
-
static struct platform_driver ls_scfg_msi_driver = {
.driver = {
.name = "ls-scfg-msi",
--
1.9.1
^ permalink raw reply related
* [PATCH 6/9] arm64: dts: ls1046a: add MSI dts node
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
LS1046a includes 3 MSI controllers.
Each controller supports 128 interrupts.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
.../interrupt-controller/fsl,ls-scfg-msi.txt | 1 +
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 31 ++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index 2755cd1..54597b0 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -6,6 +6,7 @@ Required properties:
Layerscape PCIe MSI controller block such as:
"fsl,ls1021a-msi"
"fsl,ls1043a-msi"
+ "fsl,ls1046a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 38806ca..49dbafc 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -511,5 +511,36 @@
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clockgen 4 1>;
};
+
+ msi1: msi-controller at 1580000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x1580000 0x0 0x10000>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ msi2: msi-controller at 1590000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x1590000 0x0 0x10000>;
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ msi3: msi-controller at 15a0000 {
+ compatible = "fsl,ls1046a-msi";
+ msi-controller;
+ reg = <0x0 0x15a0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH 5/9] arm64: dts: ls1043a: share all MSIs
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
In order to maximize the use of MSI, a PCIe controller will share
all MSI controllers. The patch changes "msi-parent" to refer to all
MSI controller dts nodes.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 692fc35..3947220 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -625,7 +625,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi1>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 110 0x4>,
@@ -650,7 +650,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi2>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 120 0x4>,
@@ -675,7 +675,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi3>;
+ msi-parent = <&msi1>, <&msi2>, <&msi3>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic 0 154 0x4>,
--
1.9.1
^ permalink raw reply related
* [PATCH 4/9] arm: dts: ls1021a: share all MSIs
From: Minghuan Lian @ 2016-12-27 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
In order to maximize the use of MSI, a PCIe controller will share
all MSI controllers. The patch changes msi-parent to refer to all
MSI controller dts nodes.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
arch/arm/boot/dts/ls1021a.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 6651938..1c82024 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -723,7 +723,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi1>;
+ msi-parent = <&msi1>, <&msi2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
@@ -746,7 +746,7 @@
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
- msi-parent = <&msi2>;
+ msi-parent = <&msi1>, <&msi2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0000 0 0 1 &gic GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
--
1.9.1
^ permalink raw reply related
* [PATCH 3/9] arm64: dts: ls1043a: fix typo of MSI compatible string
From: Minghuan Lian @ 2016-12-27 9:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
"1" should be replaced by "l". This is a typo.
The patch is to fix it.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index ec13a6e..692fc35 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -589,21 +589,21 @@
};
msi1: msi-controller1 at 1571000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1571000 0x0 0x8>;
msi-controller;
interrupts = <0 116 0x4>;
};
msi2: msi-controller2 at 1572000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1572000 0x0 0x8>;
msi-controller;
interrupts = <0 126 0x4>;
};
msi3: msi-controller3 at 1573000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1573000 0x0 0x8>;
msi-controller;
interrupts = <0 160 0x4>;
--
1.9.1
^ permalink raw reply related
* [PATCH 2/9] arm: dts: ls1021a: fix typo of MSI compatible string
From: Minghuan Lian @ 2016-12-27 9:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482829985-24421-1-git-send-email-Minghuan.Lian@nxp.com>
"1" should be replaced by "l". This is a typo.
The patch is to fix it.
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
arch/arm/boot/dts/ls1021a.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 282d854..6651938 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -122,14 +122,14 @@
};
msi1: msi-controller at 1570e00 {
- compatible = "fsl,1s1021a-msi";
+ compatible = "fsl,ls1021a-msi";
reg = <0x0 0x1570e00 0x0 0x8>;
msi-controller;
interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
};
msi2: msi-controller at 1570e08 {
- compatible = "fsl,1s1021a-msi";
+ compatible = "fsl,ls1021a-msi";
reg = <0x0 0x1570e08 0x0 0x8>;
msi-controller;
interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
--
1.9.1
^ permalink raw reply related
* [PATCH 1/9] irqchip/ls-scfg-msi: fix typo of MSI compatible strings
From: Minghuan Lian @ 2016-12-27 9:12 UTC (permalink / raw)
To: linux-arm-kernel
The patch is to fix typo of the Layerscape SCFG MSI dts compatible
strings. "1" is replaced by "l".
Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
---
.../devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt | 6 +++---
drivers/irqchip/irq-ls-scfg-msi.c | 6 ++++--
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index 9e38949..2755cd1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -4,8 +4,8 @@ Required properties:
- compatible: should be "fsl,<soc-name>-msi" to identify
Layerscape PCIe MSI controller block such as:
- "fsl,1s1021a-msi"
- "fsl,1s1043a-msi"
+ "fsl,ls1021a-msi"
+ "fsl,ls1043a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.
@@ -23,7 +23,7 @@ MSI controller node
Examples:
msi1: msi-controller at 1571000 {
- compatible = "fsl,1s1043a-msi";
+ compatible = "fsl,ls1043a-msi";
reg = <0x0 0x1571000 0x0 0x8>,
msi-controller;
interrupts = <0 116 0x4>;
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 02cca74c..cef67cc 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -219,8 +219,10 @@ static int ls_scfg_msi_remove(struct platform_device *pdev)
}
static const struct of_device_id ls_scfg_msi_id[] = {
- { .compatible = "fsl,1s1021a-msi", },
- { .compatible = "fsl,1s1043a-msi", },
+ { .compatible = "fsl,1s1021a-msi", }, /* a typo */
+ { .compatible = "fsl,1s1043a-msi", }, /* a typo */
+ { .compatible = "fsl,ls1021a-msi", },
+ { .compatible = "fsl,ls1043a-msi", },
{},
};
--
1.9.1
^ permalink raw reply related
* [PATCH] crypto: arm64/aes: reimplement bit-sliced ARM/NEON implementation for arm64
From: Herbert Xu @ 2016-12-27 9:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481564758-7275-1-git-send-email-ard.biesheuvel@linaro.org>
On Mon, Dec 12, 2016 at 05:45:58PM +0000, Ard Biesheuvel wrote:
>
> + .chunksize = 8 * AES_BLOCK_SIZE,
Same comment as to the previous patches regarding chunksize.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH v2 2/3] crypto: arm64/chacha20 - implement NEON version based on SSE3 code
From: Herbert Xu @ 2016-12-27 9:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481294033-23508-3-git-send-email-ard.biesheuvel@linaro.org>
On Fri, Dec 09, 2016 at 02:33:52PM +0000, Ard Biesheuvel wrote:
>
> + .chunksize = 4 * CHACHA20_BLOCK_SIZE,
This should use a new attribute specific to the walk interface.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH] crypto: arm/aes-neonbs - process 8 blocks in parallel if we can
From: Herbert Xu @ 2016-12-27 8:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481291246-20216-1-git-send-email-ard.biesheuvel@linaro.org>
On Fri, Dec 09, 2016 at 01:47:26PM +0000, Ard Biesheuvel wrote:
> The bit-sliced NEON implementation of AES only performs optimally if
> it can process 8 blocks of input in parallel. This is due to the nature
> of bit slicing, where the n-th bit of each byte of AES state of each input
> block is collected into NEON register 'n', for registers q0 - q7.
>
> This implies that the amount of work for the transform is fixed,
> regardless of whether we are handling just one block or 8 in parallel.
>
> So let's try a bit harder to iterate over the input in suitably sized
> chunks, by increasing the chunksize to 8 * AES_BLOCK_SIZE, and tweaking
> the loops to only process multiples of the chunk size, unless we are
> handling the last chunk in the input stream.
>
> Note that the skcipher walk API guarantees that a step in the walk never
> returns less that 'chunksize' bytes if there are at least that many bytes
> of input still available. However, it does *not* guarantee that those steps
> produce an exact multiple of the chunk size.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
I like this patch. However, I had different plans for the chunksize
attribute. It's primarily meant to be a hint to the upper layer
in case it does partial updates. It's meant to provide the minimum
number of bytes a partial update can carry without screwing up
subsequent updates.
It just happens to be the same value that we were using during
an skcipher walk.
So I think for your case we should add a new attribute, perhaps
walk_chunksize or walksize, which doesn't need to be exported to
the outside at all and can then be used by the walk interface.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH 0/9] Runtime PM for Exynos pin controller driver
From: Marek Szyprowski @ 2016-12-27 8:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CANAwSgRQuoriU923XT1B_0CVX2rzOR+8j2YHLMYRUu3gGySEBw@mail.gmail.com>
Hi Anand,
On 2016-12-24 11:10, Anand Moon wrote:
> Hi Marek
>
> On 23 December 2016 at 17:54, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> Hello,
>>
>> This patchset is a next step to add support for audio power domain on
>> Exynos5 SoCs.
>>
>> Audio power domain on Exynos5 SoCs contains following hardware modules:
>> 1. clock controller
>> 2. pin controller
>> 3. PL330 DMA controller
>> 4. I2S audio controller
>>
>> Till now it was assumed that pin controller is located in the "always on"
>> power domain and lacked runtime power management. This patch finally
>> removes such assumption and adds runtime pm support and awareness to this
>> driver. To achieve this, some changes in the Exynos platform support code
>> were needed, like moving pad retention control to the pin controller driver.
>> Some cleanup to the pin controller driver has been also done while changing
>> the code. This new feature requires some additional information in the
>> device tree, what is handled by patches 1,2 and 9.
>>
>> Please note that patches are ordered in such a way that the changes can be
>> bisected, so the properties are added to dts before the code requiring them.
>>
>> The other patches related to enabling full support for audio power domain
>> can be found here:
>> 1. PL330 ADMA controller non-irqsafe runtime PM:
>> https://www.spinics.net/lists/arm-kernel/msg550008.html
>> 2. Runtime PM for clock controllers (Exynos Audio subsystem will be added
>> in v4 soon): https://www.spinics.net/lists/arm-kernel/msg538122.html
>>
>> Patches are based on linux-next from 2016.12.22.
>>
>> Best regards
>> Marek Szyprowski
>> Samsung R&D Institute Poland
>>
>>
>> Patch summary:
>>
>> Marek Szyprowski (9):
>> ARM: dts: exynos: Add PMU syscon to pinctrl nodes
>> ARM: dts: exynos: Add pinctrl sleep state for 542x i2s module
>> pinctrl: samsung: Remove dead code
>> pinctrl: samsung: Use generic of_device_get_match_data helper
>> pinctrl: samsung: Move retention control from mach-exynos to the
>> pinctrl driver
>> pinctrl: samsung: Replace syscore ops with standard platform device
>> pm_ops
>> pinctrl: samsung: Add property to mark pad state as suitable for power
>> down
>> pinctrl: samsung: Add runtime PM support
>> ARM: dts: exynos: Add audio power domain support to Exynos542x SoCs
>>
>> .../bindings/pinctrl/samsung-pinctrl.txt | 12 ++
>> arch/arm/boot/dts/exynos3250.dtsi | 2 +
>> arch/arm/boot/dts/exynos4210.dtsi | 3 +
>> arch/arm/boot/dts/exynos4x12.dtsi | 3 +
>> arch/arm/boot/dts/exynos5250.dtsi | 4 +
>> arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 11 ++
>> arch/arm/boot/dts/exynos5420.dtsi | 18 ++-
>> arch/arm/mach-exynos/suspend.c | 64 ---------
>> drivers/pinctrl/samsung/pinctrl-exynos.c | 148 +++++++++++++++++++++
>> drivers/pinctrl/samsung/pinctrl-samsung.c | 126 ++++++++----------
>> drivers/pinctrl/samsung/pinctrl-samsung.h | 15 +++
>> 11 files changed, 271 insertions(+), 135 deletions(-)
>>
> Is their core configuration missing to enable audio through HDMI on
> Odroid Boards.
> I could not get the sound working on Odroid XU4.
Audio support for HDMI on Exynos requires some additional code. We will take
a look at this too.
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* [PATCH v3 3/3] ARM: DT: add power-off support to linkstation lsgl and kuroboxpro
From: Roger Shimizu @ 2016-12-27 7:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161227070611.14852-1-rogershimizu@gmail.com>
A few models of Linkstation / KuroBox has micro-controller which
controls the power (as well as FAN, but not related here), while
others not. So remove the restart-poweroff driver in linkstation
common dtsi file, and specify the proper power driver in dts
of each device.
Devices need micro-controler to power-off:
- Linkstation LS-GL
- KuroBox Pro
Device continues using original restart-poweroff driver:
- Linkstation LS-WTGL
To: Jason Cooper <jason@lakedaemon.net>
To: Andrew Lunn <andrew@lunn.ch>
To: Gregory Clement <gregory.clement@free-electrons.com>
To: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Cc: Ryan Tandy <ryan@nardis.ca>
Cc: linux-pm at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Reported-by: Ryan Tandy <ryan@nardis.ca>
Tested-by: Ryan Tandy <ryan@nardis.ca>
Signed-off-by: Roger Shimizu <rogershimizu@gmail.com>
---
arch/arm/boot/dts/orion5x-kuroboxpro.dts | 8 ++++++++
arch/arm/boot/dts/orion5x-linkstation-lsgl.dts | 10 ++++++++++
arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts | 4 ++++
arch/arm/boot/dts/orion5x-linkstation.dtsi | 4 ----
4 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/orion5x-kuroboxpro.dts b/arch/arm/boot/dts/orion5x-kuroboxpro.dts
index 1a672b098d0b..aba38d802bda 100644
--- a/arch/arm/boot/dts/orion5x-kuroboxpro.dts
+++ b/arch/arm/boot/dts/orion5x-kuroboxpro.dts
@@ -60,6 +60,14 @@
<MBUS_ID(0x09, 0x00) 0 0xf2200000 0x800>,
<MBUS_ID(0x01, 0x0f) 0 0xf4000000 0x40000>,
<MBUS_ID(0x01, 0x1e) 0 0xfc000000 0x1000000>;
+
+ internal-regs {
+ power_off {
+ compatible = "linkstation,power-off";
+ reg = <0x12100 0x100>;
+ clocks = <&core_clk 0>;
+ };
+ };
};
memory { /* 128 MB */
diff --git a/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts b/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
index 51dc734cd5b9..370fc17a6dd9 100644
--- a/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
+++ b/arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
@@ -56,6 +56,16 @@
model = "Buffalo Linkstation Pro/Live";
compatible = "buffalo,lsgl", "marvell,orion5x-88f5182", "marvell,orion5x";
+ soc {
+ internal-regs {
+ power_off {
+ compatible = "linkstation,power-off";
+ reg = <0x12100 0x100>;
+ clocks = <&core_clk 0>;
+ };
+ };
+ };
+
memory { /* 128 MB */
device_type = "memory";
reg = <0x00000000 0x8000000>;
diff --git a/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts b/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
index 0eead400f427..571a71f5b7ad 100644
--- a/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
+++ b/arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
@@ -59,6 +59,10 @@
reg = <0x00000000 0x4000000>;
};
+ restart_poweroff {
+ compatible = "restart-poweroff";
+ };
+
gpio_keys {
power-on-switch {
gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/boot/dts/orion5x-linkstation.dtsi b/arch/arm/boot/dts/orion5x-linkstation.dtsi
index ed456ab35fd8..40770a8d4b36 100644
--- a/arch/arm/boot/dts/orion5x-linkstation.dtsi
+++ b/arch/arm/boot/dts/orion5x-linkstation.dtsi
@@ -57,10 +57,6 @@
<MBUS_ID(0x01, 0x0f) 0 0xf4000000 0x40000>;
};
- restart_poweroff {
- compatible = "restart-poweroff";
- };
-
regulators {
compatible = "simple-bus";
#address-cells = <1>;
--
2.11.0
^ permalink raw reply related
* [PATCH v3 2/3] DT: bingdings: power: reset: add linkstation-reset doc
From: Roger Shimizu @ 2016-12-27 7:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161227070611.14852-1-rogershimizu@gmail.com>
Add linkstation-reset doc to describe the newly added
POWER_RESET_LINKSTATION driver, which controls magic command
sending to UART1 to power-off Buffalo Linkstation / KuroBox
and their variants.
To: Sebastian Reichel <sre@kernel.org>
To: Rob Herring <robh+dt@kernel.org>
To: Mark Rutland <mark.rutland@arm.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Ryan Tandy <ryan@nardis.ca>
Cc: linux-pm at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Signed-off-by: Roger Shimizu <rogershimizu@gmail.com>
---
.../bindings/power/reset/linkstation-reset.txt | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/reset/linkstation-reset.txt
diff --git a/Documentation/devicetree/bindings/power/reset/linkstation-reset.txt b/Documentation/devicetree/bindings/power/reset/linkstation-reset.txt
new file mode 100644
index 000000000000..815e340318f3
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/reset/linkstation-reset.txt
@@ -0,0 +1,26 @@
+* Buffalo Linkstation Reset Driver
+
+Power of some Buffalo Linkstation or KuroBox Pro is managed by
+micro-controller, which connects to UART1. After being fed from UART1
+by a few magic numbers, the so-called power-off command,
+the micro-controller will turn power off the device.
+
+This is very similar to QNAP or Synology NAS devices, which is
+described in qnap-poweroff.txt, however the command is much simpler,
+only 1-byte long and without checksums.
+
+This driver adds a handler to pm_power_off which is called to turn the
+power off.
+
+Required Properties:
+- compatible: Should be "linkstation,power-off"
+- reg: Address and length of the register set for UART1
+- clocks: tclk clock
+
+Example:
+
+ reset {
+ compatible = "linkstation,power-off";
+ reg = <0x12100 0x100>;
+ clocks = <&core_clk 0>;
+ };
--
2.11.0
^ permalink raw reply related
* [PATCH v3 1/3] power: reset: add linkstation-reset driver
From: Roger Shimizu @ 2016-12-27 7:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161227070611.14852-1-rogershimizu@gmail.com>
Buffalo Linkstation / KuroBox and their variants need magic command
sending to UART1 to power-off.
Power driver linkstation-reset implements the magic command and I/O
routine, which come from files listed below:
- arch/arm/mach-orion5x/kurobox_pro-setup.c
- arch/arm/mach-orion5x/terastation_pro2-setup.c
To: Sebastian Reichel <sre@kernel.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Martin Michlmayr <tbm@cyrius.com>
Cc: Sylver Bruneau <sylver.bruneau@googlemail.com>
Cc: Herbert Valerio Riedel <hvr@gnu.org>
Cc: Ryan Tandy <ryan@nardis.ca>
Cc: linux-pm at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Reported-by: Ryan Tandy <ryan@nardis.ca>
Tested-by: Ryan Tandy <ryan@nardis.ca>
Signed-off-by: Roger Shimizu <rogershimizu@gmail.com>
---
drivers/power/reset/Kconfig | 10 ++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/linkstation-reset.c | 269 ++++++++++++++++++++++++++++++++
3 files changed, 280 insertions(+)
create mode 100644 drivers/power/reset/linkstation-reset.c
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index c74c3f67b8da..77c44cad7ece 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -98,6 +98,16 @@ config POWER_RESET_IMX
say N here or disable in dts to make sure pm_power_off never be
overwrote wrongly by this driver.
+config POWER_RESET_LINKSTATION
+ bool "Buffalo Linkstation and its variants reset driver"
+ depends on OF_GPIO && PLAT_ORION
+ help
+ This driver supports power off Buffalo Linkstation / KuroBox Pro
+ NAS and their variants by sending commands to the micro-controller
+ which controls the main power.
+
+ Say Y if you have a Buffalo Linkstation / KuroBox Pro NAS.
+
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 1be307c7fc25..692ba6417cfb 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
+obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-reset.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/linkstation-reset.c b/drivers/power/reset/linkstation-reset.c
new file mode 100644
index 000000000000..4390495dfe0e
--- /dev/null
+++ b/drivers/power/reset/linkstation-reset.c
@@ -0,0 +1,269 @@
+/*
+ * Buffalo Linkstation power reset driver.
+ * It may also be used on following devices:
+ * - KuroBox Pro
+ * - Buffalo Linkstation Pro (LS-GL)
+ * - Buffalo Terastation Pro II/Live
+ * - Buffalo Linkstation Duo (LS-WTGL)
+ * - Buffalo Linkstation Mini (LS-WSGL)
+ *
+ * Copyright (C) 2016 Roger Shimizu <rogershimizu@gmail.com>
+ *
+ * Based on the code from:
+ *
+ * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch>
+ * Copyright (C) 2009 Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2008 Byron Bradley <byron.bbradley@gmail.com>
+ * Copyright (C) 2008 Sylver Bruneau <sylver.bruneau@googlemail.com>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_reg.h>
+#include <linux/kallsyms.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define UART1_REG(x) (base + ((UART_##x) << 2))
+#define MICON_CMD_SIZE 4
+
+/* 4-byte magic hello command to UART1-attached microcontroller */
+static const unsigned char linkstation_micon_magic[] = {
+ 0x1b,
+ 0x00,
+ 0x07,
+ 0x00
+};
+
+/* for each row, first byte is the size of command */
+static const unsigned char linkstation_power_off_cmd[][MICON_CMD_SIZE] = {
+ { 3, 0x01, 0x35, 0x00},
+ { 2, 0x00, 0x0c},
+ { 2, 0x00, 0x06},
+ {}
+};
+
+struct reset_cfg {
+ u32 baud;
+ const unsigned char *magic;
+ const unsigned char (*cmd)[MICON_CMD_SIZE];
+};
+
+static const struct reset_cfg linkstation_power_off_cfg = {
+ .baud = 38400,
+ .magic = linkstation_micon_magic,
+ .cmd = linkstation_power_off_cmd,
+};
+
+static const struct of_device_id linkstation_reset_of_match_table[] = {
+ { .compatible = "linkstation,power-off",
+ .data = &linkstation_power_off_cfg,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, linkstation_reset_of_match_table);
+
+static int uart1_micon_read(void *base, unsigned char *buf, int count)
+{
+ int i;
+ int timeout;
+
+ for (i = 0; i < count; i++) {
+ timeout = 10;
+
+ while (!(readl(UART1_REG(LSR)) & UART_LSR_DR)) {
+ if (--timeout == 0)
+ break;
+ udelay(1000);
+ }
+
+ if (timeout == 0)
+ break;
+ buf[i] = readl(UART1_REG(RX));
+ }
+
+ /* return read bytes */
+ return i;
+}
+
+static int uart1_micon_write(void *base, const unsigned char *buf, int count)
+{
+ int i = 0;
+
+ while (count--) {
+ while (!(readl(UART1_REG(LSR)) & UART_LSR_THRE))
+ barrier();
+ writel(buf[i++], UART1_REG(TX));
+ }
+
+ return 0;
+}
+
+int uart1_micon_send(void *base, const unsigned char *data, int count)
+{
+ int i;
+ unsigned char checksum = 0;
+ unsigned char recv_buf[40];
+ unsigned char send_buf[40];
+ unsigned char correct_ack[3];
+ int retry = 2;
+
+ /* Generate checksum */
+ for (i = 0; i < count; i++)
+ checksum -= data[i];
+
+ do {
+ /* Send data */
+ uart1_micon_write(base, data, count);
+
+ /* send checksum */
+ uart1_micon_write(base, &checksum, 1);
+
+ if (uart1_micon_read(base, recv_buf, sizeof(recv_buf)) <= 3) {
+ printk(KERN_ERR ">%s: receive failed.\n", __func__);
+
+ /* send preamble to clear the receive buffer */
+ memset(&send_buf, 0xff, sizeof(send_buf));
+ uart1_micon_write(base, send_buf, sizeof(send_buf));
+
+ /* make dummy reads */
+ mdelay(100);
+ uart1_micon_read(base, recv_buf, sizeof(recv_buf));
+ } else {
+ /* Generate expected ack */
+ correct_ack[0] = 0x01;
+ correct_ack[1] = data[1];
+ correct_ack[2] = 0x00;
+
+ /* checksum Check */
+ if ((recv_buf[0] + recv_buf[1] + recv_buf[2] +
+ recv_buf[3]) & 0xFF) {
+ printk(KERN_ERR ">%s: Checksum Error : "
+ "Received data[%02x, %02x, %02x, %02x]"
+ "\n", __func__, recv_buf[0],
+ recv_buf[1], recv_buf[2], recv_buf[3]);
+ } else {
+ /* Check Received Data */
+ if (correct_ack[0] == recv_buf[0] &&
+ correct_ack[1] == recv_buf[1] &&
+ correct_ack[2] == recv_buf[2]) {
+ /* Interval for next command */
+ mdelay(10);
+
+ /* Receive ACK */
+ return 0;
+ }
+ }
+ /* Received NAK or illegal Data */
+ printk(KERN_ERR ">%s: Error : NAK or Illegal Data "
+ "Received\n", __func__);
+ }
+ } while (retry--);
+
+ /* Interval for next command */
+ mdelay(10);
+
+ return -1;
+}
+
+static void __iomem *base;
+static unsigned long tclk;
+static const struct reset_cfg *cfg;
+
+static void linkstation_reset(void)
+{
+ const unsigned divisor = ((tclk + (8 * cfg->baud)) / (16 * cfg->baud));
+ int i;
+
+ pr_err("%s: triggering power-off...\n", __func__);
+
+ /* hijack UART1 and reset into sane state */
+ writel(0x83, UART1_REG(LCR));
+ writel(divisor & 0xff, UART1_REG(DLL));
+ writel((divisor >> 8) & 0xff, UART1_REG(DLM));
+ writel(cfg->magic[0], UART1_REG(LCR));
+ writel(cfg->magic[1], UART1_REG(IER));
+ writel(cfg->magic[2], UART1_REG(FCR));
+ writel(cfg->magic[3], UART1_REG(MCR));
+
+ /* send the power-off command to PIC */
+ for(i = 0; cfg->cmd[i][0] > 0; i ++) {
+ /* [0] is size of the command; command starts from [1] */
+ uart1_micon_send(base, &(cfg->cmd[i][1]), cfg->cmd[i][0]);
+ }
+}
+
+static int linkstation_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct clk *clk;
+ char symname[KSYM_NAME_LEN];
+
+ const struct of_device_id *match =
+ of_match_node(linkstation_reset_of_match_table, np);
+ cfg = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Missing resource");
+ return -EINVAL;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "Unable to map resource");
+ return -EINVAL;
+ }
+
+ /* We need to know tclk in order to calculate the UART divisor */
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Clk missing");
+ return PTR_ERR(clk);
+ }
+
+ tclk = clk_get_rate(clk);
+
+ /* Check that nothing else has already setup a handler */
+ if (pm_power_off) {
+ lookup_symbol_name((ulong)pm_power_off, symname);
+ dev_err(&pdev->dev,
+ "pm_power_off already claimed %p %s",
+ pm_power_off, symname);
+ return -EBUSY;
+ }
+ pm_power_off = linkstation_reset;
+
+ return 0;
+}
+
+static int linkstation_reset_remove(struct platform_device *pdev)
+{
+ pm_power_off = NULL;
+ return 0;
+}
+
+static struct platform_driver linkstation_reset_driver = {
+ .probe = linkstation_reset_probe,
+ .remove = linkstation_reset_remove,
+ .driver = {
+ .name = "linkstation_reset",
+ .of_match_table = of_match_ptr(linkstation_reset_of_match_table),
+ },
+};
+
+module_platform_driver(linkstation_reset_driver);
+
+MODULE_AUTHOR("Roger Shimizu <rogershimizu@gmail.com>");
+MODULE_DESCRIPTION("Linkstation Reset driver");
+MODULE_LICENSE("GPL v2");
--
2.11.0
^ permalink raw reply related
* [PATCH v3 0/3] make kurobox-pro be able to shutdown after device-tree migration
From: Roger Shimizu @ 2016-12-27 7:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161216100501.18173-1-rogershimizu@gmail.com>
Dear Kernel Maintainers,
Kurobox-Pro (and variants) need more commands sending to UART1 to shutdown.
So here I make this patch series to let current qnap-poweroff implementation
be able to handle such case.
Here I give 3 patches, for 3 different kernel subsystems respectivelay:
- Patch 1/3: System reset/shutdown driver
- Patch 2/3: Open firmware and flattened device tree bindings
- Patch 3/3: ARM/Marvell Dove/MV78xx0/Orion SOC support
Ryan Tandy, the issue reporter, and I have already tested those changes on
Linkstation/KuroBoxPro devices, and confirmed it's working well.
Merry Xmax and look forward to your feedback!
Changes:
v0 => v1:
- Update 0003 to split kuroboxpro related code into kuroboxpro-common.c
v1 => v2:
- Split off linkstation/kuroboxpro related code to linkstation-reset.c
Because linkstation before kuroboxpro also need this driver to power
off properly. It's more proper to call it linkstation driver.
v2 => v3:
- Split off devicetree bindings doc into a separate patch.
- Add device-tree patch to make Linkstation LS-GL and KuroBox Pro to
use the newly created linkstation-reset driver.
- Remove the unused one-byte command sending case in linkstation-reset
driver.
Cheers,
Roger Shimizu, GMT +9 Tokyo
PGP/GPG: 4096R/6C6ACD6417B3ACB1
Roger Shimizu (3):
power: reset: add linkstation-reset driver
DT: bingdings: power: reset: add linkstation-reset doc
ARM: DT: add power-off support to linkstation lsgl and kuroboxpro
.../bindings/power/reset/linkstation-reset.txt | 26 ++
arch/arm/boot/dts/orion5x-kuroboxpro.dts | 8 +
arch/arm/boot/dts/orion5x-linkstation-lsgl.dts | 10 +
arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts | 4 +
arch/arm/boot/dts/orion5x-linkstation.dtsi | 4 -
drivers/power/reset/Kconfig | 10 +
drivers/power/reset/Makefile | 1 +
drivers/power/reset/linkstation-reset.c | 269 +++++++++++++++++++++
8 files changed, 328 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/power/reset/linkstation-reset.txt
create mode 100644 drivers/power/reset/linkstation-reset.c
--
2.11.0
^ permalink raw reply
* [PATCH 3/3 v2] iio: adc: add a driver for Qualcomm PM8xxx HK/XOADC
From: Bjorn Andersson @ 2016-12-27 6:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481842118-14095-1-git-send-email-linus.walleij@linaro.org>
On Thu 15 Dec 14:48 PST 2016, Linus Walleij wrote:
> The Qualcomm PM8xxx PMICs contain a simpler ADC than its
> successors (already in the kernel as qcom-spmi-adc.c):
> the HK/XO ADC (Housekeeping/Chrystal oscillator ADC).
>
> As far as I can understand this is equal to the PMICs
> using SSBI transport and encompass PM8018, PM8038,
> PM8058, PM8917 and PM8921, so this is shortly named
> PM8xxx.
>
> This ADC monitors a bunch of on-board voltages and the die
> temperature of the PMIC itself, but it can also be routed
> to convert a few external MPPs (multi-purpose pins). On
> the APQ8060 DragonBoard this feature is used to let this
> ADC convert an analog ALS (Ambient Light Sensor) voltage
> signal from a Capella CM3605 ALS into a LUX value.
>
> Developed and tested with APQ8060 DragonBoard based on
> Ivan's driver. The SPMI VADC driver is quite different,
> but share enough minor functionality that I have split
> out to the common file in a previous patch.
I gave this a spin on one of my APQ8064 devices - with PM8921 - and I
can do measurements.
Several of the channels do give me reasonable readings. But the channels
in PM8921 are different than PM8058, so it looks like we need additional
prescales defined. Further more, the 8921 has several different
thermo-related channels, each with their own (post-)scaling function.
And lastly it seems that I have 2 thermo-channels on "mpp amux", but I'm
still confused to how that is supposed to work in the downstream code -
I will need to investigate this further.
One of the channels defined in my APQ8064 device measures
ADC_MPP_1_AMUX5, a lookup table is used to convert the measured value to
a temperature. As the table depends on an external thermistor, which
seems to differ between products a number of lookup tables exists - with
156 data points each.
[..]
> +
> +/*
> + * The different channels have hard-coded prescale ratios defined
> + * by the hardware.
> + */
> +static const struct vadc_prescale_ratio adc_prescale_ratios[] = {
> + { .num = 1, .den = 2 }, /* CHANNEL_VCOIN */
> + { .num = 1, .den = 3 }, /* CHANNEL_VBAT */
> + { .num = 1, .den = 10 }, /* CHANNEL_VCHG */
> + { .num = 1, .den = 1 }, /* CHANNEL_CHG_MONITOR */
> + { .num = 1, .den = 3 }, /* CHANNEL_VPH_PWR */
> + { .num = 1, .den = 1 }, /* CHANNEL_MPP5 */
> + { .num = 1, .den = 1 }, /* CHANNEL_MPP6 */
> + { .num = 1, .den = 2 }, /* CHANNEL_MPP7 */
> + { .num = 1, .den = 2 }, /* CHANNEL_MPP8 */
> + { .num = 1, .den = 3 }, /* CHANNEL_MPP9 */
> + { .num = 1, .den = 3 }, /* CHANNEL_USB_VBUS */
> + { .num = 1, .den = 1 }, /* CHANNEL_DIE_TEMP */
> + { .num = 1, .den = 1 }, /* CHANNEL_INTERNAL */
> + { .num = 1, .den = 1 }, /* CHANNEL_125V */
> + { .num = 1, .den = 1 }, /* CHANNEL_INTERNAL_2 */
> + { .num = 1, .den = 1 }, /* CHANNEL_MUXOFF */
> +};
The pm8921 have different meaning for the channels and the prescale
values are hence different. In the downstream kernel the values comes
from the board file, but I don't know if that means they will ever
change.
[..]
> +
> +static int pm8xxx_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
> + const struct pm8xxx_chan_info *ch;
> + u16 adc_code;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_PROCESSED:
> + /* Only die temperature ends up here */
> + ch = pm8xxx_get_channel(adc, chan->address);
> + if (!ch) {
> + dev_err(adc->dev, "no such channel %lu\n",
> + chan->address);
> + return -EINVAL;
> + }
> + ret = pm8xxx_read_channel(adc, ch, &adc_code);
> + if (ret)
> + return ret;
> + *val = pm8xxx_calibrate(adc, ch, adc_code);
> + /* 2mV/K, return milli Celsius */
> + *val /= 2;
> + *val -= KELVINMIL_CELSIUSMIL;
On my 8064 device I have 6 different temperatures (2 coming from amux'ed
mpp channels). They all have different lookup tables, which seems
calibrated based on some external resistor.
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_RAW:
> + switch (chan->type) {
> + case IIO_VOLTAGE:
> + ch = pm8xxx_get_channel(adc, chan->address);
> + if (!ch) {
> + dev_err(adc->dev, "no such channel %lu\n",
> + chan->address);
> + return -EINVAL;
> + }
> + ret = pm8xxx_read_channel(adc, ch, &adc_code);
> + if (ret)
> + return ret;
> + *val = pm8xxx_calibrate(adc, ch, adc_code);
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> + case IIO_CHAN_INFO_SCALE:
> + /*
> + * Applies to all voltage channels: we scale the microvolts
> + * to millivolts as required by the userspace ABI.
> + */
> + *val = 0;
> + *val2 = 1000;
> + return IIO_VAL_INT_PLUS_MICRO;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
> + const struct of_phandle_args *iiospec)
> +{
> + struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
> + unsigned int i;
> +
> + for (i = 0; i < adc->nchans; i++)
> + if (adc->iio_chans[i].channel == iiospec->args[0])
> + return i;
> +
> + return -EINVAL;
> +}
> +
> +static const struct iio_info pm8xxx_xoadc_info = {
> + .driver_module = THIS_MODULE,
> + .of_xlate = pm8xxx_of_xlate,
> + .read_raw = pm8xxx_read_raw,
> +};
> +
> +static int pm8xxx_xoadc_parse_channel(struct device *dev,
> + struct device_node *np,
> + struct pm8xxx_chan_info *ch)
> +{
> + const char *name = np->name;
> + u32 chan, rsv, dec;
> + int ret;
> +
> + ret = of_property_read_u32(np, "reg", &chan);
> + if (ret) {
> + dev_err(dev, "invalid channel number %s\n", name);
> + return ret;
> + }
> + if (chan > XOADC_CHAN_MAX) {
> + dev_err(dev, "%s too big channel number %d\n", name, chan);
> + return -EINVAL;
> + }
> +
> + if (of_property_read_bool(np, "qcom,ratiometric")) {
> + ch->calibration = VADC_CALIB_RATIOMETRIC;
> + ret = of_property_read_u32(np, "qcom,ratiometric-ref", &rsv);
If this is what you intended, you can squash the two properties into
one.
> + if (ret) {
> + dev_err(dev, "invalid RSV %s\n", name);
> + return ret;
> + }
> + if (rsv > XOADC_RSV_MAX) {
> + dev_err(dev, "%s too large RSV value %d\n", name, rsv);
> + return -EINVAL;
> + }
> + if (rsv == AMUX_RSV3) {
> + dev_err(dev, "%s invalid RSV value %d\n", name, rsv);
> + return -EINVAL;
> + }
> + } else {
> + ch->calibration = VADC_CALIB_ABSOLUTE;
> + rsv = 0;
> + }
> +
> + ret = of_property_read_u32(np, "qcom,decimation", &dec);
> + if (!ret) {
> + /* It's OK to skip this ... */
> + ret = qcom_vadc_decimation_from_dt(dec);
> + if (ret < 0) {
> + dev_err(dev, "%s invalid decimation %d\n",
> + name, dec);
> + return ret;
> + }
> + ch->decimation = ret;
> + } else {
> + ch->decimation = VADC_DEF_DECIMATION;
> + }
> +
> + ch->amux_channel = chan;
> + ch->name = name;
> + ch->amux_ip_rsv = rsv;
> + ch->amux_mpp_channel = PREMUX_MPP_SCALE_0; /* FIXME: get from DT */
After reading the code related to "amux/mpp" I've quite confused, it
does indeed look like the only thing done is to apply some scaling to
the value - but this doesn't make sense looking at the board files and
naming of the defines used downstream.
I will have to try to find some hints in the documentation and play
around with this a little bit more.
> +
> + dev_dbg(dev, "channel %d \"%s\" ref voltage: %d, decimation %d\n",
> + ch->amux_channel,
> + ch->name,
> + ch->amux_ip_rsv,
> + ch->decimation);
> + return 0;
> +}
> +
> +static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc,
> + struct device_node *np)
> +{
> + struct device_node *child;
> + struct pm8xxx_chan_info *ch;
> + int ret;
> + int i;
> +
> + adc->nchans = of_get_available_child_count(np);
> + if (!adc->nchans) {
> + dev_err(adc->dev, "no channel children\n");
> + return -ENODEV;
> + }
> + dev_dbg(adc->dev, "found %d ADC channels\n", adc->nchans);
> +
> + adc->iio_chans = devm_kcalloc(adc->dev, adc->nchans,
> + sizeof(*adc->iio_chans), GFP_KERNEL);
> + if (!adc->iio_chans)
> + return -ENOMEM;
> +
> + adc->chans = devm_kcalloc(adc->dev, adc->nchans,
> + sizeof(*adc->chans), GFP_KERNEL);
> + if (!adc->chans)
> + return -ENOMEM;
> +
> + i = 0;
> + for_each_available_child_of_node(np, child) {
> + struct iio_chan_spec *iio_chan;
> +
> + ch = &adc->chans[i];
> + ret = pm8xxx_xoadc_parse_channel(adc->dev, child, ch);
> + if (ret) {
> + of_node_put(child);
> + return ret;
> + }
> +
> + iio_chan = &adc->iio_chans[i];
> + iio_chan->channel = ch->amux_channel;
> + iio_chan->datasheet_name = ch->name;
> + /* A single temperature channel, the rest are voltages */
> + if (ch->amux_channel == CHANNEL_DIE_TEMP) {
> + iio_chan->type = IIO_TEMP;
> + iio_chan->info_mask_separate =
> + BIT(IIO_CHAN_INFO_PROCESSED);
> + } else {
> + iio_chan->type = IIO_VOLTAGE;
> + iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE);
> + }
> + iio_chan->indexed = 1;
> + iio_chan->address = ch->amux_channel;
> +
> + i++;
> + }
> +
> + /* Check for required channels */
> + ch = pm8xxx_get_channel(adc, CHANNEL_125V);
> + if (!ch) {
> + dev_err(adc->dev, "missing 1.25V reference channel\n");
> + return -ENODEV;
> + }
> + ch = pm8xxx_get_channel(adc, CHANNEL_INTERNAL);
> + if (!ch) {
> + dev_err(adc->dev, "missing 0.625V reference channel\n");
> + return -ENODEV;
> + }
> + ch = pm8xxx_get_channel(adc, CHANNEL_MUXOFF);
> + if (!ch) {
> + dev_err(adc->dev, "missing MUXOFF reference channel\n");
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int pm8xxx_xoadc_probe(struct platform_device *pdev)
> +{
> + struct pm8xxx_xoadc *adc;
> + struct iio_dev *indio_dev;
> + struct device_node *np = pdev->dev.of_node;
> + struct regmap *map;
> + struct device *dev = &pdev->dev;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
> + if (!indio_dev)
> + return -ENOMEM;
> + platform_set_drvdata(pdev, indio_dev);
> +
> + adc = iio_priv(indio_dev);
> + adc->dev = dev;
> + init_completion(&adc->complete);
> + mutex_init(&adc->lock);
> +
> + ret = pm8xxx_xoadc_parse_channels(adc, np);
> + if (ret)
> + return ret;
> +
> + map = dev_get_regmap(dev->parent, NULL);
> + if (!map) {
> + dev_err(dev, "Parent regmap unavailable.\n");
> + return -ENXIO;
> + }
> + adc->map = map;
> +
> + /* Bring up regulator */
> + adc->vref = devm_regulator_get(dev, "xoadc-ref");
> + if (IS_ERR(adc->vref)) {
> + dev_err(dev, "failed to get XOADC VREF regulator\n");
> + return PTR_ERR(adc->vref);
> + }
> + /* We strictly require this voltage */
> + ret = regulator_set_voltage(adc->vref, 2200000, 2200000);
On 8064 the reference is L14 and it's at 1.8V, so this fails for me.
However, the way that this is written should reflect on the board design
and your L18 (and my L14) will have a single valid value. As such there
should be no need to set a voltage here (other then to catch mistakes).
> + if (ret) {
> + dev_err(dev, "unable to set LDO18 voltage to 2.2V\n");
> + return ret;
> + }
Regards,
Bjorn
^ permalink raw reply
* [PATCH] PCI: exynos: refactor exynos pcie driver
From: Alim Akhtar @ 2016-12-27 6:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6de4bc5b-05fb-793f-d3ab-b1c6ee19cfeb@samsung.com>
Hi Jaehoon,
On 12/27/2016 08:00 AM, Jaehoon Chung wrote:
> On 12/27/2016 11:12 AM, Alim Akhtar wrote:
>>
>>
>> On 12/27/2016 06:39 AM, Jaehoon Chung wrote:
>>> Dear Alim,
>>>
>>> On 12/26/2016 06:46 PM, Alim Akhtar wrote:
>>>> Hello Jaehoon
>>>>
>>>> On 12/26/2016 02:32 PM, Jaehoon Chung wrote:
>>>>> Hi Pankaj,
>>>>>
>>>>> On 12/23/2016 07:56 PM, Pankaj Dubey wrote:
>>>>>> From: Niyas Ahmed S T <niyas.ahmed@samsung.com>
>>>>>>
>>>>>> Currently Exynos PCIe driver is only supported for Exynos5440 SoC.
>>>>>> This patch does refactoring of Exynos PCIe driver to extend support
>>>>>> for other Exynos SoC.
>>>>>>
>>>>>> Following are the main changes done via this patch:
>>>>>> 1) It adds separate structs for memory, clock resources.
>>>>>> 2) It add exynos_pcie_ops struct which will allow us to support the
>>>>>> differences in resources in different Exynos SoC.
>>>>>
>>>>> It's nice to me for reusing this file.
>>>>> but after considering too many times, i decided not to use this file.
>>>>>
>>>>> I'm not sure what block base is..actually this pci-exynos.c is really black-box.
>>>>> (No one maintains this file, even Samsung didn't care.)
>>>>> Who is using this?
>>>>> If Someone can share the information about exynos5440, i can refactor everything.
>>>>> Otherwise, there are two solution..
>>>>>
>>>>> One is "adding the new pci-exynos.c" likes pci-exynos5433.c
>>>>> Other is "refactor this file" under assuming the each register's usage.
>>>>>
>>>> Its alway good to reuse code as far as possible.
>>>> I am yet to see the details of 5440, but since people are now going to support more Exynos variants, in my opinion, instead of adding pci-exynos5433.c, you can rename current pci-exynos.c to something like pci-exynos5440.c (only in case its too much changes needed to support 5433/exynos7) and lets have a common pci-exynos.c where we can add exynos7/5433 and others SoCs, AFAIK at least exynos7 and 5433 has similar pci controller.
>>>
>>> Yes, It's always good to reuse. but as you know, current pci-exynos.c file is really specific for only exynos5440.
>>> I will try to check about combining.
>>>
>>>>> I want to use the PHY generic Framework for EXYNOS PCIe.
>>>>>
>>>> I don't think you have an option here, you should use generic PHY APIs, otherwise phy drive should go to drivers/misc.
>>>> Other thoughts are welcome.
>>>
>>> Why go to drivers/misc? There is driver/phy/ for PHY generic Framework.
>>> If i will touch this file, then i will put our phy-exynos-pcie file under driver/phy/ .
>>> I already sent the patch for this. Could you check them?
>>>
>> My point was, if you are not going to use generic PHY APIs, then phy driver should go into drivers/misc. Anyway as you said you have already posted patches with generic phy framework, I will take a look.
>
> Ah. Right..And i'm doing the refactoring to reuse the current pci-exynos.c.
There is a nice refactoring patch posted by Pankaj recently @
https://lkml.org/lkml/2016/12/23/73
I would suggest you to rebase your work on this top.
> Maybe..Today or Tomorrow..I will send the patches..At that time, could you also check them?
> Any comments might be helpful to me! :)
>
Will wait for you patches :-)
> Best Regards,
> Jaehoon Chung
>
>>> http://patchwork.ozlabs.org/patch/708738/
>>> http://patchwork.ozlabs.org/patch/708742/
>>>
>> Thanks.
>>
>>> Best Regards,
>>> Jaehoon Chung
>>>
>>>>
>>>>> If you or other guys really want to use the pci-exynos.c for other exynos,
>>>>> I will rework with PHY generic framework. Then i will resend the my patches as V2.
>>>>>
>>>>> One more thing..Does anyone know what the usage of block base is?
>>>>> Can i use that register as "syscon"?
>>>>>
>>>>> Best Regards,
>>>>> Jaehoon Chung
>>>>>
>>>>>>
>>>>>> No functional change intended.
>>>>>>
>>>>>> Signed-off-by: Niyas Ahmed S T <niyas.ahmed@samsung.com>
>>>>>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>>>>>> ---
>>>>>> This patch set is prepared on top of Krzysztof's for-next and
>>>>>> PCIe driver cleanup patch [1] by Jaehoon Chung.
>>>>>>
>>>>>> [1]: https://lkml.org/lkml/2016/12/19/44
>>>>>>
>>>>>>
>>>>>> drivers/pci/host/pci-exynos.c | 346 ++++++++++++++++++++++++++----------------
>>>>>> 1 file changed, 217 insertions(+), 129 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
>>>>>> index 33562cf..2dc54f7 100644
>>>>>> --- a/drivers/pci/host/pci-exynos.c
>>>>>> +++ b/drivers/pci/host/pci-exynos.c
>>>>>> @@ -17,6 +17,7 @@
>>>>>> #include <linux/interrupt.h>
>>>>>> #include <linux/kernel.h>
>>>>>> #include <linux/init.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> #include <linux/of_gpio.h>
>>>>>> #include <linux/pci.h>
>>>>>> #include <linux/platform_device.h>
>>>>>> @@ -28,16 +29,6 @@
>>>>>>
>>>>>> #define to_exynos_pcie(x) container_of(x, struct exynos_pcie, pp)
>>>>>>
>>>>>> -struct exynos_pcie {
>>>>>> - struct pcie_port pp;
>>>>>> - void __iomem *elbi_base; /* DT 0th resource */
>>>>>> - void __iomem *phy_base; /* DT 1st resource */
>>>>>> - void __iomem *block_base; /* DT 2nd resource */
>>>>>> - int reset_gpio;
>>>>>> - struct clk *clk;
>>>>>> - struct clk *bus_clk;
>>>>>> -};
>>>>>> -
>>>>>> /* PCIe ELBI registers */
>>>>>> #define PCIE_IRQ_PULSE 0x000
>>>>>> #define IRQ_INTA_ASSERT BIT(0)
>>>>>> @@ -102,6 +93,122 @@ struct exynos_pcie {
>>>>>> #define PCIE_PHY_TRSV3_PD_TSV BIT(7)
>>>>>> #define PCIE_PHY_TRSV3_LVCC 0x31c
>>>>>>
>>>>>> +struct exynos_pcie_mem_res {
>>>>>> + void __iomem *elbi_base; /* DT 0th resource: PCIE CTRL */
>>>>>> + void __iomem *phy_base; /* DT 1st resource: PHY CTRL */
>>>>>> + void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */
>>>>>> +};
>>>>>> +
>>>>>> +struct exynos_pcie_clk_res {
>>>>>> + struct clk *clk;
>>>>>> + struct clk *bus_clk;
>>>>>> +};
>>>>>> +
>>>>>> +struct exynos_pcie {
>>>>>> + struct pcie_port pp;
>>>>>> + struct exynos_pcie_mem_res *mem_res;
>>>>>> + struct exynos_pcie_clk_res *clk_res;
>>>>>> + const struct exynos_pcie_ops *ops;
>>>>>> + int reset_gpio;
>>>>>> +};
>>>>>> +
>>>>>> +struct exynos_pcie_ops {
>>>>>> + int (*get_mem_resources)(struct platform_device *pdev,
>>>>>> + struct exynos_pcie *ep);
>>>>>> + int (*get_clk_resources)(struct exynos_pcie *ep);
>>>>>> + int (*init_clk_resources)(struct exynos_pcie *ep);
>>>>>> + void (*deinit_clk_resources)(struct exynos_pcie *ep);
>>>>>> +};
>>>>>> +
>>>>>> +static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
>>>>>> + struct exynos_pcie *ep)
>>>>>> +{
>>>>>> + struct resource *res;
>>>>>> + struct device *dev = ep->pp.dev;
>>>>>> +
>>>>>> + ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
>>>>>> + if (!ep->mem_res)
>>>>>> + return -ENOMEM;
>>>>>> +
>>>>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>> + ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
>>>>>> + if (IS_ERR(ep->mem_res->elbi_base))
>>>>>> + return PTR_ERR(ep->mem_res->elbi_base);
>>>>>> +
>>>>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>>>>> + ep->mem_res->phy_base = devm_ioremap_resource(dev, res);
>>>>>> + if (IS_ERR(ep->mem_res->phy_base))
>>>>>> + return PTR_ERR(ep->mem_res->phy_base);
>>>>>> +
>>>>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
>>>>>> + ep->mem_res->block_base = devm_ioremap_resource(dev, res);
>>>>>> + if (IS_ERR(ep->mem_res->block_base))
>>>>>> + return PTR_ERR(ep->mem_res->block_base);
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
>>>>>> +{
>>>>>> + struct device *dev = ep->pp.dev;
>>>>>> +
>>>>>> + ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
>>>>>> + if (!ep->clk_res)
>>>>>> + return -ENOMEM;
>>>>>> +
>>>>>> + ep->clk_res->clk = devm_clk_get(dev, "pcie");
>>>>>> + if (IS_ERR(ep->clk_res->clk)) {
>>>>>> + dev_err(dev, "Failed to get pcie rc clock\n");
>>>>>> + return PTR_ERR(ep->clk_res->clk);
>>>>>> + }
>>>>>> +
>>>>>> + ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
>>>>>> + if (IS_ERR(ep->clk_res->bus_clk)) {
>>>>>> + dev_err(dev, "Failed to get pcie bus clock\n");
>>>>>> + return PTR_ERR(ep->clk_res->bus_clk);
>>>>>> + }
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
>>>>>> +{
>>>>>> + struct device *dev = ep->pp.dev;
>>>>>> + int ret;
>>>>>> +
>>>>>> + ret = clk_prepare_enable(ep->clk_res->clk);
>>>>>> + if (ret) {
>>>>>> + dev_err(dev, "cannot enable pcie rc clock");
>>>>>> + return ret;
>>>>>> + }
>>>>>> +
>>>>>> + ret = clk_prepare_enable(ep->clk_res->bus_clk);
>>>>>> + if (ret) {
>>>>>> + dev_err(dev, "cannot enable pcie bus clock");
>>>>>> + goto err_bus_clk;
>>>>>> + }
>>>>>> +
>>>>>> + return 0;
>>>>>> +
>>>>>> +err_bus_clk:
>>>>>> + clk_disable_unprepare(ep->clk_res->clk);
>>>>>> +
>>>>>> + return ret;
>>>>>> +}
>>>>>> +
>>>>>> +static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
>>>>>> +{
>>>>>> + clk_disable_unprepare(ep->clk_res->bus_clk);
>>>>>> + clk_disable_unprepare(ep->clk_res->clk);
>>>>>> +}
>>>>>> +
>>>>>> +static const struct exynos_pcie_ops exynos5440_pcie_ops = {
>>>>>> + .get_mem_resources = exynos5440_pcie_get_mem_resources,
>>>>>> + .get_clk_resources = exynos5440_pcie_get_clk_resources,
>>>>>> + .init_clk_resources = exynos5440_pcie_init_clk_resources,
>>>>>> + .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources,
>>>>>> +};
>>>>>> +
>>>>>> static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
>>>>>> {
>>>>>> writel(val, base + reg);
>>>>>> @@ -116,155 +223,155 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
>>>>>> if (on)
>>>>>> val |= PCIE_ELBI_SLV_DBI_ENABLE;
>>>>>> else
>>>>>> val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
>>>>>> if (on)
>>>>>> val |= PCIE_ELBI_SLV_DBI_ENABLE;
>>>>>> else
>>>>>> val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>>>>>> val &= ~PCIE_CORE_RESET_ENABLE;
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 0, PCIE_PWR_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
>>>>>> val |= PCIE_CORE_RESET_ENABLE;
>>>>>>
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
>>>>>> - exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_MAC_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_MAC_RESET);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_assert_phy_reset(struct exynos_pcie *ep)
>>>>>> {
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_MAC_RESET);
>>>>>> - exynos_pcie_writel(ep->block_base, 1, PCIE_PHY_GLOBAL_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_MAC_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_GLOBAL_RESET);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *ep)
>>>>>> {
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_GLOBAL_RESET);
>>>>>> - exynos_pcie_writel(ep->elbi_base, 1, PCIE_PWR_RESET);
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_COMMON_RESET);
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_CMN_REG);
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSVREG_RESET);
>>>>>> - exynos_pcie_writel(ep->block_base, 0, PCIE_PHY_TRSV_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_GLOBAL_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_PWR_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_CMN_REG);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSVREG_RESET);
>>>>>> + exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSV_RESET);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_power_on_phy(struct exynos_pcie *ep)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>>>>>> val &= ~PCIE_PHY_COMMON_PD_CMN;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>>>>>> val &= ~PCIE_PHY_TRSV0_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>>>>>> val &= ~PCIE_PHY_TRSV1_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>>>>>> val &= ~PCIE_PHY_TRSV2_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>>>>>> val &= ~PCIE_PHY_TRSV3_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_power_off_phy(struct exynos_pcie *ep)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
>>>>>> val |= PCIE_PHY_COMMON_PD_CMN;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
>>>>>> val |= PCIE_PHY_TRSV0_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
>>>>>> val |= PCIE_PHY_TRSV1_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
>>>>>> val |= PCIE_PHY_TRSV2_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
>>>>>> val |= PCIE_PHY_TRSV3_PD_TSV;
>>>>>> - exynos_pcie_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_init_phy(struct exynos_pcie *ep)
>>>>>> {
>>>>>> /* DCC feedback control off */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
>>>>>>
>>>>>> /* set TX/RX impedance */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
>>>>>>
>>>>>> /* set 50Mhz PHY clock */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
>>>>>>
>>>>>> /* set TX Differential output for lane 0 */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
>>>>>>
>>>>>> /* set TX Pre-emphasis Level Control for lane 0 to minimum */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
>>>>>>
>>>>>> /* set RX clock and data recovery bandwidth */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
>>>>>>
>>>>>> /* change TX Pre-emphasis Level Control for lanes */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
>>>>>>
>>>>>> /* set LVCC */
>>>>>> - exynos_pcie_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
>>>>>> - exynos_pcie_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
>>>>>> + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie)
>>>>>> @@ -295,25 +402,27 @@ static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie)
>>>>>> exynos_pcie_init_phy(exynos_pcie);
>>>>>>
>>>>>> /* pulse for common reset */
>>>>>> - exynos_pcie_writel(exynos_pcie->block_base, 1, PCIE_PHY_COMMON_RESET);
>>>>>> + exynos_pcie_writel(exynos_pcie->mem_res->block_base, 1,
>>>>>> + PCIE_PHY_COMMON_RESET);
>>>>>> udelay(500);
>>>>>> - exynos_pcie_writel(exynos_pcie->block_base, 0, PCIE_PHY_COMMON_RESET);
>>>>>> + exynos_pcie_writel(exynos_pcie->mem_res->block_base, 0,
>>>>>> + PCIE_PHY_COMMON_RESET);
>>>>>>
>>>>>> exynos_pcie_deassert_core_reset(exynos_pcie);
>>>>>> dw_pcie_setup_rc(pp);
>>>>>> exynos_pcie_assert_reset(exynos_pcie);
>>>>>>
>>>>>> /* assert LTSSM enable */
>>>>>> - exynos_pcie_writel(exynos_pcie->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
>>>>>> - PCIE_APP_LTSSM_ENABLE);
>>>>>> + exynos_pcie_writel(exynos_pcie->mem_res->elbi_base,
>>>>>> + PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE);
>>>>>>
>>>>>> /* check if the link is up or not */
>>>>>> if (!dw_pcie_wait_for_link(pp))
>>>>>> return 0;
>>>>>>
>>>>>> - while (exynos_pcie_readl(exynos_pcie->phy_base,
>>>>>> + while (exynos_pcie_readl(exynos_pcie->mem_res->phy_base,
>>>>>> PCIE_PHY_PLL_LOCKED) == 0) {
>>>>>> - val = exynos_pcie_readl(exynos_pcie->block_base,
>>>>>> + val = exynos_pcie_readl(exynos_pcie->mem_res->block_base,
>>>>>> PCIE_PHY_PLL_LOCKED);
>>>>>> dev_info(dev, "PLL Locked: 0x%x\n", val);
>>>>>> }
>>>>>> @@ -325,8 +434,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
>>>>>> {
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
>>>>>> @@ -336,7 +445,7 @@ static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
>>>>>> /* enable INTX interrupt */
>>>>>> val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
>>>>>> IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
>>>>>> }
>>>>>>
>>>>>> static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
>>>>>> @@ -363,9 +472,9 @@ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
>>>>>> dw_pcie_msi_init(pp);
>>>>>>
>>>>>> /* enable MSI interrupt */
>>>>>> - val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_EN_LEVEL);
>>>>>> + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
>>>>>> val |= IRQ_MSI_ENABLE;
>>>>>> - exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_LEVEL);
>>>>>> + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
>>>>>> }
>>>>>>
>>>>>> static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie)
>>>>>> @@ -425,7 +534,8 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
>>>>>> struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
>>>>>> u32 val;
>>>>>>
>>>>>> - val = exynos_pcie_readl(exynos_pcie->elbi_base, PCIE_ELBI_RDLH_LINKUP);
>>>>>> + val = exynos_pcie_readl(exynos_pcie->mem_res->elbi_base,
>>>>>> + PCIE_ELBI_RDLH_LINKUP);
>>>>>> if (val == PCIE_ELBI_LTSSM_ENABLE)
>>>>>> return 1;
>>>>>>
>>>>>> @@ -503,7 +613,6 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>>>>>> struct exynos_pcie *exynos_pcie;
>>>>>> struct pcie_port *pp;
>>>>>> struct device_node *np = dev->of_node;
>>>>>> - struct resource *res;
>>>>>> int ret;
>>>>>>
>>>>>> exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL);
>>>>>> @@ -513,59 +622,37 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
>>>>>> pp = &exynos_pcie->pp;
>>>>>> pp->dev = dev;
>>>>>>
>>>>>> - exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
>>>>>> -
>>>>>> - exynos_pcie->clk = devm_clk_get(dev, "pcie");
>>>>>> - if (IS_ERR(exynos_pcie->clk)) {
>>>>>> - dev_err(dev, "Failed to get pcie rc clock\n");
>>>>>> - return PTR_ERR(exynos_pcie->clk);
>>>>>> - }
>>>>>> - ret = clk_prepare_enable(exynos_pcie->clk);
>>>>>> - if (ret)
>>>>>> - return ret;
>>>>>> + exynos_pcie->ops = (const struct exynos_pcie_ops *)
>>>>>> + of_device_get_match_data(dev);
>>>>>>
>>>>>> - exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
>>>>>> - if (IS_ERR(exynos_pcie->bus_clk)) {
>>>>>> - dev_err(dev, "Failed to get pcie bus clock\n");
>>>>>> - ret = PTR_ERR(exynos_pcie->bus_clk);
>>>>>> - goto fail_clk;
>>>>>> - }
>>>>>> - ret = clk_prepare_enable(exynos_pcie->bus_clk);
>>>>>> - if (ret)
>>>>>> - goto fail_clk;
>>>>>> + exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
>>>>>>
>>>>>> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>> - exynos_pcie->elbi_base = devm_ioremap_resource(dev, res);
>>>>>> - if (IS_ERR(exynos_pcie->elbi_base)) {
>>>>>> - ret = PTR_ERR(exynos_pcie->elbi_base);
>>>>>> - goto fail_bus_clk;
>>>>>> + if (exynos_pcie->ops && exynos_pcie->ops->get_mem_resources) {
>>>>>> + ret = exynos_pcie->ops->get_mem_resources(pdev, exynos_pcie);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> }
>>>>>>
>>>>>> - res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>>>>> - exynos_pcie->phy_base = devm_ioremap_resource(dev, res);
>>>>>> - if (IS_ERR(exynos_pcie->phy_base)) {
>>>>>> - ret = PTR_ERR(exynos_pcie->phy_base);
>>>>>> - goto fail_bus_clk;
>>>>>> - }
>>>>>> + if (exynos_pcie->ops && exynos_pcie->ops->get_clk_resources) {
>>>>>> + ret = exynos_pcie->ops->get_clk_resources(exynos_pcie);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>>
>>>>>> - res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
>>>>>> - exynos_pcie->block_base = devm_ioremap_resource(dev, res);
>>>>>> - if (IS_ERR(exynos_pcie->block_base)) {
>>>>>> - ret = PTR_ERR(exynos_pcie->block_base);
>>>>>> - goto fail_bus_clk;
>>>>>> + ret = exynos_pcie->ops->init_clk_resources(exynos_pcie);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> }
>>>>>>
>>>>>> ret = exynos_add_pcie_port(exynos_pcie, pdev);
>>>>>> if (ret < 0)
>>>>>> - goto fail_bus_clk;
>>>>>> + goto fail_probe;
>>>>>>
>>>>>> platform_set_drvdata(pdev, exynos_pcie);
>>>>>> return 0;
>>>>>>
>>>>>> -fail_bus_clk:
>>>>>> - clk_disable_unprepare(exynos_pcie->bus_clk);
>>>>>> -fail_clk:
>>>>>> - clk_disable_unprepare(exynos_pcie->clk);
>>>>>> +fail_probe:
>>>>>> + if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
>>>>>> + exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>>>>>> return ret;
>>>>>> }
>>>>>>
>>>>>> @@ -573,14 +660,15 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
>>>>>> {
>>>>>> struct exynos_pcie *exynos_pcie = platform_get_drvdata(pdev);
>>>>>>
>>>>>> - clk_disable_unprepare(exynos_pcie->bus_clk);
>>>>>> - clk_disable_unprepare(exynos_pcie->clk);
>>>>>> + if (exynos_pcie->ops && exynos_pcie->ops->deinit_clk_resources)
>>>>>> + exynos_pcie->ops->deinit_clk_resources(exynos_pcie);
>>>>>>
>>>>>> return 0;
>>>>>> }
>>>>>>
>>>>>> static const struct of_device_id exynos_pcie_of_match[] = {
>>>>>> - { .compatible = "samsung,exynos5440-pcie", },
>>>>>> + { .compatible = "samsung,exynos5440-pcie",
>>>>>> + .data = &exynos5440_pcie_ops },
>>>>>> {},
>>>>>> };
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>
>
>
>
^ permalink raw reply
* [PATCH v4 4/4] clk: rockchip: add clock controller for rk3328
From: Elaine Zhang @ 2016-12-27 6:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482820373-10186-1-git-send-email-zhangqing@rock-chips.com>
Add the clock tree definition for the new rk3328 SoC.
Changes in v4:
adjust the pacth 3 and 4 order.
Changes in v3:
fix up the pll parent only xin24m.
Changes in v2:
fix up these *_sample error description.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-rk3328.c | 1068 +++++++++++++++++++++++++++++++++++++
drivers/clk/rockchip/clk.h | 22 +
3 files changed, 1091 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-rk3328.c
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 16e098c36f90..68b04bfca282 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -16,5 +16,6 @@ obj-y += clk-rk3036.o
obj-y += clk-rk3188.o
obj-y += clk-rk3228.o
obj-y += clk-rk3288.o
+obj-y += clk-rk3328.o
obj-y += clk-rk3368.o
obj-y += clk-rk3399.o
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
new file mode 100644
index 000000000000..9958ce7d0dcd
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ * Author: Elaine <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3328-cru.h>
+#include "clk.h"
+
+#define RK3328_GRF_SOC_STATUS0 0x480
+#define RK3328_GRF_MAC_CON1 0x904
+#define RK3328_GRF_MAC_CON2 0x908
+
+enum rk3328_plls {
+ apll, dpll, cpll, gpll, npll,
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+ RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0),
+ RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
+ RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0),
+ RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
+ RK3036_PLL_RATE(900000000, 4, 300, 2, 1, 1, 0),
+ RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0),
+ RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0),
+ RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0),
+ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0),
+ RK3036_PLL_RATE(700000000, 6, 350, 2, 1, 1, 0),
+ RK3036_PLL_RATE(696000000, 1, 58, 2, 1, 1, 0),
+ RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
+ RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE(504000000, 1, 63, 3, 1, 1, 0),
+ RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0),
+ RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
+ RK3036_PLL_RATE(312000000, 1, 52, 2, 2, 1, 0),
+ RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
+ RK3036_PLL_RATE(96000000, 1, 64, 4, 4, 1, 0),
+ { /* sentinel */ },
+};
+
+static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
+ /* vco = 1016064000 */
+ RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
+ /* vco = 983040000 */
+ RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
+ /* vco = 983040000 */
+ RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
+ /* vco = 860156000 */
+ RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
+ /* vco = 903168000 */
+ RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
+ /* vco = 819200000 */
+ { /* sentinel */ },
+};
+
+#define RK3328_DIV_CPU_MASK 0x1f
+#define RK3328_DIV_CPU_SHIFT 8
+
+#define RK3328_DIV_PERI_MASK 0xf
+#define RK3328_DIV_PERI_SHIFT 0
+#define RK3328_DIV_ACLK_MASK 0x7
+#define RK3328_DIV_ACLK_SHIFT 4
+#define RK3328_DIV_HCLK_MASK 0x3
+#define RK3328_DIV_HCLK_SHIFT 8
+#define RK3328_DIV_PCLK_MASK 0x7
+#define RK3328_DIV_PCLK_SHIFT 12
+
+#define RK3328_CLKSEL1(_aclk_core, _pclk_dbg) \
+{ \
+ .reg = RK3328_CLKSEL_CON(1), \
+ .val = HIWORD_UPDATE(_aclk_core, RK3328_DIV_ACLKM_MASK, \
+ RK3328_DIV_ACLKM_SHIFT) | \
+ HIWORD_UPDATE(_pclk_dbg, RK3328_DIV_PCLK_DBG_MASK, \
+ RK3328_DIV_PCLK_DBG_SHIFT), \
+}
+
+#define RK3328_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg) \
+{ \
+ .prate = _prate, \
+ .divs = { \
+ RK3328_CLKSEL1(_aclk_core, _pclk_dbg), \
+ }, \
+}
+
+static struct rockchip_cpuclk_rate_table rk3328_cpuclk_rates[] __initdata = {
+ RK3328_CPUCLK_RATE(1800000000, 1, 7),
+ RK3328_CPUCLK_RATE(1704000000, 1, 7),
+ RK3328_CPUCLK_RATE(1608000000, 1, 7),
+ RK3328_CPUCLK_RATE(1512000000, 1, 7),
+ RK3328_CPUCLK_RATE(1488000000, 1, 5),
+ RK3328_CPUCLK_RATE(1416000000, 1, 5),
+ RK3328_CPUCLK_RATE(1392000000, 1, 5),
+ RK3328_CPUCLK_RATE(1296000000, 1, 5),
+ RK3328_CPUCLK_RATE(1200000000, 1, 5),
+ RK3328_CPUCLK_RATE(1104000000, 1, 5),
+ RK3328_CPUCLK_RATE(1008000000, 1, 5),
+ RK3328_CPUCLK_RATE(912000000, 1, 5),
+ RK3328_CPUCLK_RATE(816000000, 1, 3),
+ RK3328_CPUCLK_RATE(696000000, 1, 3),
+ RK3328_CPUCLK_RATE(600000000, 1, 3),
+ RK3328_CPUCLK_RATE(408000000, 1, 1),
+ RK3328_CPUCLK_RATE(312000000, 1, 1),
+ RK3328_CPUCLK_RATE(216000000, 1, 1),
+ RK3328_CPUCLK_RATE(96000000, 1, 1),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3328_cpuclk_data = {
+ .core_reg = RK3328_CLKSEL_CON(0),
+ .div_core_shift = 0,
+ .div_core_mask = 0x1f,
+ .mux_core_alt = 1,
+ .mux_core_main = 3,
+ .mux_core_shift = 6,
+ .mux_core_mask = 0x3,
+};
+
+PNAME(mux_pll_p) = { "xin24m" };
+
+PNAME(mux_2plls_p) = { "cpll", "gpll" };
+PNAME(mux_gpll_cpll_p) = { "gpll", "cpll" };
+PNAME(mux_cpll_gpll_apll_p) = { "cpll", "gpll", "apll" };
+PNAME(mux_2plls_xin24m_p) = { "cpll", "gpll", "xin24m" };
+PNAME(mux_2plls_hdmiphy_p) = { "cpll", "gpll",
+ "dummy_hdmiphy" };
+PNAME(mux_4plls_p) = { "cpll", "gpll",
+ "dummy_hdmiphy",
+ "usb480m" };
+PNAME(mux_2plls_u480m_p) = { "cpll", "gpll",
+ "usb480m" };
+PNAME(mux_2plls_24m_u480m_p) = { "cpll", "gpll",
+ "xin24m", "usb480m" };
+
+PNAME(mux_ddrphy_p) = { "dpll", "apll", "cpll" };
+PNAME(mux_armclk_p) = { "apll_core",
+ "gpll_core",
+ "dpll_core",
+ "npll_core"};
+PNAME(mux_hdmiphy_p) = { "hdmi_phy", "xin24m" };
+PNAME(mux_usb480m_p) = { "usb480m_phy",
+ "xin24m" };
+
+PNAME(mux_i2s0_p) = { "clk_i2s0_div",
+ "clk_i2s0_frac",
+ "xin12m",
+ "xin12m" };
+PNAME(mux_i2s1_p) = { "clk_i2s1_div",
+ "clk_i2s1_frac",
+ "clkin_i2s1",
+ "xin12m" };
+PNAME(mux_i2s2_p) = { "clk_i2s2_div",
+ "clk_i2s2_frac",
+ "clkin_i2s2",
+ "xin12m" };
+PNAME(mux_i2s1out_p) = { "clk_i2s1", "xin12m"};
+PNAME(mux_i2s2out_p) = { "clk_i2s2", "xin12m" };
+PNAME(mux_spdif_p) = { "clk_spdif_div",
+ "clk_spdif_frac",
+ "xin12m",
+ "xin12m" };
+PNAME(mux_uart0_p) = { "clk_uart0_div",
+ "clk_uart0_frac",
+ "xin24m" };
+PNAME(mux_uart1_p) = { "clk_uart1_div",
+ "clk_uart1_frac",
+ "xin24m" };
+PNAME(mux_uart2_p) = { "clk_uart2_div",
+ "clk_uart2_frac",
+ "xin24m" };
+
+PNAME(mux_sclk_cif_p) = { "clk_cif_src",
+ "xin24m" };
+PNAME(mux_dclk_lcdc_p) = { "hdmiphy",
+ "dclk_lcdc_src" };
+PNAME(mux_aclk_peri_pre_p) = { "cpll_peri",
+ "gpll_peri",
+ "hdmiphy_peri" };
+PNAME(mux_ref_usb3otg_src_p) = { "xin24m",
+ "clk_usb3otg_ref" };
+PNAME(mux_xin24m_32k_p) = { "xin24m",
+ "clk_rtc32k" };
+PNAME(mux_mac2io_src_p) = { "clk_mac2io_src",
+ "gmac_clkin" };
+PNAME(mux_mac2phy_src_p) = { "clk_mac2phy_src",
+ "phy_50m_out" };
+
+static struct rockchip_pll_clock rk3328_pll_clks[] __initdata = {
+ [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p,
+ 0, RK3328_PLL_CON(0),
+ RK3328_MODE_CON, 0, 4, 0, rk3328_pll_frac_rates),
+ [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p,
+ 0, RK3328_PLL_CON(8),
+ RK3328_MODE_CON, 4, 3, 0, NULL),
+ [cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p,
+ 0, RK3328_PLL_CON(16),
+ RK3328_MODE_CON, 8, 2, 0, rk3328_pll_rates),
+ [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p,
+ 0, RK3328_PLL_CON(24),
+ RK3328_MODE_CON, 12, 1, 0, rk3328_pll_frac_rates),
+ [npll] = PLL(pll_rk3328, PLL_NPLL, "npll", mux_pll_p,
+ 0, RK3328_PLL_CON(40),
+ RK3328_MODE_CON, 1, 0, 0, rk3328_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3328_i2s0_fracmux __initdata =
+ MUX(0, "i2s0_pre", mux_i2s0_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(6), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s1_fracmux __initdata =
+ MUX(0, "i2s1_pre", mux_i2s1_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(8), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_i2s2_fracmux __initdata =
+ MUX(0, "i2s2_pre", mux_i2s2_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(10), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_spdif_fracmux __initdata =
+ MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(12), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart0_fracmux __initdata =
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart1_fracmux __initdata =
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(16), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_uart2_fracmux __initdata =
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(18), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
+ /*
+ * Clock-Architecture Diagram 1
+ */
+
+ DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(2), 8, 5, DFLAGS),
+ COMPOSITE(SCLK_RTC32K, "clk_rtc32k", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(38), 14, 2, MFLAGS, 0, 14, DFLAGS,
+ RK3328_CLKGATE_CON(0), 11, GFLAGS),
+ /* PD_MISC */
+ MUX(HDMIPHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+ RK3328_MISC_CON, 13, 1, MFLAGS),
+ MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
+ RK3328_MISC_CON, 15, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 2
+ */
+
+ /* PD_CORE */
+ GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 0, GFLAGS),
+ GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 2, GFLAGS),
+ GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 1, GFLAGS),
+ GATE(0, "npll_core", "npll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 12, GFLAGS),
+ COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(1), 0, 4,
+ DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK3328_CLKGATE_CON(7), 0, GFLAGS),
+ COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(1), 4, 3,
+ DFLAGS | CLK_DIVIDER_READ_ONLY,
+ RK3328_CLKGATE_CON(7), 1, GFLAGS),
+ GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(13), 0, GFLAGS),
+ GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(13), 1, GFLAGS),
+
+ GATE(0, "clk_jtag", "jtag_clkin", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(7), 2, GFLAGS),
+
+ /* PD_GPU */
+ COMPOSITE(0, "aclk_gpu_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(44), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 6, GFLAGS),
+ GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(14), 0, GFLAGS),
+ GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(14), 1, GFLAGS),
+
+ /* PD_DDR */
+ COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3,
+ DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+ RK3328_CLKGATE_CON(0), 4, GFLAGS),
+ GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 6, GFLAGS),
+ GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 5, GFLAGS),
+ GATE(0, "aclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 4, GFLAGS),
+ GATE(0, "clk_ddrmon", "xin24m", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(0), 6, GFLAGS),
+
+ COMPOSITE(PCLK_DDR, "pclk_ddr", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(4), 13, 2, MFLAGS, 8, 3, DFLAGS,
+ RK3328_CLKGATE_CON(7), 4, GFLAGS),
+ GATE(0, "pclk_ddrupctl", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 1, GFLAGS),
+ GATE(0, "pclk_ddr_msch", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 2, GFLAGS),
+ GATE(0, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 3, GFLAGS),
+ GATE(0, "pclk_ddrstdby", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 7, GFLAGS),
+ GATE(0, "pclk_ddr_grf", "pclk_ddr", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(18), 9, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 3
+ */
+ /* PD_BUS */
+ COMPOSITE(ACLK_BUS_PRE, "aclk_bus_pre", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(8), 0, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_BUS_PRE, "hclk_bus_pre", "aclk_bus_pre", 0,
+ RK3328_CLKSEL_CON(1), 8, 2, DFLAGS,
+ RK3328_CLKGATE_CON(8), 1, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_BUS_PRE, "pclk_bus_pre", "aclk_bus_pre", 0,
+ RK3328_CLKSEL_CON(1), 12, 3, DFLAGS,
+ RK3328_CLKGATE_CON(8), 2, GFLAGS),
+ GATE(0, "pclk_bus", "pclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(8), 3, GFLAGS),
+ GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(8), 4, GFLAGS),
+
+ COMPOSITE(SCLK_TSP, "clk_tsp", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(21), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 5, GFLAGS),
+ GATE(0, "clk_hsadc_tsp", "ext_gpio3a2", 0,
+ RK3328_CLKGATE_CON(17), 13, GFLAGS),
+
+ /* PD_I2S */
+ COMPOSITE(0, "clk_i2s0_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 1, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(7), 0,
+ RK3328_CLKGATE_CON(1), 2, GFLAGS,
+ &rk3328_i2s0_fracmux),
+ GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(1), 3, GFLAGS),
+
+ COMPOSITE(0, "clk_i2s1_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(8), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 4, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(9), 0,
+ RK3328_CLKGATE_CON(1), 5, GFLAGS,
+ &rk3328_i2s1_fracmux),
+ GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(0), 6, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0,
+ RK3328_CLKSEL_CON(8), 12, 1, MFLAGS,
+ RK3328_CLKGATE_CON(1), 7, GFLAGS),
+
+ COMPOSITE(0, "clk_i2s2_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 8, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(11), 0,
+ RK3328_CLKGATE_CON(1), 9, GFLAGS,
+ &rk3328_i2s2_fracmux),
+ GATE(SCLK_I2S2, "clk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(1), 10, GFLAGS),
+ COMPOSITE_NODIV(SCLK_I2S2_OUT, "i2s2_out", mux_i2s2out_p, 0,
+ RK3328_CLKSEL_CON(10), 12, 1, MFLAGS,
+ RK3328_CLKGATE_CON(1), 11, GFLAGS),
+
+ COMPOSITE(0, "clk_spdif_div", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(12), 15, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 12, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(13), 0,
+ RK3328_CLKGATE_CON(1), 13, GFLAGS,
+ &rk3328_spdif_fracmux),
+
+ /* PD_UART */
+ COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(1), 14, GFLAGS),
+ COMPOSITE(0, "clk_uart1_div", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(16), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 0, GFLAGS),
+ COMPOSITE(0, "clk_uart2_div", mux_2plls_u480m_p,
+ 0, RK3328_CLKSEL_CON(18), 12, 2, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 2, GFLAGS),
+ COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(15), 0,
+ RK3328_CLKGATE_CON(1), 15, GFLAGS,
+ &rk3328_uart0_fracmux),
+ COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(17), 0,
+ RK3328_CLKGATE_CON(2), 1, GFLAGS,
+ &rk3328_uart1_fracmux),
+ COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div",
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(19), 0,
+ RK3328_CLKGATE_CON(2), 3, GFLAGS,
+ &rk3328_uart2_fracmux),
+
+ /*
+ * Clock-Architecture Diagram 4
+ */
+ COMPOSITE(SCLK_I2C0, "clk_i2c0", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(34), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 9, GFLAGS),
+ COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(34), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 10, GFLAGS),
+ COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(35), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 11, GFLAGS),
+ COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(35), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 12, GFLAGS),
+ COMPOSITE(SCLK_CRYPTO, "clk_crypto", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 4, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "clk_24m", 0,
+ RK3328_CLKSEL_CON(22), 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(2), 6, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "clk_24m", 0,
+ RK3328_CLKSEL_CON(23), 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(2), 14, GFLAGS),
+ COMPOSITE(SCLK_SPI, "clk_spi", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(24), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 7, GFLAGS),
+ COMPOSITE(SCLK_PWM, "clk_pwm", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 7, DFLAGS,
+ RK3328_CLKGATE_CON(2), 8, GFLAGS),
+ COMPOSITE(SCLK_OTP, "clk_otp", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3328_CLKGATE_CON(3), 8, GFLAGS),
+ COMPOSITE(SCLK_EFUSE, "clk_efuse", mux_2plls_xin24m_p, 0,
+ RK3328_CLKSEL_CON(5), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 13, GFLAGS),
+ COMPOSITE(SCLK_PDM, "clk_pdm", mux_cpll_gpll_apll_p,
+ CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(2), 15, GFLAGS),
+
+ GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 5, GFLAGS),
+ GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 6, GFLAGS),
+ GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 7, GFLAGS),
+ GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 8, GFLAGS),
+ GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 9, GFLAGS),
+ GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
+ RK3328_CLKGATE_CON(8), 10, GFLAGS),
+
+ COMPOSITE(SCLK_WIFI, "clk_wifi", mux_2plls_u480m_p, 0,
+ RK3328_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 6, DFLAGS,
+ RK3328_CLKGATE_CON(0), 10, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 5
+ */
+ /* PD_VIDEO */
+ COMPOSITE(ACLK_RKVDEC_PRE, "aclk_rkvdec_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 0, GFLAGS),
+ FACTOR_GATE(HCLK_RKVDEC_PRE, "hclk_rkvdec_pre", "aclk_rkvdec_pre",
+ 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 0, GFLAGS),
+ GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(24), 0, GFLAGS),
+ GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(24), 1, GFLAGS),
+ GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(24), 2, GFLAGS),
+ GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(24), 3, GFLAGS),
+
+ COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(48), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 1, GFLAGS),
+
+ COMPOSITE(SCLK_VDEC_CORE, "sclk_vdec_core", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(49), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 2, GFLAGS),
+
+ COMPOSITE(ACLK_VPU_PRE, "aclk_vpu_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(50), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 5, GFLAGS),
+ FACTOR_GATE(HCLK_VPU_PRE, "hclk_vpu_pre", "aclk_vpu_pre", 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 8, GFLAGS),
+ GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(23), 0, GFLAGS),
+ GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(23), 1, GFLAGS),
+ GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(23), 2, GFLAGS),
+ GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(23), 3, GFLAGS),
+
+ COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 3, GFLAGS),
+ FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4,
+ RK3328_CLKGATE_CON(11), 4, GFLAGS),
+ GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(PCLK_H265, "pclk_h265", "hclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_H264, "aclk_h264", "aclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+ GATE(HCLK_H264, "hclk_h264", "hclk_rkvenc", 0,
+ RK3328_CLKGATE_CON(25), 1, GFLAGS),
+ GATE(ACLK_AXISRAM, "aclk_axisram", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(25), 0, GFLAGS),
+
+ COMPOSITE(SCLK_VENC_CORE, "sclk_venc_core", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(51), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 4, GFLAGS),
+
+ COMPOSITE(SCLK_VENC_DSP, "sclk_venc_dsp", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(52), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(6), 7, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 6
+ */
+ /* PD_VIO */
+ COMPOSITE(ACLK_VIO_PRE, "aclk_vio_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 2, GFLAGS),
+ DIV(HCLK_VIO_PRE, "hclk_vio_pre", "aclk_vio_pre", 0,
+ RK3328_CLKSEL_CON(37), 8, 5, DFLAGS),
+
+ COMPOSITE(ACLK_RGA_PRE, "aclk_rga_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 0, GFLAGS),
+ COMPOSITE(SCLK_RGA, "clk_rga", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 1, GFLAGS),
+ COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0,
+ RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(5), 5, GFLAGS),
+ GATE(0, "clk_hdmi_sfc", "xin24m", 0,
+ RK3328_CLKGATE_CON(5), 4, GFLAGS),
+
+ COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(42), 7, 1, MFLAGS,
+ RK3328_CLKGATE_CON(5), 3, GFLAGS),
+ COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cif_out", mux_sclk_cif_p,
+ CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(42), 5, 1, MFLAGS, 0, 5, DFLAGS),
+
+ COMPOSITE(DCLK_LCDC_SRC, "dclk_lcdc_src", mux_gpll_cpll_p, 0,
+ RK3328_CLKSEL_CON(40), 0, 1, MFLAGS, 8, 8, DFLAGS,
+ RK3328_CLKGATE_CON(5), 6, GFLAGS),
+ DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0,
+ RK3328_CLKSEL_CON(40), 3, 3, DFLAGS),
+ MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0,
+ RK3328_CLKSEL_CON(40), 1, 1, MFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 7
+ */
+ /* PD_PERI */
+ GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 0, GFLAGS),
+ GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 1, GFLAGS),
+ GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(4), 2, GFLAGS),
+ COMPOSITE_NOGATE(ACLK_PERI_PRE, "aclk_peri_pre", mux_aclk_peri_pre_p, 0,
+ RK3328_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS),
+ COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(29), 0, 2, DFLAGS,
+ RK3328_CLKGATE_CON(10), 2, GFLAGS),
+ COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED,
+ RK3328_CLKSEL_CON(29), 4, 3, DFLAGS,
+ RK3328_CLKGATE_CON(10), 1, GFLAGS),
+ GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre",
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
+ RK3328_CLKGATE_CON(10), 0, GFLAGS),
+
+ COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(30), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 3, GFLAGS),
+
+ COMPOSITE(SCLK_SDIO, "clk_sdio", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(31), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 4, GFLAGS),
+
+ COMPOSITE(SCLK_EMMC, "clk_emmc", mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(32), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 5, GFLAGS),
+
+ COMPOSITE(SCLK_SDMMC_EXT, "clk_sdmmc_ext",
+ mux_2plls_24m_u480m_p, 0,
+ RK3328_CLKSEL_CON(43), 8, 2, MFLAGS, 0, 8, DFLAGS,
+ RK3328_CLKGATE_CON(4), 10, GFLAGS),
+
+ COMPOSITE(SCLK_REF_USB3OTG_SRC, "clk_ref_usb3otg_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS,
+ RK3328_CLKGATE_CON(4), 9, GFLAGS),
+
+ MUX(SCLK_REF_USB3OTG, "clk_ref_usb3otg",
+ mux_ref_usb3otg_src_p, CLK_SET_RATE_PARENT,
+ RK3328_CLKSEL_CON(45), 8, 1, MFLAGS),
+
+ GATE(SCLK_USB3OTG_REF, "clk_usb3otg_ref", "xin24m", 0,
+ RK3328_CLKGATE_CON(4), 7, GFLAGS),
+
+ COMPOSITE(SCLK_USB3OTG_SUSPEND, "clk_usb3otg_suspend",
+ mux_xin24m_32k_p, 0,
+ RK3328_CLKSEL_CON(33), 15, 1, MFLAGS, 0, 10, DFLAGS,
+ RK3328_CLKGATE_CON(4), 8, GFLAGS),
+
+ /*
+ * Clock-Architecture Diagram 8
+ */
+ /* PD_GMAC */
+
+ COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0,
+ RK3328_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 2, GFLAGS),
+ COMPOSITE_NOMUX(PCLK_GMAC, "pclk_gmac", "aclk_gmac", 0,
+ RK3328_CLKSEL_CON(25), 8, 3, DFLAGS,
+ RK3328_CLKGATE_CON(9), 0, GFLAGS),
+
+ COMPOSITE(SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 1, GFLAGS),
+ GATE(SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 7, GFLAGS),
+ GATE(SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 4, GFLAGS),
+ GATE(SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 5, GFLAGS),
+ GATE(SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0,
+ RK3328_CLKGATE_CON(9), 6, GFLAGS),
+ COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 5, GFLAGS),
+
+ COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
+ RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
+ RK3328_CLKGATE_CON(3), 0, GFLAGS),
+ GATE(SCLK_MAC2PHY_REF, "clk_mac2phy_ref", "clk_mac2phy", 0,
+ RK3328_CLKGATE_CON(9), 3, GFLAGS),
+ GATE(SCLK_MAC2PHY_RXTX, "clk_mac2phy_rxtx", "clk_mac2phy", 0,
+ RK3328_CLKGATE_CON(9), 1, GFLAGS),
+ COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0,
+ RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
+ RK3328_CLKGATE_CON(9), 2, GFLAGS),
+
+ FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
+
+ /*
+ * Clock-Architecture Diagram 9
+ */
+
+ /* PD_VOP */
+ GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
+ RK3328_CLKGATE_CON(21), 10, GFLAGS),
+ GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(22), 3, GFLAGS),
+ GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0,
+ RK3328_CLKGATE_CON(21), 2, GFLAGS),
+ GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 4, GFLAGS),
+
+ GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 6, GFLAGS),
+ GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 8, GFLAGS),
+ GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 15, GFLAGS),
+ GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(22), 2, GFLAGS),
+
+ GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 3, GFLAGS),
+ GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 5, GFLAGS),
+ GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 7, GFLAGS),
+ GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 9, GFLAGS),
+ GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(21), 11, GFLAGS),
+ GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 12, GFLAGS),
+ GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 13, GFLAGS),
+ GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(21), 14, GFLAGS),
+ GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 0, GFLAGS),
+ GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 1, GFLAGS),
+ GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 4, GFLAGS),
+ GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0,
+ RK3328_CLKGATE_CON(22), 5, GFLAGS),
+
+ /* PD_PERI */
+ GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 11, GFLAGS),
+ GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 4, GFLAGS),
+
+ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 0, GFLAGS),
+ GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 1, GFLAGS),
+ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 2, GFLAGS),
+ GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 15, GFLAGS),
+ GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 6, GFLAGS),
+ GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 7, GFLAGS),
+ GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 8, GFLAGS),
+ GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0,
+ RK3328_CLKGATE_CON(19), 9, GFLAGS),
+ GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 12, GFLAGS),
+ GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(19), 13, GFLAGS),
+
+ /* PD_GMAC */
+ GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 0, GFLAGS),
+ GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 2, GFLAGS),
+ GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(26), 4, GFLAGS),
+ GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 1, GFLAGS),
+ GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0,
+ RK3328_CLKGATE_CON(26), 3, GFLAGS),
+ GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(26), 5, GFLAGS),
+
+ /* PD_BUS */
+ GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 12, GFLAGS),
+ GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 11, GFLAGS),
+ GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(17), 12, GFLAGS),
+ GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 0, GFLAGS),
+ GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 1, GFLAGS),
+
+ GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 2, GFLAGS),
+ GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 3, GFLAGS),
+ GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 4, GFLAGS),
+ GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 5, GFLAGS),
+ GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 6, GFLAGS),
+ GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(17), 11, GFLAGS),
+ GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 7, GFLAGS),
+ GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(15), 8, GFLAGS),
+ GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 13, GFLAGS),
+ GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0,
+ RK3328_CLKGATE_CON(28), 0, GFLAGS),
+
+ GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 14, GFLAGS),
+ GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 9, GFLAGS),
+ GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(28), 4, GFLAGS),
+ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(15), 10, GFLAGS),
+ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 0, GFLAGS),
+ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 1, GFLAGS),
+ GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 2, GFLAGS),
+ GATE(PCLK_TIMER, "pclk_timer0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 3, GFLAGS),
+ GATE(0, "pclk_stimer", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 4, GFLAGS),
+ GATE(PCLK_SPI, "pclk_spi", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 5, GFLAGS),
+ GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 6, GFLAGS),
+ GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 7, GFLAGS),
+ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 8, GFLAGS),
+ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 9, GFLAGS),
+ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 10, GFLAGS),
+ GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 11, GFLAGS),
+ GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 12, GFLAGS),
+ GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 13, GFLAGS),
+ GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 14, GFLAGS),
+ GATE(PCLK_DCF, "pclk_dcf", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(16), 15, GFLAGS),
+ GATE(PCLK_GRF, "pclk_grf", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 0, GFLAGS),
+ GATE(0, "pclk_cru", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 4, GFLAGS),
+ GATE(0, "pclk_sgrf", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 6, GFLAGS),
+ GATE(0, "pclk_sim", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 10, GFLAGS),
+ GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0,
+ RK3328_CLKGATE_CON(17), 15, GFLAGS),
+ GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(28), 3, GFLAGS),
+
+ GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0,
+ RK3328_CLKGATE_CON(28), 1, GFLAGS),
+ GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0,
+ RK3328_CLKGATE_CON(28), 2, GFLAGS),
+ GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 2, GFLAGS),
+ GATE(PCLK_USB2_GRF, "pclk_usb2_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 14, GFLAGS),
+ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 13, GFLAGS),
+ GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 5, GFLAGS),
+ GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 7, GFLAGS),
+ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(17), 8, GFLAGS),
+ GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED,
+ RK3328_CLKGATE_CON(15), 15, GFLAGS),
+
+ /* PD_MMC */
+ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc",
+ RK3328_SDMMC_CON0, 1),
+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc",
+ RK3328_SDMMC_CON1, 1),
+
+ MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio",
+ RK3328_SDIO_CON0, 1),
+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio",
+ RK3328_SDIO_CON1, 1),
+
+ MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc",
+ RK3328_EMMC_CON0, 1),
+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc",
+ RK3328_EMMC_CON1, 1),
+
+ MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "sclk_sdmmc_ext",
+ RK3328_SDMMC_EXT_CON0, 1),
+ MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "sclk_sdmmc_ext",
+ RK3328_SDMMC_EXT_CON1, 1),
+};
+
+static struct rockchip_clk_branch rk3328_clk_grf_branches[] __initdata = {
+ /*
+ * GRF CRU Clock-Architecture
+ */
+ MUX(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, 0,
+ RK3328_GRF_MAC_CON1, 10, 1, MFLAGS),
+ MUX(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, 0,
+ RK3328_GRF_MAC_CON2, 10, 1, MFLAGS),
+};
+
+static const char *const rk3328_critical_clocks[] __initconst = {
+ "aclk_bus",
+ "pclk_bus",
+ "hclk_bus",
+ "aclk_peri",
+ "hclk_peri",
+ "pclk_peri",
+ "pclk_dbg",
+ "aclk_core_niu",
+ "aclk_gic400",
+ "aclk_intmem",
+ "hclk_rom",
+ "pclk_grf",
+ "pclk_cru",
+ "pclk_sgrf",
+ "pclk_timer0",
+ "clk_timer0",
+ "pclk_ddr_msch",
+ "pclk_ddr_mon",
+ "pclk_ddr_grf",
+ "clk_ddrupctl",
+ "clk_ddrmsch",
+ "hclk_ahb1tom",
+ "clk_jtag",
+ "pclk_ddrphy",
+ "pclk_pmu",
+ "hclk_otg_pmu",
+ "aclk_rga_niu",
+ "pclk_vio_h2p",
+ "hclk_vio_h2p",
+};
+
+static void __iomem *rk3328_cru_base;
+
+void rk3328_dump_cru(void)
+{
+ if (rk3328_cru_base) {
+ pr_warn("CRU:\n");
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
+ 32, 4, rk3328_cru_base,
+ 0x400, false);
+ }
+}
+EXPORT_SYMBOL_GPL(rk3328_dump_cru);
+
+static int rk3328_clk_panic(struct notifier_block *this,
+ unsigned long ev, void *ptr)
+{
+ rk3328_dump_cru();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rk3328_clk_panic_block = {
+ .notifier_call = rk3328_clk_panic,
+};
+
+static void __init rk3328_clk_init(struct device_node *np)
+{
+ struct rockchip_clk_provider *ctx;
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru region\n", __func__);
+ return;
+ }
+
+ rk3328_cru_base = reg_base;
+
+ ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (IS_ERR(ctx)) {
+ pr_err("%s: rockchip clk init failed\n", __func__);
+ iounmap(reg_base);
+ return;
+ }
+
+ rockchip_clk_register_plls(ctx, rk3328_pll_clks,
+ ARRAY_SIZE(rk3328_pll_clks),
+ RK3328_GRF_SOC_STATUS0);
+ rockchip_clk_register_branches(ctx, rk3328_clk_branches,
+ ARRAY_SIZE(rk3328_clk_branches));
+ rockchip_clk_protect_critical(rk3328_critical_clocks,
+ ARRAY_SIZE(rk3328_critical_clocks));
+
+ rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
+ mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+ &rk3328_cpuclk_data, rk3328_cpuclk_rates,
+ ARRAY_SIZE(rk3328_cpuclk_rates));
+
+ rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0),
+ ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+ rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL);
+
+ rockchip_clk_of_add_provider(np, ctx);
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &rk3328_clk_panic_block);
+}
+
+CLK_OF_DECLARE(rk3328_cru, "rockchip,rk3328-cru", rk3328_clk_init);
+
+static void __init rk3328_grf_clk_init(struct device_node *np)
+{
+ struct rockchip_clk_provider *ctx;
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: could not map cru pmu region\n", __func__);
+ return;
+ }
+
+ ctx = rockchip_clk_init(np, reg_base, CLKGRF_NR_CLKS);
+ if (IS_ERR(ctx)) {
+ pr_err("%s: rockchip pmu clk init failed\n", __func__);
+ return;
+ }
+
+ rockchip_clk_register_branches(ctx, rk3328_clk_grf_branches,
+ ARRAY_SIZE(rk3328_clk_grf_branches));
+
+ rockchip_clk_of_add_provider(np, ctx);
+}
+
+CLK_OF_DECLARE(rk3328_cru_grf, "rockchip,rk3328-grf", rk3328_grf_clk_init);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 06acb7e0911f..7225997f8d52 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -91,6 +91,28 @@
#define RK3288_EMMC_CON0 0x218
#define RK3288_EMMC_CON1 0x21c
+#define RK3328_PLL_CON(x) RK2928_PLL_CON(x)
+#define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
+#define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
+#define RK3328_GRFCLKSEL_CON(x) ((x) * 0x4 + 0x100)
+#define RK3328_GLB_SRST_FST 0x9c
+#define RK3328_GLB_SRST_SND 0x98
+#define RK3328_SOFTRST_CON(x) ((x) * 0x4 + 0x300)
+#define RK3328_MODE_CON 0x80
+#define RK3328_MISC_CON 0x84
+#define RK3328_DIV_ACLKM_MASK 0x7
+#define RK3328_DIV_ACLKM_SHIFT 4
+#define RK3328_DIV_PCLK_DBG_MASK 0xf
+#define RK3328_DIV_PCLK_DBG_SHIFT 0
+#define RK3328_SDMMC_CON0 0x380
+#define RK3328_SDMMC_CON1 0x384
+#define RK3328_SDIO_CON0 0x388
+#define RK3328_SDIO_CON1 0x38c
+#define RK3328_EMMC_CON0 0x390
+#define RK3328_EMMC_CON1 0x394
+#define RK3328_SDMMC_EXT_CON0 0x398
+#define RK3328_SDMMC_EXT_CON1 0x39C
+
#define RK3368_PLL_CON(x) RK2928_PLL_CON(x)
#define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
#define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
--
1.9.1
^ permalink raw reply related
* [PATCH v4 3/4] clk: rockchip: add new pll-type for rk3328
From: Elaine Zhang @ 2016-12-27 6:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482820373-10186-1-git-send-email-zhangqing@rock-chips.com>
The rk3328's pll and clock are similar with rk3036's,
it different with pll_mode_mask, the rk3328 soc
pll mode only one bit(rk3036 soc have two bits)
so these should be independent and separate from
the series of rk3328s.
Changes in v4:
adjust the pacth 3 and 4 order.
move pll_rk3328 to patch 3.
Changes in v3:
fix up the pll type pll_rk3328 description and use
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
drivers/clk/rockchip/clk-pll.c | 16 +++++++++++++---
drivers/clk/rockchip/clk.h | 1 +
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 6ed605776abd..eec51893a7e6 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -29,6 +29,7 @@
#define PLL_MODE_SLOW 0x0
#define PLL_MODE_NORM 0x1
#define PLL_MODE_DEEP 0x2
+#define PLL_RK3328_MODE_MASK 0x1
struct rockchip_clk_pll {
struct clk_hw hw;
@@ -848,7 +849,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
struct clk *pll_clk, *mux_clk;
char pll_name[20];
- if (num_parents != 2) {
+ if ((pll_type != pll_rk3328 && num_parents != 2) ||
+ (pll_type == pll_rk3328 && num_parents != 1)) {
pr_err("%s: needs two parent clocks\n", __func__);
return ERR_PTR(-EINVAL);
}
@@ -865,13 +867,17 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
pll_mux = &pll->pll_mux;
pll_mux->reg = ctx->reg_base + mode_offset;
pll_mux->shift = mode_shift;
- pll_mux->mask = PLL_MODE_MASK;
+ if (pll_type == pll_rk3328)
+ pll_mux->mask = PLL_RK3328_MODE_MASK;
+ else
+ pll_mux->mask = PLL_MODE_MASK;
pll_mux->flags = 0;
pll_mux->lock = &ctx->lock;
pll_mux->hw.init = &init;
if (pll_type == pll_rk3036 ||
pll_type == pll_rk3066 ||
+ pll_type == pll_rk3328 ||
pll_type == pll_rk3399)
pll_mux->flags |= CLK_MUX_HIWORD_MASK;
@@ -884,7 +890,10 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
init.flags = CLK_SET_RATE_PARENT;
init.ops = pll->pll_mux_ops;
init.parent_names = pll_parents;
- init.num_parents = ARRAY_SIZE(pll_parents);
+ if (pll_type == pll_rk3328)
+ init.num_parents = 2;
+ else
+ init.num_parents = ARRAY_SIZE(pll_parents);
mux_clk = clk_register(NULL, &pll_mux->hw);
if (IS_ERR(mux_clk))
@@ -918,6 +927,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
switch (pll_type) {
case pll_rk3036:
+ case pll_rk3328:
if (!pll->rate_table || IS_ERR(ctx->grf))
init.ops = &rockchip_rk3036_pll_clk_norate_ops;
else
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index d67eecc4ade9..06acb7e0911f 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -130,6 +130,7 @@
enum rockchip_pll_type {
pll_rk3036,
pll_rk3066,
+ pll_rk3328,
pll_rk3399,
};
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox