Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH 13/14] ARM: configs: Add Milbeaut M10V defconfig
From: Sugaya Taichi @ 2018-11-19  1:02 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589336-13925-1-git-send-email-sugaya.taichi@socionext.com>

This patch adds the minimal defconfig for the Milbeaut M10V.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 arch/arm/configs/milbeaut_m10v_defconfig | 364 +++++++++++++++++++++++++++++++
 1 file changed, 364 insertions(+)
 create mode 100644 arch/arm/configs/milbeaut_m10v_defconfig

diff --git a/arch/arm/configs/milbeaut_m10v_defconfig b/arch/arm/configs/milbeaut_m10v_defconfig
new file mode 100644
index 0000000..90c22f8
--- /dev/null
+++ b/arch/arm/configs/milbeaut_m10v_defconfig
@@ -0,0 +1,364 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="mlbel"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ_FULL_ALL=y
+CONFIG_NO_HZ_FULL_SYSIDLE=y
+CONFIG_NO_HZ_FULL_SYSIDLE_SMALL=4
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_ARCH_MILBEAUT=y
+CONFIG_ARCH_MILBEAUT_M10V=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_775420=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_HOST_GENERIC is not set
+# CONFIG_PCIE_SN_DW_PLAT is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCIEAER is not set
+# CONFIG_PCIEASPM is not set
+CONFIG_SMP=y
+# CONFIG_ARM_CPU_TOPOLOGY is not set
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_HIGHMEM=y
+# CONFIG_COMPACTION is not set
+CONFIG_CMA=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_KEXEC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=m
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_NET_IPVTI=m
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_UDP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_IP_SCTP=m
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_TIPC=y
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_IPX=m
+CONFIG_NETLINK_MMAP=y
+CONFIG_NETLINK_DIAG=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_DEVELOPER_WARNINGS=y
+CONFIG_CFG80211_REG_DEBUG=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_MAC80211_LEDS=y
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_REGULATOR=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=16
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_CDN_HPNFC=y
+CONFIG_MTD_NAND_CDN_HPNFC_DT=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=3
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_MACVLAN=y
+CONFIG_TUN=y
+CONFIG_VETH=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_SOCIONEXT_OGMA=y
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_REALTEK_PHY=y
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_LEGACY_PTY_COUNT=4
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_M10V_USIO=y
+CONFIG_SERIAL_M10V_USIO_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_BOARDINFO is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_SNI_M10V is not set
+CONFIG_SPI=y
+# CONFIG_SPI_SN_USIO=y
+#CONFIG_SPI_SNI is not set
+#CONFIG_SPI_SPIDEV is not set
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_S6AP412=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_USB_GSPCA is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_PLATFORM=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VIDEO_VIVID=m
+CONFIG_VIDEO_VIVID_MAX_DEVS=64
+CONFIG_FB=y
+# CONFIG_VGA_ARB is not set
+# CONFIG_USB is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD_PCI is not set
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC3_PCI is not set
+# CONFIG_USB_DWC3_OTG is not set
+# CONFIG_USB_DWC3_SN is not set
+# CONFIG_USB_DWC3_OF_SIMPLE is not set
+# CONFIG_USB_GADGET_SN_LAP is not set
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_CONFIGFS_ACM is not set
+# CONFIG_USB_CONFIGFS_MASS_STORAGE is not set
+# CONFIG_USB_CONFIGFS_F_MTP is not set
+# CONFIG_USB_CONFIGFS_F_UVC is not set
+# CONFIG_USB_CONFIGFS_UEVENT is not set
+# CONFIG_MMC is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_SDHCI_F_SDH30 is not set
+# CONFIG_MMC_SDHCI_F_EMMC50 is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_SYSTOHC is not set
+CONFIG_RTC_DEBUG=y
+CONFIG_RTC_DRV_RX8025=y
+CONFIG_DMADEVICES=y
+CONFIG_MB86S7X_HDMAC=y
+CONFIG_MB8AC0300_XDMAC=y
+CONFIG_UIO=y
+CONFIG_UIO_SNI=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PWM=y
+# CONFIG_PWM_SYSFS is not set
+CONFIG_PWM_M10V=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_EXFAT=y
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_USE_FOR_EXT23 is not set
+# CONFIG_XFS_FS is not set
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=932
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_BOTH=y
+CONFIG_NFS_FS=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_MAC_ROMAN=y
+CONFIG_NLS_MAC_CELTIC=y
+CONFIG_NLS_MAC_CENTEURO=y
+CONFIG_NLS_MAC_CROATIAN=y
+CONFIG_NLS_MAC_CYRILLIC=y
+CONFIG_NLS_MAC_GAELIC=y
+CONFIG_NLS_MAC_GREEK=y
+CONFIG_NLS_MAC_ICELAND=y
+CONFIG_NLS_MAC_INUIT=y
+CONFIG_NLS_MAC_ROMANIAN=y
+CONFIG_NLS_MAC_TURKISH=y
+CONFIG_NLS_UTF8=y
+CONFIG_IPCU_FS=y
+# CONFIG_TEST_IPCU_FS is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+#CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_GIC_BL=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_KGDB=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_MILBEAUT_UART=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK_DIRECT is not set
+CONFIG_KEYS=y
+CONFIG_ENCRYPTED_KEYS=y
+CONFIG_SECURITY=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_FONTS=y
-- 
1.9.1

^ permalink raw reply related

* [PATCH 12/14] ARM: dts: milbeaut: Add device tree set for the Milbeaut M10V board
From: Sugaya Taichi @ 2018-11-19  1:02 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589336-13925-1-git-send-email-sugaya.taichi@socionext.com>

Add devicetree for Milbeaut M10V SoC and M10V Evaluation board.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 arch/arm/boot/dts/Makefile               |   1 +
 arch/arm/boot/dts/milbeaut-m10v-evb.dts  |  35 +++
 arch/arm/boot/dts/milbeaut-m10v-evb.dtsi |  17 ++
 arch/arm/boot/dts/milbeaut-m10v.dtsi     | 510 +++++++++++++++++++++++++++++++
 4 files changed, 563 insertions(+)
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v-evb.dts
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v-evb.dtsi
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b0e966d..ee6220b 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -1207,6 +1207,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
 	mt7623n-bananapi-bpi-r2.dtb \
 	mt8127-moose.dtb \
 	mt8135-evbp1.dtb
+dtb-$(CONFIG_MACH_M10V_EVB) += milbeaut-m10v-evb.dtb
 dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
 dtb-$(CONFIG_ARCH_ASPEED) += \
 	aspeed-ast2500-evb.dtb \
diff --git a/arch/arm/boot/dts/milbeaut-m10v-evb.dts b/arch/arm/boot/dts/milbeaut-m10v-evb.dts
new file mode 100644
index 0000000..af8d6e4
--- /dev/null
+++ b/arch/arm/boot/dts/milbeaut-m10v-evb.dts
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Socionext Milbeaut M10V Evaluation Board */
+/dts-v1/;
+#include "milbeaut-m10v-evb.dtsi"
+
+/ {
+	cpus {
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0xf00>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0xf01>;
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0xf02>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0xf03>;
+		};
+
+	};
+	trampoline: trampoline@0x0000F100 {
+		compatible = "socionext,smp-trampoline";
+		reg = <0x0000F100 0x100>;
+	};
+};
diff --git a/arch/arm/boot/dts/milbeaut-m10v-evb.dtsi b/arch/arm/boot/dts/milbeaut-m10v-evb.dtsi
new file mode 100644
index 0000000..fc35c0b
--- /dev/null
+++ b/arch/arm/boot/dts/milbeaut-m10v-evb.dtsi
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "milbeaut-m10v.dtsi"
+
+/ {
+	model = "Socionext M10V EVB";
+	compatible = "socionext,sc2000a", "socionext,milbeaut-m10v-evb";
+	interrupt-parent = <&gic>;
+	chosen {
+		bootargs = "consoleblank=0 loglevel=8 init=/sbin/finit root=/dev/mmcblk0p2 rootwait ro console=ttyUSI0,115200n8 console=/dev/tty1 ";
+		linux,initrd-start = <0x4A000000>;
+		linux,initrd-end =   <0x4BF00000>;
+	};
+	memory {
+		device_type = "memory";
+		reg = <0x40000000  0x80000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/milbeaut-m10v.dtsi b/arch/arm/boot/dts/milbeaut-m10v.dtsi
new file mode 100644
index 0000000..4745dc6
--- /dev/null
+++ b/arch/arm/boot/dts/milbeaut-m10v.dtsi
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "socionext,sc2000a";
+	interrupt-parent = <&gic>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+
+	gic: interrupt-controller@1d000000 {
+		compatible = "arm,cortex-a7-gic";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0x1d001000 0x1000>, /* Distributer base and size */
+		      <0x1d002000 0x1000>; /* CPU I/f base and size */
+	};
+
+	m10v-clk-tree@ {
+		compatible = "socionext,milbeaut-m10v-clk-regs";
+		reg = <0x1d021000 0x4000>;
+
+		clocks {
+			#address-cells = <0>;
+			#size-cells = <0>;
+
+			uclk40xi: uclk40xi {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <40000000>;
+			};
+
+			aumclki: aumclki {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <20000000>;
+			};
+
+			rtc32k: rtc32k {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <32768>;
+			};
+
+			pxrefclk: pxrefclk {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <100000000>;
+			};
+
+			pcisuppclk: pcisuppclk {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				clock-div = <20>;
+				clock-mult = <1>;
+			};
+
+			usb2_clk: usb2_clk {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			pll1: pll1 {
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <1>;
+				clock-div = <1>;
+				clock-mult = <40>;
+			};
+
+			pll2: pll2 {
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <2>;
+				clock-div = <1>;
+				clock-mult = <30>;
+			};
+
+			pll6: pll6 { /* CLK 6-1 */
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <7>;
+				clock-div = <1>;
+				clock-mult = <35>;
+			};
+
+			pll7: pll7 { /* CLK 7-1 */
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <8>;
+				clock-div = <1>;
+				clock-mult = <40>;
+			};
+
+			pll9: pll9 { /* CA7CLK, ATCLK */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				clock-div = <1>;
+				clock-mult = <33>;
+			};
+
+			pll10: pll10 {
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <10>;
+				clock-div = <5>;
+				clock-mult = <108>;
+			};
+
+			pll11: pll11 { /* CLK 11-1 */
+				compatible =
+				"socionext,milbeaut-m10v-pll-fixed-factor";
+				#clock-cells = <0>;
+				clocks = <&uclk40xi>;
+				offset = <12>;
+				clock-div = <2>;
+				clock-mult = <75>;
+			};
+
+			emmcclk: emmcclk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll11>;
+				offset = <28>; /* EMMCCLK */
+				mask = <0x3>;
+				ratios = <15 0x7 10 0x6 9 0x5 8 0x4>;
+			};
+
+			pll1_div_1_2: pll1_div_1_2 { /* CLK 1-2 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll1>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			pll2_div_1_2: pll2_div_1_2 { /* CLK 2-2 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll2>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			pll6_div_1_2: pll6_div_1_2 { /* CLK 6-2 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll6>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			pll6_div_1_3: pll6_div_1_3 { /* CLK 6-3 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll6>;
+				clock-div = <3>;
+				clock-mult = <1>;
+			};
+
+			pll7_div_1_2: pll7_div_1_2 { /* CLK 7-2 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll7>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			pll7_div_1_5: pll7_div_1_5 { /* CLK 7-5 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll7>;
+				clock-div = <5>;
+				clock-mult = <1>;
+			};
+
+			pll10_div_1_2: pll10_div_1_2 { /* CLK 10-2 */
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll10>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			spiclk_mux_0: spiclk_mux_0 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll10_div_1_2>;
+				offset = <227>; /* SPICLK */
+				mask = <0x3>;
+				ratios = <4 0x5 2 0x4>;
+			};
+
+			spiclk_mux_1: spiclk_mux_1 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7_div_1_2>;
+				offset = <227>; /* SPICLK */
+				mask = <0x3>;
+				ratios = <8 0x6>;
+			};
+
+			spiclk: spiclk {
+				compatible = "socionext,milbeaut-m10v-clk-mux";
+				#clock-cells = <0>;
+				clocks = <&spiclk_mux_0>, <&spiclk_mux_1>;
+			};
+
+			ca7wdclk: ca7wdclk {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll2_div_1_2>;
+				clock-div = <12>;
+				clock-mult = <1>;
+			};
+
+			pll9_div_1_2: pll9_div_1_2 {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll9>;
+				clock-div = <2>;
+				clock-mult = <1>;
+			};
+
+			mclk400: mclk400 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <295>; /* MCLK400 */
+				mask = <0x3>;
+				ratios = <4 0x7 2 0x5>;
+			};
+
+			mclk200: mclk200 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <291>; /* MCLK200 */
+				mask = <0x7>;
+				ratios = <8 0xf 4 0xb>;
+			};
+
+			aclk400: aclk400 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <288>; /* ACLK400 */
+				mask = <0x3>;
+				ratios = <4 0x7 2 0x5>;
+			};
+
+			aclk300: aclk300 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll2_div_1_2>;
+				offset = <352>; /* ACLK300 */
+				mask = <0x1>;
+				ratios = <6 0x3 4 0x2>;
+			};
+
+			aclk: aclk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <276>; /* ACLK */
+				mask = <0x7>;
+				ratios = <8 0xf 4 0xb>;
+			};
+
+			aclkexs: aclkexs {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <272>; /* ACLKEXS */
+				mask = <0x7>;
+				ratios = <8 0xf 6 0xd 5 0xc 4 0xb>;
+			};
+
+			hclk: hclk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <263>; /* HCLK */
+				mask = <0xf>;
+				ratios = <16 0x1f 8 0x17>;
+			};
+
+			hclkbmh: hclkbmh {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <268>; /* HCLKBMH */
+				mask = <0x7>;
+				ratios = <8 0xf 4 0xb>;
+			};
+
+			pclk: pclk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				offset = <256>; /* PCLK */
+				mask = <0x3f>;
+				ratios = <32 0x5f 16 0x4f>;
+			};
+
+			pclkca7wd: pclkca7wd {
+				compatible = "fixed-factor-clock";
+				#clock-cells = <0>;
+				clocks = <&pll1_div_1_2>;
+				clock-div = <16>;
+				clock-mult = <1>;
+			};
+
+			rclk: rclk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll10_div_1_2>;
+				offset = <0>; /* RCLK */
+				mask = <0x3>;
+				ratios = <64 0x7 48 0x6 32 0x5 16 0x4>;
+			};
+
+			uhs1clk0: uhs1clk0 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7>;
+				offset = <3>; /* UHS1CLK0 */
+				mask = <0xf>;
+				ratios = <16 0x14 8 0x13 4 0x12 3 0x11 2 0x10>;
+			};
+
+			uhs1clk1_div1: uhs1clk1_div1 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7>;
+				offset = <8>; /* UHS1CLK1 */
+				mask = <0xf>;
+				ratios = <16 0x14 8 0x13>;
+			};
+
+			uhs1clk1_div2: uhs1clk1_div2 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll6_div_1_2>;
+				offset = <8>; /* UHS1CLK1 */
+				mask = <0xf>;
+				ratios = <1 0x18>;
+			};
+
+			uhs1clk1: uhs1clk1 {
+				compatible = "socionext,milbeaut-m10v-clk-mux";
+				#clock-cells = <0>;
+				clocks = <&uhs1clk1_div1>, <&uhs1clk1_div2>;
+			};
+
+			uhs1clk2_div1: uhs1clk2_div1 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7>;
+				offset = <13>; /* UHS1CLK2 */
+				mask = <0xf>;
+				ratios = <16 0x14 8 0x13 4 0x12>;
+			};
+
+			uhs1clk2_div2: uhs1clk2_div2 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll6_div_1_2>;
+				offset = <13>; /* UHS1CLK2 */
+				mask = <0xf>;
+				ratios = <1 0x18>;
+			};
+
+			uhs1clk2: uhs1clk2 {
+				compatible = "socionext,milbeaut-m10v-clk-mux";
+				#clock-cells = <0>;
+				clocks = <&uhs1clk2_div1>, <&uhs1clk2_div2>;
+			};
+
+			uhs2clk: uhs2clk {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll6_div_1_3>;
+				offset = <18>; /* UHS2CLK */
+				mask = <0x7>;
+				ratios = <18 0xf 16 0xe 14 0xd 13 0xc
+						12 0xb 11 0xa 10 0x9 9 0x8>;
+			};
+
+			nfclk_div1: nfclk_div1 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7_div_1_2>;
+				offset = <22>; /* NFCLK */
+				mask = <0x1f>;
+				ratios = <40 0x24 16 0x23 13 0x22 10 0x21
+						8 0x20>;
+			};
+
+			nfclk_div2: nfclk_div2 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll7_div_1_5>;
+				offset = <22>; /* NFCLK */
+				mask = <0x1f>;
+				ratios = <10 0x28>;
+			};
+
+			nfclk: nfclk {
+				compatible = "socionext,milbeaut-m10v-clk-mux";
+				#clock-cells = <0>;
+				clocks = <&nfclk_div1>, <&nfclk_div2>;
+			};
+
+			clk5: clk5 {
+				compatible = "socionext,milbeaut-m10v-clk-div";
+				#clock-cells = <0>;
+				clocks = <&pll10_div_1_2>;
+				offset = <239>; /* NETAUSEL */
+				mask = <0x3>;
+				ratios = <64 0x7 48 0x6 32 0x5 16 0x4>;
+			};
+		};
+	};
+
+	peri-timer@1e000000 { /* 32-bit Reload Timers */
+		compatible = "socionext,milbeaut-m10v-timer";
+		reg = <0x1e000050 0x10>, <0x1e000060 0x10>;
+		interrupts = <0 91 4>;
+		clocks = <&rclk>;
+	};
+
+	timer { /* The Generic Timer */
+		compatible = "arm,armv7-timer";
+		interrupts = <GIC_PPI 13
+				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			<GIC_PPI 14
+				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			<GIC_PPI 11
+				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			<GIC_PPI 10
+				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		clock-frequency = <40000000>;//40M
+		always-on;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	dummy_clk: dummy_clk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <50000000>;
+	};
+
+	pinctrl: pinctrl@1d022000 {
+		compatible = "socionext,milbeaut-m10v-pinctrl";
+		reg = <0x1d022000 0x1000>,
+		      <0x1c26f000 0x1000>;
+		reg-names = "pinctrl", "exiu";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		clocks = <&dummy_clk>;
+		interrupts = <0 54 4>, <0 55 4>, <0 56 4>, <0 57 4>,
+				<0 58 4>, <0 59 4>, <0 60 4>, <0 61 4>,
+				<0 62 4>, <0 63 4>, <0 64 4>, <0 65 4>,
+				<0 66 4>, <0 67 4>, <0 68 4>, <0 69 4>;
+		interrupt-names = "pin-48", "pin-49", "pin-50", "pin-51",
+				"pin-52", "pin-53", "pin-54", "pin-55",
+				"pin-56", "pin-57", "pin-58", "pin-59",
+				"pin-60", "pin-61", "pin-62", "pin-63";
+
+		usio1_pins: usio1_pins {
+			pins = "PE4", "PE5", "P87";
+			function = "usio1";
+		};
+	};
+
+	usio1: usio_uart@1e700010 { /* PE4, PE5 */
+		/* Enable this as ttyUSI0 */
+		index = <0>;
+		compatible = "socionext,milbeaut-m10v-usio-uart";
+		reg = <0x1e700010 0x10>;
+		interrupts = <0 141 0x4>, <0 149 0x4>;
+		interrupt-names = "rx", "tx";
+		clocks = <&hclk>;
+	};
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 11/14] pinctrl: milbeaut: Add Milbeaut M10V pinctrl
From: Sugaya Taichi @ 2018-11-19  1:02 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589336-13925-1-git-send-email-sugaya.taichi@socionext.com>

