* [PATCH 14/14] arm64: dts: sparx5: Add i2c devices, i2c muxes
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This patch adds i2c devices and muxes to the Sparx5 reference boards.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
arch/arm64/boot/dts/microchip/sparx5.dtsi | 36 +++
.../boot/dts/microchip/sparx5_pcb125.dts | 4 +
.../dts/microchip/sparx5_pcb134_board.dtsi | 237 ++++++++++++++++++
.../dts/microchip/sparx5_pcb135_board.dtsi | 77 ++++++
.../boot/dts/microchip/sparx5_pcb_common.dtsi | 4 +
5 files changed, 358 insertions(+)
diff --git a/arch/arm64/boot/dts/microchip/sparx5.dtsi b/arch/arm64/boot/dts/microchip/sparx5.dtsi
index ca4055f04ac26..b5cb3d8dc876b 100644
--- a/arch/arm64/boot/dts/microchip/sparx5.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5.dtsi
@@ -160,7 +160,43 @@ uart2_pins: uart2-pins {
function = "uart2";
};
+ i2c_pins: i2c-pins {
+ pins = "GPIO_14", "GPIO_15";
+ function = "twi";
+ };
+
+ i2c2_pins: i2c2-pins {
+ pins = "GPIO_28", "GPIO_29";
+ function = "twi2";
+ };
+ };
+
+ i2c0: i2c@600101000 {
+ compatible = "snps,designware-i2c";
+ status = "disabled";
+ pinctrl-0 = <&i2c_pins>;
+ pinctrl-names = "default";
+ reg = <0x6 0x00101000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ i2c-sda-hold-time-ns = <300>;
+ clock-frequency = <100000>;
+ clocks = <&ahb_clk>;
};
+ i2c1: i2c@600103000 {
+ compatible = "snps,designware-i2c";
+ status = "disabled";
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+ reg = <0x6 0x00103000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ i2c-sda-hold-time-ns = <300>;
+ clock-frequency = <100000>;
+ clocks = <&ahb_clk>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
index d7f985f7ee020..91ee5b6cfc37a 100644
--- a/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
@@ -15,3 +15,7 @@ memory@0 {
reg = <0x00000000 0x00000000 0x10000000>;
};
};
+
+&i2c1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
index 9b2aec400101b..18a535a043686 100644
--- a/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
@@ -7,9 +7,246 @@
#include "sparx5_pcb_common.dtsi"
/{
+ aliases {
+ i2c0 = &i2c0;
+ i2c100 = &i2c100;
+ i2c101 = &i2c101;
+ i2c102 = &i2c102;
+ i2c103 = &i2c103;
+ i2c104 = &i2c104;
+ i2c105 = &i2c105;
+ i2c106 = &i2c106;
+ i2c107 = &i2c107;
+ i2c108 = &i2c108;
+ i2c109 = &i2c109;
+ i2c110 = &i2c110;
+ i2c111 = &i2c111;
+ i2c112 = &i2c112;
+ i2c113 = &i2c113;
+ i2c114 = &i2c114;
+ i2c115 = &i2c115;
+ i2c116 = &i2c116;
+ i2c117 = &i2c117;
+ i2c118 = &i2c118;
+ i2c119 = &i2c119;
+ };
+
gpio-restart {
compatible = "gpio-restart";
gpios = <&gpio 37 GPIO_ACTIVE_LOW>;
priority = <200>;
};
};
+
+&gpio {
+ i2cmux_pins_i: i2cmux-pins-i {
+ pins = "GPIO_16", "GPIO_17", "GPIO_18", "GPIO_19",
+ "GPIO_20", "GPIO_22", "GPIO_36", "GPIO_35",
+ "GPIO_50", "GPIO_51", "GPIO_56", "GPIO_57";
+ function = "twi_scl_m";
+ output-low;
+ };
+ i2cmux_0: i2cmux-0 {
+ pins = "GPIO_16";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_1: i2cmux-1 {
+ pins = "GPIO_17";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_2: i2cmux-2 {
+ pins = "GPIO_18";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_3: i2cmux-3 {
+ pins = "GPIO_19";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_4: i2cmux-4 {
+ pins = "GPIO_20";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_5: i2cmux-5 {
+ pins = "GPIO_22";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_6: i2cmux-6 {
+ pins = "GPIO_36";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_7: i2cmux-7 {
+ pins = "GPIO_35";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_8: i2cmux-8 {
+ pins = "GPIO_50";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_9: i2cmux-9 {
+ pins = "GPIO_51";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_10: i2cmux-10 {
+ pins = "GPIO_56";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_11: i2cmux-11 {
+ pins = "GPIO_57";
+ function = "twi_scl_m";
+ output-high;
+ };
+};
+
+&axi {
+ i2c0_imux: i2c0-imux@0 {
+ compatible = "i2c-mux-pinctrl";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-parent = <&i2c0>;
+ };
+ i2c0_emux: i2c0-emux@0 {
+ compatible = "i2c-mux-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-parent = <&i2c0>;
+ };
+};
+
+&i2c0_imux {
+ pinctrl-names =
+ "i2c100", "i2c101", "i2c102", "i2c103",
+ "i2c104", "i2c105", "i2c106", "i2c107",
+ "i2c108", "i2c109", "i2c110", "i2c111", "idle";
+ pinctrl-0 = <&i2cmux_0>;
+ pinctrl-1 = <&i2cmux_1>;
+ pinctrl-2 = <&i2cmux_2>;
+ pinctrl-3 = <&i2cmux_3>;
+ pinctrl-4 = <&i2cmux_4>;
+ pinctrl-5 = <&i2cmux_5>;
+ pinctrl-6 = <&i2cmux_6>;
+ pinctrl-7 = <&i2cmux_7>;
+ pinctrl-8 = <&i2cmux_8>;
+ pinctrl-9 = <&i2cmux_9>;
+ pinctrl-10 = <&i2cmux_10>;
+ pinctrl-11 = <&i2cmux_11>;
+ pinctrl-12 = <&i2cmux_pins_i>;
+ i2c100: i2c_sfp1 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c101: i2c_sfp2 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c102: i2c_sfp3 {
+ reg = <0x2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c103: i2c_sfp4 {
+ reg = <0x3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c104: i2c_sfp5 {
+ reg = <0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c105: i2c_sfp6 {
+ reg = <0x5>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c106: i2c_sfp7 {
+ reg = <0x6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c107: i2c_sfp8 {
+ reg = <0x7>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c108: i2c_sfp9 {
+ reg = <0x8>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c109: i2c_sfp10 {
+ reg = <0x9>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c110: i2c_sfp11 {
+ reg = <0xa>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c111: i2c_sfp12 {
+ reg = <0xb>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+};
+
+&i2c0_emux {
+ mux-gpios = <&gpio 55 GPIO_ACTIVE_HIGH
+ &gpio 60 GPIO_ACTIVE_HIGH
+ &gpio 61 GPIO_ACTIVE_HIGH
+ &gpio 54 GPIO_ACTIVE_HIGH>;
+ idle-state = <0x8>;
+ i2c112: i2c_sfp13 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c113: i2c_sfp14 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c114: i2c_sfp15 {
+ reg = <0x2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c115: i2c_sfp16 {
+ reg = <0x3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c116: i2c_sfp17 {
+ reg = <0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c117: i2c_sfp18 {
+ reg = <0x5>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c118: i2c_sfp19 {
+ reg = <0x6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c119: i2c_sfp20 {
+ reg = <0x7>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
index 9b2aec400101b..d71f11a10b3d2 100644
--- a/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
@@ -7,9 +7,86 @@
#include "sparx5_pcb_common.dtsi"
/{
+ aliases {
+ i2c0 = &i2c0;
+ i2c152 = &i2c152;
+ i2c153 = &i2c153;
+ i2c154 = &i2c154;
+ i2c155 = &i2c155;
+ };
+
gpio-restart {
compatible = "gpio-restart";
gpios = <&gpio 37 GPIO_ACTIVE_LOW>;
priority = <200>;
};
};
+
+&gpio {
+ i2cmux_pins_i: i2cmux-pins-i {
+ pins = "GPIO_35", "GPIO_36",
+ "GPIO_50", "GPIO_51";
+ function = "twi_scl_m";
+ output-low;
+ };
+ i2cmux_s29: i2cmux-0 {
+ pins = "GPIO_35";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_s30: i2cmux-1 {
+ pins = "GPIO_36";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_s31: i2cmux-2 {
+ pins = "GPIO_50";
+ function = "twi_scl_m";
+ output-high;
+ };
+ i2cmux_s32: i2cmux-3 {
+ pins = "GPIO_51";
+ function = "twi_scl_m";
+ output-high;
+ };
+};
+
+&axi {
+ i2c0_imux: i2c0-imux@0 {
+ compatible = "i2c-mux-pinctrl";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-parent = <&i2c0>;
+ };
+};
+
+&i2c0_imux {
+ pinctrl-names =
+ "i2c152", "i2c153", "i2c154", "i2c155",
+ "idle";
+ pinctrl-0 = <&i2cmux_s29>;
+ pinctrl-1 = <&i2cmux_s30>;
+ pinctrl-2 = <&i2cmux_s31>;
+ pinctrl-3 = <&i2cmux_s32>;
+ pinctrl-4 = <&i2cmux_pins_i>;
+ i2c152: i2c_sfp1 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c153: i2c_sfp2 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c154: i2c_sfp3 {
+ reg = <0x2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ i2c155: i2c_sfp4 {
+ reg = <0x3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
index 1f99d0db1284f..9d1a082de3e29 100644
--- a/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
@@ -13,3 +13,7 @@ &uart0 {
&uart1 {
status = "okay";
};
+
+&i2c0 {
+ status = "okay";
+};
--
2.26.2
^ permalink raw reply related
* [PATCH 13/14] arm64: dts: sparx5: Add Sparx5 SoC DPLL clock
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds a DPLL clock to the Sparx5 SoC. It is used to generate clock
to misc peripherals, specifically the SDHCI/eMMC controller.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
arch/arm64/boot/dts/microchip/sparx5.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/microchip/sparx5.dtsi b/arch/arm64/boot/dts/microchip/sparx5.dtsi
index 45a60993789c8..ca4055f04ac26 100644
--- a/arch/arm64/boot/dts/microchip/sparx5.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5.dtsi
@@ -82,6 +82,11 @@ sys_clk: sys-clk {
#clock-cells = <0>;
clock-frequency = <625000000>;
};
+ clks: clks@61110000c {
+ compatible = "microchip,sparx5-dpll";
+ #clock-cells = <1>;
+ reg = <0x6 0x1110000c 0x24>;
+ };
};
axi: axi@600000000 {
--
2.26.2
^ permalink raw reply related
* [PATCH 12/14] clk: sparx5: Add Sparx5 SoC DPLL clock driver
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds a device driver for the Sparx5 SoC DPLL clock
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
drivers/clk/Makefile | 1 +
drivers/clk/clk-sparx5.c | 269 +++++++++++++++++++++++++++++++++++++++
2 files changed, 270 insertions(+)
create mode 100644 drivers/clk/clk-sparx5.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f4169cc2fd318..9332e32667527 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
+obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
diff --git a/drivers/clk/clk-sparx5.c b/drivers/clk/clk-sparx5.c
new file mode 100644
index 0000000000000..685b3028a7071
--- /dev/null
+++ b/drivers/clk/clk-sparx5.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip Sparx5 SoC Clock driver.
+ *
+ * Copyright (c) 2019 Microchip Inc.
+ *
+ * Author: Lars Povlsen <lars.povlsen@microchip.com>
+ */
+
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/microchip,sparx5.h>
+
+#define PLL_DIV_MASK GENMASK(7, 0)
+#define PLL_PRE_DIV_MASK GENMASK(10, 8)
+#define PLL_PRE_DIV_SHIFT 8
+#define PLL_ROT_DIR BIT(11)
+#define PLL_ROT_SEL_MASK GENMASK(13, 12)
+#define PLL_ROT_SEL_SHIFT 12
+#define PLL_ROT_ENA BIT(14)
+#define PLL_CLK_ENA BIT(15)
+
+#define MAX_SEL 4
+#define MAX_PRE BIT(3)
+
+#define KHZ 1000
+#define MHZ (KHZ*KHZ)
+
+#define BASE_CLOCK (2500UL*MHZ)
+
+static u8 sel_rates[MAX_SEL] = { 0, 2*8, 2*4, 2*2 };
+
+static const char *clk_names[N_CLOCKS] = {
+ "core", "ddr", "cpu2", "arm2",
+ "aux1", "aux2", "aux3", "aux4",
+ "synce",
+};
+
+struct s5_hw_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ int index;
+};
+
+struct s5_clk_data {
+ void __iomem *base;
+ struct s5_hw_clk s5_hw[N_CLOCKS];
+};
+
+struct pll_conf {
+ int freq;
+ u8 div;
+ bool rot_ena;
+ u8 rot_sel;
+ u8 rot_dir;
+ u8 pre_div;
+};
+
+#define to_clk_pll(hw) container_of(hw, struct s5_hw_clk, hw)
+
+unsigned long calc_freq(const struct pll_conf *pdata)
+{
+ unsigned long rate = BASE_CLOCK / pdata->div;
+
+ if (pdata->rot_ena) {
+ unsigned long base = BASE_CLOCK / pdata->div;
+ int sign = pdata->rot_dir ? -1 : 1;
+ int divt = sel_rates[pdata->rot_sel] * (1 + pdata->pre_div);
+ int divb = divt + sign;
+
+ rate = mult_frac(base, divt, divb);
+ rate = roundup(rate, 1000);
+ }
+
+ return rate;
+}
+
+static unsigned long clk_calc_params(unsigned long rate,
+ struct pll_conf *conf)
+{
+ memset(conf, 0, sizeof(*conf));
+
+ conf->div = DIV_ROUND_CLOSEST_ULL(BASE_CLOCK, rate);
+
+ if (BASE_CLOCK % rate) {
+ struct pll_conf best;
+ ulong cur_offset, best_offset = rate;
+ int i, j;
+
+ /* Enable fractional rotation */
+ conf->rot_ena = true;
+
+ if ((BASE_CLOCK / rate) != conf->div) {
+ /* Overshoot, adjust other direction */
+ conf->rot_dir = 1;
+ }
+
+ /* Brute force search over MAX_PRE * (MAX_SEL - 1) = 24 */
+ for (i = 0; i < MAX_PRE; i++) {
+ conf->pre_div = i;
+ for (j = 1; j < MAX_SEL; j++) {
+ conf->rot_sel = j;
+ conf->freq = calc_freq(conf);
+ cur_offset = abs(rate - conf->freq);
+ if (cur_offset == 0)
+ /* Perfect fit */
+ goto done;
+ if (cur_offset < best_offset) {
+ /* Better fit found */
+ best_offset = cur_offset;
+ best = *conf;
+ }
+ }
+ }
+ /* Best match */
+ *conf = best;
+ }
+
+done:
+ return conf->freq;
+}
+
+static int clk_pll_enable(struct clk_hw *hw)
+{
+ struct s5_hw_clk *pll = to_clk_pll(hw);
+ u32 val = readl(pll->reg);
+
+ val |= PLL_CLK_ENA;
+ writel(val, pll->reg);
+ pr_debug("%s: Enable val %04x\n", clk_names[pll->index], val);
+ return 0;
+}
+
+static void clk_pll_disable(struct clk_hw *hw)
+{
+ struct s5_hw_clk *pll = to_clk_pll(hw);
+ u32 val = readl(pll->reg);
+
+ val &= ~PLL_CLK_ENA;
+ writel(val, pll->reg);
+ pr_debug("%s: Disable val %04x\n", clk_names[pll->index], val);
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct s5_hw_clk *pll = to_clk_pll(hw);
+ struct pll_conf conf;
+ unsigned long eff_rate;
+ int ret = 0;
+
+ eff_rate = clk_calc_params(rate, &conf);
+ if (eff_rate == rate) {
+ u32 val;
+
+ val = readl(pll->reg) & PLL_CLK_ENA;
+ val |= PLL_DIV_MASK & conf.div;
+ if (conf.rot_ena) {
+ val |= (PLL_ROT_ENA |
+ (PLL_ROT_SEL_MASK &
+ (conf.rot_sel << PLL_ROT_SEL_SHIFT)) |
+ (PLL_PRE_DIV_MASK &
+ (conf.pre_div << PLL_PRE_DIV_SHIFT)));
+ if (conf.rot_dir)
+ val |= PLL_ROT_DIR;
+ }
+ pr_debug("%s: Rate %ld >= 0x%04x\n",
+ clk_names[pll->index], rate, val);
+ writel(val, pll->reg);
+ } else {
+ pr_err("%s: freq unsupported: %ld paren %ld\n",
+ clk_names[pll->index], rate, parent_rate);
+ ret = -ENOTSUPP;
+ }
+
+ return ret;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ /* Don't care */
+ return 0;
+}
+
+static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct pll_conf conf;
+ unsigned long eff_rate;
+
+ eff_rate = clk_calc_params(rate, &conf);
+ pr_debug("%s: Rate %ld rounded to %ld\n", __func__, rate, eff_rate);
+
+ return eff_rate;
+}
+
+static const struct clk_ops s5_pll_ops = {
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
+ .set_rate = clk_pll_set_rate,
+ .round_rate = clk_pll_round_rate,
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+static struct s5_clk_data *s5_clk_alloc(struct device_node *np)
+{
+ struct s5_clk_data *clk_data;
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (WARN_ON(!clk_data))
+ return NULL;
+
+ clk_data->base = of_iomap(np, 0);
+ if (WARN_ON(!clk_data->base))
+ return NULL;
+
+ return clk_data;
+}
+
+static struct clk_hw *s5_clk_hw_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct s5_clk_data *pll_clk = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx >= N_CLOCKS) {
+ pr_err("%s: invalid index %u\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return &pll_clk->s5_hw[idx].hw;
+}
+
+static void __init s5_pll_init(struct device_node *np)
+{
+ int i, ret;
+ struct s5_clk_data *pll_clk;
+ struct clk_init_data init = { 0 };
+
+ pll_clk = s5_clk_alloc(np);
+ if (!pll_clk)
+ return;
+
+ init.ops = &s5_pll_ops;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+
+ for (i = 0; i < N_CLOCKS; i++) {
+ struct s5_hw_clk *s5_hw = &pll_clk->s5_hw[i];
+
+ init.name = clk_names[i];
+ s5_hw->index = i;
+ s5_hw->reg = pll_clk->base + (i * sizeof(u32));
+ s5_hw->hw.init = &init;
+ ret = of_clk_hw_register(np, &s5_hw->hw);
+ if (ret) {
+ pr_err("failed to register %s clock\n", init.name);
+ return;
+ }
+ }
+
+ of_clk_add_hw_provider(np, s5_clk_hw_get, pll_clk);
+}
+CLK_OF_DECLARE_DRIVER(microchip_s5, "microchip,sparx5-dpll", s5_pll_init);
--
2.26.2
^ permalink raw reply related
* [PATCH 11/14] dt-bindings: clock: sparx5: Add bindings include file
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij, Rob Herring
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
The Sparx5 support 9 different clock outputs. This include file has
defines for each supported clock ordinal.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
include/dt-bindings/clock/microchip,sparx5.h | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 include/dt-bindings/clock/microchip,sparx5.h
diff --git a/include/dt-bindings/clock/microchip,sparx5.h b/include/dt-bindings/clock/microchip,sparx5.h
new file mode 100644
index 0000000000000..4b04dabacec2c
--- /dev/null
+++ b/include/dt-bindings/clock/microchip,sparx5.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019 Microchip Inc.
+ *
+ * Author: Lars Povlsen <lars.povlsen@microchip.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_SPARX5_H
+#define _DT_BINDINGS_CLK_SPARX5_H
+
+#define CLK_ID_CORE 0
+#define CLK_ID_DDR 1
+#define CLK_ID_CPU2 2
+#define CLK_ID_ARM2 3
+#define CLK_ID_AUX1 4
+#define CLK_ID_AUX2 5
+#define CLK_ID_AUX3 6
+#define CLK_ID_AUX4 7
+#define CLK_ID_SYNCE 8
+
+#define N_CLOCKS 9
+
+#endif
--
2.26.2
^ permalink raw reply related
* [PATCH 08/14] arm64: dts: sparx5: Add pinctrl support
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This add pinctrl support to the Microchip Sparx5 SoC.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
arch/arm64/boot/dts/microchip/sparx5.dtsi | 26 +++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/arm64/boot/dts/microchip/sparx5.dtsi b/arch/arm64/boot/dts/microchip/sparx5.dtsi
index 3136b4369f507..45a60993789c8 100644
--- a/arch/arm64/boot/dts/microchip/sparx5.dtsi
+++ b/arch/arm64/boot/dts/microchip/sparx5.dtsi
@@ -102,6 +102,8 @@ gic: interrupt-controller@600300000 {
};
uart0: serial@600100000 {
+ pinctrl-0 = <&uart_pins>;
+ pinctrl-names = "default";
compatible = "ns16550a";
reg = <0x6 0x00100000 0x20>;
clocks = <&ahb_clk>;
@@ -113,6 +115,8 @@ uart0: serial@600100000 {
};
uart1: serial@600102000 {
+ pinctrl-0 = <&uart2_pins>;
+ pinctrl-names = "default";
compatible = "ns16550a";
reg = <0x6 0x00102000 0x20>;
clocks = <&ahb_clk>;
@@ -131,5 +135,27 @@ timer1: timer@600105000 {
interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
};
+ gpio: pinctrl@6110101e0 {
+ compatible = "microchip,sparx5-pinctrl";
+ reg = <0x6 0x110101e0 0x90>, <0x6 0x10508010 0x100>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&gpio 0 0 64>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <2>;
+
+ uart_pins: uart-pins {
+ pins = "GPIO_10", "GPIO_11";
+ function = "uart";
+ };
+
+ uart2_pins: uart2-pins {
+ pins = "GPIO_26", "GPIO_27";
+ function = "uart2";
+ };
+
+ };
+
};
};
--
2.26.2
^ permalink raw reply related
* [PATCH 07/14] dt-bindings: pinctrl: ocelot: Add Sparx5 SoC support
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij, Rob Herring
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds documentation for the "compatible" value designated for Sparx5
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
.../devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt
index 32a8a8fa7805d..00912449237bd 100644
--- a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt
@@ -2,8 +2,8 @@ Microsemi Ocelot pin controller Device Tree Bindings
----------------------------------------------------
Required properties:
- - compatible : Should be "mscc,ocelot-pinctrl" or
- "mscc,jaguar2-pinctrl"
+ - compatible : Should be "mscc,ocelot-pinctrl",
+ "mscc,jaguar2-pinctrl" or "microchip,sparx5-pinctrl"
- reg : Address and length of the register set for the device
- gpio-controller : Indicates this device is a GPIO controller
- #gpio-cells : Must be 2.
--
2.26.2
^ permalink raw reply related
* [PATCH 06/14] arm64: dts: sparx5: Add basic cpu support
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds the basic DT structure for the Microchip Sparx5 SoC, and the
reference boards, pcb125, pcb134 and pcb135. The two latter have a
NAND vs a eMMC centric variant (as a mount option),
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
MAINTAINERS | 1 +
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/microchip/Makefile | 4 +
arch/arm64/boot/dts/microchip/sparx5.dtsi | 135 ++++++++++++++++++
.../boot/dts/microchip/sparx5_pcb125.dts | 17 +++
.../boot/dts/microchip/sparx5_pcb134.dts | 17 +++
.../dts/microchip/sparx5_pcb134_board.dtsi | 15 ++
.../boot/dts/microchip/sparx5_pcb134_emmc.dts | 17 +++
.../boot/dts/microchip/sparx5_pcb135.dts | 17 +++
.../dts/microchip/sparx5_pcb135_board.dtsi | 15 ++
.../boot/dts/microchip/sparx5_pcb135_emmc.dts | 17 +++
.../boot/dts/microchip/sparx5_pcb_common.dtsi | 15 ++
12 files changed, 271 insertions(+)
create mode 100644 arch/arm64/boot/dts/microchip/Makefile
create mode 100644 arch/arm64/boot/dts/microchip/sparx5.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134_emmc.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135_emmc.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
diff --git a/MAINTAINERS b/MAINTAINERS
index 1b5a18d3dbb9f..5aa28d6e39d4f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2084,6 +2084,7 @@ M: Lars Povlsen <lars.povlsen@microchip.com>
M: Steen Hegelund <Steen.Hegelund@microchip.com>
M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+F: arch/arm64/boot/dts/microchip/
N: sparx5
S: Supported
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index f19b762c008d8..9680a7f20c307 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -17,6 +17,7 @@ subdir-y += intel
subdir-y += lg
subdir-y += marvell
subdir-y += mediatek
+subdir-y += microchip
subdir-y += nvidia
subdir-y += qcom
subdir-y += realtek
diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
new file mode 100644
index 0000000000000..c6e0313eea0f9
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
+dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
+dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
diff --git a/arch/arm64/boot/dts/microchip/sparx5.dtsi b/arch/arm64/boot/dts/microchip/sparx5.dtsi
new file mode 100644
index 0000000000000..3136b4369f507
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5.dtsi
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "microchip,sparx5";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ };
+ };
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x0000fff8>;
+ next-level-cache = <&L2_0>;
+ };
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x1>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x0000fff8>;
+ next-level-cache = <&L2_0>;
+ };
+ L2_0: l2-cache0 {
+ compatible = "cache";
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts =
+ <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ clocks: clocks {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ ahb_clk: ahb-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <250000000>;
+ };
+ sys_clk: sys-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <625000000>;
+ };
+ };
+
+ axi: axi@600000000 {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+
+ gic: interrupt-controller@600300000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-controller;
+ reg = <0x6 0x00300000 0x20000>, /* GICD */
+ <0x6 0x00340000 0x1000000>; /* GICR */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart0: serial@600100000 {
+ compatible = "ns16550a";
+ reg = <0x6 0x00100000 0x20>;
+ clocks = <&ahb_clk>;
+ reg-io-width = <4>;
+ reg-shift = <2>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@600102000 {
+ compatible = "ns16550a";
+ reg = <0x6 0x00102000 0x20>;
+ clocks = <&ahb_clk>;
+ reg-io-width = <4>;
+ reg-shift = <2>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+
+ status = "disabled";
+ };
+
+ timer1: timer@600105000 {
+ compatible = "snps,dw-apb-timer";
+ reg = <0x6 0x00105000 0x1000>;
+ clocks = <&ahb_clk>;
+ clock-names = "timer";
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
new file mode 100644
index 0000000000000..d7f985f7ee020
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb_common.dtsi"
+
+/ {
+ model = "Sparx5 PCB125 Reference Board";
+ compatible = "microchip,sparx5-pcb125", "microchip,sparx5";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x10000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb134.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb134.dts
new file mode 100644
index 0000000000000..feee4e99ff57c
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb134.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb134_board.dtsi"
+
+/ {
+ model = "Sparx5 PCB134 Reference Board (NAND)";
+ compatible = "microchip,sparx5-pcb134", "microchip,sparx5";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x10000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
new file mode 100644
index 0000000000000..9b2aec400101b
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb_common.dtsi"
+
+/{
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpio 37 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb134_emmc.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb134_emmc.dts
new file mode 100644
index 0000000000000..10081a66961bb
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb134_emmc.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb134_board.dtsi"
+
+/ {
+ model = "Sparx5 PCB134 Reference Board (eMMC enabled)";
+ compatible = "microchip,sparx5-pcb134", "microchip,sparx5";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x10000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb135.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb135.dts
new file mode 100644
index 0000000000000..20e409a9be196
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb135.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb135_board.dtsi"
+
+/ {
+ model = "Sparx5 PCB135 Reference Board (NAND)";
+ compatible = "microchip,sparx5-pcb135", "microchip,sparx5";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x10000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
new file mode 100644
index 0000000000000..9b2aec400101b
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb_common.dtsi"
+
+/{
+ gpio-restart {
+ compatible = "gpio-restart";
+ gpios = <&gpio 37 GPIO_ACTIVE_LOW>;
+ priority = <200>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb135_emmc.dts b/arch/arm64/boot/dts/microchip/sparx5_pcb135_emmc.dts
new file mode 100644
index 0000000000000..741f0e12260e5
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb135_emmc.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5_pcb135_board.dtsi"
+
+/ {
+ model = "Sparx5 PCB135 Reference Board (eMMC enabled)";
+ compatible = "microchip,sparx5-pcb135", "microchip,sparx5";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x10000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi b/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
new file mode 100644
index 0000000000000..1f99d0db1284f
--- /dev/null
+++ b/arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+/dts-v1/;
+#include "sparx5.dtsi"
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
--
2.26.2
^ permalink raw reply related
* [PATCH 05/14] dt-bindings: arm: sparx5: Add documentation for Microchip Sparx5 SoC
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij, Rob Herring
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds the main Sparx5 SoC DT documentation file, with information
abut the supported board types.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
.../bindings/arm/microchip,sparx5.yaml | 87 +++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/microchip,sparx5.yaml
diff --git a/Documentation/devicetree/bindings/arm/microchip,sparx5.yaml b/Documentation/devicetree/bindings/arm/microchip,sparx5.yaml
new file mode 100644
index 0000000000000..83b36d1217988
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/microchip,sparx5.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/microchip,sparx5.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip Sparx5 Boards Device Tree Bindings
+
+maintainers:
+ - Lars Povlsen <lars.povlsen@microchip.com>
+
+description: |+
+ The Microchip Sparx5 SoC is a ARMv8-based used in a family of
+ gigabit TSN-capable gigabit switches.
+
+ The SparX-5 Ethernet switch family provides a rich set of switching
+ features such as advanced TCAM-based VLAN and QoS processing
+ enabling delivery of differentiated services, and security through
+ TCAM-based frame processing using versatile content aware processor
+ (VCAP)
+
+properties:
+ $nodename:
+ const: '/'
+ compatible:
+ oneOf:
+ - description: The Sparx5 pcb125 board is a modular board,
+ which has both spi-nor and eMMC storage. The modular design
+ allows for connection of different network ports.
+ items:
+ - const: microchip,sparx5-pcb125
+ - const: microchip,sparx5
+
+ - description: The Sparx5 pcb134 is a pizzabox form factor
+ gigabit switch with 20 SFP ports. It features spi-nor and
+ either spi-nand or eMMC storage (mount option).
+ items:
+ - const: microchip,sparx5-pcb134
+ - const: microchip,sparx5
+
+ - description: The Sparx5 pcb135 is a pizzabox form factor
+ gigabit switch with 48+4 Cu ports. It features spi-nor and
+ either spi-nand or eMMC storage (mount option).
+ items:
+ - const: microchip,sparx5-pcb135
+ - const: microchip,sparx5
+
+ axi@600000000:
+ type: object
+ description: the root node in the Sparx5 platforms must contain
+ an axi bus child node. They are always at physical address
+ 0x600000000 in all the Sparx5 variants.
+ properties:
+ compatible:
+ items:
+ - const: simple-bus
+ reg:
+ maxItems: 1
+
+ required:
+ - compatible
+ - reg
+
+patternProperties:
+ "^syscon@[0-9a-f]+$":
+ description: All Sparx5 boards must provide a system controller,
+ typically under the axi bus node. It contain reset registers and
+ other system control.
+ type: object
+ properties:
+ compatible:
+ items:
+ - const: microchip,sparx5-cpu-syscon
+ - const: syscon
+ reg:
+ maxItems: 1
+
+ required:
+ - compatible
+ - reg
+
+required:
+ - compatible
+ - axi@600000000
+ - syscon@600000000
+
+...
--
2.26.2
^ permalink raw reply related
* [PATCH 04/14] arm64: sparx5: Add support for Microchip 2xA53 SoC
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This adds support for the Microchip Sparx5 ARMv8-based SoC family of
TSN-capable gigabit switches.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
MAINTAINERS | 8 ++++++++
arch/arm64/Kconfig.platforms | 14 ++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 091ec22c1a23f..1b5a18d3dbb9f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2079,6 +2079,14 @@ X: drivers/net/wireless/atmel/
N: at91
N: atmel
+ARM/Microchip Sparx5 SoC support
+M: Lars Povlsen <lars.povlsen@microchip.com>
+M: Steen Hegelund <Steen.Hegelund@microchip.com>
+M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+N: sparx5
+S: Supported
+
ARM/MIOA701 MACHINE SUPPORT
M: Robert Jarzmik <robert.jarzmik@free.fr>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 55d70cfe0f9e1..e1734a13a967b 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -89,6 +89,20 @@ config ARCH_EXYNOS
help
This enables support for ARMv8 based Samsung Exynos SoC family.
+config ARCH_SPARX5
+ bool "ARMv8 based Microchip Sparx5 SoC family"
+ select PINCTRL
+ select DW_APB_TIMER_OF
+ help
+ This enables support for the Microchip Sparx5 ARMv8-based
+ SoC family of TSN-capable gigabit switches.
+
+ The SparX-5 Ethernet switch family provides a rich set of
+ switching features such as advanced TCAM-based VLAN and QoS
+ processing enabling delivery of differentiated services, and
+ security through TCAM-based frame processing using versatile
+ content aware processor (VCAP).
+
config ARCH_K3
bool "Texas Instruments Inc. K3 multicore SoC architecture"
select PM_GENERIC_DOMAINS if PM
--
2.26.2
^ permalink raw reply related
* [PATCH 03/14] pinctrl: ocelot: Fix GPIO interrupt decoding on Jaguar2
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This fixes a problem with using the GPIO as an interrupt on Jaguar2
(and similar), as the register layout of the platforms with 64 GPIO's
are pairwise, such that the original offset must be multiplied with
the platform stride.
Fixes: da801ab56ad8 pinctrl: ocelot: add MSCC Jaguar2 support.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
drivers/pinctrl/pinctrl-ocelot.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index 375f3ea3b80c4..95c225bc7572f 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -680,11 +680,12 @@ static void ocelot_irq_handler(struct irq_desc *desc)
struct irq_chip *parent_chip = irq_desc_get_chip(desc);
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
struct ocelot_pinctrl *info = gpiochip_get_data(chip);
+ unsigned int id_reg = OCELOT_GPIO_INTR_IDENT * info->stride;
unsigned int reg = 0, irq, i;
unsigned long irqs;
for (i = 0; i < info->stride; i++) {
- regmap_read(info->map, OCELOT_GPIO_INTR_IDENT + 4 * i, ®);
+ regmap_read(info->map, id_reg + 4 * i, ®);
if (!reg)
continue;
--
2.26.2
^ permalink raw reply related
* [PATCH 02/14] pinctrl: ocelot: Remove instance number from pin functions
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This patch removes the instance number from the "miim", "reco_clk" and
"sfp" pin function.
The change needed is to prepare the driver for adding new platforms
with more of these instances. The instance number is also redundant,
as this is implicit for each pin.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
drivers/pinctrl/pinctrl-ocelot.c | 94 ++++++++++----------------------
1 file changed, 30 insertions(+), 64 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index d4ac65b1efc0b..375f3ea3b80c4 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -46,32 +46,15 @@ enum {
FUNC_IRQ0_OUT,
FUNC_IRQ1_IN,
FUNC_IRQ1_OUT,
- FUNC_MIIM1,
- FUNC_MIIM2,
+ FUNC_MIIM,
FUNC_PCI_WAKE,
FUNC_PTP0,
FUNC_PTP1,
FUNC_PTP2,
FUNC_PTP3,
FUNC_PWM,
- FUNC_RECO_CLK0,
- FUNC_RECO_CLK1,
- FUNC_SFP0,
- FUNC_SFP1,
- FUNC_SFP2,
- FUNC_SFP3,
- FUNC_SFP4,
- FUNC_SFP5,
- FUNC_SFP6,
- FUNC_SFP7,
- FUNC_SFP8,
- FUNC_SFP9,
- FUNC_SFP10,
- FUNC_SFP11,
- FUNC_SFP12,
- FUNC_SFP13,
- FUNC_SFP14,
- FUNC_SFP15,
+ FUNC_RECO_CLK,
+ FUNC_SFP,
FUNC_SG0,
FUNC_SG1,
FUNC_SG2,
@@ -92,32 +75,15 @@ static const char *const ocelot_function_names[] = {
[FUNC_IRQ0_OUT] = "irq0_out",
[FUNC_IRQ1_IN] = "irq1_in",
[FUNC_IRQ1_OUT] = "irq1_out",
- [FUNC_MIIM1] = "miim1",
- [FUNC_MIIM2] = "miim2",
+ [FUNC_MIIM] = "miim",
[FUNC_PCI_WAKE] = "pci_wake",
[FUNC_PTP0] = "ptp0",
[FUNC_PTP1] = "ptp1",
[FUNC_PTP2] = "ptp2",
[FUNC_PTP3] = "ptp3",
[FUNC_PWM] = "pwm",
- [FUNC_RECO_CLK0] = "reco_clk0",
- [FUNC_RECO_CLK1] = "reco_clk1",
- [FUNC_SFP0] = "sfp0",
- [FUNC_SFP1] = "sfp1",
- [FUNC_SFP2] = "sfp2",
- [FUNC_SFP3] = "sfp3",
- [FUNC_SFP4] = "sfp4",
- [FUNC_SFP5] = "sfp5",
- [FUNC_SFP6] = "sfp6",
- [FUNC_SFP7] = "sfp7",
- [FUNC_SFP8] = "sfp8",
- [FUNC_SFP9] = "sfp9",
- [FUNC_SFP10] = "sfp10",
- [FUNC_SFP11] = "sfp11",
- [FUNC_SFP12] = "sfp12",
- [FUNC_SFP13] = "sfp13",
- [FUNC_SFP14] = "sfp14",
- [FUNC_SFP15] = "sfp15",
+ [FUNC_RECO_CLK] = "reco_clk",
+ [FUNC_SFP] = "sfp",
[FUNC_SG0] = "sg0",
[FUNC_SG1] = "sg1",
[FUNC_SG2] = "sg2",
@@ -168,18 +134,18 @@ OCELOT_P(6, UART, TWI_SCL_M, NONE);
OCELOT_P(7, UART, TWI_SCL_M, NONE);
OCELOT_P(8, SI, TWI_SCL_M, IRQ0_OUT);
OCELOT_P(9, SI, TWI_SCL_M, IRQ1_OUT);
-OCELOT_P(10, PTP2, TWI_SCL_M, SFP0);
-OCELOT_P(11, PTP3, TWI_SCL_M, SFP1);
-OCELOT_P(12, UART2, TWI_SCL_M, SFP2);
-OCELOT_P(13, UART2, TWI_SCL_M, SFP3);
-OCELOT_P(14, MIIM1, TWI_SCL_M, SFP4);
-OCELOT_P(15, MIIM1, TWI_SCL_M, SFP5);
+OCELOT_P(10, PTP2, TWI_SCL_M, SFP);
+OCELOT_P(11, PTP3, TWI_SCL_M, SFP);
+OCELOT_P(12, UART2, TWI_SCL_M, SFP);
+OCELOT_P(13, UART2, TWI_SCL_M, SFP);
+OCELOT_P(14, MIIM, TWI_SCL_M, SFP);
+OCELOT_P(15, MIIM, TWI_SCL_M, SFP);
OCELOT_P(16, TWI, NONE, SI);
OCELOT_P(17, TWI, TWI_SCL_M, SI);
OCELOT_P(18, PTP0, TWI_SCL_M, NONE);
OCELOT_P(19, PTP1, TWI_SCL_M, NONE);
-OCELOT_P(20, RECO_CLK0, TACHO, NONE);
-OCELOT_P(21, RECO_CLK1, PWM, NONE);
+OCELOT_P(20, RECO_CLK, TACHO, TWI_SCL_M);
+OCELOT_P(21, RECO_CLK, PWM, TWI_SCL_M);
#define OCELOT_PIN(n) { \
.number = n, \
@@ -264,22 +230,22 @@ JAGUAR2_P(40, NONE, TWI_SCL_M);
JAGUAR2_P(41, NONE, TWI_SCL_M);
JAGUAR2_P(42, NONE, TWI_SCL_M);
JAGUAR2_P(43, NONE, TWI_SCL_M);
-JAGUAR2_P(44, NONE, SFP8);
-JAGUAR2_P(45, NONE, SFP9);
-JAGUAR2_P(46, NONE, SFP10);
-JAGUAR2_P(47, NONE, SFP11);
-JAGUAR2_P(48, SFP0, NONE);
-JAGUAR2_P(49, SFP1, SI);
-JAGUAR2_P(50, SFP2, SI);
-JAGUAR2_P(51, SFP3, SI);
-JAGUAR2_P(52, SFP4, NONE);
-JAGUAR2_P(53, SFP5, NONE);
-JAGUAR2_P(54, SFP6, NONE);
-JAGUAR2_P(55, SFP7, NONE);
-JAGUAR2_P(56, MIIM1, SFP12);
-JAGUAR2_P(57, MIIM1, SFP13);
-JAGUAR2_P(58, MIIM2, SFP14);
-JAGUAR2_P(59, MIIM2, SFP15);
+JAGUAR2_P(44, NONE, SFP);
+JAGUAR2_P(45, NONE, SFP);
+JAGUAR2_P(46, NONE, SFP);
+JAGUAR2_P(47, NONE, SFP);
+JAGUAR2_P(48, SFP, NONE);
+JAGUAR2_P(49, SFP, SI);
+JAGUAR2_P(50, SFP, SI);
+JAGUAR2_P(51, SFP, SI);
+JAGUAR2_P(52, SFP, NONE);
+JAGUAR2_P(53, SFP, NONE);
+JAGUAR2_P(54, SFP, NONE);
+JAGUAR2_P(55, SFP, NONE);
+JAGUAR2_P(56, MIIM, SFP);
+JAGUAR2_P(57, MIIM, SFP);
+JAGUAR2_P(58, MIIM, SFP);
+JAGUAR2_P(59, MIIM, SFP);
JAGUAR2_P(60, NONE, NONE);
JAGUAR2_P(61, NONE, NONE);
JAGUAR2_P(62, NONE, NONE);
--
2.26.2
^ permalink raw reply related
* R: R: [PATCH v3 08/11] devicetree: bindings: pci: document PARF params bindings
From: ansuelsmth @ 2020-05-13 12:56 UTC (permalink / raw)
To: 'Stanimir Varbanov', 'Rob Herring'
Cc: 'Bjorn Andersson', 'Andy Gross',
'Bjorn Helgaas', 'Mark Rutland',
'Lorenzo Pieralisi', 'Andrew Murray',
'Philipp Zabel', linux-arm-msm, linux-pci, devicetree,
linux-kernel
In-Reply-To: <99f42001-0f41-5e63-f6ad-2e744ec86d36@mm-sol.com>
> On 5/12/20 6:45 PM, Rob Herring wrote:
> > On Thu, May 07, 2020 at 09:34:35PM +0200, ansuelsmth@gmail.com
> wrote:
> >>> On Fri, May 01, 2020 at 12:06:15AM +0200, Ansuel Smith wrote:
> >>>> It is now supported the editing of Tx De-Emphasis, Tx Swing and
> >>>> Rx equalization params on ipq8064. Document this new optional
> params.
> >>>>
> >>>> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> >>>> ---
> >>>> .../devicetree/bindings/pci/qcom,pcie.txt | 36
> +++++++++++++++++++
> >>>> 1 file changed, 36 insertions(+)
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> >>> b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> >>>> index 6efcef040741..8cc5aea8a1da 100644
> >>>> --- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> >>>> +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
> >>>> @@ -254,6 +254,42 @@
> >>>> - "perst-gpios" PCIe endpoint reset signal line
> >>>> - "wake-gpios" PCIe endpoint wake signal line
> >>>>
> >>>> +- qcom,tx-deemph-gen1:
> >>>> + Usage: optional (available for ipq/apq8064)
> >>>> + Value type: <u32>
> >>>> + Definition: Gen1 De-emphasis value.
> >>>> + For ipq806x should be set to 24.
> >>>
> >>> Unless these need to be tuned per board, then the compatible string
> for
> >>> ipq806x should imply all these settings.
> >>>
> >>
> >> It was requested by v2 to make this settings tunable. These don't change
> are
> >> all the same for every ipq806x SoC. The original implementation had this
> >> value hardcoded for ipq806x. Should I restore this and drop this patch?
> >
> > Yes, please.
>
> I still think that the values for tx deemph and tx swing should be
> tunable. But I can live with them in the driver if they not break
> support for apq8064.
>
> The default values in the registers for apq8064 and ipq806x are:
>
> default your change
> TX_DEEMPH_GEN1 21 24
> TX_DEEMPH_GEN2_3_5DB 21 24
> TX_DEEMPH_GEN2_6DB 32 34
>
> TX_SWING_FULL 121 120
> TX_SWING_LOW 121 120
>
> So until now (without your change) apq8064 worked with default values.
>
I will limit this to ipq8064(-v2) if this could be a problem.
> >
> > Rob
> >
>
> --
> regards,
> Stan
^ permalink raw reply
* [PATCH 01/14] pinctrl: ocelot: Should register GPIO's even if not irq controller
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20200513125532.24585-1-lars.povlsen@microchip.com>
This fixes the situation where the GPIO controller is not used as an
interrupt controller as well.
Previously, the driver would silently fail to register even the
GPIO's. With this change, the driver will only register as an
interrupt controller if a parent interrupt is provided.
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
drivers/pinctrl/pinctrl-ocelot.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index ed8eac6c14944..d4ac65b1efc0b 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -751,21 +751,21 @@ static int ocelot_gpiochip_register(struct platform_device *pdev,
gc->of_node = info->dev->of_node;
gc->label = "ocelot-gpio";
- irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
- if (irq <= 0)
- return irq;
-
- girq = &gc->irq;
- girq->chip = &ocelot_irqchip;
- girq->parent_handler = ocelot_irq_handler;
- girq->num_parents = 1;
- girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents),
- GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
- girq->parents[0] = irq;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
+ irq = irq_of_parse_and_map(gc->of_node, 0);
+ if (irq) {
+ girq = &gc->irq;
+ girq->chip = &ocelot_irqchip;
+ girq->parent_handler = ocelot_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(&pdev->dev, 1,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->parents[0] = irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_edge_irq;
+ }
ret = devm_gpiochip_add_data(&pdev->dev, gc, info);
if (ret)
--
2.26.2
^ permalink raw reply related
* [PATCH 00/14] Adding support for Microchip Sparx5 SoC
From: Lars Povlsen @ 2020-05-13 12:55 UTC (permalink / raw)
To: SoC Team, Arnd Bergmann, Stephen Boyd, Linus Walleij
Cc: Lars Povlsen, Steen Hegelund, Microchip Linux Driver Support,
Olof Johansson, Michael Turquette, devicetree, linux-clk,
linux-gpio, linux-arm-kernel, linux-kernel
This patch series adds support for Microchip Sparx5 SoC, the CPU
system of a advanced, TSN capable gigabit switch. The CPU is an armv8
x 2 CPU core (A53).
Although this is an ARM core, it shares some peripherals with the
Microsemi Ocelot SoC.
This is the first official revision of the series.
Lars Povlsen (14):
pinctrl: ocelot: Should register GPIO's even if not irq controller
pinctrl: ocelot: Remove instance number from pin functions
pinctrl: ocelot: Fix GPIO interrupt decoding on Jaguar2
arm64: sparx5: Add support for Microchip 2xA53 SoC
dt-bindings: arm: sparx5: Add documentation for Microchip Sparx5 SoC
arm64: dts: sparx5: Add basic cpu support
dt-bindings: pinctrl: ocelot: Add Sparx5 SoC support
arm64: dts: sparx5: Add pinctrl support
pinctrl: ocelot: Add Sparx5 SoC support
dt-bindings: clock: sparx5: Add Sparx5 SoC DPLL clock
dt-bindings: clock: sparx5: Add bindings include file
clk: sparx5: Add Sparx5 SoC DPLL clock driver
arm64: dts: sparx5: Add Sparx5 SoC DPLL clock
arm64: dts: sparx5: Add i2c devices, i2c muxes
.../bindings/arm/microchip,sparx5.yaml | 87 +++
.../bindings/clock/microchip,sparx5-dpll.yaml | 46 ++
.../bindings/pinctrl/mscc,ocelot-pinctrl.txt | 4 +-
MAINTAINERS | 9 +
arch/arm64/Kconfig.platforms | 14 +
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/microchip/Makefile | 4 +
arch/arm64/boot/dts/microchip/sparx5.dtsi | 202 +++++++
.../boot/dts/microchip/sparx5_pcb125.dts | 21 +
.../boot/dts/microchip/sparx5_pcb134.dts | 17 +
.../dts/microchip/sparx5_pcb134_board.dtsi | 252 ++++++++
.../boot/dts/microchip/sparx5_pcb134_emmc.dts | 17 +
.../boot/dts/microchip/sparx5_pcb135.dts | 17 +
.../dts/microchip/sparx5_pcb135_board.dtsi | 92 +++
.../boot/dts/microchip/sparx5_pcb135_emmc.dts | 17 +
.../boot/dts/microchip/sparx5_pcb_common.dtsi | 19 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-sparx5.c | 269 +++++++++
drivers/pinctrl/pinctrl-ocelot.c | 558 +++++++++++++++---
include/dt-bindings/clock/microchip,sparx5.h | 23 +
20 files changed, 1587 insertions(+), 83 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/microchip,sparx5.yaml
create mode 100644 Documentation/devicetree/bindings/clock/microchip,sparx5-dpll.yaml
create mode 100644 arch/arm64/boot/dts/microchip/Makefile
create mode 100644 arch/arm64/boot/dts/microchip/sparx5.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb125.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb134_emmc.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb135_emmc.dts
create mode 100644 arch/arm64/boot/dts/microchip/sparx5_pcb_common.dtsi
create mode 100644 drivers/clk/clk-sparx5.c
create mode 100644 include/dt-bindings/clock/microchip,sparx5.h
--
2.26.2
^ permalink raw reply
* R: [PATCH v3 09/11] PCI: qcom: add ipq8064 rev2 variant and set tx term offset
From: ansuelsmth @ 2020-05-13 12:54 UTC (permalink / raw)
To: 'Stanimir Varbanov', 'Bjorn Andersson'
Cc: 'Sham Muthayyan', 'Andy Gross',
'Bjorn Helgaas', 'Rob Herring',
'Mark Rutland', 'Lorenzo Pieralisi',
'Andrew Murray', 'Philipp Zabel', linux-arm-msm,
linux-pci, devicetree, linux-kernel
In-Reply-To: <3dc89ec6-d550-9402-1a4a-ca0c6f1e1fb9@mm-sol.com>
> Hi Ansuel,
>
> On 5/1/20 1:06 AM, Ansuel Smith wrote:
> > From: Sham Muthayyan <smuthayy@codeaurora.org>
> >
> > Add tx term offset support to pcie qcom driver need in some revision of
> > the ipq806x SoC.
> > Ipq8064 have tx term offset set to 7.
> > Ipq8064-v2 revision and ipq8065 have the tx term offset set to 0.
> >
> > Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> > drivers/pci/controller/dwc/pcie-qcom.c | 15 +++++++++++++++
> > 1 file changed, 15 insertions(+)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-qcom.c
> b/drivers/pci/controller/dwc/pcie-qcom.c
> > index da8058fd1925..372d2c8508b5 100644
> > --- a/drivers/pci/controller/dwc/pcie-qcom.c
> > +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> > @@ -45,6 +45,9 @@
> > #define PCIE_CAP_CPL_TIMEOUT_DISABLE 0x10
> >
> > #define PCIE20_PARF_PHY_CTRL 0x40
> > +#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK GENMASK(12,
> 16)
>
> The mask definition is not correct. Should be GENMASK(20, 16)
>
> > +#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) ((x) << 16)
> > +
> > #define PCIE20_PARF_PHY_REFCLK 0x4C
> > #define PHY_REFCLK_SSP_EN BIT(16)
> > #define PHY_REFCLK_USE_PAD BIT(12)
> > @@ -118,6 +121,7 @@ struct qcom_pcie_resources_2_1_0 {
> > u32 tx_swing_full;
> > u32 tx_swing_low;
> > u32 rx0_eq;
> > + u8 phy_tx0_term_offset;
> > };
> >
> > struct qcom_pcie_resources_1_0_0 {
> > @@ -318,6 +322,11 @@ static int
> qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
> > if (IS_ERR(res->ext_reset))
> > return PTR_ERR(res->ext_reset);
> >
> > + if (of_device_is_compatible(dev->of_node, "qcom,pcie-ipq8064"))
> > + res->phy_tx0_term_offset = 7;
>
> Before your change the phy_tx0_term_offser was 0 for apq8064, but here
> you change it to 7, why?
>
apq8064 board should use qcom,pcie-apq8064 right? This should be set to 0
only with pcie-ipq8064 compatible. Tell me if I'm wrong.
> > + else
> > + res->phy_tx0_term_offset = 0;
> > +
> > res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
> > return PTR_ERR_OR_ZERO(res->phy_reset);
> > }
> > @@ -402,6 +411,11 @@ static int qcom_pcie_init_2_1_0(struct
> qcom_pcie *pcie)
> > /* enable PCIe clocks and resets */
> > qcom_clear_and_set_dword(pcie->parf + PCIE20_PARF_PHY_CTRL,
> BIT(0), 0);
> >
> > + /* set TX termination offset */
> > + qcom_clear_and_set_dword(pcie->parf + PCIE20_PARF_PHY_CTRL,
> > + PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK,
>
> As the mask definition is incorrect you actually clear 12 to 16 bit in
> the register where is another PHY parameter. Is that was intentional?
>
Will check this and the wrong genmask.
> > + PHY_CTRL_PHY_TX0_TERM_OFFSET(res-
> >phy_tx0_term_offset));
> > +
> > writel(PCS_DEEMPH_TX_DEEMPH_GEN1(res->tx_deemph_gen1) |
> > PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(res-
> >tx_deemph_gen2_3p5db) |
> > PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(res-
> >tx_deemph_gen2_6db),
> > @@ -1485,6 +1499,7 @@ static int qcom_pcie_probe(struct
> platform_device *pdev)
> > static const struct of_device_id qcom_pcie_match[] = {
> > { .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
> > { .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
> > + { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 },
> > { .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
> > { .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
> > { .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
> >
>
> --
> regards,
> Stan
^ permalink raw reply
* (no subject)
From: Jacopo Mondi @ 2020-05-13 12:54 UTC (permalink / raw)
To: devicetree, linux-media, Rob Herring, Kieran Bingham,
linux-renesas-soc, laurent.pinchart+renesas, niklas.soderlund
Cc: Jacopo Mondi, Hans Verkuil, sakari.ailus, mchehab,
Manivannan Sadhasivam, Hyun Kwon
In-Reply-To: <20200512223329.GA23701@bogus>
Subject: [PATCH] fixup! dt-bindings: media: i2c: Add bindings for Maxima Integrated MAX9286
Temporary fixup to ease review. To be squashed into v10 if accepted.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
While fixing Rob's reported bug on v9 I realized thanks to a
dt_binding_check warning that the i2c-mux child nodes where under-specified.
This fixup epxands the i2c-mux child nodes description and updates the
example to match our currently-out-of-tree DTS files for GMSL platforms.
dt_binding_check still reports a warning:
Documentation/devicetree/bindings/media/i2c/maxim,max9286.example.dt.yaml: camera@51: reg: [[81, 97]] is too short
Documentation/devicetree/bindings/media/i2c/maxim,max9286.example.dt.yaml: camera@52: reg: [[82, 98]] is too short
Documentation/devicetree/bindings/media/i2c/maxim,max9286.example.dt.yaml: camera@53: reg: [[83, 99]] is too short
Documentation/devicetree/bindings/media/i2c/maxim,max9286.example.dt.yaml: camera@54: reg: [[84, 100]] is too short
Which I was not able to silence.
---
.../bindings/media/i2c/maxim,max9286.yaml | 86 +++++++++++++++++--
1 file changed, 77 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
index f9d3e5712c59..d9bd19caed2f 100644
--- a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
@@ -130,9 +130,7 @@ properties:
description: |
Each GMSL link is modelled as a child bus of an i2c bus
multiplexer/switch, in accordance with bindings described in
- Documentation/devicetree/bindings/i2c/i2c-mux.txt. The serializer
- device on the remote end of the GMSL link shall be modelled as a child
- node of the corresponding I2C bus.
+ Documentation/devicetree/bindings/i2c/i2c-mux.txt.
properties:
'#address-cells':
@@ -141,7 +139,74 @@ properties:
'#size-cells':
const: 0
- additionalProperties: false
+ patternProperties:
+ "^i2c@[0-3]$":
+ type: object
+ description: |
+ Child node of the i2c bus multiplexer which represents a GMSL link.
+ Each serializer device on the GMSL link remote end is represented with
+ an i2c-mux child node. The MAX9286 chip supports up to 4 GMSL
+ channels.
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ reg:
+ description: The index of the GMSL channel.
+ maxItems: 1
+
+ patternProperties:
+ "^camera@[0-9]+":
+ type: object
+ description: |
+ The remote camera device, composed by a GMSL serializer and a
+ connected video source.
+
+ properties:
+ compatible:
+ description: The remote device compatible string.
+
+ reg:
+ description: |
+ The I2C addresses to be assigned to the remote devices through
+ address reprogramming. The number of entries depends on the
+ requirements of the currently connected remote device.
+
+ port:
+ type: object
+
+ properties:
+ endpoint:
+ type: object
+
+ properties:
+ remote-endpoint:
+ description: phandle to the MAX9286 sink endpoint.
+
+ required:
+ - remote-endpoint
+
+ additionalProperties: false
+
+ required:
+ - endpoint
+
+ additionalProperties: false
+
+ required:
+ - compatible
+ - reg
+ - port
+
+ additionalProperties: false
+
+ additionalProperties: false
+
+ additionalProperties: false
required:
- compatible
@@ -220,11 +285,11 @@ examples:
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
-
reg = <0>;
camera@51 {
- reg = <0x51>;
+ compatible = "imi,rdacm20";
+ reg = <0x51 0x61>;
port {
rdacm20_out0: endpoint {
@@ -241,7 +306,8 @@ examples:
reg = <1>;
camera@52 {
- reg = <0x52>;
+ compatible = "imi,rdacm20";
+ reg = <0x52 0x62>;
port {
rdacm20_out1: endpoint {
@@ -257,7 +323,8 @@ examples:
reg = <2>;
camera@53 {
- reg = <0x53>;
+ compatible = "imi,rdacm20";
+ reg = <0x53 0x63>;
port {
rdacm20_out2: endpoint {
@@ -273,7 +340,8 @@ examples:
reg = <3>;
camera@54 {
- reg = <0x54>;
+ compatible = "imi,rdacm20";
+ reg = <0x54 0x64>;
port {
rdacm20_out3: endpoint {
--
2.26.2
^ permalink raw reply related
* Re: [PATCH v7 2/2] mmc: host: meson-mx-sdhc: new driver for the Amlogic Meson SDHC host
From: Jerome Brunet @ 2020-05-13 12:40 UTC (permalink / raw)
To: Ulf Hansson, Martin Blumenstingl
Cc: open list:ARM/Amlogic Meson..., linux-mmc@vger.kernel.org,
Rob Herring, DTML, Jianxin Pan, Linux Kernel Mailing List,
yinxin_1989, Linux ARM, lnykww, Anand Moon
In-Reply-To: <CAPDyKFp0=RpJ9iLgwE9VUTpvQ-5=jY98Cu0Pz7Pw2xqq8edssw@mail.gmail.com>
On Wed 13 May 2020 at 14:04, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On Tue, 12 May 2020 at 22:42, Martin Blumenstingl
> <martin.blumenstingl@googlemail.com> wrote:
>>
>> The SDHC MMC host controller on Amlogic SoCs provides an eMMC and MMC
>> card interface with 1/4/8-bit bus width.
>> It supports eMMC spec 4.4x/4.5x including HS200 (up to 100MHz clock).
>>
>> The public S805 datasheet [0] contains a short documentation about the
>> registers. Unfortunately it does not describe how to use the registers
>> to make the hardware work. Thus this driver is based on reading (and
>> understanding) the Amlogic 3.10 GPL kernel code.
>>
>> Some hardware details are not easy to see. Jianxin Pan was kind enough
>> to answer my questions:
>> The hardware has built-in busy timeout support. The maximum timeout is
>> 30 seconds. This is only documented in Amlogic's internal
>> documentation.
>>
>> The controller only works with very specific clock configurations. The
>> details are not part of the public datasheet. In my own words the
>> supported configurations are:
>> - 399.812kHz: clkin = 850MHz div = 2126 sd_rx_phase = 63
>> - 1MHz: clkin = 850MHz div = 850 sd_rx_phase = 55
>> - 5.986MHz: clkin = 850MHz div = 142 sd_rx_phase = 24
>> - 25MHz: clkin = 850MHz div = 34 sd_rx_phase = 15
>> - 47.222MHz: clkin = 850MHz div = 18 sd_rx_phase = 11/15 (SDR50/HS)
>> - 53.125MHz: clkin = 850MHz div = 16 sd_rx_phase = (tuning)
>> - 70.833MHz: clkin = 850MHz div = 12 sd_rx_phase = (tuning)
>> - 85MHz: clkin = 850MHz div = 10 sd_rx_phase = (tuning)
>> - 94.44MHz: clkin = 850MHz div = 9 sd_rx_phase = (tuning)
>> - 106.25MHz: clkin = 850MHz div = 8 sd_rx_phase = (tuning)
>> - 127.5MHz: clkin = 1275MHz div = 10 sd_rx_phase = (tuning)
>> - 141.667MHz: clkin = 850MHz div = 6 sd_rx_phase = (tuning)
>> - 159.375MHz: clkin = 1275MHz div = 8 sd_rx_phase = (tuning)
>> - 212.5MHz: clkin = 1275MHz div = 6 sd_rx_phase = (tuning)
>> - (sd_tx_phase is always 1, 94.44MHz is not listed in the datasheet
>> but this is what the 3.10 BSP kernel on Odroid-C1 actually uses)
>>
>> NOTE: CMD23 support is disabled for now because it results in command
>> timeouts and thus decreases read performance.
>>
>> Tested-by: Wei Wang <lnykww@gmail.com>
>> Tested-by: Xin Yin <yinxin_1989@aliyun.com>
>> Reviewed-by: Xin Yin <yinxin_1989@aliyun.com>
>> Tested-by: Anand Moon <linux.amoon@gmail.com>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>
> This looks good to me, however I am awaiting a reviewed-by tag from
> Jerome, to make sure the clock implementation turn out as agreed upon.
Thx !
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
>
> Kind regards
> Uffe
>
>> ---
>> drivers/mmc/host/Kconfig | 14 +
>> drivers/mmc/host/Makefile | 1 +
>> drivers/mmc/host/meson-mx-sdhc-clkc.c | 158 +++++
>> drivers/mmc/host/meson-mx-sdhc.c | 907 ++++++++++++++++++++++++++
>> drivers/mmc/host/meson-mx-sdhc.h | 141 ++++
>> 5 files changed, 1221 insertions(+)
>> create mode 100644 drivers/mmc/host/meson-mx-sdhc-clkc.c
>> create mode 100644 drivers/mmc/host/meson-mx-sdhc.c
>> create mode 100644 drivers/mmc/host/meson-mx-sdhc.h
>>
>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>> index 462b5352fea7..df3fc572f842 100644
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -405,6 +405,20 @@ config MMC_MESON_GX
>>
>> If you have a controller with this interface, say Y here.
>>
>> +config MMC_MESON_MX_SDHC
>> + tristate "Amlogic Meson SDHC Host Controller support"
>> + depends on (ARM && ARCH_MESON) || COMPILE_TEST
>> + depends on COMMON_CLK
>> + depends on OF
>> + help
>> + This selects support for the SDHC Host Controller on
>> + Amlogic Meson6, Meson8, Meson8b and Meson8m2 SoCs.
>> + The controller supports the SD/SDIO Spec 3.x and eMMC Spec 4.5x
>> + with 1, 4, and 8 bit bus widths.
>> +
>> + If you have a controller with this interface, say Y or M here.
>> + If unsure, say N.
>> +
>> config MMC_MESON_MX_SDIO
>> tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
>> depends on ARCH_MESON || COMPILE_TEST
>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>> index b929ef941208..8bcb420e071c 100644
>> --- a/drivers/mmc/host/Makefile
>> +++ b/drivers/mmc/host/Makefile
>> @@ -68,6 +68,7 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o
>> obj-$(CONFIG_MMC_USHC) += ushc.o
>> obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
>> obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o
>> +obj-$(CONFIG_MMC_MESON_MX_SDHC) += meson-mx-sdhc-clkc.o meson-mx-sdhc.o
>> obj-$(CONFIG_MMC_MESON_MX_SDIO) += meson-mx-sdio.o
>> obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
>> obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
>> diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c
>> new file mode 100644
>> index 000000000000..ab0d6c68a078
>> --- /dev/null
>> +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c
>> @@ -0,0 +1,158 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Amlogic Meson SDHC clock controller
>> + *
>> + * Copyright (C) 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/device.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "meson-mx-sdhc.h"
>> +
>> +#define MESON_SDHC_NUM_BUILTIN_CLKS 6
>> +
>> +struct meson_mx_sdhc_clkc {
>> + struct clk_mux src_sel;
>> + struct clk_divider div;
>> + struct clk_gate mod_clk_en;
>> + struct clk_gate tx_clk_en;
>> + struct clk_gate rx_clk_en;
>> + struct clk_gate sd_clk_en;
>> +};
>> +
>> +static const struct clk_parent_data meson_mx_sdhc_src_sel_parents[4] = {
>> + { .fw_name = "clkin0" },
>> + { .fw_name = "clkin1" },
>> + { .fw_name = "clkin2" },
>> + { .fw_name = "clkin3" },
>> +};
>> +
>> +static const struct clk_div_table meson_mx_sdhc_div_table[] = {
>> + { .div = 6, .val = 5, },
>> + { .div = 8, .val = 7, },
>> + { .div = 9, .val = 8, },
>> + { .div = 10, .val = 9, },
>> + { .div = 12, .val = 11, },
>> + { .div = 16, .val = 15, },
>> + { .div = 18, .val = 17, },
>> + { .div = 34, .val = 33, },
>> + { .div = 142, .val = 141, },
>> + { .div = 850, .val = 849, },
>> + { .div = 2126, .val = 2125, },
>> + { .div = 4096, .val = 4095, },
>> + { /* sentinel */ }
>> +};
>> +
>> +static int meson_mx_sdhc_clk_hw_register(struct device *dev,
>> + const char *name_suffix,
>> + const struct clk_parent_data *parents,
>> + unsigned int num_parents,
>> + const struct clk_ops *ops,
>> + struct clk_hw *hw)
>> +{
>> + struct clk_init_data init = { 0 };
>> + char clk_name[32];
>> +
>> + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dev),
>> + name_suffix);
>> +
>> + init.name = clk_name;
>> + init.ops = ops;
>> + init.flags = CLK_SET_RATE_PARENT;
>> + init.parent_data = parents;
>> + init.num_parents = num_parents;
>> +
>> + hw->init = &init;
>> +
>> + return devm_clk_hw_register(dev, hw);
>> +}
>> +
>> +static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev,
>> + const char *name_suffix,
>> + struct clk_hw *parent,
>> + struct clk_hw *hw)
>> +{
>> + struct clk_parent_data parent_data = { .hw = parent };
>> +
>> + return meson_mx_sdhc_clk_hw_register(dev, name_suffix, &parent_data, 1,
>> + &clk_gate_ops, hw);
>> +}
>> +
>> +int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,
>> + struct clk_bulk_data *clk_bulk_data)
>> +{
>> + struct clk_parent_data div_parent = { 0 };
>> + struct meson_mx_sdhc_clkc *clkc_data;
>> + int ret;
>> +
>> + clkc_data = devm_kzalloc(dev, sizeof(*clkc_data), GFP_KERNEL);
>> + if (!clkc_data)
>> + return -ENOMEM;
>> +
>> + clkc_data->src_sel.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->src_sel.mask = 0x3;
>> + clkc_data->src_sel.shift = 16;
>> + ret = meson_mx_sdhc_clk_hw_register(dev, "src_sel",
>> + meson_mx_sdhc_src_sel_parents, 4,
>> + &clk_mux_ops,
>> + &clkc_data->src_sel.hw);
>> + if (ret)
>> + return ret;
>> +
>> + clkc_data->div.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->div.shift = 0;
>> + clkc_data->div.width = 12;
>> + clkc_data->div.table = meson_mx_sdhc_div_table;
>> + div_parent.hw = &clkc_data->src_sel.hw;
>> + ret = meson_mx_sdhc_clk_hw_register(dev, "div", &div_parent, 1,
>> + &clk_divider_ops,
>> + &clkc_data->div.hw);
>> + if (ret)
>> + return ret;
>> +
>> + clkc_data->mod_clk_en.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->mod_clk_en.bit_idx = 15;
>> + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "mod_clk_on",
>> + &clkc_data->div.hw,
>> + &clkc_data->mod_clk_en.hw);
>> + if (ret)
>> + return ret;
>> +
>> + clkc_data->tx_clk_en.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->tx_clk_en.bit_idx = 14;
>> + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "tx_clk_on",
>> + &clkc_data->div.hw,
>> + &clkc_data->tx_clk_en.hw);
>> + if (ret)
>> + return ret;
>> +
>> + clkc_data->rx_clk_en.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->rx_clk_en.bit_idx = 13;
>> + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "rx_clk_on",
>> + &clkc_data->div.hw,
>> + &clkc_data->rx_clk_en.hw);
>> + if (ret)
>> + return ret;
>> +
>> + clkc_data->sd_clk_en.reg = base + MESON_SDHC_CLKC;
>> + clkc_data->sd_clk_en.bit_idx = 12;
>> + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "sd_clk_on",
>> + &clkc_data->div.hw,
>> + &clkc_data->sd_clk_en.hw);
>> + if (ret)
>> + return ret;
>> +
>> + /*
>> + * TODO: Replace clk_hw.clk with devm_clk_hw_get_clk() once that is
>> + * available.
>> + */
>> + clk_bulk_data[0].clk = clkc_data->mod_clk_en.hw.clk;
>> + clk_bulk_data[1].clk = clkc_data->sd_clk_en.hw.clk;
>> + clk_bulk_data[2].clk = clkc_data->tx_clk_en.hw.clk;
>> + clk_bulk_data[3].clk = clkc_data->rx_clk_en.hw.clk;
>> +
>> + return 0;
>> +}
>> diff --git a/drivers/mmc/host/meson-mx-sdhc.c b/drivers/mmc/host/meson-mx-sdhc.c
>> new file mode 100644
>> index 000000000000..5c00958d7754
>> --- /dev/null
>> +++ b/drivers/mmc/host/meson-mx-sdhc.c
>> @@ -0,0 +1,907 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Amlogic Meson6/Meson8/Meson8b/Meson8m2 SDHC MMC host controller driver.
>> + *
>> + * Copyright (C) 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/device.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/property.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/types.h>
>> +
>> +#include <linux/mmc/host.h>
>> +#include <linux/mmc/mmc.h>
>> +#include <linux/mmc/sdio.h>
>> +#include <linux/mmc/slot-gpio.h>
>> +
>> +#include "meson-mx-sdhc.h"
>> +
>> +#define MESON_SDHC_NUM_BULK_CLKS 4
>> +#define MESON_SDHC_MAX_BLK_SIZE 512
>> +#define MESON_SDHC_NUM_TUNING_TRIES 10
>> +
>> +#define MESON_SDHC_WAIT_CMD_READY_SLEEP_US 1
>> +#define MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US 100000
>> +#define MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US 1
>> +#define MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US 200
>> +
>> +struct meson_mx_sdhc_data {
>> + void (*init_hw)(struct mmc_host *mmc);
>> + void (*set_pdma)(struct mmc_host *mmc);
>> + void (*wait_before_send)(struct mmc_host *mmc);
>> + bool hardware_flush_all_cmds;
>> +};
>> +
>> +struct meson_mx_sdhc_host {
>> + struct mmc_host *mmc;
>> +
>> + struct mmc_request *mrq;
>> + struct mmc_command *cmd;
>> + int error;
>> +
>> + struct regmap *regmap;
>> +
>> + struct clk *pclk;
>> + struct clk *sd_clk;
>> + struct clk_bulk_data bulk_clks[MESON_SDHC_NUM_BULK_CLKS];
>> + bool bulk_clks_enabled;
>> +
>> + const struct meson_mx_sdhc_data *platform;
>> +};
>> +
>> +static const struct regmap_config meson_mx_sdhc_regmap_config = {
>> + .reg_bits = 8,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> + .max_register = MESON_SDHC_CLK2,
>> +};
>> +
>> +static void meson_mx_sdhc_hw_reset(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_MAIN_CTRL |
>> + MESON_SDHC_SRST_RXFIFO | MESON_SDHC_SRST_TXFIFO |
>> + MESON_SDHC_SRST_DPHY_RX | MESON_SDHC_SRST_DPHY_TX |
>> + MESON_SDHC_SRST_DMA_IF);
>> + usleep_range(10, 100);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_SRST, 0);
>> + usleep_range(10, 100);
>> +}
>> +
>> +static void meson_mx_sdhc_clear_fifo(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 stat;
>> +
>> + regmap_read(host->regmap, MESON_SDHC_STAT, &stat);
>> + if (!FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) &&
>> + !FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat))
>> + return;
>> +
>> + regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_RXFIFO |
>> + MESON_SDHC_SRST_TXFIFO | MESON_SDHC_SRST_MAIN_CTRL);
>> + udelay(5);
>> +
>> + regmap_read(host->regmap, MESON_SDHC_STAT, &stat);
>> + if (FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) ||
>> + FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat))
>> + dev_warn(mmc_dev(host->mmc),
>> + "Failed to clear FIFOs, RX: %lu, TX: %lu\n",
>> + FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat),
>> + FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat));
>> +}
>> +
>> +static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 stat, esta;
>> + int ret;
>> +
>> + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_STAT, stat,
>> + !(stat & MESON_SDHC_STAT_CMD_BUSY),
>> + MESON_SDHC_WAIT_CMD_READY_SLEEP_US,
>> + MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US);
>> + if (ret) {
>> + dev_warn(mmc_dev(mmc),
>> + "Failed to poll for CMD_BUSY while processing CMD%d\n",
>> + host->cmd->opcode);
>> + meson_mx_sdhc_hw_reset(mmc);
>> + }
>> +
>> + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, esta,
>> + !(esta & MESON_SDHC_ESTA_11_13),
>> + MESON_SDHC_WAIT_CMD_READY_SLEEP_US,
>> + MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US);
>> + if (ret) {
>> + dev_warn(mmc_dev(mmc),
>> + "Failed to poll for ESTA[13:11] while processing CMD%d\n",
>> + host->cmd->opcode);
>> + meson_mx_sdhc_hw_reset(mmc);
>> + }
>> +}
>> +
>> +static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
>> + struct mmc_command *cmd)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 ictl, send;
>> + int pack_len;
>> +
>> + host->cmd = cmd;
>> +
>> + ictl = MESON_SDHC_ICTL_DATA_TIMEOUT | MESON_SDHC_ICTL_DATA_ERR_CRC |
>> + MESON_SDHC_ICTL_RXFIFO_FULL | MESON_SDHC_ICTL_TXFIFO_EMPTY |
>> + MESON_SDHC_ICTL_RESP_TIMEOUT | MESON_SDHC_ICTL_RESP_ERR_CRC;
>> +
>> + send = FIELD_PREP(MESON_SDHC_SEND_CMD_INDEX, cmd->opcode);
>> +
>> + if (cmd->data) {
>> + send |= MESON_SDHC_SEND_CMD_HAS_DATA;
>> + send |= FIELD_PREP(MESON_SDHC_SEND_TOTAL_PACK,
>> + cmd->data->blocks - 1);
>> +
>> + if (cmd->data->blksz < MESON_SDHC_MAX_BLK_SIZE)
>> + pack_len = cmd->data->blksz;
>> + else
>> + pack_len = 0;
>> +
>> + if (cmd->data->flags & MMC_DATA_WRITE)
>> + send |= MESON_SDHC_SEND_DATA_DIR;
>> +
>> + /*
>> + * If command with no data, just wait response done
>> + * interrupt(int[0]), and if command with data transfer, just
>> + * wait dma done interrupt(int[11]), don't need care about
>> + * dat0 busy or not.
>> + */
>> + if (host->platform->hardware_flush_all_cmds ||
>> + cmd->data->flags & MMC_DATA_WRITE)
>> + /* hardware flush: */
>> + ictl |= MESON_SDHC_ICTL_DMA_DONE;
>> + else
>> + /* software flush: */
>> + ictl |= MESON_SDHC_ICTL_DATA_XFER_OK;
>> + } else {
>> + pack_len = 0;
>> +
>> + ictl |= MESON_SDHC_ICTL_RESP_OK;
>> + }
>> +
>> + if (cmd->opcode == MMC_STOP_TRANSMISSION)
>> + send |= MESON_SDHC_SEND_DATA_STOP;
>> +
>> + if (cmd->flags & MMC_RSP_PRESENT)
>> + send |= MESON_SDHC_SEND_CMD_HAS_RESP;
>> +
>> + if (cmd->flags & MMC_RSP_136) {
>> + send |= MESON_SDHC_SEND_RESP_LEN;
>> + send |= MESON_SDHC_SEND_RESP_NO_CRC;
>> + }
>> +
>> + if (!(cmd->flags & MMC_RSP_CRC))
>> + send |= MESON_SDHC_SEND_RESP_NO_CRC;
>> +
>> + if (cmd->flags & MMC_RSP_BUSY)
>> + send |= MESON_SDHC_SEND_R1B;
>> +
>> + /* enable the new IRQs and mask all pending ones */
>> + regmap_write(host->regmap, MESON_SDHC_ICTL, ictl);
>> + regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_ARGU, cmd->arg);
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_CTRL,
>> + MESON_SDHC_CTRL_PACK_LEN,
>> + FIELD_PREP(MESON_SDHC_CTRL_PACK_LEN, pack_len));
>> +
>> + if (cmd->data)
>> + regmap_write(host->regmap, MESON_SDHC_ADDR,
>> + sg_dma_address(cmd->data->sg));
>> +
>> + meson_mx_sdhc_wait_cmd_ready(mmc);
>> +
>> + if (cmd->data)
>> + host->platform->set_pdma(mmc);
>> +
>> + if (host->platform->wait_before_send)
>> + host->platform->wait_before_send(mmc);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_SEND, send);
>> +}
>> +
>> +static void meson_mx_sdhc_disable_clks(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + if (!host->bulk_clks_enabled)
>> + return;
>> +
>> + clk_bulk_disable_unprepare(MESON_SDHC_NUM_BULK_CLKS, host->bulk_clks);
>> +
>> + host->bulk_clks_enabled = false;
>> +}
>> +
>> +static int meson_mx_sdhc_enable_clks(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + int ret;
>> +
>> + if (host->bulk_clks_enabled)
>> + return 0;
>> +
>> + ret = clk_bulk_prepare_enable(MESON_SDHC_NUM_BULK_CLKS,
>> + host->bulk_clks);
>> + if (ret)
>> + return ret;
>> +
>> + host->bulk_clks_enabled = true;
>> +
>> + return 0;
>> +}
>> +
>> +static int meson_mx_sdhc_set_clk(struct mmc_host *mmc, struct mmc_ios *ios)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 rx_clk_phase;
>> + int ret;
>> +
>> + meson_mx_sdhc_disable_clks(mmc);
>> +
>> + if (ios->clock) {
>> + ret = clk_set_rate(host->sd_clk, ios->clock);
>> + if (ret) {
>> + dev_warn(mmc_dev(mmc),
>> + "Failed to set MMC clock to %uHz: %d\n",
>> + ios->clock, host->error);
>> + return ret;
>> + }
>> +
>> + ret = meson_mx_sdhc_enable_clks(mmc);
>> + if (ret)
>> + return ret;
>> +
>> + mmc->actual_clock = clk_get_rate(host->sd_clk);
>> +
>> + /*
>> + * according to Amlogic the following latching points are
>> + * selected with empirical values, there is no (known) formula
>> + * to calculate these.
>> + */
>> + if (mmc->actual_clock > 100000000) {
>> + rx_clk_phase = 1;
>> + } else if (mmc->actual_clock > 45000000) {
>> + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
>> + rx_clk_phase = 15;
>> + else
>> + rx_clk_phase = 11;
>> + } else if (mmc->actual_clock >= 25000000) {
>> + rx_clk_phase = 15;
>> + } else if (mmc->actual_clock > 5000000) {
>> + rx_clk_phase = 23;
>> + } else if (mmc->actual_clock > 1000000) {
>> + rx_clk_phase = 55;
>> + } else {
>> + rx_clk_phase = 1061;
>> + }
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_CLK2,
>> + MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + rx_clk_phase));
>> + } else {
>> + mmc->actual_clock = 0;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void meson_mx_sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + unsigned short vdd = ios->vdd;
>> +
>> + switch (ios->power_mode) {
>> + case MMC_POWER_OFF:
>> + vdd = 0;
>> + fallthrough;
>> +
>> + case MMC_POWER_UP:
>> + if (!IS_ERR(mmc->supply.vmmc)) {
>> + host->error = mmc_regulator_set_ocr(mmc,
>> + mmc->supply.vmmc,
>> + vdd);
>> + if (host->error)
>> + return;
>> + }
>> +
>> + break;
>> +
>> + case MMC_POWER_ON:
>> + break;
>> + }
>> +
>> + host->error = meson_mx_sdhc_set_clk(mmc, ios);
>> + if (host->error)
>> + return;
>> +
>> + switch (ios->bus_width) {
>> + case MMC_BUS_WIDTH_1:
>> + regmap_update_bits(host->regmap, MESON_SDHC_CTRL,
>> + MESON_SDHC_CTRL_DAT_TYPE,
>> + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 0));
>> + break;
>> +
>> + case MMC_BUS_WIDTH_4:
>> + regmap_update_bits(host->regmap, MESON_SDHC_CTRL,
>> + MESON_SDHC_CTRL_DAT_TYPE,
>> + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 1));
>> + break;
>> +
>> + case MMC_BUS_WIDTH_8:
>> + regmap_update_bits(host->regmap, MESON_SDHC_CTRL,
>> + MESON_SDHC_CTRL_DAT_TYPE,
>> + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 2));
>> + break;
>> +
>> + default:
>> + dev_err(mmc_dev(mmc), "unsupported bus width: %d\n",
>> + ios->bus_width);
>> + host->error = -EINVAL;
>> + return;
>> + }
>> +}
>> +
>> +static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
>> +{
>> + struct mmc_data *data = mrq->data;
>> + int dma_len;
>> +
>> + if (!data)
>> + return 0;
>> +
>> + dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
>> + mmc_get_dma_dir(data));
>> + if (dma_len <= 0) {
>> + dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
>> + return -ENOMEM;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void meson_mx_sdhc_request(struct mmc_host *mmc, struct mmc_request *mrq)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + struct mmc_command *cmd = mrq->cmd;
>> +
>> + if (!host->error)
>> + host->error = meson_mx_sdhc_map_dma(mmc, mrq);
>> +
>> + if (host->error) {
>> + cmd->error = host->error;
>> + mmc_request_done(mmc, mrq);
>> + return;
>> + }
>> +
>> + host->mrq = mrq;
>> +
>> + meson_mx_sdhc_start_cmd(mmc, mrq->cmd);
>> +}
>> +
>> +static int meson_mx_sdhc_card_busy(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 stat;
>> +
>> + regmap_read(host->regmap, MESON_SDHC_STAT, &stat);
>> + return FIELD_GET(MESON_SDHC_STAT_DAT3_0, stat) == 0;
>> +}
>> +
>> +static bool meson_mx_sdhc_tuning_point_matches(struct mmc_host *mmc,
>> + u32 opcode)
>> +{
>> + unsigned int i, num_matches = 0;
>> + int ret;
>> +
>> + for (i = 0; i < MESON_SDHC_NUM_TUNING_TRIES; i++) {
>> + ret = mmc_send_tuning(mmc, opcode, NULL);
>> + if (!ret)
>> + num_matches++;
>> + }
>> +
>> + return num_matches == MESON_SDHC_NUM_TUNING_TRIES;
>> +}
>> +
>> +static int meson_mx_sdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + int div, start, len, best_start, best_len;
>> + int curr_phase, old_phase, new_phase;
>> + u32 val;
>> +
>> + len = 0;
>> + start = 0;
>> + best_len = 0;
>> +
>> + regmap_read(host->regmap, MESON_SDHC_CLK2, &val);
>> + old_phase = FIELD_GET(MESON_SDHC_CLK2_RX_CLK_PHASE, val);
>> +
>> + regmap_read(host->regmap, MESON_SDHC_CLKC, &val);
>> + div = FIELD_GET(MESON_SDHC_CLKC_CLK_DIV, val);
>> +
>> + for (curr_phase = 0; curr_phase <= div; curr_phase++) {
>> + regmap_update_bits(host->regmap, MESON_SDHC_CLK2,
>> + MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + curr_phase));
>> +
>> + if (meson_mx_sdhc_tuning_point_matches(mmc, opcode)) {
>> + if (!len) {
>> + start = curr_phase;
>> +
>> + dev_dbg(mmc_dev(mmc),
>> + "New RX phase window starts at %u\n",
>> + start);
>> + }
>> +
>> + len++;
>> + } else {
>> + if (len > best_len) {
>> + best_start = start;
>> + best_len = len;
>> +
>> + dev_dbg(mmc_dev(mmc),
>> + "New best RX phase window: %u - %u\n",
>> + best_start, best_start + best_len);
>> + }
>> +
>> + /* reset the current window */
>> + len = 0;
>> + }
>> + }
>> +
>> + if (len > best_len)
>> + /* the last window is the best (or possibly only) window */
>> + new_phase = start + (len / 2);
>> + else if (best_len)
>> + /* there was a better window than the last */
>> + new_phase = best_start + (best_len / 2);
>> + else
>> + /* no window was found at all, reset to the original phase */
>> + new_phase = old_phase;
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_CLK2,
>> + MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE,
>> + new_phase));
>> +
>> + if (!len && !best_len)
>> + return -EIO;
>> +
>> + dev_dbg(mmc_dev(mmc), "Tuned RX clock phase to %u\n", new_phase);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct mmc_host_ops meson_mx_sdhc_ops = {
>> + .hw_reset = meson_mx_sdhc_hw_reset,
>> + .request = meson_mx_sdhc_request,
>> + .set_ios = meson_mx_sdhc_set_ios,
>> + .card_busy = meson_mx_sdhc_card_busy,
>> + .execute_tuning = meson_mx_sdhc_execute_tuning,
>> + .get_cd = mmc_gpio_get_cd,
>> + .get_ro = mmc_gpio_get_ro,
>> +};
>> +
>> +static void meson_mx_sdhc_request_done(struct meson_mx_sdhc_host *host)
>> +{
>> + struct mmc_request *mrq = host->mrq;
>> + struct mmc_host *mmc = host->mmc;
>> +
>> + /* disable interrupts and mask all pending ones */
>> + regmap_update_bits(host->regmap, MESON_SDHC_ICTL,
>> + MESON_SDHC_ICTL_ALL_IRQS, 0);
>> + regmap_update_bits(host->regmap, MESON_SDHC_ISTA,
>> + MESON_SDHC_ISTA_ALL_IRQS, MESON_SDHC_ISTA_ALL_IRQS);
>> +
>> + host->mrq = NULL;
>> + host->cmd = NULL;
>> +
>> + mmc_request_done(mmc, mrq);
>> +}
>> +
>> +static u32 meson_mx_sdhc_read_response(struct meson_mx_sdhc_host *host, u8 idx)
>> +{
>> + u32 val;
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_DMA_MODE, 0);
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_PIO_RDRESP,
>> + FIELD_PREP(MESON_SDHC_PDMA_PIO_RDRESP, idx));
>> +
>> + regmap_read(host->regmap, MESON_SDHC_ARGU, &val);
>> +
>> + return val;
>> +}
>> +
>> +static irqreturn_t meson_mx_sdhc_irq(int irq, void *data)
>> +{
>> + struct meson_mx_sdhc_host *host = data;
>> + struct mmc_command *cmd = host->cmd;
>> + u32 ictl, ista;
>> +
>> + regmap_read(host->regmap, MESON_SDHC_ICTL, &ictl);
>> + regmap_read(host->regmap, MESON_SDHC_ISTA, &ista);
>> +
>> + if (!(ictl & ista))
>> + return IRQ_NONE;
>> +
>> + if (ista & MESON_SDHC_ISTA_RXFIFO_FULL ||
>> + ista & MESON_SDHC_ISTA_TXFIFO_EMPTY)
>> + cmd->error = -EIO;
>> + else if (ista & MESON_SDHC_ISTA_RESP_ERR_CRC)
>> + cmd->error = -EILSEQ;
>> + else if (ista & MESON_SDHC_ISTA_RESP_TIMEOUT)
>> + cmd->error = -ETIMEDOUT;
>> +
>> + if (cmd->data) {
>> + if (ista & MESON_SDHC_ISTA_DATA_ERR_CRC)
>> + cmd->data->error = -EILSEQ;
>> + else if (ista & MESON_SDHC_ISTA_DATA_TIMEOUT)
>> + cmd->data->error = -ETIMEDOUT;
>> + }
>> +
>> + if (cmd->error || (cmd->data && cmd->data->error))
>> + dev_dbg(mmc_dev(host->mmc), "CMD%d error, ISTA: 0x%08x\n",
>> + cmd->opcode, ista);
>> +
>> + return IRQ_WAKE_THREAD;
>> +}
>> +
>> +static irqreturn_t meson_mx_sdhc_irq_thread(int irq, void *irq_data)
>> +{
>> + struct meson_mx_sdhc_host *host = irq_data;
>> + struct mmc_command *cmd;
>> + u32 val;
>> +
>> + cmd = host->cmd;
>> + if (WARN_ON(!cmd))
>> + return IRQ_HANDLED;
>> +
>> + if (cmd->data && !cmd->data->error) {
>> + if (!host->platform->hardware_flush_all_cmds &&
>> + cmd->data->flags & MMC_DATA_READ) {
>> + meson_mx_sdhc_wait_cmd_ready(host->mmc);
>> +
>> + val = FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH,
>> + 2);
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH,
>> + val);
>> + }
>> +
>> + dma_unmap_sg(mmc_dev(host->mmc), cmd->data->sg,
>> + cmd->data->sg_len, mmc_get_dma_dir(cmd->data));
>> +
>> + cmd->data->bytes_xfered = cmd->data->blksz * cmd->data->blocks;
>> + }
>> +
>> + meson_mx_sdhc_wait_cmd_ready(host->mmc);
>> +
>> + if (cmd->flags & MMC_RSP_136) {
>> + cmd->resp[0] = meson_mx_sdhc_read_response(host, 4);
>> + cmd->resp[1] = meson_mx_sdhc_read_response(host, 3);
>> + cmd->resp[2] = meson_mx_sdhc_read_response(host, 2);
>> + cmd->resp[3] = meson_mx_sdhc_read_response(host, 1);
>> + } else {
>> + cmd->resp[0] = meson_mx_sdhc_read_response(host, 0);
>> + }
>> +
>> + if (cmd->error == -EIO || cmd->error == -ETIMEDOUT)
>> + meson_mx_sdhc_hw_reset(host->mmc);
>> + else if (cmd->data)
>> + /*
>> + * Clear the FIFOs after completing data transfers to prevent
>> + * corrupting data on write access. It's not clear why this is
>> + * needed (for reads and writes), but it mimics what the BSP
>> + * kernel did.
>> + */
>> + meson_mx_sdhc_clear_fifo(host->mmc);
>> +
>> + meson_mx_sdhc_request_done(host);
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static void meson_mx_sdhc_init_hw_meson8(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_MISC,
>> + FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 7) |
>> + FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) |
>> + FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2));
>> +
>> + regmap_write(host->regmap, MESON_SDHC_ENHC,
>> + FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 63) |
>> + MESON_SDHC_ENHC_MESON6_DMA_WR_RESP |
>> + FIELD_PREP(MESON_SDHC_ENHC_MESON6_RX_TIMEOUT, 255) |
>> + FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12));
>> +};
>> +
>> +static void meson_mx_sdhc_set_pdma_meson8(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + if (host->cmd->data->flags & MMC_DATA_WRITE)
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_DMA_MODE |
>> + MESON_SDHC_PDMA_RD_BURST |
>> + MESON_SDHC_PDMA_TXFIFO_FILL,
>> + MESON_SDHC_PDMA_DMA_MODE |
>> + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 31) |
>> + MESON_SDHC_PDMA_TXFIFO_FILL);
>> + else
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_DMA_MODE |
>> + MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH,
>> + MESON_SDHC_PDMA_DMA_MODE |
>> + FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH,
>> + 1));
>> +
>> + if (host->cmd->data->flags & MMC_DATA_WRITE)
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_RD_BURST,
>> + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15));
>> +}
>> +
>> +static void meson_mx_sdhc_wait_before_send_meson8(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> + u32 val;
>> + int ret;
>> +
>> + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, val,
>> + val == 0,
>> + MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US,
>> + MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US);
>> + if (ret)
>> + dev_warn(mmc_dev(mmc),
>> + "Failed to wait for ESTA to clear: 0x%08x\n", val);
>> +
>> + if (host->cmd->data && host->cmd->data->flags & MMC_DATA_WRITE) {
>> + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_STAT,
>> + val, val & MESON_SDHC_STAT_TXFIFO_CNT,
>> + MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US,
>> + MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US);
>> + if (ret)
>> + dev_warn(mmc_dev(mmc),
>> + "Failed to wait for TX FIFO to fill\n");
>> + }
>> +}
>> +
>> +static void meson_mx_sdhc_init_hw_meson8m2(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_MISC,
>> + FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 6) |
>> + FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) |
>> + FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2));
>> +
>> + regmap_write(host->regmap, MESON_SDHC_ENHC,
>> + FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 64) |
>> + FIELD_PREP(MESON_SDHC_ENHC_MESON8M2_DEBUG, 1) |
>> + MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE |
>> + FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12));
>> +}
>> +
>> +static void meson_mx_sdhc_set_pdma_meson8m2(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + regmap_update_bits(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_DMA_MODE, MESON_SDHC_PDMA_DMA_MODE);
>> +}
>> +
>> +static void meson_mx_sdhc_init_hw(struct mmc_host *mmc)
>> +{
>> + struct meson_mx_sdhc_host *host = mmc_priv(mmc);
>> +
>> + meson_mx_sdhc_hw_reset(mmc);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_CTRL,
>> + FIELD_PREP(MESON_SDHC_CTRL_RX_PERIOD, 0xf) |
>> + FIELD_PREP(MESON_SDHC_CTRL_RX_TIMEOUT, 0x7f) |
>> + FIELD_PREP(MESON_SDHC_CTRL_RX_ENDIAN, 0x7) |
>> + FIELD_PREP(MESON_SDHC_CTRL_TX_ENDIAN, 0x7));
>> +
>> + /*
>> + * start with a valid divider and enable the memory (un-setting
>> + * MESON_SDHC_CLKC_MEM_PWR_OFF).
>> + */
>> + regmap_write(host->regmap, MESON_SDHC_CLKC, MESON_SDHC_CLKC_CLK_DIV);
>> +
>> + regmap_write(host->regmap, MESON_SDHC_CLK2,
>> + FIELD_PREP(MESON_SDHC_CLK2_SD_CLK_PHASE, 1));
>> +
>> + regmap_write(host->regmap, MESON_SDHC_PDMA,
>> + MESON_SDHC_PDMA_DMA_URGENT |
>> + FIELD_PREP(MESON_SDHC_PDMA_WR_BURST, 7) |
>> + FIELD_PREP(MESON_SDHC_PDMA_TXFIFO_TH, 49) |
>> + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15) |
>> + FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_TH, 7));
>> +
>> + /* some initialization bits depend on the SoC: */
>> + host->platform->init_hw(mmc);
>> +
>> + /* disable and mask all interrupts: */
>> + regmap_write(host->regmap, MESON_SDHC_ICTL, 0);
>> + regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS);
>> +}
>> +
>> +static int meson_mx_sdhc_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct meson_mx_sdhc_host *host;
>> + struct mmc_host *mmc;
>> + void __iomem *base;
>> + int ret, irq;
>> +
>> + mmc = mmc_alloc_host(sizeof(*host), dev);
>> + if (!mmc)
>> + return -ENOMEM;
>> +
>> + ret = devm_add_action_or_reset(dev, (void(*)(void *))mmc_free_host,
>> + mmc);
>> + if (ret) {
>> + dev_err(dev, "Failed to register mmc_free_host action\n");
>> + return ret;
>> + }
>> +
>> + host = mmc_priv(mmc);
>> + host->mmc = mmc;
>> +
>> + platform_set_drvdata(pdev, host);
>> +
>> + host->platform = device_get_match_data(dev);
>> + if (!host->platform)
>> + return -EINVAL;
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + host->regmap = devm_regmap_init_mmio(dev, base,
>> + &meson_mx_sdhc_regmap_config);
>> + if (IS_ERR(host->regmap))
>> + return PTR_ERR(host->regmap);
>> +
>> + host->pclk = devm_clk_get(dev, "pclk");
>> + if (IS_ERR(host->pclk))
>> + return PTR_ERR(host->pclk);
>> +
>> + /* accessing any register requires the module clock to be enabled: */
>> + ret = clk_prepare_enable(host->pclk);
>> + if (ret) {
>> + dev_err(dev, "Failed to enable 'pclk' clock\n");
>> + return ret;
>> + }
>> +
>> + meson_mx_sdhc_init_hw(mmc);
>> +
>> + ret = meson_mx_sdhc_register_clkc(dev, base, host->bulk_clks);
>> + if (ret)
>> + goto err_disable_pclk;
>> +
>> + host->sd_clk = host->bulk_clks[1].clk;
>> +
>> + /* Get regulators and the supported OCR mask */
>> + ret = mmc_regulator_get_supply(mmc);
>> + if (ret)
>> + goto err_disable_pclk;
>> +
>> + mmc->max_req_size = SZ_128K;
>> + mmc->max_seg_size = mmc->max_req_size;
>> + mmc->max_blk_count = FIELD_GET(MESON_SDHC_SEND_TOTAL_PACK, ~0);
>> + mmc->max_blk_size = MESON_SDHC_MAX_BLK_SIZE;
>> + mmc->max_busy_timeout = 30 * MSEC_PER_SEC;
>> + mmc->f_min = clk_round_rate(host->sd_clk, 1);
>> + mmc->f_max = clk_round_rate(host->sd_clk, ULONG_MAX);
>> + mmc->max_current_180 = 300;
>> + mmc->max_current_330 = 300;
>> + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_HW_RESET;
>> + mmc->ops = &meson_mx_sdhc_ops;
>> +
>> + ret = mmc_of_parse(mmc);
>> + if (ret)
>> + goto err_disable_pclk;
>> +
>> + irq = platform_get_irq(pdev, 0);
>> + ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq,
>> + meson_mx_sdhc_irq_thread, IRQF_ONESHOT,
>> + NULL, host);
>> + if (ret)
>> + goto err_disable_pclk;
>> +
>> + ret = mmc_add_host(mmc);
>> + if (ret)
>> + goto err_disable_pclk;
>> +
>> + return 0;
>> +
>> +err_disable_pclk:
>> + clk_disable_unprepare(host->pclk);
>> + return ret;
>> +}
>> +
>> +static int meson_mx_sdhc_remove(struct platform_device *pdev)
>> +{
>> + struct meson_mx_sdhc_host *host = platform_get_drvdata(pdev);
>> +
>> + mmc_remove_host(host->mmc);
>> +
>> + meson_mx_sdhc_disable_clks(host->mmc);
>> +
>> + clk_disable_unprepare(host->pclk);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8 = {
>> + .init_hw = meson_mx_sdhc_init_hw_meson8,
>> + .set_pdma = meson_mx_sdhc_set_pdma_meson8,
>> + .wait_before_send = meson_mx_sdhc_wait_before_send_meson8,
>> + .hardware_flush_all_cmds = false,
>> +};
>> +
>> +static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8m2 = {
>> + .init_hw = meson_mx_sdhc_init_hw_meson8m2,
>> + .set_pdma = meson_mx_sdhc_set_pdma_meson8m2,
>> + .hardware_flush_all_cmds = true,
>> +};
>> +
>> +static const struct of_device_id meson_mx_sdhc_of_match[] = {
>> + {
>> + .compatible = "amlogic,meson8-sdhc",
>> + .data = &meson_mx_sdhc_data_meson8
>> + },
>> + {
>> + .compatible = "amlogic,meson8b-sdhc",
>> + .data = &meson_mx_sdhc_data_meson8
>> + },
>> + {
>> + .compatible = "amlogic,meson8m2-sdhc",
>> + .data = &meson_mx_sdhc_data_meson8m2
>> + },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match);
>> +
>> +static struct platform_driver meson_mx_sdhc_driver = {
>> + .probe = meson_mx_sdhc_probe,
>> + .remove = meson_mx_sdhc_remove,
>> + .driver = {
>> + .name = "meson-mx-sdhc",
>> + .of_match_table = of_match_ptr(meson_mx_sdhc_of_match),
>> + },
>> +};
>> +
>> +module_platform_driver(meson_mx_sdhc_driver);
>> +
>> +MODULE_DESCRIPTION("Meson6, Meson8, Meson8b and Meson8m2 SDHC Host Driver");
>> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/mmc/host/meson-mx-sdhc.h b/drivers/mmc/host/meson-mx-sdhc.h
>> new file mode 100644
>> index 000000000000..230e8fbe6b3f
>> --- /dev/null
>> +++ b/drivers/mmc/host/meson-mx-sdhc.h
>> @@ -0,0 +1,141 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> + */
>> +
>> +#ifndef _MESON_MX_SDHC_H_
>> +#define _MESON_MX_SDHC_H_
>> +
>> +#include <linux/bitfield.h>
>> +
>> +#define MESON_SDHC_ARGU 0x00
>> +
>> +#define MESON_SDHC_SEND 0x04
>> + #define MESON_SDHC_SEND_CMD_INDEX GENMASK(5, 0)
>> + #define MESON_SDHC_SEND_CMD_HAS_RESP BIT(6)
>> + #define MESON_SDHC_SEND_CMD_HAS_DATA BIT(7)
>> + #define MESON_SDHC_SEND_RESP_LEN BIT(8)
>> + #define MESON_SDHC_SEND_RESP_NO_CRC BIT(9)
>> + #define MESON_SDHC_SEND_DATA_DIR BIT(10)
>> + #define MESON_SDHC_SEND_DATA_STOP BIT(11)
>> + #define MESON_SDHC_SEND_R1B BIT(12)
>> + #define MESON_SDHC_SEND_TOTAL_PACK GENMASK(31, 16)
>> +
>> +#define MESON_SDHC_CTRL 0x08
>> + #define MESON_SDHC_CTRL_DAT_TYPE GENMASK(1, 0)
>> + #define MESON_SDHC_CTRL_DDR_MODE BIT(2)
>> + #define MESON_SDHC_CTRL_TX_CRC_NOCHECK BIT(3)
>> + #define MESON_SDHC_CTRL_PACK_LEN GENMASK(12, 4)
>> + #define MESON_SDHC_CTRL_RX_TIMEOUT GENMASK(19, 13)
>> + #define MESON_SDHC_CTRL_RX_PERIOD GENMASK(23, 20)
>> + #define MESON_SDHC_CTRL_RX_ENDIAN GENMASK(26, 24)
>> + #define MESON_SDHC_CTRL_SDIO_IRQ_MODE BIT(27)
>> + #define MESON_SDHC_CTRL_DAT0_IRQ_SEL BIT(28)
>> + #define MESON_SDHC_CTRL_TX_ENDIAN GENMASK(31, 29)
>> +
>> +#define MESON_SDHC_STAT 0x0c
>> + #define MESON_SDHC_STAT_CMD_BUSY BIT(0)
>> + #define MESON_SDHC_STAT_DAT3_0 GENMASK(4, 1)
>> + #define MESON_SDHC_STAT_CMD BIT(5)
>> + #define MESON_SDHC_STAT_RXFIFO_CNT GENMASK(12, 6)
>> + #define MESON_SDHC_STAT_TXFIFO_CNT GENMASK(19, 13)
>> + #define MESON_SDHC_STAT_DAT7_4 GENMASK(23, 20)
>> +
>> +#define MESON_SDHC_CLKC 0x10
>> + #define MESON_SDHC_CLKC_CLK_DIV GENMASK(11, 0)
>> + #define MESON_SDHC_CLKC_CLK_JIC BIT(24)
>> + #define MESON_SDHC_CLKC_MEM_PWR_OFF GENMASK(26, 25)
>> +
>> +#define MESON_SDHC_ADDR 0x14
>> +
>> +#define MESON_SDHC_PDMA 0x18
>> + #define MESON_SDHC_PDMA_DMA_MODE BIT(0)
>> + #define MESON_SDHC_PDMA_PIO_RDRESP GENMASK(3, 1)
>> + #define MESON_SDHC_PDMA_DMA_URGENT BIT(4)
>> + #define MESON_SDHC_PDMA_WR_BURST GENMASK(9, 5)
>> + #define MESON_SDHC_PDMA_RD_BURST GENMASK(14, 10)
>> + #define MESON_SDHC_PDMA_RXFIFO_TH GENMASK(21, 15)
>> + #define MESON_SDHC_PDMA_TXFIFO_TH GENMASK(28, 22)
>> + #define MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH GENMASK(30, 29)
>> + #define MESON_SDHC_PDMA_TXFIFO_FILL BIT(31)
>> +
>> +#define MESON_SDHC_MISC 0x1c
>> + #define MESON_SDHC_MISC_WCRC_ERR_PATT GENMASK(6, 4)
>> + #define MESON_SDHC_MISC_WCRC_OK_PATT GENMASK(9, 7)
>> + #define MESON_SDHC_MISC_BURST_NUM GENMASK(21, 16)
>> + #define MESON_SDHC_MISC_THREAD_ID GENMASK(27, 22)
>> + #define MESON_SDHC_MISC_MANUAL_STOP BIT(28)
>> + #define MESON_SDHC_MISC_TXSTART_THRES GENMASK(31, 29)
>> +
>> +#define MESON_SDHC_DATA 0x20
>> +
>> +#define MESON_SDHC_ICTL 0x24
>> + #define MESON_SDHC_ICTL_RESP_OK BIT(0)
>> + #define MESON_SDHC_ICTL_RESP_TIMEOUT BIT(1)
>> + #define MESON_SDHC_ICTL_RESP_ERR_CRC BIT(2)
>> + #define MESON_SDHC_ICTL_RESP_OK_NOCLEAR BIT(3)
>> + #define MESON_SDHC_ICTL_DATA_1PACK_OK BIT(4)
>> + #define MESON_SDHC_ICTL_DATA_TIMEOUT BIT(5)
>> + #define MESON_SDHC_ICTL_DATA_ERR_CRC BIT(6)
>> + #define MESON_SDHC_ICTL_DATA_XFER_OK BIT(7)
>> + #define MESON_SDHC_ICTL_RX_HIGHER BIT(8)
>> + #define MESON_SDHC_ICTL_RX_LOWER BIT(9)
>> + #define MESON_SDHC_ICTL_DAT1_IRQ BIT(10)
>> + #define MESON_SDHC_ICTL_DMA_DONE BIT(11)
>> + #define MESON_SDHC_ICTL_RXFIFO_FULL BIT(12)
>> + #define MESON_SDHC_ICTL_TXFIFO_EMPTY BIT(13)
>> + #define MESON_SDHC_ICTL_ADDI_DAT1_IRQ BIT(14)
>> + #define MESON_SDHC_ICTL_ALL_IRQS GENMASK(14, 0)
>> + #define MESON_SDHC_ICTL_DAT1_IRQ_DELAY GENMASK(17, 16)
>> +
>> +#define MESON_SDHC_ISTA 0x28
>> + #define MESON_SDHC_ISTA_RESP_OK BIT(0)
>> + #define MESON_SDHC_ISTA_RESP_TIMEOUT BIT(1)
>> + #define MESON_SDHC_ISTA_RESP_ERR_CRC BIT(2)
>> + #define MESON_SDHC_ISTA_RESP_OK_NOCLEAR BIT(3)
>> + #define MESON_SDHC_ISTA_DATA_1PACK_OK BIT(4)
>> + #define MESON_SDHC_ISTA_DATA_TIMEOUT BIT(5)
>> + #define MESON_SDHC_ISTA_DATA_ERR_CRC BIT(6)
>> + #define MESON_SDHC_ISTA_DATA_XFER_OK BIT(7)
>> + #define MESON_SDHC_ISTA_RX_HIGHER BIT(8)
>> + #define MESON_SDHC_ISTA_RX_LOWER BIT(9)
>> + #define MESON_SDHC_ISTA_DAT1_IRQ BIT(10)
>> + #define MESON_SDHC_ISTA_DMA_DONE BIT(11)
>> + #define MESON_SDHC_ISTA_RXFIFO_FULL BIT(12)
>> + #define MESON_SDHC_ISTA_TXFIFO_EMPTY BIT(13)
>> + #define MESON_SDHC_ISTA_ADDI_DAT1_IRQ BIT(14)
>> + #define MESON_SDHC_ISTA_ALL_IRQS GENMASK(14, 0)
>> +
>> +#define MESON_SDHC_SRST 0x2c
>> + #define MESON_SDHC_SRST_MAIN_CTRL BIT(0)
>> + #define MESON_SDHC_SRST_RXFIFO BIT(1)
>> + #define MESON_SDHC_SRST_TXFIFO BIT(2)
>> + #define MESON_SDHC_SRST_DPHY_RX BIT(3)
>> + #define MESON_SDHC_SRST_DPHY_TX BIT(4)
>> + #define MESON_SDHC_SRST_DMA_IF BIT(5)
>> +
>> +#define MESON_SDHC_ESTA 0x30
>> + #define MESON_SDHC_ESTA_11_13 GENMASK(13, 11)
>> +
>> +#define MESON_SDHC_ENHC 0x34
>> + #define MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE BIT(0)
>> + #define MESON_SDHC_ENHC_MESON8M2_CHK_WRRSP BIT(1)
>> + #define MESON_SDHC_ENHC_MESON8M2_CHK_DMA BIT(2)
>> + #define MESON_SDHC_ENHC_MESON8M2_DEBUG GENMASK(5, 3)
>> + #define MESON_SDHC_ENHC_MESON6_RX_TIMEOUT GENMASK(7, 0)
>> + #define MESON_SDHC_ENHC_MESON6_DMA_RD_RESP BIT(16)
>> + #define MESON_SDHC_ENHC_MESON6_DMA_WR_RESP BIT(17)
>> + #define MESON_SDHC_ENHC_SDIO_IRQ_PERIOD GENMASK(15, 8)
>> + #define MESON_SDHC_ENHC_RXFIFO_TH GENMASK(24, 18)
>> + #define MESON_SDHC_ENHC_TXFIFO_TH GENMASK(31, 25)
>> +
>> +#define MESON_SDHC_CLK2 0x38
>> + #define MESON_SDHC_CLK2_RX_CLK_PHASE GENMASK(11, 0)
>> + #define MESON_SDHC_CLK2_SD_CLK_PHASE GENMASK(23, 12)
>> +
>> +struct clk_bulk_data;
>> +
>> +int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,
>> + struct clk_bulk_data *clk_bulk_data);
>> +
>> +#endif /* _MESON_MX_SDHC_H_ */
>> --
>> 2.26.2
>>
^ permalink raw reply
* [PATCH net-next v1] net: phy: tja11xx: add cable-test support
From: Oleksij Rempel @ 2020-05-13 12:34 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli, Heiner Kallweit, Mark Rutland,
Rob Herring
Cc: Oleksij Rempel, Pengutronix Kernel Team, linux-kernel,
David S. Miller, netdev, Marek Vasut, David Jander, devicetree
Add initial cable testing support.
This PHY needs only 100usec for this test and it is recommended to run it
before the link is up. For now, provide at least ethtool support, so it
can be tested by more developers.
This patch was tested with TJA1102 PHY with following results:
- No cable, is detected as open
- 1m cable, with no connected other end and detected as open
- a 40m cable (out of spec, max lenght should be 15m) is detected as OK.
Current patch do not provide polarity test support. This test would
indicate not proper wire connection, where "+" wire of main phy is
connected to the "-" wire of the link partner.
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
drivers/net/phy/nxp-tja11xx.c | 106 +++++++++++++++++++++++++++++++++-
1 file changed, 105 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index ca5f9d4dc57ed..8b743d25002b9 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -5,6 +5,7 @@
*/
#include <linux/delay.h>
#include <linux/ethtool.h>
+#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
#include <linux/mdio.h>
#include <linux/mii.h>
@@ -26,6 +27,7 @@
#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11)
#define MII_ECTRL_POWER_MODE_NORMAL (0x3 << 11)
#define MII_ECTRL_POWER_MODE_STANDBY (0xc << 11)
+#define MII_ECTRL_CABLE_TEST BIT(5)
#define MII_ECTRL_CONFIG_EN BIT(2)
#define MII_ECTRL_WAKE_REQUEST BIT(0)
@@ -55,6 +57,11 @@
#define MII_GENSTAT 24
#define MII_GENSTAT_PLL_LOCKED BIT(14)
+#define MII_EXTSTAT 25
+#define MII_EXTSTAT_SHORT_DETECT BIT(8)
+#define MII_EXTSTAT_OPEN_DETECT BIT(7)
+#define MII_EXTSTAT_POLARITY_DETECT BIT(6)
+
#define MII_COMMCFG 27
#define MII_COMMCFG_AUTO_OP BIT(15)
@@ -111,6 +118,11 @@ static int tja11xx_enable_link_control(struct phy_device *phydev)
return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
}
+static int tja11xx_disable_link_control(struct phy_device *phydev)
+{
+ return phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
+}
+
static int tja11xx_wakeup(struct phy_device *phydev)
{
int ret;
@@ -536,6 +548,93 @@ static int tja11xx_config_intr(struct phy_device *phydev)
return phy_write(phydev, MII_INTEN, value);
}
+static int tja11xx_cable_test_start(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_clear_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
+ if (ret)
+ return ret;
+
+ ret = tja11xx_wakeup(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = tja11xx_disable_link_control(phydev);
+ if (ret < 0)
+ return ret;
+
+ return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_CABLE_TEST);
+}
+
+/*
+ * | BI_DA+ | BI_DA- | Result
+ * | open | open | open
+ * | + short to - | - short to + | short
+ * | short to Vdd | open | open
+ * | open | shot to Vdd | open
+ * | short to Vdd | short to Vdd | short
+ * | shot to GND | open | open
+ * | open | shot to GND | open
+ * | short to GND | shot to GND | short
+ * | connected to active link partner (master) | shot and open
+ */
+static int tja11xx_cable_test_report_trans(u32 result)
+{
+ u32 mask = MII_EXTSTAT_SHORT_DETECT | MII_EXTSTAT_OPEN_DETECT;
+
+ if ((result & mask) == mask) {
+ /* connected to active link partner (master) */
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+ } else if ((result & mask) == 0) {
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
+ } else if (result & MII_EXTSTAT_SHORT_DETECT) {
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
+ } else if (result & MII_EXTSTAT_OPEN_DETECT) {
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ } else {
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+ }
+}
+
+static int tja11xx_cable_test_report(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_EXTSTAT);
+ if (ret < 0)
+ return ret;
+
+ ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
+ tja11xx_cable_test_report_trans(ret));
+
+ return 0;
+}
+
+static int tja11xx_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ int ret;
+
+ *finished = false;
+
+ ret = phy_read(phydev, MII_ECTRL);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & MII_ECTRL_CABLE_TEST)) {
+ *finished = true;
+
+ ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
+ if (ret)
+ return ret;
+
+ return tja11xx_cable_test_report(phydev);
+ }
+
+ return 0;
+}
+
static struct phy_driver tja11xx_driver[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
@@ -572,6 +671,7 @@ static struct phy_driver tja11xx_driver[] = {
}, {
.name = "NXP TJA1102 Port 0",
.features = PHY_BASIC_T1_FEATURES,
+ .flags = PHY_POLL_CABLE_TEST,
.probe = tja1102_p0_probe,
.soft_reset = tja11xx_soft_reset,
.config_aneg = tja11xx_config_aneg,
@@ -587,10 +687,12 @@ static struct phy_driver tja11xx_driver[] = {
.get_stats = tja11xx_get_stats,
.ack_interrupt = tja11xx_ack_interrupt,
.config_intr = tja11xx_config_intr,
-
+ .cable_test_start = tja11xx_cable_test_start,
+ .cable_test_get_status = tja11xx_cable_test_get_status,
}, {
.name = "NXP TJA1102 Port 1",
.features = PHY_BASIC_T1_FEATURES,
+ .flags = PHY_POLL_CABLE_TEST,
/* currently no probe for Port 1 is need */
.soft_reset = tja11xx_soft_reset,
.config_aneg = tja11xx_config_aneg,
@@ -606,6 +708,8 @@ static struct phy_driver tja11xx_driver[] = {
.get_stats = tja11xx_get_stats,
.ack_interrupt = tja11xx_ack_interrupt,
.config_intr = tja11xx_config_intr,
+ .cable_test_start = tja11xx_cable_test_start,
+ .cable_test_get_status = tja11xx_cable_test_get_status,
}
};
--
2.26.2
^ permalink raw reply related
* Re: [PATCH 13/17] spi: dw: Initialize paddr in DW SPI MMIO private data
From: Serge Semin @ 2020-05-13 12:30 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Mark Brown, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Stephen Boyd, Thomas Gleixner, YueHaibing,
Jarkko Nikula, linux-spi, linux-kernel
In-Reply-To: <20200508192144.GT185537@smile.fi.intel.com>
On Fri, May 08, 2020 at 10:21:44PM +0300, Andy Shevchenko wrote:
> On Fri, May 08, 2020 at 04:29:38PM +0300, Serge Semin wrote:
> > This field is used only for the DW SPI DMA code initialization, that's
> > why there were no problems with it being uninitialized in Dw SPI MMIO
> > driver. Since in a further patch we are going to introduce the DW SPI DMA
> > support in the MMIO version of the driver, lets set the field with the
> > physical address of the DW SPI controller registers region.
>
> ...
>
> > - dws->regs = devm_platform_ioremap_resource(pdev, 0);
> > + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + dws->regs = devm_ioremap_resource(&pdev->dev, mem);
>
> There is a helper
> dws->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
Oh, good point. It has been just added, in kernel v5.7. v5.6 didn't provide such
a convenient helper. Thanks for the suggestion.
-Sergey
>
>
> > if (IS_ERR(dws->regs)) {
> > dev_err(&pdev->dev, "SPI region map failed\n");
> > return PTR_ERR(dws->regs);
> > }
> > + dws->paddr = mem->start;
> >
> > dws->irq = platform_get_irq(pdev, 0);
> > if (dws->irq < 0)
> > --
> > 2.25.1
> >
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply
* Re: [PATCH v10 1/5] usb: xhci: Change the XHCI link order in the Makefile
From: Greg Kroah-Hartman @ 2020-05-13 12:26 UTC (permalink / raw)
To: Al Cooper
Cc: linux-kernel, Alan Stern, Andy Shevchenko,
bcm-kernel-feedback-list, devicetree, Krzysztof Kozlowski,
linux-usb, Mathias Nyman, Rob Herring, Yoshihiro Shimoda,
Andy Shevchenko
In-Reply-To: <20200512150019.25903-2-alcooperx@gmail.com>
On Tue, May 12, 2020 at 11:00:15AM -0400, Al Cooper wrote:
> Some BRCMSTB USB chips have an XHCI, EHCI and OHCI controller
> on the same port where XHCI handles 3.0 devices, EHCI handles 2.0
> devices and OHCI handles <2.0 devices. Currently the Makefile
> has XHCI linking at the bottom which will result in the XHIC driver
> initalizing after the EHCI and OHCI drivers and any installed 3.0
> device will be seen as a 2.0 device. Moving the XHCI linking
> above the EHCI and OHCI linking fixes the issue.
What happens if all of these are modules and they are loaded in a
different order? This makefile change will not help with that, you need
to have logic in the code in order to properly coordinate this type of
mess, sorry.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v9 1/4] dt-bindings: media: i2c: Add bindings for Maxim Integrated MAX9286
From: Jacopo Mondi @ 2020-05-13 12:28 UTC (permalink / raw)
To: Rob Herring
Cc: Kieran Bingham, linux-renesas-soc, linux-media, devicetree,
linux-kernel, Mauro Carvalho Chehab, Kieran Bingham,
Laurent Pinchart, Niklas Söderlund, sakari.ailus,
Hans Verkuil, Hyun Kwon, Manivannan Sadhasivam, Laurent Pinchart,
Jacopo Mondi, Niklas Söderlund
In-Reply-To: <20200512223610.GB23701@bogus>
Hi Rob,
On Tue, May 12, 2020 at 05:36:10PM -0500, Rob Herring wrote:
> On Tue, May 12, 2020 at 04:51:02PM +0100, Kieran Bingham wrote:
> > From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> >
> > The MAX9286 deserializes video data received on up to 4 Gigabit
> > Multimedia Serial Links (GMSL) and outputs them on a CSI-2 port using up
> > to 4 data lanes.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> > Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> >
> > ---
> >
> > v7:
> > - Collect Rob's RB tag
> > - Remove redundant maxItems from remote-endpoints
> > - Fix SPDX licence tag
> >
> > .../bindings/media/i2c/maxim,max9286.yaml | 287 ++++++++++++++++++
> > 1 file changed, 287 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
> > new file mode 100644
> > index 000000000000..f9d3e5712c59
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml
> > @@ -0,0 +1,287 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +# Copyright (C) 2019 Renesas Electronics Corp.
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/media/i2c/maxim,max9286.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Maxim Integrated Quad GMSL Deserializer
> > +
> > +maintainers:
> > + - Jacopo Mondi <jacopo+renesas@jmondi.org>
> > + - Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > + - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> > + - Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > +
> > +description: |
> > + The MAX9286 deserializer receives video data on up to 4 Gigabit Multimedia
> > + Serial Links (GMSL) and outputs them on a CSI-2 D-PHY port using up to 4 data
> > + lanes.
> > +
> > + In addition to video data, the GMSL links carry a bidirectional control
> > + channel that encapsulates I2C messages. The MAX9286 forwards all I2C traffic
> > + not addressed to itself to the other side of the links, where a GMSL
> > + serializer will output it on a local I2C bus. In the other direction all I2C
> > + traffic received over GMSL by the MAX9286 is output on the local I2C bus.
> > +
> > +properties:
> > + '#address-cells':
> > + const: 1
> > +
> > + '#size-cells':
> > + const: 0
> > +
> > + compatible:
> > + const: maxim,max9286
> > +
> > + reg:
> > + description: I2C device address
> > + maxItems: 1
> > +
> > + poc-supply:
> > + description: Regulator providing Power over Coax to the cameras
> > + maxItems: 1
> > +
> > + enable-gpios:
> > + description: GPIO connected to the \#PWDN pin with inverted polarity
> > + maxItems: 1
> > +
> > + ports:
> > + type: object
> > + description: |
> > + The connections to the MAX9286 GMSL and its endpoint nodes are modelled
> > + using the OF graph bindings in accordance with the video interface
> > + bindings defined in
> > + Documentation/devicetree/bindings/media/video-interfaces.txt.
> > +
> > + The following table lists the port number corresponding to each device
> > + port.
> > +
> > + Port Description
> > + ----------------------------------------
> > + Port 0 GMSL Input 0
> > + Port 1 GMSL Input 1
> > + Port 2 GMSL Input 2
> > + Port 3 GMSL Input 3
> > + Port 4 CSI-2 Output
> > +
> > + properties:
> > + '#address-cells':
> > + const: 1
> > +
> > + '#size-cells':
> > + const: 0
> > +
> > + port@[0-3]:
> > + type: object
> > + properties:
> > + reg:
> > + enum: [ 0, 1, 2, 3 ]
> > +
> > + endpoint:
> > + type: object
> > +
> > + properties:
> > + remote-endpoint:
> > + description: |
> > + phandle to the remote GMSL source endpoint subnode in the
> > + remote node port.
> > +
> > + required:
> > + - remote-endpoint
> > +
> > + required:
> > + - reg
> > + - endpoint
> > +
> > + additionalProperties: false
> > +
> > + port@4:
> > + type: object
> > + properties:
> > + reg:
> > + const: 4
> > +
> > + endpoint:
> > + type: object
> > +
> > + properties:
> > + remote-endpoint:
> > + description: phandle to the remote CSI-2 sink endpoint.
> > +
> > + data-lanes:
> > + description: array of physical CSI-2 data lane indexes.
> > +
> > + required:
> > + - remote-endpoint
> > + - data-lanes
> > +
> > + required:
> > + - reg
> > + - endpoint
> > +
> > + additionalProperties: false
> > +
> > + required:
> > + - port@4
> > +
> > + i2c-mux:
> > + type: object
> > + description: |
> > + Each GMSL link is modelled as a child bus of an i2c bus
> > + multiplexer/switch, in accordance with bindings described in
> > + Documentation/devicetree/bindings/i2c/i2c-mux.txt. The serializer
> > + device on the remote end of the GMSL link shall be modelled as a child
> > + node of the corresponding I2C bus.
> > +
> > + properties:
> > + '#address-cells':
> > + const: 1
> > +
> > + '#size-cells':
> > + const: 0
> > +
> > + additionalProperties: false
>
> Wrong indentation. Should be 2 more or this is a DT property.
>
Thanks, updating the dt tools helped spotting the error locally as
well.
This fixes the error reported in the previous email, now I get a
Documentation/devicetree/bindings/media/i2c/maxim,max9286.example.dt.yaml:
gmsl-deserializer@2c: i2c-mux: 'i2c@0', 'i2c@1', 'i2c@2', 'i2c@3' do not match any of the regexes: 'pinctrl-[0-9]+'
which makes me think the i2c-mux child nodes are under-specified in
this bindings.
I have expanded them and will reply with a fixup to be applied on top
of this patch to ease review and eventually include in v10.
Thanks
j
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - ports
> > + - i2c-mux
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/gpio/gpio.h>
> > +
> > + i2c@e66d8000 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + reg = <0 0xe66d8000 0 0x40>;
> > +
> > + gmsl-deserializer@2c {
> > + compatible = "maxim,max9286";
> > + reg = <0x2c>;
> > + poc-supply = <&camera_poc_12v>;
> > + enable-gpios = <&gpio 13 GPIO_ACTIVE_HIGH>;
> > +
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + port@0 {
> > + reg = <0>;
> > +
> > + max9286_in0: endpoint {
> > + remote-endpoint = <&rdacm20_out0>;
> > + };
> > + };
> > +
> > + port@1 {
> > + reg = <1>;
> > +
> > + max9286_in1: endpoint {
> > + remote-endpoint = <&rdacm20_out1>;
> > + };
> > + };
> > +
> > + port@2 {
> > + reg = <2>;
> > +
> > + max9286_in2: endpoint {
> > + remote-endpoint = <&rdacm20_out2>;
> > + };
> > + };
> > +
> > + port@3 {
> > + reg = <3>;
> > +
> > + max9286_in3: endpoint {
> > + remote-endpoint = <&rdacm20_out3>;
> > + };
> > + };
> > +
> > + port@4 {
> > + reg = <4>;
> > +
> > + max9286_out: endpoint {
> > + data-lanes = <1 2 3 4>;
> > + remote-endpoint = <&csi40_in>;
> > + };
> > + };
> > + };
> > +
> > + i2c-mux {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + i2c@0 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + reg = <0>;
> > +
> > + camera@51 {
> > + reg = <0x51>;
> > +
> > + port {
> > + rdacm20_out0: endpoint {
> > + remote-endpoint = <&max9286_in0>;
> > + };
> > + };
> > +
> > + };
> > + };
> > +
> > + i2c@1 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <1>;
> > +
> > + camera@52 {
> > + reg = <0x52>;
> > +
> > + port {
> > + rdacm20_out1: endpoint {
> > + remote-endpoint = <&max9286_in1>;
> > + };
> > + };
> > + };
> > + };
> > +
> > + i2c@2 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <2>;
> > +
> > + camera@53 {
> > + reg = <0x53>;
> > +
> > + port {
> > + rdacm20_out2: endpoint {
> > + remote-endpoint = <&max9286_in2>;
> > + };
> > + };
> > + };
> > + };
> > +
> > + i2c@3 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + reg = <3>;
> > +
> > + camera@54 {
> > + reg = <0x54>;
> > +
> > + port {
> > + rdacm20_out3: endpoint {
> > + remote-endpoint = <&max9286_in3>;
> > + };
> > + };
> > + };
> > + };
> > + };
> > + };
> > + };
> > --
> > 2.25.1
> >
^ permalink raw reply
* Re: [PATCH v2 5/6] irqchip: Add Loongson PCH MSI controller
From: Thomas Gleixner @ 2020-05-13 12:15 UTC (permalink / raw)
To: Jiaxun Yang, maz
Cc: Jiaxun Yang, Jason Cooper, Rob Herring, Huacai Chen, linux-kernel,
devicetree, linux-mips
In-Reply-To: <874ksk3uda.fsf@nanos.tec.linutronix.de>
Thomas Gleixner <tglx@linutronix.de> writes:
> Jiaxun Yang <jiaxun.yang@flygoat.com> writes:
>> +
>> +struct pch_msi_data {
>> + spinlock_t msi_map_lock;
>> + phys_addr_t doorbell;
>> + u32 irq_first; /* The vector number that MSIs starts */
>> + u32 num_irqs; /* The number of vectors for MSIs */
>> + unsigned long *msi_map;
>> +};
>> +
>> +static void pch_msi_mask_msi_irq(struct irq_data *d)
>> +{
>> + pci_msi_mask_irq(d);
>> + irq_chip_mask_parent(d);
>> +}
>> +
>> +static void pch_msi_unmask_msi_irq(struct irq_data *d)
>> +{
>> + pci_msi_unmask_irq(d);
>> + irq_chip_unmask_parent(d);
>
> The ordering of mask and unmask is assymetric. That does not make sense.
>
>> +static struct msi_domain_info pch_msi_domain_info = {
>> + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
>> + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
>> + .chip = &pch_msi_irq_chip,
>
> Please maintain tabular layout.
Ooops. Wanted to reply to V3, but the comments are valid for V3 as well.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH v2 5/6] irqchip: Add Loongson PCH MSI controller
From: Thomas Gleixner @ 2020-05-13 12:13 UTC (permalink / raw)
To: Jiaxun Yang, maz
Cc: Jiaxun Yang, Jason Cooper, Rob Herring, Huacai Chen, linux-kernel,
devicetree, linux-mips
In-Reply-To: <20200428063247.2223499-5-jiaxun.yang@flygoat.com>
Jiaxun Yang <jiaxun.yang@flygoat.com> writes:
> +
> +struct pch_msi_data {
> + spinlock_t msi_map_lock;
> + phys_addr_t doorbell;
> + u32 irq_first; /* The vector number that MSIs starts */
> + u32 num_irqs; /* The number of vectors for MSIs */
> + unsigned long *msi_map;
> +};
> +
> +static void pch_msi_mask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_mask_irq(d);
> + irq_chip_mask_parent(d);
> +}
> +
> +static void pch_msi_unmask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_unmask_irq(d);
> + irq_chip_unmask_parent(d);
The ordering of mask and unmask is assymetric. That does not make sense.
> +static struct msi_domain_info pch_msi_domain_info = {
> + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
> + .chip = &pch_msi_irq_chip,
Please maintain tabular layout.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH 1/5] spi: dt-bindings: sifive: Add missing 2nd register region
From: Mark Brown @ 2020-05-13 12:10 UTC (permalink / raw)
To: Rob Herring, devicetree
Cc: Paul Walmsley, linux-usb, linux-kernel, Palmer Dabbelt,
linux-riscv, Greg Kroah-Hartman, linux-spi, linux-clk
In-Reply-To: <20200512204543.22090-1-robh@kernel.org>
On Tue, 12 May 2020 15:45:39 -0500, Rob Herring wrote:
> The 'reg' description and example have a 2nd register region for memory
> mapped flash, but the schema says there is only 1 region. Fix this.
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-5.8
Thanks!
[1/1] spi: dt-bindings: sifive: Add missing 2nd register region
commit: b265b5a0ba15b6e00abce9bf162926e84b4323b4
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply
* Re: [PATCH v2 3/6] irqchip: Add Loongson PCH PIC controller
From: Thomas Gleixner @ 2020-05-13 12:09 UTC (permalink / raw)
To: Jiaxun Yang, maz
Cc: Jiaxun Yang, Jason Cooper, Rob Herring, Huacai Chen, linux-kernel,
devicetree, linux-mips
In-Reply-To: <20200428063247.2223499-3-jiaxun.yang@flygoat.com>
Jiaxun Yang <jiaxun.yang@flygoat.com> writes:
> +static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
> +{
> + void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
> + unsigned long flags;
> + u32 reg;
> +
> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
See other reply.
> + reg = readl(addr);
> + reg |= BIT(PIC_REG_BIT(bit));
> + writel(reg, addr);
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> +}
> +static int pch_pic_of_init(struct device_node *node,
> + struct device_node *parent)
> +{
> + struct pch_pic *priv;
> + struct irq_domain *parent_domain;
> + int err;
ordering
Thanks,
tglx
^ permalink raw reply
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