diff options
author | Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> | 2015-03-25 10:47:45 +0900 |
---|---|---|
committer | Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> | 2015-03-25 10:47:45 +0900 |
commit | 1c35920d85e424b3f65aa6df1dbde689dd6ec007 (patch) | |
tree | 58b2cacb3674111aad5a4ded694db0cef5cf55f3 /meta-rcar-gen2/recipes-kernel/linux/linux-renesas |
commit BSP v1.8.0
Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas')
23 files changed, 5173 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-alt-Add-vmalloc-384M-to-bootargs-of-DTS.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-alt-Add-vmalloc-384M-to-bootargs-of-DTS.patch new file mode 100644 index 0000000..b7d23b2 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-alt-Add-vmalloc-384M-to-bootargs-of-DTS.patch @@ -0,0 +1,26 @@ +From 7baf674a7c54d3241d796adf3249b304aa2aeaaf Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +Date: Mon, 14 Jul 2014 11:44:41 +0900 +Subject: [PATCH] arm: shmobile: alt: Add 'vmalloc=384M' to bootargs of DTS + +Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +--- + arch/arm/boot/dts/r8a7794-alt.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts +index 3e1afef..c85edda8 100644 +--- a/arch/arm/boot/dts/r8a7794-alt.dts ++++ b/arch/arm/boot/dts/r8a7794-alt.dts +@@ -31,7 +31,7 @@ + compatible = "renesas,alt", "renesas,r8a7794"; + + chosen { +- bootargs = "console=ttySC10,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; ++ bootargs = "console=ttySC10,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; + }; + + memory@40000000 { +-- +1.7.9.5 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-gose-Add-vmalloc-384M-to-bootargs-of-DTS.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-gose-Add-vmalloc-384M-to-bootargs-of-DTS.patch new file mode 100644 index 0000000..5c282c8 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-gose-Add-vmalloc-384M-to-bootargs-of-DTS.patch @@ -0,0 +1,26 @@ +From f1b6ab8592afda486b6c4c513f39dfbe2a4e8334 Mon Sep 17 00:00:00 2001 +From: Dien Pham <dien.pham.ry@rvc.renesas.com> +Date: Fri, 15 Aug 2014 14:59:45 +0700 +Subject: [PATCH] arm gose Add vmalloc 384M to bootargs of DTS + +Signed-off-by: Dien Pham <dien.pham.ry@rvc.renesas.com> +--- + arch/arm/boot/dts/r8a7793-gose.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts +index 9c0108b..fbe3566 100644 +--- a/arch/arm/boot/dts/r8a7793-gose.dts ++++ b/arch/arm/boot/dts/r8a7793-gose.dts +@@ -36,7 +36,7 @@ + }; + + chosen { +- bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; ++ bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; + }; + + memory@40000000 { +-- +1.8.0.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-koelsch-Add-vmalloc-384M-to-bootargs-of-DTS.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-koelsch-Add-vmalloc-384M-to-bootargs-of-DTS.patch new file mode 100644 index 0000000..d32019f --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-koelsch-Add-vmalloc-384M-to-bootargs-of-DTS.patch @@ -0,0 +1,26 @@ +From 6f5df111b2cf5d4cb01922da7076a7ab238f5650 Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +Date: Mon, 14 Jul 2014 11:43:03 +0900 +Subject: [PATCH 1/3] arm: shmobile: koelsch: Add 'vmalloc=384M' to bootargs of DTS + +Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +--- + arch/arm/boot/dts/r8a7791-koelsch.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts +index 5dc4f7d..d3619fc 100644 +--- a/arch/arm/boot/dts/r8a7791-koelsch.dts ++++ b/arch/arm/boot/dts/r8a7791-koelsch.dts +@@ -39,7 +39,7 @@ + }; + + chosen { +- bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; ++ bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; + }; + + memory@40000000 { +-- +1.7.9.5 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-lager-Add-vmalloc-384M-to-bootargs-of-DTS.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-lager-Add-vmalloc-384M-to-bootargs-of-DTS.patch new file mode 100644 index 0000000..8d19c6d --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-arm-lager-Add-vmalloc-384M-to-bootargs-of-DTS.patch @@ -0,0 +1,26 @@ +From 7a6b38f46db215055017a3288bd0d0bc6cfd5e8d Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +Date: Mon, 14 Jul 2014 11:43:33 +0900 +Subject: [PATCH] arm: shmobile: lager: Add 'vmalloc=384M' to bootargs of DTS + +Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> +--- + arch/arm/boot/dts/r8a7790-lager.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts +index 58b30a2..e0ac607 100644 +--- a/arch/arm/boot/dts/r8a7790-lager.dts ++++ b/arch/arm/boot/dts/r8a7790-lager.dts +@@ -38,7 +38,7 @@ + }; + + chosen { +- bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; ++ bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; + }; + + memory@40000000 { +-- +1.7.9.5 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-kernel-Silk-board-support.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-kernel-Silk-board-support.patch new file mode 100644 index 0000000..12fb76c --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0001-kernel-Silk-board-support.patch @@ -0,0 +1,1456 @@ +From f04a201ce9bfc04ca4b8b017116ca1cf9a313c9a Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Sat, 6 Dec 2014 03:29:15 +0300 +Subject: [linux-kernel][PATCH] arm: rmobile: Add SILK board support + +SILK is an entry level development board based on R-Car E2 SoC (R8A7794) + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> + +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/r8a7794-silk.dts | 360 ++++++++++ + arch/arm/configs/shmobile_defconfig | 1 + + arch/arm/mach-shmobile/Kconfig | 6 + + arch/arm/mach-shmobile/Makefile | 1 + + arch/arm/mach-shmobile/Makefile.boot | 1 + + arch/arm/mach-shmobile/board-silk-reference.c | 995 ++++++++++++++++++++++++++ + 7 files changed, 1365 insertions(+) + create mode 100644 arch/arm/boot/dts/r8a7794-silk.dts + create mode 100644 arch/arm/mach-shmobile/board-silk-reference.c + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 2a7b49b..f2b99db 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -178,6 +178,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \ + r8a7791-koelsch.dtb \ + r8a7790-lager.dtb \ + r8a7794-alt.dtb \ ++ r8a7794-silk.dtb \ + r8a7793-gose.dtb \ + r8a7779-marzen.dtb + dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb \ +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +new file mode 100644 +index 0000000..cb69f6b +--- /dev/null ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -0,0 +1,360 @@ ++/* ++ * Device Tree Source for the Silk board ++ * ++ * Copyright (C) 2014 Renesas Electronics Corporation ++ * Copyright (C) 2014 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++/* ++ * SSI-AK4643 ++ * ++ * SW1: 1: AK4643 ++ * 3: ADV7511 ++ * ++ * this command is required when playback. ++ * ++ * # amixer set "LINEOUT Mixer DACL" on ++ * # amixer set "Digital" 200 ++ * # amixer set "DVC Out" 50 ++ */ ++ ++/dts-v1/; ++#include "r8a7794.dtsi" ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/input/input.h> ++ ++/ { ++ model = "Silk"; ++ compatible = "renesas,silk", "renesas,r8a7794"; ++ ++ aliases { ++ serial10 = &scif2; ++ }; ++ ++ chosen { ++ bootargs = "console=ttySC10,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0 0x40000000 0 0x40000000>; ++ }; ++ ++ lbsc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ key-1 { ++ gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_1>; ++ label = "SW12"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-2 { ++ gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_2>; ++ label = "SW12"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-3 { ++ gpios = <&gpio3 11 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_3>; ++ label = "SW12"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-4 { ++ gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_4>; ++ label = "SW12"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-a { ++ gpios = <&gpio5 10 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_A>; ++ label = "SW3"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-b { ++ gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_B>; ++ label = "SW4"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ key-c { ++ gpios = <&gpio5 12 GPIO_ACTIVE_LOW>; ++ linux,code = <KEY_C>; ++ label = "SW6"; ++ gpio-key,wakeup; ++ debounce-interval = <20>; ++ }; ++ }; ++ ++ vcc_sdhi0: regulator@0 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI0 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpio = <&gpio2 26 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ vccq_sdhi0: regulator@1 { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "SDHI0 VccQ"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>; ++ gpios-states = <1>; ++ states = <3300000 1 ++ 1800000 0>; ++ }; ++ ++ vcc_sdhi1: regulator@2 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI1 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpio = <&gpio4 26 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ vccq_sdhi1: regulator@3 { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "SDHI1 VccQ"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>; ++ gpios-states = <1>; ++ states = <3300000 1 ++ 1800000 0>; ++ }; ++ ++ fixedregulator3v3: fixedregulator@0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ hdmi_transmitter: adv7511 { ++ compatible = "adi,adv7511"; ++ gpios = <&gpio5 23 GPIO_ACTIVE_LOW>; ++ ++ adi,input-style = <0x02>; ++ adi,input-id = <0x00>; ++ adi,input-color-depth = <0x03>; ++ adi,sync-pulse = <0x03>; ++ adi,bit-justification = <0x01>; ++ adi,up-conversion = <0x00>; ++ adi,timing-generation-sequence = <0x00>; ++ adi,vsync-polarity = <0x02>; ++ adi,hsync-polarity = <0x02>; ++ adi,clock-delay = <0x03>; ++ }; ++}; ++ ++&extal_clk { ++ clock-frequency = <20000000>; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ snd_codec: ak4643 { ++ #sound-dai-cells = <0>; ++ compatible = "asahi-kasei,ak4643"; ++ reg = <0x12>; ++ }; ++}; ++ ++&i2c8 { ++ status = "okay"; ++ clock-frequency = <100000>; ++}; ++ ++&pfc { ++ pinctrl-0 = <&du_pins &usb0_pins &usb1_pins &sound_pins &sound_clk_pins ++ &vin0_pins>; ++ pinctrl-names = "default"; ++ ++ du_pins: du { ++ renesas,groups = "du0_rgb888", "du0_sync", "du0_clk_out", ++ "du1_rgb666", "du1_sync", "du1_clk_out"; ++ renesas,function = "du"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ renesas,groups = "i2c1"; ++ renesas,function = "i2c1"; ++ }; ++ ++ scif2_pins: serial2 { ++ renesas,groups = "scif2_data"; ++ renesas,function = "scif2"; ++ }; ++ ++ ether_pins: ether { ++ renesas,groups = "eth_link", "eth_mdio", "eth_rmii"; ++ renesas,function = "eth"; ++ }; ++ ++ qspi_pins: spi0 { ++ renesas,groups = "qspi_ctrl", "qspi_data4"; ++ renesas,function = "qspi"; ++ }; ++ ++ sdhi0_pins: sd0 { ++ renesas,groups = "sdhi0_data4", "sdhi0_ctrl"; ++ renesas,function = "sdhi0"; ++ }; ++ ++ sdhi1_pins: sd1 { ++ renesas,groups = "sdhi1_data4", "sdhi1_ctrl"; ++ renesas,function = "sdhi1"; ++ }; ++ ++ mmc0_pins: mmc0 { ++ renesas,groups = "mmc_data8", "mmc_ctrl"; ++ renesas,function = "mmc"; ++ }; ++ ++ usb0_pins: usb0 { ++ renesas,groups = "usb0"; ++ renesas,function = "usb0"; ++ }; ++ ++ usb1_pins: usb1 { ++ renesas,groups = "usb1"; ++ renesas,function = "usb1"; ++ }; ++ ++ vin0_pins: vin0 { ++ renesas,groups = "vin0_data8", "vin0_sync", "vin0_field", ++ "vin0_clkenb", "vin0_clk"; ++ renesas,function = "vin0"; ++ }; ++ ++ sound_pins: sound { ++ renesas,groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data"; ++ renesas,function = "ssi"; ++ }; ++ sound_clk_pins: sound_clk { ++ renesas,groups = "audio_clk_c"; ++ renesas,function = "audio_clk"; ++ }; ++}; ++ ++ðer { ++ phy-handle = <&phy1>; ++ renesas,ether-link-active-low; ++ status = "ok"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ interrupt-parent = <&irqc0>; ++ interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ micrel,led-mode = <1>; ++ }; ++}; ++ ++&scif2 { ++ pinctrl-0 = <&scif2_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&qspi { ++ pinctrl-0 = <&qspi_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ ++ flash: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,s25fl512s"; ++ reg = <0>; ++ spi-max-frequency = <30000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ m25p,fast-read; ++ spi-cpol; ++ spi-cpha; ++ ++ partition@0 { ++ label = "loader"; ++ reg = <0x00000000 0x00040000>; ++ read-only; ++ }; ++ partition@40000 { ++ label = "user"; ++ reg = <0x00040000 0x00400000>; ++ read-only; ++ }; ++ partition@440000 { ++ label = "flash"; ++ reg = <0x00440000 0x03bc0000>; ++ }; ++ }; ++}; ++ ++&sdhi0 { ++ pinctrl-0 = <&sdhi0_pins>; ++ pinctrl-names = "default"; ++ ++ vmmc-supply = <&vcc_sdhi0>; ++ vqmmc-supply = <&vccq_sdhi0>; ++ cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>; ++ wp-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&sdhi1 { ++ pinctrl-0 = <&sdhi1_pins>; ++ pinctrl-names = "default"; ++ ++ vmmc-supply = <&vcc_sdhi1>; ++ vqmmc-supply = <&vccq_sdhi1>; ++ cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>; ++ wp-gpios = <&gpio6 15 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&mmcif0 { ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ ++ vmmc-supply = <&fixedregulator3v3>; ++ bus-width = <8>; ++ non-removable; ++ status = "okay"; ++}; +diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig +index efdc321..11237db 100644 +--- a/arch/arm/configs/shmobile_defconfig ++++ b/arch/arm/configs/shmobile_defconfig +@@ -24,6 +24,7 @@ CONFIG_MACH_KOELSCH=y + CONFIG_MACH_LAGER=y + CONFIG_MACH_GOSE=y + CONFIG_MACH_ALT=y ++CONFIG_MACH_SILK=y + CONFIG_MACH_MARZEN=y + CONFIG_SHMOBILE_TIMER_HZ=100 + CONFIG_ARM_LPAE=y +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index bb1b599..e2e00a9 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -82,6 +82,12 @@ config MACH_ALT + select MICREL_PHY if SH_ETH + select SND_SOC_AK4642 if SND_SIMPLE_CARD + ++config MACH_SILK ++ bool "Silk board" ++ depends on ARCH_R8A7794 ++ select MICREL_PHY if SH_ETH ++ select SND_SOC_AK4642 if SND_SIMPLE_CARD ++ + config MACH_MARZEN + bool "MARZEN board" + depends on ARCH_R8A7779 +diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile +index 8d997e2..139f31c 100644 +--- a/arch/arm/mach-shmobile/Makefile ++++ b/arch/arm/mach-shmobile/Makefile +@@ -76,6 +76,7 @@ obj-$(CONFIG_MACH_KOELSCH) += board-koelsch-reference.o + obj-$(CONFIG_MACH_LAGER) += board-lager-reference.o + obj-$(CONFIG_MACH_GOSE) += board-gose-reference.o + obj-$(CONFIG_MACH_ALT) += board-alt-reference.o ++obj-$(CONFIG_MACH_SILK) += board-silk-reference.o + obj-$(CONFIG_MACH_MARZEN) += board-marzen-reference.o + else + obj-$(CONFIG_MACH_APE6EVM) += board-ape6evm.o +diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot +index 58c2623..25105b2 100644 +--- a/arch/arm/mach-shmobile/Makefile.boot ++++ b/arch/arm/mach-shmobile/Makefile.boot +@@ -15,6 +15,7 @@ loadaddr-$(CONFIG_MACH_MACKEREL) += 0x40008000 + loadaddr-$(CONFIG_MACH_MARZEN) += 0x60008000 + loadaddr-$(CONFIG_MACH_GOSE) += 0x40008000 + loadaddr-$(CONFIG_MACH_ALT) += 0x40008000 ++loadaddr-$(CONFIG_MACH_SILK) += 0x40008000 + + __ZRELADDR := $(sort $(loadaddr-y)) + zreladdr-y += $(__ZRELADDR) +diff --git a/arch/arm/mach-shmobile/board-silk-reference.c b/arch/arm/mach-shmobile/board-silk-reference.c +new file mode 100644 +index 0000000..090a4df +--- /dev/null ++++ b/arch/arm/mach-shmobile/board-silk-reference.c +@@ -0,0 +1,995 @@ ++/* ++ * Silk board support - Reference DT implementation ++ * ++ * Copyright (C) 2014 Renesas Electronics Corporation ++ * Copyright (C) 2014 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. ++ * ++ * 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 ++ */ ++ ++#include <linux/dma-mapping.h> ++#include <linux/gpio.h> ++#include <linux/i2c.h> ++#include <linux/kernel.h> ++#include <linux/mfd/tmio.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/sh_mmcif.h> ++#include <linux/mmc/sh_mobile_sdhi.h> ++#include <linux/of_gpio.h> ++#include <linux/of_platform.h> ++#include <linux/platform_data/camera-rcar.h> ++#include <linux/platform_data/rcar-du.h> ++#include <linux/platform_data/usb-rcar-gen2-phy.h> ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++#include <linux/platform_data/vsp1.h> ++#endif ++#include <linux/serial_sci.h> ++#include <linux/sh_dma.h> ++#include <linux/spi/flash.h> ++#include <linux/spi/sh_msiof.h> ++#include <linux/spi/spi.h> ++#include <linux/usb/phy.h> ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++#include <linux/usb/renesas_usbhs.h> ++#endif ++#include <media/soc_camera.h> ++#include <asm/mach/arch.h> ++#include <sound/rcar_snd.h> ++#include <sound/simple_card.h> ++ ++#include "clock.h" ++#include "common.h" ++#include "dma-register.h" ++#include "irqs.h" ++#include "r8a7794.h" ++#include "rcar-gen2.h" ++ ++/* DU */ ++static struct rcar_du_encoder_data silk_du_encoders[] = { ++ { ++ .type = RCAR_DU_ENCODER_HDMI, ++ .output = RCAR_DU_OUTPUT_DPAD0, ++ }, ++ { ++ .type = RCAR_DU_ENCODER_NONE, ++ .output = RCAR_DU_OUTPUT_LVDS0, ++ .connector.lvds.panel = { ++ .width_mm = 210, ++ .height_mm = 158, ++ .mode = { ++ .clock = 65000, ++ .hdisplay = 1024, ++ .hsync_start = 1048, ++ .hsync_end = 1184, ++ .htotal = 1344, ++ .vdisplay = 768, ++ .vsync_start = 771, ++ .vsync_end = 777, ++ .vtotal = 806, ++ .flags = 0, ++ }, ++ }, ++ }, ++ { ++ .type = RCAR_DU_ENCODER_VGA, ++ .output = RCAR_DU_OUTPUT_DPAD1, ++ }, ++}; ++ ++static struct rcar_du_crtc_data silk_du_crtcs[] = { ++ { ++ .exclk = 148500000, ++ .init_conn_type = DRM_MODE_CONNECTOR_HDMIA, ++ }, ++ { ++ .exclk = 74250000, ++ .init_conn_type = DRM_MODE_CONNECTOR_VGA, ++ }, ++}; ++ ++static int silk_lvds_backlight_on(void) ++{ ++ return 0; ++} ++ ++static int silk_lvds_backlight_off(void) ++{ ++ return 0; ++} ++ ++static struct rcar_du_platform_data silk_du_pdata = { ++ .encoders = silk_du_encoders, ++ .num_encoders = ARRAY_SIZE(silk_du_encoders), ++ .crtcs = silk_du_crtcs, ++ .num_crtcs = ARRAY_SIZE(silk_du_crtcs), ++#ifdef CONFIG_DRM_FBDEV_CRTC ++ .fbdev_crtc = 0, ++#endif ++ .backlight_on = silk_lvds_backlight_on, ++ .backlight_off = silk_lvds_backlight_off, ++ .i2c_ch = 1, ++}; ++ ++static const struct resource du_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfeb00000, 0x40000), ++ DEFINE_RES_IRQ(gic_spi(256)), ++ DEFINE_RES_IRQ(gic_spi(268)), ++}; ++ ++static void __init silk_add_du_device(void) ++{ ++ struct platform_device_info info = { ++ .name = "rcar-du-r8a7794", ++ .id = -1, ++ .res = du_resources, ++ .num_res = ARRAY_SIZE(du_resources), ++ .data = &silk_du_pdata, ++ .size_data = sizeof(silk_du_pdata), ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ ++ platform_device_register_full(&info); ++} ++ ++/* Sound */ ++static struct rsnd_ssi_platform_info rsnd_ssi[] = { ++ RSND_SSI(AUDIOPP_DMAC_SLAVE_CMD0_TO_SSI0, gic_spi(370), 0), ++ RSND_SSI(AUDIOPP_DMAC_SLAVE_SSI1_TO_SCU2, gic_spi(371), RSND_SSI_CLK_PIN_SHARE), ++}; ++ ++static struct rsnd_src_platform_info rsnd_src[3] = { ++ RSND_SRC_UNUSED, ++ RSND_SRC(0, AUDIO_DMAC_SLAVE_SCU1_TX, gic_spi(353)), ++ RSND_SRC(0, AUDIO_DMAC_SLAVE_CMD1_TO_MEM, gic_spi(354)), ++}; ++ ++static struct rsnd_dvc_platform_info rsnd_dvc[2] = { ++}; ++ ++static struct rsnd_dai_platform_info rsnd_dai = { ++ .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[1], .dvc = &rsnd_dvc[0], }, ++ .capture = { .ssi = &rsnd_ssi[1], .src = &rsnd_src[2], .dvc = &rsnd_dvc[1], }, ++}; ++ ++static struct rcar_snd_info rsnd_info = { ++ .flags = RSND_GEN2, ++ .ssi_info = rsnd_ssi, ++ .ssi_info_nr = ARRAY_SIZE(rsnd_ssi), ++ .src_info = rsnd_src, ++ .src_info_nr = ARRAY_SIZE(rsnd_src), ++ .dvc_info = rsnd_dvc, ++ .dvc_info_nr = ARRAY_SIZE(rsnd_dvc), ++ .dai_info = &rsnd_dai, ++ .dai_info_nr = 1, ++}; ++ ++static struct asoc_simple_card_info rsnd_card_info = { ++ .name = "SSI01-AK4643", ++ .codec = "ak4642-codec.1-0012", ++ .platform = "rcar_sound", ++ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, ++ .cpu_dai = { ++ .name = "rcar_sound", ++ }, ++ .codec_dai = { ++ .name = "ak4642-hifi", ++ .sysclk = 12288000, ++ }, ++}; ++ ++static void __init silk_add_rsnd_device(void) ++{ ++ struct resource rsnd_resources[] = { ++ [RSND_GEN2_SCU] = DEFINE_RES_MEM(0xec500000, 0x1000), ++ [RSND_GEN2_ADG] = DEFINE_RES_MEM(0xec5a0000, 0x100), ++ [RSND_GEN2_SSIU] = DEFINE_RES_MEM(0xec540000, 0x1000), ++ [RSND_GEN2_SSI] = DEFINE_RES_MEM(0xec541000, 0x1280), ++ }; ++ ++ struct platform_device_info cardinfo = { ++ .parent = &platform_bus, ++ .name = "asoc-simple-card", ++ .id = -1, ++ .data = &rsnd_card_info, ++ .size_data = sizeof(struct asoc_simple_card_info), ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ ++ platform_device_register_resndata( ++ &platform_bus, "rcar_sound", -1, ++ rsnd_resources, ARRAY_SIZE(rsnd_resources), ++ &rsnd_info, sizeof(rsnd_info)); ++ ++ platform_device_register_full(&cardinfo); ++} ++ ++ ++/* ++ * This is a really crude hack to provide clkdev support to platform ++ * devices until they get moved to DT. ++ */ ++static const struct clk_name clk_names[] __initconst = { ++ { "cmt0", NULL, "sh_cmt.0" }, ++ { "scifa0", NULL, "sh-sci.0" }, ++ { "scifa1", NULL, "sh-sci.1" }, ++ { "scifb0", NULL, "sh-sci.2" }, ++ { "scifb1", NULL, "sh-sci.3" }, ++ { "scifb2", NULL, "sh-sci.4" }, ++ { "scifa2", NULL, "sh-sci.5" }, ++ { "scif0", NULL, "sh-sci.6" }, ++ { "scif1", NULL, "sh-sci.7" }, ++ { "hscif0", NULL, "sh-sci.8" }, ++ { "hscif1", NULL, "sh-sci.9" }, ++ { "scif2", NULL, "sh-sci.10" }, ++ { "scif3", NULL, "sh-sci.11" }, ++ { "scif4", NULL, "sh-sci.12" }, ++ { "scif5", NULL, "sh-sci.13" }, ++ { "scifa3", NULL, "sh-sci.14" }, ++ { "scifa4", NULL, "sh-sci.15" }, ++ { "scifa5", NULL, "sh-sci.16" }, ++ { "hscif2", NULL, "sh-sci.17" }, ++ { "du0", "du.0", "rcar-du-r8a7794" }, ++ { "du1", "du.1", "rcar-du-r8a7794" }, ++ { "hsusb", NULL, "usb_phy_rcar_gen2" }, ++ { "ssi0", "ssi.0", "rcar_sound" }, ++ { "ssi1", "ssi.1", "rcar_sound" }, ++ { "src1", "src.1", "rcar_sound" }, ++ { "src2", "src.2", "rcar_sound" }, ++ { "dvc0", "dvc.0", "rcar_sound" }, ++ { "dvc1", "dvc.1", "rcar_sound" }, ++ { "vin0", NULL, "r8a7794-vin.0" }, ++ { "vsps", NULL, NULL }, ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++ { "vsp1-du0", NULL, "vsp1.2" }, ++#else ++ { "vsp1-du0", NULL, NULL }, ++#endif ++ { "vpc0", NULL, "vpc1" }, ++ { "2ddmac", NULL, "tddmac" }, ++ { "fdp0", NULL, "fdp0" }, ++ { "pvrsrvkm", NULL, "pvrsrvkm" }, ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ { "hsusb", NULL, "renesas_usbhs" }, ++#else ++ { "ehci", NULL, "pci-rcar-gen2.0" }, ++#endif ++}; ++ ++/* ++ * This is a really crude hack to work around core platform clock issues ++ */ ++static const struct clk_name clk_enables[] __initconst = { ++ { "ether", NULL, "ee700000.ethernet" }, ++ { "i2c1", NULL, "e6518000.i2c" }, ++ { "mmcif0", NULL, "ee200000.mmc" }, ++ { "sdhi0", NULL, "ee100000.sd" }, ++ { "sdhi1", NULL, "ee140000.sd" }, ++ { "ehci", NULL, "pci-rcar-gen2.1" }, ++ { "vcp0", NULL, "vcp1" }, ++ { "dmal", NULL, "sh-dma-engine.0" }, ++ { "sys-dmac1", NULL, "sh-dma-engine.2" }, ++ { "sys-dmac0", NULL, "sh-dma-engine.3" }, ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ { "usbdmac0", NULL, "sh-dma-engine.4" }, ++#endif ++ { "ipmmu_gp", NULL, "ipmmu_gp" }, ++}; ++ ++#define DMAE_CHANNEL(a, b) \ ++{ \ ++ .offset = (a) - 0x20, \ ++ .dmars = (a) - 0x20 + 0x40, \ ++ .chclr_bit = (b), \ ++ .chclr_offset = 0x80 - 0x20, \ ++} ++ ++/* Sys-DMAC */ ++#define SYS_DMAC_SLAVE(_id, _bit, _addr, toffset, roffset, t, r) \ ++{ \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_TX, \ ++ .addr = _addr + toffset, \ ++ .chcr = CHCR_TX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = t, \ ++}, { \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_RX, \ ++ .addr = _addr + roffset, \ ++ .chcr = CHCR_RX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = r, \ ++} ++ ++#define SYS_DMAC_SLAVE_TX(_id, _bit, _addr, toffset, roffset, t, r) \ ++{ \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_TX, \ ++ .addr = _addr + toffset, \ ++ .chcr = CHCR_TX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = t, \ ++} ++ ++static const struct sh_dmae_slave_config r8a7794_sys_dmac_slaves[] = { ++ SYS_DMAC_SLAVE(MMCIF0, 32, 0xee200000, 0x34, 0x34, 0xd1, 0xd2), ++ SYS_DMAC_SLAVE(SDHI0, 256, 0xee100000, 0x60, 0x2060, 0xcd, 0xce), ++ SYS_DMAC_SLAVE(SDHI1, 256, 0xee140000, 0x30, 0x2030, 0xc1, 0xc2), ++ SYS_DMAC_SLAVE(SCIF0, 8, 0xe6e60000, 0xc, 0x14, 0x29, 0x2a), ++ SYS_DMAC_SLAVE(SCIF1, 8, 0xe6e68000, 0xc, 0x14, 0x2d, 0x2e), ++ SYS_DMAC_SLAVE(SCIF2, 8, 0xe6e58000, 0xc, 0x14, 0x2b, 0x2c), ++ SYS_DMAC_SLAVE(SCIF3, 8, 0xe6ea8000, 0xc, 0x14, 0x2f, 0x30), ++ SYS_DMAC_SLAVE(SCIF4, 8, 0xe6ee0000, 0xc, 0x14, 0xfb, 0xfc), ++ SYS_DMAC_SLAVE(SCIF5, 8, 0xe6ee8000, 0xc, 0x14, 0xfd, 0xfe), ++ SYS_DMAC_SLAVE(SCIFA0, 8, 0xe6c40000, 0x20, 0x24, 0x21, 0x22), ++ SYS_DMAC_SLAVE(SCIFA1, 8, 0xe6c50000, 0x20, 0x24, 0x25, 0x26), ++ SYS_DMAC_SLAVE(SCIFA2, 8, 0xe6c60000, 0x20, 0x24, 0x27, 0x28), ++ SYS_DMAC_SLAVE(SCIFA3, 8, 0xe6c70000, 0x20, 0x24, 0x1b, 0x1c), ++ SYS_DMAC_SLAVE(SCIFA4, 8, 0xe6c78000, 0x20, 0x24, 0x1f, 0x20), ++ SYS_DMAC_SLAVE(SCIFA5, 8, 0xe6c80000, 0x20, 0x24, 0x23, 0x24), ++ SYS_DMAC_SLAVE(SCIFB0, 8, 0xe6c20000, 0x40, 0x60, 0x3d, 0x3e), ++ SYS_DMAC_SLAVE(SCIFB1, 8, 0xe6c30000, 0x40, 0x60, 0x19, 0x1a), ++ SYS_DMAC_SLAVE(SCIFB2, 8, 0xe6ce0000, 0x40, 0x60, 0x1d, 0x1e), ++ SYS_DMAC_SLAVE(HSCIF0, 8, 0xe62c0000, 0xc, 0x14, 0x39, 0x3a), ++ SYS_DMAC_SLAVE(HSCIF1, 8, 0xe62c8000, 0xc, 0x14, 0x4d, 0x4e), ++ SYS_DMAC_SLAVE(HSCIF2, 8, 0xe62d0000, 0xc, 0x14, 0x3b, 0x3c), ++ SYS_DMAC_SLAVE(MSIOF0, 32, 0xe7e20000, 0x50, 0x60, 0x51, 0x52), ++ SYS_DMAC_SLAVE(MSIOF1, 32, 0xe7e10000, 0x50, 0x60, 0x55, 0x56), ++ SYS_DMAC_SLAVE(MSIOF2, 32, 0xe7e00000, 0x50, 0x60, 0x41, 0x42), ++}; ++ ++static const struct sh_dmae_channel r8a7794_sys_dmac_channels[] = { ++ DMAE_CHANNEL(0x8000, 0), ++ DMAE_CHANNEL(0x8080, 1), ++ DMAE_CHANNEL(0x8100, 2), ++ DMAE_CHANNEL(0x8180, 3), ++ DMAE_CHANNEL(0x8200, 4), ++ DMAE_CHANNEL(0x8280, 5), ++ DMAE_CHANNEL(0x8300, 6), ++ DMAE_CHANNEL(0x8380, 7), ++ DMAE_CHANNEL(0x8400, 8), ++ DMAE_CHANNEL(0x8480, 9), ++ DMAE_CHANNEL(0x8500, 10), ++ DMAE_CHANNEL(0x8580, 11), ++ DMAE_CHANNEL(0x8600, 12), ++ DMAE_CHANNEL(0x8680, 13), ++ DMAE_CHANNEL(0x8700, 14), ++}; ++ ++static struct sh_dmae_pdata r8a7794_sys_dmac_platform_data = { ++ .slave = r8a7794_sys_dmac_slaves, ++ .slave_num = ARRAY_SIZE(r8a7794_sys_dmac_slaves), ++ .channel = r8a7794_sys_dmac_channels, ++ .channel_num = ARRAY_SIZE(r8a7794_sys_dmac_channels), ++ .ts_low_shift = TS_LOW_SHIFT, ++ .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, ++ .ts_high_shift = TS_HI_SHIFT, ++ .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, ++ .ts_shift = dma_ts_shift, ++ .ts_shift_num = ARRAY_SIZE(dma_ts_shift), ++ .dmaor_init = DMAOR_DME, ++ .chclr_present = 1, ++ .chclr_bitwise = 1, ++ .fourty_bits_addr = 1, ++}; ++ ++static struct resource r8a7794_sys_dmac_resources[] = { ++ /* Channel registers and DMAOR for low */ ++ DEFINE_RES_MEM(0xe6700020, 0x8763 - 0x20), ++ DEFINE_RES_IRQ(gic_spi(197)), ++ DEFINE_RES_NAMED(gic_spi(200), 15, NULL, IORESOURCE_IRQ), ++ ++ /* Channel registers and DMAOR for high */ ++ DEFINE_RES_MEM(0xe6720020, 0x8763 - 0x20), ++ DEFINE_RES_IRQ(gic_spi(220)), ++ DEFINE_RES_NAMED(gic_spi(216), 4, NULL, IORESOURCE_IRQ), ++ DEFINE_RES_NAMED(gic_spi(308), 11, NULL, IORESOURCE_IRQ), ++}; ++ ++#define r8a7794_register_sys_dmac(id) \ ++ platform_device_register_resndata( \ ++ &platform_bus, "sh-dma-engine", 2 + id, \ ++ &r8a7794_sys_dmac_resources[id * 3], id * 1 + 3, \ ++ &r8a7794_sys_dmac_platform_data, \ ++ sizeof(r8a7794_sys_dmac_platform_data)) ++ ++static void __init silk_add_dmac_prototype(void) ++{ ++ r8a7794_register_sys_dmac(0); ++ r8a7794_register_sys_dmac(1); ++} ++ ++static struct sh_mmcif_plat_data mmcif0_pdata = { ++ .caps = MMC_CAP_4_BIT_DATA | ++ MMC_CAP_8_BIT_DATA | ++ MMC_CAP_NONREMOVABLE, ++ .ccs_unsupported = true, ++ .clk_ctrl2_present = true, ++ .slave_id_tx = SYS_DMAC_SLAVE_MMCIF0_TX, ++ .slave_id_rx = SYS_DMAC_SLAVE_MMCIF0_RX, ++}; ++ ++static struct sh_mobile_sdhi_info sdhi0_info __initdata = { ++ .dma_slave_tx = SYS_DMAC_SLAVE_SDHI0_TX, ++ .dma_slave_rx = SYS_DMAC_SLAVE_SDHI0_RX, ++ .dma_rx_offset = 0x2000, ++ ++ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | ++ MMC_CAP_POWER_OFF_CARD, ++ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, ++}; ++ ++static struct sh_mobile_sdhi_info sdhi1_info __initdata = { ++ .dma_slave_tx = SYS_DMAC_SLAVE_SDHI1_TX, ++ .dma_slave_rx = SYS_DMAC_SLAVE_SDHI1_RX, ++ .dma_rx_offset = 0x2000, ++ ++ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | ++ MMC_CAP_POWER_OFF_CARD, ++ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, ++}; ++ ++/* SCIF */ ++#define SCIF_PD(scif_type, index, scif_index) \ ++static struct plat_sci_port scif##index##_platform_data = { \ ++ .type = PORT_##scif_type, \ ++ .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \ ++ .scscr = SCSCR_RE | SCSCR_TE, \ ++ .dma_slave_tx = SYS_DMAC_SLAVE_##scif_type##scif_index##_TX, \ ++ .dma_slave_rx = SYS_DMAC_SLAVE_##scif_type##scif_index##_RX, \ ++} ++ ++#define PDATA_SCIF(index, baseaddr, irq, i) SCIF_PD(SCIF, index, i) ++#define PDATA_SCIFA(index, baseaddr, irq, i) SCIF_PD(SCIFA, index, i) ++#define PDATA_SCIFB(index, baseaddr, irq, i) SCIF_PD(SCIFB, index, i) ++#define PDATA_HSCIF(index, baseaddr, irq, i) SCIF_PD(HSCIF, index, i) ++ ++PDATA_SCIFA(0, 0xe6c40000, gic_spi(144), 0); /* SCIFA0 */ ++PDATA_SCIFA(1, 0xe6c50000, gic_spi(145), 1); /* SCIFA1 */ ++PDATA_SCIFB(2, 0xe6c20000, gic_spi(148), 0); /* SCIFB0 */ ++PDATA_SCIFB(3, 0xe6c30000, gic_spi(149), 1); /* SCIFB1 */ ++PDATA_SCIFB(4, 0xe6ce0000, gic_spi(150), 2); /* SCIFB2 */ ++PDATA_SCIFA(5, 0xe6c60000, gic_spi(151), 2); /* SCIFA2 */ ++PDATA_SCIF(6, 0xe6e60000, gic_spi(152), 0); /* SCIF0 */ ++PDATA_SCIF(7, 0xe6e68000, gic_spi(153), 1); /* SCIF1 */ ++PDATA_HSCIF(8, 0xe62c0000, gic_spi(154), 0); /* HSCIF0 */ ++PDATA_HSCIF(9, 0xe62c8000, gic_spi(155), 1); /* HSCIF1 */ ++PDATA_SCIF(10, 0xe6e58000, gic_spi(22), 2); /* SCIF2 */ ++PDATA_SCIF(11, 0xe6ea8000, gic_spi(23), 3); /* SCIF3 */ ++PDATA_SCIF(12, 0xe6ee0000, gic_spi(24), 4); /* SCIF4 */ ++PDATA_SCIF(13, 0xe6ee8000, gic_spi(25), 5); /* SCIF5 */ ++PDATA_SCIFA(14, 0xe6c70000, gic_spi(29), 3); /* SCIFA3 */ ++PDATA_SCIFA(15, 0xe6c78000, gic_spi(30), 4); /* SCIFA4 */ ++PDATA_SCIFA(16, 0xe6c80000, gic_spi(31), 5); /* SCIFA5 */ ++PDATA_HSCIF(17, 0xe6cd0000, gic_spi(21), 2); /* HSCIF2 */ ++ ++#define SCIF_AD(scif_type, index, baseaddr) \ ++ OF_DEV_AUXDATA("renesas," scif_type "-r8a7794", baseaddr, \ ++ "sh-sci." # index, &scif##index##_platform_data) ++ ++#define AUXDATA_SCIF(index, baseaddr, irq) SCIF_AD("scif", index, baseaddr) ++#define AUXDATA_SCIFA(index, baseaddr, irq) SCIF_AD("scifa", index, baseaddr) ++#define AUXDATA_SCIFB(index, baseaddr, irq) SCIF_AD("scifb", index, baseaddr) ++#define AUXDATA_HSCIF(index, baseaddr, irq) SCIF_AD("hscif", index, baseaddr) ++ ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++/* USB-DMAC */ ++static const struct sh_dmae_channel usb_dmac_channels[] = { ++ { ++ .offset = 0, ++ }, { ++ .offset = 0x20, ++ }, ++}; ++ ++static const struct sh_dmae_slave_config usb_dmac_slaves[] = { ++ { ++ .slave_id = USB_DMAC_SLAVE_USBHS_TX, ++ .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_32BYTE), ++ }, { ++ .slave_id = USB_DMAC_SLAVE_USBHS_RX, ++ .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_32BYTE), ++ }, ++}; ++ ++static struct sh_dmae_pdata usb_dmac_platform_data = { ++ .slave = usb_dmac_slaves, ++ .slave_num = ARRAY_SIZE(usb_dmac_slaves), ++ .channel = usb_dmac_channels, ++ .channel_num = ARRAY_SIZE(usb_dmac_channels), ++ .ts_low_shift = USBTS_LOW_SHIFT, ++ .ts_low_mask = USBTS_LOW_BIT << USBTS_LOW_SHIFT, ++ .ts_high_shift = USBTS_HI_SHIFT, ++ .ts_high_mask = USBTS_HI_BIT << USBTS_HI_SHIFT, ++ .ts_shift = dma_usbts_shift, ++ .ts_shift_num = ARRAY_SIZE(dma_usbts_shift), ++ .dmaor_init = DMAOR_DME, ++ .chcr_offset = 0x14, ++ .chcr_ie_bit = 1 << 5, ++ .dmaor_is_32bit = 1, ++ .needs_tend_set = 1, ++ .no_dmars = 1, ++ .slave_only = 1, ++}; ++ ++static struct resource usb_dmac_resources[] = { ++ DEFINE_RES_MEM(0xe65a0020, 0x44), /* Channel registers and DMAOR */ ++ DEFINE_RES_MEM(0xe65a0000, 0x14), /* VCR/SWR/DMICR */ ++ DEFINE_RES_IRQ(gic_spi(109)), ++}; ++ ++static void __init silk_add_usb_dmac_prototype(void) ++{ ++ platform_device_register_resndata(&platform_bus, "sh-dma-engine", ++ 4, ++ usb_dmac_resources, ++ ARRAY_SIZE(usb_dmac_resources), ++ &usb_dmac_platform_data, ++ sizeof(usb_dmac_platform_data)); ++} ++ ++/* USBHS */ ++static const struct resource usbhs_resources[] __initconst = { ++ DEFINE_RES_MEM(0xe6590000, 0x100), ++ DEFINE_RES_IRQ(gic_spi(107)), ++}; ++ ++struct usbhs_private { ++ struct renesas_usbhs_platform_info info; ++ struct usb_phy *phy; ++ int pwen_gpio; ++}; ++ ++#define usbhs_get_priv(pdev) \ ++ container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info) ++ ++static int usbhs_power_ctrl(struct platform_device *pdev, ++ void __iomem *base, int enable) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ ++ if (!priv->phy) ++ return -ENODEV; ++ ++ if (enable) { ++ int retval = usb_phy_init(priv->phy); ++ ++ if (!retval) ++ retval = usb_phy_set_suspend(priv->phy, 0); ++ return retval; ++ } ++ ++ usb_phy_set_suspend(priv->phy, 1); ++ usb_phy_shutdown(priv->phy); ++ return 0; ++} ++ ++static int usbhs_hardware_init(struct platform_device *pdev) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ struct usb_phy *phy; ++ int ret; ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/gpio@e6055000"); ++ if (np) { ++ priv->pwen_gpio = of_get_gpio(np, 24); ++ of_node_put(np); ++ } else { ++ pr_warn("Error: Unable to get PWEN GPIO line\n"); ++ ret = -ENOTSUPP; ++ goto error2; ++ } ++ ++ phy = usb_get_phy_dev(&pdev->dev, 0); ++ if (IS_ERR(phy)) { ++ ret = PTR_ERR(phy); ++ goto error; ++ } ++ ++ priv->phy = phy; ++ return 0; ++ error: ++ gpio_free(priv->pwen_gpio); ++ error2: ++ return ret; ++} ++ ++static int usbhs_hardware_exit(struct platform_device *pdev) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ ++ if (!priv->phy) ++ return 0; ++ ++ usb_put_phy(priv->phy); ++ priv->phy = NULL; ++ gpio_free(priv->pwen_gpio); ++ return 0; ++} ++ ++static int usbhs_get_id(struct platform_device *pdev) ++{ ++ return USBHS_GADGET; ++} ++ ++static int usbhs_get_vbus(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static u32 lager_usbhs_pipe_type[] = { ++ USB_ENDPOINT_XFER_CONTROL, ++ USB_ENDPOINT_XFER_ISOC, ++ USB_ENDPOINT_XFER_ISOC, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++}; ++ ++static struct usbhs_private usbhs_priv __initdata = { ++ .info = { ++ .platform_callback = { ++ .power_ctrl = usbhs_power_ctrl, ++ .hardware_init = usbhs_hardware_init, ++ .hardware_exit = usbhs_hardware_exit, ++ .get_id = usbhs_get_id, ++ .get_vbus = usbhs_get_vbus, ++ }, ++ .driver_param = { ++ .buswait_bwait = 4, ++ .pipe_type = lager_usbhs_pipe_type, ++ .pipe_size = ARRAY_SIZE(lager_usbhs_pipe_type), ++ .d0_rx_id = USB_DMAC_SLAVE_USBHS_RX, ++ .d1_tx_id = USB_DMAC_SLAVE_USBHS_TX, ++ .usb_dmac_xfer_size = 32, ++ }, ++ } ++}; ++ ++static void __init silk_register_usbhs(void) ++{ ++ usb_bind_phy("renesas_usbhs", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_resndata(&platform_bus, ++ "renesas_usbhs", -1, ++ usbhs_resources, ++ ARRAY_SIZE(usbhs_resources), ++ &usbhs_priv.info, ++ sizeof(usbhs_priv.info)); ++} ++ ++#else ++/* Internal PCI0 */ ++static const struct resource pci0_resources[] __initconst = { ++ DEFINE_RES_MEM(0xee090000, 0x10000), /* CFG */ ++ DEFINE_RES_MEM(0xee080000, 0x10000), /* MEM */ ++ DEFINE_RES_IRQ(gic_spi(108)), ++}; ++ ++static const struct platform_device_info pci0_info __initconst = { ++ .parent = &platform_bus, ++ .name = "pci-rcar-gen2", ++ .id = 0, ++ .res = pci0_resources, ++ .num_res = ARRAY_SIZE(pci0_resources), ++ .dma_mask = DMA_BIT_MASK(32), ++}; ++ ++static void __init silk_add_usb0_device(void) ++{ ++ usb_bind_phy("pci-rcar-gen2.0", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_full(&pci0_info); ++} ++#endif ++/* USBHS PHY */ ++static const struct rcar_gen2_phy_platform_data usbhs_phy_pdata __initconst = { ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ .chan0_pci = 0, /* Channel 0 is USBHS */ ++#else ++ .chan0_pci = 1, /* Channel 0 is PCI USB */ ++#endif ++ .chan2_pci = 1, /* Channel 2 is PCI USB */ ++ .gpio_vbus = 857, ++ .wakeup = true, ++}; ++ ++static const struct resource usbhs_phy_resources[] __initconst = { ++ DEFINE_RES_MEM(0xe6590100, 0x100), ++}; ++ ++/* Internal PCI1 */ ++static const struct resource pci1_resources[] __initconst = { ++ DEFINE_RES_MEM(0xee0d0000, 0x10000), /* CFG */ ++ DEFINE_RES_MEM(0xee0c0000, 0x10000), /* MEM */ ++ DEFINE_RES_IRQ(gic_spi(113)), ++}; ++ ++static const struct platform_device_info pci1_info __initconst = { ++ .parent = &platform_bus, ++ .name = "pci-rcar-gen2", ++ .id = 1, ++ .res = pci1_resources, ++ .num_res = ARRAY_SIZE(pci1_resources), ++ .dma_mask = DMA_BIT_MASK(32), ++}; ++ ++static void __init silk_add_usb1_device(void) ++{ ++ usb_bind_phy("pci-rcar-gen2.1", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_full(&pci1_info); ++} ++ ++/* POWER IC */ ++static struct i2c_board_info poweric_i2c[] = { ++ { I2C_BOARD_INFO("da9063", 0x58), }, ++}; ++ ++static void silk_restart(char mode, const char *cmd) ++{ ++ struct i2c_adapter *adap; ++ struct i2c_client *client; ++ u8 val; ++ int busnum = 8; ++ ++ adap = i2c_get_adapter(busnum); ++ if (!adap) { ++ pr_err("failed to get adapter i2c%d\n", busnum); ++ return; ++ } ++ ++ client = i2c_new_device(adap, &poweric_i2c[0]); ++ if (!client) ++ pr_err("failed to register %s to i2c%d\n", ++ poweric_i2c[0].type, busnum); ++ ++ i2c_put_adapter(adap); ++ ++ val = i2c_smbus_read_byte_data(client, 0x13); ++ ++ if (val < 0) ++ pr_err("couldn't access da9063\n"); ++ ++ val |= 0x02; ++ ++ i2c_smbus_write_byte_data(client, 0x13, val); ++} ++ ++/* VIN */ ++static const struct resource vin_resources[] __initconst = { ++ /* VIN0 */ ++ DEFINE_RES_MEM(0xe6ef0000, 0x1000), ++ DEFINE_RES_IRQ(gic_spi(188)), ++}; ++ ++static void __init silk_add_vin_device(unsigned idx, ++ struct rcar_vin_platform_data *pdata) ++{ ++ struct platform_device_info vin_info = { ++ .parent = &platform_bus, ++ .name = "r8a7794-vin", ++ .id = idx, ++ .res = &vin_resources[idx * 2], ++ .num_res = 2, ++ .dma_mask = DMA_BIT_MASK(32), ++ .data = pdata, ++ .size_data = sizeof(*pdata), ++ }; ++ ++ BUG_ON(idx > 1); ++ ++ platform_device_register_full(&vin_info); ++} ++ ++#define SILK_CAMERA(idx, name, addr, pdata, flag) \ ++static struct i2c_board_info i2c_cam##idx##_device = { \ ++ I2C_BOARD_INFO(name, addr), \ ++}; \ ++ \ ++static struct rcar_vin_platform_data vin##idx##_pdata = { \ ++ .flags = flag, \ ++}; \ ++ \ ++static struct soc_camera_link cam##idx##_link = { \ ++ .bus_id = idx, \ ++ .board_info = &i2c_cam##idx##_device, \ ++ .i2c_adapter_id = 1, \ ++ .module_name = name, \ ++ .priv = pdata, \ ++} ++ ++SILK_CAMERA(0, "adv7180", 0x20, NULL, RCAR_VIN_BT656); ++ ++static void __init silk_add_camera0_device(void) ++{ ++ platform_device_register_data(&platform_bus, "soc-camera-pdrv", 0, ++ &cam0_link, sizeof(cam0_link)); ++ silk_add_vin_device(0, &vin0_pdata); ++} ++ ++/* VSP1 */ ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++static const struct vsp1_platform_data silk_vsps_pdata __initconst = { ++ .features = 0, ++ .rpf_count = 5, ++ .uds_count = 3, ++ .wpf_count = 4, ++}; ++ ++static const struct vsp1_platform_data silk_vspd0_pdata __initconst = { ++ .features = VSP1_HAS_LIF, ++ .rpf_count = 4, ++ .uds_count = 1, ++ .wpf_count = 4, ++}; ++ ++static const struct vsp1_platform_data * const silk_vsp1_pdata[] __initconst ++ = { ++ &silk_vsps_pdata, ++ &silk_vspd0_pdata, ++}; ++ ++static const struct resource vsp1_1_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfe928000, 0x8000), ++ DEFINE_RES_IRQ(gic_spi(267)), ++}; ++ ++static const struct resource vsp1_2_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfe930000, 0x8000), ++ DEFINE_RES_IRQ(gic_spi(246)), ++}; ++ ++static const struct resource * const vsp1_resources[] __initconst = { ++ vsp1_1_resources, ++ vsp1_2_resources, ++}; ++ ++static void __init silk_add_vsp1_devices(void) ++{ ++ struct platform_device_info info = { ++ .name = "vsp1", ++ .size_data = sizeof(*silk_vsp1_pdata[0]), ++ .num_res = 2, ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ unsigned int i; ++ ++ for (i = 1; i < ARRAY_SIZE(vsp1_resources); ++i) { ++ info.id = i + 1; ++ info.data = silk_vsp1_pdata[i]; ++ info.res = vsp1_resources[i]; ++ ++ platform_device_register_full(&info); ++ } ++} ++#endif ++ ++/* MSIOF */ ++static struct sh_msiof_spi_info msiof0_info = { ++ .rx_fifo_override = 256, ++ .num_chipselect = 1, ++ .dma_tx_id = SYS_DMAC_SLAVE_MSIOF0_TX, ++ .dma_rx_id = SYS_DMAC_SLAVE_MSIOF0_RX, ++}; ++ ++static struct sh_msiof_spi_info msiof1_info = { ++ .rx_fifo_override = 256, ++ .num_chipselect = 1, ++ .dma_tx_id = SYS_DMAC_SLAVE_MSIOF1_TX, ++ .dma_rx_id = SYS_DMAC_SLAVE_MSIOF1_RX, ++}; ++ ++/* MSIOF spidev */ ++static const struct spi_board_info spi_bus[] __initconst = { ++ { ++ .modalias = "spidev", ++ .max_speed_hz = 6000000, ++ .mode = SPI_MODE_3, ++ .bus_num = 1, ++ .chip_select = 0, ++ }, ++ { ++ .modalias = "spidev", ++ .max_speed_hz = 6000000, ++ .mode = SPI_MODE_3, ++ .bus_num = 2, ++ .chip_select = 0, ++ }, ++}; ++ ++#define silk_add_msiof_device spi_register_board_info ++ ++static struct of_dev_auxdata silk_auxdata_lookup[] __initdata = { ++ OF_DEV_AUXDATA("renesas,mmcif-r8a7794", 0xee200000, "sh_mmcif", ++ &mmcif0_pdata), ++ OF_DEV_AUXDATA("renesas,sdhi-r8a7794", 0xee100000, "sdhi0", ++ &sdhi0_info), ++ OF_DEV_AUXDATA("renesas,sdhi-r8a7794", 0xee140000, "sdhi1", ++ &sdhi1_info), ++ AUXDATA_SCIFA(0, 0xe6c40000, gic_spi(144)), /* SCIFA0 */ ++ AUXDATA_SCIFA(1, 0xe6c50000, gic_spi(145)), /* SCIFA1 */ ++ AUXDATA_SCIFB(2, 0xe6c20000, gic_spi(148)), /* SCIFB0 */ ++ AUXDATA_SCIFB(3, 0xe6c30000, gic_spi(149)), /* SCIFB1 */ ++ AUXDATA_SCIFB(4, 0xe6ce0000, gic_spi(150)), /* SCIFB2 */ ++ AUXDATA_SCIFA(5, 0xe6c60000, gic_spi(151)), /* SCIFA2 */ ++ AUXDATA_SCIF(6, 0xe6e60000, gic_spi(152)), /* SCIF0 */ ++ AUXDATA_SCIF(7, 0xe6e68000, gic_spi(153)), /* SCIF1 */ ++ AUXDATA_HSCIF(8, 0xe62c0000, gic_spi(154)), /* HSCIF0 */ ++ AUXDATA_HSCIF(9, 0xe62c8000, gic_spi(155)), /* HSCIF1 */ ++ AUXDATA_SCIF(10, 0xe6e58000, gic_spi(22)), /* SCIF2 */ ++ AUXDATA_SCIF(11, 0xe6ea8000, gic_spi(23)), /* SCIF3 */ ++ AUXDATA_SCIF(12, 0xe6ee0000, gic_spi(24)), /* SCIF4 */ ++ AUXDATA_SCIF(13, 0xe6ee8000, gic_spi(25)), /* SCIF5 */ ++ AUXDATA_SCIFA(14, 0xe6c70000, gic_spi(29)), /* SCIFA3 */ ++ AUXDATA_SCIFA(15, 0xe6c78000, gic_spi(30)), /* SCIFA4 */ ++ AUXDATA_SCIFA(16, 0xe6c80000, gic_spi(31)), /* SCIFA5 */ ++ AUXDATA_HSCIF(17, 0xe6cd0000, gic_spi(21)), /* HSCIF2 */ ++ OF_DEV_AUXDATA("renesas,msiof-r8a7794", 0xe6e20000, ++ "spi_r8a7794_msiof.0", &msiof0_info), ++ OF_DEV_AUXDATA("renesas,msiof-r8a7794", 0xe6e10000, ++ "spi_r8a7794_msiof.1", &msiof1_info), ++ {}, ++}; ++ ++static void __init silk_add_standard_devices(void) ++{ ++ shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); ++ shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true); ++ r8a7794_add_dt_devices(); ++ silk_add_dmac_prototype(); ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ silk_add_usb_dmac_prototype(); ++#endif ++ of_platform_populate(NULL, of_default_bus_match_table, ++ silk_auxdata_lookup, NULL); ++ silk_add_du_device(); ++ ++ platform_device_register_resndata(&platform_bus, "usb_phy_rcar_gen2", ++ -1, usbhs_phy_resources, ++ ARRAY_SIZE(usbhs_phy_resources), ++ &usbhs_phy_pdata, ++ sizeof(usbhs_phy_pdata)); ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ silk_register_usbhs(); ++#else ++ silk_add_usb0_device(); ++#endif ++ silk_add_usb1_device(); ++ silk_add_rsnd_device(); ++ silk_add_camera0_device(); ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++ silk_add_vsp1_devices(); ++#endif ++ silk_add_msiof_device(spi_bus, ARRAY_SIZE(spi_bus)); ++} ++ ++static const char * const silk_boards_compat_dt[] __initconst = { ++ "renesas,silk", ++ "renesas,silk-reference", ++ NULL, ++}; ++ ++DT_MACHINE_START(SILK_DT, "silk") ++ .smp = smp_ops(r8a7794_smp_ops), ++ .init_early = r8a7794_init_early, ++ .init_time = r8a7794_timer_init, ++ .init_machine = silk_add_standard_devices, ++ .init_late = shmobile_init_late, ++ .reserve = rcar_gen2_reserve, ++ .restart = silk_restart, ++ .dt_compat = silk_boards_compat_dt, ++MACHINE_END +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0002-kernel-silk-fix-ethernet-phy-irq.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0002-kernel-silk-fix-ethernet-phy-irq.patch new file mode 100644 index 0000000..5e72b82 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0002-kernel-silk-fix-ethernet-phy-irq.patch @@ -0,0 +1,25 @@ +From f186213b9d9d3942dc403060542796e07d254d52 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 2 Feb 2015 13:34:25 +0300 +Subject: [PATCH] Silk: Ethernet phy interrupt is connected to IRQ8 + +--- + arch/arm/boot/dts/r8a7794-silk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +index cb69f6b..aa20df8 100644 +--- a/arch/arm/boot/dts/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -280,7 +280,7 @@ + phy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&irqc0>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; + }; + }; +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0003-kernel-silk-fix-sd-detect.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0003-kernel-silk-fix-sd-detect.patch new file mode 100644 index 0000000..0bb4f75 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0003-kernel-silk-fix-sd-detect.patch @@ -0,0 +1,25 @@ +From 1a56b82aad68465e69827f1cbe18f53ab886f7df Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 2 Feb 2015 13:35:06 +0300 +Subject: [PATCH] Silk: Fix SDHI1 write protect pin detection + +--- + arch/arm/boot/dts/r8a7794-silk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +index aa20df8..9438dfa 100644 +--- a/arch/arm/boot/dts/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -345,7 +345,7 @@ + vmmc-supply = <&vcc_sdhi1>; + vqmmc-supply = <&vccq_sdhi1>; + cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>; +- wp-gpios = <&gpio6 15 GPIO_ACTIVE_HIGH>; ++ wp-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0004-kernel-Revert-i2c-rcar-Support-ACK-by-HW-auto-restart-after-NACK.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0004-kernel-Revert-i2c-rcar-Support-ACK-by-HW-auto-restart-after-NACK.patch new file mode 100644 index 0000000..5f23129 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0004-kernel-Revert-i2c-rcar-Support-ACK-by-HW-auto-restart-after-NACK.patch @@ -0,0 +1,66 @@ +From 4f249ca259008006d972ea76fd2b37a2558ea2f1 Mon Sep 17 00:00:00 2001 +From: Petr Nechaev <petr.nechaev@cogentembedded.com> +Date: Mon, 2 Feb 2015 13:37:55 +0300 +Subject: [PATCH] Revert "i2c: rcar: Support ACK by HW auto restart after + NACK" + +This reverts commit 4df6b2af6c0f795d810eb1e2e9411ad1cbbe4245. +--- + drivers/i2c/busses/i2c-rcar.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c +index 18034cd..0e863f3 100644 +--- a/drivers/i2c/busses/i2c-rcar.c ++++ b/drivers/i2c/busses/i2c-rcar.c +@@ -522,6 +522,7 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) + + /* go to stop phase */ + rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); ++ rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); + rcar_i2c_flags_set(priv, ID_NACK); + rcar_i2c_status_bit_clear(priv, MNR); + goto out; +@@ -532,14 +533,8 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) + */ + if (msr & MST) { + dev_dbg(dev, "Stop\n"); +- if (rcar_i2c_flags_has(priv, ID_NACK)) { +- /* don't set ID_DONE for expecting ACK +- after auto-restart by HW */ +- rcar_i2c_status_bit_clear(priv, MST); +- } else { +- rcar_i2c_flags_set(priv, ID_DONE); +- rcar_i2c_status_clear(priv); +- } ++ rcar_i2c_flags_set(priv, ID_DONE); ++ rcar_i2c_status_clear(priv); + goto out; + } + +@@ -616,10 +611,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, + rcar_i2c_flags_has(priv, ID_DONE), + 5 * HZ); + if (!timeout) { +- if (rcar_i2c_flags_has(priv, ID_NACK)) { +- ret = -ENXIO; +- break; +- } + ret = -ETIMEDOUT; + break; + } +@@ -627,6 +618,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, + /* + * error handling + */ ++ if (rcar_i2c_flags_has(priv, ID_NACK)) { ++ ret = -ENXIO; ++ break; ++ } ++ + if (rcar_i2c_flags_has(priv, ID_ARBLOST)) { + ret = -EAGAIN; + break; +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0006-Rcar-DU-add-RGB-connector.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0006-Rcar-DU-add-RGB-connector.patch new file mode 100644 index 0000000..d1c8da8 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0006-Rcar-DU-add-RGB-connector.patch @@ -0,0 +1,276 @@ +From 488e93a1d8371c6ce8cfd24d7299973c476a1aef Mon Sep 17 00:00:00 2001 +From: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Date: Sun, 28 Dec 2014 19:58:58 +0300 +Subject: [PATCH] Rcar-DU: add RGB connector + + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + drivers/gpu/drm/rcar-du/Makefile | 1 + + drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 9 ++ + drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c | 142 +++++++++++++++++++++++++++++ + drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h | 24 +++++ + include/linux/platform_data/rcar-du.h | 7 ++ + 5 files changed, 183 insertions(+) + create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c + create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h + +diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile +index a6909f0..744da0f 100644 +--- a/drivers/gpu/drm/rcar-du/Makefile ++++ b/drivers/gpu/drm/rcar-du/Makefile +@@ -5,6 +5,7 @@ rcar-du-drm-y := rcar_du_crtc.o \ + rcar_du_hdmicon.o \ + rcar_du_kms.o \ + rcar_du_lvdscon.o \ ++ rcar_du_rgbcon.o \ + rcar_du_plane.o \ + rcar_du_vgacon.o + +diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +index 0edec97..de0ccc1 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c ++++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +@@ -24,6 +24,7 @@ + #include "rcar_du_encoder.h" + #include "rcar_du_kms.h" + #include "rcar_du_lvdscon.h" ++#include "rcar_du_rgbcon.h" + #include "rcar_du_lvdsenc.h" + #include "rcar_du_vgacon.h" + #include "rcar_du_hdmicon.h" +@@ -235,6 +236,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, + case RCAR_DU_ENCODER_LVDS: + encoder_type = DRM_MODE_ENCODER_LVDS; + break; ++ case RCAR_DU_ENCODER_RGB: ++ encoder_type = DRM_MODE_ENCODER_NONE; ++ break; + case RCAR_DU_ENCODER_HDMI: + encoder_type = DRM_MODE_ENCODER_TMDS; + break; +@@ -277,6 +281,11 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, + case DRM_MODE_ENCODER_DAC: + return rcar_du_vga_connector_init(rcdu, renc); + ++ case DRM_MODE_ENCODER_NONE: ++ if (type == RCAR_DU_ENCODER_RGB) ++ return rcar_du_rgb_connector_init(rcdu, renc, ++ &data->connector.rgb.panel); ++ /* fallthrough */ + default: + return -EINVAL; + } +diff --git a/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c +new file mode 100644 +index 0000000..9ee845d +--- /dev/null ++++ b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.c +@@ -0,0 +1,142 @@ ++/* ++ * rcar_du_rgbcon.c -- R-Car Display Unit RGB Connector ++ * base on rcar_du_lvdscon.c ++ * ++ * Copyright (C) 2013-2014 Renesas Electronics Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <drm/drmP.h> ++#include <drm/drm_crtc.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_encoder_slave.h> ++ ++#include "rcar_du_drv.h" ++#include "rcar_du_encoder.h" ++#include "rcar_du_kms.h" ++#include "rcar_du_rgbcon.h" ++ ++struct rcar_du_rgb_connector { ++ struct rcar_du_connector connector; ++ ++ const struct rcar_du_panel_data *panel; ++}; ++ ++#define to_rcar_rgb_connector(c) \ ++ container_of(c, struct rcar_du_rgb_connector, connector.connector) ++ ++static int rcar_du_rgb_connector_get_modes(struct drm_connector *connector) ++{ ++ struct rcar_du_rgb_connector *rgbcon = ++ to_rcar_rgb_connector(connector); ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_create(connector->dev); ++ if (mode == NULL) ++ return 0; ++ ++ mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; ++ mode->clock = rgbcon->panel->mode.clock; ++ mode->hdisplay = rgbcon->panel->mode.hdisplay; ++ mode->hsync_start = rgbcon->panel->mode.hsync_start; ++ mode->hsync_end = rgbcon->panel->mode.hsync_end; ++ mode->htotal = rgbcon->panel->mode.htotal; ++ mode->vdisplay = rgbcon->panel->mode.vdisplay; ++ mode->vsync_start = rgbcon->panel->mode.vsync_start; ++ mode->vsync_end = rgbcon->panel->mode.vsync_end; ++ mode->vtotal = rgbcon->panel->mode.vtotal; ++ mode->flags = rgbcon->panel->mode.flags; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); ++ ++ return 1; ++} ++ ++static int rcar_du_rgb_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ return MODE_OK; ++} ++ ++static const struct drm_connector_helper_funcs connector_helper_funcs = { ++ .get_modes = rcar_du_rgb_connector_get_modes, ++ .mode_valid = rcar_du_rgb_connector_mode_valid, ++ .best_encoder = rcar_du_connector_best_encoder, ++}; ++ ++static void rcar_du_rgb_connector_destroy(struct drm_connector *connector) ++{ ++ drm_sysfs_connector_remove(connector); ++ drm_connector_cleanup(connector); ++} ++ ++static enum drm_connector_status ++rcar_du_rgb_connector_detect(struct drm_connector *connector, bool force) ++{ ++ return connector_status_connected; ++} ++ ++static const struct drm_connector_funcs connector_funcs = { ++ .dpms = drm_helper_connector_dpms, ++ .detect = rcar_du_rgb_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = rcar_du_rgb_connector_destroy, ++}; ++ ++int rcar_du_rgb_connector_init(struct rcar_du_device *rcdu, ++ struct rcar_du_encoder *renc, ++ const struct rcar_du_panel_data *panel) ++{ ++ struct rcar_du_rgb_connector *rgbcon; ++ struct drm_connector *connector; ++ int ret; ++ ++ if (rcdu->pdata->backlight_on) { ++ ret = rcdu->pdata->backlight_on(); ++ if (ret < 0) ++ return ret; ++ } ++ ++ rgbcon = devm_kzalloc(rcdu->dev, sizeof(*rgbcon), GFP_KERNEL); ++ if (rgbcon == NULL) ++ return -ENOMEM; ++ ++ rgbcon->panel = panel; ++ ++ connector = &rgbcon->connector.connector; ++ connector->display_info.width_mm = panel->width_mm; ++ connector->display_info.height_mm = panel->height_mm; ++ ++ ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, ++ DRM_MODE_CONNECTOR_Component); ++ if (ret < 0) ++ return ret; ++ ++ drm_connector_helper_add(connector, &connector_helper_funcs); ++ ret = drm_sysfs_connector_add(connector); ++ if (ret < 0) ++ return ret; ++ ++#if 0 ++ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); ++ drm_object_property_set_value(&connector->base, ++ rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); ++#else ++ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); ++ drm_object_property_set_value(&connector->base, ++ rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_ON); ++#endif ++ ret = drm_mode_connector_attach_encoder(connector, renc->encoder); ++ if (ret < 0) ++ return ret; ++ ++ connector->encoder = renc->encoder; ++ rgbcon->connector.encoder = renc; ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h +new file mode 100644 +index 0000000..d4d51be +--- /dev/null ++++ b/drivers/gpu/drm/rcar-du/rcar_du_rgbcon.h +@@ -0,0 +1,24 @@ ++/* ++ * rcar_du_rgbcon.h -- R-Car Display Unit RGB Connector ++ * based on rcar_du_lvdscon.h ++ * ++ * Copyright (C) 2013-2014 Renesas Electronics Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef __RCAR_DU_RGBCON_H__ ++#define __RCAR_DU_RGBCON_H__ ++ ++struct rcar_du_device; ++struct rcar_du_encoder; ++struct rcar_du_panel_data; ++ ++int rcar_du_rgb_connector_init(struct rcar_du_device *rcdu, ++ struct rcar_du_encoder *renc, ++ const struct rcar_du_panel_data *panel); ++ ++#endif /* __RCAR_DU_RGBCON_H__ */ +diff --git a/include/linux/platform_data/rcar-du.h b/include/linux/platform_data/rcar-du.h +index 62464de..93c29af 100644 +--- a/include/linux/platform_data/rcar-du.h ++++ b/include/linux/platform_data/rcar-du.h +@@ -31,6 +31,7 @@ enum rcar_du_encoder_type { + RCAR_DU_ENCODER_NONE, + RCAR_DU_ENCODER_VGA, + RCAR_DU_ENCODER_LVDS, ++ RCAR_DU_ENCODER_RGB, + RCAR_DU_ENCODER_HDMI, + }; + +@@ -44,6 +45,11 @@ struct rcar_du_connector_lvds_data { + struct rcar_du_panel_data panel; + }; + ++struct rcar_du_connector_rgb_data { ++ struct rcar_du_panel_data panel; ++}; ++ ++ + struct rcar_du_connector_vga_data { + /* TODO: Add DDC information for EDID retrieval */ + }; +@@ -68,6 +74,7 @@ struct rcar_du_encoder_data { + + union { + struct rcar_du_connector_lvds_data lvds; ++ struct rcar_du_connector_rgb_data rgb; + struct rcar_du_connector_vga_data vga; + struct rcar_du_connector_hdmi_data hdmi; + } connector; +-- +1.7.10.4 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0007-SILK-add-i2c0.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0007-SILK-add-i2c0.patch new file mode 100644 index 0000000..1f02501 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0007-SILK-add-i2c0.patch @@ -0,0 +1,45 @@ +From 207ad91c8ebbfbd2b862323200071a8c2a816fef Mon Sep 17 00:00:00 2001 +From: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +Date: Sun, 28 Dec 2014 20:01:53 +0300 +Subject: [PATCH] SILK: add i2c0 + + +Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com> +--- + arch/arm/boot/dts/r8a7794-silk.dts | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +index aa20df8..bd1359d 100644 +--- a/arch/arm/boot/dts/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -181,6 +181,14 @@ + clock-frequency = <20000000>; + }; + ++&i2c0 { ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++}; ++ + &i2c1 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; +@@ -211,6 +219,11 @@ + renesas,function = "du"; + }; + ++ i2c0_pins: i2c0 { ++ renesas,groups = "i2c0_d"; ++ renesas,function = "i2c0"; ++ }; ++ + i2c1_pins: i2c1 { + renesas,groups = "i2c1"; + renesas,function = "i2c1"; +-- +1.7.10.4 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0008-Porter-board-support.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0008-Porter-board-support.patch new file mode 100644 index 0000000..13fc68b --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0008-Porter-board-support.patch @@ -0,0 +1,1426 @@ +From c8c4c6ed85b5f34b8f8178b8ce53c246a67cfa00 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Mon, 2 Feb 2015 14:12:24 +0300 +Subject: [PATCH] Add Porter board support + +Porter is an entry level development board based on R-Car M2 SoC +(R8A7791) + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/r8a7791-porter.dts | 385 ++++++++++ + arch/arm/configs/shmobile_defconfig | 1 + + arch/arm/mach-shmobile/Kconfig | 6 + + arch/arm/mach-shmobile/Makefile | 1 + + arch/arm/mach-shmobile/board-porter-reference.c | 953 ++++++++++++++++++++++++ + 6 files changed, 1347 insertions(+) + create mode 100644 arch/arm/boot/dts/r8a7791-porter.dts + create mode 100644 arch/arm/mach-shmobile/board-porter-reference.c + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index f2b99db..a1de751 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -176,6 +176,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \ + r7s72100-genmai.dtb \ + r8a7791-henninger.dtb \ + r8a7791-koelsch.dtb \ ++ r8a7791-porter.dtb \ + r8a7790-lager.dtb \ + r8a7794-alt.dtb \ + r8a7794-silk.dtb \ +diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts +new file mode 100644 +index 0000000..6a0ccde +--- /dev/null ++++ b/arch/arm/boot/dts/r8a7791-porter.dts +@@ -0,0 +1,385 @@ ++/* ++ * Device Tree Source for the Porter board ++ * ++ * Copyright (C) 2015 Renesas Electronics Corporation ++ * Copyright (C) 2015 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++/* ++ * SSI-AK4643 ++ * ++ * these commands are required when playback. ++ * ++ * # amixer set "LINEOUT Mixer DACL" on ++ * # amixer set "Digital" 200 ++ * # amixer set "DVC Out" 50 ++ */ ++ ++/dts-v1/; ++#include "r8a7791.dtsi" ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ model = "Porter"; ++ compatible = "renesas,porter", "renesas,r8a7791"; ++ ++ aliases { ++ serial6 = &scif0; ++ }; ++ ++ chosen { ++ bootargs = "console=ttySC6,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp vmalloc=384M"; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0 0x40000000 0 0x40000000>; ++ }; ++ ++ memory@200000000 { ++ device_type = "memory"; ++ reg = <2 0x00000000 0 0x40000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ led2 { ++ gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>; ++ }; ++ led3 { ++ gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; ++ }; ++ led4 { ++ gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ vcc_sdhi0: regulator@0 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI0 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vccq_sdhi0: regulator@1 { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "SDHI0 VccQ"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; ++ gpios-states = <1>; ++ states = <3300000 1 ++ 1800000 0>; ++ }; ++ ++ vcc_sdhi2: regulator@2 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "SDHI2 Vcc"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vccq_sdhi2: regulator@3 { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "SDHI2 VccQ"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>; ++ gpios-states = <1>; ++ states = <3300000 1 ++ 1800000 0>; ++ }; ++ ++ hdmi_transmitter: adv7511 { ++ compatible = "adi,adv7511"; ++ gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; ++ ++ adi,input-style = <0x02>; ++ adi,input-id = <0x00>; ++ adi,input-color-depth = <0x03>; ++ adi,sync-pulse = <0x03>; ++ adi,bit-justification = <0x01>; ++ adi,up-conversion = <0x00>; ++ adi,timing-generation-sequence = <0x00>; ++ adi,vsync-polarity = <0x02>; ++ adi,hsync-polarity = <0x02>; ++ adi,clock-delay = <0x03>; ++ }; ++ ++ usbhs_udc { ++ gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&extal_clk { ++ clock-frequency = <20000000>; ++}; ++ ++&pfc { ++ pinctrl-0 = <&du_pins &usb0_pins &usb1_pins &sound_pins &sound_clk_pins &vin0_pins>; ++ pinctrl-names = "default"; ++ ++ du_pins: du { ++ renesas,groups = "du_rgb666", "du_sync", "du_clk_out_0"; ++ renesas,function = "du"; ++ }; ++ ++ scif0_pins: serial6 { ++ renesas,groups = "scif0_data_d"; ++ renesas,function = "scif0"; ++ }; ++ ++ i2c1_pins: i2c1 { ++ renesas,groups = "i2c1_e"; ++ renesas,function = "i2c1"; ++ }; ++ ++ i2c2_pins: i2c2 { ++ renesas,groups = "i2c2"; ++ renesas,function = "i2c2"; ++ }; ++ ++ i2c4_pins: i2c4 { ++ renesas,groups = "i2c4_c"; ++ renesas,function = "i2c4"; ++ }; ++ ++ ether_pins: ether { ++ renesas,groups = "eth_link", "eth_mdio", "eth_rmii"; ++ renesas,function = "eth"; ++ }; ++ ++ phy1_pins: phy1 { ++ renesas,groups = "intc_irq0"; ++ renesas,function = "intc"; ++ }; ++ ++ sdhi0_pins: sd0 { ++ renesas,groups = "sdhi0_data4", "sdhi0_ctrl"; ++ renesas,function = "sdhi0"; ++ }; ++ ++ sdhi2_pins: sd2 { ++ renesas,groups = "sdhi2_data4", "sdhi2_ctrl"; ++ renesas,function = "sdhi2"; ++ }; ++ ++ qspi_pins: spi0 { ++ renesas,groups = "qspi_ctrl", "qspi_data4"; ++ renesas,function = "qspi"; ++ }; ++ ++ msiof0_pins: spi1 { ++ renesas,groups = "msiof0_clk", "msiof0_sync", "msiof0_rx", ++ "msiof0_tx"; ++ renesas,function = "msiof0"; ++ }; ++ ++ sound_pins: sound { ++ renesas,groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data"; ++ renesas,function = "ssi"; ++ }; ++ ++ sound_clk_pins: sound_clk { ++ renesas,groups = "audio_clk_a"; ++ renesas,function = "audio_clk"; ++ }; ++ ++ usb0_pins: usb0 { ++ renesas,groups = "usb0"; ++ renesas,function = "usb0"; ++ }; ++ ++ usb1_pins: usb1 { ++ renesas,groups = "usb1"; ++ renesas,function = "usb1"; ++ }; ++ ++ vin0_pins: vin0 { ++ renesas,groups = "vin0_data8", "vin0_clk"; ++ renesas,function = "vin0"; ++ }; ++}; ++ ++ðer { ++ pinctrl-0 = <ðer_pins &phy1_pins>; ++ pinctrl-names = "default"; ++ ++ phy-handle = <&phy1>; ++ renesas,ether-link-active-low; ++ status = "ok"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ interrupt-parent = <&irqc0>; ++ interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ micrel,led-mode = <1>; ++ }; ++}; ++ ++&sata0 { ++ status = "okay"; ++}; ++ ++&scif0 { ++ pinctrl-0 = <&scif0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&sdhi0 { ++ pinctrl-0 = <&sdhi0_pins>; ++ pinctrl-names = "default"; ++ ++ vmmc-supply = <&vcc_sdhi0>; ++ vqmmc-supply = <&vccq_sdhi0>; ++ cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>; ++ wp-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&sdhi2 { ++ pinctrl-0 = <&sdhi2_pins>; ++ pinctrl-names = "default"; ++ ++ vmmc-supply = <&vcc_sdhi2>; ++ vqmmc-supply = <&vccq_sdhi2>; ++ cd-gpios = <&gpio6 22 GPIO_ACTIVE_LOW>; ++ toshiba,mmc-wrprotect-disable; ++ status = "okay"; ++}; ++ ++&qspi { ++ pinctrl-0 = <&qspi_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ ++ flash: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,s25fl512s"; ++ reg = <0>; ++ spi-max-frequency = <30000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ m25p,fast-read; ++ spi-cpol; ++ spi-cpha; ++ ++ partition@0 { ++ label = "loader"; ++ reg = <0x00000000 0x00040000>; ++ read-only; ++ }; ++ partition@40000 { ++ label = "user"; ++ reg = <0x00040000 0x00400000>; ++ read-only; ++ }; ++ partition@440000 { ++ label = "flash"; ++ reg = <0x00440000 0x03bc0000>; ++ }; ++ }; ++}; ++ ++&msiof0 { ++ pinctrl-0 = <&msiof0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&i2c1 { ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++}; ++ ++&i2c2 { ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ eeprom@50 { ++ compatible = "renesas,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ snd_codec: ak4643 { ++ #sound-dai-cells = <0>; ++ compatible = "asahi-kasei,ak4643"; ++ reg = <0x12>; ++ }; ++}; ++ ++&i2c4 { ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++}; ++ ++&i2c5 { ++ status = "okay"; ++ clock-frequency = <400000>; ++}; ++ ++&i2c6 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ ++ vdd_dvfs: regulator@68 { ++ compatible = "diasemi,da9210"; ++ reg = <0x68>; ++ ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&pci0 { ++ status = "okay"; ++ pinctrl-0 = <&usb0_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&pci1 { ++ status = "okay"; ++ pinctrl-0 = <&usb1_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&pcie_bus_clk { ++ status = "okay"; ++}; ++ ++&pciec { ++ status = "okay"; ++}; ++ ++&cpu0 { ++ cpu0-supply = <&vdd_dvfs>; ++}; +diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig +index 11237db..bb4e0e6 100644 +--- a/arch/arm/configs/shmobile_defconfig ++++ b/arch/arm/configs/shmobile_defconfig +@@ -26,6 +26,7 @@ CONFIG_MACH_GOSE=y + CONFIG_MACH_ALT=y + CONFIG_MACH_SILK=y + CONFIG_MACH_MARZEN=y ++CONFIG_MACH_PORTER=y + CONFIG_SHMOBILE_TIMER_HZ=100 + CONFIG_ARM_LPAE=y + # CONFIG_SWP_EMULATE is not set +diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig +index e2e00a9..7c15245 100644 +--- a/arch/arm/mach-shmobile/Kconfig ++++ b/arch/arm/mach-shmobile/Kconfig +@@ -93,6 +93,12 @@ config MACH_MARZEN + depends on ARCH_R8A7779 + select REGULATOR_FIXED_VOLTAGE if REGULATOR + ++config MACH_PORTER ++ bool "Porter board" ++ depends on ARCH_R8A7791 ++ select MICREL_PHY if SH_ETH ++ select SND_SOC_AK4642 if SND_SIMPLE_CARD ++ + comment "Renesas ARM SoCs System Configuration" + endif + +diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile +index 139f31c..43b4025 100644 +--- a/arch/arm/mach-shmobile/Makefile ++++ b/arch/arm/mach-shmobile/Makefile +@@ -78,6 +78,7 @@ obj-$(CONFIG_MACH_GOSE) += board-gose-reference.o + obj-$(CONFIG_MACH_ALT) += board-alt-reference.o + obj-$(CONFIG_MACH_SILK) += board-silk-reference.o + obj-$(CONFIG_MACH_MARZEN) += board-marzen-reference.o ++obj-$(CONFIG_MACH_PORTER) += board-porter-reference.o + else + obj-$(CONFIG_MACH_APE6EVM) += board-ape6evm.o + obj-$(CONFIG_MACH_APE6EVM_REFERENCE) += board-ape6evm-reference.o +diff --git a/arch/arm/mach-shmobile/board-porter-reference.c b/arch/arm/mach-shmobile/board-porter-reference.c +new file mode 100644 +index 0000000..d481ecd +--- /dev/null ++++ b/arch/arm/mach-shmobile/board-porter-reference.c +@@ -0,0 +1,953 @@ ++/* ++ * Porter board support - Reference DT implementation ++ * ++ * Copyright (C) 2013-2015 Renesas Electronics Corporation ++ * Copyright (C) 2013 Renesas Solutions Corp. ++ * Copyright (C) 2013 Magnus Damm ++ * Copyright (C) 2015 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. ++ * ++ * 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 ++ */ ++ ++#include <linux/dma-mapping.h> ++#include <linux/kernel.h> ++#include <linux/mfd/tmio.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/sh_mobile_sdhi.h> ++#include <linux/of_gpio.h> ++#include <linux/of_platform.h> ++#include <linux/platform_data/camera-rcar.h> ++#include <linux/platform_data/rcar-du.h> ++#include <linux/platform_data/usb-rcar-gen2-phy.h> ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++#include <linux/platform_data/vsp1.h> ++#endif ++#include <linux/serial_sci.h> ++#include <linux/sh_dma.h> ++#include <linux/spi/flash.h> ++#include <linux/spi/sh_msiof.h> ++#include <linux/spi/spi.h> ++#include <linux/usb/phy.h> ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++#include <linux/usb/renesas_usbhs.h> ++#endif ++#include <media/soc_camera.h> ++#include <asm/mach/arch.h> ++#include <sound/rcar_snd.h> ++#include <sound/simple_card.h> ++ ++#include "clock.h" ++#include "common.h" ++#include "dma-register.h" ++#include "irqs.h" ++#include "r8a7791.h" ++#include "rcar-gen2.h" ++ ++/* DU */ ++static struct rcar_du_encoder_data porter_du_encoders[] = { ++ { ++ .type = RCAR_DU_ENCODER_HDMI, ++ .output = RCAR_DU_OUTPUT_DPAD0, ++ }, ++ { ++ .type = RCAR_DU_ENCODER_NONE, ++ .output = RCAR_DU_OUTPUT_LVDS0, ++ .connector.lvds.panel = { ++ .width_mm = 229, ++ .height_mm = 149, ++ .mode = { ++ .clock = 69000, ++ .hdisplay = 1280, ++ .hsync_start = 1280 + 48, ++ .hsync_end = 1280 + 48 + 32, ++ .htotal = 1280 + 48 + 32 + 80, ++ .vdisplay = 800, ++ .vsync_start = 800 + 2, ++ .vsync_end = 800 + 2 + 6, ++ .vtotal = 800 + 2 + 6 + 15, ++ .flags = 0, ++ }, ++ }, ++ }, ++}; ++ ++static struct rcar_du_crtc_data porter_du_crtcs[] = { ++ { ++ .exclk = 0, /* NoP */ ++ .init_conn_type = DRM_MODE_CONNECTOR_LVDS, ++ }, ++ { ++ .exclk = 0, /* NoP */ ++ .init_conn_type = DRM_MODE_CONNECTOR_HDMIA, ++ }, ++}; ++ ++static struct rcar_du_platform_data porter_du_pdata = { ++ .encoders = porter_du_encoders, ++ .num_encoders = ARRAY_SIZE(porter_du_encoders), ++ .crtcs = porter_du_crtcs, ++ .num_crtcs = ARRAY_SIZE(porter_du_crtcs), ++#ifdef CONFIG_DRM_FBDEV_CRTC ++ .fbdev_crtc = 1, ++#endif ++ .i2c_ch = 2, ++}; ++ ++static const struct resource du_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfeb00000, 0x40000), ++ DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), ++ DEFINE_RES_IRQ(gic_spi(256)), ++ DEFINE_RES_IRQ(gic_spi(268)), ++}; ++ ++static void __init porter_add_du_device(void) ++{ ++ struct platform_device_info info = { ++ .name = "rcar-du-r8a7791", ++ .id = -1, ++ .res = du_resources, ++ .num_res = ARRAY_SIZE(du_resources), ++ .data = &porter_du_pdata, ++ .size_data = sizeof(porter_du_pdata), ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ ++ platform_device_register_full(&info); ++} ++ ++/* Sound */ ++static struct rsnd_ssi_platform_info rsnd_ssi[] = { ++ RSND_SSI(AUDIOPP_DMAC_SLAVE_CMD0_TO_SSI0, gic_spi(370), 0), ++ RSND_SSI(AUDIOPP_DMAC_SLAVE_SSI1_TO_SCU1, gic_spi(371), RSND_SSI_CLK_PIN_SHARE), ++}; ++ ++static struct rsnd_src_platform_info rsnd_src[2] = { ++ RSND_SRC(0, AUDIO_DMAC_SLAVE_SCU0_TX, gic_spi(352)), ++ RSND_SRC(0, AUDIO_DMAC_SLAVE_CMD1_TO_MEM, gic_spi(353)), ++}; ++ ++static struct rsnd_dvc_platform_info rsnd_dvc[2] = { ++}; ++ ++static struct rsnd_dai_platform_info rsnd_dai = { ++ .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0], .dvc = &rsnd_dvc[0], }, ++ .capture = { .ssi = &rsnd_ssi[1], .src = &rsnd_src[1], .dvc = &rsnd_dvc[1], }, ++}; ++ ++static struct rcar_snd_info rsnd_info = { ++ .flags = RSND_GEN2, ++ .ssi_info = rsnd_ssi, ++ .ssi_info_nr = ARRAY_SIZE(rsnd_ssi), ++ .src_info = rsnd_src, ++ .src_info_nr = ARRAY_SIZE(rsnd_src), ++ .dvc_info = rsnd_dvc, ++ .dvc_info_nr = ARRAY_SIZE(rsnd_dvc), ++ .dai_info = &rsnd_dai, ++ .dai_info_nr = 1, ++}; ++ ++static struct asoc_simple_card_info rsnd_card_info = { ++ .name = "SSI01-AK4643", ++ .codec = "ak4642-codec.2-0012", ++ .platform = "rcar_sound", ++ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, ++ .cpu_dai = { ++ .name = "rcar_sound", ++ }, ++ .codec_dai = { ++ .name = "ak4642-hifi", ++ .sysclk = 11289600, ++ }, ++}; ++ ++static void __init porter_add_rsnd_device(void) ++{ ++ struct resource rsnd_resources[] = { ++ [RSND_GEN2_SCU] = DEFINE_RES_MEM(0xec500000, 0x1000), ++ [RSND_GEN2_ADG] = DEFINE_RES_MEM(0xec5a0000, 0x100), ++ [RSND_GEN2_SSIU] = DEFINE_RES_MEM(0xec540000, 0x1000), ++ [RSND_GEN2_SSI] = DEFINE_RES_MEM(0xec541000, 0x1280), ++ }; ++ ++ struct platform_device_info cardinfo = { ++ .parent = &platform_bus, ++ .name = "asoc-simple-card", ++ .id = -1, ++ .data = &rsnd_card_info, ++ .size_data = sizeof(struct asoc_simple_card_info), ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ ++ platform_device_register_resndata( ++ &platform_bus, "rcar_sound", -1, ++ rsnd_resources, ARRAY_SIZE(rsnd_resources), ++ &rsnd_info, sizeof(rsnd_info)); ++ ++ platform_device_register_full(&cardinfo); ++} ++ ++ ++/* ++ * This is a really crude hack to provide clkdev support to platform ++ * devices until they get moved to DT. ++ */ ++static const struct clk_name clk_names[] __initconst = { ++ { "cmt0", NULL, "sh_cmt.0" }, ++ { "cmt0", "fck", "sh-cmt-48-gen2.0" }, ++ { "du0", "du.0", "rcar-du-r8a7791" }, ++ { "du1", "du.1", "rcar-du-r8a7791" }, ++ { "lvds0", "lvds.0", "rcar-du-r8a7791" }, ++ { "hsusb", NULL, "usb_phy_rcar_gen2" }, ++ { "ssi0", "ssi.0", "rcar_sound" }, ++ { "ssi1", "ssi.1", "rcar_sound" }, ++ { "src0", "src.0", "rcar_sound" }, ++ { "src1", "src.1", "rcar_sound" }, ++ { "dvc0", "dvc.0", "rcar_sound" }, ++ { "dvc1", "dvc.1", "rcar_sound" }, ++ { "vin0", NULL, "r8a7791-vin.0" }, ++ { "vsps", NULL, NULL }, ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++ { "vsp1-du0", NULL, "vsp1.2" }, ++ { "vsp1-du1", NULL, "vsp1.3" }, ++#else ++ { "vsp1-du0", NULL, NULL }, ++ { "vsp1-du1", NULL, NULL }, ++#endif ++ { "vcp0", NULL, NULL }, ++ { "vpc0", NULL, NULL }, ++ { "tddmac", NULL, NULL }, ++ { "fdp1", NULL, NULL }, ++ { "fdp0", NULL, NULL }, ++ { "pvrsrvkm", NULL, "pvrsrvkm" }, ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ { "hsusb", NULL, "renesas_usbhs" }, ++#else ++ { "ehci", NULL, "pci-rcar-gen2.0" }, ++#endif ++}; ++ ++/* ++ * This is a really crude hack to work around core platform clock issues ++ */ ++static const struct clk_name clk_enables[] __initconst = { ++ { "ehci", NULL, "pci-rcar-gen2.1" }, ++ { "dmal", NULL, "sh-dma-engine.0" }, ++ { "dmah", NULL, "sh-dma-engine.1" }, ++ { "sys-dmac1", NULL, "sh-dma-engine.2" }, ++ { "sys-dmac0", NULL, "sh-dma-engine.3" }, ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ { "usbdmac0", NULL, "sh-dma-engine.4" }, ++#endif ++ { "ssp_dev", NULL, "ssp_dev" }, ++ { "ipmmu_gp", NULL, "ipmmu_gp" }, ++}; ++ ++#define DMAE_CHANNEL(a, b) \ ++{ \ ++ .offset = (a) - 0x20, \ ++ .dmars = (a) - 0x20 + 0x40, \ ++ .chclr_bit = (b), \ ++ .chclr_offset = 0x80 - 0x20, \ ++} ++ ++/* Sys-DMAC */ ++#define SYS_DMAC_SLAVE(_id, _bit, _addr, toffset, roffset, t, r) \ ++{ \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_TX, \ ++ .addr = _addr + toffset, \ ++ .chcr = CHCR_TX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = t, \ ++}, { \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_RX, \ ++ .addr = _addr + roffset, \ ++ .chcr = CHCR_RX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = r, \ ++} ++ ++#define SYS_DMAC_SLAVE_TX(_id, _bit, _addr, toffset, roffset, t, r) \ ++{ \ ++ .slave_id = SYS_DMAC_SLAVE_## _id ##_TX, \ ++ .addr = _addr + toffset, \ ++ .chcr = CHCR_TX(XMIT_SZ_## _bit ##BIT), \ ++ .mid_rid = t, \ ++} ++ ++static const struct sh_dmae_slave_config r8a7791_sys_dmac_slaves[] = { ++ SYS_DMAC_SLAVE(SDHI0, 256, 0xee100000, 0x60, 0x2060, 0xcd, 0xce), ++ SYS_DMAC_SLAVE(SDHI1, 256, 0xee140000, 0x30, 0x2030, 0xc1, 0xc2), ++ SYS_DMAC_SLAVE(SDHI2, 256, 0xee160000, 0x30, 0x2030, 0xd3, 0xd4), ++ SYS_DMAC_SLAVE(SCIF0, 8, 0xe6e60000, 0xc, 0x14, 0x29, 0x2a), ++ SYS_DMAC_SLAVE(SCIF1, 8, 0xe6e68000, 0xc, 0x14, 0x2d, 0x2e), ++ SYS_DMAC_SLAVE(SCIF2, 8, 0xe6e58000, 0xc, 0x14, 0x2b, 0x2c), ++ SYS_DMAC_SLAVE(SCIF3, 8, 0xe6ea8000, 0xc, 0x14, 0x2f, 0x30), ++ SYS_DMAC_SLAVE(SCIF4, 8, 0xe6ee0000, 0xc, 0x14, 0xfb, 0xfc), ++ SYS_DMAC_SLAVE(SCIF5, 8, 0xe6ee8000, 0xc, 0x14, 0xfd, 0xfe), ++ SYS_DMAC_SLAVE(SCIFA0, 8, 0xe6c40000, 0x20, 0x24, 0x21, 0x22), ++ SYS_DMAC_SLAVE(SCIFA1, 8, 0xe6c50000, 0x20, 0x24, 0x25, 0x26), ++ SYS_DMAC_SLAVE(SCIFA2, 8, 0xe6c60000, 0x20, 0x24, 0x27, 0x28), ++ SYS_DMAC_SLAVE(SCIFA3, 8, 0xe6c70000, 0x20, 0x24, 0x1b, 0x1c), ++ SYS_DMAC_SLAVE(SCIFA4, 8, 0xe6c78000, 0x20, 0x24, 0x1f, 0x20), ++ SYS_DMAC_SLAVE(SCIFA5, 8, 0xe6c80000, 0x20, 0x24, 0x23, 0x24), ++ SYS_DMAC_SLAVE(SCIFB0, 8, 0xe6c20000, 0x40, 0x60, 0x3d, 0x3e), ++ SYS_DMAC_SLAVE(SCIFB1, 8, 0xe6c30000, 0x40, 0x60, 0x19, 0x1a), ++ SYS_DMAC_SLAVE(SCIFB2, 8, 0xe6ce0000, 0x40, 0x60, 0x1d, 0x1e), ++ SYS_DMAC_SLAVE(HSCIF0, 8, 0xe62c0000, 0xc, 0x14, 0x39, 0x3a), ++ SYS_DMAC_SLAVE(HSCIF1, 8, 0xe62c8000, 0xc, 0x14, 0x4d, 0x4e), ++ SYS_DMAC_SLAVE(HSCIF2, 8, 0xe62d0000, 0xc, 0x14, 0x3b, 0x3c), ++ SYS_DMAC_SLAVE(MSIOF0, 32, 0xe7e20000, 0x50, 0x60, 0x51, 0x52), ++ SYS_DMAC_SLAVE(MSIOF1, 32, 0xe7e10000, 0x50, 0x60, 0x55, 0x56), ++ SYS_DMAC_SLAVE(MSIOF2, 32, 0xe7e00000, 0x50, 0x60, 0x41, 0x42), ++}; ++ ++static const struct sh_dmae_channel r8a7791_sys_dmac_channels[] = { ++ DMAE_CHANNEL(0x8000, 0), ++ DMAE_CHANNEL(0x8080, 1), ++ DMAE_CHANNEL(0x8100, 2), ++ DMAE_CHANNEL(0x8180, 3), ++ DMAE_CHANNEL(0x8200, 4), ++ DMAE_CHANNEL(0x8280, 5), ++ DMAE_CHANNEL(0x8300, 6), ++ DMAE_CHANNEL(0x8380, 7), ++ DMAE_CHANNEL(0x8400, 8), ++ DMAE_CHANNEL(0x8480, 9), ++ DMAE_CHANNEL(0x8500, 10), ++ DMAE_CHANNEL(0x8580, 11), ++ DMAE_CHANNEL(0x8600, 12), ++ DMAE_CHANNEL(0x8680, 13), ++ DMAE_CHANNEL(0x8700, 14), ++}; ++ ++static struct sh_dmae_pdata r8a7791_sys_dmac_platform_data = { ++ .slave = r8a7791_sys_dmac_slaves, ++ .slave_num = ARRAY_SIZE(r8a7791_sys_dmac_slaves), ++ .channel = r8a7791_sys_dmac_channels, ++ .channel_num = ARRAY_SIZE(r8a7791_sys_dmac_channels), ++ .ts_low_shift = TS_LOW_SHIFT, ++ .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, ++ .ts_high_shift = TS_HI_SHIFT, ++ .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, ++ .ts_shift = dma_ts_shift, ++ .ts_shift_num = ARRAY_SIZE(dma_ts_shift), ++ .dmaor_init = DMAOR_DME, ++ .chclr_present = 1, ++ .chclr_bitwise = 1, ++ .fourty_bits_addr = 1, ++}; ++ ++static struct resource r8a7791_sys_dmac_resources[] = { ++ /* Channel registers and DMAOR for low */ ++ DEFINE_RES_MEM(0xe6700020, 0x8763 - 0x20), ++ DEFINE_RES_IRQ(gic_spi(197)), ++ DEFINE_RES_NAMED(gic_spi(200), 15, NULL, IORESOURCE_IRQ), ++ ++ /* Channel registers and DMAOR for high */ ++ DEFINE_RES_MEM(0xe6720020, 0x8763 - 0x20), ++ DEFINE_RES_IRQ(gic_spi(220)), ++ DEFINE_RES_NAMED(gic_spi(216), 4, NULL, IORESOURCE_IRQ), ++ DEFINE_RES_NAMED(gic_spi(308), 11, NULL, IORESOURCE_IRQ), ++}; ++ ++#define r8a7791_register_sys_dmac(id) \ ++ platform_device_register_resndata( \ ++ &platform_bus, "sh-dma-engine", 2 + id, \ ++ &r8a7791_sys_dmac_resources[id * 3], id * 1 + 3, \ ++ &r8a7791_sys_dmac_platform_data, \ ++ sizeof(r8a7791_sys_dmac_platform_data)) ++ ++static void __init porter_add_dmac_prototype(void) ++{ ++ r8a7791_register_sys_dmac(0); ++ r8a7791_register_sys_dmac(1); ++} ++ ++static struct sh_mobile_sdhi_info sdhi0_info __initdata = { ++ .dma_slave_tx = SYS_DMAC_SLAVE_SDHI0_TX, ++ .dma_slave_rx = SYS_DMAC_SLAVE_SDHI0_RX, ++ .dma_rx_offset = 0x2000, ++ ++ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | ++ MMC_CAP_POWER_OFF_CARD, ++ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, ++}; ++ ++static struct sh_mobile_sdhi_info sdhi2_info __initdata = { ++ .dma_slave_tx = SYS_DMAC_SLAVE_SDHI2_TX, ++ .dma_slave_rx = SYS_DMAC_SLAVE_SDHI2_RX, ++ .dma_rx_offset = 0x2000, ++ ++ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | ++ MMC_CAP_POWER_OFF_CARD, ++ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | ++ TMIO_MMC_WRPROTECT_DISABLE, ++}; ++ ++/* SCIF */ ++#define SCIF_PD(scif_type, index, scif_index) \ ++static struct plat_sci_port scif##index##_platform_data = { \ ++ .type = PORT_##scif_type, \ ++ .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \ ++ .scscr = SCSCR_RE | SCSCR_TE, \ ++ .dma_slave_tx = SYS_DMAC_SLAVE_##scif_type##scif_index##_TX, \ ++ .dma_slave_rx = SYS_DMAC_SLAVE_##scif_type##scif_index##_RX, \ ++} ++ ++#define PDATA_SCIF(index, baseaddr, irq, i) SCIF_PD(SCIF, index, i) ++#define PDATA_SCIFA(index, baseaddr, irq, i) SCIF_PD(SCIFA, index, i) ++#define PDATA_SCIFB(index, baseaddr, irq, i) SCIF_PD(SCIFB, index, i) ++#define PDATA_HSCIF(index, baseaddr, irq, i) SCIF_PD(HSCIF, index, i) ++ ++PDATA_SCIFA(0, 0xe6c40000, gic_spi(144), 0); /* SCIFA0 */ ++PDATA_SCIFA(1, 0xe6c50000, gic_spi(145), 1); /* SCIFA1 */ ++PDATA_SCIFB(2, 0xe6c20000, gic_spi(148), 0); /* SCIFB0 */ ++PDATA_SCIFB(3, 0xe6c30000, gic_spi(149), 1); /* SCIFB1 */ ++PDATA_SCIFB(4, 0xe6ce0000, gic_spi(150), 2); /* SCIFB2 */ ++PDATA_SCIFA(5, 0xe6c60000, gic_spi(151), 2); /* SCIFA2 */ ++PDATA_SCIF(6, 0xe6e60000, gic_spi(152), 0); /* SCIF0 */ ++PDATA_SCIF(7, 0xe6e68000, gic_spi(153), 1); /* SCIF1 */ ++PDATA_HSCIF(8, 0xe62c0000, gic_spi(154), 0); /* HSCIF0 */ ++PDATA_HSCIF(9, 0xe62c8000, gic_spi(155), 1); /* HSCIF1 */ ++PDATA_SCIF(10, 0xe6e58000, gic_spi(22), 2); /* SCIF2 */ ++PDATA_SCIF(11, 0xe6ea8000, gic_spi(23), 3); /* SCIF3 */ ++PDATA_SCIF(12, 0xe6ee0000, gic_spi(24), 4); /* SCIF4 */ ++PDATA_SCIF(13, 0xe6ee8000, gic_spi(25), 5); /* SCIF5 */ ++PDATA_SCIFA(14, 0xe6c70000, gic_spi(29), 3); /* SCIFA3 */ ++PDATA_SCIFA(15, 0xe6c78000, gic_spi(30), 4); /* SCIFA4 */ ++PDATA_SCIFA(16, 0xe6c80000, gic_spi(31), 5); /* SCIFA5 */ ++PDATA_HSCIF(17, 0xe6cd0000, gic_spi(21), 2); /* HSCIF2 */ ++ ++#define SCIF_AD(scif_type, index, baseaddr) \ ++ OF_DEV_AUXDATA("renesas," scif_type "-r8a7791", baseaddr, \ ++ "sh-sci." # index, &scif##index##_platform_data) ++ ++#define AUXDATA_SCIF(index, baseaddr, irq) SCIF_AD("scif", index, baseaddr) ++#define AUXDATA_SCIFA(index, baseaddr, irq) SCIF_AD("scifa", index, baseaddr) ++#define AUXDATA_SCIFB(index, baseaddr, irq) SCIF_AD("scifb", index, baseaddr) ++#define AUXDATA_HSCIF(index, baseaddr, irq) SCIF_AD("hscif", index, baseaddr) ++ ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++/* USB-DMAC */ ++static const struct sh_dmae_channel usb_dmac_channels[] = { ++ { ++ .offset = 0, ++ }, { ++ .offset = 0x20, ++ }, ++}; ++ ++static const struct sh_dmae_slave_config usb_dmac_slaves[] = { ++ { ++ .slave_id = USB_DMAC_SLAVE_USBHS_TX, ++ .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_32BYTE), ++ }, { ++ .slave_id = USB_DMAC_SLAVE_USBHS_RX, ++ .chcr = USBTS_INDEX2VAL(USBTS_XMIT_SZ_32BYTE), ++ }, ++}; ++ ++static struct sh_dmae_pdata usb_dmac_platform_data = { ++ .slave = usb_dmac_slaves, ++ .slave_num = ARRAY_SIZE(usb_dmac_slaves), ++ .channel = usb_dmac_channels, ++ .channel_num = ARRAY_SIZE(usb_dmac_channels), ++ .ts_low_shift = USBTS_LOW_SHIFT, ++ .ts_low_mask = USBTS_LOW_BIT << USBTS_LOW_SHIFT, ++ .ts_high_shift = USBTS_HI_SHIFT, ++ .ts_high_mask = USBTS_HI_BIT << USBTS_HI_SHIFT, ++ .ts_shift = dma_usbts_shift, ++ .ts_shift_num = ARRAY_SIZE(dma_usbts_shift), ++ .dmaor_init = DMAOR_DME, ++ .chcr_offset = 0x14, ++ .chcr_ie_bit = 1 << 5, ++ .dmaor_is_32bit = 1, ++ .needs_tend_set = 1, ++ .no_dmars = 1, ++ .slave_only = 1, ++}; ++ ++static struct resource usb_dmac_resources[] = { ++ DEFINE_RES_MEM(0xe65a0020, 0x44), /* Channel registers and DMAOR */ ++ DEFINE_RES_MEM(0xe65a0000, 0x14), /* VCR/SWR/DMICR */ ++ DEFINE_RES_IRQ(gic_spi(109)), ++}; ++ ++static void __init porter_add_usb_dmac_prototype(void) ++{ ++ platform_device_register_resndata(&platform_bus, "sh-dma-engine", ++ 4, ++ usb_dmac_resources, ++ ARRAY_SIZE(usb_dmac_resources), ++ &usb_dmac_platform_data, ++ sizeof(usb_dmac_platform_data)); ++} ++ ++ ++/* USBHS */ ++static const struct resource usbhs_resources[] __initconst = { ++ DEFINE_RES_MEM(0xe6590000, 0x100), ++ DEFINE_RES_IRQ(gic_spi(107)), ++}; ++ ++struct usbhs_private { ++ struct renesas_usbhs_platform_info info; ++ struct usb_phy *phy; ++ int id_gpio; ++}; ++ ++#define usbhs_get_priv(pdev) \ ++ container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info) ++ ++static int usbhs_power_ctrl(struct platform_device *pdev, ++ void __iomem *base, int enable) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ ++ if (!priv->phy) ++ return -ENODEV; ++ ++ if (enable) { ++ int retval = usb_phy_init(priv->phy); ++ ++ if (!retval) ++ retval = usb_phy_set_suspend(priv->phy, 0); ++ return retval; ++ } ++ ++ usb_phy_set_suspend(priv->phy, 1); ++ usb_phy_shutdown(priv->phy); ++ return 0; ++} ++ ++static int usbhs_hardware_init(struct platform_device *pdev) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ struct usb_phy *phy; ++ int ret; ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/gpio@e6055000"); ++ if (np) { ++ priv->id_gpio = of_get_gpio(np, 31); ++ of_node_put(np); ++ } else { ++ pr_warn("Error: Unable to get MAX3355 ID input\n"); ++ ret = -ENOTSUPP; ++ goto error2; ++ } ++ ++ /* Check MAX3355E ID pin */ ++ gpio_request_one(priv->id_gpio, GPIOF_IN, NULL); ++ if (!gpio_get_value(priv->id_gpio)) { ++ pr_warn("Error: USB0 cable selects host mode\n"); ++ ret = -ENOTSUPP; ++ goto error; ++ } ++ ++ phy = usb_get_phy_dev(&pdev->dev, 0); ++ if (IS_ERR(phy)) ++ return PTR_ERR(phy); ++ ++ priv->phy = phy; ++ return 0; ++ ++error: ++ gpio_free(priv->id_gpio); ++error2: ++ return ret; ++} ++ ++static int usbhs_hardware_exit(struct platform_device *pdev) ++{ ++ struct usbhs_private *priv = usbhs_get_priv(pdev); ++ ++ if (!priv->phy) ++ return 0; ++ ++ usb_put_phy(priv->phy); ++ priv->phy = NULL; ++ ++ gpio_free(priv->id_gpio); ++ return 0; ++} ++ ++static int usbhs_get_id(struct platform_device *pdev) ++{ ++ return USBHS_GADGET; ++} ++ ++static int usbhs_get_vbus(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static u32 porter_usbhs_pipe_type[] = { ++ USB_ENDPOINT_XFER_CONTROL, ++ USB_ENDPOINT_XFER_ISOC, ++ USB_ENDPOINT_XFER_ISOC, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_INT, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++ USB_ENDPOINT_XFER_BULK, ++}; ++ ++static struct usbhs_private usbhs_priv __initdata = { ++ .info = { ++ .platform_callback = { ++ .power_ctrl = usbhs_power_ctrl, ++ .hardware_init = usbhs_hardware_init, ++ .hardware_exit = usbhs_hardware_exit, ++ .get_id = usbhs_get_id, ++ .get_vbus = usbhs_get_vbus, ++ }, ++ .driver_param = { ++ .buswait_bwait = 4, ++ .pipe_type = porter_usbhs_pipe_type, ++ .pipe_size = ARRAY_SIZE(porter_usbhs_pipe_type), ++ .d0_rx_id = USB_DMAC_SLAVE_USBHS_RX, ++ .d1_tx_id = USB_DMAC_SLAVE_USBHS_TX, ++ .usb_dmac_xfer_size = 32, ++ }, ++ } ++}; ++ ++static void __init porter_add_usb0_gadget(void) ++{ ++ usb_bind_phy("renesas_usbhs", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_resndata(&platform_bus, ++ "renesas_usbhs", -1, ++ usbhs_resources, ++ ARRAY_SIZE(usbhs_resources), ++ &usbhs_priv.info, ++ sizeof(usbhs_priv.info)); ++} ++#else ++/* Internal PCI0 */ ++static const struct resource pci0_resources[] __initconst = { ++ DEFINE_RES_MEM(0xee090000, 0x10000), /* CFG */ ++ DEFINE_RES_MEM(0xee080000, 0x10000), /* MEM */ ++ DEFINE_RES_IRQ(gic_spi(108)), ++}; ++ ++static void __init porter_add_usb0_host(void) ++{ ++ usb_bind_phy("pci-rcar-gen2.0", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_simple("pci-rcar-gen2", ++ 0, pci0_resources, ++ ARRAY_SIZE(pci0_resources)); ++} ++#endif ++ ++/* Internal PCI1 */ ++static const struct resource pci1_resources[] __initconst = { ++ DEFINE_RES_MEM(0xee0d0000, 0x10000), /* CFG */ ++ DEFINE_RES_MEM(0xee0c0000, 0x10000), /* MEM */ ++ DEFINE_RES_IRQ(gic_spi(113)), ++}; ++ ++static void __init porter_add_usb1_host(void) ++{ ++ usb_bind_phy("pci-rcar-gen2.1", 0, "usb_phy_rcar_gen2"); ++ platform_device_register_simple("pci-rcar-gen2", ++ 1, pci1_resources, ++ ARRAY_SIZE(pci1_resources)); ++} ++ ++/* USBHS PHY */ ++static const struct rcar_gen2_phy_platform_data usbhs_phy_pdata __initconst = { ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ .chan0_pci = 0, /* Channel 0 is USBHS */ ++#else ++ .chan0_pci = 1, /* Channel 0 is PCI USB */ ++#endif ++ .chan2_pci = 1, /* Channel 2 is PCI USB host */ ++ .gpio_vbus = 798, ++ .wakeup = true, ++}; ++ ++/* VIN */ ++static const struct resource vin_resources[] __initconst = { ++ /* VIN0 */ ++ DEFINE_RES_MEM(0xe6ef0000, 0x1000), ++ DEFINE_RES_IRQ(gic_spi(188)), ++ /* VIN1 */ ++ DEFINE_RES_MEM(0xe6ef1000, 0x1000), ++ DEFINE_RES_IRQ(gic_spi(189)), ++}; ++ ++static void __init porter_add_vin_device(unsigned idx, ++ struct rcar_vin_platform_data *pdata) ++{ ++ struct platform_device_info vin_info = { ++ .parent = &platform_bus, ++ .name = "r8a7791-vin", ++ .id = idx, ++ .res = &vin_resources[idx * 2], ++ .num_res = 2, ++ .dma_mask = DMA_BIT_MASK(32), ++ .data = pdata, ++ .size_data = sizeof(*pdata), ++ }; ++ ++ BUG_ON(idx > 1); ++ ++ platform_device_register_full(&vin_info); ++} ++ ++#define PORTER_CAMERA(idx, name, addr, pdata, flag) \ ++static struct i2c_board_info i2c_cam##idx##_device = { \ ++ I2C_BOARD_INFO(name, addr), \ ++}; \ ++ \ ++static struct rcar_vin_platform_data vin##idx##_pdata = { \ ++ .flags = flag, \ ++}; \ ++ \ ++static struct soc_camera_link cam##idx##_link = { \ ++ .bus_id = idx, \ ++ .board_info = &i2c_cam##idx##_device, \ ++ .i2c_adapter_id = 2, \ ++ .module_name = name, \ ++ .priv = pdata, \ ++} ++ ++PORTER_CAMERA(0, "adv7180", 0x20, NULL, RCAR_VIN_BT656); ++ ++static void __init porter_add_camera0_device(void) ++{ ++ platform_device_register_data(&platform_bus, "soc-camera-pdrv", 0, ++ &cam0_link, sizeof(cam0_link)); ++ porter_add_vin_device(0, &vin0_pdata); ++} ++ ++/* VSP1 */ ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++static const struct vsp1_platform_data porter_vsps_pdata __initconst = { ++ .features = 0, ++ .rpf_count = 5, ++ .uds_count = 3, ++ .wpf_count = 4, ++}; ++ ++static const struct vsp1_platform_data porter_vspd0_pdata __initconst = { ++ .features = VSP1_HAS_LIF, ++ .rpf_count = 4, ++ .uds_count = 1, ++ .wpf_count = 4, ++}; ++ ++static const struct vsp1_platform_data porter_vspd1_pdata __initconst = { ++ .features = VSP1_HAS_LIF, ++ .rpf_count = 4, ++ .uds_count = 1, ++ .wpf_count = 4, ++}; ++ ++static const struct vsp1_platform_data * const porter_vsp1_pdata[] __initconst ++ = { ++ &porter_vsps_pdata, ++ &porter_vspd0_pdata, ++ &porter_vspd1_pdata, ++}; ++ ++static const struct resource vsp1_1_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfe928000, 0x8000), ++ DEFINE_RES_IRQ(gic_spi(267)), ++}; ++ ++static const struct resource vsp1_2_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfe930000, 0x8000), ++ DEFINE_RES_IRQ(gic_spi(246)), ++}; ++ ++static const struct resource vsp1_3_resources[] __initconst = { ++ DEFINE_RES_MEM(0xfe938000, 0x8000), ++ DEFINE_RES_IRQ(gic_spi(247)), ++}; ++ ++static const struct resource * const vsp1_resources[] __initconst = { ++ vsp1_1_resources, ++ vsp1_2_resources, ++ vsp1_3_resources, ++}; ++ ++static void __init porter_add_vsp1_devices(void) ++{ ++ struct platform_device_info info = { ++ .name = "vsp1", ++ .size_data = sizeof(*porter_vsp1_pdata[0]), ++ .num_res = 2, ++ .dma_mask = DMA_BIT_MASK(32), ++ }; ++ unsigned int i; ++ ++ for (i = 1; i < ARRAY_SIZE(vsp1_resources); ++i) { ++ info.id = i + 1; ++ info.data = porter_vsp1_pdata[i]; ++ info.res = vsp1_resources[i]; ++ ++ platform_device_register_full(&info); ++ } ++} ++#endif ++ ++static const struct resource usbhs_phy_resources[] __initconst = { ++ DEFINE_RES_MEM(0xe6590100, 0x100), ++}; ++ ++/* Add all available USB devices */ ++static void __init porter_add_usb_devices(void) ++{ ++ platform_device_register_resndata(&platform_bus, "usb_phy_rcar_gen2", ++ -1, usbhs_phy_resources, ++ ARRAY_SIZE(usbhs_phy_resources), ++ &usbhs_phy_pdata, ++ sizeof(usbhs_phy_pdata)); ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ porter_add_usb0_gadget(); ++#else ++ porter_add_usb0_host(); ++#endif ++ porter_add_usb1_host(); ++} ++ ++/* MSIOF */ ++static struct sh_msiof_spi_info msiof0_info = { ++ .rx_fifo_override = 256, ++ .num_chipselect = 1, ++ .dma_tx_id = SYS_DMAC_SLAVE_MSIOF0_TX, ++ .dma_rx_id = SYS_DMAC_SLAVE_MSIOF0_RX, ++}; ++ ++/* MSIOF spidev */ ++static const struct spi_board_info spi_bus[] __initconst = { ++ { ++ .modalias = "spidev", ++ .max_speed_hz = 6000000, ++ .mode = SPI_MODE_3, ++ .bus_num = 1, ++ .chip_select = 0, ++ }, ++}; ++ ++#define porter_add_msiof_device spi_register_board_info ++ ++/* POWER IC */ ++static struct i2c_board_info poweric_i2c[] = { ++ { I2C_BOARD_INFO("da9063", 0x58), }, ++}; ++ ++static void porter_restart(char mode, const char *cmd) ++{ ++ struct i2c_adapter *adap; ++ struct i2c_client *client; ++ u8 val; ++ int busnum = 6; ++ ++ adap = i2c_get_adapter(busnum); ++ if (!adap) { ++ pr_err("failed to get adapter i2c%d\n", busnum); ++ return; ++ } ++ ++ client = i2c_new_device(adap, &poweric_i2c[0]); ++ if (!client) ++ pr_err("failed to register %s to i2c%d\n", ++ poweric_i2c[0].type, busnum); ++ ++ i2c_put_adapter(adap); ++ ++ val = i2c_smbus_read_byte_data(client, 0x13); ++ ++ if (val < 0) ++ pr_err("couldn't access da9063\n"); ++ ++ val |= 0x02; ++ ++ i2c_smbus_write_byte_data(client, 0x13, val); ++} ++ ++static struct of_dev_auxdata porter_auxdata_lookup[] __initdata = { ++ OF_DEV_AUXDATA("renesas,sdhi-r8a7791", 0xee100000, "sdhi0", ++ &sdhi0_info), ++ OF_DEV_AUXDATA("renesas,sdhi-r8a7791", 0xee160000, "sdhi2", ++ &sdhi2_info), ++ AUXDATA_SCIFA(0, 0xe6c40000, gic_spi(144)), /* SCIFA0 */ ++ AUXDATA_SCIFA(1, 0xe6c50000, gic_spi(145)), /* SCIFA1 */ ++ AUXDATA_SCIFB(2, 0xe6c20000, gic_spi(148)), /* SCIFB0 */ ++ AUXDATA_SCIFB(3, 0xe6c30000, gic_spi(149)), /* SCIFB1 */ ++ AUXDATA_SCIFB(4, 0xe6ce0000, gic_spi(150)), /* SCIFB2 */ ++ AUXDATA_SCIFA(5, 0xe6c60000, gic_spi(151)), /* SCIFA2 */ ++ AUXDATA_SCIF(6, 0xe6e60000, gic_spi(152)), /* SCIF0 */ ++ AUXDATA_SCIF(7, 0xe6e68000, gic_spi(153)), /* SCIF1 */ ++ AUXDATA_HSCIF(8, 0xe62c0000, gic_spi(154)), /* HSCIF0 */ ++ AUXDATA_HSCIF(9, 0xe62c8000, gic_spi(155)), /* HSCIF1 */ ++ AUXDATA_SCIF(10, 0xe6e58000, gic_spi(22)), /* SCIF2 */ ++ AUXDATA_SCIF(11, 0xe6ea8000, gic_spi(23)), /* SCIF3 */ ++ AUXDATA_SCIF(12, 0xe6ee0000, gic_spi(24)), /* SCIF4 */ ++ AUXDATA_SCIF(13, 0xe6ee8000, gic_spi(25)), /* SCIF5 */ ++ AUXDATA_SCIFA(14, 0xe6c70000, gic_spi(29)), /* SCIFA3 */ ++ AUXDATA_SCIFA(15, 0xe6c78000, gic_spi(30)), /* SCIFA4 */ ++ AUXDATA_SCIFA(16, 0xe6c80000, gic_spi(31)), /* SCIFA5 */ ++ AUXDATA_HSCIF(17, 0xe6cd0000, gic_spi(21)), /* HSCIF2 */ ++ OF_DEV_AUXDATA("renesas,msiof-r8a7791", 0xe6e20000, ++ "spi_r8a7791_msiof.0", &msiof0_info), ++ {}, ++}; ++ ++static void __init porter_add_standard_devices(void) ++{ ++ shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); ++ shmobile_clk_workaround(clk_enables, ARRAY_SIZE(clk_enables), true); ++ r8a7791_add_dt_devices(); ++ porter_add_dmac_prototype(); ++#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC) ++ porter_add_usb_dmac_prototype(); ++#endif ++ of_platform_populate(NULL, of_default_bus_match_table, ++ porter_auxdata_lookup, NULL); ++ ++ porter_add_du_device(); ++ porter_add_usb_devices(); ++ porter_add_rsnd_device(); ++ porter_add_camera0_device(); ++#if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) ++ porter_add_vsp1_devices(); ++#endif ++ porter_add_msiof_device(spi_bus, ARRAY_SIZE(spi_bus)); ++} ++ ++static const char * const porter_boards_compat_dt[] __initconst = { ++ "renesas,porter", ++ "renesas,porter-reference", ++ NULL, ++}; ++ ++DT_MACHINE_START(PORTER_DT, "porter") ++ .smp = smp_ops(r8a7791_smp_ops), ++ .init_early = shmobile_init_delay, ++ .init_time = rcar_gen2_timer_init, ++ .init_machine = porter_add_standard_devices, ++ .init_late = shmobile_init_late, ++ .reserve = rcar_gen2_reserve, ++ .restart = porter_restart, ++ .dt_compat = porter_boards_compat_dt, ++MACHINE_END +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0009-shmobile-add-atag-dtb-compat.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0009-shmobile-add-atag-dtb-compat.patch new file mode 100644 index 0000000..8b6935f --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0009-shmobile-add-atag-dtb-compat.patch @@ -0,0 +1,26 @@ +From 80644cc053765ec9ea7c509acad7cfd819ea25f5 Mon Sep 17 00:00:00 2001 +From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +Date: Wed, 11 Feb 2015 15:19:56 +0300 +Subject: [PATCH] Add ATAG DTB compatibility + +This is useful when DTB is static + +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> + +--- + arch/arm/configs/shmobile_defconfig | 2 ++ + 1 file changed, 2 insertions(+) + +Index: renesas-backport.v0/arch/arm/configs/shmobile_defconfig +=================================================================== +--- renesas-backport.v0.orig/arch/arm/configs/shmobile_defconfig 2015-01-28 12:21:43.823500578 +0300 ++++ renesas-backport.v0/arch/arm/configs/shmobile_defconfig 2015-02-11 14:33:34.864892464 +0300 +@@ -52,6 +52,8 @@ + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_ARM_APPENDED_DTB=y ++CONFIG_ARM_ATAG_DTB_COMPAT=y ++CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y + CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT_DETAILS=y diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0010-Silk-Add-missing-pins-handle-to-Eth.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0010-Silk-Add-missing-pins-handle-to-Eth.patch new file mode 100644 index 0000000..22742ea --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0010-Silk-Add-missing-pins-handle-to-Eth.patch @@ -0,0 +1,43 @@ +From 4369d6e8d6c7068f6d570701afd87fb0e3b50495 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 13 Feb 2015 23:12:41 +0300 +Subject: [PATCH] ARM: dts: r8a7794-silk: Add missing pins handle to + Ethernet node + +This adds missing pins handle to the Ethernet node. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> +--- + arch/arm/boot/dts/r8a7794-silk.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +index dc04673..9775aba 100644 +--- a/arch/arm/boot/dts/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -239,6 +239,11 @@ + renesas,function = "eth"; + }; + ++ phy1_pins: phy1 { ++ renesas,groups = "intc_irq8"; ++ renesas,function = "intc"; ++ }; ++ + qspi_pins: spi0 { + renesas,groups = "qspi_ctrl", "qspi_data4"; + renesas,function = "qspi"; +@@ -286,6 +291,9 @@ + }; + + ðer { ++ pinctrl-0 = <ðer_pins &phy1_pins>; ++ pinctrl-names = "default"; ++ + phy-handle = <&phy1>; + renesas,ether-link-active-low; + status = "ok"; +-- +1.9.3 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0011-Silk-Add-missing-DU-pins.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0011-Silk-Add-missing-DU-pins.patch new file mode 100644 index 0000000..791b1a8 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0011-Silk-Add-missing-DU-pins.patch @@ -0,0 +1,49 @@ +From 78aac9e8fbd6b5463554990e055302074a7fc485 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Fri, 13 Feb 2015 06:01:51 +0300 +Subject: [PATCH] ARM: dts: r8a7794-silk: Add missing DU pins + +This adds missing DU pins to R8A7794 SILK device tree. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm/boot/dts/r8a7794-silk.dts | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts +index f6994c9..dc04673 100644 +--- a/arch/arm/boot/dts/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/r8a7794-silk.dts +@@ -209,16 +209,26 @@ + }; + + &pfc { +- pinctrl-0 = <&du_pins &usb0_pins &usb1_pins &sound_pins &sound_clk_pins ++ pinctrl-0 = <&du_pins &du0_pins &du1_pins &usb0_pins &usb1_pins &sound_pins &sound_clk_pins + &vin0_pins>; + pinctrl-names = "default"; + + du_pins: du { +- renesas,groups = "du0_rgb888", "du0_sync", "du0_clk_out", +- "du1_rgb666", "du1_sync", "du1_clk_out"; ++ renesas,groups = "du0_rgb888", "du0_sync", "du0_clk_out", "du0_cde_disp", ++ "du1_rgb666", "du1_sync", "du1_clk_out", "du1_cde_disp"; + renesas,function = "du"; + }; + ++ du0_pins: du0 { ++ renesas,groups = "du0_clk_in"; ++ renesas,function = "du0"; ++ }; ++ ++ du1_pins: du1 { ++ renesas,groups = "du1_clk_in"; ++ renesas,function = "du1"; ++ }; ++ + i2c0_pins: i2c0 { + renesas,groups = "i2c0_d"; + renesas,function = "i2c0"; +-- +1.9.3 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0012-can-add-Renesas-R-Car-CAN-driver.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0012-can-add-Renesas-R-Car-CAN-driver.patch new file mode 100644 index 0000000..55450c0 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0012-can-add-Renesas-R-Car-CAN-driver.patch @@ -0,0 +1,958 @@ +From fd1159318e55e901cf269de90163b19fd62938cb Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Sat, 17 May 2014 00:03:54 +0400 +Subject: [PATCH] can: add Renesas R-Car CAN driver + +Add support for the CAN controller found in Renesas R-Car SoCs. + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +--- + drivers/net/can/Kconfig | 10 + + drivers/net/can/Makefile | 1 + + drivers/net/can/rcar_can.c | 876 ++++++++++++++++++++++++++++++++++ + include/linux/can/platform/rcar_can.h | 17 + + 4 files changed, 904 insertions(+) + create mode 100644 drivers/net/can/rcar_can.c + create mode 100644 include/linux/can/platform/rcar_can.h + +diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig +index ac67afa..714b187 100644 +--- a/drivers/net/can/Kconfig ++++ b/drivers/net/can/Kconfig +@@ -119,6 +119,16 @@ config CAN_GRCAN + endian syntheses of the cores would need some modifications on + the hardware level to work. + ++config CAN_RCAR ++ tristate "Renesas R-Car CAN controller" ++ depends on ARM ++ ---help--- ++ Say Y here if you want to use CAN controller found on Renesas R-Car ++ SoCs. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called rcar_can. ++ + source "drivers/net/can/mscan/Kconfig" + + source "drivers/net/can/sja1000/Kconfig" +diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile +index c420588..90f538c 100644 +--- a/drivers/net/can/Makefile ++++ b/drivers/net/can/Makefile +@@ -25,5 +25,6 @@ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o + obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o + obj-$(CONFIG_PCH_CAN) += pch_can.o + obj-$(CONFIG_CAN_GRCAN) += grcan.o ++obj-$(CONFIG_CAN_RCAR) += rcar_can.o + + ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG +diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c +new file mode 100644 +index 0000000..5268d21 +--- /dev/null ++++ b/drivers/net/can/rcar_can.c +@@ -0,0 +1,876 @@ ++/* Renesas R-Car CAN device driver ++ * ++ * Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com> ++ * Copyright (C) 2013 Renesas Solutions Corp. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/interrupt.h> ++#include <linux/errno.h> ++#include <linux/netdevice.h> ++#include <linux/platform_device.h> ++#include <linux/can/led.h> ++#include <linux/can/dev.h> ++#include <linux/clk.h> ++#include <linux/can/platform/rcar_can.h> ++ ++#define RCAR_CAN_DRV_NAME "rcar_can" ++ ++/* Mailbox configuration: ++ * mailbox 60 - 63 - Rx FIFO mailboxes ++ * mailbox 56 - 59 - Tx FIFO mailboxes ++ * non-FIFO mailboxes are not used ++ */ ++#define RCAR_CAN_N_MBX 64 /* Number of mailboxes in non-FIFO mode */ ++#define RCAR_CAN_RX_FIFO_MBX 60 /* Mailbox - window to Rx FIFO */ ++#define RCAR_CAN_TX_FIFO_MBX 56 /* Mailbox - window to Tx FIFO */ ++#define RCAR_CAN_FIFO_DEPTH 4 ++ ++/* Mailbox registers structure */ ++struct rcar_can_mbox_regs { ++ u32 id; /* IDE and RTR bits, SID and EID */ ++ u8 stub; /* Not used */ ++ u8 dlc; /* Data Length Code - bits [0..3] */ ++ u8 data[8]; /* Data Bytes */ ++ u8 tsh; /* Time Stamp Higher Byte */ ++ u8 tsl; /* Time Stamp Lower Byte */ ++}; ++ ++struct rcar_can_regs { ++ struct rcar_can_mbox_regs mb[RCAR_CAN_N_MBX]; /* Mailbox registers */ ++ u32 mkr_2_9[8]; /* Mask Registers 2-9 */ ++ u32 fidcr[2]; /* FIFO Received ID Compare Register */ ++ u32 mkivlr1; /* Mask Invalid Register 1 */ ++ u32 mier1; /* Mailbox Interrupt Enable Register 1 */ ++ u32 mkr_0_1[2]; /* Mask Registers 0-1 */ ++ u32 mkivlr0; /* Mask Invalid Register 0*/ ++ u32 mier0; /* Mailbox Interrupt Enable Register 0 */ ++ u8 pad_440[0x3c0]; ++ u8 mctl[64]; /* Message Control Registers */ ++ u16 ctlr; /* Control Register */ ++ u16 str; /* Status register */ ++ u8 bcr[3]; /* Bit Configuration Register */ ++ u8 clkr; /* Clock Select Register */ ++ u8 rfcr; /* Receive FIFO Control Register */ ++ u8 rfpcr; /* Receive FIFO Pointer Control Register */ ++ u8 tfcr; /* Transmit FIFO Control Register */ ++ u8 tfpcr; /* Transmit FIFO Pointer Control Register */ ++ u8 eier; /* Error Interrupt Enable Register */ ++ u8 eifr; /* Error Interrupt Factor Judge Register */ ++ u8 recr; /* Receive Error Count Register */ ++ u8 tecr; /* Transmit Error Count Register */ ++ u8 ecsr; /* Error Code Store Register */ ++ u8 cssr; /* Channel Search Support Register */ ++ u8 mssr; /* Mailbox Search Status Register */ ++ u8 msmr; /* Mailbox Search Mode Register */ ++ u16 tsr; /* Time Stamp Register */ ++ u8 afsr; /* Acceptance Filter Support Register */ ++ u8 pad_857; ++ u8 tcr; /* Test Control Register */ ++ u8 pad_859[7]; ++ u8 ier; /* Interrupt Enable Register */ ++ u8 isr; /* Interrupt Status Register */ ++ u8 pad_862; ++ u8 mbsmr; /* Mailbox Search Mask Register */ ++}; ++ ++struct rcar_can_priv { ++ struct can_priv can; /* Must be the first member! */ ++ struct net_device *ndev; ++ struct napi_struct napi; ++ struct rcar_can_regs __iomem *regs; ++ struct clk *clk; ++ u8 tx_dlc[RCAR_CAN_FIFO_DEPTH]; ++ u32 tx_head; ++ u32 tx_tail; ++ u8 clock_select; ++ u8 ier; ++}; ++ ++static const struct can_bittiming_const rcar_can_bittiming_const = { ++ .name = RCAR_CAN_DRV_NAME, ++ .tseg1_min = 4, ++ .tseg1_max = 16, ++ .tseg2_min = 2, ++ .tseg2_max = 8, ++ .sjw_max = 4, ++ .brp_min = 1, ++ .brp_max = 1024, ++ .brp_inc = 1, ++}; ++ ++/* Control Register bits */ ++#define RCAR_CAN_CTLR_BOM (3 << 11) /* Bus-Off Recovery Mode Bits */ ++#define RCAR_CAN_CTLR_BOM_ENT (1 << 11) /* Entry to halt mode */ ++ /* at bus-off entry */ ++#define RCAR_CAN_CTLR_SLPM (1 << 10) ++#define RCAR_CAN_CTLR_CANM (3 << 8) /* Operating Mode Select Bit */ ++#define RCAR_CAN_CTLR_CANM_HALT (1 << 9) ++#define RCAR_CAN_CTLR_CANM_RESET (1 << 8) ++#define RCAR_CAN_CTLR_CANM_FORCE_RESET (3 << 8) ++#define RCAR_CAN_CTLR_MLM (1 << 3) /* Message Lost Mode Select */ ++#define RCAR_CAN_CTLR_IDFM (3 << 1) /* ID Format Mode Select Bits */ ++#define RCAR_CAN_CTLR_IDFM_MIXED (1 << 2) /* Mixed ID mode */ ++#define RCAR_CAN_CTLR_MBM (1 << 0) /* Mailbox Mode select */ ++ ++/* Status Register bits */ ++#define RCAR_CAN_STR_RSTST (1 << 8) /* Reset Status Bit */ ++ ++/* FIFO Received ID Compare Registers 0 and 1 bits */ ++#define RCAR_CAN_FIDCR_IDE (1 << 31) /* ID Extension Bit */ ++#define RCAR_CAN_FIDCR_RTR (1 << 30) /* Remote Transmission Request Bit */ ++ ++/* Receive FIFO Control Register bits */ ++#define RCAR_CAN_RFCR_RFEST (1 << 7) /* Receive FIFO Empty Status Flag */ ++#define RCAR_CAN_RFCR_RFE (1 << 0) /* Receive FIFO Enable */ ++ ++/* Transmit FIFO Control Register bits */ ++#define RCAR_CAN_TFCR_TFUST (7 << 1) /* Transmit FIFO Unsent Message */ ++ /* Number Status Bits */ ++#define RCAR_CAN_TFCR_TFUST_SHIFT 1 /* Offset of Transmit FIFO Unsent */ ++ /* Message Number Status Bits */ ++#define RCAR_CAN_TFCR_TFE (1 << 0) /* Transmit FIFO Enable */ ++ ++#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */ ++ /* for Rx mailboxes 0-31 */ ++#define RCAR_CAN_N_RX_MKREGS2 8 ++ ++/* Bit Configuration Register settings */ ++#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20) ++#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8) ++#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4) ++#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07) ++ ++/* Mailbox and Mask Registers bits */ ++#define RCAR_CAN_IDE (1 << 31) ++#define RCAR_CAN_RTR (1 << 30) ++#define RCAR_CAN_SID_SHIFT 18 ++ ++/* Mailbox Interrupt Enable Register 1 bits */ ++#define RCAR_CAN_MIER1_RXFIE (1 << 28) /* Receive FIFO Interrupt Enable */ ++#define RCAR_CAN_MIER1_TXFIE (1 << 24) /* Transmit FIFO Interrupt Enable */ ++ ++/* Interrupt Enable Register bits */ ++#define RCAR_CAN_IER_ERSIE (1 << 5) /* Error (ERS) Interrupt Enable Bit */ ++#define RCAR_CAN_IER_RXFIE (1 << 4) /* Reception FIFO Interrupt */ ++ /* Enable Bit */ ++#define RCAR_CAN_IER_TXFIE (1 << 3) /* Transmission FIFO Interrupt */ ++ /* Enable Bit */ ++/* Interrupt Status Register bits */ ++#define RCAR_CAN_ISR_ERSF (1 << 5) /* Error (ERS) Interrupt Status Bit */ ++#define RCAR_CAN_ISR_RXFF (1 << 4) /* Reception FIFO Interrupt */ ++ /* Status Bit */ ++#define RCAR_CAN_ISR_TXFF (1 << 3) /* Transmission FIFO Interrupt */ ++ /* Status Bit */ ++ ++/* Error Interrupt Enable Register bits */ ++#define RCAR_CAN_EIER_BLIE (1 << 7) /* Bus Lock Interrupt Enable */ ++#define RCAR_CAN_EIER_OLIE (1 << 6) /* Overload Frame Transmit */ ++ /* Interrupt Enable */ ++#define RCAR_CAN_EIER_ORIE (1 << 5) /* Receive Overrun Interrupt Enable */ ++#define RCAR_CAN_EIER_BORIE (1 << 4) /* Bus-Off Recovery Interrupt Enable */ ++#define RCAR_CAN_EIER_BOEIE (1 << 3) /* Bus-Off Entry Interrupt Enable */ ++#define RCAR_CAN_EIER_EPIE (1 << 2) /* Error Passive Interrupt Enable */ ++#define RCAR_CAN_EIER_EWIE (1 << 1) /* Error Warning Interrupt Enable */ ++#define RCAR_CAN_EIER_BEIE (1 << 0) /* Bus Error Interrupt Enable */ ++ ++/* Error Interrupt Factor Judge Register bits */ ++#define RCAR_CAN_EIFR_BLIF (1 << 7) /* Bus Lock Detect Flag */ ++#define RCAR_CAN_EIFR_OLIF (1 << 6) /* Overload Frame Transmission */ ++ /* Detect Flag */ ++#define RCAR_CAN_EIFR_ORIF (1 << 5) /* Receive Overrun Detect Flag */ ++#define RCAR_CAN_EIFR_BORIF (1 << 4) /* Bus-Off Recovery Detect Flag */ ++#define RCAR_CAN_EIFR_BOEIF (1 << 3) /* Bus-Off Entry Detect Flag */ ++#define RCAR_CAN_EIFR_EPIF (1 << 2) /* Error Passive Detect Flag */ ++#define RCAR_CAN_EIFR_EWIF (1 << 1) /* Error Warning Detect Flag */ ++#define RCAR_CAN_EIFR_BEIF (1 << 0) /* Bus Error Detect Flag */ ++ ++/* Error Code Store Register bits */ ++#define RCAR_CAN_ECSR_EDPM (1 << 7) /* Error Display Mode Select Bit */ ++#define RCAR_CAN_ECSR_ADEF (1 << 6) /* ACK Delimiter Error Flag */ ++#define RCAR_CAN_ECSR_BE0F (1 << 5) /* Bit Error (dominant) Flag */ ++#define RCAR_CAN_ECSR_BE1F (1 << 4) /* Bit Error (recessive) Flag */ ++#define RCAR_CAN_ECSR_CEF (1 << 3) /* CRC Error Flag */ ++#define RCAR_CAN_ECSR_AEF (1 << 2) /* ACK Error Flag */ ++#define RCAR_CAN_ECSR_FEF (1 << 1) /* Form Error Flag */ ++#define RCAR_CAN_ECSR_SEF (1 << 0) /* Stuff Error Flag */ ++ ++#define RCAR_CAN_NAPI_WEIGHT 4 ++#define MAX_STR_READS 0x100 ++ ++static void tx_failure_cleanup(struct net_device *ndev) ++{ ++ int i; ++ ++ for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++) ++ can_free_echo_skb(ndev, i); ++} ++ ++static void rcar_can_error(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct can_frame *cf; ++ struct sk_buff *skb; ++ u8 eifr, txerr = 0, rxerr = 0; ++ ++ /* Propagate the error condition to the CAN stack */ ++ skb = alloc_can_err_skb(ndev, &cf); ++ ++ eifr = readb(&priv->regs->eifr); ++ if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) { ++ txerr = readb(&priv->regs->tecr); ++ rxerr = readb(&priv->regs->recr); ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[6] = txerr; ++ cf->data[7] = rxerr; ++ } ++ } ++ if (eifr & RCAR_CAN_EIFR_BEIF) { ++ int rx_errors = 0, tx_errors = 0; ++ u8 ecsr; ++ ++ netdev_dbg(priv->ndev, "Bus error interrupt:\n"); ++ if (skb) { ++ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_UNSPEC; ++ } ++ ecsr = readb(&priv->regs->ecsr); ++ if (ecsr & RCAR_CAN_ECSR_ADEF) { ++ netdev_dbg(priv->ndev, "ACK Delimiter Error\n"); ++ tx_errors++; ++ writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr); ++ if (skb) ++ cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL; ++ } ++ if (ecsr & RCAR_CAN_ECSR_BE0F) { ++ netdev_dbg(priv->ndev, "Bit Error (dominant)\n"); ++ tx_errors++; ++ writeb(~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr); ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_BIT0; ++ } ++ if (ecsr & RCAR_CAN_ECSR_BE1F) { ++ netdev_dbg(priv->ndev, "Bit Error (recessive)\n"); ++ tx_errors++; ++ writeb(~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr); ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_BIT1; ++ } ++ if (ecsr & RCAR_CAN_ECSR_CEF) { ++ netdev_dbg(priv->ndev, "CRC Error\n"); ++ rx_errors++; ++ writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); ++ if (skb) ++ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; ++ } ++ if (ecsr & RCAR_CAN_ECSR_AEF) { ++ netdev_dbg(priv->ndev, "ACK Error\n"); ++ tx_errors++; ++ writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); ++ if (skb) { ++ cf->can_id |= CAN_ERR_ACK; ++ cf->data[3] |= CAN_ERR_PROT_LOC_ACK; ++ } ++ } ++ if (ecsr & RCAR_CAN_ECSR_FEF) { ++ netdev_dbg(priv->ndev, "Form Error\n"); ++ rx_errors++; ++ writeb(~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr); ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ } ++ if (ecsr & RCAR_CAN_ECSR_SEF) { ++ netdev_dbg(priv->ndev, "Stuff Error\n"); ++ rx_errors++; ++ writeb(~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr); ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ } ++ ++ priv->can.can_stats.bus_error++; ++ ndev->stats.rx_errors += rx_errors; ++ ndev->stats.tx_errors += tx_errors; ++ writeb(~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr); ++ } ++ if (eifr & RCAR_CAN_EIFR_EWIF) { ++ netdev_dbg(priv->ndev, "Error warning interrupt\n"); ++ priv->can.state = CAN_STATE_ERROR_WARNING; ++ priv->can.can_stats.error_warning++; ++ /* Clear interrupt condition */ ++ writeb(~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr); ++ if (skb) ++ cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_WARNING : ++ CAN_ERR_CRTL_RX_WARNING; ++ } ++ if (eifr & RCAR_CAN_EIFR_EPIF) { ++ netdev_dbg(priv->ndev, "Error passive interrupt\n"); ++ priv->can.state = CAN_STATE_ERROR_PASSIVE; ++ priv->can.can_stats.error_passive++; ++ /* Clear interrupt condition */ ++ writeb(~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr); ++ if (skb) ++ cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_PASSIVE : ++ CAN_ERR_CRTL_RX_PASSIVE; ++ } ++ if (eifr & RCAR_CAN_EIFR_BOEIF) { ++ netdev_dbg(priv->ndev, "Bus-off entry interrupt\n"); ++ tx_failure_cleanup(ndev); ++ priv->ier = RCAR_CAN_IER_ERSIE; ++ writeb(priv->ier, &priv->regs->ier); ++ priv->can.state = CAN_STATE_BUS_OFF; ++ /* Clear interrupt condition */ ++ writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); ++ can_bus_off(ndev); ++ if (skb) ++ cf->can_id |= CAN_ERR_BUSOFF; ++ } ++ if (eifr & RCAR_CAN_EIFR_ORIF) { ++ netdev_dbg(priv->ndev, "Receive overrun error interrupt\n"); ++ ndev->stats.rx_over_errors++; ++ ndev->stats.rx_errors++; ++ writeb(~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr); ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; ++ } ++ } ++ if (eifr & RCAR_CAN_EIFR_OLIF) { ++ netdev_dbg(priv->ndev, ++ "Overload Frame Transmission error interrupt\n"); ++ ndev->stats.rx_over_errors++; ++ ndev->stats.rx_errors++; ++ writeb(~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr); ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] |= CAN_ERR_PROT_OVERLOAD; ++ } ++ } ++ ++ if (skb) { ++ stats->rx_packets++; ++ stats->rx_bytes += cf->can_dlc; ++ netif_rx(skb); ++ } ++} ++ ++static void rcar_can_tx_done(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ u8 isr; ++ ++ while (1) { ++ u8 unsent = readb(&priv->regs->tfcr); ++ ++ unsent = (unsent & RCAR_CAN_TFCR_TFUST) >> ++ RCAR_CAN_TFCR_TFUST_SHIFT; ++ if (priv->tx_head - priv->tx_tail <= unsent) ++ break; ++ stats->tx_packets++; ++ stats->tx_bytes += priv->tx_dlc[priv->tx_tail % ++ RCAR_CAN_FIFO_DEPTH]; ++ priv->tx_dlc[priv->tx_tail % RCAR_CAN_FIFO_DEPTH] = 0; ++ can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH); ++ priv->tx_tail++; ++ netif_wake_queue(ndev); ++ } ++ /* Clear interrupt */ ++ isr = readb(&priv->regs->isr); ++ writeb(isr & ~RCAR_CAN_ISR_TXFF, &priv->regs->isr); ++ can_led_event(ndev, CAN_LED_EVENT_TX); ++} ++ ++static irqreturn_t rcar_can_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *ndev = dev_id; ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ u8 isr; ++ ++ isr = readb(&priv->regs->isr); ++ if (!(isr & priv->ier)) ++ return IRQ_NONE; ++ ++ if (isr & RCAR_CAN_ISR_ERSF) ++ rcar_can_error(ndev); ++ ++ if (isr & RCAR_CAN_ISR_TXFF) ++ rcar_can_tx_done(ndev); ++ ++ if (isr & RCAR_CAN_ISR_RXFF) { ++ if (napi_schedule_prep(&priv->napi)) { ++ /* Disable Rx FIFO interrupts */ ++ priv->ier &= ~RCAR_CAN_IER_RXFIE; ++ writeb(priv->ier, &priv->regs->ier); ++ __napi_schedule(&priv->napi); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void rcar_can_set_bittiming(struct net_device *dev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(dev); ++ struct can_bittiming *bt = &priv->can.bittiming; ++ u32 bcr; ++ ++ bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) | ++ RCAR_CAN_BCR_BPR(bt->brp - 1) | RCAR_CAN_BCR_SJW(bt->sjw - 1) | ++ RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1); ++ /* Don't overwrite CLKR with 32-bit BCR access; CLKR has 8-bit access. ++ * All the registers are big-endian but they get byte-swapped on 32-bit ++ * read/write (but not on 8-bit, contrary to the manuals)... ++ */ ++ writel((bcr << 8) | priv->clock_select, &priv->regs->bcr); ++} ++ ++static void rcar_can_start(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ u16 ctlr; ++ int i; ++ ++ /* Set controller to known mode: ++ * - FIFO mailbox mode ++ * - accept all messages ++ * - overrun mode ++ * CAN is in sleep mode after MCU hardware or software reset. ++ */ ++ ctlr = readw(&priv->regs->ctlr); ++ ctlr &= ~RCAR_CAN_CTLR_SLPM; ++ writew(ctlr, &priv->regs->ctlr); ++ /* Go to reset mode */ ++ ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; ++ writew(ctlr, &priv->regs->ctlr); ++ for (i = 0; i < MAX_STR_READS; i++) { ++ if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) ++ break; ++ } ++ rcar_can_set_bittiming(ndev); ++ ctlr |= RCAR_CAN_CTLR_IDFM_MIXED; /* Select mixed ID mode */ ++ ctlr |= RCAR_CAN_CTLR_BOM_ENT; /* Entry to halt mode automatically */ ++ /* at bus-off */ ++ ctlr |= RCAR_CAN_CTLR_MBM; /* Select FIFO mailbox mode */ ++ ctlr |= RCAR_CAN_CTLR_MLM; /* Overrun mode */ ++ writew(ctlr, &priv->regs->ctlr); ++ ++ /* Accept all SID and EID */ ++ writel(0, &priv->regs->mkr_2_9[6]); ++ writel(0, &priv->regs->mkr_2_9[7]); ++ /* In FIFO mailbox mode, write "0" to bits 24 to 31 */ ++ writel(0, &priv->regs->mkivlr1); ++ /* Accept all frames */ ++ writel(0, &priv->regs->fidcr[0]); ++ writel(RCAR_CAN_FIDCR_IDE | RCAR_CAN_FIDCR_RTR, &priv->regs->fidcr[1]); ++ /* Enable and configure FIFO mailbox interrupts */ ++ writel(RCAR_CAN_MIER1_RXFIE | RCAR_CAN_MIER1_TXFIE, &priv->regs->mier1); ++ ++ priv->ier = RCAR_CAN_IER_ERSIE | RCAR_CAN_IER_RXFIE | ++ RCAR_CAN_IER_TXFIE; ++ writeb(priv->ier, &priv->regs->ier); ++ ++ /* Accumulate error codes */ ++ writeb(RCAR_CAN_ECSR_EDPM, &priv->regs->ecsr); ++ /* Enable error interrupts */ ++ writeb(RCAR_CAN_EIER_EWIE | RCAR_CAN_EIER_EPIE | RCAR_CAN_EIER_BOEIE | ++ (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING ? ++ RCAR_CAN_EIER_BEIE : 0) | RCAR_CAN_EIER_ORIE | ++ RCAR_CAN_EIER_OLIE, &priv->regs->eier); ++ priv->can.state = CAN_STATE_ERROR_ACTIVE; ++ ++ /* Go to operation mode */ ++ writew(ctlr & ~RCAR_CAN_CTLR_CANM, &priv->regs->ctlr); ++ for (i = 0; i < MAX_STR_READS; i++) { ++ if (!(readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)) ++ break; ++ } ++ /* Enable Rx and Tx FIFO */ ++ writeb(RCAR_CAN_RFCR_RFE, &priv->regs->rfcr); ++ writeb(RCAR_CAN_TFCR_TFE, &priv->regs->tfcr); ++} ++ ++static int rcar_can_open(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ int err; ++ ++ err = clk_prepare_enable(priv->clk); ++ if (err) { ++ netdev_err(ndev, "clk_prepare_enable() failed, error %d\n", ++ err); ++ goto out; ++ } ++ err = open_candev(ndev); ++ if (err) { ++ netdev_err(ndev, "open_candev() failed, error %d\n", err); ++ goto out_clock; ++ } ++ napi_enable(&priv->napi); ++ err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); ++ if (err) { ++ netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq); ++ goto out_close; ++ } ++ can_led_event(ndev, CAN_LED_EVENT_OPEN); ++ rcar_can_start(ndev); ++ netif_start_queue(ndev); ++ return 0; ++out_close: ++ napi_disable(&priv->napi); ++ close_candev(ndev); ++out_clock: ++ clk_disable_unprepare(priv->clk); ++out: ++ return err; ++} ++ ++static void rcar_can_stop(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ u16 ctlr; ++ int i; ++ ++ /* Go to (force) reset mode */ ++ ctlr = readw(&priv->regs->ctlr); ++ ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET; ++ writew(ctlr, &priv->regs->ctlr); ++ for (i = 0; i < MAX_STR_READS; i++) { ++ if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST) ++ break; ++ } ++ writel(0, &priv->regs->mier0); ++ writel(0, &priv->regs->mier1); ++ writeb(0, &priv->regs->ier); ++ writeb(0, &priv->regs->eier); ++ /* Go to sleep mode */ ++ ctlr |= RCAR_CAN_CTLR_SLPM; ++ writew(ctlr, &priv->regs->ctlr); ++ priv->can.state = CAN_STATE_STOPPED; ++} ++ ++static int rcar_can_close(struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ ++ netif_stop_queue(ndev); ++ rcar_can_stop(ndev); ++ free_irq(ndev->irq, ndev); ++ napi_disable(&priv->napi); ++ clk_disable_unprepare(priv->clk); ++ close_candev(ndev); ++ can_led_event(ndev, CAN_LED_EVENT_STOP); ++ return 0; ++} ++ ++static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) ++{ ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ struct can_frame *cf = (struct can_frame *)skb->data; ++ u32 data, i; ++ ++ if (can_dropped_invalid_skb(ndev, skb)) ++ return NETDEV_TX_OK; ++ ++ if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ ++ data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE; ++ else /* Standard frame format */ ++ data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT; ++ ++ if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */ ++ data |= RCAR_CAN_RTR; ++ } else { ++ for (i = 0; i < cf->can_dlc; i++) ++ writeb(cf->data[i], ++ &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].data[i]); ++ } ++ ++ writel(data, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].id); ++ ++ writeb(cf->can_dlc, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc); ++ ++ priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->can_dlc; ++ can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH); ++ priv->tx_head++; ++ /* Start Tx: write 0xff to the TFPCR register to increment ++ * the CPU-side pointer for the transmit FIFO to the next ++ * mailbox location ++ */ ++ writeb(0xff, &priv->regs->tfpcr); ++ /* Stop the queue if we've filled all FIFO entries */ ++ if (priv->tx_head - priv->tx_tail >= RCAR_CAN_FIFO_DEPTH) ++ netif_stop_queue(ndev); ++ ++ return NETDEV_TX_OK; ++} ++ ++static const struct net_device_ops rcar_can_netdev_ops = { ++ .ndo_open = rcar_can_open, ++ .ndo_stop = rcar_can_close, ++ .ndo_start_xmit = rcar_can_start_xmit, ++}; ++ ++static void rcar_can_rx_pkt(struct rcar_can_priv *priv) ++{ ++ struct net_device_stats *stats = &priv->ndev->stats; ++ struct can_frame *cf; ++ struct sk_buff *skb; ++ u32 data; ++ u8 dlc; ++ ++ skb = alloc_can_skb(priv->ndev, &cf); ++ if (!skb) { ++ stats->rx_dropped++; ++ return; ++ } ++ ++ data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id); ++ if (data & RCAR_CAN_IDE) ++ cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; ++ else ++ cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK; ++ ++ dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc); ++ cf->can_dlc = get_can_dlc(dlc); ++ if (data & RCAR_CAN_RTR) { ++ cf->can_id |= CAN_RTR_FLAG; ++ } else { ++ for (dlc = 0; dlc < cf->can_dlc; dlc++) ++ cf->data[dlc] = ++ readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]); ++ } ++ ++ can_led_event(priv->ndev, CAN_LED_EVENT_RX); ++ ++ stats->rx_bytes += cf->can_dlc; ++ stats->rx_packets++; ++ netif_receive_skb(skb); ++} ++ ++static int rcar_can_rx_poll(struct napi_struct *napi, int quota) ++{ ++ struct rcar_can_priv *priv = container_of(napi, ++ struct rcar_can_priv, napi); ++ int num_pkts; ++ ++ for (num_pkts = 0; num_pkts < quota; num_pkts++) { ++ u8 rfcr, isr; ++ ++ isr = readb(&priv->regs->isr); ++ /* Clear interrupt bit */ ++ if (isr & RCAR_CAN_ISR_RXFF) ++ writeb(isr & ~RCAR_CAN_ISR_RXFF, &priv->regs->isr); ++ rfcr = readb(&priv->regs->rfcr); ++ if (rfcr & RCAR_CAN_RFCR_RFEST) ++ break; ++ rcar_can_rx_pkt(priv); ++ /* Write 0xff to the RFPCR register to increment ++ * the CPU-side pointer for the receive FIFO ++ * to the next mailbox location ++ */ ++ writeb(0xff, &priv->regs->rfpcr); ++ } ++ /* All packets processed */ ++ if (num_pkts < quota) { ++ napi_complete(napi); ++ priv->ier |= RCAR_CAN_IER_RXFIE; ++ writeb(priv->ier, &priv->regs->ier); ++ } ++ return num_pkts; ++} ++ ++static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode) ++{ ++ switch (mode) { ++ case CAN_MODE_START: ++ rcar_can_start(ndev); ++ netif_wake_queue(ndev); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int rcar_can_get_berr_counter(const struct net_device *dev, ++ struct can_berr_counter *bec) ++{ ++ struct rcar_can_priv *priv = netdev_priv(dev); ++ int err; ++ ++ err = clk_prepare_enable(priv->clk); ++ if (err) ++ return err; ++ bec->txerr = readb(&priv->regs->tecr); ++ bec->rxerr = readb(&priv->regs->recr); ++ clk_disable_unprepare(priv->clk); ++ return 0; ++} ++ ++static int rcar_can_probe(struct platform_device *pdev) ++{ ++ struct rcar_can_platform_data *pdata; ++ struct rcar_can_priv *priv; ++ struct net_device *ndev; ++ struct resource *mem; ++ void __iomem *addr; ++ int err = -ENODEV; ++ int irq; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++ if (!pdata) { ++ dev_err(&pdev->dev, "No platform data provided!\n"); ++ goto fail; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (!irq) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ goto fail; ++ } ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ addr = devm_ioremap_resource(&pdev->dev, mem); ++ if (IS_ERR(addr)) { ++ err = PTR_ERR(addr); ++ goto fail; ++ } ++ ++ ndev = alloc_candev(sizeof(struct rcar_can_priv), RCAR_CAN_FIFO_DEPTH); ++ if (!ndev) { ++ dev_err(&pdev->dev, "alloc_candev() failed\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ priv = netdev_priv(ndev); ++ ++ priv->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ err = PTR_ERR(priv->clk); ++ dev_err(&pdev->dev, "cannot get clock: %d\n", err); ++ goto fail_clk; ++ } ++ ++ ndev->netdev_ops = &rcar_can_netdev_ops; ++ ndev->irq = irq; ++ ndev->flags |= IFF_ECHO; ++ priv->ndev = ndev; ++ priv->regs = addr; ++ priv->clock_select = pdata->clock_select; ++ priv->can.clock.freq = clk_get_rate(priv->clk); ++ priv->can.bittiming_const = &rcar_can_bittiming_const; ++ priv->can.do_set_mode = rcar_can_do_set_mode; ++ priv->can.do_get_berr_counter = rcar_can_get_berr_counter; ++ priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING; ++ platform_set_drvdata(pdev, ndev); ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ++ netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll, ++ RCAR_CAN_NAPI_WEIGHT); ++ err = register_candev(ndev); ++ if (err) { ++ dev_err(&pdev->dev, "register_candev() failed, error %d\n", ++ err); ++ goto fail_candev; ++ } ++ ++ devm_can_led_init(ndev); ++ ++ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", ++ priv->regs, ndev->irq); ++ ++ return 0; ++fail_candev: ++ netif_napi_del(&priv->napi); ++fail_clk: ++ free_candev(ndev); ++fail: ++ return err; ++} ++ ++static int rcar_can_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ ++ unregister_candev(ndev); ++ netif_napi_del(&priv->napi); ++ free_candev(ndev); ++ return 0; ++} ++ ++static int __maybe_unused rcar_can_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ u16 ctlr; ++ ++ if (netif_running(ndev)) { ++ netif_stop_queue(ndev); ++ netif_device_detach(ndev); ++ } ++ ctlr = readw(&priv->regs->ctlr); ++ ctlr |= RCAR_CAN_CTLR_CANM_HALT; ++ writew(ctlr, &priv->regs->ctlr); ++ ctlr |= RCAR_CAN_CTLR_SLPM; ++ writew(ctlr, &priv->regs->ctlr); ++ priv->can.state = CAN_STATE_SLEEPING; ++ ++ clk_disable(priv->clk); ++ return 0; ++} ++ ++static int __maybe_unused rcar_can_resume(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct rcar_can_priv *priv = netdev_priv(ndev); ++ u16 ctlr; ++ int err; ++ ++ err = clk_enable(priv->clk); ++ if (err) { ++ netdev_err(ndev, "clk_enable() failed, error %d\n", err); ++ return err; ++ } ++ ++ ctlr = readw(&priv->regs->ctlr); ++ ctlr &= ~RCAR_CAN_CTLR_SLPM; ++ writew(ctlr, &priv->regs->ctlr); ++ ctlr &= ~RCAR_CAN_CTLR_CANM; ++ writew(ctlr, &priv->regs->ctlr); ++ priv->can.state = CAN_STATE_ERROR_ACTIVE; ++ ++ if (netif_running(ndev)) { ++ netif_device_attach(ndev); ++ netif_start_queue(ndev); ++ } ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume); ++ ++static struct platform_driver rcar_can_driver = { ++ .driver = { ++ .name = RCAR_CAN_DRV_NAME, ++ .owner = THIS_MODULE, ++ .pm = &rcar_can_pm_ops, ++ }, ++ .probe = rcar_can_probe, ++ .remove = rcar_can_remove, ++}; ++ ++module_platform_driver(rcar_can_driver); ++ ++MODULE_AUTHOR("Cogent Embedded, Inc."); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC"); ++MODULE_ALIAS("platform:" RCAR_CAN_DRV_NAME); +diff --git a/include/linux/can/platform/rcar_can.h b/include/linux/can/platform/rcar_can.h +new file mode 100644 +index 0000000..0f4a2f3 +--- /dev/null ++++ b/include/linux/can/platform/rcar_can.h +@@ -0,0 +1,17 @@ ++#ifndef _CAN_PLATFORM_RCAR_CAN_H_ ++#define _CAN_PLATFORM_RCAR_CAN_H_ ++ ++#include <linux/types.h> ++ ++/* Clock Select Register settings */ ++enum CLKR { ++ CLKR_CLKP1 = 0, /* Peripheral clock (clkp1) */ ++ CLKR_CLKP2 = 1, /* Peripheral clock (clkp2) */ ++ CLKR_CLKEXT = 3 /* Externally input clock */ ++}; ++ ++struct rcar_can_platform_data { ++ enum CLKR clock_select; /* Clock source select */ ++}; ++ ++#endif /* !_CAN_PLATFORM_RCAR_CAN_H_ */ +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0013-sh-pfc-r8a7791-add-CAN-pin-groups.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0013-sh-pfc-r8a7791-add-CAN-pin-groups.patch new file mode 100644 index 0000000..23e74c7 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0013-sh-pfc-r8a7791-add-CAN-pin-groups.patch @@ -0,0 +1,216 @@ +From 0e9386752758b74fd42fda7cbdd6ccb5cb31033c Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Wed, 2 Jul 2014 00:58:16 +0400 +Subject: [PATCH] sh-pfc: r8a7791: add CAN pin groups + +Add CAN0/1 data/clock pin groups to R8A7791 PFC driver. + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 167 +++++++++++++++++++++++++++++++++++ + 1 file changed, 167 insertions(+) + +diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +index 394b234..576d41b 100644 +--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c ++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +@@ -1726,6 +1726,133 @@ static const unsigned int audio_clkout_mux[] = { + AUDIO_CLKOUT_MARK, + }; + ++/* - CAN -------------------------------------------------------------------- */ ++ ++static const unsigned int can0_data_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(3, 26), RCAR_GP_PIN(3, 29), ++}; ++ ++static const unsigned int can0_data_mux[] = { ++ CAN0_TX_MARK, CAN0_RX_MARK, ++}; ++ ++static const unsigned int can0_data_b_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(7, 4), RCAR_GP_PIN(7, 3), ++}; ++ ++static const unsigned int can0_data_b_mux[] = { ++ CAN0_TX_B_MARK, CAN0_RX_B_MARK, ++}; ++ ++static const unsigned int can0_data_c_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(5, 17), RCAR_GP_PIN(5, 18), ++}; ++ ++static const unsigned int can0_data_c_mux[] = { ++ CAN0_TX_C_MARK, CAN0_RX_C_MARK, ++}; ++ ++static const unsigned int can0_data_d_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(2, 26), RCAR_GP_PIN(2, 27), ++}; ++ ++static const unsigned int can0_data_d_mux[] = { ++ CAN0_TX_D_MARK, CAN0_RX_D_MARK, ++}; ++ ++static const unsigned int can0_data_e_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(4, 18), RCAR_GP_PIN(4, 28), ++}; ++ ++static const unsigned int can0_data_e_mux[] = { ++ CAN0_TX_E_MARK, CAN0_RX_E_MARK, ++}; ++ ++static const unsigned int can0_data_f_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6), ++}; ++ ++static const unsigned int can0_data_f_mux[] = { ++ CAN0_TX_F_MARK, CAN0_RX_F_MARK, ++}; ++ ++static const unsigned int can1_data_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(3, 21), RCAR_GP_PIN(3, 20), ++}; ++ ++static const unsigned int can1_data_mux[] = { ++ CAN1_TX_MARK, CAN1_RX_MARK, ++}; ++ ++static const unsigned int can1_data_b_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 9), ++}; ++ ++static const unsigned int can1_data_b_mux[] = { ++ CAN1_TX_B_MARK, CAN1_RX_B_MARK, ++}; ++ ++static const unsigned int can1_data_c_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 19), ++}; ++ ++static const unsigned int can1_data_c_mux[] = { ++ CAN1_TX_C_MARK, CAN1_RX_C_MARK, ++}; ++ ++static const unsigned int can1_data_d_pins[] = { ++ /* TX, RX */ ++ RCAR_GP_PIN(4, 29), RCAR_GP_PIN(4, 31), ++}; ++ ++static const unsigned int can1_data_d_mux[] = { ++ CAN1_TX_D_MARK, CAN1_RX_D_MARK, ++}; ++ ++static const unsigned int can_clk_pins[] = { ++ /* CLK */ ++ RCAR_GP_PIN(7, 2), ++}; ++ ++static const unsigned int can_clk_mux[] = { ++ CAN_CLK_MARK, ++}; ++ ++static const unsigned int can_clk_b_pins[] = { ++ /* CLK */ ++ RCAR_GP_PIN(5, 21), ++}; ++ ++static const unsigned int can_clk_b_mux[] = { ++ CAN_CLK_B_MARK, ++}; ++ ++static const unsigned int can_clk_c_pins[] = { ++ /* CLK */ ++ RCAR_GP_PIN(4, 30), ++}; ++ ++static const unsigned int can_clk_c_mux[] = { ++ CAN_CLK_C_MARK, ++}; ++ ++static const unsigned int can_clk_d_pins[] = { ++ /* CLK */ ++ RCAR_GP_PIN(7, 19), ++}; ++ ++static const unsigned int can_clk_d_mux[] = { ++ CAN_CLK_D_MARK, ++}; + + /* - DU --------------------------------------------------------------------- */ + static const unsigned int du_rgb666_pins[] = { +@@ -4055,6 +4182,20 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(audio_clk_b_b), + SH_PFC_PIN_GROUP(audio_clk_c), + SH_PFC_PIN_GROUP(audio_clkout), ++ SH_PFC_PIN_GROUP(can0_data), ++ SH_PFC_PIN_GROUP(can0_data_b), ++ SH_PFC_PIN_GROUP(can0_data_c), ++ SH_PFC_PIN_GROUP(can0_data_d), ++ SH_PFC_PIN_GROUP(can0_data_e), ++ SH_PFC_PIN_GROUP(can0_data_f), ++ SH_PFC_PIN_GROUP(can1_data), ++ SH_PFC_PIN_GROUP(can1_data_b), ++ SH_PFC_PIN_GROUP(can1_data_c), ++ SH_PFC_PIN_GROUP(can1_data_d), ++ SH_PFC_PIN_GROUP(can_clk), ++ SH_PFC_PIN_GROUP(can_clk_b), ++ SH_PFC_PIN_GROUP(can_clk_c), ++ SH_PFC_PIN_GROUP(can_clk_d), + SH_PFC_PIN_GROUP(du_rgb666), + SH_PFC_PIN_GROUP(du_rgb888), + SH_PFC_PIN_GROUP(du_clk_out_0), +@@ -4367,6 +4508,30 @@ static const char * const audio_clk_groups[] = { + "audio_clkout", + }; + ++static const char * const can0_groups[] = { ++ "can0_data_a", ++ "can0_data_b", ++ "can0_data_c", ++ "can0_data_d", ++ "can0_data_e", ++ "can0_data_f", ++ "can_clk_a", ++ "can_clk_b", ++ "can_clk_c", ++ "can_clk_d", ++}; ++ ++static const char * const can1_groups[] = { ++ "can1_data_a", ++ "can1_data_b", ++ "can1_data_c", ++ "can1_data_d", ++ "can_clk_a", ++ "can_clk_b", ++ "can_clk_c", ++ "can_clk_d", ++}; ++ + static const char * const du_groups[] = { + "du_rgb666", + "du_rgb888", +@@ -4790,6 +4955,8 @@ static const char * const vin2_groups[] = { + + static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(audio_clk), ++ SH_PFC_FUNCTION(can0), ++ SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(du0), + SH_PFC_FUNCTION(du1), +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0014-sh-pfc-r8a7791-fix-CAN-pin-groups.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0014-sh-pfc-r8a7791-fix-CAN-pin-groups.patch new file mode 100644 index 0000000..65b0fcd --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0014-sh-pfc-r8a7791-fix-CAN-pin-groups.patch @@ -0,0 +1,52 @@ +From 302fb1781783ded370f515e8e649b8285ee29cdc Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Tue, 29 Jul 2014 02:12:55 +0400 +Subject: [PATCH] sh-pfc: r8a7791: fix CAN pin groups + +I had made last-minute changes before submitting the patch "sh-pfc: r8a7791: +add CAN pin groups"; now I'm seeing that they weren't complete: I had missed +update to the pin group names in pin[01]_groups[]. Drop the "_a" suffixes there. + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +index 576d41b..c6e5deb 100644 +--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c ++++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +@@ -4509,24 +4509,24 @@ static const char * const audio_clk_groups[] = { + }; + + static const char * const can0_groups[] = { +- "can0_data_a", ++ "can0_data", + "can0_data_b", + "can0_data_c", + "can0_data_d", + "can0_data_e", + "can0_data_f", +- "can_clk_a", ++ "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", + }; + + static const char * const can1_groups[] = { +- "can1_data_a", ++ "can1_data", + "can1_data_b", + "can1_data_c", + "can1_data_d", +- "can_clk_a", ++ "can_clk", + "can_clk_b", + "can_clk_c", + "can_clk_d", +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch new file mode 100644 index 0000000..65f33af --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch @@ -0,0 +1,139 @@ +From 862e2b6af9413b43ef044979b934cab07bfd33e5 Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Fri, 1 Aug 2014 01:23:32 +0400 +Subject: [PATCH] can: rcar_can: support all input clocks + +When writing the driver, I didn't give enough attention to the possible sources +of the CAN clock: although the value of the CLKR register was specified by the +platform data, the driver only handled one case, that is CAN clock being +sourced from the clkp1 clock, the same that clocks the whole CAN module. In +order to fix that overlook, we'll have to handle the CAN clock separately from +the peripheral clock (however, clkp1 will be specified for a CAN device only +once)... + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +--- + drivers/net/can/rcar_can.c | 42 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 36 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c +index 5268d21..c02fcf3 100644 +--- a/drivers/net/can/rcar_can.c ++++ b/drivers/net/can/rcar_can.c +@@ -87,6 +87,7 @@ struct rcar_can_priv { + struct napi_struct napi; + struct rcar_can_regs __iomem *regs; + struct clk *clk; ++ struct clk *can_clk; + u8 tx_dlc[RCAR_CAN_FIFO_DEPTH]; + u32 tx_head; + u32 tx_tail; +@@ -505,14 +506,20 @@ static int rcar_can_open(struct net_device *ndev) + + err = clk_prepare_enable(priv->clk); + if (err) { +- netdev_err(ndev, "clk_prepare_enable() failed, error %d\n", ++ netdev_err(ndev, "failed to enable periperal clock, error %d\n", + err); + goto out; + } ++ err = clk_prepare_enable(priv->can_clk); ++ if (err) { ++ netdev_err(ndev, "failed to enable CAN clock, error %d\n", ++ err); ++ goto out_clock; ++ } + err = open_candev(ndev); + if (err) { + netdev_err(ndev, "open_candev() failed, error %d\n", err); +- goto out_clock; ++ goto out_can_clock; + } + napi_enable(&priv->napi); + err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); +@@ -527,6 +534,8 @@ static int rcar_can_open(struct net_device *ndev) + out_close: + napi_disable(&priv->napi); + close_candev(ndev); ++out_can_clock: ++ clk_disable_unprepare(priv->can_clk); + out_clock: + clk_disable_unprepare(priv->clk); + out: +@@ -565,6 +574,7 @@ static int rcar_can_close(struct net_device *ndev) + rcar_can_stop(ndev); + free_irq(ndev->irq, ndev); + napi_disable(&priv->napi); ++ clk_disable_unprepare(priv->can_clk); + clk_disable_unprepare(priv->clk); + close_candev(ndev); + can_led_event(ndev, CAN_LED_EVENT_STOP); +@@ -715,6 +725,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev, + return 0; + } + ++static const char * const clock_names[] = { ++ [CLKR_CLKP1] = "clkp1", ++ [CLKR_CLKP2] = "clkp2", ++ [CLKR_CLKEXT] = "can_clk", ++}; ++ + static int rcar_can_probe(struct platform_device *pdev) + { + struct rcar_can_platform_data *pdata; +@@ -722,6 +738,7 @@ static int rcar_can_probe(struct platform_device *pdev) + struct net_device *ndev; + struct resource *mem; + void __iomem *addr; ++ u32 clock_select; + int err = -ENODEV; + int irq; + +@@ -730,6 +747,7 @@ static int rcar_can_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "No platform data provided!\n"); + goto fail; + } ++ clock_select = pdata->clock_select; + + irq = platform_get_irq(pdev, 0); + if (!irq) { +@@ -753,10 +771,22 @@ static int rcar_can_probe(struct platform_device *pdev) + + priv = netdev_priv(ndev); + +- priv->clk = devm_clk_get(&pdev->dev, NULL); ++ priv->clk = devm_clk_get(&pdev->dev, "clkp1"); + if (IS_ERR(priv->clk)) { + err = PTR_ERR(priv->clk); +- dev_err(&pdev->dev, "cannot get clock: %d\n", err); ++ dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err); ++ goto fail_clk; ++ } ++ ++ if (clock_select >= ARRAY_SIZE(clock_names)) { ++ err = -EINVAL; ++ dev_err(&pdev->dev, "invalid CAN clock selected\n"); ++ goto fail_clk; ++ } ++ priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]); ++ if (IS_ERR(priv->can_clk)) { ++ err = PTR_ERR(priv->can_clk); ++ dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err); + goto fail_clk; + } + +@@ -765,8 +795,8 @@ static int rcar_can_probe(struct platform_device *pdev) + ndev->flags |= IFF_ECHO; + priv->ndev = ndev; + priv->regs = addr; +- priv->clock_select = pdata->clock_select; +- priv->can.clock.freq = clk_get_rate(priv->clk); ++ priv->clock_select = clock_select; ++ priv->can.clock.freq = clk_get_rate(priv->can_clk); + priv->can.bittiming_const = &rcar_can_bittiming_const; + priv->can.do_set_mode = rcar_can_do_set_mode; + priv->can.do_get_berr_counter = rcar_can_get_berr_counter; +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0016-can-rcar_can-document-device-tree-bindings.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0016-can-rcar_can-document-device-tree-bindings.patch new file mode 100644 index 0000000..df8137f --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0016-can-rcar_can-document-device-tree-bindings.patch @@ -0,0 +1,66 @@ +From 632e25ca722e5361a1b40d89e77808f8f1c6799f Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Fri, 1 Aug 2014 01:24:25 +0400 +Subject: [PATCH] can: rcar_can: document device tree bindings + +Document the R-Car CAN device tree bindings. + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +--- + .../devicetree/bindings/net/can/rcar_can.txt | 43 ++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/can/rcar_can.txt + +diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt +new file mode 100644 +index 0000000..002d844 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/can/rcar_can.txt +@@ -0,0 +1,43 @@ ++Renesas R-Car CAN controller Device Tree Bindings ++------------------------------------------------- ++ ++Required properties: ++- compatible: "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. ++ "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. ++ "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC. ++ "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC. ++- reg: physical base address and size of the R-Car CAN register map. ++- interrupts: interrupt specifier for the sole interrupt. ++- clocks: phandles and clock specifiers for 3 CAN clock inputs. ++- clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk". ++- pinctrl-0: pin control group to be used for this controller. ++- pinctrl-names: must be "default". ++ ++Optional properties: ++- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are: ++ <0x0> (default) : Peripheral clock (clkp1) ++ <0x1> : Peripheral clock (clkp2) ++ <0x3> : Externally input clock ++ ++Example ++------- ++ ++SoC common .dtsi file: ++ ++ can0: can@e6e80000 { ++ compatible = "renesas,can-r8a7791"; ++ reg = <0 0xe6e80000 0 0x1000>; ++ interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&mstp9_clks R8A7791_CLK_RCAN0>, ++ <&cpg_clocks R8A7791_CLK_RCAN>, <&can_clk>; ++ clock-names = "clkp1", "clkp2", "can_clk"; ++ status = "disabled"; ++ }; ++ ++Board specific .dts file: ++ ++&can0 { ++ pinctrl-0 = <&can0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0017-can-rcar_can-add-device-tree-support.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0017-can-rcar_can-add-device-tree-support.patch new file mode 100644 index 0000000..716bdbc --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0017-can-rcar_can-add-device-tree-support.patch @@ -0,0 +1,77 @@ +From a268de6c68e4933234e9ac62f2ab7ff8264ce0b4 Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Fri, 1 Aug 2014 01:25:53 +0400 +Subject: [PATCH] can: rcar_can: add device tree support + +Add support of the device tree probing for the Renesas R-Car CAN controllers. + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +--- + drivers/net/can/rcar_can.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c +index c02fcf3..1abe133 100644 +--- a/drivers/net/can/rcar_can.c ++++ b/drivers/net/can/rcar_can.c +@@ -20,6 +20,7 @@ + #include <linux/can/dev.h> + #include <linux/clk.h> + #include <linux/can/platform/rcar_can.h> ++#include <linux/of.h> + + #define RCAR_CAN_DRV_NAME "rcar_can" + +@@ -738,16 +739,21 @@ static int rcar_can_probe(struct platform_device *pdev) + struct net_device *ndev; + struct resource *mem; + void __iomem *addr; +- u32 clock_select; ++ u32 clock_select = CLKR_CLKP1; + int err = -ENODEV; + int irq; + +- pdata = dev_get_platdata(&pdev->dev); +- if (!pdata) { +- dev_err(&pdev->dev, "No platform data provided!\n"); +- goto fail; ++ if (pdev->dev.of_node) { ++ of_property_read_u32(pdev->dev.of_node, ++ "renesas,can-clock-select", &clock_select); ++ } else { ++ pdata = dev_get_platdata(&pdev->dev); ++ if (!pdata) { ++ dev_err(&pdev->dev, "No platform data provided!\n"); ++ goto fail; ++ } ++ clock_select = pdata->clock_select; + } +- clock_select = pdata->clock_select; + + irq = platform_get_irq(pdev, 0); + if (!irq) { +@@ -888,10 +894,20 @@ static int __maybe_unused rcar_can_resume(struct device *dev) + + static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume); + ++static const struct of_device_id rcar_can_of_table[] __maybe_unused = { ++ { .compatible = "renesas,can-r8a7778" }, ++ { .compatible = "renesas,can-r8a7779" }, ++ { .compatible = "renesas,can-r8a7790" }, ++ { .compatible = "renesas,can-r8a7791" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rcar_can_of_table); ++ + static struct platform_driver rcar_can_driver = { + .driver = { + .name = RCAR_CAN_DRV_NAME, + .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(rcar_can_of_table), + .pm = &rcar_can_pm_ops, + }, + .probe = rcar_can_probe, +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0018-porter-can-support.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0018-porter-can-support.patch new file mode 100644 index 0000000..e56bda3 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0018-porter-can-support.patch @@ -0,0 +1,63 @@ +From b73784d861cfff9651936b3d101b1a91ca3550a8 Mon Sep 17 00:00:00 2001 +From: Andrey Dolnikov <andrey.dolnikov@cogentembedded.com> +Date: Wed, 25 Feb 2015 15:17:46 +0300 +Subject: [PATCH] Porter: Add CAN support. + +--- + arch/arm/boot/dts/r8a7791-porter.dts | 12 ++++++++++++ + arch/arm/boot/dts/r8a7791.dtsi | 9 +++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts +index 6a0ccde..4fb5cd5 100644 +--- a/arch/arm/boot/dts/r8a7791-porter.dts ++++ b/arch/arm/boot/dts/r8a7791-porter.dts +@@ -211,6 +211,11 @@ + renesas,groups = "vin0_data8", "vin0_clk"; + renesas,function = "vin0"; + }; ++ ++ can0_pins: can0 { ++ renesas,groups = "can0_data_b"; ++ renesas,function = "can0"; ++ }; + }; + + ðer { +@@ -229,6 +234,13 @@ + }; + }; + ++&can0 { ++ pinctrl-0 = <&can0_pins>; ++ pinctrl-names = "default"; ++ renesas,can-clock-select = <0x0>; ++ status = "okay"; ++}; ++ + &sata0 { + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi +index 799d41c..1cad41e 100644 +--- a/arch/arm/boot/dts/r8a7791.dtsi ++++ b/arch/arm/boot/dts/r8a7791.dtsi +@@ -533,6 +533,15 @@ + status = "disabled"; + }; + ++ can0: can@e6e80000 { ++ compatible = "renesas,can-r8a7791"; ++ reg = <0 0xe6e80000 0 0x1000>; ++ interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&mstp9_clks R8A7791_CLK_RCAN0>; ++ clock-names = "clkp1", "clkp2", "can_clk"; ++ status = "disabled"; ++ }; ++ + sata0: sata@ee300000 { + compatible = "renesas,sata-r8a7791"; + reg = <0 0xee300000 0 0x2000>; +-- +1.9.1 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0019-i2c-busses-rcar-Workaround-arbitration-loss-error.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0019-i2c-busses-rcar-Workaround-arbitration-loss-error.patch new file mode 100644 index 0000000..209d1b4 --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0019-i2c-busses-rcar-Workaround-arbitration-loss-error.patch @@ -0,0 +1,31 @@ +From 23fa8d125ca1be9c03ac7d2f42530a57d6ca28f2 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Tue, 3 Mar 2015 18:30:16 +0300 +Subject: [PATCH] i2c: busses: rcar: Workaround arbitration loss error + +Sometimes I2C master enable/disable at every transmission +causes arbitration loss errors making the bus unusable. +Workaround the issue by enabling I2C master +in the rcar_i2c_init() function. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/i2c/busses/i2c-rcar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c +index 0e863f3..4334006 100644 +--- a/drivers/i2c/busses/i2c-rcar.c ++++ b/drivers/i2c/busses/i2c-rcar.c +@@ -161,7 +161,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) + + /* reset master mode */ + rcar_i2c_write(priv, ICMIER, 0); +- rcar_i2c_write(priv, ICMCR, 0); ++ rcar_i2c_write(priv, ICMCR, MDBS | MIE); + rcar_i2c_write(priv, ICMSR, 0); + rcar_i2c_write(priv, ICMAR, 0); + } +-- +1.9.3 + diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0020-Silk-Remove-I2C1-clock-from-clk_enables.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0020-Silk-Remove-I2C1-clock-from-clk_enables.patch new file mode 100644 index 0000000..78a3a5b --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0020-Silk-Remove-I2C1-clock-from-clk_enables.patch @@ -0,0 +1,30 @@ +From 6c0691906b3bcce0a9629ca00faa6be88a013aaa Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Tue, 3 Mar 2015 18:25:15 +0300 +Subject: [PATCH] ARM: shmobile: silk: Remove I2C1 clock from clk_enables + array + +Remove I2C1 clock from clk_enables array since it is not needed. +I2C clocks are handled by the OF driver while shmobile_clk_workaround +is only needed for platform devices. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + arch/arm/mach-shmobile/board-silk-reference.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm/mach-shmobile/board-silk-reference.c b/arch/arm/mach-shmobile/board-silk-reference.c +index 090a4df..d4c64fa 100644 +--- a/arch/arm/mach-shmobile/board-silk-reference.c ++++ b/arch/arm/mach-shmobile/board-silk-reference.c +@@ -271,7 +271,6 @@ static const struct clk_name clk_names[] __initconst = { + */ + static const struct clk_name clk_enables[] __initconst = { + { "ether", NULL, "ee700000.ethernet" }, +- { "i2c1", NULL, "e6518000.i2c" }, + { "mmcif0", NULL, "ee200000.mmc" }, + { "sdhi0", NULL, "ee100000.sd" }, + { "sdhi1", NULL, "ee140000.sd" }, +-- +1.9.3 + |