Add Milbeaut M10V pinctrl.
The M10V has the pins that can be used GPIOs or take multiple other
functions.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 drivers/pinctrl/Kconfig        |   9 +
 drivers/pinctrl/Makefile       |   1 +
 drivers/pinctrl/pinctrl-m10v.c | 765 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 775 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-m10v.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 4d8c00e..b9f17e0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -177,6 +177,15 @@ config PINCTRL_OXNAS
 	select GPIOLIB_IRQCHIP
 	select MFD_SYSCON
 
+config PINCTRL_M10V
+	bool
+	select PINMUX
+	select PINCONF
+	select GENERIC_PINCONF
+	select OF_GPIO
+	select REGMAP_MMIO
+	select GPIOLIB_IRQCHIP
+
 config PINCTRL_ROCKCHIP
 	bool
 	select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 18a13c1..1a4a2b2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_PINCTRL_GEMINI)	+= pinctrl-gemini.o
 obj-$(CONFIG_PINCTRL_MAX77620)	+= pinctrl-max77620.o
 obj-$(CONFIG_PINCTRL_MCP23S08)	+= pinctrl-mcp23s08.o
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
+obj-$(CONFIG_PINCTRL_M10V)	+= pinctrl-m10v.o
 obj-$(CONFIG_PINCTRL_OXNAS)	+= pinctrl-oxnas.o
 obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl-pic32.o
diff --git a/drivers/pinctrl/pinctrl-m10v.c b/drivers/pinctrl/pinctrl-m10v.c
new file mode 100644
index 0000000..d4ca713
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-m10v.c
@@ -0,0 +1,765 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Ltd.
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Jassi Brar <jaswinder.singh@linaro.org>
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "pinctrl-utils.h"
+
+#define EIMASK		0x0
+#define EISRCSEL	0x4
+#define EIREQSTA	0x8
+#define EIRAWREQSTA	0xc
+#define EIREQCLR	0x10
+#define EILVL		0x14
+#define EIEDG		0x18
+#define EISIR		0x1c
+
+#define PDR		0x0
+#define PDR_S		0x50
+#define PDR_C		0xa0
+#define DDR		0x100
+#define EPCR		0x200
+#define PUDER		0x300
+#define PUDCR		0x400
+
+#define M10V_BANKS	26
+#define PINS_PER_BANK	8
+#define M10V_TOTAL_PINS	(M10V_BANKS * PINS_PER_BANK)
+#define PINS_PER_REG	16
+
+struct pin_irq_map {
+	int pin; /* offset of pin in the managed range */
+	int irq; /* virq of the pin as fpint */
+	int type;
+	char irqname[8];
+};
+
+struct m10v_pinctrl {
+	void __iomem *base;
+	void __iomem *exiu;
+	struct gpio_chip gc;
+	struct pinctrl_desc pd;
+	char pin_names[4 * M10V_TOTAL_PINS];
+	struct pinctrl_pin_desc pins[M10V_TOTAL_PINS];
+	unsigned int gpins[M10V_TOTAL_PINS][1]; /* 1 pin-per-group */
+	struct irq_domain *irqdom;
+	spinlock_t irq_lock, lock;
+	int extints;
+	struct pin_irq_map fpint[]; /* keep at end */
+};
+
+struct milbeaut_function {
+	const char		*name;
+	const char * const	*groups;
+	unsigned int		ngroups;
+};
+
+static const char m10v_bank_name[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+				 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+				 'G', 'H', 'W', 'J', 'K', 'L', 'M', 'N',
+				 'Y', 'P'};
+static const char * const usio0_m10v_grps[] = {"PE2", "PE3", "PF0"};
+static const char * const usio1_m10v_grps[] = {"PE4", "PE5", "PF1"};
+static const char * const usio2_m10v_grps[] = {"PE0", "PE1"};
+static const char * const usio3_m10v_grps[] = {"PY0", "PY1", "PY2"};
+static const char * const usio4_m10v_grps[] = {"PP0", "PP1", "PP2"};
+static const char * const usio5_m10v_grps[] = {"PM0", "PM1", "PM3"};
+static const char * const usio6_m10v_grps[] = {"PN0", "PN1", "PN3"};
+static const char * const usio7_m10v_grps[] = {"PY3", "PY5", "PY6"};
+static const char *gpio_m10v_grps[M10V_TOTAL_PINS];
+
+static const struct milbeaut_function m10v_functions[] = {
+#define FUNC_M10V(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_m10v_grps,		\
+		.ngroups = ARRAY_SIZE(fname##_m10v_grps),	\
+	}
+	FUNC_M10V(gpio), /* GPIO always at index 0 */
+	FUNC_M10V(usio0),
+	FUNC_M10V(usio1),
+	FUNC_M10V(usio2),
+	FUNC_M10V(usio3),
+	FUNC_M10V(usio4),
+	FUNC_M10V(usio5),
+	FUNC_M10V(usio6),
+	FUNC_M10V(usio7),
+};
+
+static const char *bank_name;
+static const struct milbeaut_function *milbeaut_functions;
+
+static int m10v_pconf_group_set(struct pinctrl_dev *pctldev,
+				 unsigned int group,
+				 unsigned long *configs,
+				 unsigned int num_configs)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	u32 pin, val, reg, offset;
+	unsigned long flags;
+	int i;
+
+	pin = pctl->gpins[group][0];
+	reg = pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	for (i = 0; i < num_configs; i++) {
+		switch (pinconf_to_config_param(configs[i])) {
+		case PIN_CONFIG_BIAS_PULL_UP:
+			/* enable Pull-Up/Down resistance */
+			val = readl_relaxed(pctl->base + PUDER + reg);
+			val |= BIT(offset);
+			writel_relaxed(val, pctl->base + PUDER + reg);
+			/* enable Pull-Up */
+			val = readl_relaxed(pctl->base + PUDCR + reg);
+			val |= BIT(offset);
+			writel_relaxed(val, pctl->base + PUDCR + reg);
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			/* enable Pull-Up/Down resistance */
+			val = readl_relaxed(pctl->base + PUDER + reg);
+			val |= BIT(offset);
+			writel_relaxed(val, pctl->base + PUDER + reg);
+			/* enable Pull-Down */
+			val = readl_relaxed(pctl->base + PUDCR + reg);
+			val &= ~BIT(offset);
+			writel_relaxed(val, pctl->base + PUDCR + reg);
+			break;
+		case PIN_CONFIG_BIAS_DISABLE:
+			val = readl_relaxed(pctl->base + PUDER + reg);
+			val &= ~BIT(offset);
+			writel_relaxed(val, pctl->base + PUDER + reg);
+			break;
+		default:
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
+
+	return 0;
+}
+
+static const struct pinconf_ops m10v_pconf_ops = {
+	.pin_config_group_set	= m10v_pconf_group_set,
+};
+
+static int m10v_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return M10V_TOTAL_PINS;
+}
+
+static const char *m10v_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+					      unsigned int pin)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return &pctl->pin_names[4 * pin];
+}
+
+static int m10v_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+				      unsigned int group,
+				      const unsigned int **pins,
+				      unsigned int *num_pins)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pctl->gpins[group];
+	*num_pins = 1;
+	return 0;
+}
+
+static const struct pinctrl_ops m10v_pctrl_ops = {
+	.get_groups_count	= m10v_pctrl_get_groups_count,
+	.get_group_name		= m10v_pctrl_get_group_name,
+	.get_group_pins		= m10v_pctrl_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
+	.dt_free_map		= pinctrl_utils_free_map,
+};
+
+static int m10v_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(m10v_functions);
+}
+
+static const char *m10v_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					   unsigned int function)
+{
+	return milbeaut_functions[function].name;
+}
+
+static int m10v_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				     unsigned int function,
+				     const char * const **groups,
+				     unsigned * const num_groups)
+{
+	*groups = milbeaut_functions[function].groups;
+	*num_groups = milbeaut_functions[function].ngroups;
+	return 0;
+}
+
+static void _set_mux(struct m10v_pinctrl *pctl, unsigned int pin, bool gpio)
+{
+	u32 val, reg, offset;
+	unsigned long flags;
+
+	reg = pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+
+	reg += EPCR;
+
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	val = readl_relaxed(pctl->base + reg);
+
+	if (gpio)
+		val &= ~BIT(offset);
+	else
+		val |= BIT(offset);
+
+	writel_relaxed(val, pctl->base + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
+}
+
+static int m10v_pmx_set_mux(struct pinctrl_dev *pctldev,
+			     unsigned int function,
+			     unsigned int group)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	u32 pin = pctl->gpins[group][0]; /* each group has exactly 1 pin */
+
+	_set_mux(pctl, pin, !function);
+
+	return 0;
+}
+
+static int _set_direction(struct m10v_pinctrl *pctl,
+			unsigned int pin, bool input)
+{
+	u32 val, reg, offset;
+	unsigned long flags;
+
+	reg = pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+
+	reg += DDR;
+
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	val = readl_relaxed(pctl->base + reg);
+
+	if (input)
+		val &= ~BIT(offset);
+	else
+		val |= BIT(offset);
+
+	writel_relaxed(val, pctl->base + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
+
+	return 0;
+}
+
+static int
+m10v_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range,
+			unsigned int pin, bool input)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return _set_direction(pctl, pin, input);
+}
+
+static int
+m10v_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
+			    struct pinctrl_gpio_range *range,
+			    unsigned int pin)
+{
+	struct m10v_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	_set_mux(pctl, pin, true);
+	return 0;
+}
+
+static const struct pinmux_ops m10v_pmx_ops = {
+	.get_functions_count	= m10v_pmx_get_funcs_cnt,
+	.get_function_name	= m10v_pmx_get_func_name,
+	.get_function_groups	= m10v_pmx_get_func_groups,
+	.set_mux		= m10v_pmx_set_mux,
+	.gpio_set_direction	= m10v_pmx_gpio_set_direction,
+	.gpio_request_enable	= m10v_pmx_gpio_request_enable,
+};
+
+static int m10v_gpio_get(struct gpio_chip *gc, unsigned int group)
+{
+	struct m10v_pinctrl *pctl =
+		container_of(gc, struct m10v_pinctrl, gc);
+	u32 pin, val, reg, offset;
+
+	pin = pctl->gpins[group][0];
+	reg = PDR + pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+	val = readl_relaxed(pctl->base + reg);
+
+	return !!(val & BIT(offset));
+}
+
+static void m10v_gpio_set(struct gpio_chip *gc, unsigned int group, int set)
+{
+	struct m10v_pinctrl *pctl =
+		container_of(gc, struct m10v_pinctrl, gc);
+	u32 pin, reg, offset, val;
+
+	pin = pctl->gpins[group][0];
+	reg = PDR + pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+
+	val = BIT(offset + 16);
+	if (set)
+		val |= BIT(offset);
+
+	writel_relaxed(val, pctl->base + reg);
+}
+
+static void (*gpio_set)(struct gpio_chip *, unsigned int, int);
+
+static int m10v_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int m10v_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	int ret;
+
+	ret = pinctrl_gpio_direction_output(gc->base + offset);
+	if (!ret)
+		gpio_set(gc, offset, value);
+
+	return ret;
+}
+
+static int m10v_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+	struct m10v_pinctrl *pctl =
+		container_of(gc, struct m10v_pinctrl, gc);
+
+	return irq_linear_revmap(pctl->irqdom, offset);
+}
+
+static struct lock_class_key gpio_lock_class;
+static struct lock_class_key gpio_request_class;
+
+static int pin_to_extint(struct m10v_pinctrl *pctl, int pin)
+{
+	int extint;
+
+	for (extint = 0; extint < pctl->extints; extint++)
+		if (pctl->fpint[extint].pin == pin)
+			break;
+
+	if (extint == pctl->extints)
+		return -1;
+
+	return extint;
+}
+
+static void update_trigger(struct m10v_pinctrl *pctl, int extint)
+{
+	int type = pctl->fpint[extint].type;
+	int pin = pctl->fpint[extint].pin;
+	u32 masked, val, eilvl, eiedg;
+	int lvl;
+	u32 reg, offset;
+
+	reg = pin / PINS_PER_REG * 4;
+	offset = pin % PINS_PER_REG;
+
+	/* sense gpio */
+	val = readl_relaxed(pctl->base + PDR + reg);
+	lvl = (val >> offset) & 1;
+
+	eilvl = readl_relaxed(pctl->exiu + EILVL);
+	eiedg = readl_relaxed(pctl->exiu + EIEDG);
+
+	if (type == IRQ_TYPE_LEVEL_LOW ||
+			(lvl && (type & IRQ_TYPE_LEVEL_LOW))) {
+		eilvl &= ~BIT(extint);
+		eiedg &= ~BIT(extint);
+	}
+
+	if (type == IRQ_TYPE_EDGE_FALLING ||
+			(lvl && (type & IRQ_TYPE_EDGE_FALLING))) {
+		eilvl &= ~BIT(extint);
+		eiedg |= BIT(extint);
+	}
+
+	if (type == IRQ_TYPE_LEVEL_HIGH ||
+			(!lvl && (type & IRQ_TYPE_LEVEL_HIGH))) {
+		eilvl |= BIT(extint);
+		eiedg &= ~BIT(extint);
+	}
+
+	if (type == IRQ_TYPE_EDGE_RISING ||
+			(!lvl && (type & IRQ_TYPE_EDGE_RISING))) {
+		eilvl |= BIT(extint);
+		eiedg |= BIT(extint);
+	}
+
+	/* Mask the interrupt */
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	masked = val & BIT(extint); /* save status */
+	val |= BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+
+	/* Program trigger */
+	writel_relaxed(eilvl, pctl->exiu + EILVL);
+	writel_relaxed(eiedg, pctl->exiu + EIEDG);
+
+	if (masked)
+		return;
+
+	/* UnMask the interrupt */
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	val &= ~BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+}
+
+static irqreturn_t m10v_gpio_irq_handler(int irq, void *data)
+{
+	struct m10v_pinctrl *pctl = data;
+	int i, pin;
+	u32 val;
+
+	for (i = 0; i < pctl->extints; i++)
+		if (pctl->fpint[i].irq == irq)
+			break;
+	if (i == pctl->extints) {
+		pr_err("%s:%d IRQ(%d)!\n", __func__, __LINE__, irq);
+		return IRQ_NONE;
+	}
+
+	if (!pctl->exiu)
+		return IRQ_NONE;
+
+	val = readl_relaxed(pctl->exiu + EIREQSTA);
+	if (!(val & BIT(i))) {
+		pr_err("%s:%d i=%d EIREQSTA=0x%x IRQ(%d)!\n",
+				__func__, __LINE__, i, val, irq);
+		return IRQ_NONE;
+	}
+
+	pin = pctl->fpint[i].pin;
+	generic_handle_irq(irq_linear_revmap(pctl->irqdom, pin));
+
+	return IRQ_HANDLED;
+}
+
+static void m10v_gpio_irq_enable(struct irq_data *data)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+	unsigned long flags;
+	u32 val;
+
+	if (extint < 0 || !pctl->exiu)
+		return;
+
+	_set_mux(pctl, irqd_to_hwirq(data), true);
+	_set_direction(pctl, irqd_to_hwirq(data), true);
+
+	spin_lock_irqsave(&pctl->irq_lock, flags);
+
+	/* Clear before enabling */
+	writel_relaxed(BIT(extint), pctl->exiu + EIREQCLR);
+
+	/* UnMask the interrupt */
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	val &= ~BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+
+	spin_unlock_irqrestore(&pctl->irq_lock, flags);
+}
+
+static void m10v_gpio_irq_disable(struct irq_data *data)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+	unsigned long flags;
+	u32 val;
+
+	if (extint < 0 || !pctl->exiu)
+		return;
+
+	spin_lock_irqsave(&pctl->irq_lock, flags);
+
+	/* Mask the interrupt */
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	val |= BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+
+	spin_unlock_irqrestore(&pctl->irq_lock, flags);
+}
+
+static int m10v_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+	unsigned long flags;
+
+	if (extint < 0 || !pctl->exiu)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pctl->irq_lock, flags);
+
+	pctl->fpint[extint].type = type;
+	update_trigger(pctl, extint);
+
+	spin_unlock_irqrestore(&pctl->irq_lock, flags);
+
+	return 0;
+}
+
+void m10v_gpio_irq_ack(struct irq_data *data)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+
+	if (extint < 0 || !pctl->exiu)
+		return;
+
+	writel_relaxed(BIT(extint), pctl->exiu + EIREQCLR);
+}
+
+void m10v_gpio_irq_mask(struct irq_data *data)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+	unsigned long flags;
+	u32 val;
+
+	if (extint < 0 || !pctl->exiu)
+		return;
+
+	spin_lock_irqsave(&pctl->irq_lock, flags);
+
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	val |= BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+
+	spin_unlock_irqrestore(&pctl->irq_lock, flags);
+}
+
+void m10v_gpio_irq_unmask(struct irq_data *data)
+{
+	struct m10v_pinctrl *pctl = irq_data_get_irq_chip_data(data);
+	int extint = pin_to_extint(pctl, irqd_to_hwirq(data));
+	unsigned long flags;
+	u32 val;
+
+	if (extint < 0 || !pctl->exiu)
+		return;
+
+	spin_lock_irqsave(&pctl->irq_lock, flags);
+
+	update_trigger(pctl, extint);
+
+	val = readl_relaxed(pctl->exiu + EIMASK);
+	val &= ~BIT(extint);
+	writel_relaxed(val, pctl->exiu + EIMASK);
+
+	spin_unlock_irqrestore(&pctl->irq_lock, flags);
+}
+
+static struct irq_chip m10v_gpio_irq_chip = {
+	.name = "m10v-pin-irq",
+	.irq_enable = m10v_gpio_irq_enable,
+	.irq_disable = m10v_gpio_irq_disable,
+	.irq_set_type = m10v_gpio_irq_set_type,
+	.irq_mask = m10v_gpio_irq_mask,
+	.irq_unmask = m10v_gpio_irq_unmask,
+	.irq_ack = m10v_gpio_irq_ack,
+};
+
+static const struct of_device_id m10v_pmatch[] = {
+	{ .compatible = "socionext,milbeaut-m10v-pinctrl" },
+	{},
+};
+
+static int m10v_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pinctrl_dev *pctl_dev;
+	struct pin_irq_map fpint[32];
+	struct m10v_pinctrl *pctl;
+	struct pinctrl_desc *pd;
+	struct gpio_chip *gc;
+	struct resource *res;
+	int idx, i, ret, extints, tpins;
+
+	extints = of_irq_count(np);
+
+	pctl = devm_kzalloc(&pdev->dev,	sizeof(*pctl) +
+				sizeof(struct pin_irq_map) * extints,
+				GFP_KERNEL);
+	if (!pctl)
+		return -ENOMEM;
+
+	gpio_set = m10v_gpio_set;
+	bank_name = m10v_bank_name;
+	milbeaut_functions = m10v_functions;
+	tpins = M10V_TOTAL_PINS;
+
+	pd = &pctl->pd;
+	gc = &pctl->gc;
+	spin_lock_init(&pctl->lock);
+	spin_lock_init(&pctl->irq_lock);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pinctrl");
+	pctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (!pctl->base)
+		return -EINVAL;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "exiu");
+	if (res)
+		pctl->exiu = devm_ioremap_resource(&pdev->dev, res);
+	if (res && !IS_ERR(pctl->exiu)) {
+		writel_relaxed(~0, pctl->exiu + EIMASK); /* mask all */
+		writel_relaxed(~0, pctl->exiu + EIREQCLR); /* eoi all */
+		writel_relaxed(0, pctl->exiu + EISRCSEL); /* all fpint */
+		writel_relaxed(~0, pctl->exiu + EILVL); /* rising edge type*/
+		writel_relaxed(~0, pctl->exiu + EIEDG);
+	} else {
+		dev_info(&pdev->dev, "continuing without EXIU support\n");
+		pctl->exiu = NULL;
+	}
+
+	for (i = 0; i < tpins; i++) {
+		pctl->pins[i].number = i;
+		pctl->pins[i].name = &pctl->pin_names[4 * i];
+		snprintf(&pctl->pin_names[4 * i], 4, "P%c%d",
+			bank_name[i / PINS_PER_BANK], i % PINS_PER_BANK);
+		gpio_m10v_grps[i] = &pctl->pin_names[4 * i];
+		pctl->gpins[i][0] = i;
+	}
+	/* absent or incomplete entries allow all access */
+	pd->name = dev_name(&pdev->dev);
+	pd->pins = pctl->pins;
+	pd->npins = tpins;
+	pd->pctlops = &m10v_pctrl_ops;
+	pd->pmxops = &m10v_pmx_ops;
+	pd->confops = &m10v_pconf_ops;
+	pd->owner = THIS_MODULE;
+	pctl_dev = pinctrl_register(pd, &pdev->dev, pctl);
+	if (!pctl_dev) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	pctl->extints = extints;
+
+	pctl->irqdom = irq_domain_add_linear(np, tpins,
+						&irq_domain_simple_ops, pctl);
+	idx = 0;
+	for (i = 0; i < tpins && idx < pctl->extints; i++) {
+		int irq;
+
+		snprintf(fpint[idx].irqname, 8, "pin-%d", i);
+		irq = platform_get_irq_byname(pdev, fpint[idx].irqname);
+		if (irq < 0)
+			continue;
+		fpint[idx].irq = irq;
+		fpint[idx].pin = i;
+		idx++;
+	}
+
+	for (idx = 0, i = 0; i < pctl->extints; i++) {
+		int j = 0, irq = platform_get_irq(pdev, i);
+
+		while (fpint[j].irq != irq)
+			j++;
+
+		snprintf(pctl->fpint[idx].irqname, 8, "pin-%d", fpint[j].pin);
+		pctl->fpint[idx].irq = fpint[j].irq;
+		pctl->fpint[idx].pin = fpint[j].pin;
+		idx++;
+	}
+
+	for (i = 0; i < pctl->extints; i++) {
+		int irq, err = devm_request_irq(&pdev->dev, pctl->fpint[i].irq,
+					m10v_gpio_irq_handler, IRQF_SHARED,
+					pctl->fpint[i].irqname, pctl);
+		if (err)
+			continue;
+
+		irq = irq_create_mapping(pctl->irqdom, pctl->fpint[i].pin);
+		irq_set_lockdep_class(irq, &gpio_lock_class,
+			&gpio_request_class);
+		irq_set_chip_and_handler(irq, &m10v_gpio_irq_chip,
+					 handle_level_irq);
+		irq_set_chip_data(irq, pctl);
+	}
+
+	gc->base = -1;
+	gc->ngpio = tpins;
+	gc->label = dev_name(&pdev->dev);
+	gc->owner = THIS_MODULE;
+	gc->of_node = np;
+	gc->direction_input = m10v_gpio_direction_input;
+	gc->direction_output = m10v_gpio_direction_output;
+	gc->get = m10v_gpio_get;
+	gc->set = gpio_set;
+	gc->to_irq = m10v_gpio_to_irq;
+	gc->request = gpiochip_generic_request;
+	gc->free = gpiochip_generic_free;
+	ret = gpiochip_add(gc);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed register gpiochip\n");
+		return ret;
+	}
+
+	ret = gpiochip_add_pin_range(gc, dev_name(&pdev->dev),
+					0, 0, tpins);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add pin range\n");
+		gpiochip_remove(gc);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver m10v_pinctrl_driver = {
+	.probe	= m10v_pinctrl_probe,
+	.driver	= {
+		.name		= "m10v-pinctrl",
+		.of_match_table	= m10v_pmatch,
+	},
+};
+
+static int __init m10v_pinctrl_init(void)
+{
+	return platform_driver_register(&m10v_pinctrl_driver);
+}
+arch_initcall(m10v_pinctrl_init);
+
-- 
1.9.1

