aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch5
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0051-arm64-renesas-r8a7798-Add-Renesas-R8A7798-SoC-suppor.patch8
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0110-Renesas-clk-Add-RPC-clock-source.patch263
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0111-Renesas-r8a7798-Add-RPC-clock.patch46
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-Renesas-r8a7798-pinctrl-Add-RPC-pin-control.patch119
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0113-Renesas-RPC-Add-RPC-driver.patch1483
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0114-R8A7798-dtsi-Add-RPC-node-to-dtsi.patch35
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0115-R8A7798-condor-dts-Add-qspi-flash.patch98
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0116-spi-nor-Add-s25fs512-flash-support.patch126
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0117-spi-nor-Add-flash-array-support.patch89
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0118-r8a7797-clk-Add-rpc-clock.patch45
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0119-r8a7797-pinctrl-Add-qspi-pins.patch118
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0120-r8a7797-dtsi-Add-rpc-node.patch35
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0121-r8a7797-eagle-dts-Add-spi-flash-node.patch96
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0122-r8a7797-v3msk-r8a7797-v3mzf-dts-Add-spi-flash-s25fs5.patch172
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0123-V3HSK-dts-Add-qspi-node.patch101
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0124-RPC-Hyperflash-Add-devicetree-support.patch219
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0125-r8a7797-pinctrl-Add-pin-function-for-hyperflash.patch70
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0126-r8a7798-pinctrl-Add-pin-function-for-hyperflash.patch69
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0127-IMR-UIO-Driver-initial-version.patch875
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0128-rcar_imr-v4l2-driver-Fix-module-support.patch321
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0129-Add-cropping-handling-to-VSP-alpha-planes.patch44
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0130-Add-RAW-sensors-MBUS-formats.patch36
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0131-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch (renamed from meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch)0
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/imr.cfg3
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg3
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg1
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3mzf.cfg2
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend35
34 files changed, 4503 insertions, 19 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
index 63c109a..42b8f23 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
@@ -79,7 +79,7 @@ new file mode 100644
index 0000000..faefe8a
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
-@@ -0,0 +1,1168 @@
+@@ -0,0 +1,1167 @@
+/*
+ * Device Tree Source for the r8a7797 SoC
+ *
@@ -1239,12 +1239,11 @@ index 0000000..faefe8a
+ isp0: isp@fec00000 {
+ compatible = "renesas,isp-r8a7797";
+ reg = <0 0xfec00000 0 0x20000>,
-+ <0 0xfed00000 0 0x4000>;
++ <0 0xfed00000 0 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 817>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
-+ status = "disabled";
+ };
+ };
+};
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0051-arm64-renesas-r8a7798-Add-Renesas-R8A7798-SoC-suppor.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0051-arm64-renesas-r8a7798-Add-Renesas-R8A7798-SoC-suppor.patch
index db09aab..d9eb2fa 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0051-arm64-renesas-r8a7798-Add-Renesas-R8A7798-SoC-suppor.patch
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0051-arm64-renesas-r8a7798-Add-Renesas-R8A7798-SoC-suppor.patch
@@ -79,7 +79,7 @@ new file mode 100644
index 0000000..00bd4d6
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
-@@ -0,0 +1,1724 @@
+@@ -0,0 +1,1722 @@
+/*
+ * Device Tree Source for the r8a7798 SoC
+ *
@@ -1784,23 +1784,21 @@ index 0000000..00bd4d6
+ isp0: isp@fec00000 {
+ compatible = "renesas,isp-r8a7798";
+ reg = <0 0xfec00000 0 0x20000>,
-+ <0 0xfed00000 0 0x4000>;
++ <0 0xfed00000 0 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 817>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
-+ status = "disabled";
+ };
+
+ isp1: isp@fee00000 {
+ compatible = "renesas,isp-r8a7798";
+ reg = <0 0xfee00000 0 0x20000>,
-+ <0 0xfed20000 0 0x4000>;
++ <0 0xfed20000 0 0x10000>;
+ interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 814>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
-+ status = "disabled";
+ };
+ };
+};
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0110-Renesas-clk-Add-RPC-clock-source.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0110-Renesas-clk-Add-RPC-clock-source.patch
new file mode 100644
index 0000000..37d08e9
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0110-Renesas-clk-Add-RPC-clock-source.patch
@@ -0,0 +1,263 @@
+From b4acae6eda19307e0051763a532f522006a82d5c Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 10:37:04 +0300
+Subject: [PATCH 01/12] Renesas: clk: Add RPC clock source
+
+Add RPC clock source functionality
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/clk/renesas/rcar-gen3-cpg.c | 200 ++++++++++++++++++++++++++++++++++++
+ drivers/clk/renesas/rcar-gen3-cpg.h | 4 +
+ 2 files changed, 204 insertions(+)
+
+diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
+index 99acba2..969e1b2 100644
+--- a/drivers/clk/renesas/rcar-gen3-cpg.c
++++ b/drivers/clk/renesas/rcar-gen3-cpg.c
+@@ -599,6 +599,7 @@ static const struct clk_div_table cpg_sd01_div_table[] = {
+ { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 },
+ };
+
++
+ #define CPG_SD_STP_HCK BIT(9)
+ #define CPG_SD_STP_CK BIT(8)
+
+@@ -811,6 +812,202 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
+ return clk;
+ }
+
++/**************** RPCSCK ***********************************/
++
++
++
++struct rpc_clock {
++ struct clk_hw hw;
++ void __iomem *reg;
++ const struct clk_div_table *div_table;
++ unsigned int div_num;
++ unsigned int div_min;
++ unsigned int div_max;
++};
++
++static const struct clk_div_table cpg_rpc_div_table[] = {
++ { 0x11, 20 }, { 0x13, 40 }, { 0x15, 60 }, { 0x17, 80 },
++ { 0x19, 24 }, { 0x1B, 48 }, { 0x1D, 72 }, { 0x1F, 96 },
++};
++
++#define to_rpc_clock(_hw) container_of(_hw, struct rpc_clock, hw)
++
++#define CPG_RPC_ENA_MASK (BIT(9) | BIT(8))
++#define CPG_RPC_SCALE_MASK (0x1F)
++
++
++static int cpg_rpc_clock_endisable(void __iomem *reg, bool enable)
++{
++ u32 val;
++
++ val = readl(reg);
++
++ if (enable)
++ val &= ~CPG_RPC_ENA_MASK;
++ else
++ val |= CPG_RPC_ENA_MASK;
++
++ writel(val, reg);
++ return 0;
++};
++
++static int cpg_rpc_clock_enable(struct clk_hw *hw)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++
++ cpg_rpc_clock_endisable(clock->reg, true);
++
++ return 0;
++}
++
++static void cpg_rpc_clock_disable(struct clk_hw *hw)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++
++ cpg_rpc_clock_endisable(clock->reg, false);
++}
++
++static int cpg_rpc_clock_is_enabled(struct clk_hw *hw)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++
++ return !(readl(clock->reg) & CPG_RPC_ENA_MASK);
++}
++
++static unsigned long cpg_rpc_clock_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++ unsigned long rate = parent_rate;
++ u32 val, scale;
++ unsigned int i;
++
++ val = readl(clock->reg);
++
++ scale = val & CPG_RPC_SCALE_MASK;
++ for (i = 0; i < clock->div_num; i++)
++ if (scale == clock->div_table[i].val)
++ break;
++
++ if (i >= clock->div_num)
++ return 0;
++
++ return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div);
++}
++
++static unsigned int cpg_rpc_clock_calc_div(struct rpc_clock *clock,
++ unsigned long rate,
++ unsigned long parent_rate)
++{
++ unsigned int div;
++
++ if (!rate)
++ rate = 1;
++
++ div = DIV_ROUND_CLOSEST(parent_rate, rate);
++
++ return clamp_t(unsigned int, div, clock->div_min, clock->div_max);
++}
++
++static long cpg_rpc_clock_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++ unsigned int div = cpg_rpc_clock_calc_div(clock, rate, *parent_rate);
++
++ return DIV_ROUND_CLOSEST(*parent_rate, div);
++}
++
++static int cpg_rpc_clock_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct rpc_clock *clock = to_rpc_clock(hw);
++ unsigned int div = cpg_rpc_clock_calc_div(clock, rate, parent_rate);
++ u32 val;
++ unsigned int i, nearest_i, nearest_div;
++
++
++ for (i = 0; i < clock->div_num; i++)
++ if (div == clock->div_table[i].div)
++ break;
++
++ if (i >= clock->div_num) {
++ /* find nearest */
++ nearest_div = -1;
++ nearest_i = clock->div_num;
++ for (i = 0; i < clock->div_num; i++) {
++ if (clock->div_table[i].div >= div &&
++ clock->div_table[i].div <= nearest_div) {
++ nearest_i = i;
++ nearest_div = clock->div_table[i].div;
++ }
++ }
++
++ i = nearest_i;
++ }
++
++ if (i >= clock->div_num)
++ return -EINVAL;
++
++ val = readl(clock->reg);
++ val &= ~CPG_RPC_SCALE_MASK;
++ val |= clock->div_table[i].val;
++ writel(val, clock->reg);
++
++ return 0;
++}
++
++static const struct clk_ops cpg_rpc_clock_ops = {
++ .enable = cpg_rpc_clock_enable,
++ .disable = cpg_rpc_clock_disable,
++ .is_enabled = cpg_rpc_clock_is_enabled,
++ .recalc_rate = cpg_rpc_clock_recalc_rate,
++ .round_rate = cpg_rpc_clock_round_rate,
++ .set_rate = cpg_rpc_clock_set_rate,
++};
++
++static struct clk * __init cpg_rpc_clk_register(const struct cpg_core_clk *core,
++ void __iomem *base,
++ const char *parent_name)
++{
++ struct clk_init_data init;
++ struct rpc_clock *clock;
++ struct clk *clk;
++ unsigned int i;
++
++ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
++ if (!clock)
++ return ERR_PTR(-ENOMEM);
++
++ init.name = core->name;
++ init.ops = &cpg_rpc_clock_ops;
++ init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
++ init.parent_names = &parent_name;
++ init.num_parents = 1;
++
++ clock->reg = base + core->offset;
++ clock->hw.init = &init;
++ clock->div_table = cpg_rpc_div_table;
++ clock->div_num = ARRAY_SIZE(cpg_rpc_div_table);
++
++ clock->div_max = clock->div_table[0].div;
++ clock->div_min = clock->div_max;
++ for (i = 1; i < clock->div_num; i++) {
++ clock->div_max = max(clock->div_max, clock->div_table[i].div);
++ clock->div_min = min(clock->div_min, clock->div_table[i].div);
++ }
++
++ clk = clk_register(NULL, &clock->hw);
++ if (IS_ERR(clk))
++ kfree(clock);
++
++ return clk;
++}
++
++/***********************************************************/
++
++
++
+
+ static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata;
+ static unsigned int cpg_clk_extalr __initdata;
+@@ -943,6 +1140,9 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
+ return cpg_zg_clk_register(core->name, __clk_get_name(parent),
+ base);
+
++ case CLK_TYPE_GEN3_RPCSRC:
++ return cpg_rpc_clk_register(core, base, __clk_get_name(parent));
++
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h
+index 694bedc..636ef54 100644
+--- a/drivers/clk/renesas/rcar-gen3-cpg.h
++++ b/drivers/clk/renesas/rcar-gen3-cpg.h
+@@ -27,6 +27,7 @@ enum rcar_gen3_clk_types {
+ CLK_TYPE_GEN3_ZG,
+ CLK_TYPE_GEN3_RINT,
+ CLK_TYPE_GEN3_OSC,
++ CLK_TYPE_GEN3_RPCSRC,
+ };
+
+ #define DEF_GEN3_SD(_name, _id, _parent, _offset) \
+@@ -36,6 +37,9 @@ enum rcar_gen3_clk_types {
+ #define DEF_GEN3_SD0H(_name, _id, _parent, _offset) \
+ DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD0H, _parent, .offset = _offset)
+
++#define DEF_GEN3_RPCSRC(_name, _id, _parent, _offset) \
++ DEF_BASE(_name, _id, CLK_TYPE_GEN3_RPCSRC, _parent, .offset = _offset)
++
+ struct rcar_gen3_cpg_pll_config {
+ unsigned int extal_div;
+ unsigned int pll1_mult;
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0111-Renesas-r8a7798-Add-RPC-clock.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0111-Renesas-r8a7798-Add-RPC-clock.patch
new file mode 100644
index 0000000..e0fb7d2
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0111-Renesas-r8a7798-Add-RPC-clock.patch
@@ -0,0 +1,46 @@
+From 05ab83db0e0012674a0255fe37a51713a1601732 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 10:42:50 +0300
+Subject: [PATCH 02/12] Renesas: r8a7798: Add RPC clock
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/clk/renesas/r8a7798-cpg-mssr.c | 3 +++
+ include/dt-bindings/clock/r8a7798-cpg-mssr.h | 1 +
+ 2 files changed, 4 insertions(+)
+
+diff --git a/drivers/clk/renesas/r8a7798-cpg-mssr.c b/drivers/clk/renesas/r8a7798-cpg-mssr.c
+index e407916..2614147 100644
+--- a/drivers/clk/renesas/r8a7798-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a7798-cpg-mssr.c
+@@ -90,6 +90,8 @@ static const struct cpg_core_clk r8a7798_core_clks[] __initconst = {
+
+ DEF_GEN3_SD("sd0", R8A7798_CLK_SD0, CLK_SDSRC, 0x0074), /* OK? */
+
++ DEF_GEN3_RPCSRC("rpcsrc", R8A7798_CLK_RPCSRC, CLK_PLL1, 0x0238),
++
+ DEF_FIXED("cl", R8A7798_CLK_CL, CLK_PLL1_DIV2, 48, 1),
+ DEF_FIXED("cp", R8A7798_CLK_CP, CLK_EXTAL, 2, 1),
+
+@@ -194,6 +196,7 @@ static const struct mssr_mod_clk r8a7798_mod_clks[] __initconst = {
+ DEF_MOD("gpio1", 911, R8A7798_CLK_CP),
+ DEF_MOD("gpio0", 912, R8A7798_CLK_CP),
+ DEF_MOD("can-fd", 914, R8A7798_CLK_S3D2),
++ DEF_MOD("rpc", 917, R8A7798_CLK_RPCSRC),
+ /* FIXME missing MSSR for i2c5; should it be 919 as in H3/M3? */
+ /* DEF_MOD("i2c4", 919, R8A7798_CLK_S3D2), */
+ DEF_MOD("i2c4", 927, R8A7798_CLK_S0D6),
+diff --git a/include/dt-bindings/clock/r8a7798-cpg-mssr.h b/include/dt-bindings/clock/r8a7798-cpg-mssr.h
+index 3d85730..821383d3 100644
+--- a/include/dt-bindings/clock/r8a7798-cpg-mssr.h
++++ b/include/dt-bindings/clock/r8a7798-cpg-mssr.h
+@@ -52,5 +52,6 @@
+ #define R8A7798_CLK_CPEX 36
+ #define R8A7798_CLK_R 37
+ #define R8A7798_CLK_OSC 38
++#define R8A7798_CLK_RPCSRC 39
+
+ #endif /* __DT_BINDINGS_CLOCK_R8A7798_CPG_MSSR_H__ */
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-Renesas-r8a7798-pinctrl-Add-RPC-pin-control.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-Renesas-r8a7798-pinctrl-Add-RPC-pin-control.patch
new file mode 100644
index 0000000..5c91f56
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-Renesas-r8a7798-pinctrl-Add-RPC-pin-control.patch
@@ -0,0 +1,119 @@
+From ba6a829c33809d780c40c3f60e97e8a9e2a99a92 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 10:48:44 +0300
+Subject: [PATCH 03/12] Renesas: r8a7798: pinctrl: Add RPC pin control
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/pinctrl/sh-pfc/pfc-r8a7798.c | 74 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+
+diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7798.c b/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
+index 39aba74..f20afd1 100644
+--- a/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
+@@ -1472,6 +1472,60 @@ static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+ };
+
++/* - QSPI ------------------------------------------------------------------- */
++static const unsigned int qspi0_ctrl_pins[] = {
++ /* QSPI0_SPCLK QSPI0_SSL */
++ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 0),
++};
++static const unsigned int qspi0_ctrl_mux[] = {
++ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
++};
++
++static const unsigned int qspi0_data2_pins[] = {
++ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
++};
++static const unsigned int qspi0_data2_mux[] = {
++ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
++};
++
++static const unsigned int qspi0_data4_pins[] = {
++ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
++ RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 4),
++};
++static const unsigned int qspi0_data4_mux[] = {
++ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
++ QSPI0_IO2_MARK, QSPI0_IO3_MARK
++};
++
++static const unsigned int qspi1_ctrl_pins[] = {
++ /* QSPI1_SPCLK QSPI1_SSL */
++ RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 11),
++};
++static const unsigned int qspi1_ctrl_mux[] = {
++ QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
++};
++
++static const unsigned int qspi1_data2_pins[] = {
++ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
++ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 8),
++};
++static const unsigned int qspi1_data2_mux[] = {
++ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
++};
++
++static const unsigned int qspi1_data4_pins[] = {
++ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */
++ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 8),
++ RCAR_GP_PIN(5, 9), RCAR_GP_PIN(5, 10),
++};
++static const unsigned int qspi1_data4_mux[] = {
++ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
++ QSPI1_IO2_MARK, QSPI1_IO3_MARK
++};
++
++
+ /* - I2C -------------------------------------------------------------------- */
+ static const unsigned int i2c0_pins[] = {
+ /* SDA0, SCL0 */
+@@ -2419,6 +2473,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(vin1_field),
+ SH_PFC_PIN_GROUP(vin1_clkenb),
+ SH_PFC_PIN_GROUP(vin1_clk),
++ SH_PFC_PIN_GROUP(qspi0_ctrl),
++ SH_PFC_PIN_GROUP(qspi0_data2),
++ SH_PFC_PIN_GROUP(qspi0_data4),
++ SH_PFC_PIN_GROUP(qspi1_ctrl),
++ SH_PFC_PIN_GROUP(qspi1_data2),
++ SH_PFC_PIN_GROUP(qspi1_data4),
+ };
+
+ static const char * const avb_groups[] = {
+@@ -2683,6 +2743,18 @@ static const char * const vin1_groups[] = {
+ "vin1_clk",
+ };
+
++static const char * const qspi0_groups[] = {
++ "qspi0_ctrl",
++ "qspi0_data2",
++ "qspi0_data4",
++};
++
++static const char * const qspi1_groups[] = {
++ "qspi1_ctrl",
++ "qspi1_data2",
++ "qspi1_data4",
++};
++
+ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(gether),
+@@ -2719,6 +2791,8 @@ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(vin0),
+ SH_PFC_FUNCTION(vin1),
++ SH_PFC_FUNCTION(qspi0),
++ SH_PFC_FUNCTION(qspi1),
+ };
+
+ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0113-Renesas-RPC-Add-RPC-driver.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0113-Renesas-RPC-Add-RPC-driver.patch
new file mode 100644
index 0000000..86b2d6c
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0113-Renesas-RPC-Add-RPC-driver.patch
@@ -0,0 +1,1483 @@
+From 931484f9bd4eb1741588dc1574080fa4534ac5dc Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 11:08:16 +0300
+Subject: [PATCH 04/12] Renesas: RPC: Add RPC driver
+
+This is initial commit. Driver supports single and dual mode.
+Dual mode means that there are two spi-nor flashes connected.
+Supports qspi flashes.
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/mtd/spi-nor/Kconfig | 8 +
+ drivers/mtd/spi-nor/Makefile | 1 +
+ drivers/mtd/spi-nor/renesas-rpc.c | 1429 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1438 insertions(+)
+ create mode 100644 drivers/mtd/spi-nor/renesas-rpc.c
+
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 4a682ee..298dc1d 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -7,6 +7,14 @@ menuconfig MTD_SPI_NOR
+
+ if MTD_SPI_NOR
+
++
++config SPI_RENESAS_RPC
++ tristate "Renesas RPC controller"
++ depends on ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A7797 || ARCH_R8A7798 || COMPILE_TEST
++ help
++ QSPI driver for Renesas SPI Multi I/O Bus controller. This controller
++ supports normal, dual and quad spi for one or two SPI NOR Flashes.
++
+ config MTD_MT81xx_NOR
+ tristate "Mediatek MT81xx SPI NOR flash controller"
+ depends on HAS_IOMEM
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index 121695e..e99d775 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -5,3 +5,4 @@ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
+ obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
+ obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
++obj-$(CONFIG_SPI_RENESAS_RPC) += renesas-rpc.o
+diff --git a/drivers/mtd/spi-nor/renesas-rpc.c b/drivers/mtd/spi-nor/renesas-rpc.c
+new file mode 100644
+index 0000000..1e93c98
+--- /dev/null
++++ b/drivers/mtd/spi-nor/renesas-rpc.c
+@@ -0,0 +1,1429 @@
++/*
++ * Renesas RPC driver
++ *
++ * Copyright (C) 2018, Cogent Embedded Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/mtd/spi-nor.h>
++
++
++
++#define CMNCR 0x0000
++#define SSLDR 0x0004
++#define DRCR 0x000C
++#define DRCMR 0x0010
++#define DREAR 0x0014
++#define DROPR 0x0018
++#define DRENR 0x001C
++#define SMCR 0x0020
++#define SMCMR 0x0024
++#define SMADR 0x0028
++#define SMOPR 0x002C
++#define SMENR 0x0030
++#define SMRDR0 0x0038
++#define SMRDR1 0x003C
++#define SMWDR0 0x0040
++#define SMWDR1 0x0044
++#define CMNSR 0x0048
++#define DRDMCR 0x0058
++#define DRDRENR 0x005C
++#define SMDMCR 0x0060
++#define SMDRENR 0x0064
++#define PHYCNT 0x007C
++#define PHYOFFSET1 0x0080
++#define PHYOFFSET2 0x0084
++#define PHYINT 0x0088
++#define DIV_REG 0x00A8
++
++/* CMNCR */
++#define CMNCR_BSZ_MASK (0x03)
++#define CMNCR_BSZ_4x1 (0x0)
++#define CMNCR_BSZ_8x1 (0x1)
++#define CMNCR_BSZ_4x2 (0x1)
++#define CMNCR_MD (0x1 << 31)
++#define CMNCR_MOIIO3_MASK (0x3 << 22)
++#define CMNCR_MOIIO3_HIZ (0x3 << 22)
++#define CMNCR_MOIIO2_MASK (0x3 << 20)
++#define CMNCR_MOIIO2_HIZ (0x3 << 20)
++#define CMNCR_MOIIO1_MASK (0x3 << 18)
++#define CMNCR_MOIIO1_HIZ (0x3 << 18)
++#define CMNCR_MOIIO0_MASK (0x3 << 16)
++#define CMNCR_MOIIO0_HIZ (0x3 << 16)
++#define CMNCR_IO0FV_MASK (0x3 << 8)
++#define CMNCR_IO0FV_HIZ (0x3 << 8)
++
++
++/* DRCR */
++#define DRCR_RBURST_MASK (0x1f << 16)
++#define DRCR_RBURST(v) (((v) & 0x1f) << 16)
++#define DRCR_SSLE (0x1)
++#define DRCR_RBE (0x1 << 8)
++#define DRCR_RCF (0x1 << 9)
++#define DRCR_RBURST_32 (0x1f << 16)
++
++
++/* SMENR */
++#define SMENR_CDB_MASK (0x03 << 30)
++#define SMENR_CDB(v) (((v) & 0x03) << 30)
++#define SMENR_CDB_1B (0)
++#define SMENR_CDB_2B (0x1 << 30)
++#define SMENR_CDB_4B (0x2 << 30)
++#define SMENR_OCDB_MASK (0x03 << 28)
++#define SMENR_OCDB_1B (0)
++#define SMENR_OCDB_2B (0x1 << 28)
++#define SMENR_OCDB_4B (0x2 << 28)
++#define SMENR_ADB_MASK (0x03 << 24)
++#define SMENR_ADB(v) (((v) & 0x03) << 24)
++#define SMENR_ADB_1B (0)
++#define SMENR_ADB_2B (0x1 << 24)
++#define SMENR_ADB_4B (0x2 << 24)
++#define SMENR_OPDB_MASK (0x03 << 20)
++#define SMENR_OPDB_1B (0)
++#define SMENR_OPDB_2B (0x1 << 20)
++#define SMENR_OPDB_4B (0x2 << 20)
++#define SMENR_SPIDB_MASK (0x03 << 16)
++#define SMENR_SPIDB(v) (((v) & 0x03) << 16)
++#define SMENR_SPIDB_1B (0)
++#define SMENR_SPIDB_2B (0x1 << 16)
++#define SMENR_SPIDB_4B (0x2 << 16)
++#define SMENR_OPDE_MASK (0xf << 4)
++#define SMENR_OPDE_DISABLE (0)
++#define SMENR_OPDE3 (0x8 << 4)
++#define SMENR_OPDE32 (0xC << 4)
++#define SMENR_OPDE321 (0xE << 4)
++#define SMENR_OPDE3210 (0xF << 4)
++#define SMENR_SPIDE_MASK (0x0F)
++#define SMENR_SPIDE_DISABLE (0)
++#define SMENR_SPIDE_8B (0x08)
++#define SMENR_SPIDE_16B (0x0C)
++#define SMENR_SPIDE_32B (0x0F)
++#define SMENR_DME (1<<15)
++#define SMENR_CDE (1<<14)
++#define SMENR_OCDE (1<<12)
++#define SMENR_ADE_MASK (0xf << 8)
++#define SMENR_ADE_DISABLE (0)
++#define SMENR_ADE_23_16 (0x4 << 8)
++#define SMENR_ADE_23_8 (0x6 << 8)
++#define SMENR_ADE_23_0 (0x7 << 8)
++#define SMENR_ADE_31_0 (0xf << 8)
++
++
++/* SMCMR */
++#define SMCMR_CMD(cmd) (((cmd) & 0xff) << 16)
++#define SMCMR_CMD_MASK (0xff << 16)
++#define SMCMR_OCMD(cmd) (((cmd) & 0xff))
++#define SMCMR_OCMD_MASK (0xff)
++
++
++/* SMDRENR */
++#define SMDRENR_HYPE_MASK (0x7 << 12)
++#define SMDRENR_HYPE_SPI_FLASH (0x0)
++#define SMDRENR_ADDRE (0x1 << 8)
++#define SMDRENR_OPDRE (0x1 << 4)
++#define SMDRENR_SPIDRE (0x1)
++
++/* PHYCNT */
++#define PHYCNT_CAL (0x1 << 31)
++#define PHYCNT_OCTA_MASK (0x3 << 22)
++#define PHYCNT_EXDS (0x1 << 21)
++#define PHYCNT_OCT (0x1 << 20)
++#define PHYCNT_DDRCAL (0x1 << 19)
++#define PHYCNT_HS (0x1 << 18)
++#define PHYCNT_STREAM_MASK (0x7 << 15)
++#define PHYCNT_STREAM(o) (((o) & 0x7) << 15)
++#define PHYCNT_WBUF2 (0x1 << 4)
++#define PHYCNT_WBUF (0x1 << 2)
++#define PHYCNT_PHYMEM_MASK (0x3)
++
++/* SMCR */
++#define SMCR_SSLKP (0x1 << 8)
++#define SMCR_SPIRE (0x1 << 2)
++#define SMCR_SPIWE (0x1 << 1)
++#define SMCR_SPIE (0x1)
++
++/* CMNSR */
++#define CMNSR_TEND (0x1 << 0)
++
++/* SSLDR */
++#define SSLDR_SPNDL(v) (((v) & 0x7) << 16)
++#define SSLDR_SLNDL(v) ((((v) | 0x4) & 0x7) << 8)
++#define SSLDR_SCKDL(v) ((v) & 0x7)
++
++/* DREAR */
++#define DREAR_EAV_MASK (0xff << 16)
++#define DREAR_EAV(v) (((v) & 0xff) << 16)
++#define DREAR_EAC_MASK (0x7)
++#define DREAR_24B (0)
++#define DREAR_25B (1)
++
++/* DRENR */
++#define DRENR_CDB_MASK (0x03 << 30)
++#define DRENR_CDB(v) (((v) & 0x3) << 30)
++#define DRENR_CDB_1B (0)
++#define DRENR_CDB_2B (0x1 << 30)
++#define DRENR_CDB_4B (0x2 << 30)
++#define DRENR_OCDB_MASK (0x03 << 28)
++#define DRENR_OCDB_1B (0)
++#define DRENR_OCDB_2B (0x1 << 28)
++#define DRENR_OCDB_4B (0x2 << 28)
++#define DRENR_ADB_MASK (0x03 << 24)
++#define DRENR_ADB(v) (((v) & 0x3) << 24)
++#define DRENR_ADB_1B (0)
++#define DRENR_ADB_2B (0x1 << 24)
++#define DRENR_ADB_4B (0x2 << 24)
++#define DRENR_OPDB_MASK (0x03 << 20)
++#define DRENR_OPDB_1B (0)
++#define DRENR_OPDB_2B (0x1 << 20)
++#define DRENR_OPDB_4B (0x2 << 20)
++#define DRENR_DRDB_MASK (0x03 << 16)
++#define DRENR_DRDB(v) (((v) & 0x3) << 16)
++#define DRENR_DRDB_1B (0)
++#define DRENR_DRDB_2B (0x1 << 16)
++#define DRENR_DRDB_4B (0x2 << 16)
++#define DRENR_OPDE_MASK (0xf << 4)
++#define DRENR_OPDE_DISABLE (0)
++#define DRENR_OPDE3 (0x8 << 4)
++#define DRENR_OPDE32 (0xC << 4)
++#define DRENR_OPDE321 (0xE << 4)
++#define DRENR_OPDE3210 (0xF << 4)
++#define DRENR_DME (1<<15)
++#define DRENR_CDE (1<<14)
++#define DRENR_OCDE (1<<12)
++#define DRENR_ADE_MASK (0xf << 8)
++#define DRENR_ADE_DISABLE (0)
++#define DRENR_ADE_23_0 (0x7 << 8)
++#define DRENR_ADE_31_0 (0xf << 8)
++
++/* DRCMR */
++#define DRCMR_CMD(cmd) (((cmd) & 0xff) << 16)
++#define DRCMR_CMD_MASK (0xff << 16)
++#define DRCMR_OCMD(cmd) (((cmd) & 0xff))
++#define DRCMR_OCMD_MASK (0xff)
++
++/* DRCMR */
++#define DRDMCR_DMCYC(v) ((v) & 0x1f)
++#define DRDMCR_DMCYC_MASK (0x1f)
++
++/* SMDMCR */
++#define SMDMCR_DMCYC(v) ((v) & 0x0f)
++#define SMDMCR_DMCYC_MASK (0x0f)
++
++/* PHYOFFSET1 */
++#define PHYOFFSET1_DDRTMG (1 << 28)
++
++/* DIVREG */
++#define DIVREG_RATIO_MASK (0x03)
++#define DIVREG_RATIO(v) ((v) & 0x03)
++#define DIVREG_RATIO_MAX (0x2)
++
++
++#define DEFAULT_TO (100)
++#define WRITE_BUF_SIZE (0x100)
++#define WRITE_BUF_ADR_MASK (0xff)
++
++#define REPEAT_MAX (20)
++#define REPEAT_TIME (10)
++
++
++struct rpc_spi {
++ struct platform_device *pdev;
++ void __iomem *base;
++ void __iomem *read_area;
++ void __iomem *write_area;
++ struct clk *clk;
++ unsigned int irq;
++ struct spi_nor spi_nor;
++
++#define MTD_QSPI_1x 0
++#define MTD_QSPI_2x 1
++
++ u32 mtdtype;
++};
++
++
++
++/* IP block use it's own clock divigion register */
++#define OWN_CLOCK_DIVIDER BIT(0)
++
++
++
++static void regs_dump(struct rpc_spi *rpc)
++{
++ static u32 regs[] = {
++ CMNCR, SSLDR, DRCR, DRCMR, DREAR,
++ DROPR, DRENR, SMCR, SMCMR, SMADR,
++ SMOPR, SMENR, SMRDR0, SMRDR1, SMWDR0,
++ SMWDR1, CMNSR, DRDMCR, DRDRENR, SMDMCR,
++ SMDRENR, PHYCNT, PHYOFFSET1, PHYOFFSET2,
++ PHYINT
++ };
++
++ static const char *const names[] = {
++ "CMNCR", "SSLDR", "DRCR", "DRCMR", "DREAR",
++ "DROPR", "DRENR", "SMCR", "SMCMR", "SMADR",
++ "SMOPR", "SMENR", "SMRDR0", "SMRDR1", "SMWDR0",
++ "SMWDR1", "CMNSR", "DRDMCR", "DRDRENR", "SMDMCR",
++ "SMDRENR", "PHYCNT", "PHYOFFSET1", "PHYOFFSET2",
++ "PHYINT"
++ };
++
++ int i;
++
++ dev_dbg(&rpc->pdev->dev, "RPC regs dump:\n");
++ for (i = 0; i < ARRAY_SIZE(regs); i++)
++ dev_dbg(&rpc->pdev->dev, "%s = 0x%08x\n", names[i],
++ readl(rpc->base + regs[i]));
++}
++
++
++
++
++
++static u32 rpc_read(struct rpc_spi *rpc, unsigned int reg)
++{
++ u32 val;
++
++ val = readl(rpc->base + reg);
++ return val;
++}
++
++static void rpc_write(struct rpc_spi *rpc, unsigned int reg, u32 val)
++{
++ writel(val, rpc->base + reg);
++}
++
++
++static int rpc_wait(struct rpc_spi *rpc, u32 to)
++{
++ u32 val;
++ int i;
++
++ for (i = 0; i < to; i++) {
++ val = rpc_read(rpc, CMNSR);
++ val &= CMNSR_TEND;
++ if (val)
++ break;
++
++ udelay(100);
++ }
++
++ if (i == to) {
++ dev_err(&rpc->pdev->dev, "timeout waiting for operation end %d\n",
++ rpc_read(rpc, CMNSR));
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++
++
++
++
++
++
++
++
++
++
++
++
++static int rpc_setup_clk_ratio(struct rpc_spi *rpc, u32 max_clk_rate)
++{
++ unsigned long rate = clk_get_rate(rpc->clk);
++ u32 ratio;
++ u32 val;
++
++ ratio = DIV_ROUND_UP(rate, max_clk_rate * 2) >> 1;
++ if (ratio > DIVREG_RATIO_MAX)
++ ratio = DIVREG_RATIO_MAX;
++
++ val = rpc_read(rpc, DIV_REG);
++ val &= DIVREG_RATIO_MASK;
++ val |= DIVREG_RATIO(ratio);
++ rpc_write(rpc, DIV_REG, val);
++
++ return 0;
++}
++
++static int rpc_endisable_write_buf(struct rpc_spi *rpc, bool en)
++{
++ u32 val;
++
++ val = rpc_read(rpc, PHYCNT);
++
++ if (en)
++ val |= PHYCNT_WBUF | PHYCNT_WBUF2;
++ else
++ val &= ~(PHYCNT_WBUF | PHYCNT_WBUF2);
++
++ rpc_write(rpc, PHYCNT, val);
++
++ return 0;
++}
++
++
++static int rpc_begin(struct rpc_spi *rpc,
++ bool rx, bool tx, bool last)
++{
++ u32 val = SMCR_SPIE;
++
++ if (rx)
++ val |= SMCR_SPIRE;
++
++ if (tx)
++ val |= SMCR_SPIWE;
++
++ if (!last)
++ val |= SMCR_SSLKP;
++
++ rpc_write(rpc, SMCR, val);
++
++ return 0;
++}
++
++
++static int rpc_setup_reg_mode(struct rpc_spi *rpc)
++{
++ u32 val;
++
++ rpc_wait(rpc, DEFAULT_TO);
++
++ rpc_endisable_write_buf(rpc, false);
++
++ /* ...setup manual mode */
++ val = rpc_read(rpc, CMNCR);
++ val |= CMNCR_MD;
++ rpc_write(rpc, CMNCR, val);
++
++ /* disable ddr */
++ val = rpc_read(rpc, SMDRENR);
++ val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE);
++ rpc_write(rpc, SMDRENR, val);
++
++ /* enable 1bit command */
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDB_MASK | SMENR_OCDB_MASK | SMENR_DME
++ | SMENR_OCDE | SMENR_SPIDB_MASK
++ | SMENR_ADE_MASK | SMENR_ADB_MASK
++ | SMENR_OPDE_MASK | SMENR_SPIDE_MASK);
++ val |= SMENR_CDB_1B | SMENR_CDE | SMENR_SPIDE_32B;
++ rpc_write(rpc, SMENR, val);
++
++
++ return 0;
++}
++
++static void rpc_flush_cache(struct rpc_spi *rpc)
++{
++ u32 val;
++
++ val = rpc_read(rpc, DRCR);
++ val |= DRCR_RCF;
++
++ rpc_write(rpc, DRCR, val);
++}
++
++
++static int rpc_setup_ext_mode(struct rpc_spi *rpc)
++{
++ u32 val;
++ u32 cmncr;
++
++ rpc_wait(rpc, DEFAULT_TO);
++
++ rpc_endisable_write_buf(rpc, false);
++
++ /* ...setup ext mode */
++ val = rpc_read(rpc, CMNCR);
++ cmncr = val;
++ val &= ~(CMNCR_MD);
++ rpc_write(rpc, CMNCR, val);
++
++ /* ...enable burst and clear cache */
++ val = rpc_read(rpc, DRCR);
++ val &= ~(DRCR_RBURST_MASK | DRCR_RBE | DRCR_SSLE);
++ val |= DRCR_RBURST(0x1f) | DRCR_RBE;
++
++ if (cmncr & CMNCR_MD)
++ val |= DRCR_RCF;
++
++ rpc_write(rpc, DRCR, val);
++
++ return 0;
++}
++
++
++static int rpc_setup_data_size(struct rpc_spi *rpc, u32 size, bool copy)
++{
++ u32 val;
++
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_SPIDE_MASK);
++
++ if (rpc->mtdtype == MTD_QSPI_2x && !copy)
++ size >>= 1;
++
++ switch (size) {
++ case 0:
++ break;
++ case 1:
++ val |= SMENR_SPIDE_8B;
++ break;
++ case 2:
++ val |= SMENR_SPIDE_16B;
++ break;
++ case 4:
++ val |= SMENR_SPIDE_32B;
++ break;
++ default:
++ dev_err(&rpc->pdev->dev, "Unsupported data width %d\n", size);
++ return -EINVAL;
++ }
++ rpc_write(rpc, SMENR, val);
++
++ return 0;
++}
++
++
++static int rpc_setup_extmode_read_addr(struct rpc_spi *rpc,
++ int adr_width, loff_t adr)
++{
++ u32 val;
++ u32 v;
++
++ val = rpc_read(rpc, DREAR);
++ val &= ~(DREAR_EAV_MASK | DREAR_EAC_MASK);
++
++ if (adr_width == 4) {
++ v = adr >> 25;
++ val |= DREAR_EAV(v) | DREAR_25B;
++ }
++ rpc_write(rpc, DREAR, val);
++
++ val = rpc_read(rpc, DRENR);
++ val &= ~(DRENR_ADE_MASK);
++ if (adr_width == 4)
++ val |= DRENR_ADE_31_0;
++ else
++ val |= DRENR_ADE_23_0;
++ rpc_write(rpc, DRENR, val);
++
++ return 0;
++}
++
++
++
++#define NBITS_TO_VAL(v) ((v >> 1) & 3)
++static int rpc_setup_extmode_nbits(struct rpc_spi *rpc, int cnb,
++ int anb, int dnb)
++{
++ u32 val;
++
++ val = rpc_read(rpc, DRENR);
++ val &= ~(DRENR_CDB_MASK | DRENR_ADB_MASK | DRENR_DRDB_MASK);
++ val |= DRENR_CDB(NBITS_TO_VAL(cnb))
++ | DRENR_ADB(NBITS_TO_VAL(anb))
++ | DRENR_DRDB(NBITS_TO_VAL(dnb));
++ rpc_write(rpc, DRENR, val);
++
++ return 0;
++}
++
++static int rpc_setup_writemode_nbits(struct rpc_spi *rpc, int cnb,
++ int anb, int dnb)
++{
++ u32 val;
++
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDB_MASK | SMENR_ADB_MASK | SMENR_SPIDB_MASK);
++ val |= SMENR_CDB(NBITS_TO_VAL(cnb))
++ | SMENR_ADB(NBITS_TO_VAL(anb))
++ | SMENR_SPIDB(NBITS_TO_VAL(dnb));
++ rpc_write(rpc, SMENR, val);
++
++ return 0;
++}
++
++static void rpc_setup_write_mode_command_and_adr(struct rpc_spi *rpc,
++ int adr_width, bool ena)
++{
++ u32 val;
++
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDB_MASK | SMENR_CDE | SMENR_ADE_MASK);
++
++ if (ena) {
++ /* enable 1bit command */
++ val |= SMENR_CDB_1B | SMENR_CDE;
++
++ if (adr_width == 4)
++ val |= SMENR_ADE_31_0;
++ else
++ val |= SMENR_ADE_23_0;
++ }
++ rpc_write(rpc, SMENR, val);
++}
++
++static int rpc_setup_write_mode(struct rpc_spi *rpc)
++{
++ u32 val;
++
++ rpc_wait(rpc, DEFAULT_TO);
++
++ rpc_endisable_write_buf(rpc, true);
++
++ /* ...setup manual mode */
++ val = rpc_read(rpc, CMNCR);
++ val |= CMNCR_MD;
++ rpc_write(rpc, CMNCR, val);
++
++ /* disable ddr */
++ val = rpc_read(rpc, SMDRENR);
++ val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE);
++ rpc_write(rpc, SMDRENR, val);
++
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_OCDB_MASK | SMENR_DME | SMENR_OCDE | SMENR_SPIDB_MASK
++ | SMENR_ADB_MASK | SMENR_OPDE_MASK | SMENR_SPIDE_MASK);
++ val |= SMENR_SPIDE_32B;
++ rpc_write(rpc, SMENR, val);
++
++ return 0;
++}
++
++static void rpc_read_manual_data(struct rpc_spi *rpc, u32 *pv0, u32 *pv1)
++{
++ u32 val0, val1, rd0, rd1;
++
++ val0 = rpc_read(rpc, SMRDR0);
++ val1 = rpc_read(rpc, SMRDR1);
++
++ if (rpc->mtdtype == MTD_QSPI_2x) {
++ rd1 = (val0 & 0xff000000) | ((val0 << 8) & 0xff0000) |
++ ((val1 >> 16) & 0xff00) | ((val1 >> 8) & 0xff);
++ rd0 = ((val0 & 0xff0000) << 8) | ((val0 << 16) & 0xff0000) |
++ ((val1 >> 8) & 0xff00) | (val1 & 0xff);
++ } else
++ rd0 = val0;
++
++ if (pv0)
++ *pv0 = rd0;
++
++ if (pv1 && rpc->mtdtype == MTD_QSPI_2x)
++ *pv1 = rd1;
++}
++
++
++static int rpc_datalen2trancfersize(struct rpc_spi *rpc, int len, bool copy)
++{
++ int sz = len;
++
++ if (len >= 2)
++ sz = 2;
++
++ if (len >= 4)
++ sz = 4;
++
++ if (rpc->mtdtype == MTD_QSPI_2x
++ && len >= 8 && !copy)
++ sz = 8;
++
++ return sz;
++}
++
++static int __rpc_write_data2reg(struct rpc_spi *rpc, int off,
++ const u8 *buf, int sz)
++{
++ const u32 *b32 = (const u32 *)buf;
++ const u16 *b16 = (const u16 *)buf;
++
++ if (sz == 4)
++ rpc_write(rpc, off, *b32);
++ else if (sz == 2)
++ writew(*b16, rpc->base+off);
++ else if (sz == 1)
++ writeb(*buf, rpc->base+off);
++ else if (sz != 0) {
++ dev_err(&rpc->pdev->dev, "incorrect data size %d\n", sz);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++#define __SETVAL(x) ((((x) & 0xff) << 8) | ((x) & 0xff))
++static int rpc_write_data2reg(struct rpc_spi *rpc, const u8 *buf,
++ int sz, bool copy)
++{
++ int i, ret;
++ u32 v = 0;
++
++ if (rpc->mtdtype == MTD_QSPI_2x) {
++ if (copy) {
++ for (i = 0; i < sz && i < 2; i++)
++ v |= (__SETVAL(buf[i]) << 16*i);
++
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? SMWDR1 : SMWDR0,
++ (u8 *)&v,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++
++ v = 0;
++ for (; i < sz; i++)
++ v |= (__SETVAL(buf[i]) << 16*i);
++
++
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? SMWDR0 : SMWDR1,
++ (u8 *)&v,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++
++ return 0;
++ }
++
++ sz >>= 1;
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? SMWDR1 : SMWDR0,
++ buf,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++ buf += sz;
++
++ return __rpc_write_data2reg(rpc,
++ sz == 4 ? SMWDR0 : SMWDR1,
++ buf, sz == 4 ? sz : sz * 2);
++ }
++
++ return __rpc_write_data2reg(rpc, SMWDR0, buf, sz);
++}
++
++static ssize_t rpc_write_unaligned(struct spi_nor *nor, loff_t to, size_t len,
++ const u_char *buf, size_t fullen)
++{
++ int ret = len, dsize;
++ struct rpc_spi *rpc = nor->priv;
++ bool copy = false, last;
++ loff_t _to;
++
++ rpc_endisable_write_buf(rpc, false);
++
++ while (len > 0) {
++ _to = to;
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ _to >>= 1;
++ rpc_write(rpc, SMADR, _to);
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++
++ rpc_write_data2reg(rpc, buf, dsize, copy);
++
++ last = (len <= dsize && fullen <= ret);
++ rpc_begin(rpc, false, true, last);
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ rpc_setup_write_mode_command_and_adr(rpc,
++ nor->addr_width, false);
++
++ buf += dsize;
++ len -= dsize;
++ to += dsize;
++ }
++
++ return ret;
++}
++
++
++
++
++static ssize_t rpc_write_flash(struct spi_nor *nor, loff_t to, size_t len,
++ const u_char *buf)
++{
++ ssize_t res = len, full = len;
++ u32 val;
++ u8 rval[2];
++ struct rpc_spi *rpc = nor->priv;
++ loff_t bo;
++ loff_t offset;
++ loff_t _to;
++ bool is_rounded = false;
++
++ /* ...len should be rounded to 2 bytes */
++ if (rpc->mtdtype == MTD_QSPI_2x && (len & 1)) {
++ is_rounded = true;
++ len &= ~(1);
++ }
++
++ bo = to & (WRITE_BUF_ADR_MASK);
++
++ rpc_flush_cache(rpc);
++ rpc_setup_write_mode(rpc);
++ rpc_setup_write_mode_command_and_adr(rpc, nor->addr_width, true);
++ rpc_setup_writemode_nbits(rpc, 1, 1, 1);
++
++ /* ...setup command */
++ val = rpc_read(rpc, SMCMR);
++ val &= ~(SMCMR_CMD_MASK);
++ val |= SMCMR_CMD(nor->program_opcode);
++ rpc_write(rpc, SMCMR, val);
++
++ offset = (to & (~WRITE_BUF_ADR_MASK));
++
++ /* ...write unaligned first bytes */
++ if (bo) {
++ rpc_write_unaligned(nor, to, WRITE_BUF_SIZE - bo, buf, full);
++ rpc_setup_write_mode(rpc);
++
++ len -= WRITE_BUF_SIZE - bo;
++ buf += WRITE_BUF_SIZE - bo;
++ to += WRITE_BUF_SIZE - bo;
++ full -= WRITE_BUF_SIZE - bo;
++ }
++
++ /* Unfortunatly RPC does not write properly in write buf mode
++ * without transferring command.
++ * May be it is better just remove this code
++ */
++ if (len >= WRITE_BUF_SIZE && !bo) {
++ _to = to;
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ _to >>= 1;
++ rpc_write(rpc, SMADR, _to);
++ memcpy_toio(rpc->write_area, buf, WRITE_BUF_SIZE);
++ buf += WRITE_BUF_SIZE;
++ len -= WRITE_BUF_SIZE;
++ to += WRITE_BUF_SIZE;
++ full -= WRITE_BUF_SIZE;
++
++ rpc_begin(rpc, false, true, full <= 0);
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ rpc_setup_write_mode_command_and_adr(rpc,
++ nor->addr_width, false);
++ }
++
++ if (len) {
++ rpc_write_unaligned(nor, to, len, buf, full);
++ buf += len;
++ to += len;
++ full -= len;
++ len = 0;
++ }
++
++ if (is_rounded) {
++ rval[0] = *buf;
++ rval[1] = 0xFF;
++ rpc_write_unaligned(nor, to, 2, rval, full);
++ }
++
++ rpc_flush_cache(rpc);
++
++ return res;
++}
++
++static inline unsigned int rpc_rx_nbits(struct spi_nor *nor)
++{
++ switch (nor->flash_read) {
++ case SPI_NOR_DUAL:
++ return 2;
++ case SPI_NOR_QUAD:
++ return 4;
++ default:
++ return 0;
++ }
++}
++
++
++#if 0
++//manual read
++static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len,
++ u_char *buf)
++{
++ ssize_t ret = len;
++ struct rpc_spi *rpc = nor->priv;
++ int adr_width = nor->addr_width;
++ int opcode_nbits = 1;//SPI_NBITS_SINGLE;
++ int addr_nbits = spi_nor_get_read_addr_nbits(nor->read_opcode);
++ int data_nbits = rpc_rx_nbits(nor);
++ int dummy = nor->read_dummy - 1;
++ u32 val, val2;
++ u32 *buf32;
++ int sz = 4;
++ int i, j;
++ loff_t adr = from;
++
++ rpc_wait(rpc, DEFAULT_TO);
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ sz <<= 1;
++
++ /* ...setup manual mode */
++ val = rpc_read(rpc, CMNCR);
++ val |= CMNCR_MD;
++ rpc_write(rpc, CMNCR, val);
++
++ /*...setup dummy */
++ val = rpc_read(rpc, SMDMCR);
++ val &= ~(SMDMCR_DMCYC_MASK);
++ val |= SMDMCR_DMCYC(dummy);
++ rpc_write(rpc, SMDMCR, val);
++
++ /* disable ddr */
++ val = rpc_read(rpc, SMDRENR);
++ val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE);
++ rpc_write(rpc, SMDRENR, val);
++
++ /* enable 1bit command */
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDB_MASK | SMENR_OCDB_MASK | SMENR_DME
++ | SMENR_OCDE | SMENR_SPIDB_MASK
++ | SMENR_ADE_MASK | SMENR_ADB_MASK
++ | SMENR_OPDE_MASK | SMENR_SPIDE_MASK);
++ val |= SMENR_CDB_1B | SMENR_ADB_4B | SMENR_SPIDB_4B
++ | SMENR_CDE | SMENR_ADE_31_0 | SMENR_DME | SMENR_SPIDE_32B;
++ rpc_write(rpc, SMENR, val);
++
++ /* ...setup command */
++ val = rpc_read(rpc, SMCMR);
++ val &= ~(SMCMR_CMD_MASK);
++ val |= SMCMR_CMD(nor->read_opcode);
++ rpc_write(rpc, SMCMR, val);
++
++ buf32 = (u32 *)buf;
++
++ while (len > 0) {
++ adr = from + ret - len;
++
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ adr >>= 1;
++
++ rpc_write(rpc, SMADR, adr);
++
++ rpc_begin(rpc, true, false, len <= sz);
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ rpc_read_manual_data(rpc, &val, &val2);
++
++ j = 0;
++ do {
++ if (len > 4) {
++ *buf32 = val;
++ buf32++;
++ len -= 4;
++ } else {
++ buf = (u8 *)buf32;
++ for (i = 0; i < len; i++) {
++ *buf = (val >> (8 * i)) & 0x000000ff;
++ buf++;
++ }
++ len = 0;
++ }
++ val = val2;
++ j++;
++ } while (j < 2 && rpc->mtdtype == MTD_QSPI_2x);
++ }
++
++ return ret;
++}
++#else
++#define READ_ADR_MASK (BIT(26) - 1)
++static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len,
++ u_char *buf)
++{
++ u32 val;
++ struct rpc_spi *rpc = nor->priv;
++ int adr_width = nor->addr_width;
++ int opcode_nbits = 1;
++ int addr_nbits = spi_nor_get_read_addr_nbits(nor->read_opcode);
++ int data_nbits = rpc_rx_nbits(nor);
++ int dummy = nor->read_dummy - 1;
++ ssize_t ret = len;
++ ssize_t readlen;
++ loff_t _from;
++
++ rpc_setup_ext_mode(rpc);
++ /* ...setup n bits */
++ rpc_setup_extmode_nbits(rpc, opcode_nbits, addr_nbits, data_nbits);
++
++ /* TODO: setup DDR */
++
++ /* ...setup command */
++ val = rpc_read(rpc, DRCMR);
++ val &= ~(DRCMR_CMD_MASK);
++ val |= DRCMR_CMD(nor->read_opcode);
++ rpc_write(rpc, DRCMR, val);
++
++ /* ...setup dummy cycles */
++ val = rpc_read(rpc, DRDMCR);
++ val &= ~(DRDMCR_DMCYC_MASK);
++ val |= DRDMCR_DMCYC(dummy);
++ rpc_write(rpc, DRDMCR, val);
++
++ /* ...setup read sequence */
++ val = rpc_read(rpc, DRENR);
++ val |= DRENR_DME | DRENR_CDE;
++ rpc_write(rpc, DRENR, val);
++
++ while (len > 0) {
++ /* ...setup address */
++ rpc_setup_extmode_read_addr(rpc, adr_width, from);
++ /* ...use adr [25...0] */
++ _from = from & READ_ADR_MASK;
++
++ readlen = READ_ADR_MASK - _from + 1;
++ readlen = readlen > len ? len : readlen;
++
++ memcpy_fromio(buf, rpc->read_area + _from, readlen);
++ buf += readlen;
++ from += readlen;
++ len -= readlen;
++ }
++
++ return ret;
++}
++#endif
++
++static int __rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ u32 val, val2;
++ u32 *buf32;
++ int i;
++ u32 mask = 0, type;
++ struct rpc_spi *rpc = nor->priv;
++
++ type = rpc->mtdtype;
++
++ rpc_setup_reg_mode(rpc);
++ val = rpc_read(rpc, SMCMR);
++ val &= ~(SMCMR_CMD_MASK);
++ val |= SMCMR_CMD(opcode);
++ rpc_write(rpc, SMCMR, val);
++
++ rpc_begin(rpc, true, false, len <= 4);
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDE);
++ rpc_write(rpc, SMENR, val);
++
++ buf32 = (u32 *)buf;
++
++ while (len > 0) {
++ rpc_read_manual_data(rpc, &val, &val2);
++
++ if (mask) {
++ dev_warn(&rpc->pdev->dev,
++ "Using mask workaround (0x%x)\n", mask);
++ val &= ~(mask);
++ val2 &= ~(mask);
++ }
++
++ /* ... spi flashes should be the same */
++ if (type == MTD_QSPI_2x && val != val2) {
++ /* clear cs */
++ rpc_begin(rpc, true, false, true);
++ return -EAGAIN;
++ }
++
++ if (len > 4) {
++ *buf32 = val;
++ buf32++;
++ len -= 4;
++ } else {
++ buf = (u8 *)buf32;
++ for (i = 0; i < len; i++) {
++ *buf = (val >> (8 * i)) & 0x000000ff;
++ buf++;
++ }
++ len = 0;
++ }
++
++ if (!len)
++ break;
++
++ mask = 0xff;
++
++ rpc_begin(rpc, true, false, len <= 4);
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ }
++
++ return 0;
++}
++
++
++static int rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int i, ret;
++
++ /* A few read commands like read status can
++ * generate different answers. We repeat reading
++ * in that case
++ */
++ for (i = 0; i < REPEAT_MAX; i++) {
++ ret = __rpc_read_reg(nor, opcode, buf, len);
++ if (!ret || ret != -EAGAIN)
++ break;
++ mdelay(REPEAT_TIME);
++ }
++
++ return ret;
++}
++
++
++
++static int rpc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ struct rpc_spi *rpc = nor->priv;
++ u32 val;
++ int dsize;
++ bool copy = true;
++
++ rpc_setup_reg_mode(rpc);
++
++ val = rpc_read(rpc, SMCMR);
++ val &= ~(SMCMR_CMD_MASK);
++ val |= SMCMR_CMD(opcode);
++ rpc_write(rpc, SMCMR, val);
++
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++
++ if (rpc_write_data2reg(rpc, buf, dsize, copy))
++ return -EINVAL;
++ buf += dsize;
++ len -= dsize;
++ rpc_begin(rpc, false, dsize > 0, len == 0);
++
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ val = rpc_read(rpc, SMENR);
++ val &= ~(SMENR_CDE);
++ rpc_write(rpc, SMENR, val);
++
++ while (len > 0) {
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++ rpc_write_data2reg(rpc, buf, dsize, copy);
++ buf += dsize;
++ len -= dsize;
++
++ rpc_begin(rpc, false, dsize, len == 0);
++
++ if (rpc_wait(rpc, DEFAULT_TO))
++ return -ETIMEDOUT;
++
++ }
++
++ return 0;
++}
++
++
++
++/* hw init for spi-nor flashes */
++static int rpc_hw_init_1x2x(struct rpc_spi *rpc)
++{
++ u32 val;
++
++ /* Exec calibration */
++ val = rpc_read(rpc, PHYCNT);
++ val &= ~(PHYCNT_OCTA_MASK | PHYCNT_EXDS | PHYCNT_OCT
++ | PHYCNT_DDRCAL | PHYCNT_HS | PHYCNT_STREAM_MASK
++ | PHYCNT_WBUF2 | PHYCNT_WBUF | PHYCNT_PHYMEM_MASK);
++ val |= (PHYCNT_CAL) | PHYCNT_STREAM(6);
++ rpc_write(rpc, PHYCNT, val);
++
++ /* disable rpc_* pins */
++ val = rpc_read(rpc, PHYINT);
++ val &= ~((1<<24) | (7<<16));
++ rpc_write(rpc, PHYINT, val);
++
++ val = rpc_read(rpc, SMDRENR);
++ val &= ~(SMDRENR_HYPE_MASK);
++ val |= SMDRENR_HYPE_SPI_FLASH;
++ rpc_write(rpc, SMDRENR, val);
++
++ val = rpc_read(rpc, CMNCR);
++ val &= ~(CMNCR_BSZ_MASK);
++ if (rpc->mtdtype != MTD_QSPI_1x)
++ val |= CMNCR_BSZ_4x2;
++ rpc_write(rpc, CMNCR, val);
++
++ val = rpc_read(rpc, PHYOFFSET1);
++ val |= PHYOFFSET1_DDRTMG;
++ rpc_write(rpc, PHYOFFSET1, val);
++
++ val = SSLDR_SPNDL(0) | SSLDR_SLNDL(4) | SSLDR_SCKDL(0);
++ rpc_write(rpc, SSLDR, val);
++
++ return 0;
++}
++
++
++static int rpc_hw_init(struct rpc_spi *rpc)
++{
++ switch (rpc->mtdtype) {
++ case MTD_QSPI_1x:
++ case MTD_QSPI_2x:
++ return rpc_hw_init_1x2x(rpc);
++
++ default:
++ dev_err(&rpc->pdev->dev, "Unsupported connection mode\n");
++ return -ENODEV;
++ }
++}
++
++
++static int rpc_erase_sector(struct spi_nor *nor, loff_t addr)
++{
++ struct rpc_spi *rpc = nor->priv;
++ u8 buf[6];
++ int i;
++
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ addr >>= 1;
++
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++
++
++
++static const struct of_device_id rpc_of_match[] = {
++ { .compatible = "renesas,qspi-rpc-r8a7798" },
++ { .compatible = "renesas,qspi-rpc-r8a7797", .data = (void *)OWN_CLOCK_DIVIDER },
++ { },
++};
++
++MODULE_DEVICE_TABLE(of, rpc_of_match);
++
++
++
++static int rpc_spi_probe(struct platform_device *pdev)
++{
++ struct device_node *flash_np;
++ struct spi_nor *nor;
++ struct rpc_spi *rpc;
++ struct resource *res;
++ enum read_mode mode = SPI_NOR_NORMAL;
++ u32 max_clk_rate = 50000000;
++ u32 property;
++ int ret;
++ int own_clk;
++
++
++ flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
++ if (!flash_np) {
++ dev_err(&pdev->dev, "no SPI flash device to configure\n");
++ return -ENODEV;
++ }
++
++ if (!of_property_read_u32(flash_np, "spi-rx-bus-width", &property)) {
++ switch (property) {
++ case 1:
++ break;
++ case 2:
++ mode = SPI_NOR_DUAL;
++ break;
++ case 4:
++ mode = SPI_NOR_QUAD;
++ break;
++ default:
++ dev_err(&pdev->dev, "unsupported rx-bus-width\n");
++ return -EINVAL;
++ }
++ }
++
++ of_property_read_u32(flash_np, "spi-max-frequency", &max_clk_rate);
++ own_clk = of_device_get_match_data(&pdev->dev);
++
++ rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL);
++ if (!rpc)
++ return -ENOMEM;
++
++ rpc->pdev = pdev;
++
++ /* ... setup nor hooks */
++ nor = &rpc->spi_nor;
++ nor->dev = &pdev->dev;
++ spi_nor_set_flash_node(nor, flash_np);
++ nor->read = rpc_read_flash;
++ nor->write = rpc_write_flash;
++ nor->read_reg = rpc_read_reg;
++ nor->write_reg = rpc_write_reg;
++ nor->priv = rpc;
++ rpc->mtdtype = MTD_QSPI_1x;
++ if (of_find_property(pdev->dev.of_node, "dual", NULL)) {
++ rpc->mtdtype = MTD_QSPI_2x;
++ spi_nor_set_array_size(nor, 2);
++ }
++ if (rpc->mtdtype == MTD_QSPI_2x)
++ nor->erase = rpc_erase_sector;
++
++ /* ...get memory */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ rpc->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->base)) {
++ dev_err(&pdev->dev, "cannot get resources\n");
++ ret = PTR_ERR(rpc->base);
++ goto error;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++
++ rpc->read_area = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->base)) {
++ dev_err(&pdev->dev, "cannot get resources\n");
++ ret = PTR_ERR(rpc->base);
++ goto error;
++ }
++
++ /* ...get memory */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ rpc->write_area = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->base)) {
++ dev_err(&pdev->dev, "cannot get resources\n");
++ ret = PTR_ERR(rpc->base);
++ goto error;
++ }
++
++ /* ...get clk */
++ rpc->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(rpc->clk)) {
++ dev_err(&pdev->dev, "cannot get clock\n");
++ ret = PTR_ERR(rpc->clk);
++ goto error;
++ }
++
++ /* ...set max clk rate */
++ if (!own_clk) {
++ ret = clk_set_rate(rpc->clk, max_clk_rate);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot set clock rate\n");
++ goto error;
++ }
++ }
++
++ /* ... enable clk */
++ ret = clk_prepare_enable(rpc->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot prepare clock\n");
++ goto error;
++ }
++
++ /* ...init device */
++ ret = rpc_hw_init(rpc);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "rpc_hw_init error.\n");
++ goto error_clk_disable;
++ }
++
++ /* ...set clk ratio */
++ if (own_clk) {
++ ret = rpc_setup_clk_ratio(rpc, max_clk_rate);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot set clock ratio\n");
++ goto error;
++ }
++ }
++
++ platform_set_drvdata(pdev, rpc);
++
++ ret = spi_nor_scan(nor, NULL, mode);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_nor_scan error.\n");
++ goto error_clk_disable;
++ }
++
++ ret = mtd_device_register(&nor->mtd, NULL, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "mtd_device_register error.\n");
++ goto error_clk_disable;
++ }
++
++ dev_info(&pdev->dev, "probed as %s\n",
++ rpc->mtdtype == MTD_QSPI_1x ? "single" : "dual");
++
++ return 0;
++
++
++error_clk_disable:
++ clk_disable_unprepare(rpc->clk);
++error:
++ return ret;
++}
++
++
++
++
++static int rpc_spi_remove(struct platform_device *pdev)
++{
++ struct rpc_spi *rpc = platform_get_drvdata(pdev);
++
++ /* HW shutdown */
++ clk_disable_unprepare(rpc->clk);
++ mtd_device_unregister(&rpc->spi_nor.mtd);
++ return 0;
++}
++
++
++
++
++
++/* platform driver interface */
++static struct platform_driver rpc_platform_driver = {
++ .probe = rpc_spi_probe,
++ .remove = rpc_spi_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "rpc",
++ .of_match_table = of_match_ptr(rpc_of_match),
++ },
++};
++
++module_platform_driver(rpc_platform_driver);
++
++
++MODULE_ALIAS("rpc");
++MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>");
++MODULE_DESCRIPTION("Renesas RPC Driver");
++MODULE_LICENSE("GPL");
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0114-R8A7798-dtsi-Add-RPC-node-to-dtsi.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0114-R8A7798-dtsi-Add-RPC-node-to-dtsi.patch
new file mode 100644
index 0000000..7169baa
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0114-R8A7798-dtsi-Add-RPC-node-to-dtsi.patch
@@ -0,0 +1,35 @@
+From 80ebc1949eb5d7db33c60faa8537029fcf6379ba Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 11:14:26 +0300
+Subject: [PATCH 05/12] R8A7798: dtsi: Add RPC node to dtsi
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7798.dtsi | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7798.dtsi b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+index e2b3404..fac60e6 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7798.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+@@ -1026,6 +1026,17 @@
+ status = "disabled";
+ };
+
++ qspi0: qspi@ee200000 {
++ compatible = "renesas,qspi-rpc-r8a7798";
++ reg = <0 0xee200000 0 0x1f0>,
++ <0 0x08000000 0 0x04000000>,
++ <0 0xee208000 0 0x100>;
++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 917>;
++ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ status = "disabled";
++ };
++
+ msiof0: spi@e6e90000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0115-R8A7798-condor-dts-Add-qspi-flash.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0115-R8A7798-condor-dts-Add-qspi-flash.patch
new file mode 100644
index 0000000..213421c
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0115-R8A7798-condor-dts-Add-qspi-flash.patch
@@ -0,0 +1,98 @@
+From 45ac82977a015e6ec80a1fb119b26c5b5841b760 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 11:19:54 +0300
+Subject: [PATCH 06/12] R8A7798-condor: dts: Add qspi flash
+
+Add s25fs512 flash support
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7798-condor.dts | 72 ++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7798-condor.dts b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts
+index cdd9844..81f984f1 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7798-condor.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts
+@@ -240,6 +240,78 @@
+ groups = "tpu_to0";
+ function = "tpu";
+ };
++
++ qspi0_pins: qspi0 {
++ groups = "qspi0_ctrl", "qspi0_data4";
++ function = "qspi0";
++ };
++
++ qspi1_pins: qspi1 {
++ groups = "qspi1_ctrl", "qspi1_data4";
++ function = "qspi1";
++ };
++};
++
++&qspi0 {
++ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash@0 {
++ compatible = "spansion,s25fs512s", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ cr7@00040000 {
++ reg = <0x00040000 0x080000>;
++ read-only;
++ };
++ cert_header_sa3@000C0000 {
++ reg = <0x000C0000 0x080000>;
++ read-only;
++ };
++ bl2@00140000 {
++ reg = <0x00140000 0x040000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x460000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x0C0000>;
++ read-only;
++ };
++ uboot-env@00700000 {
++ reg = <0x00700000 0x040000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
+ };
+
+ &scif0 {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0116-spi-nor-Add-s25fs512-flash-support.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0116-spi-nor-Add-s25fs512-flash-support.patch
new file mode 100644
index 0000000..7a3500b
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0116-spi-nor-Add-s25fs512-flash-support.patch
@@ -0,0 +1,126 @@
+From 1b2a145d72c4202fc41b2af138b862a8be94b0f0 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 11:29:21 +0300
+Subject: [PATCH 07/12] spi-nor: Add s25fs512 flash support
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 31 ++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 15 +++++++++++++++
+ 2 files changed, 43 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index d0fc165..1855bbe 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -75,6 +75,7 @@ struct flash_info {
+ * bit. Must be used with
+ * SPI_NOR_HAS_LOCK.
+ */
++#define SPANSION_S512FS_QUIRK BIT(10)
+ };
+
+ #define JEDEC_MFR(info) ((info)->id[0])
+@@ -222,8 +223,18 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor)
+ int sr = read_sr(nor);
+ if (sr < 0)
+ return sr;
+- else
+- return !(sr & SR_WIP);
++
++ if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) {
++ if (sr & SR_E_ERR)
++ dev_err(nor->dev, "Erase Error occurred\n");
++ else
++ dev_err(nor->dev, "Programming Error occurred\n");
++
++ nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
++ return -EIO;
++ }
++
++ return !(sr & SR_WIP);
+ }
+
+ static inline int spi_nor_fsr_ready(struct spi_nor *nor)
+@@ -901,7 +912,21 @@ static const struct flash_info spi_nor_ids[] = {
+ { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
+ { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+- { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++ { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++
++ {
++ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256,
++ SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPANSION_S512FS_QUIRK)
++ },
++ {
++ "s25fs128s0", INFO6(0x012018, 0x4d0381, 256 * 1024, 64,
++ SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPANSION_S512FS_QUIRK)
++ },
++ {
++ "s25fs128s1", INFO6(0x012018, 0x4d0181, 64 * 1024, 256,
++ SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPANSION_S512FS_QUIRK)
++ },
++
+ { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
+ { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
+ { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index c425c7b..99f7b2a 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -60,8 +60,10 @@
+ #define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
+ #define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
+ #define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
++#define SPINOR_OP_READ4_1_4_4 0xec /* Read data bytes (Quad I/O SPI) */
+ #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
+ #define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
++#define SPINOR_OP_BE_4K_4B 0x21 /* Erase 4KiB block */
+
+ /* Used for SST flashes only. */
+ #define SPINOR_OP_BP 0x02 /* Byte program */
+@@ -74,6 +76,7 @@
+
+ /* Used for Spansion flashes only. */
+ #define SPINOR_OP_BRWR 0x17 /* Bank register write */
++#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
+
+ /* Used for Micron flashes only. */
+ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
+@@ -88,6 +91,9 @@
+ #define SR_BP2 BIT(4) /* Block protect 2 */
+ #define SR_TB BIT(5) /* Top/Bottom protect */
+ #define SR_SRWD BIT(7) /* SR write protect */
++/* Spansion/Cypress specific status bits */
++#define SR_E_ERR BIT(5)
++#define SR_P_ERR BIT(6)
+
+ #define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+
+@@ -119,6 +125,7 @@ enum spi_nor_ops {
+ enum spi_nor_option_flags {
+ SNOR_F_USE_FSR = BIT(0),
+ SNOR_F_HAS_SR_TB = BIT(1),
++ SNOR_F_USE_CLSR = BIT(5),
+ };
+
+ /**
+@@ -197,6 +204,14 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
+ return mtd_get_of_node(&nor->mtd);
+ }
+
++static inline int spi_nor_get_read_addr_nbits(u8 opcode)
++{
++ if (opcode == SPINOR_OP_READ4_1_4_4)
++ return 4;
++ return 1;
++}
++
++
+ /**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor: the spi_nor structure
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0117-spi-nor-Add-flash-array-support.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0117-spi-nor-Add-flash-array-support.patch
new file mode 100644
index 0000000..5003ae6
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0117-spi-nor-Add-flash-array-support.patch
@@ -0,0 +1,89 @@
+From 0d10eb085d28a442b147e63383d1836cb3e62ae4 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Mon, 19 Mar 2018 11:32:58 +0300
+Subject: [PATCH 08/12] spi-nor: Add flash array support
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 20 ++++++++++++++++++--
+ include/linux/mtd/spi-nor.h | 12 ++++++++++++
+ 2 files changed, 30 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 1855bbe..3ced558 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1338,6 +1338,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ if (ret)
+ return ret;
+
++ if (!nor->array_size)
++ nor->array_size = 1;
++
+ if (name)
+ info = spi_nor_match_id(name);
+ /* Try to auto-detect if chip name wasn't specified or not found */
+@@ -1500,7 +1503,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ /* Dedicated 4-byte command set */
+ switch (nor->flash_read) {
+ case SPI_NOR_QUAD:
+- nor->read_opcode = SPINOR_OP_READ4_1_1_4;
++ if (info->flags & SPANSION_S512FS_QUIRK)
++ nor->read_opcode = SPINOR_OP_READ4_1_4_4;
++ else
++ nor->read_opcode = SPINOR_OP_READ4_1_1_4;
+ break;
+ case SPI_NOR_DUAL:
+ nor->read_opcode = SPINOR_OP_READ4_1_1_2;
+@@ -1528,7 +1534,17 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ return -EINVAL;
+ }
+
+- nor->read_dummy = spi_nor_read_dummy_cycles(nor);
++ if (info->flags & SPANSION_S512FS_QUIRK) {
++ nor->read_dummy = 10;
++ nor->flags |= SNOR_F_USE_CLSR;
++ } else
++ nor->read_dummy = spi_nor_read_dummy_cycles(nor);
++
++ /* recount parameters using array size */
++ mtd->erasesize *= nor->array_size;
++ mtd->size *= nor->array_size;
++ nor->page_size *= nor->array_size;
++ mtd->writebufsize *= nor->array_size;
+
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+ (long long)mtd->size >> 10);
+diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
+index 99f7b2a..7216b09 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -174,6 +174,7 @@ struct spi_nor {
+ bool sst_write_second;
+ u32 flags;
+ u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
++ u8 array_size;
+
+ int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+ void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+@@ -204,6 +205,17 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
+ return mtd_get_of_node(&nor->mtd);
+ }
+
++static inline void spi_nor_set_array_size(struct spi_nor *nor,
++ u8 size)
++{
++ nor->array_size = size;
++}
++
++static inline u8 spi_nor_get_array_size(struct spi_nor *nor)
++{
++ return nor->array_size;
++}
++
+ static inline int spi_nor_get_read_addr_nbits(u8 opcode)
+ {
+ if (opcode == SPINOR_OP_READ4_1_4_4)
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0118-r8a7797-clk-Add-rpc-clock.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0118-r8a7797-clk-Add-rpc-clock.patch
new file mode 100644
index 0000000..7910790
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0118-r8a7797-clk-Add-rpc-clock.patch
@@ -0,0 +1,45 @@
+From 730f3d906fa599bf76bb0b1fdf35b44a7cbdc2ed Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 22 Mar 2018 14:57:46 +0300
+Subject: [PATCH 09/12] r8a7797: clk: Add rpc clock
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/clk/renesas/r8a7797-cpg-mssr.c | 2 ++
+ include/dt-bindings/clock/r8a7797-cpg-mssr.h | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/drivers/clk/renesas/r8a7797-cpg-mssr.c b/drivers/clk/renesas/r8a7797-cpg-mssr.c
+index a3eed41..9763f6c 100644
+--- a/drivers/clk/renesas/r8a7797-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a7797-cpg-mssr.c
+@@ -74,6 +74,7 @@ static const struct cpg_core_clk r8a7797_core_clks[] __initconst = {
+ DEF_FIXED("s2d1", R8A7797_CLK_S2D1, CLK_S2, 1, 1),
+ DEF_FIXED("s2d2", R8A7797_CLK_S2D2, CLK_S2, 2, 1),
+ DEF_FIXED("s2d4", R8A7797_CLK_S2D4, CLK_S2, 4, 1),
++ DEF_FIXED("rpcsrc", R8A7797_CLK_RPCSRC, CLK_PLL1_DIV2, 5, 1),
+
+ DEF_GEN3_SD0H("sd0h", R8A7797_CLK_SD0H, CLK_PLL1_DIV4, 0x0074),
+ DEF_GEN3_SD0("sd0", R8A7797_CLK_SD0, CLK_PLL1_DIV4, 0x0074),
+@@ -158,6 +159,7 @@ static const struct mssr_mod_clk r8a7797_mod_clks[] __initconst = {
+ DEF_MOD("i2c2", 929, R8A7797_CLK_S2D2),
+ DEF_MOD("i2c1", 930, R8A7797_CLK_S2D2),
+ DEF_MOD("i2c0", 931, R8A7797_CLK_S2D2),
++ DEF_MOD("rpc", 917, R8A7797_CLK_RPCSRC),
+ };
+
+ static const unsigned int r8a7797_crit_mod_clks[] __initconst = {
+diff --git a/include/dt-bindings/clock/r8a7797-cpg-mssr.h b/include/dt-bindings/clock/r8a7797-cpg-mssr.h
+index ae6b3af..c3bd0a7 100644
+--- a/include/dt-bindings/clock/r8a7797-cpg-mssr.h
++++ b/include/dt-bindings/clock/r8a7797-cpg-mssr.h
+@@ -44,5 +44,6 @@
+ #define R8A7797_CLK_CPEX 29
+ #define R8A7797_CLK_R 30
+ #define R8A7797_CLK_OSC 31
++#define R8A7797_CLK_RPCSRC 32
+
+ #endif /* __DT_BINDINGS_CLOCK_R8A7797_CPG_MSSR_H__ */
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0119-r8a7797-pinctrl-Add-qspi-pins.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0119-r8a7797-pinctrl-Add-qspi-pins.patch
new file mode 100644
index 0000000..a0b4330
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0119-r8a7797-pinctrl-Add-qspi-pins.patch
@@ -0,0 +1,118 @@
+From 441ae85fe3fec270ea1284a669cdd348a8432d85 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 22 Mar 2018 15:00:02 +0300
+Subject: [PATCH 10/12] r8a7797: pinctrl: Add qspi pins
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/pinctrl/sh-pfc/pfc-r8a7797.c | 73 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7797.c b/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
+index 6b83f44..4f451c4 100644
+--- a/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
+@@ -1143,6 +1143,59 @@ static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+ };
+
++/* - QSPI ------------------------------------------------------------------- */
++static const unsigned int qspi0_ctrl_pins[] = {
++ /* QSPI0_SPCLK QSPI0_SSL */
++ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 0),
++};
++static const unsigned int qspi0_ctrl_mux[] = {
++ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
++};
++
++static const unsigned int qspi0_data2_pins[] = {
++ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
++};
++static const unsigned int qspi0_data2_mux[] = {
++ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
++};
++
++static const unsigned int qspi0_data4_pins[] = {
++ /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
++ RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 4),
++};
++static const unsigned int qspi0_data4_mux[] = {
++ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
++ QSPI0_IO2_MARK, QSPI0_IO3_MARK
++};
++
++static const unsigned int qspi1_ctrl_pins[] = {
++ /* QSPI1_SPCLK QSPI1_SSL */
++ RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 11),
++};
++static const unsigned int qspi1_ctrl_mux[] = {
++ QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
++};
++
++static const unsigned int qspi1_data2_pins[] = {
++ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
++ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 8),
++};
++static const unsigned int qspi1_data2_mux[] = {
++ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
++};
++
++static const unsigned int qspi1_data4_pins[] = {
++ /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */
++ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 8),
++ RCAR_GP_PIN(5, 9), RCAR_GP_PIN(5, 10),
++};
++static const unsigned int qspi1_data4_mux[] = {
++ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
++ QSPI1_IO2_MARK, QSPI1_IO3_MARK
++};
++
+ /* - I2C -------------------------------------------------------------------- */
+ static const unsigned int i2c0_pins[] = {
+ /* SDA0, SCL0 */
+@@ -1971,6 +2024,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(vin1_field),
+ SH_PFC_PIN_GROUP(vin1_clkenb),
+ SH_PFC_PIN_GROUP(vin1_clk),
++ SH_PFC_PIN_GROUP(qspi0_ctrl),
++ SH_PFC_PIN_GROUP(qspi0_data2),
++ SH_PFC_PIN_GROUP(qspi0_data4),
++ SH_PFC_PIN_GROUP(qspi1_ctrl),
++ SH_PFC_PIN_GROUP(qspi1_data2),
++ SH_PFC_PIN_GROUP(qspi1_data4),
+ };
+
+ static const char * const avb0_groups[] = {
+@@ -2201,6 +2260,18 @@ static const char * const vin1_groups[] = {
+ "vin1_clk",
+ };
+
++static const char * const qspi0_groups[] = {
++ "qspi0_ctrl",
++ "qspi0_data2",
++ "qspi0_data4",
++};
++
++static const char * const qspi1_groups[] = {
++ "qspi1_ctrl",
++ "qspi1_data2",
++ "qspi1_data4",
++};
++
+ #define POCCTRL0 0x380
+ #define POCCTRL1 0x384
+ #define PIN2POCCTRL0_SHIFT(a) ({ \
+@@ -2244,6 +2315,8 @@ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(vin0),
+ SH_PFC_FUNCTION(vin1),
++ SH_PFC_FUNCTION(qspi0),
++ SH_PFC_FUNCTION(qspi1),
+ };
+
+ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0120-r8a7797-dtsi-Add-rpc-node.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0120-r8a7797-dtsi-Add-rpc-node.patch
new file mode 100644
index 0000000..8d782ca
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0120-r8a7797-dtsi-Add-rpc-node.patch
@@ -0,0 +1,35 @@
+From 847b14e65374563ec3ee1d06eec05b4004233e7d Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 22 Mar 2018 15:27:49 +0300
+Subject: [PATCH 11/12] r8a7797: dtsi: Add rpc node
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7797.dtsi | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797.dtsi b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+index a5552d6..2beca53 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+@@ -889,6 +889,17 @@
+ status = "disabled";
+ };
+
++ qspi0: qspi@ee200000 {
++ compatible = "renesas,qspi-rpc-r8a7797";
++ reg = <0 0xee200000 0 0x1f0>,
++ <0 0x08000000 0 0x04000000>,
++ <0 0xee208000 0 0x100>;
++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 917>;
++ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
++ status = "disabled";
++ };
++
+ msiof0: spi@e6e90000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0121-r8a7797-eagle-dts-Add-spi-flash-node.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0121-r8a7797-eagle-dts-Add-spi-flash-node.patch
new file mode 100644
index 0000000..8dabedc
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0121-r8a7797-eagle-dts-Add-spi-flash-node.patch
@@ -0,0 +1,96 @@
+From 0e884fcce89a6b15bd3971392b5641b48d1ad9ab Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 22 Mar 2018 15:31:48 +0300
+Subject: [PATCH 12/12] r8a7797-eagle: dts: Add spi flash node
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7797-eagle.dts | 72 +++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797-eagle.dts b/arch/arm64/boot/dts/renesas/r8a7797-eagle.dts
+index ce7a88e..c8150d9 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797-eagle.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7797-eagle.dts
+@@ -203,6 +203,78 @@
+ groups = "du_rgb666", "du_sync", "du_clk_out_0", "du_disp";
+ function = "du";
+ };
++
++ qspi0_pins: qspi0 {
++ groups = "qspi0_ctrl", "qspi0_data4";
++ function = "qspi0";
++ };
++
++ qspi1_pins: qspi1 {
++ groups = "qspi1_ctrl", "qspi1_data4";
++ function = "qspi1";
++ };
++};
++
++&qspi0 {
++ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash@0 {
++ compatible = "spansion,s25fs512s", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ cr7@00040000 {
++ reg = <0x00040000 0x080000>;
++ read-only;
++ };
++ cert_header_sa3@000C0000 {
++ reg = <0x000C0000 0x080000>;
++ read-only;
++ };
++ bl2@00140000 {
++ reg = <0x00140000 0x040000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x460000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x0C0000>;
++ read-only;
++ };
++ uboot-env@00700000 {
++ reg = <0x00700000 0x040000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
+ };
+
+ &scif0 {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0122-r8a7797-v3msk-r8a7797-v3mzf-dts-Add-spi-flash-s25fs5.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0122-r8a7797-v3msk-r8a7797-v3mzf-dts-Add-spi-flash-s25fs5.patch
new file mode 100644
index 0000000..07a55d5
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0122-r8a7797-v3msk-r8a7797-v3mzf-dts-Add-spi-flash-s25fs5.patch
@@ -0,0 +1,172 @@
+From 22f31ca58e24e9c8b92361e0d1f57a59d1fdbf64 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Fri, 23 Mar 2018 16:32:07 +0300
+Subject: [PATCH] r8a7797-v3msk,r8a7797-v3mzf: dts: Add spi flash s25fs512
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts | 68 +++++++++++++++++++++++++++
+ arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts | 68 +++++++++++++++++++++++++++
+ 2 files changed, 136 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts
+index 33c6c0d..604475d 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts
+@@ -213,6 +213,74 @@
+ function = "mmc";
+ power-source = <3300>;
+ };
++
++ qspi0_pins: qspi0 {
++ groups = "qspi0_ctrl", "qspi0_data4";
++ function = "qspi0";
++ };
++
++ qspi1_pins: qspi1 {
++ groups = "qspi1_ctrl", "qspi1_data4";
++ function = "qspi1";
++ };
++};
++
++&qspi0 {
++ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash@0 {
++ compatible = "spansion,s25fs512s", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ cr7@00040000 {
++ reg = <0x00040000 0x080000>;
++ read-only;
++ };
++ cert_header_sa3@000C0000 {
++ reg = <0x000C0000 0x080000>;
++ read-only;
++ };
++ bl2@00140000 {
++ reg = <0x00140000 0x040000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x460000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x100000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
+ };
+
+ &scif0 {
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts b/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts
+index 71d7bad..4a64881 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts
+@@ -401,6 +401,74 @@
+ function = "mmc";
+ power-source = <3300>;
+ };
++
++ qspi0_pins: qspi0 {
++ groups = "qspi0_ctrl", "qspi0_data4";
++ function = "qspi0";
++ };
++
++ qspi1_pins: qspi1 {
++ groups = "qspi1_ctrl", "qspi1_data4";
++ function = "qspi1";
++ };
++};
++
++&qspi0 {
++ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash@0 {
++ compatible = "spansion,s25fs512s", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ cr7@00040000 {
++ reg = <0x00040000 0x080000>;
++ read-only;
++ };
++ cert_header_sa3@000C0000 {
++ reg = <0x000C0000 0x080000>;
++ read-only;
++ };
++ bl2@00140000 {
++ reg = <0x00140000 0x040000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x460000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x100000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
+ };
+
+ &scif0 {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0123-V3HSK-dts-Add-qspi-node.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0123-V3HSK-dts-Add-qspi-node.patch
new file mode 100644
index 0000000..4e39ed6
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0123-V3HSK-dts-Add-qspi-node.patch
@@ -0,0 +1,101 @@
+From 2e5e9bce98281417fec62cb8af23c086c3d5b01a Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 5 Apr 2018 17:23:14 +0300
+Subject: [PATCH] V3HSK: dts: Add qspi node
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7798-v3hsk.dts | 73 +++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7798-v3hsk.dts b/arch/arm64/boot/dts/renesas/r8a7798-v3hsk.dts
+index bf8abe6..d863a95 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7798-v3hsk.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7798-v3hsk.dts
+@@ -225,6 +225,17 @@
+ groups = "tpu_to0";
+ function = "tpu";
+ };
++
++
++ qspi0_pins: qspi0 {
++ groups = "qspi0_ctrl", "qspi0_data4";
++ function = "qspi0";
++ };
++
++ qspi1_pins: qspi1 {
++ groups = "qspi1_ctrl", "qspi1_data4";
++ function = "qspi1";
++ };
+ };
+
+ &scif0 {
+@@ -356,3 +367,65 @@
+ max-speed = <1000>;
+ };
+ };
++
++&qspi0 {
++ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash@0 {
++ compatible = "spansion,s25fs512s", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ cr7@00040000 {
++ reg = <0x00040000 0x080000>;
++ read-only;
++ };
++ cert_header_sa3@000C0000 {
++ reg = <0x000C0000 0x080000>;
++ read-only;
++ };
++ bl2@00140000 {
++ reg = <0x00140000 0x040000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x460000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x0C0000>;
++ read-only;
++ };
++ uboot-env@00700000 {
++ reg = <0x00700000 0x040000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
++};
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0124-RPC-Hyperflash-Add-devicetree-support.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0124-RPC-Hyperflash-Add-devicetree-support.patch
new file mode 100644
index 0000000..f347d47
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0124-RPC-Hyperflash-Add-devicetree-support.patch
@@ -0,0 +1,219 @@
+From 466608ee2217ce02df6df977a35c4afa6ee1e350 Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Wed, 4 Apr 2018 12:29:47 +0300
+Subject: [PATCH 1/2] RPC: Hyperflash: Add devicetree support
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/mtd/rpc_hyperflash.c | 142 +++++++++++++++++++++++--------------------
+ 1 file changed, 77 insertions(+), 65 deletions(-)
+
+diff --git a/drivers/mtd/rpc_hyperflash.c b/drivers/mtd/rpc_hyperflash.c
+index cf4d56e..c15e520 100644
+--- a/drivers/mtd/rpc_hyperflash.c
++++ b/drivers/mtd/rpc_hyperflash.c
+@@ -15,8 +15,10 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/of.h>
++#include <linux/clk.h>
+ #include <linux/rwsem.h>
+ #include <linux/slab.h>
++#include <linux/platform_device.h>
+
+ /* RPC */
+ #define RPC_BASE 0xEE200000
+@@ -156,10 +158,9 @@
+
+ struct rpc_info {
+ struct rw_semaphore lock;
++ struct clk *clk;
+ void __iomem *rpc_base;
+ void __iomem *flash_base;
+- struct resource *rpc_res;
+- struct resource *flash_res;
+ u32 flash_id;
+ struct mtd_info mtd;
+ };
+@@ -243,8 +244,6 @@ enum rpc_hf_size {
+ RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
+ };
+
+-struct rpc_info *rpc_info;
+-
+ static void rpc_hf_mode_man(struct rpc_info *info)
+ {
+ rpc_wait_tend(info);
+@@ -861,8 +860,8 @@ static int rpc_hf_init_mtd(struct rpc_info *info)
+ rpc_hf_read_reg(info, 0x27 << 1, data, RPC_HF_SIZE_16BIT);
+ size = 1 << data[0];
+
+- if (size > resource_size(info->flash_res))
+- size = resource_size(info->flash_res);
++ if (size > RPC_FLASH_SIZE)
++ size = RPC_FLASH_SIZE;
+
+ if (size & (RPC_HF_ERASE_SIZE - 1)) {
+ retval = -EINVAL;
+@@ -891,86 +890,99 @@ static int rpc_hf_init_mtd(struct rpc_info *info)
+ return retval;
+ }
+
+-static int rpc_flash_init(void)
++static int rpc_flash_probe(struct platform_device *pdev)
+ {
+- struct rpc_info *info;
++ struct rpc_info *rpc;
+ struct resource *res;
+- void __iomem *base;
+- int retval = -ENODEV;
+-
+- if (!of_machine_is_compatible("renesas,r8a7795"))
+- return -ENODEV;
++ int ret;
+
+- info = kzalloc(sizeof(*info), GFP_KERNEL);
+- if (!info)
++ rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL);
++ if (!rpc)
+ return -ENOMEM;
+
+- res = request_mem_region(RPC_BASE, RPC_SIZE, "RPC");
+- if (!res)
+- goto out_info;
++ /* ...get memory */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ rpc->rpc_base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->rpc_base)) {
++ dev_err(&pdev->dev, "cannot get resources\n");
++ ret = PTR_ERR(rpc->rpc_base);
++ goto error;
++ }
+
+- info->rpc_res = res;
+- base = ioremap(res->start, resource_size(res));
+- if (!base)
+- goto out_rpc_res;
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ rpc->flash_base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(rpc->flash_base)) {
++ dev_err(&pdev->dev, "cannot get resources\n");
++ ret = PTR_ERR(rpc->flash_base);
++ goto error;
++ }
+
+- info->rpc_base = base;
+- res = request_mem_region(RPC_FLASH_BASE, RPC_FLASH_SIZE, "RPC-ext");
+- if (!res)
+- goto out_rpc_base;
++ /* ...get clk */
++ rpc->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(rpc->clk)) {
++ dev_err(&pdev->dev, "cannot get clock\n");
++ ret = PTR_ERR(rpc->clk);
++ goto error;
++ }
+
+- info->flash_res = res;
+- base = ioremap(res->start, resource_size(res));
+- if (!base)
+- goto out_flash_res;
++ /* ... enable clk */
++ ret = clk_prepare_enable(rpc->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot prepare clock\n");
++ goto error;
++ }
++
++ platform_set_drvdata(pdev, rpc);
+
+- info->flash_base = base;
+- retval = rpc_hf_init_mtd(info);
+- if (retval)
+- goto out_flash_base;
++ mtd_set_of_node(&rpc->mtd, pdev->dev.of_node);
++ ret = rpc_hf_init_mtd(rpc);
++ if (ret) {
++ dev_err(&pdev->dev, "mtd device register error.\n");
++ goto error_clk_disable;
++ }
+
+- pr_info("HyperFlash Id: %x\n", info->flash_id);
++ dev_info(&pdev->dev, "HyperFlash Id: %x\n", rpc->flash_id);
+
+- rpc_info = info;
+ return 0;
+
+-out_flash_base:
+- iounmap(info->flash_base);
+-out_flash_res:
+- release_mem_region(info->flash_res->start,
+- resource_size(info->flash_res));
+-out_rpc_base:
+- iounmap(info->rpc_base);
+-out_rpc_res:
+- release_mem_region(info->rpc_res->start,
+- resource_size(info->rpc_res));
+-out_info:
+- kfree(info);
+- return retval;
++
++error_clk_disable:
++ clk_disable_unprepare(rpc->clk);
++error:
++ return ret;
+ }
+
+-static void rpc_flash_exit(void)
++static int rpc_flash_exit(struct platform_device *pdev)
+ {
+- struct rpc_info *info = rpc_info;
++ struct rpc_info *rpc = platform_get_drvdata(pdev);
++
++ /* HW shutdown */
++ clk_disable_unprepare(rpc->clk);
++ mtd_device_unregister(&rpc->mtd);
++ return 0;
++}
+
+- if (!info)
+- return;
+
+- rpc_info = NULL;
++static const struct of_device_id rpc_flash_of_match[] = {
++ { .compatible = "renesas,rpc-hyperflash-r8a7798" },
++ { .compatible = "renesas,rpc-hyperflash-r8a7797" },
++ { },
++};
+
+- mtd_device_unregister(&info->mtd);
++MODULE_DEVICE_TABLE(of, rpc_flash_of_match);
+
+- iounmap(info->flash_base);
+- release_mem_region(info->flash_res->start,
+- resource_size(info->flash_res));
+- iounmap(info->rpc_base);
+- release_mem_region(info->rpc_res->start,
+- resource_size(info->rpc_res));
+- kfree(info);
+-}
++/* platform driver interface */
++static struct platform_driver rpc_flash_platform_driver = {
++ .probe = rpc_flash_probe,
++ .remove = rpc_flash_exit,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "rpc",
++ .of_match_table = of_match_ptr(rpc_flash_of_match),
++ },
++};
+
+-module_init(rpc_flash_init);
+-module_exit(rpc_flash_exit);
++module_platform_driver(rpc_flash_platform_driver);
+
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("Renesas RPC HyperFlash MTD driver");
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0125-r8a7797-pinctrl-Add-pin-function-for-hyperflash.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0125-r8a7797-pinctrl-Add-pin-function-for-hyperflash.patch
new file mode 100644
index 0000000..08bee0d
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0125-r8a7797-pinctrl-Add-pin-function-for-hyperflash.patch
@@ -0,0 +1,70 @@
+From 4b5dc172d87cc8291ddb7377d3252b6777cf8d4b Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Wed, 4 Apr 2018 12:59:59 +0300
+Subject: [PATCH 2/2] r8a7797: pinctrl: Add pin function for hyperflash
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/pinctrl/sh-pfc/pfc-r8a7797.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7797.c b/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
+index 4f451c4..d989acd 100644
+--- a/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7797.c
+@@ -1196,6 +1196,25 @@ static const unsigned int qspi1_data4_mux[] = {
+ QSPI1_IO2_MARK, QSPI1_IO3_MARK
+ };
+
++static const unsigned int rpc_hyperflash_pins[] = {
++ RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 12),
++ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 7),
++ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9),
++ RCAR_GP_PIN(5, 10), RCAR_GP_PIN(5, 6),
++ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 4),
++ RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 2),
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0)
++};
++static const unsigned int rpc_hyperflash_mux[] = {
++ RPC_INT_N_MARK, RPC_RESET_N_MARK,
++ QSPI1_SSL_MARK, QSPI1_IO3_MARK,
++ QSPI1_IO2_MARK, QSPI1_MISO_IO1_MARK,
++ QSPI1_MOSI_IO0_MARK, QSPI1_SPCLK_MARK,
++ QSPI0_SSL_MARK, QSPI0_IO3_MARK,
++ QSPI0_IO2_MARK, QSPI0_MISO_IO1_MARK,
++ QSPI0_MOSI_IO0_MARK, QSPI0_SPCLK_MARK
++};
++
+ /* - I2C -------------------------------------------------------------------- */
+ static const unsigned int i2c0_pins[] = {
+ /* SDA0, SCL0 */
+@@ -2030,6 +2049,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(qspi1_ctrl),
+ SH_PFC_PIN_GROUP(qspi1_data2),
+ SH_PFC_PIN_GROUP(qspi1_data4),
++ SH_PFC_PIN_GROUP(rpc_hyperflash),
+ };
+
+ static const char * const avb0_groups[] = {
+@@ -2272,6 +2292,10 @@ static const char * const qspi1_groups[] = {
+ "qspi1_data4",
+ };
+
++static const char * const rpc_hyperflash_groups[] = {
++ "rpc_hyperflash",
++};
++
+ #define POCCTRL0 0x380
+ #define POCCTRL1 0x384
+ #define PIN2POCCTRL0_SHIFT(a) ({ \
+@@ -2317,6 +2341,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(vin1),
+ SH_PFC_FUNCTION(qspi0),
+ SH_PFC_FUNCTION(qspi1),
++ SH_PFC_FUNCTION(rpc_hyperflash),
+ };
+
+ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0126-r8a7798-pinctrl-Add-pin-function-for-hyperflash.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0126-r8a7798-pinctrl-Add-pin-function-for-hyperflash.patch
new file mode 100644
index 0000000..0babaa4
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0126-r8a7798-pinctrl-Add-pin-function-for-hyperflash.patch
@@ -0,0 +1,69 @@
+From 6633820967dcedde29b2e0507b7583c08901a12f Mon Sep 17 00:00:00 2001
+From: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+Date: Thu, 5 Apr 2018 18:32:59 +0300
+Subject: [PATCH] r8a7798: pinctrl: Add pin function for hyperflash
+
+Signed-off-by: Dmitry Shifrin <dmitry.shifrin@cogentembedded.com>
+---
+ drivers/pinctrl/sh-pfc/pfc-r8a7798.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7798.c b/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
+index f20afd1..f6f159e 100644
+--- a/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7798.c
+@@ -1525,6 +1525,24 @@ static const unsigned int qspi1_data4_mux[] = {
+ QSPI1_IO2_MARK, QSPI1_IO3_MARK
+ };
+
++static const unsigned int rpc_hyperflash_pins[] = {
++ RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 12),
++ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 7),
++ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9),
++ RCAR_GP_PIN(5, 10), RCAR_GP_PIN(5, 6),
++ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 4),
++ RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 2),
++ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0)
++};
++static const unsigned int rpc_hyperflash_mux[] = {
++ RPC_INT_N_MARK, RPC_RESET_N_MARK,
++ QSPI1_SSL_MARK, QSPI1_IO3_MARK,
++ QSPI1_IO2_MARK, QSPI1_MISO_IO1_MARK,
++ QSPI1_MOSI_IO0_MARK, QSPI1_SPCLK_MARK,
++ QSPI0_SSL_MARK, QSPI0_IO3_MARK,
++ QSPI0_IO2_MARK, QSPI0_MISO_IO1_MARK,
++ QSPI0_MOSI_IO0_MARK, QSPI0_SPCLK_MARK
++};
+
+ /* - I2C -------------------------------------------------------------------- */
+ static const unsigned int i2c0_pins[] = {
+@@ -2479,6 +2497,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(qspi1_ctrl),
+ SH_PFC_PIN_GROUP(qspi1_data2),
+ SH_PFC_PIN_GROUP(qspi1_data4),
++ SH_PFC_PIN_GROUP(rpc_hyperflash),
+ };
+
+ static const char * const avb_groups[] = {
+@@ -2755,6 +2774,10 @@ static const char * const qspi1_groups[] = {
+ "qspi1_data4",
+ };
+
++static const char * const rpc_hyperflash_groups[] = {
++ "rpc_hyperflash",
++};
++
+ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(gether),
+@@ -2793,6 +2816,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(vin1),
+ SH_PFC_FUNCTION(qspi0),
+ SH_PFC_FUNCTION(qspi1),
++ SH_PFC_FUNCTION(rpc_hyperflash),
+ };
+
+ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0127-IMR-UIO-Driver-initial-version.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0127-IMR-UIO-Driver-initial-version.patch
new file mode 100644
index 0000000..74d6c07
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0127-IMR-UIO-Driver-initial-version.patch
@@ -0,0 +1,875 @@
+From 4a0e94fec7f69a717fc084fa168c2120998f076c Mon Sep 17 00:00:00 2001
+From: Toshiya Tamaki <toshiya.tamaki.ue@renesas.com>
+Date: Thu, 1 Jun 2017 15:43:21 +0900
+Subject: [PATCH 1/2] IMR UIO Driver initial version
+
+Signed-off-by: Toshiya Tamaki <toshiya.tamaki.ue@renesas.com>
+---
+ .../devicetree/bindings/imr/renesas,imr.txt | 55 +++
+ arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi | 24 +-
+ arch/arm64/boot/dts/renesas/r8a7795.dtsi | 24 +-
+ arch/arm64/boot/dts/renesas/r8a7796.dtsi | 16 +
+ arch/arm64/boot/dts/renesas/r8a7797.dtsi | 24 +-
+ arch/arm64/boot/dts/renesas/r8a7798.dtsi | 36 +-
+ drivers/clk/renesas/r8a7796-cpg-mssr.c | 2 +
+ drivers/uio/Kconfig | 8 +
+ drivers/uio/Makefile | 1 +
+ drivers/uio/uio_imr.c | 495 +++++++++++++++++++++
+ 10 files changed, 631 insertions(+), 54 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/imr/renesas,imr.txt
+ create mode 100644 drivers/uio/uio_imr.c
+
+diff --git a/Documentation/devicetree/bindings/imr/renesas,imr.txt b/Documentation/devicetree/bindings/imr/renesas,imr.txt
+new file mode 100644
+index 0000000..50ce539
+--- /dev/null
++++ b/Documentation/devicetree/bindings/imr/renesas,imr.txt
+@@ -0,0 +1,55 @@
++* Renesas Electronics IMR
++
++This file provides information on what the device node for the IMR
++interface contains.
++
++Required properties:
++- compatible: "renesas,imr-r8a7795" if the device is a part of R8A7795 SoC.
++ "renesas,imr-r8a7796" if the device is a part of R8A7796 SoC.
++ "renesas,imr-r8a7797" if the device is a part of R8A7797 SoC.
++
++ When compatible with the generic version, nodes must list the
++ SoC-specific version corresponding to the platform first
++ followed by the generic version.
++
++- reg: offset and length of (1) the register block and (2) the stream buffer.
++- interrupts: A list of interrupt-specifiers, one for each entry in
++ interrupt-names.
++ If interrupt-names is not present, an interrupt specifier
++ for a single muxed interrupt.
++- clocks: clock phandle and specifier pair.
++- power-domains: must contain a reference to the PM domain.
++
++Example:
++
++ imr0{
++ compatible = "renesas,imr-r8a7797";
++ reg = <0 0xfe860000 0 0x10000>;
++ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 823>;
++ power-domains = <&sysc R8A7797_PD_A3VC>;
++ };
++
++ imr1{
++ compatible = "renesas,imr-r8a7797";
++ reg = <0 0xfe870000 0 0x10000>;
++ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 822>;
++ power-domains = <&sysc R8A7797_PD_A3VC>;
++ };
++
++ imr2{
++ compatible = "renesas,imr-r8a7797";
++ reg = <0 0xfe880000 0 0x10000>;
++ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 821>;
++ power-domains = <&sysc R8A7797_PD_A3VC>;
++ };
++
++ imr3{
++ compatible = "renesas,imr-r8a7797";
++ reg = <0 0xfe890000 0 0x10000>;
++ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 820>;
++ power-domains = <&sysc R8A7797_PD_A3VC>;
++ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
+index 13516e9..745493c 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
+@@ -2899,33 +2899,33 @@
+ power-domains = <&sysc R8A7795_PD_A3IR>;
+ };
+
+- imrlx4_ch0: imr-lx4@fe860000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe860000 0 0x2000>;
++ imrlx4_ch0: imr0@fe860000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch1: imr-lx4@fe870000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe870000 0 0x2000>;
++ imrlx4_ch1: imr1@fe870000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe870000 0 0x10000>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch2: imr-lx4@fe880000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe880000 0 0x2000>;
++ imrlx4_ch2: imr2@fe880000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe880000 0 0x10000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch3: imr-lx4@fe890000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe890000 0 0x2000>;
++ imrlx4_ch3: imr3@fe890000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe890000 0 0x10000>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+index 565beb9..96e182a 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+@@ -2895,33 +2895,33 @@
+ power-domains = <&sysc R8A7795_PD_A3IR>;
+ };
+
+- imrlx4_ch0: imr-lx4@fe860000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe860000 0 0x2000>;
++ imrlx4_ch0: imr0@fe860000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch1: imr-lx4@fe870000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe870000 0 0x2000>;
++ imrlx4_ch1: imr1@fe870000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe870000 0 0x10000>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch2: imr-lx4@fe880000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe880000 0 0x2000>;
++ imrlx4_ch2: imr2@fe880000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe880000 0 0x10000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+ };
+
+- imrlx4_ch3: imr-lx4@fe890000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe890000 0 0x2000>;
++ imrlx4_ch3: imr3@fe890000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
++ reg = <0 0xfe890000 0 0x10000>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
+diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+index bf37b8a..b747f0c 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+@@ -1174,6 +1174,22 @@
+ status = "disabled";
+ };
+
++ imrlx4_ch0: imr0@fe860000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7796";
++ reg = <0 0xfe860000 0 0x10000>;
++ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 823>;
++ power-domains = <&sysc R8A7796_PD_A3VC>;
++ };
++
++ imrlx4_ch1: imr1@fe870000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7796";
++ reg = <0 0xfe870000 0 0x10000>;
++ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 822>;
++ power-domains = <&sysc R8A7796_PD_A3VC>;
++ };
++
+ can0: can@e6c30000 {
+ compatible = "renesas,can-r8a7796",
+ "renesas,rcar-gen3-can";
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797.dtsi b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+index 2beca53..c878467 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+@@ -1239,33 +1239,33 @@
+ power-domains = <&sysc R8A7797_PD_A3IR>;
+ };
+
+- imrlx4_ch0: imr-lx4@fe860000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe860000 0 0x2000>;
++ imrlx4_ch0: imr0@fe860000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7797";
++ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch1: imr-lx4@fe870000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe870000 0 0x2000>;
++ imrlx4_ch1: imr1@fe870000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7797";
++ reg = <0 0xfe870000 0 0x10000>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch2: imr-lx4@fe880000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe880000 0 0x2000>;
++ imrlx4_ch2: imr2@fe880000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7797";
++ reg = <0 0xfe880000 0 0x10000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch3: imr-lx4@fe890000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe890000 0 0x2000>;
++ imrlx4_ch3: imr3@fe890000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7797";
++ reg = <0 0xfe890000 0 0x10000>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
+diff --git a/arch/arm64/boot/dts/renesas/r8a7798.dtsi b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+index 48ce2af..7bfd0483 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7798.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+@@ -1588,50 +1588,50 @@
+ power-domains = <&sysc R8A7798_PD_A3IR>;
+ };
+
+- imrlx4_ch0: imr-lx4@fe860000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe860000 0 0x2000>;
++ imrlx4_ch0: imr0@fe860000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch1: imr-lx4@fe870000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe870000 0 0x2000>;
++ imrlx4_ch1: imr1@fe870000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe870000 0 0x10000>;
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch2: imr-lx4@fe880000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe880000 0 0x2000>;
++ imrlx4_ch2: imr2@fe880000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe880000 0 0x10000>;
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch3: imr-lx4@fe890000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe890000 0 0x2000>;
++ imrlx4_ch3: imr3@fe890000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe890000 0 0x10000>;
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+ };
+
+- imrlx4_ch4: imr-lx4@fe8a0000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe8a0000 0 0x2000>;
++ imrlx4_ch4: imr4@fe8a0000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe8a0000 0 0x10000>;
+ interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 707>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+ rse;
+ };
+
+- imrlx4_ch5: imr-lx4@fe8b0000 {
+- compatible = "renesas,imr-lx4";
+- reg = <0 0xfe8b0000 0 0x2000>;
++ imrlx4_ch5: imr5@fe8b0000 {
++ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
++ reg = <0 0xfe8b0000 0 0x10000>;
+ interrupts = <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 706>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
+diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
+index e886d8a..e2ca77c 100644
+--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
+@@ -204,6 +204,8 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
+ DEF_MOD("vin1", 810, R8A7796_CLK_S0D2),
+ DEF_MOD("vin0", 811, R8A7796_CLK_S0D2),
+ DEF_MOD("etheravb", 812, R8A7796_CLK_S0D6),
++ DEF_MOD("imr1", 822, R8A7796_CLK_S2D1),
++ DEF_MOD("imr0", 823, R8A7796_CLK_S2D1),
+ DEF_MOD("imp", 824, R8A7796_CLK_S1D1),
+ DEF_MOD("gpio7", 905, R8A7796_CLK_S3D4),
+ DEF_MOD("gpio6", 906, R8A7796_CLK_S3D4),
+diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
+index 52c98ce..09d91ac 100644
+--- a/drivers/uio/Kconfig
++++ b/drivers/uio/Kconfig
+@@ -155,4 +155,12 @@ config UIO_MF624
+
+ If you compile this as a module, it will be called uio_mf624.
+
++config UIO_IMR
++ tristate "Renesas IMR support"
++
++ help
++ Renesas IMR device driver.
++ This driver supports the following SoCs:
++ - R8A7795, R8A7796, R8A7797.
++
+ endif
+diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
+index 8560dad..3d29324 100644
+--- a/drivers/uio/Makefile
++++ b/drivers/uio/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_UIO_NETX) += uio_netx.o
+ obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+ obj-$(CONFIG_UIO_MF624) += uio_mf624.o
+ obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o
++obj-$(CONFIG_UIO_IMR) += uio_imr.o
+diff --git a/drivers/uio/uio_imr.c b/drivers/uio/uio_imr.c
+new file mode 100644
+index 0000000..a64c65e
+--- /dev/null
++++ b/drivers/uio/uio_imr.c
+@@ -0,0 +1,495 @@
++/*************************************************************************/ /*
++ IMR
++
++ Copyright (C) 2015-2017 Renesas Electronics Corporation
++
++ License Dual MIT/GPLv2
++
++ The contents of this file are subject to the MIT license as set out below.
++
++ Permission is hereby granted, free of charge, to any person obtaining a copy
++ of this software and associated documentation files (the "Software"), to deal
++ in the Software without restriction, including without limitation the rights
++ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ copies of the Software, and to permit persons to whom the Software is
++ furnished to do so, subject to the following conditions:
++
++ The above copyright notice and this permission notice shall be included in
++ all copies or substantial portions of the Software.
++
++ Alternatively, the contents of this file may be used under the terms of
++ the GNU General Public License Version 2 ("GPL") in which case the provisions
++ of GPL are applicable instead of those above.
++
++ If you wish to allow use of your version of this file only under the terms of
++ GPL, and not to allow others to use your version of this file under the terms
++ of the MIT license, indicate your decision by deleting the provisions above
++ and replace them with the notice and other provisions required by GPL as set
++ out in the file called "GPL-COPYING" included in this distribution. If you do
++ not delete the provisions above, a recipient may use your version of this file
++ under the terms of either the MIT license or GPL.
++
++ This License is also included in this distribution in the file called
++ "MIT-COPYING".
++
++ EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
++ PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
++ BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
++ PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
++ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
++ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++
++
++ GPLv2:
++ If you wish to use this file under the terms of GPL, following terms are
++ effective.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; version 2 of the License.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++*/ /*************************************************************************/
++
++/* PRQA S 292,2212,2214 EOF */
++#include <linux/platform_device.h>
++#include <linux/uio_driver.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++
++#include <linux/of.h>
++#include <linux/of_irq.h>
++
++/* IMR uio driver name */
++#define DRIVER_NAME "uio_imr"
++
++/* IMR register definition */
++#define IMR_REG_IMR_ADDRESS (0x018U)
++#define IMR_REG_IMR_BIT_BASE (0x3U << 3)
++#define IMR_REG_IMR_BIT_INT (0x1U << 2)
++#define IMR_REG_IMR_BIT_IER (0x1U << 1)
++#define IMR_REG_IMR_BIT_TRA (0x1U << 0)
++
++/**
++ * struct uio_platdata - the uio platform data structure
++ * @uioinfo: UIO device capabilities
++ * @lock lock flag for irq.
++ * @flags: flags for request_irq.
++ * @pdev: IMR platform device data.
++ * @base_reg: IMR base register address.
++ * @clk: clock data.
++ *
++ * the uio platform data structure.
++ */
++struct uio_platdata {
++ struct uio_info *uioinfo;
++ spinlock_t lock;
++ unsigned long flags;
++ struct platform_device *pdev;
++ void __iomem *base_reg;
++ struct clk *clock;
++};
++
++static void write_register(struct uio_platdata *priv,
++ u32 reg_offs, u32 data);
++static int uio_imr_open(struct uio_info *info,
++ __attribute__((unused)) struct inode *inode);
++static int uio_imr_release(struct uio_info *info,
++ __attribute__((unused)) struct inode *inode);
++static irqreturn_t uio_imr_handler(__attribute__((unused)) int irq,
++ struct uio_info *dev_info);
++static int uio_imr_irqcontrol(struct uio_info *info, s32 irq_on);
++static int uio_imr_probe(struct platform_device *pdev);
++static int uio_imr_remove(struct platform_device *pdev);
++static int uio_runtime_imr_nop(__attribute__((unused)) struct device *dev);
++
++/**
++ * write_register() - register setting
++ * @priv: uio platform data.
++ * @reg_offs: register offset.
++ * @data: register value.
++ *
++ * register setting.
++ *
++ *
++ * Return: none
++ */
++static void write_register(struct uio_platdata *priv,
++ u32 reg_offs, u32 data)
++{
++ iowrite32(data, (u8 *)priv->base_reg + reg_offs); /* PRQA S 488 */
++}
++
++/**
++ * uio_imr_open() - open imr module
++ * @info: UIO device capabilities.
++ * @inode: inode.
++ *
++ * Open imr module.
++ *
++ *
++ * Return: 0 normal end.
++ */
++/* PRQA S 3206 2 */
++static int uio_imr_open(struct uio_info *info,
++ __attribute__((unused)) struct inode *inode)
++{
++ struct uio_platdata *pdata = info->priv;
++ /* PRQA S 3200 1 */
++ pr_debug("uio_imr_open enter. name=%s\n", pdata->uioinfo->name);
++
++ /* Wait until the Runtime PM code has woken up the device */
++ (void)pm_runtime_get_sync(&pdata->pdev->dev);
++
++ return 0;
++}
++
++/**
++ * uio_imr_release() - close imr module
++ * @info: UIO device capabilities.
++ * @inode: inode.
++ *
++ * Close imr module.
++ *
++ *
++ * Return: 0 normal end.
++ */
++/* PRQA S 3206 2 */
++static int uio_imr_release(struct uio_info *info,
++ __attribute__((unused)) struct inode *inode)
++{
++ struct uio_platdata *pdata = info->priv;
++
++ pr_debug("uio_imr_release enter\n"); /* PRQA S 3200 */
++
++ /* Tell the Runtime PM code that the device has become idle */
++ (void)pm_runtime_put_sync(&pdata->pdev->dev);
++
++ return 0;
++}
++
++/**
++ * uio_imr_handler() - IMR interrupt handler
++ * @irq: irq No.
++ * @dev_info: UIO device capabilities.
++ *
++ * IMR interrupt handler.
++ *
++ *
++ * Return: IRQ_HANDLED normal end.
++ */
++/* PRQA S 3206 1*/
++static irqreturn_t uio_imr_handler(__attribute__((unused))int irq,
++ struct uio_info *dev_info)
++{
++ struct uio_platdata *pdata = dev_info->priv;
++
++
++ pr_debug("uio_imr_handler enter\n"); /* PRQA S 3200 */
++
++ /* Mask interrupt */
++ write_register(pdata, IMR_REG_IMR_ADDRESS,
++ IMR_REG_IMR_BIT_BASE | (IMR_REG_IMR_BIT_INT |
++ IMR_REG_IMR_BIT_IER | IMR_REG_IMR_BIT_TRA));
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * uio_imr_irqcontrol() - IMR irq controller
++ * @info: UIO device capabilities.
++ * @irq_on: irq enable/disable.
++ *
++ * IMR irq controller. Enable and disable the interrupt.
++ *
++ *
++ * Return: 0 normal end.
++ */
++static int uio_imr_irqcontrol(struct uio_info *info, s32 irq_on)
++{
++ struct uio_platdata *pdata = info->priv;
++ u64 flag;
++
++ pr_debug("uio_imr_irqcontrol enter\n"); /* PRQA S 3200 */
++
++ spin_lock_irqsave(&pdata->lock, flag);
++ if (irq_on != 0) {
++ if (test_and_clear_bit(0, &pdata->flags) != 0)
++ enable_irq((u32)info->irq);
++ } else {
++ if (test_and_set_bit(0, &pdata->flags) == 0)
++ disable_irq((u32)info->irq);
++ }
++ spin_unlock_irqrestore(&pdata->lock, flag);
++
++ return 0;
++}
++
++/* PRQA S 1053,1041,605 10 */
++static const struct of_device_id rcar_imr_dt_ids[] = {
++ { .compatible = "renesas,imr-r8a7795", .data = 0 },
++ { .compatible = "renesas,imr-r8a7796", .data = 0 },
++ { .compatible = "renesas,imr-r8a7797", .data = 0 },
++ { .compatible = "renesas,imr-r8a7798", .data = 0 },
++ {},
++};
++MODULE_DEVICE_TABLE(of, rcar_imr_dt_ids); /* PRQA S 605 */
++
++/**
++ * uio_imr_probe() - Initialize IMR module.
++ * @pdev: platform device data.
++ *
++ * Initialize IMR module.
++ *
++ *
++ * Return: 0 normal end.
++ * -EINVAL parameter error.
++ * -ENOMEM memory error.
++ * -ENODEV system error.
++ */
++static int uio_imr_probe(struct platform_device *pdev)
++{
++ struct uio_info *uioinfo_data = NULL;
++ struct uio_platdata *pdata;
++ struct uio_mem *uiomem;
++ int ret = 0;
++ unsigned int i;
++ struct resource *rsc;
++ unsigned int irq_l;
++ unsigned long remap_size;
++
++ if (pdev == NULL) {
++ pr_err("missing pdev\n");
++ ret = -EINVAL;
++ } else {
++ if (pdev->dev.of_node == NULL) {
++ dev_err(&pdev->dev, "missing pdev->dev.of_node\n");
++ ret = -EINVAL;
++ }
++ }
++
++ if (ret == 0) {
++ pr_debug("uio_imr_probe enter name = %s\n", /* PRQA S 3200 */
++ pdev->dev.of_node->name);
++
++ uioinfo_data = devm_kzalloc(&pdev->dev,
++ sizeof(*uioinfo_data),
++ GFP_KERNEL);
++ if (uioinfo_data == NULL)
++ ret = -ENOMEM;
++ }
++
++ if (ret == 0) {
++ uioinfo_data->name = pdev->dev.of_node->name;
++ uioinfo_data->version = "0.1";
++
++ /* get irq number */
++ irq_l = irq_of_parse_and_map(pdev->dev.of_node, 0);
++ if ((int)irq_l == -ENXIO)
++ uioinfo_data->irq = platform_get_irq(pdev, 0);
++ else
++ uioinfo_data->irq = (int)irq_l;
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (pdata == NULL)
++ ret = -ENOMEM;
++ }
++
++ if (ret == 0) {
++ pdata->uioinfo = uioinfo_data;
++ spin_lock_init(&pdata->lock); /* PRQA S 3200 */
++ pdata->flags = 0;
++ pdata->pdev = pdev;
++
++ uiomem = &uioinfo_data->mem[0];
++
++ for (i = 0; i < pdev->num_resources; ++i) {
++ /* PRQA S 491 1 */
++ struct resource *r = &pdev->resource[i];
++
++ if (r->flags == IORESOURCE_IRQ) {
++ uioinfo_data->irq = (long)r->start;
++ } else if (r->flags != IORESOURCE_MEM) {
++ ;
++ } else {
++ if (uiomem >=
++ &uioinfo_data->mem[MAX_UIO_MAPS]) {
++ dev_warn(&pdev->dev,
++ "device has more than "
++ __stringify(MAX_UIO_MAPS)
++ " I/O memory resources.\n");
++ break;
++ }
++
++ uiomem->memtype = UIO_MEM_PHYS;
++ uiomem->addr = r->start;
++ uiomem->size = (r->end - r->start) + 1;
++ ++uiomem; /* PRQA S 489 */
++ }
++ }
++
++ while (uiomem < &uioinfo_data->mem[MAX_UIO_MAPS]) {
++ uiomem->size = 0;
++ ++uiomem; /* PRQA S 489 */
++ }
++
++ uioinfo_data->handler = &uio_imr_handler;
++ uioinfo_data->irqcontrol = &uio_imr_irqcontrol;
++ uioinfo_data->open = &uio_imr_open;
++ uioinfo_data->release = &uio_imr_release;
++ uioinfo_data->priv = pdata;
++
++ pm_runtime_enable(&pdev->dev);
++
++ ret = uio_register_device(&pdev->dev, pdata->uioinfo);
++ if (ret != 0) {
++ pm_runtime_disable(&pdev->dev);
++ dev_err(&pdev->dev, "could not register uio device\n");
++ ret = -ENODEV;
++ }
++ }
++
++ if (ret == 0) {
++ platform_set_drvdata(pdev, pdata);
++ pdata->clock = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(pdata->clock)) {
++ pm_runtime_disable(&pdev->dev);
++ dev_err(&pdev->dev, "could not get clock\n");
++ ret = -ENODEV;
++ } else {
++ /* clock enable */
++ (void)clk_prepare_enable(pdata->clock);
++ }
++ }
++
++ if (ret == 0) {
++ rsc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (rsc == 0) {
++ pm_runtime_disable(&pdev->dev);
++ dev_err(&pdev->dev, "could not platform_get_resource\n");
++ ret = -ENODEV;
++ }
++ }
++
++ if (ret == 0) {
++ remap_size = (rsc->end - rsc->start) + 1;
++ if (!request_mem_region(rsc->start,
++ remap_size,
++ uioinfo_data->name)) {
++ dev_err(&pdev->dev, "could not request IO\n");
++ pm_runtime_disable(&pdev->dev);
++ ret = -ENOMEM;
++ }
++ }
++
++ if (ret == 0) {
++ /* IMR Register Adderss */
++ pdata->base_reg = devm_ioremap_nocache(&pdev->dev,
++ rsc->start,
++ remap_size);
++ if (pdata->base_reg == NULL) {
++ release_mem_region(rsc->start, resource_size(rsc));
++ dev_err(&pdev->dev, "could not remap IMR register\n");
++ pm_runtime_disable(&pdev->dev);
++ ret = -ENOMEM;
++ } else {
++ /* PRQA S 3200 2 */
++ pr_debug("IMR reg_base = %x size = %x\n",
++ (uint32_t)(rsc->start), (uint32_t)remap_size);
++ }
++ }
++
++ return ret;
++}
++
++/**
++ * uio_imr_remove() - release IMR module.
++ * @pdev: platform device data.
++ *
++ * release IMR module.
++ *
++ *
++ * Return: 0 normal end.
++ */
++static int uio_imr_remove(struct platform_device *pdev)
++{
++ struct resource *rsc;
++ struct uio_platdata *pdata = platform_get_drvdata(pdev);
++
++ /* PRQA S 3200 1 */
++ pr_debug("uio_imr_remove enter name = %s\n", pdata->uioinfo->name);
++
++ clk_disable_unprepare(pdata->clock);
++
++ uio_unregister_device(pdata->uioinfo);
++
++ pm_runtime_disable(&pdev->dev);
++
++ irq_dispose_mapping((u32)pdata->uioinfo->irq);
++
++ pdata->uioinfo->handler = NULL;
++ pdata->uioinfo->irqcontrol = NULL;
++
++ platform_set_drvdata(pdev, NULL);
++
++ if (pdata->base_reg != NULL)
++ devm_iounmap(&pdev->dev, pdata->base_reg);
++
++ rsc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (rsc != 0)
++ release_mem_region(rsc->start, resource_size(rsc));
++
++ return 0;
++}
++
++/**
++ * uio_runtime_imr_nop() - Runtime PM callback function.
++ * @dev: device data.
++ *
++ * Runtime PM callback function.
++ *
++ *
++ * Return: 0 normal end.
++ */
++ /* PRQA S 3206 1 */
++static int uio_runtime_imr_nop(__attribute__((unused)) struct device *dev)
++{
++ pr_debug("uio_runtime_imr_nop enter\n"); /* PRQA S 3200 */
++ return 0;
++}
++/* PRQA S 1053 4 */
++static const struct dev_pm_ops uio_dev_pm_imr_ops = {
++ .runtime_suspend = &uio_runtime_imr_nop,
++ .runtime_resume = &uio_runtime_imr_nop,
++};
++
++static struct platform_driver uio_imr_platform_driver = {
++ .probe = &uio_imr_probe,
++ .remove = &uio_imr_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &uio_dev_pm_imr_ops,
++ .of_match_table = of_match_ptr(rcar_imr_dt_ids),
++ },
++};
++
++module_platform_driver(uio_imr_platform_driver);
++
++
++MODULE_AUTHOR("Renesas Electronics Corporation");
++MODULE_DESCRIPTION("Userspace I/O driver for IMR");
++MODULE_LICENSE("Dual MIT/GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0128-rcar_imr-v4l2-driver-Fix-module-support.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0128-rcar_imr-v4l2-driver-Fix-module-support.patch
new file mode 100644
index 0000000..f4ee6e2
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0128-rcar_imr-v4l2-driver-Fix-module-support.patch
@@ -0,0 +1,321 @@
+From 772299b20e32fc3ff86de4a83845e8246d97bcbb Mon Sep 17 00:00:00 2001
+From: Andrey Dolnikov <andrey.dolnikov@cogentembedded.com>
+Date: Mon, 9 Apr 2018 12:50:23 +0300
+Subject: [PATCH 2/2] rcar_imr v4l2 driver: Fix module support.
+
+---
+ arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi | 8 +++++++
+ arch/arm64/boot/dts/renesas/r8a7795.dtsi | 8 +++++++
+ arch/arm64/boot/dts/renesas/r8a7796.dtsi | 6 ++++++
+ arch/arm64/boot/dts/renesas/r8a7797.dtsi | 8 +++++++
+ arch/arm64/boot/dts/renesas/r8a7798.dtsi | 10 +++++++++
+ drivers/media/platform/rcar_imr.c | 32 +++++++++++++++++++++++++---
+ 6 files changed, 69 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
+index 745493c..f2769c2 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
+@@ -2899,12 +2899,17 @@
+ power-domains = <&sysc R8A7795_PD_A3IR>;
+ };
+
++ imr_v4l2_alloc: imr_alloc {
++ dma-coherent;
++ };
++
+ imrlx4_ch0: imr0@fe860000 {
+ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
+ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch1: imr1@fe870000 {
+@@ -2913,6 +2918,7 @@
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch2: imr2@fe880000 {
+@@ -2921,6 +2927,7 @@
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch3: imr3@fe890000 {
+@@ -2929,6 +2936,7 @@
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+index 96e182a..366ee5f 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+@@ -2895,12 +2895,17 @@
+ power-domains = <&sysc R8A7795_PD_A3IR>;
+ };
+
++ imr_v4l2_alloc: imr_alloc {
++ dma-coherent;
++ };
++
+ imrlx4_ch0: imr0@fe860000 {
+ compatible = "renesas,imr-lx4", "renesas,imr-r8a7795";
+ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch1: imr1@fe870000 {
+@@ -2909,6 +2914,7 @@
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch2: imr2@fe880000 {
+@@ -2917,6 +2923,7 @@
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch3: imr3@fe890000 {
+@@ -2925,6 +2932,7 @@
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7795_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+index b747f0c..442f027 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+@@ -1174,12 +1174,17 @@
+ status = "disabled";
+ };
+
++ imr_v4l2_alloc: imr_alloc {
++ dma-coherent;
++ };
++
+ imrlx4_ch0: imr0@fe860000 {
+ compatible = "renesas,imr-lx4", "renesas,imr-r8a7796";
+ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7796_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch1: imr1@fe870000 {
+@@ -1188,6 +1193,7 @@
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7796_PD_A3VC>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ can0: can@e6c30000 {
+diff --git a/arch/arm64/boot/dts/renesas/r8a7797.dtsi b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+index c878467..16e73b4 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7797.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7797.dtsi
+@@ -1239,12 +1239,17 @@
+ power-domains = <&sysc R8A7797_PD_A3IR>;
+ };
+
++ imr_v4l2_alloc: imr_alloc {
++ dma-coherent;
++ };
++
+ imrlx4_ch0: imr0@fe860000 {
+ compatible = "renesas,imr-lx4", "renesas,imr-r8a7797";
+ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch1: imr1@fe870000 {
+@@ -1253,6 +1258,7 @@
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch2: imr2@fe880000 {
+@@ -1261,6 +1267,7 @@
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch3: imr3@fe890000 {
+@@ -1269,6 +1276,7 @@
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7798.dtsi b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+index 7bfd0483..0742ec0 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7798.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7798.dtsi
+@@ -1588,12 +1588,17 @@
+ power-domains = <&sysc R8A7798_PD_A3IR>;
+ };
+
++ imr_v4l2_alloc: imr_alloc {
++ dma-coherent;
++ };
++
+ imrlx4_ch0: imr0@fe860000 {
+ compatible = "renesas,imr-lx4", "renesas,imr-r8a7798";
+ reg = <0 0xfe860000 0 0x10000>;
+ interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 823>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch1: imr1@fe870000 {
+@@ -1602,6 +1607,7 @@
+ interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 822>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch2: imr2@fe880000 {
+@@ -1610,6 +1616,7 @@
+ interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 821>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch3: imr3@fe890000 {
+@@ -1618,6 +1625,7 @@
+ interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 820>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ };
+
+ imrlx4_ch4: imr4@fe8a0000 {
+@@ -1626,6 +1634,7 @@
+ interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 707>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ rse;
+ };
+
+@@ -1635,6 +1644,7 @@
+ interrupts = <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 706>;
+ power-domains = <&sysc R8A7798_PD_ALWAYS_ON>;
++ alloc-dev = <&imr_v4l2_alloc>;
+ rse;
+ };
+
+diff --git a/drivers/media/platform/rcar_imr.c b/drivers/media/platform/rcar_imr.c
+index 7b16765..3558211 100644
+--- a/drivers/media/platform/rcar_imr.c
++++ b/drivers/media/platform/rcar_imr.c
+@@ -18,6 +18,7 @@
+ #include <linux/delay.h>
+ #include <linux/rcar-imr.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ctrls.h>
+ #include <media/v4l2-fh.h>
+@@ -1917,6 +1918,8 @@ static int imr_probe(struct platform_device *pdev)
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
++ phandle *prop;
++ struct device_node *node;
+
+ imr = devm_kzalloc(&pdev->dev, sizeof(*imr), GFP_KERNEL);
+ if (!imr)
+@@ -1989,10 +1992,15 @@ static int imr_probe(struct platform_device *pdev)
+ ret = PTR_ERR(adev);
+ goto m2m_init_rollback;
+ }
++
+ adev->dma_mask = &adev->coherent_dma_mask;
+ adev->coherent_dma_mask = DMA_BIT_MASK(32);
+- arch_setup_dma_ops(adev, 0, DMA_BIT_MASK(32) + 1, NULL, true);
+ imr->alloc_dev = adev;
++ prop = of_get_property(np, "alloc-dev", NULL);
++ if (prop) {
++ node = of_find_node_by_phandle(be32_to_cpup(prop));
++ of_dma_configure(adev, node);
++ }
+
+ strlcpy(imr->video_dev.name, dev_name(&pdev->dev), sizeof(imr->video_dev.name));
+ imr->video_dev.fops = &imr_fops;
+@@ -2032,7 +2040,6 @@ static int imr_remove(struct platform_device *pdev)
+
+ //pm_runtime_disable(imr->v4l2_dev.dev);
+ video_unregister_device(&imr->video_dev);
+- //device_destroy(imr->alloc_dev, MKDEV(0, 0));
+ v4l2_m2m_release(imr->m2m_dev);
+ v4l2_device_unregister(&imr->v4l2_dev);
+
+@@ -2100,7 +2107,26 @@ static struct platform_driver imr_platform_driver = {
+ },
+ };
+
+-module_platform_driver(imr_platform_driver);
++static int __init imr_module_init(void)
++{
++ return platform_driver_register(&imr_platform_driver);
++}
++
++static int imr_device_destroy(struct device *dev, void *data)
++{
++ device_destroy(imr_alloc_class, dev->devt);
++ return 0;
++}
++
++static void __exit imr_module_exit(void)
++{
++ class_for_each_device(imr_alloc_class, NULL, NULL, imr_device_destroy);
++ class_destroy(imr_alloc_class);
++ platform_driver_unregister(&imr_platform_driver);
++}
++
++module_init(imr_module_init);
++module_exit(imr_module_exit);
+
+ MODULE_ALIAS("imr");
+ MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>");
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0129-Add-cropping-handling-to-VSP-alpha-planes.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0129-Add-cropping-handling-to-VSP-alpha-planes.patch
new file mode 100644
index 0000000..d55b196
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0129-Add-cropping-handling-to-VSP-alpha-planes.patch
@@ -0,0 +1,44 @@
+From 4b26e8c561541c68c5755660eaad355d9a9afc86 Mon Sep 17 00:00:00 2001
+From: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com>
+Date: Wed, 11 Apr 2018 05:11:21 -0700
+Subject: [PATCH] Add cropping handling to VSP alpha-planes
+
+---
+ drivers/media/platform/vsp1/vsp1_dl.c | 2 +-
+ drivers/media/platform/vsp1/vsp1_rpf.c | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
+index f9c6d09..d6314cd 100644
+--- a/drivers/media/platform/vsp1/vsp1_dl.c
++++ b/drivers/media/platform/vsp1/vsp1_dl.c
+@@ -363,7 +363,7 @@ void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf)
+ dl->src_dst_addr[v_bot_index].addr = v_bot_addr;
+
+ /* ...set alpha-plane address as needed */
+- dl->src_dst_addr[alpha_index].addr = rpf->mem.alpha;
++ dl->src_dst_addr[alpha_index].addr = rpf->mem.alpha + crop->top * width + crop->left;
+ }
+
+ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
+diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
+index 2cce294..1f70186 100644
+--- a/drivers/media/platform/vsp1/vsp1_rpf.c
++++ b/drivers/media/platform/vsp1/vsp1_rpf.c
+@@ -292,10 +292,11 @@ static void rpf_configure(struct vsp1_entity *entity,
+
+ // ...setup alpha-plane as required
+ if (rpf->mem.alpha) {
+- vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_AI, rpf->mem.alpha);
++ struct v4l2_rect *crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
++ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_AI, rpf->mem.alpha + crop->top * rpf->alpha_pitch + crop->left);
+ vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_ASEL_8B_PLANE);
+ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ASTRIDE, rpf->alpha_pitch);
+- dev_dbg(vsp1->dev, "rpf#%d: setup alpha-plane: buffer=%pad, stride=%u\n", rpf->entity.index, &rpf->mem.alpha, rpf->alpha_pitch);
++ dev_dbg(vsp1->dev, "rpf#%d: setup alpha-plane: buffer=%pad, crop=%d,%d, stride=%u\n", rpf->entity.index, &rpf->mem.alpha, crop->left, crop->top, rpf->alpha_pitch);
+ goto out;
+ }
+
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0130-Add-RAW-sensors-MBUS-formats.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0130-Add-RAW-sensors-MBUS-formats.patch
new file mode 100644
index 0000000..3278fc2
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0130-Add-RAW-sensors-MBUS-formats.patch
@@ -0,0 +1,36 @@
+From f977b84f5899093208f64b31731ea991579d6f8f Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 13 Apr 2018 16:51:15 +0300
+Subject: [PATCH] Add RAW sensors MBUS formats.
+
+---
+ drivers/media/platform/soc_camera/rcar_vin.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
+index 37f1a11..b4ea2de 100644
+--- a/drivers/media/platform/soc_camera/rcar_vin.c
++++ b/drivers/media/platform/soc_camera/rcar_vin.c
+@@ -1074,6 +1074,9 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
+ break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
++ case MEDIA_BUS_FMT_SRGGB12_1X12:
++ case MEDIA_BUS_FMT_SGRBG12_1X12:
++ case MEDIA_BUS_FMT_SGRBG14_1X14:
+ vnmc |= VNMC_INF_RAW8 | VNMC_BPS;
+ break;
+ default:
+@@ -2213,6 +2216,9 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
++ case MEDIA_BUS_FMT_SRGGB12_1X12:
++ case MEDIA_BUS_FMT_SGRBG12_1X12:
++ case MEDIA_BUS_FMT_SGRBG14_1X14:
+ if (cam->extra_fmt)
+ break;
+
+--
+2.7.4
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0131-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch
index 8d7409a..8d7409a 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0112-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0131-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg
index c0300de..8efcbff 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg
@@ -21,7 +21,6 @@ CONFIG_SOC_CAMERA_SCALE_CROP=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
CONFIG_SOC_CAMERA_OV106XX=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_UINPUT=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg
index 3a07f36..2b4cdc1 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg
@@ -21,7 +21,6 @@ CONFIG_SOC_CAMERA_SCALE_CROP=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
CONFIG_SOC_CAMERA_OV106XX=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_UINPUT=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/imr.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/imr.cfg
new file mode 100644
index 0000000..cc7f69e
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/imr.cfg
@@ -0,0 +1,3 @@
+CONFIG_VIDEO_RENESAS_IMR=m
+CONFIG_UIO=y
+CONFIG_UIO_IMR=m
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg
new file mode 100644
index 0000000..9a1c695
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg
@@ -0,0 +1,3 @@
+CONFIG_SPI_RENESAS_RPC=y
+CONFIG_MTD_BLOCK=y
+CONFIG_JFFS2_FS=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg
index 36c6103..4af8122 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg
@@ -24,7 +24,6 @@ CONFIG_USB_XHCI_PLATFORM=y
CONFIG_USB_XHCI_RCAR=y
CONFIG_MMC_SDHI_PRE_REQ=y
CONFIG_MMC_SDHI_SEQ=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
CONFIG_HID_MULTITOUCH=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
index 5442f19..2714452 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
@@ -37,7 +37,6 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PLATFORM=y
CONFIG_USB_XHCI_RCAR=y
CONFIG_USB_ACM=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_VIRTIO_RCAR_PCIE=y
CONFIG_BT=y
CONFIG_BT_BNEP=m
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
index 218909c..c3cec9a 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
@@ -25,7 +25,6 @@ CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
CONFIG_SOC_CAMERA_TI9X4=y
CONFIG_SOC_CAMERA_OV106XX=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_UINPUT=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg
index c32752e..3af1cea 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg
@@ -25,7 +25,6 @@ CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
CONFIG_SOC_CAMERA_TI9X4=y
CONFIG_SOC_CAMERA_OV106XX=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_UINPUT=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3mzf.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3mzf.cfg
index 3d3bc5a..bf4f35e 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3mzf.cfg
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3mzf.cfg
@@ -18,9 +18,7 @@ CONFIG_SOC_CAMERA_SCALE_CROP=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_TI9X4=y
CONFIG_SOC_CAMERA_OV106XX=y
-CONFIG_VIDEO_RENESAS_IMR=y
CONFIG_SERIAL_SH_SCI_DMA=y
-CONFIG_UIO=y
CONFIG_SPI_SLAVE=y
CONFIG_SPI_SLAVE_TIME=y
CONFIG_SPI_SLAVE_SYSTEM_CONTROL=y
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend
index c7c7f96..b35a8e1 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend
@@ -9,6 +9,8 @@ COMPATIBLE_MACHINE_v3hsk = "v3hsk"
SRC_URI_append = " \
${@bb.utils.contains('MACHINE_FEATURES', 'h3ulcb-had', ' file://hyperflash.cfg', '', d)} \
${@base_conditional("SDHI_SEQ", "1", " file://sdhi_seq.cfg", "", d)} \
+ file://qspi.cfg \
+ file://imr.cfg \
file://0001-spi-sh-msiof-fixes.patch \
file://0002-spi-spidev-add-spi-gpio-into-spidev.patch \
file://0003-spi-spi-gpio-fix-CPOL-mode.patch \
@@ -87,7 +89,28 @@ SRC_URI_append = " \
file://0107-V3H-device-tree-Add-VIP-devices-IRQs.patch \
file://0108-can-mcp251x-add-reset-gpio-support.patch \
file://0109-ASoC-R-Car-fix-incorrect-behavior-with-PulseAudio.patch \
- file://0112-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch \
+ file://0110-Renesas-clk-Add-RPC-clock-source.patch \
+ file://0111-Renesas-r8a7798-Add-RPC-clock.patch \
+ file://0112-Renesas-r8a7798-pinctrl-Add-RPC-pin-control.patch \
+ file://0113-Renesas-RPC-Add-RPC-driver.patch \
+ file://0114-R8A7798-dtsi-Add-RPC-node-to-dtsi.patch \
+ file://0115-R8A7798-condor-dts-Add-qspi-flash.patch \
+ file://0116-spi-nor-Add-s25fs512-flash-support.patch \
+ file://0117-spi-nor-Add-flash-array-support.patch \
+ file://0118-r8a7797-clk-Add-rpc-clock.patch \
+ file://0119-r8a7797-pinctrl-Add-qspi-pins.patch \
+ file://0120-r8a7797-dtsi-Add-rpc-node.patch \
+ file://0121-r8a7797-eagle-dts-Add-spi-flash-node.patch \
+ file://0122-r8a7797-v3msk-r8a7797-v3mzf-dts-Add-spi-flash-s25fs5.patch \
+ file://0123-V3HSK-dts-Add-qspi-node.patch \
+ file://0124-RPC-Hyperflash-Add-devicetree-support.patch \
+ file://0125-r8a7797-pinctrl-Add-pin-function-for-hyperflash.patch \
+ file://0126-r8a7798-pinctrl-Add-pin-function-for-hyperflash.patch \
+ file://0127-IMR-UIO-Driver-initial-version.patch \
+ file://0128-rcar_imr-v4l2-driver-Fix-module-support.patch \
+ file://0129-Add-cropping-handling-to-VSP-alpha-planes.patch \
+ file://0130-Add-RAW-sensors-MBUS-formats.patch \
+ file://0131-ARM64-dts-renesas-ulcb-Make-AK4613-sound-device-name.patch \
"
SRC_URI_append_h3ulcb = " file://ulcb.cfg"
@@ -163,7 +186,13 @@ KERNEL_DEVICETREE_append_v3hsk = " \
renesas/r8a7798-v3hsk-vbm-v2-isp.dtb \
"
+# Prefer V4L2 rcar_imr driver over UIO uio_imr
+KERNEL_MODULE_AUTOLOAD += "rcar_imr"
+KERNEL_MODULE_PROBECONF += "rcar_imr"
+KERNEL_MODULE_PROBECONF += "uio_imr"
+module_conf_uio_imr = 'blacklist uio_imr'
+
# V3H VIP devices
-KERNEL_MODULE_AUTOLOAD_r8a7798 += "uio_pdrv_genirq"
-KERNEL_MODULE_PROBECONF_r8a7798 += "uio_pdrv_genirq"
+KERNEL_MODULE_AUTOLOAD_append_r8a7798 += " uio_pdrv_genirq"
+KERNEL_MODULE_PROBECONF_append_r8a7798 += " uio_pdrv_genirq"
module_conf_uio_pdrv_genirq_r8a7798 = 'options uio_pdrv_genirq of_id="generic-uio"'