^ permalink raw reply related

* [PATCH 10/14] dt-bindings: pinctrl: milbeaut: Add Milbeaut M10V pinctrl description
From: Sugaya Taichi @ 2018-11-19  1:02 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi

Add DT bindings document for Milbeaut M10V pinctrl.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../pinctrl/socionext,milbeaut-pinctrl.txt         | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/socionext,milbeaut-pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/socionext,milbeaut-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/socionext,milbeaut-pinctrl.txt
new file mode 100644
index 0000000..7469189
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/socionext,milbeaut-pinctrl.txt
@@ -0,0 +1,33 @@
+Milbeaut SoCs pin controller
+
+Required properties:
+- compatible: should be one of the following:
+    "socionext,milbeaut-m10v-pinctrl"  - for m10v SoC
+- reg: offset and length of the register set.
+- reg-names: should be "pinctrl", "exiu".
+- gpio-cells; should be 2.
+- interrupt-cells: should be 2.
+- clocks: phandle to the input clock.
+- interrupts: three interrupts specifer.
+- interrupt-names: corresponds "interrupts" factor.
+
+Example:
+	pinctrl: pinctrl@1d022000 {
+		compatible = "socionext,milbeaut-m10v-pinctrl";
+		reg = <0x1d022000 0x1000>,
+			<0x1c26f000 0x1000>;
+		reg-names = "pinctrl", "exiu";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		clocks = <&dummy_clk>;
+		interrupts = <0 54 4>, <0 55 4>, <0 56 4>, <0 57 4>,
+				<0 58 4>, <0 59 4>, <0 60 4>, <0 61 4>,
+				<0 62 4>, <0 63 4>, <0 64 4>, <0 65 4>,
+				<0 66 4>, <0 67 4>, <0 68 4>, <0 69 4>;
+		interrupt-names = "pin-48", "pin-49", "pin-50", "pin-51",
+				"pin-52", "pin-53", "pin-54", "pin-55",
+				"pin-56", "pin-57", "pin-58", "pin-59",
+				"pin-60", "pin-61", "pin-62", "pin-63";
+	}
-- 
1.9.1

^ permalink raw reply related

* [PATCH 09/14] serial: Add Milbeaut M10V serial control
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add Milbeaut M10V serial control.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 drivers/tty/serial/Kconfig       |  24 ++
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/m10v_usio.c   | 605 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 633 insertions(+)
 create mode 100644 drivers/tty/serial/m10v_usio.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 32886c3..cd28a7e 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1529,6 +1529,30 @@ config SERIAL_OWL_CONSOLE
 	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
 	  as the system console.
 
+config SERIAL_M10V_USIO
+	tristate "M10V USIO/UART serial port support"
+	depends on ARCH_MILBEAUT
+	default y
+	select SERIAL_CORE
+	help
+	  This selects the USIO/UART IP found in Socionext Milbeaut M10V.
+
+config SERIAL_M10V_USIO_PORTS
+	int "Maximum number of CSIO/UART ports (1-8)"
+	range 1 8
+	depends on SERIAL_M10V_USIO
+	default "4"
+
+config SERIAL_M10V_USIO_CONSOLE
+	bool "Support for console on M10V USIO/UART serial port"
+	depends on SERIAL_M10V_USIO=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Say 'Y' here if you wish to use a USIO/UART of Socionext Milbeaut
+	  M10V as the system console (the system console is the device which
+	  receives all kernel messages and warnings and which allows logins in
+	  single user mode).
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index daac675..5ea46bc 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
 obj-$(CONFIG_SERIAL_MPS2_UART)	+= mps2-uart.o
 obj-$(CONFIG_SERIAL_OWL)	+= owl-uart.o
+obj-$(CONFIG_SERIAL_M10V_USIO)   += m10v_usio.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/m10v_usio.c b/drivers/tty/serial/m10v_usio.c
new file mode 100644
index 0000000..3abb465
--- /dev/null
+++ b/drivers/tty/serial/m10v_usio.c
@@ -0,0 +1,605 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ */
+
+#if defined(CONFIG_SERIAL_M10V_USIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+
+#define USIO_NAME		"sn-usio-uart"
+#define USIO_UART_DEV_NAME	"ttyUSI"
+
+static struct uart_port usio_ports[CONFIG_SERIAL_M10V_USIO_PORTS];
+
+#define RX	0
+#define TX	1
+static int usio_irq[CONFIG_SERIAL_M10V_USIO_PORTS][2];
+
+#define SN_USIO_REG_SMR		0
+#define SN_USIO_REG_SCR		1
+#define SN_USIO_REG_ESCR	2
+#define SN_USIO_REG_SSR		3
+#define SN_USIO_REG_DR		4
+#define SN_USIO_REG_BGR		6
+#define SN_USIO_REG_FCR		12
+#define SN_USIO_REG_FBYTE	14
+
+#define SN_USIO_SMR_SOE		BIT(0)
+#define SN_USIO_SMR_SBL		BIT(3)
+#define SN_USIO_SCR_TXE		BIT(0)
+#define SN_USIO_SCR_RXE		BIT(1)
+#define SN_USIO_SCR_TBIE	BIT(2)
+#define SN_USIO_SCR_TIE		BIT(3)
+#define SN_USIO_SCR_RIE		BIT(4)
+#define SN_USIO_SCR_UPCL	BIT(7)
+#define SN_USIO_ESCR_L_8BIT	0
+#define SN_USIO_ESCR_L_5BIT	1
+#define SN_USIO_ESCR_L_6BIT	2
+#define SN_USIO_ESCR_L_7BIT	3
+#define SN_USIO_ESCR_P		BIT(3)
+#define SN_USIO_ESCR_PEN	BIT(4)
+#define SN_USIO_ESCR_FLWEN	BIT(7)
+#define SN_USIO_SSR_TBI		BIT(0)
+#define SN_USIO_SSR_TDRE	BIT(1)
+#define SN_USIO_SSR_RDRF	BIT(2)
+#define SN_USIO_SSR_ORE		BIT(3)
+#define SN_USIO_SSR_FRE		BIT(4)
+#define SN_USIO_SSR_PE		BIT(5)
+#define SN_USIO_SSR_REC		BIT(7)
+#define SN_USIO_SSR_BRK		BIT(8)
+#define SN_USIO_FCR_FE1		BIT(0)
+#define SN_USIO_FCR_FE2		BIT(1)
+#define SN_USIO_FCR_FCL1	BIT(2)
+#define SN_USIO_FCR_FCL2	BIT(3)
+#define SN_USIO_FCR_FSET	BIT(4)
+#define SN_USIO_FCR_FTIE	BIT(9)
+#define SN_USIO_FCR_FDRQ	BIT(10)
+#define SN_USIO_FCR_FRIIE	BIT(11)
+
+static void usio_stop_tx(struct uart_port *port)
+{
+	writew(readw(port->membase + SN_USIO_REG_FCR) & ~SN_USIO_FCR_FTIE,
+	       port->membase + SN_USIO_REG_FCR);
+	writeb(readb(port->membase + SN_USIO_REG_SCR) & ~SN_USIO_SCR_TBIE,
+	       port->membase + SN_USIO_REG_SCR);
+}
+
+static void usio_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	int count;
+
+	writew(readw(port->membase + SN_USIO_REG_FCR) & ~SN_USIO_FCR_FTIE,
+	       port->membase + SN_USIO_REG_FCR);
+	writeb(readb(port->membase + SN_USIO_REG_SCR) &
+	       ~(SN_USIO_SCR_TIE | SN_USIO_SCR_TBIE),
+	       port->membase + SN_USIO_REG_SCR);
+
+	if (port->x_char) {
+		writew(port->x_char, port->membase + SN_USIO_REG_DR);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		usio_stop_tx(port);
+		return;
+	}
+
+	count = port->fifosize -
+		(readw(port->membase + SN_USIO_REG_FBYTE) & 0xff);
+
+	do {
+		writew(xmit->buf[xmit->tail], port->membase + SN_USIO_REG_DR);
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+
+	} while (--count > 0);
+
+	writew(readw(port->membase + SN_USIO_REG_FCR) & ~SN_USIO_FCR_FDRQ,
+	       port->membase + SN_USIO_REG_FCR);
+
+	writeb(readb(port->membase + SN_USIO_REG_SCR) | SN_USIO_SCR_TBIE,
+	       port->membase + SN_USIO_REG_SCR);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		usio_stop_tx(port);
+}
+
+static void usio_start_tx(struct uart_port *port)
+{
+	u16 fcr = readw(port->membase + SN_USIO_REG_FCR);
+
+	writew(fcr | SN_USIO_FCR_FTIE, port->membase + SN_USIO_REG_FCR);
+	if (!(fcr & SN_USIO_FCR_FDRQ))
+		return;
+
+	writeb(readb(port->membase + SN_USIO_REG_SCR) | SN_USIO_SCR_TBIE,
+	       port->membase + SN_USIO_REG_SCR);
+
+	if (readb(port->membase + SN_USIO_REG_SSR) & SN_USIO_SSR_TBI)
+		usio_tx_chars(port);
+}
+
+static void usio_stop_rx(struct uart_port *port)
+{
+	writeb(readb(port->membase + SN_USIO_REG_SCR) & ~SN_USIO_SCR_RIE,
+	       port->membase + SN_USIO_REG_SCR);
+}
+
+static void usio_enable_ms(struct uart_port *port)
+{
+	writeb(readb(port->membase + SN_USIO_REG_SCR) |
+	       SN_USIO_SCR_RIE | SN_USIO_SCR_RXE,
+	       port->membase + SN_USIO_REG_SCR);
+}
+
+static void usio_rx_chars(struct uart_port *port)
+{
+	struct tty_port *ttyport = &port->state->port;
+	unsigned long flag = 0;
+	char ch = 0;
+	u8 status;
+	int max_count = 2;
+
+	while (max_count--) {
+		status = readb(port->membase + SN_USIO_REG_SSR);
+
+		if (!(status & SN_USIO_SSR_RDRF))
+			break;
+
+		if (!(status & (SN_USIO_SSR_ORE | SN_USIO_SSR_FRE |
+				SN_USIO_SSR_PE))) {
+			ch = readw(port->membase + SN_USIO_REG_DR);
+			flag = TTY_NORMAL;
+			port->icount.rx++;
+			if (uart_handle_sysrq_char(port, ch))
+				continue;
+			uart_insert_char(port, status, SN_USIO_SSR_ORE,
+					 ch, flag);
+			continue;
+		}
+		if (status & SN_USIO_SSR_PE)
+			port->icount.parity++;
+		if (status & SN_USIO_SSR_ORE)
+			port->icount.overrun++;
+		status &= port->read_status_mask;
+		if (status & SN_USIO_SSR_BRK) {
+			flag = TTY_BREAK;
+			ch = 0;
+		} else
+			if (status & SN_USIO_SSR_PE) {
+				flag = TTY_PARITY;
+				ch = 0;
+			} else
+				if (status & SN_USIO_SSR_FRE) {
+					flag = TTY_FRAME;
+					ch = 0;
+				}
+		if (flag)
+			uart_insert_char(port, status, SN_USIO_SSR_ORE,
+					 ch, flag);
+
+		writeb(readb(port->membase + SN_USIO_REG_SSR) | SN_USIO_SSR_REC,
+			port->membase + SN_USIO_REG_SSR);
+
+		max_count = readw(port->membase + SN_USIO_REG_FBYTE) >> 8;
+		writew(readw(port->membase + SN_USIO_REG_FCR) |
+		       SN_USIO_FCR_FE2 | SN_USIO_FCR_FRIIE,
+		port->membase + SN_USIO_REG_FCR);
+	}
+
+	tty_flip_buffer_push(ttyport);
+}
+
+static irqreturn_t usio_rx_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+
+	spin_lock(&port->lock);
+	usio_rx_chars(port);
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t usio_tx_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+
+	spin_lock(&port->lock);
+	if (readb(port->membase + SN_USIO_REG_SSR) & SN_USIO_SSR_TBI)
+		usio_tx_chars(port);
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int usio_tx_empty(struct uart_port *port)
+{
+	return (readb(port->membase + SN_USIO_REG_SSR) & SN_USIO_SSR_TBI) ?
+		TIOCSER_TEMT : 0;
+}
+
+static void usio_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int usio_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+
+}
+
+static void usio_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int usio_startup(struct uart_port *port)
+{
+	const char *portname = to_platform_device(port->dev)->name;
+	unsigned long flags;
+	int ret, index = port->line;
+	unsigned char  escr;
+
+	ret = request_irq(usio_irq[index][RX], usio_rx_irq, 0, portname, port);
+	if (ret)
+		return ret;
+	ret = request_irq(usio_irq[index][TX], usio_tx_irq, 0, portname, port);
+	if (ret) {
+		free_irq(usio_irq[index][RX], port);
+		return ret;
+	}
+
+	escr = readb(port->membase + SN_USIO_REG_ESCR);
+	if (of_property_read_bool(port->dev->of_node, "uart-flow-enable"))
+		escr |= SN_USIO_ESCR_FLWEN;
+	spin_lock_irqsave(&port->lock, flags);
+	writeb(0, port->membase + SN_USIO_REG_SCR);
+	writeb(escr, port->membase + SN_USIO_REG_ESCR);
+	writeb(SN_USIO_SCR_UPCL, port->membase + SN_USIO_REG_SCR);
+	writeb(SN_USIO_SSR_REC, port->membase + SN_USIO_REG_SSR);
+	writew(0, port->membase + SN_USIO_REG_FCR);
+	writew(SN_USIO_FCR_FCL1 | SN_USIO_FCR_FCL2,
+	       port->membase + SN_USIO_REG_FCR);
+	writew(SN_USIO_FCR_FE1 | SN_USIO_FCR_FE2 | SN_USIO_FCR_FRIIE,
+	       port->membase + SN_USIO_REG_FCR);
+	writew(0, port->membase + SN_USIO_REG_FBYTE);
+	writew(BIT(12), port->membase + SN_USIO_REG_FBYTE);
+
+	writeb(SN_USIO_SCR_TXE  | SN_USIO_SCR_RIE | SN_USIO_SCR_TBIE |
+	       SN_USIO_SCR_RXE, port->membase + SN_USIO_REG_SCR);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void usio_shutdown(struct uart_port *port)
+{
+	int index = port->line;
+
+	free_irq(usio_irq[index][RX], port);
+	free_irq(usio_irq[index][TX], port);
+}
+
+static void usio_set_termios(struct uart_port *port, struct ktermios *termios,
+			     struct ktermios *old)
+{
+	unsigned int escr, smr = SN_USIO_SMR_SOE;
+	unsigned long flags, baud, quot;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		escr = SN_USIO_ESCR_L_5BIT;
+		break;
+	case CS6:
+		escr = SN_USIO_ESCR_L_6BIT;
+		break;
+	case CS7:
+		escr = SN_USIO_ESCR_L_7BIT;
+		break;
+	case CS8:
+	default:
+		escr = SN_USIO_ESCR_L_8BIT;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		smr |= SN_USIO_SMR_SBL;
+
+	if (termios->c_cflag & PARENB) {
+		escr |= SN_USIO_ESCR_PEN;
+		if (termios->c_cflag & PARODD)
+			escr |= SN_USIO_ESCR_P;
+	}
+	/* Set hard flow control */
+	if (of_property_read_bool(port->dev->of_node, "uart-flow-enable") ||
+			(termios->c_cflag & CRTSCTS))
+		escr |= SN_USIO_ESCR_FLWEN;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
+	if (baud > 1)
+		quot = port->uartclk / baud - 1;
+	else
+		quot = 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+	uart_update_timeout(port, termios->c_cflag, baud);
+	port->read_status_mask = SN_USIO_SSR_ORE | SN_USIO_SSR_RDRF |
+				 SN_USIO_SSR_TDRE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= SN_USIO_SSR_FRE | SN_USIO_SSR_PE;
+
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= SN_USIO_SSR_FRE | SN_USIO_SSR_PE;
+	if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
+		port->ignore_status_mask |= SN_USIO_SSR_ORE;
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= SN_USIO_SSR_RDRF;
+
+	writeb(0, port->membase + SN_USIO_REG_SCR);
+	writeb(SN_USIO_SCR_UPCL, port->membase + SN_USIO_REG_SCR);
+	writeb(SN_USIO_SSR_REC, port->membase + SN_USIO_REG_SSR);
+	writew(0, port->membase + SN_USIO_REG_FCR);
+	writeb(smr, port->membase + SN_USIO_REG_SMR);
+	writeb(escr, port->membase + SN_USIO_REG_ESCR);
+	writew(quot, port->membase + SN_USIO_REG_BGR);
+	writew(0, port->membase + SN_USIO_REG_FCR);
+	writew(SN_USIO_FCR_FCL1 | SN_USIO_FCR_FCL2 | SN_USIO_FCR_FE1 |
+	       SN_USIO_FCR_FE2 | SN_USIO_FCR_FRIIE,
+	       port->membase + SN_USIO_REG_FCR);
+	writew(0, port->membase + SN_USIO_REG_FBYTE);
+	writew(BIT(12), port->membase + SN_USIO_REG_FBYTE);
+	writeb(SN_USIO_SCR_RIE | SN_USIO_SCR_RXE | SN_USIO_SCR_TBIE |
+	       SN_USIO_SCR_TXE, port->membase + SN_USIO_REG_SCR);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *usio_type(struct uart_port *port)
+{
+	return ((port->type == PORT_SN_USIO) ? USIO_NAME : NULL);
+}
+
+static void usio_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_SN_USIO;
+}
+
+static const struct uart_ops usio_ops = {
+	.tx_empty	= usio_tx_empty,
+	.set_mctrl	= usio_set_mctrl,
+	.get_mctrl	= usio_get_mctrl,
+	.stop_tx	= usio_stop_tx,
+	.start_tx	= usio_start_tx,
+	.stop_rx	= usio_stop_rx,
+	.enable_ms	= usio_enable_ms,
+	.break_ctl	= usio_break_ctl,
+	.startup	= usio_startup,
+	.shutdown	= usio_shutdown,
+	.set_termios	= usio_set_termios,
+	.type		= usio_type,
+	.config_port	= usio_config_port,
+};
+
+#ifdef CONFIG_SERIAL_M10V_USIO_CONSOLE
+
+static void usio_console_putchar(struct uart_port *port, int c)
+{
+	while (!(readb(port->membase + SN_USIO_REG_SSR) & SN_USIO_SSR_TDRE))
+		cpu_relax();
+
+	writew(c, port->membase + SN_USIO_REG_DR);
+}
+
+static void usio_console_write(struct console *co, const char *s,
+			       unsigned int count)
+{
+	struct uart_port *port = &usio_ports[co->index];
+
+	uart_console_write(port, s, count, usio_console_putchar);
+}
+
+static int __init usio_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int parity = 'n';
+	int flow = 'n';
+	int bits = 8;
+
+	if (co->index >= CONFIG_SERIAL_M10V_USIO_PORTS)
+		return -ENODEV;
+
+	port = &usio_ports[co->index];
+	if (!port->membase)
+		return -ENODEV;
+
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	if (of_property_read_bool(port->dev->of_node, "uart-flow-enable"))
+		flow = 'r';
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+
+static struct uart_driver usio_uart_driver;
+static struct console usio_console = {
+	.name   = USIO_UART_DEV_NAME,
+	.write  = usio_console_write,
+	.device = uart_console_device,
+	.setup  = usio_console_setup,
+	.flags  = CON_PRINTBUFFER,
+	.index  = -1,
+	.data   = &usio_uart_driver,
+};
+
+static int __init usio_console_init(void)
+{
+	register_console(&usio_console);
+	return 0;
+}
+console_initcall(usio_console_init);
+
+#define USIO_CONSOLE	(&usio_console)
+#else
+#define USIO_CONSOLE	NULL
+#endif
+
+
+static struct  uart_driver usio_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= USIO_NAME,
+	.dev_name	= USIO_UART_DEV_NAME,
+	.cons           = USIO_CONSOLE,
+	.nr		= CONFIG_SERIAL_M10V_USIO_PORTS,
+};
+
+static int usio_probe(struct platform_device *pdev)
+{
+	struct clk *clk = devm_clk_get(&pdev->dev, 0);
+	struct uart_port *port;
+	struct resource *res;
+	int index = 0;
+	int ret;
+
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Missing clock\n");
+		return PTR_ERR(clk);
+	}
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Clock enable failed: %d\n", ret);
+		return ret;
+	}
+	of_property_read_u32(pdev->dev.of_node, "index", &index);
+	port = &usio_ports[index];
+
+	port->private_data = (void *)clk;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Missing regs\n");
+		ret = -ENODEV;
+		goto failed;
+	}
+	port->mapbase = res->start;
+	port->membase = ioremap(res->start, (res->end - res->start + 1));
+	port->membase = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+
+	ret = platform_get_irq_byname(pdev, "rx");
+	usio_irq[index][RX] = ret;
+
+	ret = platform_get_irq_byname(pdev, "tx");
+	usio_irq[index][TX] = ret;
+
+	port->irq = usio_irq[index][RX];
+	port->uartclk = clk_get_rate(clk);
+	port->fifosize = 128;
+	port->iotype = UPIO_MEM32;
+	port->flags = UPF_BOOT_AUTOCONF | UPF_SPD_VHI;
+	port->line = index;
+	port->ops = &usio_ops;
+	port->dev = &pdev->dev;
+
+	ret = uart_add_one_port(&usio_uart_driver, port);
+	if (ret) {
+		dev_err(&pdev->dev, "Adding port failed: %d\n", ret);
+		goto failed1;
+	}
+	return 0;
+
+failed1:
+	iounmap(port->membase);
+
+failed:
+	clk_disable_unprepare(clk);
+	clk_put(clk);
+
+	return ret;
+}
+
+static int usio_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = &usio_ports[pdev->id];
+	struct clk *clk = port->private_data;
+
+	uart_remove_one_port(&usio_uart_driver, port);
+	clk_disable_unprepare(clk);
+	clk_put(clk);
+
+	return 0;
+}
+
+#define usio_suspend NULL
+#define usio_resume NULL
+
+static const struct of_device_id m10v_usio_dt_ids[] = {
+	{ .compatible = "socionext,milbeaut-m10v-usio-uart" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, m10v_usio_dt_ids);
+
+static struct platform_driver usio_driver = {
+	.probe          = usio_probe,
+	.remove         = usio_remove,
+	.suspend        = usio_suspend,
+	.resume         = usio_resume,
+	.driver         = {
+		.name   = USIO_NAME,
+		.of_match_table = m10v_usio_dt_ids,
+	},
+};
+
+static int __init usio_init(void)
+{
+	int ret = uart_register_driver(&usio_uart_driver);
+
+	if (ret) {
+		pr_err("%s: uart registration failed: %d\n", __func__, ret);
+		return ret;
+	}
+	ret = platform_driver_register(&usio_driver);
+	if (ret) {
+		uart_unregister_driver(&usio_uart_driver);
+		pr_err("%s: drv registration failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit usio_exit(void)
+{
+	platform_driver_unregister(&usio_driver);
+	uart_unregister_driver(&usio_uart_driver);
+}
+
+module_init(usio_init);
+module_exit(usio_exit);
+
+MODULE_AUTHOR("SOCIONEXT");
+MODULE_DESCRIPTION("SN_USIO/UART Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index dce5f9d..984df0d 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -281,4 +281,7 @@
 /* MediaTek BTIF */
 #define PORT_MTK_BTIF	117
 
+/* Socionext UART */
+#define PORT_SN_USIO    118
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
1.9.1

^ permalink raw reply related

* [PATCH 08/14] dt-bindings: serial: Add Milbeaut M10V serial description
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add DT bindings document for Milbeaut M10V serial.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../devicetree/bindings/serial/milbeaut-uart.txt   | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/milbeaut-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/milbeaut-uart.txt b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt
new file mode 100644
index 0000000..19d1480
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt
@@ -0,0 +1,23 @@
+Socionext Milbeaut UART controller
+
+Required properties:
+- index: must be 0
+- compatible: should be "socionext,milbeaut-m10v-usio-uart".
+- reg: offset and length of the register set for the device.
+- interrupts: two interrupts specifier.
+- clocks: phandle to the input clock.
+- interrupt-names: should be "rx", "tx".
+
+Optional properties:
+- uart-flow-enable: flow control enable.
+
+Example:
+	usio1: usio_uart@1e700010 {
+		index = <0>;
+		compatible = "socionext,milbeaut-m10v-usio-uart";
+		reg = <0x1e700010 0x10>;
+		interrupts = <0 141 0x4>, <0 149 0x4>;
+		interrupt-names = "rx", "tx";
+		clocks = <&hclk>;
+		uart-flow-enable;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 07/14] clock: milbeaut: Add Milbeaut M10V clock control
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add Milbeaut M10V clock ( including PLL ) control.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 drivers/clk/Makefile   |   1 +
 drivers/clk/clk-m10v.c | 671 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 672 insertions(+)
 create mode 100644 drivers/clk/clk-m10v.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 72be7a3..da5b282 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_GEMINI)		+= clk-gemini.o
 obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
+obj-$(CONFIG_ARCH_MILBEAUT_M10V)	+= clk-m10v.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_MAX9485)	+= clk-max9485.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
diff --git a/drivers/clk/clk-m10v.c b/drivers/clk/clk-m10v.c
new file mode 100644
index 0000000..aa92a69
--- /dev/null
+++ b/drivers/clk/clk-m10v.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ * Copyright (C) 2016 Linaro Ltd.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+#define CLKSEL1		0x0
+#define CLKSEL(n)	(((n) - 1) * 4 + CLKSEL1)
+
+#define PLLCNT1		0x30
+#define PLLCNT(n)	(((n) - 1) * 4 + PLLCNT1)
+
+#define CLKSTOP1	0x54
+#define CLKSTOP(n)	(((n) - 1) * 4 + CLKSTOP1)
+
+#define CRSWR		0x8c
+#define CRRRS		0x90
+#define CRRSM		0x94
+
+#define to_m10v_mux(_hw)	container_of(_hw, struct m10v_mux, hw)
+#define to_m10v_gate(_hw)	container_of(_hw, struct m10v_gate, hw)
+#define to_m10v_div(_hw)	container_of(_hw, struct m10v_div, hw)
+#define to_m10v_pll(_hw)	container_of(_hw, struct m10v_pll, hw)
+
+static void __iomem *clk_base;
+static struct device_node *np_top;
+static DEFINE_SPINLOCK(crglock);
+
+static __init void __iomem *m10v_clk_iomap(void)
+{
+	if (clk_base)
+		return clk_base;
+
+	np_top = of_find_compatible_node(NULL, NULL,
+			"socionext,milbeaut-m10v-clk-regs");
+	if (!np_top) {
+		pr_err("%s: CLK iomap failed!\n", __func__);
+		return NULL;
+	}
+
+	clk_base = of_iomap(np_top, 0);
+	of_node_put(np_top);
+
+	return clk_base;
+}
+
+struct m10v_mux {
+	struct clk_hw hw;
+	const char *cname;
+	u32 parent;
+};
+
+static u8 m10v_mux_get_parent(struct clk_hw *hw)
+{
+	struct m10v_mux *mcm = to_m10v_mux(hw);
+	struct clk_hw *parent;
+	int i;
+
+	i = clk_hw_get_num_parents(hw);
+	while (i--) {
+		parent = clk_hw_get_parent_by_index(hw, i);
+		if (clk_hw_get_rate(parent))
+			break;
+	}
+
+	if (i < 0) {
+		pr_info("%s:%s no parent?!\n",
+			__func__, mcm->cname);
+		i = 0;
+	}
+
+	return i;
+}
+
+static int m10v_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct m10v_mux *mcm = to_m10v_mux(hw);
+
+	mcm->parent = index;
+	return 0;
+}
+
+static const struct clk_ops m10v_mux_ops = {
+	.get_parent = m10v_mux_get_parent,
+	.set_parent = m10v_mux_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+};
+
+void __init m10v_clk_mux_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	struct clk_init_data init;
+	const char **parent_names;
+	struct m10v_mux *mcm;
+	struct clk *clk;
+	int i, parents;
+
+	if (!m10v_clk_iomap())
+		return;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	parents = of_clk_get_parent_count(node);
+	if (parents < 2) {
+		pr_err("%s: not a mux\n", clk_name);
+		return;
+	}
+
+	parent_names = kzalloc((sizeof(char *) * parents), GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	for (i = 0; i < parents; i++)
+		parent_names[i] = of_clk_get_parent_name(node, i);
+
+	mcm = kzalloc(sizeof(*mcm), GFP_KERNEL);
+	if (!mcm)
+		goto err_mcm;
+
+	init.name = clk_name;
+	init.ops = &m10v_mux_ops;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	init.num_parents = parents;
+	init.parent_names = parent_names;
+
+	mcm->cname = clk_name;
+	mcm->parent = 0;
+	mcm->hw.init = &init;
+
+	clk = clk_register(NULL, &mcm->hw);
+	if (IS_ERR(clk))
+		goto err_clk;
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	return;
+
+err_clk:
+	kfree(mcm);
+err_mcm:
+	kfree(parent_names);
+}
+CLK_OF_DECLARE(m10v_clk_mux, "socionext,milbeaut-m10v-clk-mux",
+			m10v_clk_mux_setup);
+
+struct m10v_pll {
+	struct clk_hw hw;
+	const char *cname;
+	const struct clk_ops ops;
+	u32 offset;
+	u32 div, mult;
+	bool ro;
+};
+
+#define ST	1
+#define SEL	2
+
+static void _mpg_enable(struct clk_hw *hw, unsigned int enable)
+{
+	struct m10v_pll *mpg = to_m10v_pll(hw);
+	unsigned long flags;
+	u32 val;
+
+	if (mpg->ro) {
+		pr_debug("%s:%d %s: read-only\n",
+			 __func__, __LINE__, mpg->cname);
+		return;
+	}
+
+	spin_lock_irqsave(&crglock, flags);
+
+	val = readl(clk_base + PLLCNT(SEL));
+	if (enable)
+		val |= BIT(mpg->offset);
+	else
+		val &= ~BIT(mpg->offset);
+	writel(val, clk_base + PLLCNT(SEL));
+
+	spin_unlock_irqrestore(&crglock, flags);
+}
+
+static int mpg_enable(struct clk_hw *hw)
+{
+	_mpg_enable(hw, 1);
+	return 0;
+}
+
+static void mpg_disable(struct clk_hw *hw)
+{
+	_mpg_enable(hw, 0);
+}
+
+static int mpg_is_enabled(struct clk_hw *hw)
+{
+	struct m10v_pll *mpg = to_m10v_pll(hw);
+
+	return readl(clk_base + PLLCNT(SEL)) & (1 << mpg->offset);
+}
+
+static void _mpg_prepare(struct clk_hw *hw, unsigned int on)
+{
+	struct m10v_pll *mpg = to_m10v_pll(hw);
+	unsigned long flags;
+	u32 val;
+
+	if (mpg->ro) {
+		pr_debug("%s:%d %s: read-only\n",
+			 __func__, __LINE__, mpg->cname);
+		return;
+	}
+
+	val = readl(clk_base + PLLCNT(ST));
+	if (!on == !(val & BIT(mpg->offset)))
+		return;
+
+	/* disable */
+	mpg_disable(hw);
+
+	spin_lock_irqsave(&crglock, flags);
+
+	val = readl(clk_base + PLLCNT(ST));
+	if (on)
+		val |= BIT(mpg->offset);
+	else
+		val &= ~BIT(mpg->offset);
+	writel(val, clk_base + PLLCNT(ST));
+
+	spin_unlock_irqrestore(&crglock, flags);
+
+	udelay(on ? 200 : 10);
+}
+
+static int mpg_prepare(struct clk_hw *hw)
+{
+	_mpg_prepare(hw, 1);
+	return 0;
+}
+
+static void mpg_unprepare(struct clk_hw *hw)
+{
+	_mpg_prepare(hw, 0);
+}
+
+static int mpg_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long prate)
+{
+	return 0;
+}
+
+static unsigned long mpg_recalc_rate(struct clk_hw *hw,
+		unsigned long prate)
+{
+	struct m10v_pll *mpg = to_m10v_pll(hw);
+	unsigned long long rate = prate;
+
+	if (mpg_is_enabled(hw)) {
+		rate = (unsigned long long)prate * mpg->mult;
+		do_div(rate, mpg->div);
+	}
+
+	return (unsigned long)rate;
+}
+
+static long mpg_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct m10v_pll *mpg = to_m10v_pll(hw);
+	unsigned long long temp_rate = (unsigned long long)*prate * mpg->mult;
+
+	if (mpg->ro)
+		return mpg_recalc_rate(hw, *prate);
+
+	return do_div(temp_rate, mpg->div);
+}
+
+static const struct clk_ops m10v_pll_ops = {
+	.prepare = mpg_prepare,
+	.enable = mpg_enable,
+	.is_enabled = mpg_is_enabled,
+	.disable = mpg_disable,
+	.unprepare = mpg_unprepare,
+	.round_rate = mpg_round_rate,
+	.set_rate = mpg_set_rate,
+	.recalc_rate = mpg_recalc_rate,
+};
+
+void __init m10v_pll_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	struct clk_init_data init;
+	const char *parent_name;
+	u32 offset, div, mult;
+	struct m10v_pll *mpg;
+	struct clk *clk;
+	int ret;
+
+	if (!m10v_clk_iomap())
+		return;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	ret = of_property_read_u32(node, "offset", &offset);
+	if (ret) {
+		pr_err("%s: missing 'offset' property\n", clk_name);
+		return;
+	}
+
+	div = mult = 1;
+	of_property_read_u32(node, "clock-div", &div);
+	of_property_read_u32(node, "clock-mult", &mult);
+
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	mpg = kzalloc(sizeof(*mpg), GFP_KERNEL);
+	if (!mpg)
+		return;
+
+	init.name = clk_name;
+	init.ops = &m10v_pll_ops;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_GATE;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	mpg->cname = clk_name;
+	mpg->offset = offset;
+	mpg->div = div;
+	mpg->mult = mult;
+	mpg->hw.init = &init;
+	if (of_get_property(node, "read-only", NULL))
+		mpg->ro = true;
+
+	clk = clk_register(NULL, &mpg->hw);
+	if (IS_ERR(clk))
+		kfree(mpg);
+	else
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(m10v_clk_pll_gate, "socionext,milbeaut-m10v-pll-fixed-factor",
+		m10v_pll_setup);
+
+struct m10v_div {
+	struct clk_hw hw;
+	const char *cname;
+	bool waitdchreq;
+	u32 offset;
+	u32 mask;
+	u32 *table;
+	u32 tlen;
+	bool ro;
+};
+
+static void mdc_set_div(struct m10v_div *mdc, u32 div)
+{
+	u32 off, shift, val;
+
+	off = mdc->offset / 32 * 4;
+	shift = mdc->offset % 32;
+
+	val = readl(clk_base + CLKSEL1 + off);
+	val &= ~(mdc->mask << shift);
+	val |= (div << shift);
+	writel(val, clk_base + CLKSEL1 + off);
+
+	if (mdc->waitdchreq) {
+		unsigned int count = 250;
+
+		writel(1, clk_base + CLKSEL(11));
+
+		do {
+			udelay(1);
+		} while (--count && readl(clk_base + CLKSEL(11)) & 1);
+
+		if (!count)
+			pr_err("%s:%s CLK(%d) couldn't stabilize\n",
+				__func__, mdc->cname, mdc->offset);
+	}
+}
+
+static u32 mdc_get_div(struct m10v_div *mdc)
+{
+	u32 off, shift, div;
+
+	off = mdc->offset / 32 * 4;
+	shift = mdc->offset % 32;
+
+	div = readl(clk_base + CLKSEL1 + off);
+	div >>= shift;
+	div &= mdc->mask;
+
+	return div;
+}
+
+static int mdc_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long prate)
+{
+	struct m10v_div *mdc = to_m10v_div(hw);
+	u64 pr;
+	int i;
+
+	if (mdc->ro) {
+		pr_debug("%s:%d %s: read-only\n",
+			 __func__, __LINE__, mdc->cname);
+		return 0;
+	}
+
+	/* divisors are already in descending order in DT */
+	for (i = mdc->tlen - 2; i >= 0; i -= 2) {
+		pr = prate;
+		do_div(pr, mdc->table[i]);
+
+		if (rate >= pr)
+			break;
+	}
+	if (i < 0)
+		i = 0;
+
+	mdc_set_div(mdc, mdc->table[i + 1]);
+
+	return 0;
+}
+
+static unsigned long mdc_div_recalc_rate(struct clk_hw *hw,
+		unsigned long prate)
+{
+	struct m10v_div *mdc = to_m10v_div(hw);
+	u64 prate64 = prate;
+	u32 div;
+	int i;
+
+	div = mdc_get_div(mdc);
+
+	for (i = 1; i < mdc->tlen && div != mdc->table[i]; i += 2)
+		if (div == (mdc->table[i] & mdc->mask))
+			break; /* the MSB is already read back as 0 */
+
+	if (i > mdc->tlen) /* some other is enabled in the mux */
+		prate64 = 0;
+	else
+		do_div(prate64, mdc->table[i - 1]);
+
+	return (unsigned long)prate64;
+}
+
+static long mdc_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent)
+{
+	struct m10v_div *mdc = to_m10v_div(hw);
+	u64 prate;
+	int i;
+
+	if (mdc->ro)
+		return mdc_div_recalc_rate(hw, *parent);
+
+	/* divisors are already in descending order in DT */
+	for (i = mdc->tlen - 2; i >= 0; i -= 2) {
+		prate = *parent;
+		do_div(prate, mdc->table[i]);
+
+		if (rate >= prate)
+			break;
+	}
+
+	return (unsigned long)prate;
+}
+
+static const struct clk_ops m10v_div_ops = {
+	.round_rate = mdc_div_round_rate,
+	.set_rate = mdc_div_set_rate,
+	.recalc_rate = mdc_div_recalc_rate,
+};
+
+void __init m10v_clk_div_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	struct clk_init_data init;
+	const char *parent_name;
+	struct m10v_div *mdc;
+	struct clk *clk;
+	u32 *table, mask;
+	u32 offset;
+	int count, ret;
+
+	if (!m10v_clk_iomap())
+		return;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	parent_name = of_clk_get_parent_name(node, 0);
+	if (!parent_name) {
+		pr_err("%s: no parent specified\n", clk_name);
+		return;
+	}
+
+	ret = of_property_read_u32(node, "offset", &offset);
+	if (ret) {
+		pr_err("%s: missing 'offset' property\n", clk_name);
+		return;
+	}
+
+	ret = of_property_read_u32(node, "mask", &mask);
+	if (ret) {
+		pr_err("%s: missing 'mask' property\n", clk_name);
+		return;
+	}
+
+	count = of_property_count_u32_elems(node, "ratios");
+	if (count < 2 || count%2) {
+		pr_err("%s: invalid 'ratios' property\n", clk_name);
+		return;
+	}
+
+	table = kzalloc(sizeof(*table) * count, GFP_KERNEL);
+	if (!table)
+		return;
+
+	/*
+	 * The 'ratios' must be in descending order, we park at
+	 * first ratio (biggest divider) when disabled.
+	 */
+	ret = of_property_read_u32_array(node, "ratios", table, count);
+	if (ret) {
+		pr_err("%s: 'ratios' property read fail\n", clk_name);
+		goto err_mdc;
+	}
+
+	mdc = kzalloc(sizeof(*mdc), GFP_KERNEL);
+	if (!mdc)
+		goto err_mdc;
+
+	if (of_get_property(node, "wait-on-dchreq", NULL))
+		mdc->waitdchreq = true;
+
+	init.name = clk_name;
+	init.ops = &m10v_div_ops;
+	init.flags = CLK_IS_BASIC;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	mdc->cname = clk_name;
+	mdc->offset = offset;
+	mdc->mask = mask;
+	mdc->table = table;
+	mdc->tlen = count;
+	mdc->hw.init = &init;
+	if (of_get_property(node, "read-only", NULL))
+		mdc->ro = true;
+
+	clk = clk_register(NULL, &mdc->hw);
+	if (IS_ERR(clk))
+		goto err_clk;
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	return;
+
+err_clk:
+	kfree(mdc);
+err_mdc:
+	kfree(table);
+}
+CLK_OF_DECLARE(m10v_clk_div, "socionext,milbeaut-m10v-clk-div",
+			m10v_clk_div_setup);
+
+struct m10v_gate {
+	struct clk_hw hw;
+	const char *cname;
+	u32 offset;
+	bool ro;
+};
+
+static void _mgc_enable(struct clk_hw *hw, bool en)
+{
+	struct m10v_gate *mgc = to_m10v_gate(hw);
+	u32 off, mask;
+
+	if (mgc->ro) {
+		pr_debug("%s:%d %s: read-only\n",
+			 __func__, __LINE__, mgc->cname);
+		return;
+	}
+
+	off = CLKSTOP1 + (mgc->offset / 32) * 4;
+
+	mask = (en ? 2 : 3) << (mgc->offset % 32);
+
+	writel(mask, clk_base + off);
+}
+
+static int mgc_enable(struct clk_hw *hw)
+{
+	_mgc_enable(hw, true);
+	return 0;
+}
+
+static void mgc_disable(struct clk_hw *hw)
+{
+	_mgc_enable(hw, false);
+}
+
+static int mgc_is_enabled(struct clk_hw *hw)
+{
+	struct m10v_gate *mgc = to_m10v_gate(hw);
+	u32 off, val, mask = 1 << (mgc->offset % 32);
+
+	off = CLKSTOP1 + (mgc->offset / 32) * 4;
+	val = readl(clk_base + off);
+
+	return !(val & mask);
+}
+
+static const struct clk_ops m10v_gate_ops = {
+	.enable = mgc_enable,
+	.disable = mgc_disable,
+	.is_enabled = mgc_is_enabled,
+};
+
+void __init m10v_clk_gate_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	struct clk_init_data init;
+	const char *parent_name;
+	struct m10v_gate *mgc;
+	struct clk *clk;
+	u32 offset;
+	int ret;
+
+	if (!m10v_clk_iomap())
+		return;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	ret = of_property_read_u32(node, "offset", &offset);
+	if (ret) {
+		pr_err("%s: missing 'offset' property\n", clk_name);
+		return;
+	}
+
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	mgc = kzalloc(sizeof(*mgc), GFP_KERNEL);
+	if (!mgc)
+		return;
+
+	init.name = clk_name;
+	init.ops = &m10v_gate_ops;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	mgc->cname = clk_name;
+	mgc->offset = offset;
+	mgc->hw.init = &init;
+	if (of_get_property(node, "read-only", NULL))
+		mgc->ro = true;
+
+	clk = clk_register(NULL, &mgc->hw);
+	if (IS_ERR(clk))
+		kfree(mgc);
+	else
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(m10v_clk_gate, "socionext,milbeaut-m10v-clk-gate",
+		m10v_clk_gate_setup);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 06/14] dt-bindings: clock: milbeaut: add Milbeaut clock description
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add DT bindings document for Milbeaut clock.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../devicetree/bindings/clock/milbeaut-clock.txt   | 93 ++++++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/milbeaut-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/milbeaut-clock.txt b/Documentation/devicetree/bindings/clock/milbeaut-clock.txt
new file mode 100644
index 0000000..5c093c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/milbeaut-clock.txt
@@ -0,0 +1,93 @@
+Milbeaut M10V Clock Controller Binding
+----------------------------------------
+Milbeaut clock controller is consists of few oscillators, PLL, multiplexer
+and few divider modules
+
+This binding uses common clock bindings
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible: shall be "socionext,milbeaut-m10v-clk-regs"
+- reg: shall contain base address and length of clock registers
+- #clock-cells: shall be 0
+
+Example:
+	m10v-clk-tree@ {
+		compatible = "socionext,milbeaut-m10v-clk-regs";
+		reg = <0x1d021000 0x4000>;
+
+		clocks {
+			#address-cells = <0>;
+			#size-cells = <0>;
+
+			uclk40xi: uclk40xi {
+				compatible = "fixed-clock";
+				#clock-cells = <0>;
+				clock-frequency = <40000000>;
+			};
+		};
+	}
+
+The clock consumer shall specify the desired clock-output of the clock
+controller (as defined in [2]) by specifying output-id in its "clock"
+phandle cell
+[2] arch/arm/boot/dts/milbeaut-m10v-clk.h
+
+For example for UART1:
+	usio1:  usio_uart@1e700010 {
+		index = <0>;
+		compatible = "socionext,milbeaut-m10v-usio-uart";
+		reg = <0x1e700010 0x10>;
+		interrupts = <0 141 0x4>, <0 149 0x4>;
+		interrupt-names = "rx", "tx";
+		clocks = <&hclk>;
+	};
+
+
+
+
+Required properties:
+- compatible:
+	"socionext,milbeaut-m10v-clk-mux"
+		-clock-cells: should be 0
+		-clocks: should be two factor
+	"socionext,milbeaut-m10v-pll-fixed-factor"
+		-clock-cells: should be 0
+		-clocks: should be one factor
+		-offset: offset
+		-clock-div: div number
+		-clock-mult: multiple number
+	"socionext,milbeaut-m10v-clk-div"
+		-clock-cells: should be 0
+		-clocks: should be one factor
+		-offset: offset
+		-mask: mask bit
+		-ratios: div ratio
+
+Example
+	piclk_mux_0: spiclk_mux_0 {
+		compatible = "socionext,m10v-clk-div";
+		#clock-cells = <0>;
+		clocks = <&pll10_div_1_2>;
+		offset = <bSPICLK>;
+		mask = <0x3>;
+		ratios = <4 0x5 2 0x4>;
+	};
+
+	pll10: pll10 {
+		compatible = "socionext,m10v-pll-fixed-factor";
+		#clock-cells = <0>;
+		clocks = <&uclk40xi>;
+		offset = <10>;
+		clock-div = <5>;
+		clock-mult = <108>;
+	};
+
+	emmcclk: emmcclk {
+		compatible = "socionext,m10v-clk-div";
+		#clock-cells = <0>;
+		clocks = <&pll11>;
+		offset = <bEMMCCLK>;
+		mask = <0x3>;
+		ratios = <15 0x7 10 0x6 9 0x5 8 0x4>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 05/14] clocksource/drivers/timer-milbeaut: Add Milbeaut M10V timer
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add Milbeaut M10V timer using 32bit timer in peripheral.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 drivers/clocksource/Kconfig      |   8 +++
 drivers/clocksource/Makefile     |   1 +
 drivers/clocksource/timer-m10v.c | 146 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 drivers/clocksource/timer-m10v.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 55c77e4..a278d72 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -638,4 +638,12 @@ config GX6605S_TIMER
 	help
 	  This option enables support for gx6605s SOC's timer.
 
+config M10V_TIMER
+	bool "Milbeaut M10V timer driver" if COMPILE_TEST
+	depends on OF
+	depends on ARM
+	select TIMER_OF
+	help
+	  Enables the support for Milbeaut M10V timer driver.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index dd91381..8e908b4 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_CLKSRC_TI_32K)	+= timer-ti-32k.o
 obj-$(CONFIG_CLKSRC_NPS)	+= timer-nps.o
 obj-$(CONFIG_OXNAS_RPS_TIMER)	+= timer-oxnas-rps.o
 obj-$(CONFIG_OWL_TIMER)		+= timer-owl.o
+obj-$(CONFIG_M10V_TIMER)	+= timer-m10v.o
 obj-$(CONFIG_SPRD_TIMER)	+= timer-sprd.o
 obj-$(CONFIG_NPCM7XX_TIMER)	+= timer-npcm7xx.o
 
diff --git a/drivers/clocksource/timer-m10v.c b/drivers/clocksource/timer-m10v.c
new file mode 100644
index 0000000..ff97c23
--- /dev/null
+++ b/drivers/clocksource/timer-m10v.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include "timer-of.h"
+
+#define FSL_TMR_TMCSR_OFS	0x0
+#define FSL_TMR_TMR_OFS		0x4
+#define FSL_TMR_TMRLR1_OFS	0x8
+#define FSL_TMR_TMRLR2_OFS	0xc
+#define FSL_RMT_REGSZPCH	0x10
+
+#define FSL_TMR_TMCSR_OUTL	BIT(5)
+#define FSL_TMR_TMCSR_RELD	BIT(4)
+#define FSL_TMR_TMCSR_INTE	BIT(3)
+#define FSL_TMR_TMCSR_UF	BIT(2)
+#define FSL_TMR_TMCSR_CNTE	BIT(1)
+#define FSL_TMR_TMCSR_TRG	BIT(0)
+
+#define FSL_TMR_TMCSR_CSL_DIV2	0
+#define FSL_TMR_TMCSR_CSL	BIT(10)
+
+#define M10V_TIMER_RATING	500
+
+static irqreturn_t m10v_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *clk = dev_id;
+	struct timer_of *to = to_timer_of(clk);
+	u32 val;
+
+	val = readl_relaxed(timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+	val &= ~FSL_TMR_TMCSR_UF;
+	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+
+	clk->event_handler(clk);
+
+	return IRQ_HANDLED;
+}
+
+static int m10v_set_state_periodic(struct clock_event_device *clk)
+{
+	struct timer_of *to = to_timer_of(clk);
+	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);
+
+	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+
+	writel_relaxed(to->of_clk.period, timer_of_base(to) +
+				FSL_TMR_TMRLR1_OFS);
+	val |= FSL_TMR_TMCSR_RELD | FSL_TMR_TMCSR_CNTE |
+		FSL_TMR_TMCSR_TRG | FSL_TMR_TMCSR_INTE;
+	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+	return 0;
+}
+
+static int m10v_set_state_oneshot(struct clock_event_device *clk)
+{
+	struct timer_of *to = to_timer_of(clk);
+	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);
+
+	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+	return 0;
+}
+
+static int m10v_clkevt_next_event(unsigned long event,
+				   struct clock_event_device *clk)
+{
+	struct timer_of *to = to_timer_of(clk);
+
+	writel_relaxed(event, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
+	writel_relaxed((FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL) |
+			FSL_TMR_TMCSR_CNTE | FSL_TMR_TMCSR_INTE |
+			FSL_TMR_TMCSR_TRG, timer_of_base(to) +
+			FSL_TMR_TMCSR_OFS);
+	return 0;
+}
+
+static int m10v_config_clock_source(struct timer_of *to)
+{
+	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMR_OFS);
+	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
+	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR2_OFS);
+	writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) +
+		FSL_TMR_TMCSR_OFS);
+	return 0;
+}
+
+static int m10v_config_clock_event(struct timer_of *to)
+{
+	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
+	return 0;
+}
+
+static struct timer_of to = {
+	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
+
+	.clkevt = {
+		.name = "m10v-clkevt",
+		.rating = M10V_TIMER_RATING,
+		.cpumask = cpu_possible_mask,
+	},
+
+	.of_irq = {
+		.flags = IRQF_TIMER | IRQF_IRQPOLL,
+	},
+};
+
+static int __init m10v_timer_init(struct device_node *node)
+{
+	int ret;
+
+	to.clkevt.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT;
+	to.clkevt.set_state_oneshot = m10v_set_state_oneshot;
+	to.clkevt.set_state_periodic = m10v_set_state_periodic;
+	to.clkevt.set_next_event = m10v_clkevt_next_event;
+	to.of_irq.handler = m10v_timer_interrupt;
+
+	ret = timer_of_init(node, &to);
+	if (ret)
+		goto err;
+
+	m10v_config_clock_source(&to);
+	clocksource_mmio_init(timer_of_base(&to) + FSL_TMR_TMR_OFS,
+		node->name, timer_of_rate(&to), M10V_TIMER_RATING, 32,
+		clocksource_mmio_readl_down);
+	m10v_config_clock_event(&to);
+	clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
+				15, 0xffffffff);
+
+	return 0;
+err:
+	timer_of_cleanup(&to);
+	return ret;
+}
+TIMER_OF_DECLARE(m10v_peritimer, "socionext,milbeaut-m10v-timer",
+		m10v_timer_init);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 04/14] dt-bindings: timer: Add Milbeaut M10V timer description
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Mark Rutland, Sugaya Taichi, Masami Hiramatsu, Stephen Boyd,
	Greg Kroah-Hartman, Michael Turquette, Daniel Lezcano,
	Russell King, Jassi Brar, Rob Herring, Jiri Slaby,
	Thomas Gleixner
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add DT bindings document for Milbeaut M10V timer.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../bindings/timer/socionext,milbeaut-timer.txt         | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt b/Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt
new file mode 100644
index 0000000..ddb1b31
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt
@@ -0,0 +1,17 @@
+Milbeaut SoCs Timer Controller
+
+Required properties:
+
+- compatible : should be "socionext,milbeaut-m10v-timer"
+- reg : Specifies base physical address and size of the registers.
+- interrupts : The interrupt of the first timer
+- clocks: should be "rclk"
+
+Example:
+
+timer {
+	compatible = "socionext,milbeaut-m10v-timer";
+	reg = <0x1e000050 0x10>, <0x1e000060 0x10>;
+	interrupts = <0 91 4>;
+	clocks = <&rclk>;
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 03/14] ARM: milbeaut: Add Milbeaut M10V early printk
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add Milbeaut M10V earlyprintk.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 arch/arm/Kconfig.debug            | 12 ++++++++++--
 arch/arm/include/debug/milbeaut.S | 25 +++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/include/debug/milbeaut.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index d6a49f5..5c44533 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1413,6 +1413,11 @@ choice
 		  options; the platform specific options are deprecated
 		  and will be soon removed.
 
+	config DEBUG_LL_MILBEAUT_UART
+		bool "Kernel low-level debug output via USIO"
+		depends on ARCH_MILBEAUT
+		help
+		  Say Y here if you want to debug with USIO
 endchoice
 
 config DEBUG_AT91_UART
@@ -1534,6 +1539,7 @@ config DEBUG_LL_INCLUDE
 	default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART
 	default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
 	default "debug/brcmstb.S" if DEBUG_BRCMSTB_UART
+	default "debug/milbeaut.S" if DEBUG_LL_MILBEAUT_UART
 	default "mach/debug-macro.S"
 
 # Compatibility options for PL01x
@@ -1580,6 +1586,7 @@ config DEBUG_UART_PHYS
 	default 0x18020000 if DEBUG_SIRFATLAS7_UART1
 	default 0x18023000 if DEBUG_BCM_IPROC_UART3
 	default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
+	default 0x1e700010 if ARCH_MILBEAUT_M10V
 	default 0x20001000 if DEBUG_HIP01_UART
 	default 0x20060000 if DEBUG_RK29_UART0
 	default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
@@ -1681,7 +1688,7 @@ config DEBUG_UART_PHYS
 		DEBUG_S3C64XX_UART || \
 		DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \
 		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
-		DEBUG_AT91_UART
+		DEBUG_AT91_UART || DEBUG_LL_MILBEAUT_UART
 
 config DEBUG_UART_VIRT
 	hex "Virtual base address of debug UART"
@@ -1755,6 +1762,7 @@ config DEBUG_UART_VIRT
 	default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART
 	default 0xfe230000 if DEBUG_PICOXCELL_UART
 	default 0xfe300000 if DEBUG_BCM_KONA_UART
+	default 0xfe700010 if ARCH_MILBEAUT_M10V
 	default 0xfe800000 if ARCH_IOP32X
 	default 0xfeb00000 if DEBUG_HI3620_UART || DEBUG_HIX5HD2_UART
 	default 0xfeb24000 if DEBUG_RK3X_UART0
@@ -1796,7 +1804,7 @@ config DEBUG_UART_VIRT
 		DEBUG_S3C64XX_UART || \
 		DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \
 		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
-		DEBUG_AT91_UART
+		DEBUG_AT91_UART || DEBUG_LL_MILBEAUT_UART
 
 config DEBUG_UART_8250_SHIFT
 	int "Register offset shift for the 8250 debug UART"
diff --git a/arch/arm/include/debug/milbeaut.S b/arch/arm/include/debug/milbeaut.S
new file mode 100644
index 0000000..0660e0f
--- /dev/null
+++ b/arch/arm/include/debug/milbeaut.S
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ */
+
+	.macro addruart, rp, rv, tmp
+	ldr	\rp, =CONFIG_DEBUG_UART_PHYS
+	ldr	\rv, =CONFIG_DEBUG_UART_VIRT
+	.endm
+
+	.macro senduart,rd,rx
+	strh    \rd, [\rx, #0x04]               @ write to TxData register
+	.endm
+
+	.macro waituart,rd,rx
+1:	ldrb    \rd, [\rx, #0x03]               @ SSR
+	tst     \rd, #1 << 1                    @ check TDRE bit
+	beq     1b
+	.endm
+
+	.macro busyuart,rd,rx
+2:	ldrb    \rd, [\rx, #0x03]               @ SSR
+	tst     \rd, #1 << 1                    @ check TEMT bit
+	beq     2b
+	.endm
-- 
1.9.1

^ permalink raw reply related

* [PATCH 02/14] dt-bindings: soc: milbeaut: Add Milbeaut trampoline description
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

Add DT bindings document for Milbeaut trampoline.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 .../devicetree/bindings/soc/socionext/socionext,m10v.txt     | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/socionext/socionext,m10v.txt

diff --git a/Documentation/devicetree/bindings/soc/socionext/socionext,m10v.txt b/Documentation/devicetree/bindings/soc/socionext/socionext,m10v.txt
new file mode 100644
index 0000000..f5d906c
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/socionext/socionext,m10v.txt
@@ -0,0 +1,12 @@
+Socionext M10V SMP trampoline driver binding
+
+This is a driver to wait for sub-cores while boot process.
+
+- compatible: should be "socionext,smp-trampoline"
+- reg: should be <0x4C000100 0x100>
+
+EXAMPLE
+	trampoline: trampoline@0x4C000100 {
+		compatible = "socionext,smp-trampoline";
+		reg = <0x4C000100 0x100>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 01/14] ARM: milbeaut: Add basic support for Milbeaut m10v SoC
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi
In-Reply-To: <1542589274-13878-1-git-send-email-sugaya.taichi@socionext.com>

This adds the basic M10V SoC support under arch/arm.
Since all cores are activated in the custom bootloader before booting
linux, it is necessary to wait for sub-cores using the trampoline area.

Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
---
 arch/arm/Kconfig                  |   2 +
 arch/arm/Makefile                 |   1 +
 arch/arm/mach-milbeaut/Kconfig    |  28 +++++++
 arch/arm/mach-milbeaut/Makefile   |   3 +
 arch/arm/mach-milbeaut/m10v_evb.c |  31 ++++++++
 arch/arm/mach-milbeaut/platsmp.c  | 157 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 222 insertions(+)
 create mode 100644 arch/arm/mach-milbeaut/Kconfig
 create mode 100644 arch/arm/mach-milbeaut/Makefile
 create mode 100644 arch/arm/mach-milbeaut/m10v_evb.c
 create mode 100644 arch/arm/mach-milbeaut/platsmp.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 91be74d..0b8a1af 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -767,6 +767,8 @@ source "arch/arm/mach-mediatek/Kconfig"
 
 source "arch/arm/mach-meson/Kconfig"
 
+source "arch/arm/mach-milbeaut/Kconfig"
+
 source "arch/arm/mach-mmp/Kconfig"
 
 source "arch/arm/mach-moxart/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 05a91d8..627853c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -190,6 +190,7 @@ machine-$(CONFIG_ARCH_MV78XX0)		+= mv78xx0
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_MXC)		+= imx
 machine-$(CONFIG_ARCH_MEDIATEK)		+= mediatek
+machine-$(CONFIG_ARCH_MILBEAUT)		+= milbeaut
 machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
diff --git a/arch/arm/mach-milbeaut/Kconfig b/arch/arm/mach-milbeaut/Kconfig
new file mode 100644
index 0000000..63b6f69
--- /dev/null
+++ b/arch/arm/mach-milbeaut/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig ARCH_MILBEAUT
+	bool "Socionext Milbeaut SoCs"
+	depends on ARCH_MULTI_V7
+	select ARM_GIC
+	select CLKDEV_LOOKUP
+	select GENERIC_CLOCKEVENTS
+	select CLKSRC_MMIO
+	select ZONE_DMA
+	help
+		This enables support for Socionext Milbeaut SoCs
+
+if ARCH_MILBEAUT
+
+config ARCH_MILBEAUT_M10V
+	bool "Milbeaut SC2000/M10V platform"
+	select ARM_ARCH_TIMER
+	select M10V_TIMER
+	select PINCTRL
+	select PINCTRL_M10V
+	help
+	  Support for Socionext's MILBEAUT M10V based systems
+
+config MACH_M10V_EVB
+	bool "Support for Milbeaut Evaluation boards"
+	default y
+
+endif
diff --git a/arch/arm/mach-milbeaut/Makefile b/arch/arm/mach-milbeaut/Makefile
new file mode 100644
index 0000000..64f6f52
--- /dev/null
+++ b/arch/arm/mach-milbeaut/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_MACH_M10V_EVB) += m10v_evb.o
+
diff --git a/arch/arm/mach-milbeaut/m10v_evb.c b/arch/arm/mach-milbeaut/m10v_evb.c
new file mode 100644
index 0000000..a1fa7c3
--- /dev/null
+++ b/arch/arm/mach-milbeaut/m10v_evb.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ * Copyright:   (C) 2015 Linaro Ltd.
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+static struct map_desc m10v_io_desc[] __initdata = {
+};
+
+void __init m10v_map_io(void)
+{
+	debug_ll_io_init();
+	iotable_init(m10v_io_desc, ARRAY_SIZE(m10v_io_desc));
+}
+
+static const char * const m10v_compat[] = {
+	"socionext,milbeaut-m10v-evb",
+	NULL,
+};
+
+DT_MACHINE_START(M10V_REB, "Socionext Milbeaut")
+	.dt_compat	= m10v_compat,
+	.l2c_aux_mask	= 0xffffffff,
+	.map_io		= m10v_map_io,
+MACHINE_END
diff --git a/arch/arm/mach-milbeaut/platsmp.c b/arch/arm/mach-milbeaut/platsmp.c
new file mode 100644
index 0000000..b706851
--- /dev/null
+++ b/arch/arm/mach-milbeaut/platsmp.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Socionext Inc.
+ * Copyright:	(C) 2015 Linaro Ltd.
+ */
+
+#include <linux/cpu_pm.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
+#include <asm/idmap.h>
+#include <asm/smp_plat.h>
+#include <asm/suspend.h>
+
+#define M10V_MAX_CPU	4
+
+#define KERNEL_UNBOOT_FLAG	0x12345678
+#define CPU_FINISH_SUSPEND_FLAG 0x56784321
+
+static void __iomem *trampoline;
+
+static int m10v_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = cpu_logical_map(l_cpu);
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	if (cpu >= M10V_MAX_CPU)
+		return -EINVAL;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+
+	writel(virt_to_phys(secondary_startup), trampoline + cpu * 4);
+	arch_send_wakeup_ipi_mask(cpumask_of(l_cpu));
+
+	return 0;
+}
+
+static void m10v_cpu_die(unsigned int l_cpu)
+{
+	gic_cpu_if_down(0);
+
+	v7_exit_coherency_flush(louis);
+
+	/* Now we are prepared for power-down, do it: */
+	wfi();
+}
+
+static int m10v_cpu_kill(unsigned int l_cpu)
+{
+	unsigned int mpidr, cpu;
+
+	mpidr = cpu_logical_map(l_cpu);
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+
+	writel(KERNEL_UNBOOT_FLAG, trampoline + cpu * 4);
+
+	return 1;
+}
+
+static struct smp_operations m10v_smp_ops __initdata = {
+	.smp_boot_secondary	= m10v_boot_secondary,
+	.cpu_die		= m10v_cpu_die,
+	.cpu_kill		= m10v_cpu_kill,
+};
+
+static int __init m10v_smp_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "socionext,milbeaut-m10v-evb");
+	if (!np || !of_device_is_available(np))
+		return -ENODEV;
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, NULL, "socionext,smp-trampoline");
+	if (!np)
+		return -ENODEV;
+
+	trampoline = of_iomap(np, 0);
+	if (!trampoline)
+		return -ENODEV;
+	of_node_put(np);
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	pr_info("MCPM boot on cpu_%u cluster_%u\n", cpu, cluster);
+
+	for (cpu = 0; cpu < M10V_MAX_CPU; cpu++)
+		writel(KERNEL_UNBOOT_FLAG, trampoline + cpu * 4);
+
+	smp_set_ops(&m10v_smp_ops);
+
+	return 0;
+}
+early_initcall(m10v_smp_init);
+
+static int m10v_pm_valid(suspend_state_t state)
+{
+	return (state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM);
+}
+
+typedef void (*phys_reset_t)(unsigned long);
+static phys_reset_t phys_reset;
+
+static int m10v_die(unsigned long arg)
+{
+	setup_mm_for_reboot();
+	asm("wfi");
+	/* Boot just like a secondary */
+	phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+	phys_reset(virt_to_phys(cpu_resume));
+
+	return 0;
+}
+
+static int m10v_pm_enter(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		pr_err("STANDBY\n");
+		asm("wfi");
+		break;
+	case PM_SUSPEND_MEM:
+		pr_err("SUSPEND\n");
+		cpu_pm_enter();
+		cpu_suspend(0, m10v_die);
+		cpu_pm_exit();
+		break;
+	}
+	return 0;
+}
+
+static const struct platform_suspend_ops m10v_pm_ops = {
+	.valid		= m10v_pm_valid,
+	.enter		= m10v_pm_enter,
+};
+
+struct clk *m10v_clclk_register(struct device *cpu_dev);
+
+static int __init m10v_pm_init(void)
+{
+	suspend_set_ops(&m10v_pm_ops);
+
+	return 0;
+}
+late_initcall(m10v_pm_init);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 00/14] Add basic support for Socionext Milbeaut M10V SoCs
From: Sugaya Taichi @ 2018-11-19  1:01 UTC (permalink / raw)
  To: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Daniel Lezcano, Thomas Gleixner, Russell King,
	Jiri Slaby, Masami Hiramatsu, Jassi Brar, Sugaya Taichi

Hi,

Here is the series of patches the initial support for SC2000(M10V) of
Milbeaut SoCs. "M10V" is the internal name of SC2000, so commonly used in
source code.

SC2000 is a SoC of the Milbeaut series. equipped with a DSP optimized for
computer vision. It also features advanced functionalities such as 360-degree,
real-time spherical stitching with multi cameras, image stabilization for
without mechanical gimbals, and rolling shutter correction. More detail is
below:
https://www.socionext.com/en/products/assp/milbeaut/SC2000.html

Specifications for developers are below:
 - Quad-core 32bit Cortex-A7 on ARMv7-A architecture
 - NEON support
 - DSP
 - GPU
 - MAX 3GB DDR3
 - Cortex-M0 for power control
 - NAND Flash Interface
 - SD UHS-I
 - SD UHS-II
 - SDIO
 - USB2.0 HOST / Device
 - USB3.0 HOST / Device
 - PCI express Gen2
 - Ethernet Engine
 - I2C
 - UART
 - SPI
 - PWM

Support is quite minimal for now, since it only includes timer, clock,
pictrl and serial controller drivers, so we can only boot to userspace
through initramfs. Support for the other peripherals  will come eventually.


Sugaya Taichi (14):
  ARM: milbeaut: Add basic support for Milbeaut m10v SoC
  dt-bindings: soc: milbeaut: Add Milbeaut trampoline description
  ARM: milbeaut: Add Milbeaut M10V early printk
  dt-bindings: timer: Add Milbeaut M10V timer description
  clocksource/drivers/timer-milbeaut: Add Milbeaut M10V timer
  dt-bindings: clock: milbeaut: add Milbeaut clock description
  clock: milbeaut: Add Milbeaut M10V clock control
  dt-bindings: serial: Add Milbeaut M10V serial description
  serial: Add Milbeaut M10V serial control
  dt-bindings: pinctrl: milbeaut: Add Milbeaut M10V pinctrl description
  pinctrl: milbeaut: Add Milbeaut M10V pinctrl
  ARM: dts: milbeaut: Add device tree set for the Milbeaut M10V board
  ARM: configs: Add Milbeaut M10V defconfig
  MAINTAINERS: Add entry to MAINTAINERS for Milbeaut

 .../devicetree/bindings/clock/milbeaut-clock.txt   |  93 +++
 .../pinctrl/socionext,milbeaut-pinctrl.txt         |  33 +
 .../devicetree/bindings/serial/milbeaut-uart.txt   |  23 +
 .../bindings/soc/socionext/socionext,m10v.txt      |  12 +
 .../bindings/timer/socionext,milbeaut-timer.txt    |  17 +
 MAINTAINERS                                        |   9 +
 arch/arm/Kconfig                                   |   2 +
 arch/arm/Kconfig.debug                             |  12 +-
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/milbeaut-m10v-evb.dts            |  35 +
 arch/arm/boot/dts/milbeaut-m10v-evb.dtsi           |  17 +
 arch/arm/boot/dts/milbeaut-m10v.dtsi               | 510 ++++++++++++++
 arch/arm/configs/milbeaut_m10v_defconfig           | 364 ++++++++++
 arch/arm/include/debug/milbeaut.S                  |  25 +
 arch/arm/mach-milbeaut/Kconfig                     |  28 +
 arch/arm/mach-milbeaut/Makefile                    |   3 +
 arch/arm/mach-milbeaut/m10v_evb.c                  |  31 +
 arch/arm/mach-milbeaut/platsmp.c                   | 157 +++++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-m10v.c                             | 671 ++++++++++++++++++
 drivers/clocksource/Kconfig                        |   8 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-m10v.c                   | 146 ++++
 drivers/pinctrl/Kconfig                            |   9 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/pinctrl-m10v.c                     | 765 +++++++++++++++++++++
 drivers/tty/serial/Kconfig                         |  24 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/m10v_usio.c                     | 605 ++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 31 files changed, 3606 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/milbeaut-clock.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/socionext,milbeaut-pinctrl.txt
 create mode 100644 Documentation/devicetree/bindings/serial/milbeaut-uart.txt
 create mode 100644 Documentation/devicetree/bindings/soc/socionext/socionext,m10v.txt
 create mode 100644 Documentation/devicetree/bindings/timer/socionext,milbeaut-timer.txt
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v-evb.dts
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v-evb.dtsi
 create mode 100644 arch/arm/boot/dts/milbeaut-m10v.dtsi
 create mode 100644 arch/arm/configs/milbeaut_m10v_defconfig
 create mode 100644 arch/arm/include/debug/milbeaut.S
 create mode 100644 arch/arm/mach-milbeaut/Kconfig
 create mode 100644 arch/arm/mach-milbeaut/Makefile
 create mode 100644 arch/arm/mach-milbeaut/m10v_evb.c
 create mode 100644 arch/arm/mach-milbeaut/platsmp.c
 create mode 100644 drivers/clk/clk-m10v.c
 create mode 100644 drivers/clocksource/timer-m10v.c
 create mode 100644 drivers/pinctrl/pinctrl-m10v.c
 create mode 100644 drivers/tty/serial/m10v_usio.c

-- 
1.9.1

^ permalink raw reply

* Re: [PATCH v2 01/10] mailbox: Support blocking transfers in atomic context
From: Jassi Brar @ 2018-11-17 17:27 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Devicetree List, Greg KH, mliljeberg, Mikko Perttunen, talho,
	linux-serial, jslaby, linux-tegra, ppessi, Jon Hunter,
	linux-arm-kernel
In-Reply-To: <20181112151853.29289-2-thierry.reding@gmail.com>

On Mon, Nov 12, 2018 at 9:18 AM Thierry Reding <thierry.reding@gmail.com> wrote:
>
> From: Thierry Reding <treding@nvidia.com>
>
> The mailbox framework supports blocking transfers via completions for
> clients that can sleep. In order to support blocking transfers in cases
> where the transmission is not permitted to sleep, add a new ->flush()
> callback that controller drivers can implement to busy loop until the
> transmission has been completed. This will automatically be called when
> available and interrupts are disabled for clients that request blocking
> transfers.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  drivers/mailbox/mailbox.c          | 8 ++++++++
>  include/linux/mailbox_controller.h | 4 ++++
>  2 files changed, 12 insertions(+)
>
> diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> index 674b35f402f5..0eaf21259874 100644
> --- a/drivers/mailbox/mailbox.c
> +++ b/drivers/mailbox/mailbox.c
> @@ -267,6 +267,14 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
>                 unsigned long wait;
>                 int ret;
>
> +               if (irqs_disabled() && chan->mbox->ops->flush) {
> +                       ret = chan->mbox->ops->flush(chan, chan->cl->tx_tout);
> +                       if (ret < 0)
> +                               tx_tick(chan, ret);
> +
> +                       return ret;
> +               }
> +
This is hacky. I think we can do without busy waiting in atomic
context. You could queue locally while in atomic context and then
transfer in blocking mode. I don't think we should worry about the
'throughput' as there already is no h/w rate control even with
busy-waiting.

Thanks.

^ permalink raw reply

* Re: [PATCH v2 1/2] dt-bindings: serial: add documentation for the SiFive UART driver
From: Paul Walmsley @ 2018-11-16 23:10 UTC (permalink / raw)
  To: Rob Herring
  Cc: Paul Walmsley, open list:SERIAL DRIVERS, devicetree, linux-riscv,
	linux-kernel@vger.kernel.org, Greg Kroah-Hartman, Mark Rutland,
	Palmer Dabbelt, Paul Walmsley
In-Reply-To: <20181024173232.GB5652@bogus>

[-- Attachment #1: Type: text/plain, Size: 5470 bytes --]

On Wed, 24 Oct 2018, Rob Herring wrote:

> On Tue, Oct 23, 2018 at 10:05:40AM -0700, Paul Walmsley wrote:
>> On 10/20/18 7:21 AM, Rob Herring wrote:
>>> On Fri, Oct 19, 2018 at 5:06 PM Paul Walmsley <paul.walmsley@sifive.com> wrote:
>>>> On 10/19/18 1:45 PM, Rob Herring wrote:
>>>>> On Fri, Oct 19, 2018 at 1:48 PM Paul Walmsley <paul.walmsley@sifive.com> wrote:
>>>>>> Add DT binding documentation for the Linux driver for the SiFive
>>>>>> asynchronous serial IP block.  Nothing too exotic.
>>>>>>
>>>>>> Cc: linux-serial@vger.kernel.org
>>>>>> Cc: devicetree@vger.kernel.org
>>>>>> Cc: linux-riscv@lists.infradead.org
>>>>>> Cc: linux-kernel@vger.kernel.org
>>>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>>>>> Cc: Rob Herring <robh+dt@kernel.org>
>>>>>> Cc: Mark Rutland <mark.rutland@arm.com>
>>>>>> Cc: Palmer Dabbelt <palmer@sifive.com>
>>>>>> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
>>>>>> Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
>>>>>> Signed-off-by: Paul Walmsley <paul@pwsan.com>
>>>>>> ---
>>>>>>    .../bindings/serial/sifive-serial.txt         | 21 +++++++++++++++++++
>>>>>>    1 file changed, 21 insertions(+)
>>>>>>    create mode 100644 Documentation/devicetree/bindings/serial/sifive-serial.txt
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.txt b/Documentation/devicetree/bindings/serial/sifive-serial.txt
>>>>>> new file mode 100644
>>>>>> index 000000000000..8982338512f5
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/serial/sifive-serial.txt
>>>>>> @@ -0,0 +1,21 @@
>>>>>> +SiFive asynchronous serial interface (UART)
>>>>>> +
>>>>>> +Required properties:
>>>>>> +
>>>>>> +- compatible: should be "sifive,fu540-c000-uart0" or "sifive,uart0"
>>>>>>
>>>>> As I mentioned for the
>>>>> intc and now the pwm block bindings, if you are going to do version
>>>>> numbers please document the versioning scheme.
>>>>>
>>>>>
>>>>> Will add that to the binding document.
>>> I don't seem to be making my point clear. I don't want any of this
>>> added to a binding doc for particular IP blocks. Write a common doc
>>> that explains the scheme and addresses the questions I asked. Then
>>> just reference that doc here.
>>>
>>> Maybe this is documented somewhere already? Otherwise, if one is
>>> creating a new IP block, how do they know what the versioning scheme
>>> is or what goes in the DT ROM?
>>
>>
>> Seems like there might be some confusion between IP blocks as integrated on
>> an SoC vs. IP blocks in isolation.  It's not necessarily the SoC integrator
>> that sets an IP block version number; this can come from the IP block vendor
>> itself.  So each IP block may have its own version numbering practices for
>> the IP block alone.
>>
>>
>> For SiFive IP blocks, we at SiFive could probably align on a common version
>> numbering structure for what's in the sifive-blocks repository.
>
> I thought you had that from what Palmer said and what I've seen so far.
> You have at least 3 bindings so far it seems.

Yep.

>> But other IP blocks from other vendors may not align to that, or may not
>> have version numbers exposed at all.  In those cases there's no way for
>> software folks to find out what they are,  as you pointed out earlier.  This
>> is the case with most DT compatible strings in the kernel tree.
>>
>> For example, we've integrated the NVDLA IP block, from NVIDIA, on some
>> designs.  Any NVIDIA version numbers in that IP block will probably not
>> follow the SiFive version numbering scheme.  I'd propose the right thing to
>> do for an IP block compatible string is to follow the vendor's practice, and
>> then use the SoC integrator's version numbering practice for the
>> SoC-integrated compatible string.
>
> Experience has shown that using compatible strings only specific to
> vendor IP blocks (with or without version numbers) is pretty useless.
>
> For licensed IP, I'd suggest you follow standard practices.

OK

> A genericish fallback is generally only used when there's lots of SoCs 
> sharing a block.
>
> In these cases though it needs to be clear what bindings follow some
> common versioning scheme and which don't. That's accomplished
> by referencing what the version scheme is. Otherwise, I'd expect I'll
> see the versioning scheme copied when in fact the source IP in no way
> follows it.
>
>> In effect, an SoC integration DT compatible string like
>> "sifive,fu540-c000-uart" implicitly states an IP block version number:
>> "whatever came out of the fab on the chip"[**].   I'd propose that even in
>> these cases, there's an advantage to keeping the "0" on the end, since it
>> uniquely identifies an SoC-independent IP block, rather than just the type
>> of the IP block.   But if the "0" on the end of the SoC integration DT
>> compatible string is problematic for you, we can certainly drop that last 0
>> from the SoC integration DT compatible string, and only suffer a slight lack
>> of clarity as to what version was integrated on that chip.
>
> Personally I'd leave it off, but I'm fine with either way. It just needs
> to be the way you document for SiFive IP blocks.

OK, we'll leave it off.

> Really, I'd just like to see folks get better at putting version and
> configuration information into registers. We only need DT for what we
> can't discover.

Yep, agreed.


- Paul

^ permalink raw reply

* Re: Crash in msm serial on dragonboard with ftrace bootargs
From: Sai Prakash Ranjan @ 2018-11-16 10:49 UTC (permalink / raw)
  To: Viresh Kumar, srinivas.kandagatla
  Cc: Steven Rostedt, sboyd, joel, bjorn.andersson, Andy Gross,
	David Brown, Jiri Slaby, Kees Cook, geliangtang,
	Greg Kroah-Hartman, gpramod, linux-arm-msm,
	open list:ARM/QUALCOMM SUPPORT, linux-serial,
	Linux Kernel Mailing List, Rajendra Nayak, vivek.gautam, sibis
In-Reply-To: <CAOh2x=kHQ_PfZqcoDE1+jx-ArMOh4hAFqXxiiKJ9=3JZUySQEw@mail.gmail.com>

On 11/16/2018 9:09 AM, Viresh Kumar wrote:
> On Thu, Nov 15, 2018 at 4:23 PM Srinivas Kandagatla
> <srinivas.kandagatla@linaro.org> wrote:
> 
>> Yes, this is not the solution, but it proves that the hand-off between
>> booloaders and kernel is the issue.
>>
>> In general there is wider issue with resources hand-off between
>> bootloader and kernel.
>>
>> There has been some proposal in the past by Viresh for a new framework
>> called boot-constriants (https://lkml.org/lkml/2017/12/14/440) which am
>> not sure if its still actively looked at. But something similar should
>> be the way to address such issues.
> 
> It isn't dead code yet and I am waiting to gain few more use-cases
> before I attempt
> to convince Greg again :)
> 
> Here is the code..
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/linux.git boot-constraint
> 
> --
> viresh
> 

Maybe you can take this earlycon issue as a usecase.
I have added a boot constraint for earlycon on db410c and have sent a 
patch. Whenever you repitch boot-constraint, you can add that as well :)

Thanks,
Sai

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply

* Re: Crash in msm serial on dragonboard with ftrace bootargs
From: Viresh Kumar @ 2018-11-16  3:39 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: saiprakash.ranjan, Steven Rostedt, sboyd, joel, bjorn.andersson,
	Andy Gross, David Brown, Jiri Slaby, Kees Cook, geliangtang,
	Greg Kroah-Hartman, gpramod, linux-arm-msm,
	open list:ARM/QUALCOMM SUPPORT, linux-serial,
	Linux Kernel Mailing List, Rajendra Nayak, vivek.gautam, sibis
In-Reply-To: <ed648cc5-0748-8bcc-5ebb-ce6dbc7d4fee@linaro.org>

On Thu, Nov 15, 2018 at 4:23 PM Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:

> Yes, this is not the solution, but it proves that the hand-off between
> booloaders and kernel is the issue.
>
> In general there is wider issue with resources hand-off between
> bootloader and kernel.
>
> There has been some proposal in the past by Viresh for a new framework
> called boot-constriants (https://lkml.org/lkml/2017/12/14/440) which am
> not sure if its still actively looked at. But something similar should
> be the way to address such issues.

It isn't dead code yet and I am waiting to gain few more use-cases
before I attempt
to convince Greg again :)

Here is the code..

git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/linux.git boot-constraint

--
viresh

^ permalink raw reply

* Re: [PATCH v3 2/2] tty: serial: add driver for the SiFive UART
From: Paul Walmsley @ 2018-11-15 20:11 UTC (permalink / raw)
  To: Emil Renner Berthing
  Cc: paul.walmsley, linux-serial, paul, Palmer Dabbelt, wesley, jslaby,
	Linux Kernel Mailing List, julia.lawall, Greg Kroah-Hartman,
	linux-riscv
In-Reply-To: <CANBLGcy9WoBqBKQnvz-YGQpXossP2HDmW_go8WZD7FfBZdr5VQ@mail.gmail.com>

Hi Emil,

On Thu, 15 Nov 2018, Emil Renner Berthing wrote:

> Thanks for the patch!

Thanks for your comments!

> On Sat, 20 Oct 2018 at 12:12, Paul Walmsley <paul.walmsley@sifive.com> wrote:
>
>> +static int __init sifive_serial_console_setup(struct console *co, char *options)
>
> Unfortunately I get this error unless I remove the __init:
> ...
>  GEN     .version
>  CHK     include/generated/compile.h
>  AR      built-in.a
>  LD      vmlinux.o
>  MODPOST vmlinux.o
> WARNING: vmlinux.o(.data+0x14e48): Section mismatch in reference from
> the variable .LANCHOR0 to the function
> .init.text:sifive_serial_console_setup()
> The variable .LANCHOR0 references
> the function __init sifive_serial_console_setup()
> If the reference is valid then annotate the
> variable with __init* or __refdata (see linux/init.h) or name the variable:
> *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
>
> FATAL: modpost: Section mismatches detected.
> Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
> make[1]: *** [scripts/Makefile.modpost:98: vmlinux.o] Error 1
> make: *** [Makefile:1040: vmlinux] Error 2
>
> I have
> CONFIG_SERIAL_CORE=y
> CONFIG_SERIAL_CORE_CONSOLE=y
> CONFIG_SERIAL_SIFIVE=y
> CONFIG_SERIAL_SIFIVE_CONSOLE=y
> and it happens both on v4.20-rc2 and v4.19.
> Without the __init everything seems to work fine though.

Thanks for the report.  There are some patches to address this:

https://lore.kernel.org/lkml/20181115005602.30746-1-paul.walmsley@sifive.com/

>> +#else
>> +
>> +#define SIFIVE_SERIAL_CONSOLE  NULL
>> +
>> +static inline void __ssp_add_console_port(struct sifive_serial_port *ssp)
>> +{}
>> +static void __ssp_remove_console_port(struct sifive_serial_port *ssp)
>> +{}
>
> Missing "inline"?

That is indeed an error, but the other way around: I didn't mean for that 
inline to be there.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst

I've dropped the inline; thanks for pointing the situation out.

>> +static int __init sifive_serial_init(void)
>> +{
>> +       int r;
>
> If you're sending a v4 anyway, here and in the the probe function
> using int ret; for this kind of variable is a common idiom and
> hence easier to read.

Precedent exists in the kernel for using "r" as a return value also:

$ fgrep -r 'return r;' linux/
4491
$

which probably traces back ultimately to Torvalds' guidance to keep 
variable names short:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst#n284

But I am not religious about it.   So if this is a big deal for you, I 
guess reply back, and it can be changed.


- Paul

^ permalink raw reply

* Re: [PATCH v3 2/2] tty: serial: add driver for the SiFive UART
From: Emil Renner Berthing @ 2018-11-15 11:01 UTC (permalink / raw)
  To: paul.walmsley
  Cc: linux-serial, paul, Palmer Dabbelt, wesley, jslaby,
	Linux Kernel Mailing List, julia.lawall, Greg Kroah-Hartman,
	linux-riscv
In-Reply-To: <20181020101045.15991-3-paul.walmsley@sifive.com>

Hi Paul,

Thanks for the patch!

On Sat, 20 Oct 2018 at 12:12, Paul Walmsley <paul.walmsley@sifive.com> wrote:
> +/*
> + *
> + */

Interesting comment ;)

> +static int __init sifive_serial_console_setup(struct console *co, char *options)

Unfortunately I get this error unless I remove the __init:
...
  GEN     .version
  CHK     include/generated/compile.h
  AR      built-in.a
  LD      vmlinux.o
  MODPOST vmlinux.o
WARNING: vmlinux.o(.data+0x14e48): Section mismatch in reference from
the variable .LANCHOR0 to the function
.init.text:sifive_serial_console_setup()
The variable .LANCHOR0 references
the function __init sifive_serial_console_setup()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console

FATAL: modpost: Section mismatches detected.
Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.
make[1]: *** [scripts/Makefile.modpost:98: vmlinux.o] Error 1
make: *** [Makefile:1040: vmlinux] Error 2

I have
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_SIFIVE=y
CONFIG_SERIAL_SIFIVE_CONSOLE=y
and it happens both on v4.20-rc2 and v4.19.
Without the __init everything seems to work fine though.

> +#else
> +
> +#define SIFIVE_SERIAL_CONSOLE  NULL
> +
> +static inline void __ssp_add_console_port(struct sifive_serial_port *ssp)
> +{}
> +static void __ssp_remove_console_port(struct sifive_serial_port *ssp)
> +{}

Missing "inline"?

> +static int __init sifive_serial_init(void)
> +{
> +       int r;

If you're sending a v4 anyway, here and in the the probe function
using int ret; for this kind of variable is a common idiom and
hence easier to read.

/Emil

^ permalink raw reply

* Re: Crash in msm serial on dragonboard with ftrace bootargs
From: Srinivas Kandagatla @ 2018-11-15 10:53 UTC (permalink / raw)
  To: Sai Prakash Ranjan, Steven Rostedt, Stephen Boyd
  Cc: Joel Fernandes, Bjorn Andersson, Andy Gross, David Brown,
	Jiri Slaby, Kees Cook, Geliang Tang, Greg Kroah-Hartman,
	Pramod Gurav, linux-arm-msm, linux-soc, linux-serial,
	linux-kernel, Rajendra Nayak, Vivek Gautam, Sibi Sankar
In-Reply-To: <8f65f83b-8cd9-5e35-c324-30b86390906e@codeaurora.org>



On 15/11/18 10:33, Sai Prakash Ranjan wrote:
> On 11/13/2018 3:14 PM, Srinivas Kandagatla wrote:
>> Hi Sai,
>>
>>
>>
>> On 25/10/18 15:36, saiprakash.ranjan@codeaurora.org wrote:
>>> "If I disable dma node and LS-UART0, then I don't see any crash and
>>> ftrace also works fine"
>>>
>>> And one more observation is that even without ftrace cmdline, if I use
>>> earlycon and disable dma, I face the same crash.
>>>
>>> So basically this seems to be some kind of earlycon and dma issue and
>>> not ftrace(I can be wrong).
>>>
>>> So adding Srinivas for more info on this dma node.
>>
>> Its Interesting that my old email conversations with SBoyd show that I 
>> have investigated this issue in early 2016!
>>
>> My analysis so far:
>>
>> This reason for such behavior is due the common iface clock
>> (GCC_BLSP1_AHB_CLK) across multiple drivers(serial ports, bam dma
>> and other low speed devices).
>> The code flow in DB410C is bit different, as the uart0 is first
>> attempted to set as console and then uart1, this ordering triggers
>> pm state change uart_change_pm(state, UART_PM_STATE_OFF) from serial
>> core while setting up uart0, this would go and disable all the
>> clocks for uart0.
>> As uart1 is not setup Yet, and earlycon is still active, any
>> attempts by earlycon to write to registers would trigger a system
>> reboot as the clock was just disabled by uart0 change_pm code.
>>
>> This can even be triggered with any drivers like spi which uses same
>> clock I guess.
>>
>> Hope it helps,
>>
>> Either earlycon needs to reference the clocks or those clocks needs to
>> be marked always-on (but only with earlycon).
>>
>>>
>>> Also just for a note: apq8096-db820c.dtsi shows UART0 is disabled 
>>> because
>>> bootloader does not allow access to it. Could this also be the case 
>>> for db410c?
>> No, this is not the case with DB410c. DB820c has added restrictions in 
>> TZ, I think new booloaders should have solved this issue.
>>
>>
> 
> Hi Srinivas,
> 
> Thanks a lot for pointing out the cause of crash.
> I just tried setting GCC_BLSP1_AHB_CLK with flag CLK_IS_CRITICAL and the
> crash disappears.
> 
> But I suppose setting CLK_IS_CRITICAL is not the solution?
> 

Yes, this is not the solution, but it proves that the hand-off between 
booloaders and kernel is the issue.

In general there is wider issue with resources hand-off between 
bootloader and kernel.

There has been some proposal in the past by Viresh for a new framework 
called boot-constriants (https://lkml.org/lkml/2017/12/14/440) which am 
not sure if its still actively looked at. But something similar should 
be the way to address such issues.

--srini




> Thanks,
> Sai

^ permalink raw reply

* Re: Crash in msm serial on dragonboard with ftrace bootargs
From: Sai Prakash Ranjan @ 2018-11-15 10:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Steven Rostedt, Stephen Boyd
  Cc: Joel Fernandes, Bjorn Andersson, Andy Gross, David Brown,
	Jiri Slaby, Kees Cook, Geliang Tang, Greg Kroah-Hartman,
	Pramod Gurav, linux-arm-msm, linux-soc, linux-serial,
	linux-kernel, Rajendra Nayak, Vivek Gautam, Sibi Sankar
In-Reply-To: <38099043-f5ed-6d81-bf94-13f61cfa8507@linaro.org>

On 11/13/2018 3:14 PM, Srinivas Kandagatla wrote:
> Hi Sai,
> 
> 
> 
> On 25/10/18 15:36, saiprakash.ranjan@codeaurora.org wrote:
>> "If I disable dma node and LS-UART0, then I don't see any crash and
>> ftrace also works fine"
>>
>> And one more observation is that even without ftrace cmdline, if I use
>> earlycon and disable dma, I face the same crash.
>>
>> So basically this seems to be some kind of earlycon and dma issue and
>> not ftrace(I can be wrong).
>>
>> So adding Srinivas for more info on this dma node.
> 
> Its Interesting that my old email conversations with SBoyd show that I 
> have investigated this issue in early 2016!
> 
> My analysis so far:
> 
> This reason for such behavior is due the common iface clock
> (GCC_BLSP1_AHB_CLK) across multiple drivers(serial ports, bam dma
> and other low speed devices).
> The code flow in DB410C is bit different, as the uart0 is first
> attempted to set as console and then uart1, this ordering triggers
> pm state change uart_change_pm(state, UART_PM_STATE_OFF) from serial
> core while setting up uart0, this would go and disable all the
> clocks for uart0.
> As uart1 is not setup Yet, and earlycon is still active, any
> attempts by earlycon to write to registers would trigger a system
> reboot as the clock was just disabled by uart0 change_pm code.
> 
> This can even be triggered with any drivers like spi which uses same
> clock I guess.
> 
> Hope it helps,
> 
> Either earlycon needs to reference the clocks or those clocks needs to
> be marked always-on (but only with earlycon).
> 
>>
>> Also just for a note: apq8096-db820c.dtsi shows UART0 is disabled because
>> bootloader does not allow access to it. Could this also be the case 
>> for db410c?
> No, this is not the case with DB410c. DB820c has added restrictions in 
> TZ, I think new booloaders should have solved this issue.
> 
> 

Hi Srinivas,

Thanks a lot for pointing out the cause of crash.
I just tried setting GCC_BLSP1_AHB_CLK with flag CLK_IS_CRITICAL and the
crash disappears.

But I suppose setting CLK_IS_CRITICAL is not the solution?

Thanks,
Sai

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply

* [PATCH 3/3] serial: imx: avoid crash when un/re-binding serial console device
From: Stefan Agner @ 2018-11-14 17:49 UTC (permalink / raw)
  To: gregkh, jslaby
  Cc: fabio.estevam, u.kleine-koenig, s.hauer, linux-serial,
	linux-kernel, Stefan Agner
In-Reply-To: <20181114174940.7865-1-stefan@agner.ch>

If the device used as a serial console gets un/re-binded, then
register_console() will call imx_uart_setup_console() again.
Drop __init so that imx_uart_setup_console() can be safely called
at runtime.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
This addresses a kernel panic seen when unbinding/rebinding the i.MX
UART which is serial console on i.MX 6/7 via SSH:
# cd /sys/bus/platform/drivers/imx-uart/
# echo 30860000.serial > unbind && echo 30860000.serial > bind

console [ttymxc0] disabled
30860000.serial: ttymxc0 at MMIO 0x30860000 (irq = 52, base_baud = 1500000) is a IMX
Unable to handle kernel paging request at virtual address c0c4b830
pgd = 5e12e3d4
[c0c4b830] *pgd=80c1141e(bad)
Internal error: Oops: 8000000d [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 866 Comm: sh Not tainted 4.18.15-00048-gb3b505988801-dirty #403
Hardware name: Freescale i.MX7 Dual (Device Tree)
PC is at imx_uart_console_setup+0x0/0x274
LR is at register_console+0x184/0x3c4
pc : [<c0c4b830>]    lr : [<c0171314>]    psr: a0070013
sp : e8015db8  ip : c0d06548  fp : c0b4a158
r10: ec1d9380  r9 : 00000001  r8 : 00000000
r7 : 00000000  r6 : c0d819e0  r5 : c0d81e48  r4 : c0d47d68
r3 : c0c4b830  r2 : 00000000  r1 : efffca03  r0 : c0d47d68
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5387d  Table: a803806a  DAC: 00000051
Process sh (pid: 866, stack limit = 0x9c2f1d49)

It seems that also other drivers are affected. An alternative might be
to disallow unbinding/rebinding instead.

 drivers/tty/serial/imx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 757c91e5105a..674bd0ea2491 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1966,7 +1966,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
  * If the port was already initialised (eg, by a boot loader),
  * try to determine the current setup.
  */
-static void __init
+static void
 imx_uart_console_get_options(struct imx_port *sport, int *baud,
 			     int *parity, int *bits)
 {
@@ -2025,7 +2025,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
 	}
 }
 
-static int __init
+static int
 imx_uart_console_setup(struct console *co, char *options)
 {
 	struct imx_port *sport;
-- 
2.19.1

^ permalink raw reply related

* [PATCH 2/3] serial: imx: unprepare console clocks on remove
From: Stefan Agner @ 2018-11-14 17:49 UTC (permalink / raw)
  To: gregkh, jslaby
  Cc: fabio.estevam, u.kleine-koenig, s.hauer, linux-serial,
	linux-kernel, Stefan Agner
In-Reply-To: <20181114174940.7865-1-stefan@agner.ch>

Currently imx_uart_console_setup() prepares clocks which do not
get unprepared anywhere. Check whether the console has been used
by testing if index is set and unprepare clocks in this case.

This makes sure that clocks are properly unprepared after the
console device has been unbound.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/tty/serial/imx.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 313c3b1900a8..757c91e5105a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2085,7 +2085,7 @@ static struct console imx_uart_console = {
 	.data		= &imx_uart_uart_driver,
 };
 
-#define IMX_CONSOLE	&imx_uart_console
+#define IMX_CONSOLE	(&imx_uart_console)
 
 #ifdef CONFIG_OF
 static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
@@ -2378,8 +2378,17 @@ static int imx_uart_probe(struct platform_device *pdev)
 static int imx_uart_remove(struct platform_device *pdev)
 {
 	struct imx_port *sport = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+
+	if (IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) && IMX_CONSOLE->index >= 0) {
+		clk_unprepare(sport->clk_ipg);
+		clk_unprepare(sport->clk_per);
+		IMX_CONSOLE->index = -1;
+	}
 
-	return uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+	return ret;
 }
 
 static void imx_uart_restore_context(struct imx_port *sport)
-- 
2.19.1

^ permalink raw reply related

* [PATCH 1/3] serial: imx: fix error handling in console_setup
From: Stefan Agner @ 2018-11-14 17:49 UTC (permalink / raw)
  To: gregkh, jslaby
  Cc: fabio.estevam, u.kleine-koenig, s.hauer, linux-serial,
	linux-kernel, Stefan Agner

The ipg clock only needs to be unprepared in case preparing
per clock fails. The ipg clock has already disabled at the point.

Fixes: 1cf93e0d5488 ("serial: imx: remove the uart_console() check")
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/tty/serial/imx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 0f67197a3783..313c3b1900a8 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2068,7 +2068,7 @@ imx_uart_console_setup(struct console *co, char *options)
 
 	retval = clk_prepare(sport->clk_per);
 	if (retval)
-		clk_disable_unprepare(sport->clk_ipg);
+		clk_unprepare(sport->clk_ipg);
 
 error_console:
 	return retval;
-- 
2.19.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox