From 07c53738d02dc24e79e3ebe24f528f98d4276de4 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Tue, 28 May 2024 07:24:00 +0300 Subject: [PATCH 01/65] HACK: of: fdt: filter out dangerous Android bootloader parameters Since Android primary bootloader with system-as-root feature [1] enabled adds some arguments to kernel command line from boot.img, that make booting Linux harder: * skip_initramfs * root=/dev/dm-0 * init=/init * dm=... Most importantly, Linux processes root= parameter and at boot time skips initramfs and tries to mount root device that does not exist and fails. Add a quick hack to scramble these parameters from cmdline passed by primary bootloader in FDT /chosen/bootargs property, so that Linux won't accidentally process them. [1] https://source.android.com/docs/core/architecture/partitions/system-as-root Signed-off-by: Alexey Minnekhanov --- arch/arm64/Kconfig | 26 ++++++++++++++++++++++++++ drivers/of/fdt.c | 16 ++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index a2f8ff354ca670..2c36bd623feb5a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2323,6 +2323,32 @@ config CMDLINE_FORCE endchoice +config CMDLINE_DROP_DANGEROUS_ANDROID_OPTIONS + bool "Drop certain dangerous options from cmdline" + default n + help + Android >=9 primary bootloader with system-as-root feature [1] + enabled passes some arguments in kernel command line, that make + booting Linux harder: + + * skip_initramfs + * root=/dev/dm-0 + * init=/init + * dm=... + + Those parameters override default boot partition to hardcoded, + set init binary to /init, disable booting from initramfs. + + Most importantly, Linux processes root= parameter and at boot time + skips initramfs and tries to mount device that does not exist and + fails. + + If this option is enabled, those cmdline parameters will be erased + from bootloader's command line, and custom OS can boot the way it + likes. + + [1] https://source.android.com/docs/core/architecture/partitions/system-as-root + config EFI_STUB bool diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 68103ad230eebd..a129136de9aa65 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1022,6 +1022,9 @@ int __init early_init_dt_scan_chosen(char *cmdline) const char *p; const void *rng_seed; const void *fdt = initial_boot_params; +#ifdef CONFIG_CMDLINE_DROP_DANGEROUS_ANDROID_OPTIONS + char *cmdline2; +#endif node = fdt_path_offset(fdt, "/chosen"); if (node < 0) @@ -1071,6 +1074,19 @@ int __init early_init_dt_scan_chosen(char *cmdline) #endif #endif /* CONFIG_CMDLINE */ +#ifdef CONFIG_CMDLINE_DROP_DANGEROUS_ANDROID_OPTIONS + /* Quick hack - replace first character with '_' */ + cmdline2 = strstr((const char *)cmdline, "skip_initramfs"); + if (cmdline2) + *cmdline2 = '_'; + cmdline2 = strstr((const char *)cmdline, "root="); + if (cmdline2) + *cmdline2 = '_'; + cmdline2 = strstr((const char *)cmdline, "init="); + if (cmdline2) + *cmdline2 = '_'; +#endif + pr_debug("Command line is: %s\n", (char *)cmdline); return 0; From f8d606484b811bf138d4d27b5f8d47a53acc5bf5 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Thu, 4 Aug 2022 03:43:17 +0300 Subject: [PATCH 02/65] sdm660_defconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated with: $ make savedefconfig && cp defconfig ../arch/arm64/configs/sdm660_defconfig barni2000: Add CONFIG_DRM_PANEL_BOE_TD4320 as a module. Signed-off-by: Alexey Minnekhanov Signed-off-by: Barnabás Czémán --- arch/arm64/configs/sdm660_defconfig | 722 ++++++++++++++++++++++++++++ 1 file changed, 722 insertions(+) create mode 100644 arch/arm64/configs/sdm660_defconfig diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig new file mode 100644 index 00000000000000..1c6939249085e9 --- /dev/null +++ b/arch/arm64/configs/sdm660_defconfig @@ -0,0 +1,722 @@ +CONFIG_LOCALVERSION="-sdm660" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=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_PSI=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_UCLAMP_TASK=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_UCLAMP_TASK_GROUP=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PROFILING=y +CONFIG_KEXEC=y +CONFIG_ARCH_QCOM=y +CONFIG_ARM64_ERRATUM_2441007=y +CONFIG_ARM64_ERRATUM_1286807=y +CONFIG_ARM64_ERRATUM_1542419=y +# CONFIG_ARM64_ERRATUM_2077057 is not set +CONFIG_ARM64_ERRATUM_2441009=y +CONFIG_ARM64_VA_BITS_48=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_COMPAT=y +CONFIG_COMPAT_ALIGNMENT_FIXUPS=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_CMDLINE_DROP_DANGEROUS_ANDROID_OPTIONS=y +# CONFIG_EFI is not set +CONFIG_HIBERNATION=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=m +CONFIG_ARM_QCOM_CPUFREQ_HW=m +CONFIG_JUMP_LABEL=y +# CONFIG_GCC_PLUGINS is not set +CONFIG_MODULES=y +CONFIG_MODULE_DEBUG=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_COMPRESS_ZSTD=y +CONFIG_BLK_DEV_THROTTLING=y +# CONFIG_IOSCHED_BFQ is not set +CONFIG_BINFMT_MISC=m +CONFIG_SLAB_BUCKETS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_KSM=y +CONFIG_MEMORY_FAILURE=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_CMA=y +CONFIG_CMA_AREAS=7 +CONFIG_LRU_GEN=y +CONFIG_LRU_GEN_ENABLED=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IPV6=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NFT_CT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_NAT=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_FIB_INET=m +CONFIG_NETFILTER_XTABLES_COMPAT=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_IP_VS=m +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_NFCT=y +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_SCHED=y +CONFIG_NET_CLS_CGROUP=m +CONFIG_QRTR=m +CONFIG_QRTR_SMD=m +CONFIG_QRTR_TUN=m +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m +CONFIG_BT_LEDS=y +CONFIG_BT_MSFTEXT=y +CONFIG_BT_AOSPEXT=y +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_NOKIA=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_INTEL=y +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_HCIUART_RTL=y +CONFIG_BT_HCIUART_QCA=y +CONFIG_BT_ATH3K=m +CONFIG_BT_QCOMSMD=m +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=m +CONFIG_NFC=m +CONFIG_NFC_NCI=m +CONFIG_NFC_S3FWRN5_I2C=m +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_COMPRESS=y +CONFIG_FW_LOADER_COMPRESS_ZSTD=y +# CONFIG_QCOM_EBI2 is not set +CONFIG_QCOM_SSC_BLOCK_BUS=y +CONFIG_CONNECTOR=y +CONFIG_QCOM_QSEECOM=y +CONFIG_GNSS=y +CONFIG_OF_OVERLAY=y +CONFIG_ZRAM=m +CONFIG_ZRAM_DEF_COMP_ZSTD=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_VIRTIO_BLK=m +CONFIG_QCOM_COINCELL=m +CONFIG_QCOM_FASTRPC=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=y +CONFIG_MD_RAID456=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_RAID=m +CONFIG_DM_VERITY=m +CONFIG_DM_INTEGRITY=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_WIREGUARD=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=m +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_ADI is not set +# CONFIG_NET_VENDOR_LITEX is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_META is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +CONFIG_RMNET=m +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_QCOM_IPA=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_USB_NET_AQC111=m +# CONFIG_WLAN_VENDOR_ADMTEK is not set +CONFIG_ATH10K=m +CONFIG_ATH10K_SNOC=m +CONFIG_ATH10K_DEBUG=y +CONFIG_ATH10K_DEBUGFS=y +CONFIG_ATH10K_SPECTRAL=y +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_MICROCHIP is not set +# CONFIG_WLAN_VENDOR_PURELIFI is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_SILABS is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_GPIO_POLLED=y +# CONFIG_MOUSE_PS2 is not set +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GOODIX=m +CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS=m +CONFIG_TOUCHSCREEN_NT36XXX=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PM8941_PWRKEY=y +CONFIG_INPUT_PM8XXX_VIBRATOR=y +CONFIG_INPUT_QCOM_SPMI_HAPTICS=m +CONFIG_INPUT_UINPUT=y +CONFIG_RMI4_CORE=y +CONFIG_RMI4_I2C=y +CONFIG_RMI4_F11=y +CONFIG_RMI4_F12=y +# CONFIG_SERIO is not set +CONFIG_LEGACY_PTY_COUNT=16 +# CONFIG_LEGACY_TIOCSTI is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_RPMSG_TTY=m +CONFIG_SERIAL_DEV_BUS=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_GPIO=y +CONFIG_I2C_QUP=y +CONFIG_I2C_SLAVE=y +CONFIG_SPI=y +CONFIG_SPI_MEM=y +CONFIG_SPI_BITBANG=m +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPMI=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_MSM=y +CONFIG_PINCTRL_SDM660=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_QCOM_SSBI_PMIC=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_RESET_QCOM_PON=y +CONFIG_SYSCON_REBOOT_MODE=y +CONFIG_NVMEM_REBOOT_MODE=y +CONFIG_POWER_SEQUENCING=y +CONFIG_BATTERY_QCOM_BATTMGR=m +CONFIG_CHARGER_QCOM_SMBB=m +CONFIG_BATTERY_RT5033=m +CONFIG_BATTERY_QCOM_FG=m +CONFIG_CHARGER_QCOM_SMB2=m +CONFIG_THERMAL=y +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y +CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_QCOM_TSENS=y +CONFIG_QCOM_SPMI_ADC_TM5=m +CONFIG_QCOM_SPMI_TEMP_ALARM=m +CONFIG_QCOM_LMH=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_QCOM_WDT=m +CONFIG_MFD_QCOM_RPM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_NETLINK_EVENTS=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_QCOM_REFGEN=m +CONFIG_REGULATOR_QCOM_RPMH=y +CONFIG_REGULATOR_QCOM_SMD_RPM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_QCOM_USB_VBUS=y +CONFIG_REGULATOR_QCOM_LABIBB=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_PLATFORM_SUPPORT=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_QCOM_CAMSS=m +CONFIG_VIDEO_QCOM_VENUS=m +CONFIG_DRM=y +CONFIG_DRM_FBDEV_OVERALLOC=200 +CONFIG_DRM_MSM=m +# CONFIG_DRM_MSM_MDP4 is not set +# CONFIG_DRM_MSM_HDMI is not set +CONFIG_DRM_PANEL_BOE_TD4320=m +CONFIG_DRM_PANEL_BOE_NT51021=m +CONFIG_DRM_PANEL_FT8716U=m +CONFIG_DRM_PANEL_DSI_CM=y +CONFIG_DRM_PANEL_NOVATEK_NT36672A=m +CONFIG_DRM_PANEL_NOVATEK_NT36672_TIANMA_JASMINE=m +CONFIG_DRM_PANEL_NOVATEK_NT36672_TXD=m +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_PANEL_TRULY_TD4322=m +CONFIG_DRM_SIMPLEDRM=y +CONFIG_DRM_GUD=m +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_QCOM_WLED=y +CONFIG_BACKLIGHT_LP855X=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y +CONFIG_LOGO=y +CONFIG_DRM_ACCEL=y +CONFIG_SOUND=m +CONFIG_SND=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_QCOM=m +CONFIG_SND_SOC_APQ8016_SBC=m +CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m +CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_RAZER=m +CONFIG_USB_HIDDEV=y +CONFIG_I2C_HID_OF=m +CONFIG_I2C_HID_OF_GOODIX=m +CONFIG_USB_LED_TRIG=y +CONFIG_USB_CONN_GPIO=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG=y +CONFIG_USB_OTG_FSM=m +CONFIG_USB_MON=m +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI_RENESAS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=m +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_ULPI=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_QCOM_EUD=m +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_U_SERIAL_CONSOLE=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_MIDI2=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_USB_FUNCTIONFS=m +CONFIG_TYPEC=y +CONFIG_TYPEC_UCSI=y +CONFIG_UCSI_PMIC_GLINK=m +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_PATTERN=m +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PM8XXX=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_GPI_DMA=y +# CONFIG_SURFACE_PLATFORMS is not set +CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_QCOM_CLK_RPMH=y +CONFIG_SDM_MMCC_660=y +CONFIG_SDM_GPUCC_660=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_QCOM_IPCC=m +CONFIG_IOMMU_IO_PGTABLE_ARMV7S=y +CONFIG_IOMMU_DEBUGFS=y +CONFIG_ARM_SMMU=y +CONFIG_ARM_SMMU_V3=y +CONFIG_QCOM_IOMMU=y +CONFIG_REMOTEPROC=y +CONFIG_QCOM_Q6V5_MSS=m +CONFIG_QCOM_Q6V5_PAS=m +CONFIG_QCOM_Q6V5_WCSS=m +CONFIG_QCOM_SYSMON=m +CONFIG_QCOM_WCNSS_PIL=m +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_CTRL=y +CONFIG_RPMSG_NS=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_SMD=y +CONFIG_SOUNDWIRE=m +CONFIG_SOUNDWIRE_QCOM=m +CONFIG_QCOM_AOSS_QMP=m +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_GENI_SE=m +CONFIG_QCOM_GSBI=m +CONFIG_QCOM_LLCC=m +CONFIG_QCOM_OCMEM=m +CONFIG_QCOM_PMIC_GLINK=m +CONFIG_QCOM_RAMP_CTRL=m +CONFIG_QCOM_RMTFS_MEM=m +CONFIG_QCOM_RPM_MASTER_STATS=m +CONFIG_QCOM_RPMH=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_QCOM_SMP2P=y +CONFIG_QCOM_SMSM=y +CONFIG_QCOM_SOCINFO=y +CONFIG_QCOM_SPM=m +CONFIG_QCOM_STATS=m +CONFIG_QCOM_WCNSS_CTRL=m +CONFIG_QCOM_APR=m +CONFIG_QCOM_ICC_BWMON=m +CONFIG_QCOM_CPR=m +CONFIG_QCOM_RPMHPD=y +CONFIG_QCOM_RPMPD=y +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_EXTCON_GPIO=y +CONFIG_EXTCON_SM5502=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_MEMORY=y +CONFIG_IIO=m +CONFIG_BMC150_ACCEL=m +CONFIG_QCOM_SPMI_RRADC=m +CONFIG_QCOM_SPMI_IADC=m +CONFIG_QCOM_SPMI_VADC=m +CONFIG_QCOM_SPMI_ADC5=m +CONFIG_BMG160=m +CONFIG_LTR501=m +CONFIG_BMC150_MAGN_I2C=m +CONFIG_PWM=y +CONFIG_PWM_CLK=m +CONFIG_PWM_GPIO=m +CONFIG_RESET_GPIO=y +CONFIG_PHY_QCOM_QMP=y +CONFIG_PHY_QCOM_QUSB2=y +CONFIG_PHY_QCOM_SNPS_EUSB2=y +CONFIG_PHY_QCOM_EUSB2_REPEATER=y +CONFIG_PHY_QCOM_M31_USB=m +CONFIG_PHY_QCOM_USB_HS=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_QCOM_QFPROM=y +CONFIG_NVMEM_QCOM_SEC_QFPROM=m +CONFIG_SLIM_QCOM_CTRL=m +CONFIG_SLIM_QCOM_NGD_CTRL=m +CONFIG_INTERCONNECT_QCOM=y +CONFIG_INTERCONNECT_QCOM_SDM660=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_XFS_FS=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_BTRFS_FS=y +CONFIG_F2FS_FS=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=y +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_UDF_FS=m +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=y +CONFIG_NTFS3_FS=m +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=m +CONFIG_NFS_V4=m +CONFIG_NFSD=m +CONFIG_NFSD_V4=y +# CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set +CONFIG_CIFS=m +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_CHACHA20=m +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_POLY1305=m +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_NHPOLY1305_NEON=m +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA512_ARM64_CE=m +CONFIG_CRYPTO_SHA3_ARM64=m +CONFIG_CRYPTO_SM3_ARM64_CE=m +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_BS=m +CONFIG_CRYPTO_SM4_ARM64_CE=m +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_DEV_QCOM_RNG=m +CONFIG_PKCS8_PRIVATE_KEY_PARSER=m +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_PANIC_TIMEOUT=-1 +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_RCU_TRACE is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_RETVAL=y From 3ac5b55309232f1ae20812879539d2f69676a8a6 Mon Sep 17 00:00:00 2001 From: Alexey Min Date: Thu, 4 Jan 2024 15:06:13 +0300 Subject: [PATCH 03/65] Add CI that runs DTBs check --- .github/workflows/check-dtschema.yml | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/check-dtschema.yml diff --git a/.github/workflows/check-dtschema.yml b/.github/workflows/check-dtschema.yml new file mode 100644 index 00000000000000..82c3992415ff5c --- /dev/null +++ b/.github/workflows/check-dtschema.yml @@ -0,0 +1,37 @@ +name: Device tree validation +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - qcom-sdm660-6.*.y + tags: + - v*-sdm660 +jobs: + check-dbts: + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Install dependencies + run: | + sudo apt install -yqq bison build-essential device-tree-compiler flex gcc-aarch64-linux-gnu python3 python3-dev python3-venv swig + - name: Prepare build direcotory + run: | + mkdir build-dtbs-check + - name: Prepare config + run: | + make O=build-dtbs-check ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig sdm660_defconfig + - name: Compile DTBs + run: | + make O=build-dtbs-check ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs + - name: Check DTBs + run: | + python3 -m venv venv_dtschema + . venv_dtschema/bin/activate + pip3 install dtschema + make O=build-dtbs-check ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- CHECK_DTBS=y qcom/sdm630-*.dtb qcom/sdm636-*.dtb qcom/sdm660-*.dtb + deactivate + rm -r venv_dtschema From 5379b2ffa8e462092be3b029ce1616bc02da93b1 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sun, 22 Oct 2023 23:42:35 +0300 Subject: [PATCH 04/65] arm64: dts: qcom: sdm630: Add modem metadata mem Similarly to MSM8998, add and use modem metadata memory region. This fixes dtbs check warning; but however does not seemingly affect device functionality. Signed-off-by: Alexey Minnekhanov --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index c7e3764a8cf321..8918dee6b8d9d0 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -508,6 +508,12 @@ reg = <0x0 0xfed00000 0x0 0xa00000>; no-map; }; + + mdata_mem: mpss-metadata { + alloc-ranges = <0x0 0xa0000000 0x0 0x20000000>; + size = <0x0 0x4000>; + no-map; + }; }; smem: smem { @@ -1057,7 +1063,7 @@ <&rpmpd SDM660_VDDMX>; power-domain-names = "cx", "mx"; - memory-region = <&mba_region>, <&mpss_region>; + memory-region = <&mba_region>, <&mpss_region>, <&mdata_mem>; status = "disabled"; From 1038e9ff16cbca515cc3d172e1feb0836a88acc4 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Wed, 21 Jun 2023 20:28:50 +0300 Subject: [PATCH 05/65] arm64: dts: qcom: sdm630: Add support for WCN3990 Wi-Fi Describe Wi-Fi device node used in SDM630/660. Signed-off-by: Alexey Minnekhanov --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 8918dee6b8d9d0..fe9d8f5fc4357e 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -2421,6 +2421,35 @@ redistributor-stride = <0x0 0x20000>; interrupts = ; }; + + wifi: wifi@18800000 { + compatible = "qcom,wcn3990-wifi"; + reg = <0x18800000 0x800000>; + reg-names = "membase"; + memory-region = <&wlan_msa_mem>; + clocks = <&rpmcc RPM_SMD_RF_CLK1_PIN>; + clock-names = "cxo_ref_clk_pin"; + interrupts = + , + , + , + , + , + , + , + , + , + , + , + ; + + iommus = <&anoc2_smmu 0x1a00>, + <&anoc2_smmu 0x1a01>; + qcom,snoc-host-cap-8bit-quirk; + qcom,no-msa-ready-indicator; + + status = "disabled"; + }; }; sound: sound { From 4960acb31fb7f3a800ec3dd85e4abc366fd624a6 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 10 Aug 2021 20:38:28 +0200 Subject: [PATCH 06/65] iommu/arm-smmu-qcom: Skip the TTBR1 quirk for MSM8998 and SDM630 Similarly to MSM8996 DragonBoard 820c, MSM8998 and SDM630 are equipped with Adreno 5xx series, which doesn't have separate pagetables support at the moment of writing. Skip the TTBR1 quirk for these two SoCs as to get Adreno in a usable state. --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 36c6b36ad4ff74..e4b4131d8499dc 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -201,7 +201,9 @@ static bool qcom_adreno_can_do_ttbr1(struct arm_smmu_device *smmu) { const struct device_node *np = smmu->dev->of_node; - if (of_device_is_compatible(np, "qcom,msm8996-smmu-v2")) + if (of_device_is_compatible(np, "qcom,msm8996-smmu-v2") || + of_device_is_compatible(np, "qcom,msm8998-smmu-v2") || + of_device_is_compatible(np, "qcom,sdm630-smmu-v2")) return false; return true; From 8649a2b62f656828db8852efd60a43da9318c789 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 10 Aug 2021 20:42:48 +0200 Subject: [PATCH 07/65] iommu/arm-smmu-qcom: Add MSM8998 and SDM660 mss compatibles for identity Add MSM8998 and SDM660's mss-pil compatibles to switch the default iommu domain type to IDENTITY, as similarly required by SDM845 and others. Signed-off-by: AngeloGioacchino Del Regno (JAMI: fixup for 6.0-rc2) --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index e4b4131d8499dc..47f5e0df09b15e 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -250,6 +250,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,adreno-gmu" }, { .compatible = "qcom,mdp4" }, { .compatible = "qcom,mdss" }, + { .compatible = "qcom,msm8998-mss-pil" }, { .compatible = "qcom,qcm2290-mdss" }, { .compatible = "qcom,sc7180-mdss" }, { .compatible = "qcom,sc7180-mss-pil" }, @@ -257,6 +258,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc7280-mss-pil" }, { .compatible = "qcom,sc8180x-mdss" }, { .compatible = "qcom,sc8280xp-mdss" }, + { .compatible = "qcom,sdm660-mss-pil" }, { .compatible = "qcom,sdm670-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, From 482a8ed878bd6ffe1e71e46dd6f15b94212628ac Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 4 Aug 2021 16:39:35 +0200 Subject: [PATCH 08/65] iommu/arm-smmu-qcom: Allow choosing a custom bypass emulation context It cannot be taken for granted that the last IOMMU context is free and available for us to use it to emulate bypass streams and, at least on MSM8998's lpass iommu, using the last one will produce a crash; please note that this may not be only dependant on the SoC, but also on the firmware version. To overcome to this issue, allow specifying a different context for bypass emulation with the optional DT property "qcom,bypass-cbndx": if this property is not found this means that we are either booting with ACPI instead or that we don't want to specify a custom cb because the default one (the last context bank) is fine. Signed-off-by: AngeloGioacchino Del Regno (JAMI: fixup for v6.0-rc1) --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 47f5e0df09b15e..3647d0569849d3 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -313,7 +313,8 @@ static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) reg = arm_smmu_gr0_read(smmu, last_s2cr); if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { qsmmu->bypass_quirk = true; - qsmmu->bypass_cbndx = smmu->num_context_banks - 1; + if (qsmmu->bypass_cbndx == 0xff) + qsmmu->bypass_cbndx = smmu->num_context_banks - 1; set_bit(qsmmu->bypass_cbndx, smmu->context_map); @@ -484,6 +485,16 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, qsmmu->smmu.impl = impl; qsmmu->cfg = data->cfg; + qsmmu->bypass_cbndx = 0xff; + + if (np != NULL) { + /* + * This property is optional and we expect to fail finding it if: + * - Using the default bypass_cbndx (in the .cfg_probe cb) is fine; or + * - We are booting on ACPI + */ + of_property_read_u8(np, "qcom,bypass-cbndx", &qsmmu->bypass_cbndx); + } return &qsmmu->smmu; } From 8ad47ca1513665de9d33eb480f4325fdaf670d04 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 6 Aug 2021 13:14:41 +0200 Subject: [PATCH 09/65] iommu/arm-smmu: Allow skipping context bank disable at reset time On some SoCs some IOMMU context banks are actively used from TZ during system boot, or some hypervisor configurations will trigger a system reset upon disabling some protected/secured CBs. Allow skipping the disablement of such contexts at IOMMU reset time during initialization with a new implementation detail to work around this quirk. Signed-off-by: AngeloGioacchino Del Regno --- drivers/iommu/arm/arm-smmu/arm-smmu.c | 10 ++++++++++ drivers/iommu/arm/arm-smmu/arm-smmu.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 723273440c2118..25c07777a6ea29 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1680,6 +1680,16 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) /* Make sure all context banks are disabled and clear CB_FSR */ for (i = 0; i < smmu->num_context_banks; ++i) { + /* + * Some context banks cannot be disabled due to hypervisor + * configuration on some systems; if this is the case, + * skip disabling and writing FAULT on the CB FSR in order + * to avoid a system crash. + */ + if (smmu->impl && smmu->impl->reset_cb_nodisable && + smmu->impl->reset_cb_nodisable(smmu, i)) { + continue; + } arm_smmu_write_context_bank(smmu, i); arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_FSR, ARM_SMMU_CB_FSR_FAULT); } diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h index e2aeb511ae9033..ae9b4a0bc0cc5e 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.h +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h @@ -439,6 +439,7 @@ struct arm_smmu_impl { u64 val); int (*cfg_probe)(struct arm_smmu_device *smmu); int (*reset)(struct arm_smmu_device *smmu); + bool (*reset_cb_nodisable)(struct arm_smmu_device *smmu, int cbndx); int (*init_context)(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *cfg, struct device *dev); void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync, From 512b123e2b736b91934d610adf30541dd07799c3 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 6 Aug 2021 13:19:14 +0200 Subject: [PATCH 10/65] iommu/arm-smmu-qcom: Avoid disabling secured context banks Some Qualcomm SoCs' TZ/hypervisor configuration is disallowing the disablement of some context banks, being them used for tzapps and/or remote processors; any attempt to disable such CBs will result in triggering a fault and the system will freeze and/or reset. For this reason, get a list of context banks that should never get disabled during smmu initialization through a DT array property `qcom,reset-nodisable-cbs`. It was chosen to not hardcode the CBs as this is dependant on the SoC's firmware, which may vary on different boards. Signed-off-by: AngeloGioacchino Del Regno (JAMI: fixup for v6.0-rc1) --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 44 ++++++++++++++++++++++ drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 1 + 2 files changed, 45 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 3647d0569849d3..cd9ae1e46a373e 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -405,10 +405,32 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) return ret; } +static int qcom_smmu500_reset(struct arm_smmu_device *smmu) +{ + const struct device_node *np = smmu->dev->of_node; + + arm_mmu500_reset(smmu); + + if (of_device_is_compatible(np, "qcom,sdm845-smmu-500")) + return qcom_sdm845_smmu500_reset(smmu); + + return 0; +} + +static bool qcom_smmu500_reset_cb_nodisable(struct arm_smmu_device *smmu, + int cbndx) +{ + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); + + return test_bit(cbndx, qsmmu->reset_cb_nodisable_mask); +} + static const struct arm_smmu_impl qcom_smmu_v2_impl = { .init_context = qcom_smmu_init_context, .cfg_probe = qcom_smmu_cfg_probe, .def_domain_type = qcom_smmu_def_domain_type, + .reset = qcom_smmu500_reset, + .reset_cb_nodisable = qcom_smmu500_reset_cb_nodisable, .write_s2cr = qcom_smmu_write_s2cr, .tlb_sync = qcom_smmu_tlb_sync, }; @@ -442,6 +464,8 @@ static const struct arm_smmu_impl sdm845_smmu_500_impl = { static const struct arm_smmu_impl qcom_adreno_smmu_v2_impl = { .init_context = qcom_adreno_smmu_init_context, .def_domain_type = qcom_smmu_def_domain_type, + .reset = qcom_smmu500_reset, + .reset_cb_nodisable = qcom_smmu500_reset_cb_nodisable, .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, .write_sctlr = qcom_adreno_smmu_write_sctlr, .tlb_sync = qcom_smmu_tlb_sync, @@ -462,6 +486,8 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, const struct device_node *np = smmu->dev->of_node; const struct arm_smmu_impl *impl; struct qcom_smmu *qsmmu; + u8 reset_nodisable_cbs[ARM_SMMU_MAX_CBS]; + int i, sz; if (!data) return ERR_PTR(-EINVAL); @@ -486,6 +512,7 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, qsmmu->smmu.impl = impl; qsmmu->cfg = data->cfg; qsmmu->bypass_cbndx = 0xff; + bitmap_zero(qsmmu->reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS); if (np != NULL) { /* @@ -494,6 +521,23 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, * - We are booting on ACPI */ of_property_read_u8(np, "qcom,bypass-cbndx", &qsmmu->bypass_cbndx); + + /* + * Some context banks may not be disabled because they are + * secured: read from DT a list of secured contexts that cannot + * be disabled without crashing the system. + * This list is optional, as not all firmware configurations do + * require us skipping disablement of context banks. + */ + sz = of_property_read_variable_u8_array(np, "qcom,reset-nodisable-cbs", + reset_nodisable_cbs, + 1, ARM_SMMU_MAX_CBS); + if (sz > 0) { + for (i = 0; i < sz; i++) { + __set_bit(reset_nodisable_cbs[i], + qsmmu->reset_cb_nodisable_mask); + } + } } return &qsmmu->smmu; diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h index 3c134d1a62773e..74e342b103ea5f 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h @@ -9,6 +9,7 @@ struct qcom_smmu { struct arm_smmu_device smmu; const struct qcom_smmu_config *cfg; + DECLARE_BITMAP(reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS); bool bypass_quirk; u8 bypass_cbndx; u32 stall_enabled; From 85806b4ca7cd8f414f6da7cd3094bc6e2966358d Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 6 Aug 2021 15:15:33 +0200 Subject: [PATCH 11/65] iommu/arm-smmu-qcom: Don't modify sACR on hypervisor secured iommus Avoid modifying the contents of the secure Auxiliary Control Register on some Qualcomm SoCs: due to a hypervisor configuration on some firmware versions, this would result in a system crash. Signed-off-by: AngeloGioacchino Del Regno --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index cd9ae1e46a373e..09373ab919a9d9 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -408,8 +408,15 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) static int qcom_smmu500_reset(struct arm_smmu_device *smmu) { const struct device_node *np = smmu->dev->of_node; + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); - arm_mmu500_reset(smmu); + /* + * Execute the mmu-500 reset implementation detail only if there + * are no secured untouchable contexts in this iommu, otherwise + * the system will crash. + */ + if (bitmap_empty(qsmmu->reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS)) + arm_mmu500_reset(smmu); if (of_device_is_compatible(np, "qcom,sdm845-smmu-500")) return qcom_sdm845_smmu500_reset(smmu); From c600bda802f5006c8ea31884fbd58d21816078cb Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 4 Aug 2021 17:38:27 +0200 Subject: [PATCH 12/65] arm64: dts: sdm630: Override bypass emulation context for lpass, anoc2 On the LPASS and ANOC2 IOMMUs, we cannot use the last context to emulate bypass streams: set the right context banks to avoid crashes. --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index fe9d8f5fc4357e..25eea1403cbec3 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -27,6 +27,7 @@ mmc2 = &sdhc_2; }; + chosen { }; clocks { @@ -637,6 +638,7 @@ reg = <0x016c0000 0x40000>; #global-interrupts = <2>; #iommu-cells = <1>; + qcom,bypass-cbndx = /bits/ 8 <3>; interrupts = , @@ -1216,6 +1218,7 @@ compatible = "qcom,sdm630-smmu-v2", "qcom,smmu-v2"; reg = <0x05100000 0x40000>; #iommu-cells = <1>; + qcom,bypass-cbndx = /bits/ 8 <12>; #global-interrupts = <2>; interrupts = From d30c8cfe576ccff5652bfc63c1d6dd6570290493 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 4 Aug 2021 23:10:04 +0200 Subject: [PATCH 13/65] arm64: dts: qcom: sdm630: Disallow disabling secured iommu context banks Some IOMMU context banks are secured and any attempt to disable them during arm-smmu initialization will result in a system crash. To work around this issue, add a list of context banks that will never be disabled, but only reconfigured, at initialization time. Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 25eea1403cbec3..97b2331a5ef96b 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -638,7 +638,9 @@ reg = <0x016c0000 0x40000>; #global-interrupts = <2>; #iommu-cells = <1>; - qcom,bypass-cbndx = /bits/ 8 <3>; + qcom,bypass-cbndx = /bits/ 8 <6>; + qcom,reset-nodisable-cbs = /bits/ 8 <7 8 9 10 11 12 13 14 + 15 16 17 18 19 20>; interrupts = , @@ -1181,6 +1183,7 @@ "mem_iface"; #global-interrupts = <2>; #iommu-cells = <1>; + qcom,reset-nodisable-cbs = /bits/ 8 <2 3 4>; interrupts = , @@ -1219,6 +1222,7 @@ reg = <0x05100000 0x40000>; #iommu-cells = <1>; qcom,bypass-cbndx = /bits/ 8 <12>; + qcom,reset-nodisable-cbs = /bits/ 8 <13>; #global-interrupts = <2>; interrupts = From 4522e1606351f5164e4fc45e34fcde75099bfe61 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 28 Oct 2020 23:13:02 +0100 Subject: [PATCH 14/65] dt-bindings: touchscreen: Add binding for Novatek NT36xxx series driver Add binding for the Novatek NT36xxx series touchscreen driver. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring --- .../bindings/input/touchscreen/nt36xxx.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/nt36xxx.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/nt36xxx.yaml b/Documentation/devicetree/bindings/input/touchscreen/nt36xxx.yaml new file mode 100644 index 00000000000000..a360a9f5d43b5f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/nt36xxx.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/nt36xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT36xxx series touchscreen controller Bindings + +maintainers: + - AngeloGioacchino Del Regno + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + const: novatek,nt36525 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vdd-supply: + description: Power supply regulator for VDD pin + + vio-supply: + description: Power supply regulator on VDD-IO pin + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@62 { + compatible = "novatek,nt36525"; + reg = <0x62>; + interrupt-parent = <&tlmm>; + interrupts = <45 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; + }; + }; + +... From 63193af31dd78196b3225f48d5129bd42d0b75d9 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 28 Oct 2020 23:13:01 +0100 Subject: [PATCH 15/65] input: Add Novatek NT36xxx touchscreen driver This is a driver for the Novatek in-cell touch controller and supports various chips from the NT36xxx family, currently including NT36525, NT36672A, NT36676F, NT36772 and NT36870. Functionality like wake gestures and firmware flashing is not included: I am not aware of any of these DrIC+Touch combo chips not including a non-volatile memory and it should be highly unlikely to find one, since the touch firmware is embedded into the DriverIC one, which is obviously necessary to drive the display unit. However, the necessary address for the firmware update procedure was included into the address table in this driver so, in the event that someone finds the need to implement it for a reason or another, it will be pretty straightforward to. This driver is lightly based on the downstream implementation [1]. [1] https://github.com/Rasenkai/caf-tsoft-Novatek-nt36xxx Signed-off-by: AngeloGioacchino Del Regno --- drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/nt36xxx.c | 893 ++++++++++++++++++++++++++++ drivers/input/touchscreen/nt36xxx.h | 122 ++++ 4 files changed, 1028 insertions(+) create mode 100644 drivers/input/touchscreen/nt36xxx.c create mode 100644 drivers/input/touchscreen/nt36xxx.h diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c821fe3ee794e3..13dbdada574857 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -705,6 +705,18 @@ config TOUCHSCREEN_IMAGIS To compile this driver as a module, choose M here: the module will be called imagis. +config TOUCHSCREEN_NT36XXX + tristate "Novatek NT36XXX In-Cell I2C touchscreen controller" + depends on I2C + help + Say Y here if you have a Novatek NT36xxx series In-Cell + touchscreen connected to your system over I2C. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called nt36xxx. + config TOUCHSCREEN_IMX6UL_TSC tristate "Freescale i.MX6UL touchscreen controller" depends on ((OF && GPIOLIB) || COMPILE_TEST) && HAS_IOMEM diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a81cb5aa21a5b9..80682a55929689 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o +obj-$(CONFIG_TOUCHSCREEN_NT36XXX) += nt36xxx.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o diff --git a/drivers/input/touchscreen/nt36xxx.c b/drivers/input/touchscreen/nt36xxx.c new file mode 100644 index 00000000000000..ee8cdeea78c832 --- /dev/null +++ b/drivers/input/touchscreen/nt36xxx.c @@ -0,0 +1,893 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Novatek NT36xxx series touchscreens + * + * Copyright (C) 2010 - 2017 Novatek, Inc. + * Copyright (C) 2020 AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FW Param address */ +#define NT36XXX_FW_ADDR 0x01 + +/* Number of bytes for chip identification */ +#define NT36XXX_ID_LEN_MAX 6 + +/* Touch info */ +#define TOUCH_DEFAULT_MAX_WIDTH 1080 +#define TOUCH_DEFAULT_MAX_HEIGHT 2246 +#define TOUCH_MAX_FINGER_NUM 10 +#define TOUCH_MAX_PRESSURE 1000 + +/* Point data length */ +#define POINT_DATA_LEN 65 + +/* Global pages */ +#define NT36XXX_PAGE_CHIP_INFO 0x0001f64e +#define NT36XXX_PAGE_CRC 0x0003f135 + +/* Misc */ +#define NT36XXX_NUM_SUPPLIES 2 +#define NT36XXX_MAX_RETRIES 5 +#define NT36XXX_MAX_FW_RST_RETRY 50 + +struct nt36xxx_abs_object { + u16 x; + u16 y; + u16 z; + u8 tm; +}; + +struct nt36xxx_fw_info { + u8 fw_ver; + u8 x_num; + u8 y_num; + u8 max_buttons; + u16 abs_x_max; + u16 abs_y_max; + u16 nvt_pid; +}; + +struct nt36xxx_mem_map { + u32 evtbuf_addr; + u32 pipe0_addr; + u32 pipe1_addr; + u32 flash_csum_addr; + u32 flash_data_addr; +}; + +struct nt36xxx_i2c { + struct i2c_client *hw_client; + struct i2c_client *fw_client; + struct regmap *regmap; + struct regmap *fw_regmap; + struct input_dev *input; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; + + struct mutex lock; + + struct touchscreen_properties prop; + struct nt36xxx_fw_info fw_info; + struct nt36xxx_abs_object abs_obj; + + const struct nt36xxx_mem_map *mmap; +}; + +enum nt36xxx_chips { + NT36525_IC = 0, + NT36672A_IC, + NT36676F_IC, + NT36772_IC, + NT36870_IC, + NTMAX_IC, +}; + +struct nt36xxx_trim_table { + u8 id[NT36XXX_ID_LEN_MAX]; + u8 mask[NT36XXX_ID_LEN_MAX]; + enum nt36xxx_chips mapid; +}; + +enum nt36xxx_cmds { + NT36XXX_CMD_ENTER_SLEEP = 0x11, + NT36XXX_CMD_ENTER_WKUP_GESTURE = 0x13, + NT36XXX_CMD_UNLOCK = 0x35, + NT36XXX_CMD_BOOTLOADER_RESET = 0x69, + NT36XXX_CMD_SW_RESET = 0xa5, + NT36XXX_CMD_SET_PAGE = 0xff, +}; + +/** + * enum nt36xxx_fw_state - Firmware state + * @NT36XXX_STATE_INIT: IC Reset + * @NT36XXX_STATE_REK: ReK baseline + * @NT36XXX_STATE_REK_FINISH: Baseline is ready + * @NT36XXX_STATE_NORMAL_RUN: Firmware is running + */ +enum nt36xxx_fw_state { + NT36XXX_STATE_INIT = 0xa0, + NT36XXX_STATE_REK, + NT36XXX_STATE_REK_FINISH, + NT36XXX_STATE_NORMAL_RUN, + NT36XXX_STATE_MAX = 0xaf +}; + +enum nt36xxx_i2c_events { + NT36XXX_EVT_REPORT = 0x00, + NT36XXX_EVT_CRC = 0x35, + NT36XXX_EVT_CHIPID = 0x4e, + NT36XXX_EVT_HOST_CMD = 0x50, + NT36XXX_EVT_HS_OR_SUBCMD = 0x51, /* Handshake or subcommand byte */ + NT36XXX_EVT_RESET_COMPLETE = 0x60, + NT36XXX_EVT_FWINFO = 0x78, + NT36XXX_EVT_PROJECTID = 0x9a, +}; + +static const struct nt36xxx_mem_map nt36xxx_memory_maps[] = { + [NT36525_IC] = { 0x11a00, 0x10000, 0x12000, 0x14000, 0x14002 }, + [NT36672A_IC] = { 0x21c00, 0x20000, 0x23000, 0x24000, 0x24002 }, + [NT36676F_IC] = { 0x11a00, 0x10000, 0x12000, 0x14000, 0x14002 }, + [NT36772_IC] = { 0x11e00, 0x10000, 0x12000, 0x14000, 0x14002 }, + [NT36870_IC] = { 0x25000, 0x20000, 0x23000, 0x24000, 0x24002 }, +}; + +static const struct nt36xxx_trim_table trim_id_table[] = { + { + .id = { 0x0A, 0xFF, 0xFF, 0x72, 0x66, 0x03 }, + .mask = { 1, 0, 0, 1, 1, 1 }, + .mapid = NT36672A_IC, + }, + { + .id = { 0x55, 0x00, 0xFF, 0x00, 0x00, 0x00 }, + .mask = { 1, 1, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0x55, 0x72, 0xFF, 0x00, 0x00, 0x00 }, + .mask = { 1, 1, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xAA, 0x00, 0xFF, 0x00, 0x00, 0x00 }, + .mask = { 1, 1, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xAA, 0x72, 0xFF, 0x00, 0x00, 0x00 }, + .mask = { 1, 1, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x72, 0x67, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x70, 0x66, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x70, 0x67, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x72, 0x66, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x25, 0x65, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x70, 0x68, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36772_IC, + }, + { + .id = { 0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x03 }, + .mask = { 0, 0, 0, 1, 1, 1 }, + .mapid = NT36676F_IC, + }, +}; + +/** + * nt36xxx_set_page - Set page number for read/write + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_set_page(struct nt36xxx_i2c *ts, u32 pageaddr) +{ + u32 data = cpu_to_be32(pageaddr) >> 8; + int ret; + + ret = regmap_noinc_write(ts->fw_regmap, NT36XXX_CMD_SET_PAGE, + &data, sizeof(data)); + if (ret) + return ret; + + usleep_range(100, 200); + return ret; +} + +/** + * nt36xxx_sw_reset_idle - Warm restart the firmware + * @ts: Main driver structure + * + * This function restarts the running firmware without rebooting to + * the bootloader (warm restart) + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_sw_reset_idle(struct nt36xxx_i2c *ts) +{ + int ret; + + ret = regmap_write(ts->regmap, ts->hw_client->addr, + NT36XXX_CMD_SW_RESET); + if (ret) + return ret; + + /* Wait until the MCU resets the fw state */ + usleep_range(15000, 16000); + return ret; +} + +/** + * nt36xxx_bootloader_reset - Reset MCU to bootloader + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_bootloader_reset(struct nt36xxx_i2c *ts) +{ + int ret; + + ret = regmap_write(ts->regmap, ts->hw_client->addr, + NT36XXX_CMD_BOOTLOADER_RESET); + if (ret) + return ret; + + /* MCU has to reboot from bootloader: this is the typical boot time */ + msleep(35); + return ret; +} + +/** + * nt36xxx_check_reset_state - Check the boot state during reset + * @ts: Main driver structure + * @fw_state: Enumeration containing firmware states + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_check_reset_state(struct nt36xxx_i2c *ts, + enum nt36xxx_fw_state fw_state) +{ + u8 buf[2] = { 0 }; + int ret, retry = NT36XXX_MAX_FW_RST_RETRY; + + do { + ret = regmap_noinc_read(ts->fw_regmap, + NT36XXX_EVT_RESET_COMPLETE, + buf, sizeof(buf)); + if (likely(ret == 0) && + (buf[0] >= fw_state) && + (buf[0] <= NT36XXX_STATE_MAX)) { + ret = 0; + break; + } + usleep_range(10000, 11000); + } while (--retry); + + if (!retry) { + dev_err(&ts->hw_client->dev, "Firmware reset failed.\n"); + ret = -EBUSY; + } + + return ret; +} + +/** + * nt36xxx_read_pid - Read Novatek Project ID + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_read_pid(struct nt36xxx_i2c *ts) +{ + __be16 pid; + int ret; + + ret = nt36xxx_set_page(ts, ts->mmap->evtbuf_addr); + if (ret) + return ret; + + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_PROJECTID, + &pid, sizeof(pid)); + if (ret < 0) + return ret; + + ts->fw_info.nvt_pid = be16_to_cpu(pid); + return 0; +} + +/** + * __nt36xxx_get_fw_info - Get working params from firmware + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static int __nt36xxx_get_fw_info(struct nt36xxx_i2c *ts) +{ + struct nt36xxx_fw_info *fwi = &ts->fw_info; + u8 buf[11] = { 0 }; + int ret = 0; + + ret = nt36xxx_set_page(ts, ts->mmap->evtbuf_addr); + if (ret) + return ret; + + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_FWINFO, + buf, sizeof(buf)); + if (ret) + return ret; + + fwi->fw_ver = buf[0]; + fwi->x_num = buf[2]; + fwi->y_num = buf[3]; + fwi->abs_x_max = get_unaligned_be16(&buf[4]); + fwi->abs_y_max = get_unaligned_be16(&buf[6]); + fwi->max_buttons = buf[10]; + + /* Check fw info integrity and clear x_num, y_num if broken */ + if ((buf[0] + buf[1]) != 0xFF) { + dev_err(&ts->hw_client->dev, + "FW info is broken! fw_ver=0x%02X, ~fw_ver=0x%02X\n", + buf[0], buf[1]); + fwi->fw_ver = 0; + fwi->x_num = 18; + fwi->y_num = 32; + fwi->abs_x_max = TOUCH_DEFAULT_MAX_WIDTH; + fwi->abs_y_max = TOUCH_DEFAULT_MAX_HEIGHT; + fwi->max_buttons = 0; + return -EINVAL; + } + + /* Get Novatek ProjectID */ + return nt36xxx_read_pid(ts); +} + +static int nt36xxx_get_fw_info(struct nt36xxx_i2c *ts) +{ + struct nt36xxx_fw_info *fwi = &ts->fw_info; + int i, ret = 0; + + for (i = 0; i < NT36XXX_MAX_RETRIES; i++) { + ret = __nt36xxx_get_fw_info(ts); + if (ret == 0) + break; + } + + dev_dbg(&ts->hw_client->dev, + "FW Info: PID=0x%x, ver=0x%x res=%ux%u max=%ux%u buttons=%u", + fwi->nvt_pid, fwi->fw_ver, fwi->x_num, fwi->y_num, + fwi->abs_x_max, fwi->abs_y_max, fwi->max_buttons); + + return ret; +} + +/** + * nt36xxx_report - Report touch events + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static void nt36xxx_report(struct nt36xxx_i2c *ts) +{ + struct nt36xxx_abs_object *obj = &ts->abs_obj; + struct input_dev *input = ts->input; + u8 input_id = 0; + u8 point[POINT_DATA_LEN + 1] = { 0 }; + unsigned int ppos = 0; + int i, ret, finger_cnt = 0; + + mutex_lock(&ts->lock); + + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_REPORT, + point, sizeof(point)); + if (ret < 0) { + dev_err(&ts->hw_client->dev, + "Cannot read touch point data: %d\n", ret); + goto xfer_error; + } + + for (i = 0; i < TOUCH_MAX_FINGER_NUM; i++) { + ppos = 6 * i; + input_id = point[ppos + 0] >> 3; + if ((input_id == 0) || (input_id > TOUCH_MAX_FINGER_NUM)) + continue; + + if (((point[ppos] & 0x07) == 0x01) || + ((point[ppos] & 0x07) == 0x02)) { + obj->x = (point[ppos + 1] << 4) + + (point[ppos + 3] >> 4); + obj->y = (point[ppos + 2] << 4) + + (point[ppos + 3] & 0xf); + if ((obj->x > ts->prop.max_x) || + (obj->y > ts->prop.max_y)) + continue; + + obj->tm = point[ppos + 4]; + if (obj->tm == 0) + obj->tm = 1; + + obj->z = point[ppos + 5]; + if (i < 2) { + obj->z += point[i + 63] << 8; + if (obj->z > TOUCH_MAX_PRESSURE) + obj->z = TOUCH_MAX_PRESSURE; + } + + if (obj->z == 0) + obj->z = 1; + + input_mt_slot(input, input_id - 1); + input_mt_report_slot_state(input, + MT_TOOL_FINGER, true); + touchscreen_report_pos(input, &ts->prop, obj->x, + obj->y, true); + + input_report_abs(input, ABS_MT_TOUCH_MAJOR, obj->tm); + input_report_abs(input, ABS_MT_PRESSURE, obj->z); + + finger_cnt++; + } + } + input_mt_sync_frame(input); + input_sync(input); + +xfer_error: + enable_irq(ts->hw_client->irq); + + mutex_unlock(&ts->lock); +} + +static irqreturn_t nt36xxx_i2c_irq_handler(int irq, void *dev_id) +{ + struct nt36xxx_i2c *ts = dev_id; + + disable_irq_nosync(ts->hw_client->irq); + nt36xxx_report(ts); + + return IRQ_HANDLED; +} + +static bool nt36xxx_in_crc_reboot_loop(u8 *buf) +{ + return ((buf[0] == 0xFC) && (buf[1] == 0xFC) && (buf[2] == 0xFC)) || + ((buf[0] == 0xFF) && (buf[1] == 0xFF) && (buf[2] == 0xFF)); +} + +/** + * nt36xxx_stop_crc_reboot - Stop CRC reboot loop and warm-reboot the firmware + * @ts: Main driver structure + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_stop_crc_reboot(struct nt36xxx_i2c *ts) +{ + u8 buf[3] = { 0 }; + u8 val; + int ret, retry = NT36XXX_MAX_RETRIES; + + /* Read dummy buffer to check CRC fail reboot is happening or not */ + + /* Change I2C index to prevent getting 0xFF, but not 0xFC */ + ret = nt36xxx_set_page(ts, NT36XXX_PAGE_CHIP_INFO); + if (ret) { + dev_dbg(&ts->hw_client->dev, + "CRC reset failed: Cannot select page.\n"); + return ret; + } + + /* If ChipID command returns 0xFC or 0xFF, the MCU is in CRC reboot */ + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_CHIPID, + buf, sizeof(buf)); + if (ret) + return ret; + + if (!nt36xxx_in_crc_reboot_loop(buf)) + return 0; + + /* IC is in CRC fail reboot loop, needs to be stopped! */ + do { + /* Special reset-idle sequence for CRC failure */ + ret = regmap_write(ts->regmap, ts->hw_client->addr, + NT36XXX_CMD_SW_RESET); + if (ret) + dev_dbg(&ts->hw_client->dev, + "SW Reset 1 failed: may not recover\n"); + + ret = regmap_write(ts->regmap, ts->hw_client->addr, + NT36XXX_CMD_SW_RESET); + if (ret) + dev_dbg(&ts->hw_client->dev, + "SW Reset 2 failed: may not recover\n"); + usleep_range(1000, 1100); + + /* Clear CRC_ERR_FLAG */ + ret = nt36xxx_set_page(ts, NT36XXX_PAGE_CRC); + if (ret) + continue; + + val = 0xA5; + ret = regmap_raw_write(ts->fw_regmap, NT36XXX_EVT_CRC, + &val, sizeof(val)); + if (ret) + continue; + + /* Check CRC_ERR_FLAG */ + ret = nt36xxx_set_page(ts, NT36XXX_PAGE_CRC); + if (ret) + continue; + + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_CRC, + &buf, sizeof(buf)); + if (ret) + continue; + + if (buf[0] == 0xA5) + break; + } while (--retry); + + if (retry == 0) { + dev_err(&ts->hw_client->dev, + "CRC reset failed: buf=0x%2ph\n", buf); + } + + return ret; +} + +/** + * nt36xxx_i2c_chip_version_init - Detect Novatek NT36xxx family IC + * @ts: Main driver structure + * + * This function reads the ChipID from the IC and sets the right + * memory map for the detected chip. + * + * Return: Always zero for success, negative number for error + */ +static int nt36xxx_i2c_chip_version_init(struct nt36xxx_i2c *ts) +{ + u8 buf[7] = { 0 }; + int retry = NT36XXX_MAX_RETRIES; + int sz = sizeof(trim_id_table) / sizeof(struct nt36xxx_trim_table); + int i, list, mapid, ret; + + ret = nt36xxx_bootloader_reset(ts); + if (ret) { + dev_err(&ts->hw_client->dev, "Can't reset the nvt IC\n"); + return ret; + } + + do { + ret = nt36xxx_sw_reset_idle(ts); + if (ret) + continue; + + ret = regmap_write(ts->regmap, ts->hw_client->addr, NT36XXX_CMD_UNLOCK); + if (ret) + continue; + usleep_range(10000, 11000); + + ret = nt36xxx_set_page(ts, NT36XXX_PAGE_CHIP_INFO); + if (ret) + continue; + + memset(buf, 0, ARRAY_SIZE(buf)); + ret = regmap_noinc_read(ts->fw_regmap, NT36XXX_EVT_CHIPID, + buf, sizeof(buf)); + if (ret) + continue; + + /* Compare read chip id with trim list */ + for (list = 0; list < sz; list++) { + /* Compare each not masked byte */ + for (i = 0; i < NT36XXX_ID_LEN_MAX; i++) { + if (trim_id_table[list].mask[i] && + buf[i] != trim_id_table[list].id[i]) + break; + } + + if (i == NT36XXX_ID_LEN_MAX) { + mapid = trim_id_table[list].mapid; + ts->mmap = &nt36xxx_memory_maps[mapid]; + return 0; + } + + ts->mmap = NULL; + ret = -ENOENT; + } + + /* Stop CRC check to prevent IC auto reboot */ + if (nt36xxx_in_crc_reboot_loop(buf)) { + ret = nt36xxx_stop_crc_reboot(ts); + if (ret) + continue; + } + + usleep_range(10000, 11000); + } while (--retry); + + return ret; +} + +static const struct regmap_config nt36xxx_i2c_regmap_hw_config = { + .name = "nt36xxx_i2c_hw", + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_config nt36xxx_i2c_regmap_fw_config = { + .name = "nt36xxx_i2c_fw", + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, +}; + +static void nt36xxx_disable_regulators(void *data) +{ + struct nt36xxx_i2c *ts = data; + + regulator_bulk_disable(NT36XXX_NUM_SUPPLIES, ts->supplies); +} + +static int nt36xxx_i2c_probe(struct i2c_client *hw_client) +{ + struct nt36xxx_i2c *ts; + struct input_dev *input; + int ret; + + if (!i2c_check_functionality(hw_client->adapter, I2C_FUNC_I2C)) { + dev_err(&hw_client->dev, "i2c_check_functionality error\n"); + return -EIO; + } + + if (!hw_client->irq) { + dev_err(&hw_client->dev, "No irq specified\n"); + return -EINVAL; + } + + ts = devm_kzalloc(&hw_client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + ts->supplies = devm_kcalloc(&hw_client->dev, + NT36XXX_NUM_SUPPLIES, + sizeof(*ts->supplies), + GFP_KERNEL); + if (!ts->supplies) + return -ENOMEM; + + input = devm_input_allocate_device(&hw_client->dev); + if (!input) + return -ENOMEM; + + ts->fw_client = i2c_new_dummy_device(hw_client->adapter, + NT36XXX_FW_ADDR); + if (IS_ERR(ts->fw_client)) { + dev_err(&hw_client->dev, "Cannot add FW I2C device\n"); + return PTR_ERR(ts->fw_client); + } + + ts->hw_client = hw_client; + ts->input = input; + i2c_set_clientdata(ts->hw_client, ts); + i2c_set_clientdata(ts->fw_client, ts); + + ts->reset_gpio = devm_gpiod_get_optional(&hw_client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) + return PTR_ERR(ts->reset_gpio); + gpiod_set_consumer_name(ts->reset_gpio, "nt36xxx reset"); + + /* These supplies are optional */ + ts->supplies[0].supply = "vdd"; + ts->supplies[1].supply = "vio"; + ret = devm_regulator_bulk_get(&hw_client->dev, + NT36XXX_NUM_SUPPLIES, + ts->supplies); + if (ret) + return dev_err_probe(&hw_client->dev, ret, + "Cannot get supplies: %d\n", ret); + + ts->regmap = devm_regmap_init_i2c(ts->hw_client, + &nt36xxx_i2c_regmap_hw_config); + if (IS_ERR(ts->regmap)) { + dev_err(&hw_client->dev, "regmap (hw-addr) init failed\n"); + return PTR_ERR(ts->regmap); + } + + ts->fw_regmap = devm_regmap_init_i2c(ts->fw_client, + &nt36xxx_i2c_regmap_fw_config); + if (IS_ERR(ts->fw_regmap)) { + dev_err(&hw_client->dev, "regmap (fw-addr) init failed\n"); + return PTR_ERR(ts->fw_regmap); + } + + ret = regulator_bulk_enable(NT36XXX_NUM_SUPPLIES, ts->supplies); + if (ret) + return ret; + + usleep_range(10000, 11000); + + ret = devm_add_action_or_reset(&hw_client->dev, + nt36xxx_disable_regulators, ts); + if (ret) + return ret; + + mutex_init(&ts->lock); + + /* Set memory maps for the specific chip version */ + ret = nt36xxx_i2c_chip_version_init(ts); + if (ret) { + dev_err(&hw_client->dev, "Failed to check chip version\n"); + return ret; + } + + /* Reset the MCU */ + ret = nt36xxx_bootloader_reset(ts); + if (ret < 0) + return ret; + + /* Check and eventually wait until the MCU goes in reset state */ + ret = nt36xxx_check_reset_state(ts, NT36XXX_STATE_INIT); + if (ret < 0) + return ret; + + /* Get informations from the TS firmware */ + ret = nt36xxx_get_fw_info(ts); + if (ret < 0) + return ret; + + input->phys = devm_kasprintf(&hw_client->dev, GFP_KERNEL, + "%s/input0", dev_name(&hw_client->dev)); + if (!input->phys) + return -ENOMEM; + + input->name = "Novatek NT36XXX Touchscreen"; + input->id.bustype = BUS_I2C; + input->dev.parent = &hw_client->dev; + + __set_bit(EV_KEY, input->evbit); + __set_bit(EV_ABS, input->evbit); + input_set_capability(input, EV_KEY, BTN_TOUCH); + + ret = input_mt_init_slots(input, TOUCH_MAX_FINGER_NUM, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (ret) { + dev_err(&hw_client->dev, "Cannot init MT slots (%d)\n", ret); + return ret; + } + + input_set_abs_params(input, ABS_MT_PRESSURE, 0, + TOUCH_MAX_PRESSURE, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + ts->fw_info.abs_x_max - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + ts->fw_info.abs_y_max - 1, 0, 0); + + /* Override the firmware defaults, if needed */ + touchscreen_parse_properties(input, true, &ts->prop); + + input_set_drvdata(input, ts); + + ret = input_register_device(ts->input); + if (ret) { + dev_err(&hw_client->dev, "Failed to register input device: %d\n", + ret); + return ret; + } + + ret = devm_request_threaded_irq(&hw_client->dev, hw_client->irq, NULL, + nt36xxx_i2c_irq_handler, IRQF_ONESHOT, + hw_client->name, ts); + if (ret) { + dev_err(&hw_client->dev, "request irq failed: %d\n", ret); + return ret; + } + + return ret; +} + +static int __maybe_unused nt36xxx_i2c_suspend(struct device *dev) +{ + struct nt36xxx_i2c *ts = i2c_get_clientdata(to_i2c_client(dev)); + int ret; + + disable_irq(ts->hw_client->irq); + + ret = regmap_write(ts->fw_regmap, NT36XXX_EVT_HOST_CMD, + NT36XXX_CMD_ENTER_SLEEP); + if (ret) { + dev_err(&ts->hw_client->dev, "Cannot enter suspend!!\n"); + return ret; + } + + gpiod_set_value(ts->reset_gpio, 1); + + return 0; +} + +static int __maybe_unused nt36xxx_i2c_resume(struct device *dev) +{ + struct nt36xxx_i2c *ts = i2c_get_clientdata(to_i2c_client(dev)); + int ret; + + mutex_lock(&ts->lock); + + gpiod_set_value(ts->reset_gpio, 0); + + /* Reboot the MCU (also recalibrates the TS) */ + ret = nt36xxx_bootloader_reset(ts); + if (ret < 0) + goto end; + + ret = nt36xxx_check_reset_state(ts, NT36XXX_STATE_REK); + if (ret < 0) + goto end; + + enable_irq(ts->hw_client->irq); +end: + mutex_unlock(&ts->lock); + return ret; +} + +static SIMPLE_DEV_PM_OPS(nt36xxx_i2c_pm, + nt36xxx_i2c_suspend, nt36xxx_i2c_resume); + +static const struct of_device_id nt36xxx_of_match[] = { + { .compatible = "novatek,nt36525" }, + { } +}; +MODULE_DEVICE_TABLE(of, nt36xxx_of_match); + +static const struct i2c_device_id nt36xxx_i2c_ts_id[] = { + { "NVT-ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nt36xxx_i2c_ts_id); + +static struct i2c_driver nt36xxx_i2c_ts_driver = { + .driver = { + .name = "nt36xxx_ts", + .pm = &nt36xxx_i2c_pm, + .of_match_table = nt36xxx_of_match, + }, + .id_table = nt36xxx_i2c_ts_id, + .probe = nt36xxx_i2c_probe, +}; +module_i2c_driver(nt36xxx_i2c_ts_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Novatek NT36XXX Touchscreen Driver"); +MODULE_AUTHOR("AngeloGioacchino Del Regno "); diff --git a/drivers/input/touchscreen/nt36xxx.h b/drivers/input/touchscreen/nt36xxx.h new file mode 100644 index 00000000000000..6f03dfb456567a --- /dev/null +++ b/drivers/input/touchscreen/nt36xxx.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2010 - 2017 Novatek, Inc. + * Copyright (C) 2020 AngeloGioacchino Del Regno + */ + +#ifndef NT36XXX_H +#define NT36XXX_H + +#define NT36XXX_INPUT_DEVICE_NAME "Novatek NT36XXX Touch Sensor" + +/* These chips have this fixed address when in bootloader :( */ +#define NT36XXX_BLDR_ADDR 0x01 + +/* Input device info */ +#define NVT_TS_NAME "NVTCapacitiveTouchScreen" + +/* Number of bytes for chip identification */ +#define NT36XXX_ID_LEN_MAX 6 + +/* Touch info */ +#define TOUCH_DEFAULT_MAX_WIDTH 1080 +#define TOUCH_DEFAULT_MAX_HEIGHT 2246 +#define TOUCH_MAX_FINGER_NUM 10 +#define TOUCH_MAX_PRESSURE 1000 + +/* Point data length */ +#define POINT_DATA_LEN 65 + +/* Global pages */ +#define NT36XXX_PAGE_CHIP_INFO 0x0001f64e +#define NT36XXX_PAGE_CRC 0x0003f135 + +/* Misc */ +#define NT36XXX_NUM_SUPPLIES 2 +#define NT36XXX_MAX_RETRIES 5 +#define NT36XXX_MAX_FW_RST_RETRY 50 + +struct nt36xxx_abs_object { + u16 x; + u16 y; + u16 z; + u8 tm; +}; + +struct nt36xxx_fw_info { + u8 fw_ver; + u8 x_num; + u8 y_num; + u8 max_buttons; + u16 abs_x_max; + u16 abs_y_max; + u16 nvt_pid; +}; + +struct nt36xxx_mem_map { + u32 evtbuf_addr; + u32 pipe0_addr; + u32 pipe1_addr; + u32 flash_csum_addr; + u32 flash_data_addr; +}; + +struct nt36xxx_i2c { + struct i2c_client *client; + struct input_dev *input; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; + + struct work_struct ts_work; + struct workqueue_struct *ts_workq; + struct mutex lock; + + struct nt36xxx_fw_info fw_info; + struct nt36xxx_abs_object abs_obj; + + const struct nt36xxx_mem_map *mmap; + u8 max_fingers; +}; + +enum nt36xxx_chips { + NT36525_IC = 0, + NT36672A_IC, + NT36676F_IC, + NT36772_IC, + NT36870_IC, + NTMAX_IC, +}; + +struct nt36xxx_trim_table { + u8 id[NT36XXX_ID_LEN_MAX]; + u8 mask[NT36XXX_ID_LEN_MAX]; + enum nt36xxx_chips mapid; +}; + +enum nt36xxx_cmds { + NT36XXX_CMD_ENTER_SLEEP = 0x11, + NT36XXX_CMD_ENTER_WKUP_GESTURE = 0x13, + NT36XXX_CMD_UNLOCK = 0x35, + NT36XXX_CMD_BOOTLOADER_RESET = 0x69, + NT36XXX_CMD_SW_RESET = 0xa5, + NT36XXX_CMD_SET_PAGE = 0xff, +}; + +enum nt36xxx_fw_state { + NT36XXX_STATE_INIT = 0xa0, /* IC reset */ + NT36XXX_STATE_REK, /* ReK baseline */ + NT36XXX_STATE_REK_FINISH, /* Baseline is ready */ + NT36XXX_STATE_NORMAL_RUN, /* Normal run */ + NT36XXX_STATE_MAX = 0xaf +}; + +enum nt36xxx_i2c_events { + NT36XXX_EVT_CHIPID = 0x4e, + NT36XXX_EVT_HOST_CMD = 0x50, + NT36XXX_EVT_HS_OR_SUBCMD = 0x51, /* Handshake or subcommand byte */ + NT36XXX_EVT_RESET_COMPLETE = 0x60, + NT36XXX_EVT_FWINFO = 0x78, + NT36XXX_EVT_PROJECTID = 0x9a, +}; + +#endif From d65093a395d9e8d4e94441d6aeeb890c026ed9d7 Mon Sep 17 00:00:00 2001 From: Joel Selvaraj Date: Wed, 3 Feb 2021 19:54:45 +0000 Subject: [PATCH 16/65] power: supply: Add driver for Qualcomm PMIC fuel gauge Ths driver supports the fuel gauge hardware available on PMICs such as PMI8994, as well as gen 3 fuel gauge hardware available on PMI8998. Co-developed-by: Caleb Connolly Co-developed-by: Yassine Oudjana Signed-off-by: Yassine Oudjana qcom_fg: expose PROP_STATUS to fix upower not detecting charging status properly fg: adopt battery info API changes power: qcom_fg: silence -EPROBE_DEFER error Sometimes, the devm_power_supply_register function will return ERR_PTR(-EPROBE_DEFER) to make the driver subsystem probe the fuel guage later. This is not an error and do not report it as such. Signed-off-by: Richard Acayan power/supply: qcom_fg: add present sysfs property Present property is required for battery drivers from UPower>=1.90.0 onwards to work properly. Signed-off-by: Alexander Martinz Link: https://gitlab.com/sdm845-mainline/linux/-/commit/b5f9aa03a205d74b7b4e2470cb92c258040849d5 --- drivers/power/supply/Kconfig | 8 + drivers/power/supply/Makefile | 1 + drivers/power/supply/qcom_fg.c | 1318 ++++++++++++++++++++++++++++++++ 3 files changed, 1327 insertions(+) create mode 100644 drivers/power/supply/qcom_fg.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index bcfa63fb9f1e20..25cfa5c9a8a72e 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -999,6 +999,14 @@ config BATTERY_UG3105 device is off or suspended, the functionality of this driver is limited to reporting capacity only. +config BATTERY_QCOM_FG + tristate "Qualcomm PMIC fuel gauge driver" + depends on MFD_SPMI_PMIC + help + Say Y here to enable the Qualcomm PMIC Fuel Gauge driver. This + adds support for battery fuel gauging and state of charge of + battery connected to the fuel gauge. + config CHARGER_QCOM_SMB2 tristate "Qualcomm PMI8998 PMIC charger driver" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 8dcb4154531718..0199ea99fc00ec 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -115,5 +115,6 @@ obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o +obj-$(CONFIG_BATTERY_QCOM_FG) += qcom_fg.o obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_pmi8998_charger.o obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o diff --git a/drivers/power/supply/qcom_fg.c b/drivers/power/supply/qcom_fg.c new file mode 100644 index 00000000000000..271a0fc6765ee1 --- /dev/null +++ b/drivers/power/supply/qcom_fg.c @@ -0,0 +1,1318 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SOC */ +#define BATT_MONOTONIC_SOC 0x009 + +/* BATT */ +#define PARAM_ADDR_BATT_TEMP 0x150 +#define BATT_INFO_JEITA_COLD 0x162 +#define BATT_INFO_JEITA_COOL 0x163 +#define BATT_INFO_JEITA_WARM 0x164 +#define BATT_INFO_JEITA_HOT 0x165 +#define PARAM_ADDR_BATT_VOLTAGE 0x1a0 +#define PARAM_ADDR_BATT_CURRENT 0x1a2 + +/* MEMIF */ +#define MEM_INTF_STS 0x410 +#define MEM_INTF_CFG 0x450 +#define MEM_INTF_CTL 0x451 +#define MEM_INTF_IMA_CFG 0x452 +#define MEM_INTF_IMA_EXP_STS 0x455 +#define MEM_INTF_IMA_HW_STS 0x456 +#define MEM_INTF_IMA_ERR_STS 0x45f +#define MEM_INTF_IMA_BYTE_EN 0x460 +#define MEM_INTF_ADDR_LSB 0x461 +#define MEM_INTF_RD_DATA0 0x467 +#define MEM_INTF_WR_DATA0 0x463 +#define MEM_IF_DMA_STS 0x470 +#define MEM_IF_DMA_CTL 0x471 + +/* SRAM addresses */ +#define TEMP_THRESHOLD 0x454 +#define BATT_TEMP 0x550 +#define BATT_VOLTAGE_CURRENT 0x5cc + +#define BATT_TEMP_LSB_MASK GENMASK(7, 0) +#define BATT_TEMP_MSB_MASK GENMASK(2, 0) + +#define BATT_TEMP_JEITA_COLD 100 +#define BATT_TEMP_JEITA_COOL 50 +#define BATT_TEMP_JEITA_WARM 400 +#define BATT_TEMP_JEITA_HOT 450 + +#define MEM_INTF_AVAIL BIT(0) +#define MEM_INTF_CTL_BURST BIT(7) +#define MEM_INTF_CTL_WR_EN BIT(6) +#define RIF_MEM_ACCESS_REQ BIT(7) + +#define MEM_IF_TIMEOUT_MS 5000 +#define SRAM_ACCESS_RELEASE_DELAY_MS 500 + +struct qcom_fg_chip; + +struct qcom_fg_ops { + int (*get_capacity)(struct qcom_fg_chip *chip, int *); + int (*get_temperature)(struct qcom_fg_chip *chip, int *); + int (*get_current)(struct qcom_fg_chip *chip, int *); + int (*get_voltage)(struct qcom_fg_chip *chip, int *); + int (*get_temp_threshold)(struct qcom_fg_chip *chip, + enum power_supply_property psp, int *); + int (*set_temp_threshold)(struct qcom_fg_chip *chip, + enum power_supply_property psp, int); +}; + +struct qcom_fg_chip { + struct device *dev; + unsigned int base; + struct regmap *regmap; + const struct qcom_fg_ops *ops; + struct notifier_block nb; + + struct power_supply *batt_psy; + struct power_supply_battery_info *batt_info; + struct power_supply *chg_psy; + int status; + struct delayed_work status_changed_work; + + struct completion sram_access_granted; + struct completion sram_access_revoked; + struct workqueue_struct *sram_wq; + struct delayed_work sram_release_access_work; + spinlock_t sram_request_lock; + spinlock_t sram_rw_lock; + int sram_requests; +}; + +/************************ + * IO FUNCTIONS + * **********************/ + +/** + * @brief qcom_fg_read() - Read multiple registers with regmap_bulk_read + * + * @param chip Pointer to chip + * @param val Pointer to read values into + * @param addr Address to read from + * @param len Number of registers (bytes) to read + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_read(struct qcom_fg_chip *chip, u8 *val, u16 addr, int len) +{ + if (((chip->base + addr) & 0xff00) == 0) + return -EINVAL; + + dev_vdbg(chip->dev, "%s: Reading 0x%x bytes from 0x%x", __func__, len, addr); + + return regmap_bulk_read(chip->regmap, chip->base + addr, val, len); +} + +/** + * @brief qcom_fg_write() - Write multiple registers with regmap_bulk_write + * + * @param chip Pointer to chip + * @param val Pointer to write values from + * @param addr Address to write to + * @param len Number of registers (bytes) to write + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_write(struct qcom_fg_chip *chip, u8 *val, u16 addr, int len) +{ + bool sec_access = (addr & 0xff) > 0xd0; + u8 sec_addr_val = 0xa5; + int ret; + + if (((chip->base + addr) & 0xff00) == 0) + return -EINVAL; + + dev_vdbg(chip->dev, "%s: Writing 0x%x to 0x%x", __func__, *val, addr); + + if (sec_access) { + ret = regmap_bulk_write(chip->regmap, + ((chip->base + addr) & 0xff00) | 0xd0, + &sec_addr_val, 1); + if (ret) + return ret; + } + + return regmap_bulk_write(chip->regmap, chip->base + addr, val, len); +} + +/** + * @brief qcom_fg_masked_write() - like qcom_fg_write but applies + * a mask first. + * + * @param chip Pointer to chip + * @param val Pointer to write values from + * @param addr Address to write to + * @param len Number of registers (bytes) to write + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_masked_write(struct qcom_fg_chip *chip, u16 addr, u8 mask, u8 val) +{ + u8 reg; + int ret; + + ret = qcom_fg_read(chip, ®, addr, 1); + if (ret) + return ret; + + reg &= ~mask; + reg |= val & mask; + + return qcom_fg_write(chip, ®, addr, 1); +} + +/************************ + * SRAM FUNCTIONS + * **********************/ + +/** + * @brief qcom_fg_sram_check_access() - Check if SRAM is accessible + * + * @param chip Pointer to chip + * @return bool true if accessible, false otherwise + */ +static bool qcom_fg_sram_check_access(struct qcom_fg_chip *chip) +{ + u8 mem_if_status; + int ret; + + ret = qcom_fg_read(chip, &mem_if_status, + MEM_INTF_STS, 1); + + if (ret || !(mem_if_status & MEM_INTF_AVAIL)) + return false; + + ret = qcom_fg_read(chip, &mem_if_status, + MEM_INTF_CFG, 1); + + if (ret) + return false; + + return !!(mem_if_status & RIF_MEM_ACCESS_REQ); +} + +/** + * @brief qcom_fg_sram_request_access() - Request access to SRAM and wait for it + * + * @param chip Pointer to chip + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_sram_request_access(struct qcom_fg_chip *chip) +{ + bool sram_accessible; + int ret; + + spin_lock(&chip->sram_request_lock); + + sram_accessible = qcom_fg_sram_check_access(chip); + + dev_vdbg(chip->dev, "Requesting SRAM access, current state: %d, requests: %d\n", + sram_accessible, chip->sram_requests); + + if (!sram_accessible && chip->sram_requests == 0) { + ret = qcom_fg_masked_write(chip, MEM_INTF_CFG, + RIF_MEM_ACCESS_REQ, RIF_MEM_ACCESS_REQ); + if (ret) { + dev_err(chip->dev, + "Failed to set SRAM access request bit: %d\n", ret); + + spin_unlock(&chip->sram_request_lock); + return ret; + } + } + + chip->sram_requests++; + + spin_unlock(&chip->sram_request_lock); + + /* Wait to get access to SRAM, and try again if interrupted */ + do { + ret = wait_for_completion_interruptible_timeout( + &chip->sram_access_granted, + msecs_to_jiffies(MEM_IF_TIMEOUT_MS)); + } while(ret == -ERESTARTSYS); + + if (ret <= 0) { + ret = -ETIMEDOUT; + + spin_lock(&chip->sram_request_lock); + chip->sram_requests--; + spin_unlock(&chip->sram_request_lock); + } else { + ret = 0; + + reinit_completion(&chip->sram_access_revoked); + } + + return ret; +} + +/** + * @brief qcom_fg_sram_release_access() - Release access to SRAM + * + * @param chip Pointer to chip + * @return int 0 on success, negative errno on error + */ +static void qcom_fg_sram_release_access(struct qcom_fg_chip *chip) +{ + spin_lock(&chip->sram_request_lock); + + chip->sram_requests--; + + if(WARN(chip->sram_requests < 0, + "sram_requests=%d, cannot be negative! resetting to 0.\n", + chip->sram_requests)) + chip->sram_requests = 0; + + if(chip->sram_requests == 0) + /* Schedule access release */ + queue_delayed_work(chip->sram_wq, &chip->sram_release_access_work, + msecs_to_jiffies(SRAM_ACCESS_RELEASE_DELAY_MS)); + + spin_unlock(&chip->sram_request_lock); +} + +static void qcom_fg_sram_release_access_worker(struct work_struct *work) +{ + struct qcom_fg_chip *chip; + bool wait = false; + int ret; + + chip = container_of(work, struct qcom_fg_chip, sram_release_access_work.work); + + spin_lock(&chip->sram_request_lock); + + /* Request access release if there are still no access requests */ + if(chip->sram_requests == 0) { + qcom_fg_masked_write(chip, MEM_INTF_CFG, RIF_MEM_ACCESS_REQ, 0); + wait = true; + } + + spin_unlock(&chip->sram_request_lock); + + if(!wait) + return; + + /* Wait for SRAM access to be released, and try again if interrupted */ + do { + ret = wait_for_completion_interruptible_timeout( + &chip->sram_access_revoked, + msecs_to_jiffies(MEM_IF_TIMEOUT_MS)); + } while(ret == -ERESTARTSYS); + + reinit_completion(&chip->sram_access_granted); +} + +/** + * @brief qcom_fg_sram_config_access() - Configure access to SRAM + * + * @param chip Pointer to chip + * @param write 0 for read access, 1 for write access + * @param burst 1 to access mutliple addresses successively + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_sram_config_access(struct qcom_fg_chip *chip, + bool write, bool burst) +{ + u8 intf_ctl; + int ret; + + intf_ctl = (write ? MEM_INTF_CTL_WR_EN : 0) + | (burst ? MEM_INTF_CTL_BURST : 0); + + ret = qcom_fg_write(chip, &intf_ctl, + MEM_INTF_CTL, 1); + if (ret) { + dev_err(chip->dev, "Failed to configure SRAM access: %d\n", ret); + return ret; + } + + return 0; +} + +/** + * @brief qcom_fg_sram_read() - Read data from SRAM + * + * @param chip Pointer to chip + * @param val Pointer to read values into + * @param addr Address to read from + * @param len Number of bytes to read + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_sram_read(struct qcom_fg_chip *chip, + u8 *val, u16 addr, int len, int offset) +{ + u8 *rd_data = val; + int ret = 0; + + ret = qcom_fg_sram_request_access(chip); + if (ret) { + dev_err(chip->dev, "Failed to request SRAM access: %d", ret); + return ret; + } + + spin_lock(&chip->sram_rw_lock); + + dev_vdbg(chip->dev, + "Reading address 0x%x with offset %d of length %d from SRAM", + addr, len, offset); + + ret = qcom_fg_sram_config_access(chip, 0, (len > 4)); + if (ret) { + dev_err(chip->dev, "Failed to configure SRAM access: %d", ret); + goto out; + } + + while(len > 0) { + /* Set SRAM address register */ + ret = qcom_fg_write(chip, (u8 *) &addr, + MEM_INTF_ADDR_LSB, 2); + if (ret) { + dev_err(chip->dev, "Failed to set SRAM address: %d", ret); + goto out; + } + + ret = qcom_fg_read(chip, rd_data, + MEM_INTF_RD_DATA0 + offset, len); + + addr += 4; + + if (ret) + goto out; + + rd_data += 4 - offset; + len -= 4 - offset; + offset = 0; + } +out: + spin_unlock(&chip->sram_rw_lock); + qcom_fg_sram_release_access(chip); + + return ret; +} + +/** + * @brief qcom_fg_sram_write() - Write data to SRAM + * + * @param chip Pointer to chip + * @param val Pointer to write values from + * @param addr Address to write to + * @param len Number of bytes to write + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_sram_write(struct qcom_fg_chip *chip, + u8 *val, u16 addr, int len, int offset) +{ + u8 *wr_data = val; + int ret; + + ret = qcom_fg_sram_request_access(chip); + if (ret) { + dev_err(chip->dev, "Failed to request SRAM access: %d", ret); + return ret; + } + + spin_lock(&chip->sram_rw_lock); + + dev_vdbg(chip->dev, + "Wrtiting address 0x%x with offset %d of length %d to SRAM", + addr, len, offset); + + ret = qcom_fg_sram_config_access(chip, 1, (len > 4)); + if (ret) { + dev_err(chip->dev, "Failed to configure SRAM access: %d", ret); + goto out; + } + + while(len > 0) { + /* Set SRAM address register */ + ret = qcom_fg_write(chip, (u8 *) &addr, + MEM_INTF_ADDR_LSB, 2); + if (ret) { + dev_err(chip->dev, "Failed to set SRAM address: %d", ret); + goto out; + } + + ret = qcom_fg_write(chip, wr_data, + MEM_INTF_WR_DATA0 + offset, len); + + addr += 4; + + if (ret) + goto out; + + wr_data += 4 - offset; + len -= 4 - offset; + offset = 0; + } +out: + spin_unlock(&chip->sram_rw_lock); + qcom_fg_sram_release_access(chip); + + return ret; +} + +/************************* + * BATTERY STATUS + * ***********************/ + +/** + * @brief qcom_fg_get_capacity() - Get remaining capacity of battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_get_capacity(struct qcom_fg_chip *chip, int *val) +{ + u8 cap[2]; + int ret; + + ret = qcom_fg_read(chip, cap, BATT_MONOTONIC_SOC, 2); + if (ret) { + dev_err(chip->dev, "Failed to read capacity: %d", ret); + return ret; + } + + if (cap[0] != cap[1]) { + cap[0] = cap[0] < cap[1] ? cap[0] : cap[1]; + } + + *val = DIV_ROUND_CLOSEST((cap[0] - 1) * 98, 0xff - 2) + 1; + + return 0; +} + +/** + * @brief qcom_fg_get_temperature() - Get temperature of battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_get_temperature(struct qcom_fg_chip *chip, int *val) +{ + int temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_sram_read(chip, readval, BATT_TEMP, 2, 2); + if (ret) { + dev_err(chip->dev, "Failed to read temperature: %d", ret); + return ret; + } + + temp = readval[1] << 8 | readval[0]; + *val = temp * 625 / 1000 - 2730; + return 0; +} + +/** + * @brief qcom_fg_get_current() - Get current being drawn from battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_get_current(struct qcom_fg_chip *chip, int *val) +{ + s16 temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_sram_read(chip, readval, BATT_VOLTAGE_CURRENT, 2, 3); + if (ret) { + dev_err(chip->dev, "Failed to read current: %d", ret); + return ret; + } + + temp = (s16)(readval[1] << 8 | readval[0]); + *val = div_s64((s64)temp * 152587, 1000); + + return 0; +} + +/** + * @brief qcom_fg_get_voltage() - Get voltage of battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_get_voltage(struct qcom_fg_chip *chip, int *val) +{ + int temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_sram_read(chip, readval, BATT_VOLTAGE_CURRENT, 2, 1); + if (ret) { + dev_err(chip->dev, "Failed to read voltage: %d", ret); + return ret; + } + + temp = readval[1] << 8 | readval[0]; + *val = div_u64((u64)temp * 152587, 1000); + + return 0; +} + +/** + * @brief qcom_fg_get_temp_threshold() - Get configured temperature thresholds + * + * @param chip Pointer to chip + * @param psp Power supply property of temperature limit + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_get_temp_threshold(struct qcom_fg_chip *chip, + enum power_supply_property psp, int *val) +{ + u8 temp; + int offset; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP_MIN: + offset = 0; + break; + case POWER_SUPPLY_PROP_TEMP_MAX: + offset = 1; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + offset = 2; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + offset = 3; + break; + default: + return -EINVAL; + } + + ret = qcom_fg_sram_read(chip, &temp, TEMP_THRESHOLD, 1, offset); + if (ret < 0) { + dev_err(chip->dev, "Failed to read JEITA property %d level: %d\n", psp, ret); + return ret; + } + + *val = (temp - 30) * 10; + + return 0; +} + +/** + * @brief qcom_fg_set_temp_threshold() - Configure temperature thresholds + * + * @param chip Pointer to chip + * @param psp Power supply property of temperature limit + * @param val Pointer to get value from + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_set_temp_threshold(struct qcom_fg_chip *chip, + enum power_supply_property psp, int val) +{ + u8 temp; + int offset; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP_MIN: + offset = 0; + break; + case POWER_SUPPLY_PROP_TEMP_MAX: + offset = 1; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + offset = 2; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + offset = 3; + break; + default: + return -EINVAL; + } + + temp = val / 10 + 30; + + ret = qcom_fg_sram_write(chip, &temp, TEMP_THRESHOLD, 1, offset); + if (ret < 0) { + dev_err(chip->dev, "Failed to write JEITA property %d level: %d\n", psp, ret); + return ret; + } + + return 0; +} + +/************************* + * BATTERY STATUS, GEN3 + * ***********************/ + +/** + * @brief qcom_fg_gen3_get_temperature() - Get temperature of battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_gen3_get_temperature(struct qcom_fg_chip *chip, int *val) +{ + int temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_read(chip, readval, PARAM_ADDR_BATT_TEMP, 2); + if (ret) { + dev_err(chip->dev, "Failed to read temperature: %d\n", ret); + return ret; + } + + temp = ((readval[1] & BATT_TEMP_MSB_MASK) << 8) | + (readval[0] & BATT_TEMP_LSB_MASK); + temp = DIV_ROUND_CLOSEST(temp * 10, 4); + + *val = temp -2730; + return 0; +} + +/** + * @brief qcom_fg_gen3_get_current() - Get current being drawn from battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_gen3_get_current(struct qcom_fg_chip *chip, int *val) +{ + s16 temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_read(chip, readval, PARAM_ADDR_BATT_CURRENT, 2); + if (ret) { + dev_err(chip->dev, "Failed to read current: %d\n", ret); + return ret; + } + + //handle rev 1 too + temp = (s16)(readval[1] << 8 | readval[0]); + *val = div_s64((s64)temp * 488281, 1000); + + return 0; +} + +/** + * @brief qcom_fg_gen3_get_voltage() - Get voltage of battery + * + * @param chip Pointer to chip + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_gen3_get_voltage(struct qcom_fg_chip *chip, int *val) +{ + int temp; + u8 readval[2]; + int ret; + + ret = qcom_fg_read(chip, readval, PARAM_ADDR_BATT_VOLTAGE, 2); + if (ret) { + dev_err(chip->dev, "Failed to read voltage: %d\n", ret); + return ret; + } + + //handle rev 1 too + temp = readval[1] << 8 | readval[0]; + *val = div_u64((u64)temp * 122070, 1000); + return 0; +} + +/** + * @brief qcom_fg_gen3_get_temp_threshold() - Get configured temperature thresholds + * + * @param chip Pointer to chip + * @param psp Power supply property of temperature limit + * @param val Pointer to store value at + * @return int 0 on success, negative errno on error + */ +static int qcom_fg_gen3_get_temp_threshold(struct qcom_fg_chip *chip, + enum power_supply_property psp, int *val) +{ + u8 temp; + u16 reg; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_TEMP_MIN: + reg = BATT_INFO_JEITA_COLD; + break; + case POWER_SUPPLY_PROP_TEMP_MAX: + reg = BATT_INFO_JEITA_HOT; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + reg = BATT_INFO_JEITA_COOL; + break; + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + reg = BATT_INFO_JEITA_WARM; + break; + default: + return -EINVAL; + } + + ret = qcom_fg_read(chip, &temp, reg, 1); + if (ret < 0) { + dev_err(chip->dev, "Failed to read JEITA property %d level: %d\n", psp, ret); + return ret; + } + + /* Resolution is 0.5C. Base is -30C. */ + *val = (((5 * temp) / 10) - 30) * 10; + return 0; +} + +/************************ + * BATTERY POWER SUPPLY + * **********************/ + +/* Pre-Gen3 fuel gauge. PMI8996 and older */ +static const struct qcom_fg_ops ops_fg = { + .get_capacity = qcom_fg_get_capacity, + .get_temperature = qcom_fg_get_temperature, + .get_current = qcom_fg_get_current, + .get_voltage = qcom_fg_get_voltage, + .get_temp_threshold = qcom_fg_get_temp_threshold, + .set_temp_threshold = qcom_fg_set_temp_threshold, +}; + +/* Gen3 fuel gauge. PMI8998 and newer */ +static const struct qcom_fg_ops ops_fg_gen3 = { + .get_capacity = qcom_fg_get_capacity, + .get_temperature = qcom_fg_gen3_get_temperature, + .get_current = qcom_fg_gen3_get_current, + .get_voltage = qcom_fg_gen3_get_voltage, + .get_temp_threshold = qcom_fg_gen3_get_temp_threshold, +}; + +static enum power_supply_property qcom_fg_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TEMP_MIN, + POWER_SUPPLY_PROP_TEMP_MAX, + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, +}; + +static int qcom_fg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct qcom_fg_chip *chip = power_supply_get_drvdata(psy); + int temp, ret = 0; + + dev_dbg(chip->dev, "Getting property: %d", psp); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + /* Get status from charger if available */ + if (chip->chg_psy && + chip->status != POWER_SUPPLY_STATUS_UNKNOWN) { + val->intval = chip->status; + break; + } else { + /* + * Fall back to capacity and current-based + * status checking + */ + ret = chip->ops->get_capacity(chip, &temp); + if (ret) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + if (temp == 100) { + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + } + + ret = chip->ops->get_current(chip, &temp); + if (ret) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + if (temp < 0) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (temp > 0) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret = chip->ops->get_capacity(chip, &val->intval); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = chip->ops->get_current(chip, &val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = chip->ops->get_voltage(chip, &val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = chip->batt_info->voltage_min_design_uv; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = chip->batt_info->voltage_max_design_uv; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = chip->batt_info->charge_full_design_uah; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_TEMP: + ret = chip->ops->get_temperature(chip, &val->intval); + break; + case POWER_SUPPLY_PROP_TEMP_MIN: + case POWER_SUPPLY_PROP_TEMP_MAX: + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + ret = chip->ops->get_temp_threshold(chip, psp, &val->intval); + break; + default: + dev_err(chip->dev, "invalid property: %d\n", psp); + return -EINVAL; + } + + return ret; +} + +static const struct power_supply_desc batt_psy_desc = { + .name = "qcom-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = qcom_fg_props, + .num_properties = ARRAY_SIZE(qcom_fg_props), + .get_property = qcom_fg_get_property, +}; + +/******************** + * INIT FUNCTIONS + * ******************/ + +static int qcom_fg_iacs_clear_sequence(struct qcom_fg_chip *chip) +{ + u8 temp; + int ret; + + /* clear the error */ + ret = qcom_fg_masked_write(chip, MEM_INTF_IMA_CFG, BIT(2), BIT(2)); + if (ret) { + dev_err(chip->dev, "Failed to write IMA_CFG: %d\n", ret); + return ret; + } + + temp = 0x4; + ret = qcom_fg_write(chip, &temp, MEM_INTF_ADDR_LSB + 1, 1); + if (ret) { + dev_err(chip->dev, "Failed to write MEM_INTF_ADDR_MSB: %d\n", ret); + return ret; + } + + temp = 0x0; + ret = qcom_fg_write(chip, &temp, MEM_INTF_WR_DATA0 + 3, 1); + if (ret) { + dev_err(chip->dev, "Failed to write WR_DATA3: %d\n", ret); + return ret; + } + + ret = qcom_fg_read(chip, &temp, MEM_INTF_RD_DATA0 + 3, 1); + if (ret) { + dev_err(chip->dev, "Failed to write RD_DATA3: %d\n", ret); + return ret; + } + + ret = qcom_fg_masked_write(chip, MEM_INTF_IMA_CFG, BIT(2), 0); + if (ret) { + dev_err(chip->dev, "Failed to write IMA_CFG: %d\n", ret); + return ret; + } + + return 0; +} + +static int qcom_fg_clear_ima(struct qcom_fg_chip *chip, + bool check_hw_sts) +{ + u8 err_sts, exp_sts, hw_sts; + bool run_err_clr_seq = false; + int ret; + + ret = qcom_fg_read(chip, &err_sts, + MEM_INTF_IMA_ERR_STS, 1); + if (ret) { + dev_err(chip->dev, "Failed to read IMA_ERR_STS: %d\n", ret); + return ret; + } + + ret = qcom_fg_read(chip, &exp_sts, + MEM_INTF_IMA_EXP_STS, 1); + if (ret) { + dev_err(chip->dev, "Failed to read IMA_EXP_STS: %d\n", ret); + return ret; + } + + if (check_hw_sts) { + ret = qcom_fg_read(chip, &hw_sts, + MEM_INTF_IMA_HW_STS, 1); + if (ret) { + dev_err(chip->dev, "Failed to read IMA_HW_STS: %d\n", ret); + return ret; + } + /* + * Lower nibble should be equal to upper nibble before SRAM + * transactions begins from SW side. + */ + if ((hw_sts & 0x0f) != hw_sts >> 4) { + dev_dbg(chip->dev, "IMA HW not in correct state, hw_sts=%x\n", + hw_sts); + run_err_clr_seq = true; + } + } + + if (exp_sts & (BIT(0) | BIT(1) | BIT(3) | + BIT(4) | BIT(5) | BIT(6) | + BIT(7))) { + dev_dbg(chip->dev, "IMA exception bit set, exp_sts=%x\n", exp_sts); + run_err_clr_seq = true; + } + + if (run_err_clr_seq) { + ret = qcom_fg_iacs_clear_sequence(chip); + if (!ret) + return -EAGAIN; + } + + return 0; +} + +static irqreturn_t qcom_fg_handle_soc_delta(int irq, void *data) +{ + struct qcom_fg_chip *chip = data; + + /* Signal change in state of charge */ + power_supply_changed(chip->batt_psy); + dev_dbg(chip->dev, "SOC changed"); + + return IRQ_HANDLED; +} + +static irqreturn_t qcom_fg_handle_mem_avail(int irq, void *data) +{ + struct qcom_fg_chip *chip = data; + + if (qcom_fg_sram_check_access(chip)) { + complete_all(&chip->sram_access_granted); + dev_dbg(chip->dev, "SRAM access granted"); + } else { + complete_all(&chip->sram_access_revoked); + dev_dbg(chip->dev, "SRAM access revoked"); + } + + return IRQ_HANDLED; +} + +static void qcom_fg_status_changed_worker(struct work_struct *work) +{ + struct qcom_fg_chip *chip = container_of(work, struct qcom_fg_chip, + status_changed_work.work); + + power_supply_changed(chip->batt_psy); +} + +static int qcom_fg_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct qcom_fg_chip *chip = container_of(nb, struct qcom_fg_chip, nb); + struct power_supply *psy = v; + union power_supply_propval propval; + int ret; + + if (psy == chip->chg_psy) { + ret = power_supply_get_property(psy, + POWER_SUPPLY_PROP_STATUS, &propval); + if (ret) + chip->status = POWER_SUPPLY_STATUS_UNKNOWN; + + chip->status = propval.intval; + + power_supply_changed(chip->batt_psy); + + if (chip->status == POWER_SUPPLY_STATUS_UNKNOWN) { + /* + * REVISIT: Find better solution or remove current-based + * status checking once checking is properly implemented + * in charger drivers + + * Sometimes it take a while for current to stabilize, + * so signal property change again later to make sure + * current-based status is properly detected. + */ + cancel_delayed_work_sync(&chip->status_changed_work); + schedule_delayed_work(&chip->status_changed_work, + msecs_to_jiffies(1000)); + } + } + + return NOTIFY_OK; +} + +static int qcom_fg_probe(struct platform_device *pdev) +{ + struct power_supply_config supply_config = {}; + struct qcom_fg_chip *chip; + const __be32 *prop_addr; + int irq; + u8 dma_status; + bool error_present; + int ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &pdev->dev; + chip->ops = of_device_get_match_data(&pdev->dev); + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + dev_err(chip->dev, "Failed to locate the regmap\n"); + return -ENODEV; + } + + /* Get base address */ + prop_addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL); + if (!prop_addr) { + dev_err(chip->dev, "Failed to read SOC base address from dt\n"); + return -EINVAL; + } + chip->base = be32_to_cpu(*prop_addr); + + /* + * Change the FG_MEM_INT interrupt to track IACS_READY + * condition instead of end-of-transaction. This makes sure + * that the next transaction starts only after the hw is ready. + * IACS_INTR_SRC_SLCT is BIT(3) + */ + ret = qcom_fg_masked_write(chip, + MEM_INTF_IMA_CFG, BIT(3), BIT(3)); + if (ret) { + dev_err(chip->dev, + "Failed to configure interrupt sourete: %d\n", ret); + return ret; + } + + ret = qcom_fg_clear_ima(chip, true); + if (ret && ret != -EAGAIN) { + dev_err(chip->dev, "Failed to clear IMA exception: %d\n", ret); + return ret; + } + + /* Check and clear DMA errors */ + ret = qcom_fg_read(chip, &dma_status, MEM_IF_DMA_STS, 1); + if (ret < 0) { + dev_err(chip->dev, "Failed to read dma_status: %d\n", ret); + return ret; + } + + error_present = dma_status & (BIT(1) | BIT(2)); + ret = qcom_fg_masked_write(chip, MEM_IF_DMA_CTL, BIT(0), + error_present ? BIT(0) : 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to write dma_ctl: %d\n", ret); + return ret; + } + + supply_config.drv_data = chip; + supply_config.of_node = pdev->dev.of_node; + + chip->batt_psy = devm_power_supply_register(chip->dev, + &batt_psy_desc, &supply_config); + if (IS_ERR(chip->batt_psy)) { + if (PTR_ERR(chip->batt_psy) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to register battery\n"); + return PTR_ERR(chip->batt_psy); + } + + platform_set_drvdata(pdev, chip); + + ret = power_supply_get_battery_info(chip->batt_psy, &chip->batt_info); + if (ret) { + dev_err(&pdev->dev, "Failed to get battery info: %d\n", ret); + return ret; + } + + /* Initialize SRAM */ + if (of_device_is_compatible(pdev->dev.of_node, "qcom,pmi8994-fg")) { + irq = of_irq_get_byname(pdev->dev.of_node, "mem-avail"); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get irq mem-avail byname: %d\n", + irq); + return irq; + } + + init_completion(&chip->sram_access_granted); + init_completion(&chip->sram_access_revoked); + + chip->sram_wq = create_singlethread_workqueue("qcom_fg"); + INIT_DELAYED_WORK(&chip->sram_release_access_work, + qcom_fg_sram_release_access_worker); + + ret = devm_request_threaded_irq(chip->dev, irq, NULL, + qcom_fg_handle_mem_avail, + IRQF_ONESHOT, "mem-avail", chip); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request mem-avail IRQ: %d\n", ret); + return ret; + } + + spin_lock_init(&chip->sram_request_lock); + spin_lock_init(&chip->sram_rw_lock); + chip->sram_requests = 0; + } + + /* Set default temperature thresholds */ + if (chip->ops->set_temp_threshold) { + ret = chip->ops->set_temp_threshold(chip, + POWER_SUPPLY_PROP_TEMP_MIN, + BATT_TEMP_JEITA_COLD); + if (ret) { + dev_err(chip->dev, + "Failed to set cold threshold: %d\n", ret); + return ret; + } + + ret = chip->ops->set_temp_threshold(chip, + POWER_SUPPLY_PROP_TEMP_MAX, + BATT_TEMP_JEITA_WARM); + if (ret) { + dev_err(chip->dev, + "Failed to set warm threshold: %d\n", ret); + return ret; + } + + ret = chip->ops->set_temp_threshold(chip, + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, + BATT_TEMP_JEITA_COOL); + if (ret) { + dev_err(chip->dev, + "Failed to set cool threshold: %d\n", ret); + return ret; + } + + ret = chip->ops->set_temp_threshold(chip, + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, + BATT_TEMP_JEITA_HOT); + if (ret) { + dev_err(chip->dev, + "Failed to set hot threshold: %d\n", ret); + return ret; + } + } + + /* Get soc-delta IRQ */ + irq = of_irq_get_byname(pdev->dev.of_node, "soc-delta"); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get irq soc-delta byname: %d\n", + irq); + return irq; + } + + ret = devm_request_threaded_irq(chip->dev, irq, NULL, + qcom_fg_handle_soc_delta, + IRQF_ONESHOT, "soc-delta", chip); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request soc-delta IRQ: %d\n", ret); + return ret; + } + + /* Optional: Get charger power supply for status checking */ + chip->chg_psy = power_supply_get_by_phandle(chip->dev->of_node, + "power-supplies"); + if (IS_ERR(chip->chg_psy)) { + ret = PTR_ERR(chip->chg_psy); + dev_warn(chip->dev, "Failed to get charger supply: %d\n", ret); + chip->chg_psy = NULL; + } + + if (chip->chg_psy) { + INIT_DELAYED_WORK(&chip->status_changed_work, + qcom_fg_status_changed_worker); + + chip->nb.notifier_call = qcom_fg_notifier_call; + ret = power_supply_reg_notifier(&chip->nb); + if (ret) { + dev_err(chip->dev, + "Failed to register notifier: %d\n", ret); + return ret; + } + } + + return 0; +} + +static void qcom_fg_remove(struct platform_device *pdev) +{ + struct qcom_fg_chip *chip = platform_get_drvdata(pdev); + + power_supply_put_battery_info(chip->chg_psy, chip->batt_info); + + if(chip->sram_wq) + destroy_workqueue(chip->sram_wq); +} + +static const struct of_device_id fg_match_id_table[] = { + { .compatible = "qcom,pmi8994-fg", .data = &ops_fg }, + { .compatible = "qcom,pmi8998-fg", .data = &ops_fg_gen3 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fg_match_id_table); + +static struct platform_driver qcom_fg_driver = { + .probe = qcom_fg_probe, + .remove = qcom_fg_remove, + .driver = { + .name = "qcom-fg", + .of_match_table = fg_match_id_table, + }, +}; + +module_platform_driver(qcom_fg_driver); + +MODULE_AUTHOR("Caleb Connolly "); +MODULE_AUTHOR("Joel Selvaraj "); +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Qualcomm PMIC Fuel Gauge Driver"); +MODULE_LICENSE("GPL v2"); From b0b5a635586a9f648e6562bec1ad24dde8f8199b Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 10 Dec 2021 02:26:52 +0000 Subject: [PATCH 17/65] dt-bindings: input: add Qualcomm SPMI haptics driver Add bindings for qcom PMIC SPMI haptics driver. Signed-off-by: Caleb Connolly --- .../bindings/input/qcom,spmi-haptics.yaml | 123 ++++++++++++++++++ include/dt-bindings/input/qcom,spmi-haptics.h | 32 +++++ 2 files changed, 155 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml create mode 100644 include/dt-bindings/input/qcom,spmi-haptics.h diff --git a/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml b/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml new file mode 100644 index 00000000000000..d02a30c7554cd9 --- /dev/null +++ b/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2020 Unisoc Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/qcom,spmi-haptics.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies Inc PMI8998 spmi haptics + +maintainers: + - Caleb Connolly + +description: | + Qualcomm SPMI haptics is a peripheral on some QTI PMICs. It supports linear resonant + actuators and eccentric rotating mass type haptics commonly found in mobile devices. + It supports multiple sources of wave data such as an internal buffer, direct play + (from kernel or userspace) as well as an audio output mode. + +properties: + compatible: + items: + - enum: + - qcom,pmi8998-haptics + - qcom,pmi8996-haptics + - qcom,pmi8941-haptics + + reg: + maxItems: 1 + + interrupts: + items: + - description: short circuit interrupt + - description: play interrupt + + interrupt-names: + items: + - const: short + - const: play + + qcom,actuator-type: + description: | + The type of actuator attached to the hardware. + Allowed values are, + 0 - HAP_TYPE_LRA + 1 - HAP_TYPE_ERM + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + default: 0 + + qcom,wave-shape: + description: | + Selects the wave shape to use. + Allowed values are, + 0 - HAP_WAVE_SINE + 1 - HAP_WAVE_SQUARE + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + default: 0 + + qcom,play-mode: + description: | + Selects the play mode to use. + Allowed values are, + 0 - HAP_PLAY_DIRECT + 1 - HAP_PLAY_BUFFER + 2 - HAP_PLAY_AUDIO + 3 - HAP_PLAY_PWM + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2, 3 ] + default: 2 + + qcom,wave-play-rate-us: + description: | + Wave sample durection in microseconds, 1/f where f + is the resonant frequency of the actuator. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 20475 + + qcom,brake-pattern: + minItems: 4 + maxItems: 4 + description: | + The brake pattern are the strengths of the pattern + used to brake the haptics. Allowed values are, + 0 - 0V + 1 - Vmax/4 + 2 - Vmax/2 + 3 - Vmax + $ref: /schemas/types.yaml#/definitions/uint32-array + default: [0x3, 0x3, 0x2, 0x1] + +required: + - compatible + - reg + - interrupts + - qcom,wave-play-rate-us + +additionalProperties: false + +examples: + - | + #include + #include + + spmi { + #address-cells = <1>; + #size-cells = <0>; + pmi8998_haptics: haptics@c000 { + compatible = "qcom,pmi8998-haptics"; + reg = <0xc000>; + + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "short", "play"; + + qcom,wave-shape = ; + qcom,play-mode = ; + qcom,brake-pattern = <0x3 0x3 0x2 0x1>; + + status = "disabled"; + }; + }; diff --git a/include/dt-bindings/input/qcom,spmi-haptics.h b/include/dt-bindings/input/qcom,spmi-haptics.h new file mode 100644 index 00000000000000..14a7e7d1471e89 --- /dev/null +++ b/include/dt-bindings/input/qcom,spmi-haptics.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * This header provides constants for pmi8998 SPMI haptics options. + */ + +#ifndef _DT_BINDINGS_QCOM_PMIC_SPMI_HAPTICS_ +#define _DT_BINDINGS_QCOM_PMIC_SPMI_HAPTICS_ + +// Actuator types +#define HAP_TYPE_LRA 0 +#define HAP_TYPE_ERM 1 + +// LRA Wave type +#define HAP_WAVE_SINE 0 +#define HAP_WAVE_SQUARE 1 + +// Play modes +#define HAP_PLAY_DIRECT 0 +#define HAP_PLAY_BUFFER 1 +#define HAP_PLAY_AUDIO 2 +#define HAP_PLAY_PWM 3 + +#define HAP_PLAY_MAX HAP_PLAY_PWM + +// Auto resonance type +#define HAP_AUTO_RES_NONE 0 +#define HAP_AUTO_RES_ZXD 1 +#define HAP_AUTO_RES_QWD 2 +#define HAP_AUTO_RES_MAX_QWD 3 +#define HAP_AUTO_RES_ZXD_EOP 4 + +#endif /* _DT_BINDINGS_QCOM_PMIC_SPMI_HAPTICS_ */ From d12b844bea3d485cb9e5443a01753135265a21ce Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 10 Dec 2021 02:26:56 +0000 Subject: [PATCH 18/65] input: add Qualcomm SPMI haptics driver Add support for the haptics found in pmi8998 and related PMICs. Based on the ff-memless interface. Currently this driver provides a partial implementation of hardware features. This driver only supports LRAs (Linear Resonant Actuators) in the "buffer" mode with a single wave pattern. Signed-off-by: Caleb Connolly --- drivers/input/misc/Kconfig | 12 + drivers/input/misc/Makefile | 1 + drivers/input/misc/qcom-spmi-haptics.c | 975 +++++++++++++++++++++++++ 3 files changed, 988 insertions(+) create mode 100644 drivers/input/misc/qcom-spmi-haptics.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 6a852c76331b62..df77c0fdc93e79 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -214,6 +214,18 @@ config INPUT_PMIC8XXX_PWRKEY To compile this driver as a module, choose M here: the module will be called pmic8xxx-pwrkey. +config INPUT_QCOM_SPMI_HAPTICS + tristate "Qualcomm SPMI HAPTICS" + depends on ARCH_QCOM + depends on SPMI + select INPUT_FF_MEMLESS + help + This option enables support for the haptics found in pmi8998 and + related PMICs. Based on the ff-memless interface. + + To compile this driver as module, choose M here: the + module will be called qcom_spmi_haptics. + config INPUT_SPARCSPKR tristate "SPARC Speaker support" depends on PCI && SPARC64 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 4f7f736831ba84..ff1ce5d4a52562 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o +obj-$(CONFIG_INPUT_QCOM_SPMI_HAPTICS) += qcom-spmi-haptics.o obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o diff --git a/drivers/input/misc/qcom-spmi-haptics.c b/drivers/input/misc/qcom-spmi-haptics.c new file mode 100644 index 00000000000000..7221dd6ad9227d --- /dev/null +++ b/drivers/input/misc/qcom-spmi-haptics.c @@ -0,0 +1,975 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, Caleb Connolly + * Qualcomm QPMI haptics driver for pmi8998 and related PMICs. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define HAP_STATUS_1_REG 0x0A +#define HAP_BUSY_BIT BIT(1) +#define SC_FLAG_BIT BIT(3) +#define AUTO_RES_ERROR_BIT BIT(4) + +#define HAP_LRA_AUTO_RES_LO_REG 0x0B +#define HAP_LRA_AUTO_RES_HI_REG 0x0C + +#define HAP_EN_CTL_REG 0x46 +#define HAP_EN_BIT BIT(7) + +#define HAP_EN_CTL2_REG 0x48 +#define BRAKE_EN_BIT BIT(0) + +#define HAP_AUTO_RES_CTRL_REG 0x4B +#define AUTO_RES_EN_BIT BIT(7) +#define AUTO_RES_ERR_RECOVERY_BIT BIT(3) +#define AUTO_RES_EN_FLAG_BIT BIT(0) + +#define HAP_CFG1_REG 0x4C +#define HAP_ACT_TYPE_MASK BIT(0) + +#define HAP_CFG2_REG 0x4D +#define HAP_LRA_RES_TYPE_MASK BIT(0) + +#define HAP_SEL_REG 0x4E +#define HAP_WF_SOURCE_MASK GENMASK(5, 4) +#define HAP_WF_SOURCE_SHIFT 4 + +#define HAP_LRA_AUTO_RES_REG 0x4F +#define LRA_AUTO_RES_MODE_MASK GENMASK(6, 4) +#define LRA_AUTO_RES_MODE_SHIFT 4 +#define LRA_HIGH_Z_MASK GENMASK(3, 2) +#define LRA_HIGH_Z_SHIFT 2 +#define LRA_RES_CAL_MASK GENMASK(1, 0) +#define HAP_RES_CAL_PERIOD_MIN 4 +#define HAP_RES_CAL_PERIOD_MAX 32 + +#define HAP_VMAX_CFG_REG 0x51 +#define HAP_VMAX_OVD_BIT BIT(6) +#define HAP_VMAX_MASK GENMASK(5, 1) +#define HAP_VMAX_SHIFT 1 + +#define HAP_ILIM_CFG_REG 0x52 +#define HAP_ILIM_SEL_MASK BIT(0) +#define HAP_ILIM_400_MA 0 +#define HAP_ILIM_800_MA 1 + +#define HAP_SC_DEB_REG 0x53 +#define HAP_SC_DEB_MASK GENMASK(2, 0) +#define HAP_SC_DEB_CYCLES_MIN 0 +#define HAP_DEF_SC_DEB_CYCLES 8 +#define HAP_SC_DEB_CYCLES_MAX 32 + +#define HAP_RATE_CFG1_REG 0x54 +#define HAP_RATE_CFG1_MASK GENMASK(7, 0) +#define HAP_RATE_CFG2_SHIFT 8 + +#define HAP_RATE_CFG2_REG 0x55 +#define HAP_RATE_CFG2_MASK GENMASK(3, 0) + +#define HAP_SC_CLR_REG 0x59 +#define SC_CLR_BIT BIT(0) + +#define HAP_BRAKE_REG 0x5C +#define HAP_BRAKE_PAT_MASK 0x3 + +#define HAP_WF_REPEAT_REG 0x5E +#define WF_REPEAT_MASK GENMASK(6, 4) +#define WF_REPEAT_SHIFT 4 +#define WF_REPEAT_MIN 1 +#define WF_REPEAT_MAX 128 +#define WF_S_REPEAT_MASK GENMASK(1, 0) +#define WF_S_REPEAT_MIN 1 +#define WF_S_REPEAT_MAX 8 + +#define HAP_WF_S1_REG 0x60 +#define HAP_WF_SIGN_BIT BIT(7) +#define HAP_WF_OVD_BIT BIT(6) +#define HAP_WF_SAMP_MAX GENMASK(5, 1) +#define HAP_WF_SAMPLE_LEN 8 + +#define HAP_PLAY_REG 0x70 +#define HAP_PLAY_BIT BIT(7) +#define HAP_PAUSE_BIT BIT(0) + +#define HAP_SEC_ACCESS_REG 0xD0 +#define HAP_SEC_ACCESS_UNLOCK 0xA5 + +#define HAP_TEST2_REG 0xE3 + + +#define HAP_VMAX_MIN_MV 116 +#define HAP_VMAX_MAX_MV 3596 +#define HAP_VMAX_MAX_MV_STRONG 3596 + +#define HAP_WAVE_PLAY_RATE_MIN_US 0 +#define HAP_WAVE_PLAY_RATE_MAX_US 20475 +#define HAP_WAVE_PLAY_TIME_MAX_MS 15000 + +#define AUTO_RES_ERR_POLL_TIME_NS (20 * NSEC_PER_MSEC) +#define HAPTICS_BACK_EMF_DELAY_US 20000 + +#define HAP_BRAKE_PAT_LEN 4 +#define HAP_WAVE_SAMP_LEN 8 +#define NUM_WF_SET 4 +#define HAP_WAVE_SAMP_SET_LEN (HAP_WAVE_SAMP_LEN * NUM_WF_SET) +#define HAP_RATE_CFG_STEP_US 5 + +#define SC_MAX_COUNT 5 +#define SC_COUNT_RST_DELAY_US 1000000 + +enum hap_play_control { + HAP_STOP, + HAP_PAUSE, + HAP_PLAY, +}; + +/** + * struct spmi_haptics - struct for spmi haptics data. + * + * @dev: Our device parent. + * @regmap: Register map for the hardware block. + * @haptics_input_dev: The input device used to receive events. + * @work: Work struct to play effects. + * @base: Base address of the regmap. + * @active: Atomic value used to track if haptics are currently playing. + * @play_irq: Fired to load the next wave pattern. + * @sc_irq: Short circuit irq. + * @last_sc_time: Time since the short circuit IRQ last fired. + * @sc_count: Number of times the short circuit IRQ has fired in this interval. + * @actuator_type: The type of actuator in use. + * @wave_shape: The shape of the waves to use (sine or square). + * @play_mode: The play mode to use (direct, buffer, pwm, audio). + * @magnitude: The strength we should be playing at. + * @vmax: Max voltage to use when playing. + * @current_limit: The current limit for this hardware (400mA or 800mA). + * @play_wave_rate: The wave rate to use for this hardware. + * @wave_samp: The array of wave samples to write for buffer mode. + * @brake_pat: The pattern to apply when braking. + * @play_lock: Lock to be held when updating the hardware state. + */ +struct spmi_haptics { + struct device *dev; + struct regmap *regmap; + struct input_dev *haptics_input_dev; + struct work_struct work; + u32 base; + + atomic_t active; + + int play_irq; + int sc_irq; + ktime_t last_sc_time; + u8 sc_count; + + u8 actuator_type; + u8 wave_shape; + u8 play_mode; + int magnitude; + u32 vmax; + u32 current_limit; + u32 play_wave_rate; + + u32 wave_samp[HAP_WAVE_SAMP_SET_LEN]; + u8 brake_pat[HAP_BRAKE_PAT_LEN]; + + struct mutex play_lock; +}; + +static inline bool is_secure_addr(u16 addr) +{ + return (addr & 0xFF) > 0xD0; +} + +static int spmi_haptics_read(struct spmi_haptics *haptics, + u16 addr, u8 *val, int len) +{ + int ret; + + ret = regmap_bulk_read(haptics->regmap, addr, val, len); + if (ret < 0) + dev_err(haptics->dev, "Error reading address: 0x%x, ret %d\n", addr, ret); + + return ret; +} + +static int spmi_haptics_write(struct spmi_haptics *haptics, + u16 addr, u8 *val, int len) +{ + int ret, i; + + if (is_secure_addr(addr)) { + for (i = 0; i < len; i++) { + dev_dbg(haptics->dev, "%s: unlocking for addr: 0x%x, val: 0x%x", __func__, + addr, val[i]); + ret = regmap_write(haptics->regmap, + haptics->base + HAP_SEC_ACCESS_REG, HAP_SEC_ACCESS_UNLOCK); + if (ret < 0) { + dev_err(haptics->dev, "Error writing unlock code, ret %d\n", + ret); + return ret; + } + + ret = regmap_write(haptics->regmap, addr + i, val[i]); + if (ret < 0) { + dev_err(haptics->dev, "Error writing address 0x%x, ret %d\n", + addr + i, ret); + return ret; + } + } + } else { + if (len > 1) + ret = regmap_bulk_write(haptics->regmap, addr, val, len); + else + ret = regmap_write(haptics->regmap, addr, *val); + } + + if (ret < 0) + dev_err(haptics->dev, "%s: Error writing address: 0x%x, ret %d\n", + __func__, addr, ret); + + return ret; +} + +static int spmi_haptics_write_masked(struct spmi_haptics *haptics, + u16 addr, u8 mask, u8 val) +{ + int ret; + + if (is_secure_addr(addr)) { + ret = regmap_write(haptics->regmap, + haptics->base + HAP_SEC_ACCESS_REG, HAP_SEC_ACCESS_UNLOCK); + if (ret < 0) { + dev_err(haptics->dev, "Error writing unlock code - ret %d\n", ret); + return ret; + } + } + + ret = regmap_update_bits(haptics->regmap, addr, mask, val); + if (ret < 0) + dev_err(haptics->dev, "Error writing address: 0x%x - ret %d\n", addr, ret); + + return ret; +} + +static bool is_haptics_idle(struct spmi_haptics *haptics) +{ + int ret; + u8 val; + + if (haptics->play_mode == HAP_PLAY_DIRECT || + haptics->play_mode == HAP_PLAY_PWM) + return true; + + ret = spmi_haptics_read(haptics, haptics->base + HAP_STATUS_1_REG, &val, 1); + if (ret < 0 || (val & HAP_BUSY_BIT)) + return false; + + return true; +} + +static int spmi_haptics_module_enable(struct spmi_haptics *haptics, bool enable) +{ + u8 val; + + dev_dbg(haptics->dev, "Setting module enable: %d", enable); + + val = enable ? HAP_EN_BIT : 0; + return spmi_haptics_write(haptics, haptics->base + HAP_EN_CTL_REG, &val, 1); +} + +static int spmi_haptics_write_vmax(struct spmi_haptics *haptics) +{ + u8 val = 0; + u32 vmax_mv = haptics->vmax; + + vmax_mv = clamp_t(u32, vmax_mv, HAP_VMAX_MIN_MV, HAP_VMAX_MAX_MV); + + dev_dbg(haptics->dev, "Setting vmax to: %d", vmax_mv); + + val = DIV_ROUND_CLOSEST(vmax_mv, HAP_VMAX_MIN_MV); + val = FIELD_PREP(HAP_VMAX_MASK, val); + + // TODO: pm660 can enable overdrive here + + return spmi_haptics_write_masked(haptics, haptics->base + HAP_VMAX_CFG_REG, + HAP_VMAX_MASK | HAP_WF_OVD_BIT, val); +} + +static int spmi_haptics_write_current_limit(struct spmi_haptics *haptics) +{ + haptics->current_limit = clamp_t(u32, haptics->current_limit, + HAP_ILIM_400_MA, HAP_ILIM_800_MA); + + dev_dbg(haptics->dev, "Setting current_limit to: 0x%x", haptics->current_limit); + + return spmi_haptics_write_masked(haptics, haptics->base + HAP_ILIM_CFG_REG, + HAP_ILIM_SEL_MASK, haptics->current_limit); +} + +static int spmi_haptics_write_play_mode(struct spmi_haptics *haptics) +{ + u8 val = 0; + + if (!is_haptics_idle(haptics)) + return -EBUSY; + + dev_dbg(haptics->dev, "Setting play_mode to: 0x%x", haptics->play_mode); + + val = FIELD_PREP(HAP_WF_SOURCE_MASK, haptics->play_mode); + return spmi_haptics_write_masked(haptics, haptics->base + HAP_SEL_REG, + HAP_WF_SOURCE_MASK, val); + +} + +static int spmi_haptics_write_play_rate(struct spmi_haptics *haptics, u16 play_rate) +{ + u8 val[2]; + + dev_dbg(haptics->dev, "Setting play_rate to: %d", play_rate); + + val[0] = FIELD_PREP(HAP_RATE_CFG1_MASK, play_rate); + val[1] = FIELD_PREP(HAP_RATE_CFG2_MASK, play_rate >> HAP_RATE_CFG2_SHIFT); + return spmi_haptics_write(haptics, haptics->base + HAP_RATE_CFG1_REG, val, 2); +} + +/* + * spmi_haptics_set_auto_res() - Auto resonance + * allows the haptics to automatically adjust the + * speed of the oscillation in order to maintain + * the resonant frequency. + */ +static int spmi_haptics_set_auto_res(struct spmi_haptics *haptics, bool enable) +{ + u8 val; + + // LRAs are the only type to support auto res + if (haptics->actuator_type != HAP_TYPE_LRA) + return 0; + + val = enable ? AUTO_RES_EN_BIT : 0; + + return spmi_haptics_write_masked(haptics, haptics->base + HAP_TEST2_REG, + AUTO_RES_EN_BIT, val); +} + +static int spmi_haptics_write_brake(struct spmi_haptics *haptics) +{ + int ret, i; + u8 val; + + dev_dbg(haptics->dev, "Configuring brake pattern"); + + ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_EN_CTL2_REG, + BRAKE_EN_BIT, 1); + if (ret < 0) + return ret; + + for (i = HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { + u8 p = haptics->brake_pat[i] & HAP_BRAKE_PAT_MASK; + + val |= p << (i * 2); + } + + return spmi_haptics_write(haptics, haptics->base + HAP_BRAKE_REG, &val, 1); +} + +static int spmi_haptics_write_buffer_config(struct spmi_haptics *haptics) +{ + u8 buf[HAP_WAVE_SAMP_LEN]; + int i; + + dev_dbg(haptics->dev, "Writing buffer config"); + + for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) + buf[i] = haptics->wave_samp[i]; + + return spmi_haptics_write(haptics, haptics->base + HAP_WF_S1_REG, buf, + HAP_WAVE_SAMP_LEN); +} + +static int spmi_haptics_write_wave_repeat(struct spmi_haptics *haptics) +{ + u8 val, mask; + + /* The number of times to repeat each wave */ + mask = WF_REPEAT_MASK | WF_S_REPEAT_MASK; + val = FIELD_PREP(WF_REPEAT_MASK, 0) | + FIELD_PREP(WF_S_REPEAT_MASK, 0); + + return spmi_haptics_write_masked(haptics, haptics->base + HAP_WF_REPEAT_REG, + mask, val); +} + +static int spmi_haptics_write_play_control(struct spmi_haptics *haptics, + enum hap_play_control ctrl) +{ + u8 val; + + switch (ctrl) { + case HAP_STOP: + val = 0; + break; + case HAP_PAUSE: + val = HAP_PAUSE_BIT; + break; + case HAP_PLAY: + val = HAP_PLAY_BIT; + break; + default: + return 0; + } + + dev_dbg(haptics->dev, "haptics play ctrl: %d\n", ctrl); + return spmi_haptics_write(haptics, haptics->base + HAP_PLAY_REG, &val, 1); +} + +/* + * This IRQ is fired to tell us to load the next wave sample set. + * As we only currently support a single sample set, it's unused. + */ +static irqreturn_t spmi_haptics_play_irq_handler(int irq, void *data) +{ + struct spmi_haptics *haptics = data; + + dev_dbg(haptics->dev, "play_irq triggered"); + + return IRQ_HANDLED; +} + +/** + * spmi_haptics_sc_irq_handler() - short circuit irq handler + * Fires every ~50ms whilst the haptics are active. + * If the SC_FLAG_BIT is set then that means there isn't a short circuit + * and we just need to clear the IRQ to indicate that the device should + * keep vibrating. + * + * Otherwise, it means a short circuit situation has occurred. + * + * @irq: irq number + * @data: haptics data + * Returns: IRQ_HANDLED + */ +static irqreturn_t spmi_haptics_sc_irq_handler(int irq, void *data) +{ + struct spmi_haptics *haptics = data; + int ret; + u8 val; + s64 sc_delta_time_us; + ktime_t temp; + + ret = spmi_haptics_read(haptics, haptics->base + HAP_STATUS_1_REG, &val, 1); + if (ret < 0) + return IRQ_HANDLED; + + if (!(val & SC_FLAG_BIT)) { + haptics->sc_count = 0; + return IRQ_HANDLED; + } + + temp = ktime_get(); + sc_delta_time_us = ktime_us_delta(temp, haptics->last_sc_time); + haptics->last_sc_time = temp; + + if (sc_delta_time_us > SC_COUNT_RST_DELAY_US) + haptics->sc_count = 0; + else + haptics->sc_count++; + + // Clear the interrupt flag + val = SC_CLR_BIT; + ret = spmi_haptics_write(haptics, haptics->base + HAP_SC_CLR_REG, &val, 1); + if (ret < 0) + return IRQ_HANDLED; + + if (haptics->sc_count > SC_MAX_COUNT) { + dev_err(haptics->dev, "Short circuit persists, disabling haptics\n"); + ret = spmi_haptics_module_enable(haptics, false); + if (ret < 0) + dev_err(haptics->dev, "Error disabling module, rc=%d\n", ret); + } + + return IRQ_HANDLED; +} + + +/** + * spmi_haptics_init() - Initialise haptics hardware for use + * @haptics: haptics device + * Returns: 0 on success, < 0 on error + */ +static int spmi_haptics_init(struct spmi_haptics *haptics) +{ + int ret; + u8 val, mask; + u16 play_rate; + + ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_CFG1_REG, + HAP_ACT_TYPE_MASK, haptics->actuator_type); + if (ret < 0) + return ret; + + /* + * Configure auto resonance + * see spmi_haptics_lra_auto_res_config downstream + * This is greatly simplified. + */ + val = FIELD_PREP(LRA_RES_CAL_MASK, ilog2(32 / HAP_RES_CAL_PERIOD_MIN)) | + FIELD_PREP(LRA_AUTO_RES_MODE_MASK, HAP_AUTO_RES_ZXD_EOP) | + FIELD_PREP(LRA_HIGH_Z_MASK, 1); + + mask = LRA_AUTO_RES_MODE_MASK | LRA_HIGH_Z_MASK | LRA_RES_CAL_MASK; + + ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_LRA_AUTO_RES_REG, + mask, val); + + /* Configure the PLAY MODE register */ + ret = spmi_haptics_write_play_mode(haptics); + if (ret < 0) + return ret; + + ret = spmi_haptics_write_vmax(haptics); + if (ret < 0) + return ret; + + /* Configure the ILIM register */ + ret = spmi_haptics_write_current_limit(haptics); + if (ret < 0) + return ret; + + // Configure the debounce for short-circuit detection. + ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_SC_DEB_REG, + HAP_SC_DEB_MASK, HAP_SC_DEB_CYCLES_MAX); + if (ret < 0) + return ret; + + // write the wave shape + ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_CFG2_REG, + HAP_LRA_RES_TYPE_MASK, haptics->wave_shape); + if (ret < 0) + return ret; + + play_rate = haptics->play_wave_rate / HAP_RATE_CFG_STEP_US; + + /* + * Configure RATE_CFG1 and RATE_CFG2 registers. + * Note: For ERM these registers act as play rate and + * for LRA these represent resonance period + */ + ret = spmi_haptics_write_play_rate(haptics, play_rate); + if (ret < 0) + return ret; + + ret = spmi_haptics_write_brake(haptics); + if (ret < 0) + return ret; + + if (haptics->play_mode == HAP_PLAY_BUFFER) { + ret = spmi_haptics_write_wave_repeat(haptics); + if (ret < 0) + return ret; + + ret = spmi_haptics_write_buffer_config(haptics); + if (ret < 0) + return ret; + } + + dev_dbg(haptics->dev, "%s: Requesting play IRQ, irq: %d", __func__, + haptics->play_irq); + ret = devm_request_threaded_irq(haptics->dev, haptics->play_irq, + NULL, spmi_haptics_play_irq_handler, IRQF_ONESHOT, + "haptics_play_irq", haptics); + + if (ret < 0) { + dev_err(haptics->dev, "Unable to request play IRQ ret=%d\n", ret); + return ret; + } + + /* use play_irq only for buffer mode */ + if (haptics->play_mode != HAP_PLAY_BUFFER) + disable_irq(haptics->play_irq); + + dev_dbg(haptics->dev, "%s: Requesting play IRQ, irq: %d", __func__, + haptics->play_irq); + ret = devm_request_threaded_irq(haptics->dev, haptics->sc_irq, + NULL, spmi_haptics_sc_irq_handler, IRQF_ONESHOT, + "haptics_sc_irq", haptics); + + if (ret < 0) { + dev_err(haptics->dev, "Unable to request sc IRQ ret=%d\n", ret); + return ret; + } + + return 0; +} + +/** + * spmi_haptics_enable - handler to start/stop vibration + * @haptics: pointer to haptics struct + * Returns: 0 on success, < 0 on failure + */ +static int spmi_haptics_enable(struct spmi_haptics *haptics) +{ + int ret; + + mutex_lock(&haptics->play_lock); + if (haptics->sc_count > SC_MAX_COUNT) { + dev_err(haptics->dev, "Can't play while in short circuit"); + ret = -1; + goto out; + } + ret = spmi_haptics_set_auto_res(haptics, false); + if (ret < 0) { + dev_err(haptics->dev, "Error disabling auto_res, ret=%d\n", ret); + goto out; + } + + ret = spmi_haptics_module_enable(haptics, true); + if (ret < 0) { + dev_err(haptics->dev, "Error enabling module, ret=%d\n", ret); + goto out; + } + + ret = spmi_haptics_write_play_control(haptics, HAP_PLAY); + if (ret < 0) { + dev_err(haptics->dev, "Error enabling play, ret=%d\n", ret); + goto out; + } + + ret = spmi_haptics_set_auto_res(haptics, true); + if (ret < 0) { + dev_err(haptics->dev, "Error enabling auto_res, ret=%d\n", ret); + goto out; + } + +out: + mutex_unlock(&haptics->play_lock); + return ret; +} + +/** + * spmi_haptics_enable - handler to start/stop vibration + * @haptics: pointer to haptics struct + * Returns: 0 on success, < 0 on failure + */ +static int spmi_haptics_disable(struct spmi_haptics *haptics) +{ + int ret; + + mutex_lock(&haptics->play_lock); + + ret = spmi_haptics_write_play_control(haptics, HAP_STOP); + if (ret < 0) { + dev_err(haptics->dev, "Error disabling play, ret=%d\n", ret); + goto out; + } + + ret = spmi_haptics_module_enable(haptics, false); + if (ret < 0) { + dev_err(haptics->dev, "Error disabling module, ret=%d\n", ret); + goto out; + } + +out: + mutex_unlock(&haptics->play_lock); + return ret; +} + +/* + * Threaded function to update the haptics state. + */ +static void spmi_haptics_work(struct work_struct *work) +{ + struct spmi_haptics *haptics = container_of(work, struct spmi_haptics, work); + + int ret; + bool enable; + + enable = atomic_read(&haptics->active); + dev_dbg(haptics->dev, "%s: state: %d\n", __func__, enable); + + if (enable) + ret = spmi_haptics_enable(haptics); + else + ret = spmi_haptics_disable(haptics); + if (ret < 0) + dev_err(haptics->dev, "Error setting haptics, ret=%d", ret); +} + +/** + * spmi_haptics_close - callback for input device close + * @dev: input device pointer + * + * Turns off the vibrator. + */ +static void spmi_haptics_close(struct input_dev *dev) +{ + struct spmi_haptics *haptics = input_get_drvdata(dev); + + cancel_work_sync(&haptics->work); + if (atomic_read(&haptics->active)) { + atomic_set(&haptics->active, 0); + schedule_work(&haptics->work); + } +} + +/** + * spmi_haptics_play_effect - play haptics effects + * @dev: input device pointer + * @data: data of effect + * @effect: effect to play + */ +static int spmi_haptics_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct spmi_haptics *haptics = input_get_drvdata(dev); + + dev_dbg(haptics->dev, "%s: Rumbling with strong: %d and weak: %d", __func__, + effect->u.rumble.strong_magnitude, effect->u.rumble.weak_magnitude); + + haptics->magnitude = effect->u.rumble.strong_magnitude >> 8; + if (!haptics->magnitude) + haptics->magnitude = effect->u.rumble.weak_magnitude >> 10; + + if (!haptics->magnitude) { + atomic_set(&haptics->active, 0); + goto end; + } + + atomic_set(&haptics->active, 1); + + haptics->vmax = ((HAP_VMAX_MAX_MV - HAP_VMAX_MIN_MV) * haptics->magnitude) / 100 + + HAP_VMAX_MIN_MV; + + dev_dbg(haptics->dev, "%s: magnitude: %d, vmax: %d", __func__, + haptics->magnitude, haptics->vmax); + + spmi_haptics_write_vmax(haptics); + +end: + schedule_work(&haptics->work); + + return 0; +} + +static int spmi_haptics_probe(struct platform_device *pdev) +{ + struct spmi_haptics *haptics; + struct device_node *node; + struct input_dev *input_dev; + int ret; + u32 val; + int i; + + haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!haptics->regmap) + return -ENODEV; + + node = pdev->dev.of_node; + + haptics->dev = &pdev->dev; + + ret = of_property_read_u32(node, "reg", &haptics->base); + if (ret < 0) { + dev_err(haptics->dev, "Couldn't find reg in node = %s ret = %d\n", + node->full_name, ret); + return ret; + } + + haptics->play_irq = platform_get_irq_byname(pdev, "play"); + if (haptics->play_irq < 0) { + dev_err(&pdev->dev, "Unable to get play irq\n"); + ret = haptics->play_irq; + goto register_fail; + } + + haptics->sc_irq = platform_get_irq_byname(pdev, "short"); + if (haptics->sc_irq < 0) { + dev_err(&pdev->dev, "Unable to get sc irq\n"); + ret = haptics->sc_irq; + goto register_fail; + } + + // We only support LRAs for now + haptics->actuator_type = HAP_TYPE_LRA; + ret = of_property_read_u32(node, "qcom,actuator-type", &val); + if (!ret) { + if (val != HAP_TYPE_LRA) { + dev_err(&pdev->dev, "qcom,actuator-type (%d) isn't supported\n", val); + ret = -EINVAL; + goto register_fail; + } + haptics->actuator_type = val; + } + + // Only buffer mode is currently supported + haptics->play_mode = HAP_PLAY_BUFFER; + ret = of_property_read_u32(node, "qcom,play-mode", &val); + if (!ret) { + if (val != HAP_PLAY_BUFFER) { + dev_err(&pdev->dev, "qcom,play-mode (%d) isn't supported\n", val); + ret = -EINVAL; + goto register_fail; + } + haptics->play_mode = val; + } + + ret = of_property_read_u32(node, "qcom,wave-play-rate-us", &val); + if (!ret) { + haptics->play_wave_rate = val; + } else if (ret != -EINVAL) { + dev_err(haptics->dev, "Unable to read play rate ret=%d\n", ret); + goto register_fail; + } + + haptics->play_wave_rate = + clamp_t(u32, haptics->play_wave_rate, + HAP_WAVE_PLAY_RATE_MIN_US, HAP_WAVE_PLAY_RATE_MAX_US); + + haptics->wave_shape = HAP_WAVE_SINE; + ret = of_property_read_u32(node, "qcom,wave-shape", &val); + if (!ret) { + if (val != HAP_WAVE_SINE && val != HAP_WAVE_SQUARE) { + dev_err(&pdev->dev, "qcom,wave-shape is invalid: %d\n", val); + ret = -EINVAL; + goto register_fail; + } + haptics->wave_shape = val; + } + + haptics->brake_pat[0] = 0x3; + haptics->brake_pat[1] = 0x3; + haptics->brake_pat[2] = 0x2; + haptics->brake_pat[3] = 0x1; + + ret = of_property_read_u8_array(node, "qcom,brake-pattern", haptics->brake_pat, 4); + if (ret < 0 && ret != -EINVAL) { + dev_err(&pdev->dev, "qcom,brake-pattern is invalid, ret = %d\n", ret); + goto register_fail; + } + + haptics->current_limit = HAP_ILIM_400_MA; + + for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) + haptics->wave_samp[i] = HAP_WF_SAMP_MAX; + + ret = spmi_haptics_init(haptics); + if (ret < 0) { + dev_err(&pdev->dev, "Error initialising haptics, ret=%d\n", + ret); + goto register_fail; + } + + platform_set_drvdata(pdev, haptics); + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + INIT_WORK(&haptics->work, spmi_haptics_work); + haptics->haptics_input_dev = input_dev; + + input_dev->name = "spmi_haptics"; + input_dev->id.version = 1; + input_dev->close = spmi_haptics_close; + input_set_drvdata(input_dev, haptics); + // Figure out how to make this FF_PERIODIC + input_set_capability(haptics->haptics_input_dev, EV_FF, FF_RUMBLE); + + ret = input_ff_create_memless(input_dev, NULL, + spmi_haptics_play_effect); + if (ret) { + dev_err(&pdev->dev, + "couldn't register vibrator as FF device\n"); + goto register_fail; + } + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&pdev->dev, "couldn't register input device\n"); + goto register_fail; + } + + return 0; + +register_fail: + cancel_work_sync(&haptics->work); + mutex_destroy(&haptics->play_lock); + + return ret; +} + +static int __maybe_unused spmi_haptics_suspend(struct device *dev) +{ + struct spmi_haptics *haptics = dev_get_drvdata(dev); + + cancel_work_sync(&haptics->work); + spmi_haptics_disable(haptics); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(spmi_haptics_pm_ops, spmi_haptics_suspend, NULL); + +static void spmi_haptics_remove(struct platform_device *pdev) +{ + struct spmi_haptics *haptics = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&haptics->work); + mutex_destroy(&haptics->play_lock); + input_unregister_device(haptics->haptics_input_dev); +} + +static void spmi_haptics_shutdown(struct platform_device *pdev) +{ + struct spmi_haptics *haptics = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&haptics->work); + + spmi_haptics_disable(haptics); +} + +static const struct of_device_id spmi_haptics_match_table[] = { + { .compatible = "qcom,spmi-haptics" }, + { } +}; +MODULE_DEVICE_TABLE(of, spmi_haptics_match_table); + +static struct platform_driver spmi_haptics_driver = { + .probe = spmi_haptics_probe, + .remove = spmi_haptics_remove, + .shutdown = spmi_haptics_shutdown, + .driver = { + .name = "spmi-haptics", + .pm = &spmi_haptics_pm_ops, + .of_match_table = spmi_haptics_match_table, + }, +}; +module_platform_driver(spmi_haptics_driver); + +MODULE_DESCRIPTION("spmi haptics driver using ff-memless framework"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Caleb Connolly "); From c1e7a4afc55863abed9b08c3ee220bfcdffa3c46 Mon Sep 17 00:00:00 2001 From: M0Rf30 Date: Sun, 11 Feb 2024 03:21:28 +0100 Subject: [PATCH 19/65] arm64: dts: qcom: pm660: add spmi-haptics node Signed-off-by: Gianluca Boiano --- arch/arm64/boot/dts/qcom/pm660.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi index 156b2ddff0dcb5..718e086c78238f 100644 --- a/arch/arm64/boot/dts/qcom/pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -222,6 +223,23 @@ #address-cells = <1>; #size-cells = <0>; + pm660_haptics: haptics@c000 { + compatible = "qcom,pmi8998-haptics", "qcom,spmi-haptics"; + reg = <0xc000>; + + interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "short", "play"; + + qcom,actuator-type = ; + qcom,brake-pattern = <0x3 0x3 0x0 0x0>; + qcom,play-mode = ; + qcom,wave-play-rate-us = <6667>; + qcom,wave-shape = ; + + status = "disabled"; + }; + pm660_spmi_regulators: regulators { compatible = "qcom,pm660-regulators"; }; From ef3036bd70dfa7876188a4a4f6c2cd4b1ea08073 Mon Sep 17 00:00:00 2001 From: iAboothahir Date: Sat, 8 Oct 2022 16:43:42 +0530 Subject: [PATCH 20/65] arm64: dts: qcom: pm660: Add and fuel gauge PM660 has a fuel guage gen 3, which is compatible with the one used in MSM8998. Signed-off-by: Aboothahir U --- arch/arm64/boot/dts/qcom/pm660.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi index 718e086c78238f..8af539962ca89b 100644 --- a/arch/arm64/boot/dts/qcom/pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -198,6 +198,16 @@ }; }; + pm660_fg: fuel-gauge@4000 { + compatible = "qcom,pmi8998-fg"; + reg = <0x4000 0x1000>; + + interrupts = <0x0 0x40 0x3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "soc-delta"; + + status = "disabled"; + }; + pm660_rradc: adc@4500 { compatible = "qcom,pm660-rradc"; reg = <0x4500>; From 53196ed259a15ab031fa731a2d086d8c24e34502 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 18 Oct 2020 16:10:41 +0200 Subject: [PATCH 21/65] gpu go 700mhz Signed-off-by: Marijn Suijten Signed-off-by: Aboothahir U --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 97b2331a5ef96b..393db01112a4ab 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -1117,6 +1117,20 @@ gpu_sdm630_opp_table: opp-table { compatible = "operating-points-v2"; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-level = ; + opp-peak-kBps = <5184000>; + opp-supported-hw = <0xFF>; + }; + + /* + * 775MHz is only available on default speed bin + * or 0xA2 (speed bin 1). Though it cannot be used + * for now due to interconnect framework not supporting + * multiple frequencies at the same opp-level + opp-775000000 { opp-hz = /bits/ 64 <775000000>; opp-level = ; @@ -1159,6 +1173,7 @@ opp-peak-kBps = <1200000>; opp-supported-hw = <0xff>; }; + */ }; }; From fa462547ffd5a4cc8ab01719bc533751fd3347f2 Mon Sep 17 00:00:00 2001 From: Aboothahir U Date: Thu, 29 Aug 2024 15:23:43 +0300 Subject: [PATCH 22/65] drm/msm: add missing A508/512 MODULE_FIRMWARE declarations Adreno 508/509/512 MODULE_FIRMWARE was missing in a5xx_catalog. Signed-off-by: Aboothahir U --- drivers/gpu/drm/msm/adreno/a5xx_catalog.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c index 633f3153916277..c54a6cc83169d0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c @@ -151,6 +151,14 @@ static const struct adreno_info a5xx_gpus[] = { }; DECLARE_ADRENO_GPULIST(a5xx); +MODULE_FIRMWARE("qcom/a508_zap.mdt"); +MODULE_FIRMWARE("qcom/a508_zap.b00"); +MODULE_FIRMWARE("qcom/a508_zap.b01"); +MODULE_FIRMWARE("qcom/a508_zap.b02"); +MODULE_FIRMWARE("qcom/a512_zap.mdt"); +MODULE_FIRMWARE("qcom/a512_zap.b00"); +MODULE_FIRMWARE("qcom/a512_zap.b01"); +MODULE_FIRMWARE("qcom/a512_zap.b02"); MODULE_FIRMWARE("qcom/a530_pm4.fw"); MODULE_FIRMWARE("qcom/a530_pfp.fw"); MODULE_FIRMWARE("qcom/a530v3_gpmu.fw2"); From 6ed304ab920c44650504f97f045e6941e41f8fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Mon, 25 Mar 2024 17:43:38 +0100 Subject: [PATCH 23/65] arm64: dts: qcom: sdm660/sdm630: add zap-shader node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add zap-shader node for adreno_gpu to be able to load zap shader firmware, which is required for working GPU. According to drivers/gpu/drm/msm/adreno/adreno_device.c, Adreno 508 (found in SDM630) uses it's own a508_zap, Adreno 509 (found in SDM636) uses same a512_zap as Adreno 512. Signed-off-by: Barnabás Czémán --- arch/arm64/boot/dts/qcom/sdm630.dtsi | 5 +++++ arch/arm64/boot/dts/qcom/sdm660.dtsi | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 393db01112a4ab..823c79deb5fd60 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -1175,6 +1175,11 @@ }; */ }; + + zap-shader { + memory-region = <&zap_shader_region>; + firmware-name = "a508_zap.mbn"; + }; }; kgsl_smmu: iommu@5040000 { diff --git a/arch/arm64/boot/dts/qcom/sdm660.dtsi b/arch/arm64/boot/dts/qcom/sdm660.dtsi index f89b27c99f40cf..befa4fd665986e 100644 --- a/arch/arm64/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660.dtsi @@ -83,6 +83,10 @@ opp-supported-hw = <0xff>; }; }; + + zap-shader { + firmware-name = "a512_zap.mbn"; + }; }; &CPU0 { From 446f0237666350320f8d0cc6c454e69508342a38 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Wed, 6 Dec 2023 13:51:34 +0300 Subject: [PATCH 24/65] iommu/arm-smmu-qcom: Add SDM630/660 mdp5 compatibles for identity Add SDM630/660's MDP5 compatibles to switch the default iommu domain type to IDENTITY, as similarly required by SDM845 and others. Signed-off-by: Alexey Minnekhanov --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 09373ab919a9d9..bd66ce157babe6 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -258,6 +258,8 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc7280-mss-pil" }, { .compatible = "qcom,sc8180x-mdss" }, { .compatible = "qcom,sc8280xp-mdss" }, + { .compatible = "qcom,sdm630-mdp5" }, + { .compatible = "qcom,sdm660-mdp5" }, { .compatible = "qcom,sdm660-mss-pil" }, { .compatible = "qcom,sdm670-mdss" }, { .compatible = "qcom,sdm845-mdss" }, From 65e4d0a3086879086420e43447848e6596a26c99 Mon Sep 17 00:00:00 2001 From: Aboothahir U Date: Mon, 9 Sep 2024 22:03:22 +0530 Subject: [PATCH 25/65] drm/panel: Add panel driver for asus-x00td nt36672-txd Signed-off-by: Aboothahir U --- drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-novatek-nt36672-txd.c | 451 ++++++++++++++++++ 3 files changed, 461 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36672-txd.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 9f49b0189d3b83..4e352c60b3e812 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -488,6 +488,15 @@ config DRM_PANEL_NOVATEK_NT36672E LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit RGB per pixel. +config DRM_PANEL_NOVATEK_NT36672_TXD + tristate "Novatek NT36672 TXD panel for asus-x00td" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for nt36672_txd + video mode panel used in Asus Zenfone Max Pro M1 phone (codename x00td) + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 5581387707c62f..bbb8e4b85ce4d9 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672_TXD) += panel-novatek-nt36672-txd.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672-txd.c b/drivers/gpu/drm/panel/panel-novatek-nt36672-txd.c new file mode 100644 index 00000000000000..d01386e0588cad --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672-txd.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2024 FIXME +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct nt36672_txd { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data supplies[3]; + struct gpio_desc *reset_gpio; +}; + +static inline struct nt36672_txd *to_nt36672_txd(struct drm_panel *panel) +{ + return container_of(panel, struct nt36672_txd, panel); +} + +static void nt36672_txd_reset(struct nt36672_txd *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); +} + +static int nt36672_txd_on(struct nt36672_txd *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0x9e); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x94); + mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x35); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x66); + mipi_dsi_dcs_write_seq(dsi, 0x69, 0x99); + mipi_dsi_dcs_write_seq(dsi, 0x95, 0xf5); + mipi_dsi_dcs_write_seq(dsi, 0x96, 0xf5); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x23); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x6c); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0xe6); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x01, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x02, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x03, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x04, 0x0b); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0xa9); + mipi_dsi_dcs_write_seq(dsi, 0x07, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x08, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x09, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x0b, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0x10, 0x15); + mipi_dsi_dcs_write_seq(dsi, 0x11, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x13, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x14, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x15, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0x0b); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x18, 0xa9); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x05); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x03); + mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x0f); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x20, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x17); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x15); + mipi_dsi_dcs_write_seq(dsi, 0x23, 0x13); + mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x30, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x31, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0x32, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x33, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x34, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x35, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x37, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x38, 0x72); + mipi_dsi_dcs_write_seq(dsi, 0x39, 0x72); + mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0x3f, 0x72); + mipi_dsi_dcs_write_seq(dsi, 0x60, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0x61, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x68, 0x83); + mipi_dsi_dcs_write_seq(dsi, 0x78, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x79, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x7a, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0x7b, 0x9c); + mipi_dsi_dcs_write_seq(dsi, 0x7d, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x80, 0x45); + mipi_dsi_dcs_write_seq(dsi, 0x81, 0x06); + mipi_dsi_dcs_write_seq(dsi, 0x8e, 0xf0); + mipi_dsi_dcs_write_seq(dsi, 0x90, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x92, 0x76); + mipi_dsi_dcs_write_seq(dsi, 0x93, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x94, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x99, 0x33); + mipi_dsi_dcs_write_seq(dsi, 0x9b, 0xff); + mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xdc, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x75); + mipi_dsi_dcs_write_seq(dsi, 0xe9, 0x08); + mipi_dsi_dcs_write_seq(dsi, 0xed, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb1, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xb2, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xb3, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xb4, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb5, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xb6, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xb7, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xb8, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb9, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xba, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xbb, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x21); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb0, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb1, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xb2, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xb3, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xb4, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb5, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xb6, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xb7, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xb8, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x37, 0x00, 0x54, + 0x00, 0x6d, 0x00, 0x84, 0x00, 0x98, 0x00, 0xac); + mipi_dsi_dcs_write_seq(dsi, 0xb9, + 0x00, 0xbd, 0x00, 0xf9, 0x01, 0x25, 0x01, 0x6b, + 0x01, 0x9c, 0x01, 0xec, 0x02, 0x22, 0x02, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xba, + 0x02, 0x5e, 0x02, 0x9e, 0x02, 0xc9, 0x02, 0xfd, + 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5a, 0x03, 0x68); + mipi_dsi_dcs_write_seq(dsi, 0xbb, + 0x03, 0x78, 0x03, 0x8b, 0x03, 0xa1, 0x03, 0xbd, + 0x03, 0xd6, 0x03, 0xda); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x05, 0x0c); + mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x81); + mipi_dsi_dcs_write_seq(dsi, 0x0b, 0xd7); + mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0x82); + mipi_dsi_dcs_write_seq(dsi, 0x21, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x22, 0x1c); + mipi_dsi_dcs_write_seq(dsi, 0x24, 0x76); + mipi_dsi_dcs_write_seq(dsi, 0x25, 0x76); + mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x25); + mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x5e, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x22); + mipi_dsi_dcs_write_seq(dsi, 0x65, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x69, 0x60); + mipi_dsi_dcs_write_seq(dsi, 0x6b, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x71, 0x2d); + mipi_dsi_dcs_write_seq(dsi, 0x80, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x04); + mipi_dsi_dcs_write_seq(dsi, 0xd7, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xd8, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xd9, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xda, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xdc, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x06, 0xc8); + mipi_dsi_dcs_write_seq(dsi, 0x12, 0x5a); + mipi_dsi_dcs_write_seq(dsi, 0x19, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x97); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x0a); + mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x1e); + mipi_dsi_dcs_write_seq(dsi, 0x99, 0x20); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x27); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0x13, 0x0e); + mipi_dsi_dcs_write_seq(dsi, 0x16, 0xb0); + mipi_dsi_dcs_write_seq(dsi, 0x17, 0xd0); + mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10); + mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(70); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + usleep_range(10000, 11000); + + return 0; +} + +static int nt36672_txd_off(struct nt36672_txd *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(50); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(120); + + return 0; +} + +static int nt36672_txd_prepare(struct drm_panel *panel) +{ + struct nt36672_txd *ctx = to_nt36672_txd(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + nt36672_txd_reset(ctx); + + ret = nt36672_txd_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int nt36672_txd_unprepare(struct drm_panel *panel) +{ + struct nt36672_txd *ctx = to_nt36672_txd(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = nt36672_txd_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode nt36672_txd_mode = { + .clock = (1080 + 122 + 8 + 76) * (2160 + 20 + 4 + 28) * 60 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 122, + .hsync_end = 1080 + 122 + 8, + .htotal = 1080 + 122 + 8 + 76, + .vdisplay = 2160, + .vsync_start = 2160 + 20, + .vsync_end = 2160 + 20 + 4, + .vtotal = 2160 + 20 + 4 + 28, + .width_mm = 68, + .height_mm = 136, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int nt36672_txd_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &nt36672_txd_mode); +} + +static const struct drm_panel_funcs nt36672_txd_panel_funcs = { + .prepare = nt36672_txd_prepare, + .unprepare = nt36672_txd_unprepare, + .get_modes = nt36672_txd_get_modes, +}; + +static int nt36672_txd_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct nt36672_txd *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->supplies[0].supply = "vddio"; + ctx->supplies[1].supply = "lab"; + ctx->supplies[2].supply = "ibb"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; + + drm_panel_init(&ctx->panel, dev, &nt36672_txd_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void nt36672_txd_remove(struct mipi_dsi_device *dsi) +{ + struct nt36672_txd *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id nt36672_txd_of_match[] = { + { .compatible = "mdss,novatek-nt36672-txd" }, // FIXME + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, nt36672_txd_of_match); + +static struct mipi_dsi_driver nt36672_txd_driver = { + .probe = nt36672_txd_probe, + .remove = nt36672_txd_remove, + .driver = { + .name = "panel-nt36672-txd", + .of_match_table = nt36672_txd_of_match, + }, +}; +module_mipi_dsi_driver(nt36672_txd_driver); + +MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator "); // FIXME +MODULE_DESCRIPTION("DRM driver for nt36672 1080p video mode dsi txd panel"); +MODULE_LICENSE("GPL"); From 2d42e57a7a50691f30c324f963aa641cf15dbe47 Mon Sep 17 00:00:00 2001 From: iAboothahir Date: Sun, 27 Mar 2022 11:46:08 +0530 Subject: [PATCH 26/65] arm64: dts: qcom: Add initial support for asus-x00td Initial support for Asus Zenfone Max Pro M1 (SDM636) * Currently works -Simple-framebuffer -eMMC,SDCard -Power Button -Volume-keys -Wifi(Partial) -Bluetooth -Touchscreen-NT36XXX -Display -GPU(Partial) -USB Signed-off-by: Aboothahir U arm64: dts: qcom: asus-x00td: Add support for battery Enable fuelgauge, charger and round-robin ADC nodes required for fully functional battery support. Describe simple-battery node. Signed-off-by: Aboothahir U --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../arm64/boot/dts/qcom/sdm636-asus-x00td.dts | 693 ++++++++++++++++++ 2 files changed, 694 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm636-asus-x00td.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 0e5c810304fbef..fa1b6252c29972 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -193,6 +193,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-nile-pioneer.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm630-sony-xperia-nile-voyager.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm632-fairphone-fp3.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm632-motorola-ocean.dtb +dtb-$(CONFIG_ARCH_QCOM) += sdm636-asus-x00td.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-sony-xperia-ganges-mermaid.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-lavender.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm670-google-sargo.dtb diff --git a/arch/arm64/boot/dts/qcom/sdm636-asus-x00td.dts b/arch/arm64/boot/dts/qcom/sdm636-asus-x00td.dts new file mode 100644 index 00000000000000..af4dd3f0e0663c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm636-asus-x00td.dts @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Aboothahir U + */ + +/dts-v1/; + +#include "sdm636.dtsi" +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include +#include + +/delete-node/ &qhee_code; +/delete-node/ &smem_region; +/delete-node/ &tz_mem; +/delete-node/ &adsp_region; +/delete-node/ &buffer_mem; +/delete-node/ &zap_shader_region; + +/ { + model = "Asus Zenfone Max Pro M1"; + compatible = "asus,x00td", "qcom,sdm660", "qcom,sdm636"; + chassis-type = "handset"; + + qcom,msm-id = <0x159 0x0>; + qcom,board-id = <0x1000b 0x0>; + qcom,pmic-id = <0x1001b 0x101011a 0x0 0x0 0x1001b 0x201011a 0x0 0x0 0x1001b 0x102001a 0x0 0x0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "framebuffer0"; + + framebuffer0: framebuffer@9d400000 { + compatible = "simple-framebuffer"; + reg = <0x0 0x9d400000 0x0 (1080 * 2160 * 4)>; + status = "okay"; + width = <1080>; + height = <2160>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + + /* In order to allow simpledrm framebuffer to know + * physical dimensions */ + panel = <&fb_panel>; + + fb_panel: fb-panel { + width-mm = <68>; + height-mm = <136>; + }; + }; + }; + + gpio-keys { + status = "okay"; + compatible = "gpio-keys"; + + vol_up { + label = "Volume Up"; + gpios = <&tlmm 44 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + }; + + vol_down { + label = "Volume Down"; + gpios = <&tlmm 43 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + wlan_msa_guard: wlan-msa-guard@85600000 { + reg = <0x0 0x85600000 0x0 0x100000>; + no-map; + }; + + wlan_msa_mem: wlan-msa-mem@85700000 { + reg = <0x0 0x85700000 0x0 0x100000>; + no-map; + }; + + /* removed_regions in downstream / qhee_code */ + removed_region: removed_region@85800000 { + reg = <0x0 0x85800000 0x0 0x600000>; + no-map; + }; + + smem_region: smem_memory@86000000 { + reg = <0x0 0x86000000 0x0 0x200000>; + no-map; + }; + + /* tz_mem */ + tz_mem: tz_memory@86200000 { + reg = <0x0 0x86200000 0x0 0x2D00000>; + /* 0x86200000 + 0x2D00000 = 0x88F00000 */ + no-map; + }; + + /* adsp_fw_region */ + adsp_region: adsp@92a00000 { + reg = <0x0 0x92a00000 0x0 0x1e00000>; + no-map; + }; + + /* cdsp_fw_region */ + buffer_mem: buffer_region@94a00000 { + reg = <0x0 0x94a00000 0x0 0x600000>; + no-map; + }; + + /* cont_splash_region / framebuffer */ + cont_splash: splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x2400000>; + no-map; + }; + + zap_shader_region: gpu@fa800000 { + compatible = "shared-dma-pool"; + reg = <0x0 0xfa800000 0x0 0x2000>; + no-map; + }; + + ramoops@a0000000 { + compatible = "ramoops"; + reg = <0x0 0xa0000000 0x0 0x400000>; + console-size = <0x20000>; + record-size = <0x20000>; + ftrace-size = <0x0>; + pmsg-size = <0x20000>; + }; + }; + + /* + * Until we hook up type-c detection, we + * have to stick with this. But it works. + */ + extcon_usb: extcon-usb { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&tlmm 58 GPIO_ACTIVE_HIGH>; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + regulator-always-on; + regulator-boot-on; + }; + + battery: battery { + compatible = "simple-battery"; + + charge-full-design-microamp-hours = <5000000>; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4350000>; + }; +}; + +&adreno_gpu { + status = "okay"; + + zap-shader { + memory-region = <&zap_shader_region>; + firmware-name = "qcom/a512_zap.mdt"; + }; + // These OPPs are correct, but we are lacking support for the + // GPU regulator. Hence, disable them for now to prevent the + // platform from hanging on high graphics loads + opp-table { + /delete-node/ opp-700000000; + /delete-node/ opp-266000000; + }; +}; + +&adsp_pil { + status = "okay"; + firmware-name = "adsp.mdt"; +}; + +&anoc2_smmu { + status = "okay"; +}; + +&blsp1_uart2 { + status = "okay"; +}; + +&blsp2_uart1 { + status = "okay"; + /* HCI Bluetooth */ + bluetooth { + compatible = "qcom,wcn3990-bt"; + vddxo-supply = <&vreg_l9a_1p8>; + vddrf-supply = <&vreg_l6a_1p3>; + vddch0-supply = <&vreg_l19a_3p3>; + max-speed = <3200000>; + }; +}; + +&blsp_i2c2 { + status = "okay"; +}; + +&blsp_i2c4 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + touchscreen@62 { + compatible = "novatek,nt36525"; + reg = <0x62>; + vdd-supply = <&vreg_l11a_1p8>; + interrupt-parent = <&tlmm>; + interrupts = <67 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&ts_pins_active>; + pinctrl-1 = <&ts_int_sleep &ts_rst_sleep>; + reset-gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <2160>; + }; +}; + +&blsp_i2c6 { + status = "okay"; + + tfa98xx@34 { + compatible = "nxp,tfa98xx"; + reg = <0x34>; + }; +}; + +&blsp_i2c7 { /* for P/L Sensor */ + status = "okay"; +}; + +&gpucc { + status = "okay"; +}; + +&kgsl_smmu { + status = "okay"; +}; + +&lpass_smmu { + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + vdd-supply = <&vreg_l1b_0p925>; + vdda-supply = <&vreg_l1a_1p225>; + + panel: panel@0 { + reg = <0>; + compatible = "mdss,novatek-nt36672-txd"; + + backlight = <&pm660l_wled>; + + reset-gpios = <&tlmm 53 GPIO_ACTIVE_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + data-lanes = <0 1 2 3>; + remote-endpoint = <&panel_in>; +}; + +&mdss_dsi0_phy { + vcca-supply = <&vreg_l1b_0p925>; + status = "okay"; +}; + +&mmcc { + status = "okay"; +}; + +&mmss_smmu { + status = "okay"; +}; + +&pm660_charger { + status = "okay"; + monitored-battery = <&battery>; +}; + +&pm660_fg { + status = "okay"; + monitored-battery = <&battery>; + qcom,battery-capacity-ua = <5000000>; + qcom,min-voltage-uv= <3400000>; + qcom,max-voltage-uv= <4350000>; +}; + +&pm660_haptics { + status = "okay"; +}; + +&pm660_rradc { + status = "okay"; +}; + +&pm660l_wled { + status = "okay"; + default-brightness = <512>; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&qusb2phy0 { + status = "okay"; + + vdd-supply = <&vreg_l1b_0p925>; + vdda-phy-dpdm-supply = <&vreg_l7b_3p125>; +}; + +&remoteproc_mss { + firmware-name = "mba.mbn", "modem.mdt"; + status = "okay"; +}; + +&rpm_requests { + regulators-0 { + compatible = "qcom,rpm-pm660-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3-supply = <&vph_pwr>; + vdd_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l6_l7-supply = <&vreg_s5a_1p35>; + vdd_l2_l3-supply = <&vreg_s2b_1p05>; + vdd_l5-supply = <&vreg_s2b_1p05>; + vdd_l8_l9_l10_l11_l12_l13_l14-supply = <&vreg_s4a_2p04>; + vdd_l15_l16_l17_l18_l19-supply = <&vreg_bob>; + + /* + * S1A (FTAPC0), S2A (FTAPC1), S3A (HFAPC1) are managed + * by the Core Power Reduction hardened (CPRh) and the + * Operating State Manager (OSM) HW automatically. + */ + + vreg_s4a_2p04: s4 { + regulator-min-microvolt = <1805000>; + regulator-max-microvolt = <2040000>; + regulator-enable-ramp-delay = <200>; + regulator-always-on; + }; + + vreg_s5a_1p35: s5 { + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1350000>; + regulator-enable-ramp-delay = <200>; + }; + + vreg_s6a_0p87: s6 { + regulator-min-microvolt = <504000>; + regulator-max-microvolt = <992000>; + regulator-enable-ramp-delay = <150>; + }; + + /* LDOs */ + vreg_l1a_1p225: l1 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1250000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l2a_1p0: l2 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l3a_1p0: l3 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l5a_0p848: l5 { + regulator-min-microvolt = <525000>; + regulator-max-microvolt = <950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l6a_1p3: l6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1370000>; + regulator-allow-set-load; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l7a_1p2: l7 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l8a_1p8: l8 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <250>; + regulator-system-load = <325000>; + regulator-allow-set-load; + }; + + vreg_l9a_1p8: l9 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l10a_1p8: l10 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l11a_1p8: l11 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l12a_1p8: l12 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + }; + + /* This gives power to the LPDDR4: never turn it off! */ + vreg_l13a_1p8: l13 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_l14a_1p8: l14 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l15a_1p8: l15 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l16a_2p7: l16 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <250>; + regulator-always-on; + }; + + vreg_l17a_1p8: l17 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2952000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l19a_3p3: l19 { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3400000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + }; + + regulators-1 { + compatible = "qcom,rpm-pm660l-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l9_l10-supply = <&vreg_s2b_1p05>; + vdd_l2-supply = <&vreg_bob>; + vdd_l3_l5_l7_l8-supply = <&vreg_bob>; + vdd_l4_l6-supply = <&vreg_bob>; + vdd_bob-supply = <&vph_pwr>; + + vreg_bob: bob { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <500>; + }; + + vreg_s1b_1p125: s1 { + regulator-min-microvolt = <1125000>; + regulator-max-microvolt = <1125000>; + regulator-enable-ramp-delay = <200>; + }; + + vreg_s2b_1p05: s2 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <200>; + }; + + /* LDOs */ + vreg_l1b_0p925: l1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <925000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + /* SDHCI 3.3V signal doesn't seem to be supported. */ + vreg_l2b_2p95: l2 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2696000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l3b_3p3: l3 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + regulator-always-on; + }; + + vreg_l4b_2p95: l4 { + regulator-min-microvolt = <2944000>; + regulator-max-microvolt = <2952000>; + regulator-enable-ramp-delay = <250>; + + regulator-min-microamp = <200>; + regulator-max-microamp = <600000>; + regulator-system-load = <570000>; + regulator-allow-set-load; + }; + + /* + * Downstream specifies a range of 1721-3600mV, + * but the only assigned consumers are SDHCI2 VMMC + * and Coresight QPDI that both request pinned 2.95V. + * Tighten the range to 1.8-3.328 (closest to 3.3) to + * make the mmc driver happy. + */ + vreg_l5b_2p95: l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3328000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + regulator-system-load = <800000>; + }; + + vreg_l7b_3p125: l7 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3125000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l8b_3p3: l8 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + regulator-enable-ramp-delay = <250>; + }; + }; +}; + +&sdhc_1 { + status = "okay"; + bus-width = <8>; + non-removable; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + vmmc-supply = <&vreg_l4b_2p95>; + vqmmc-supply = <&vreg_l8a_1p8>; +}; + + +&sdhc_2 { + status = "okay"; + + vmmc-supply = <&vreg_l5b_2p95>; + vqmmc-supply = <&vreg_l2b_2p95>; +}; + +&tlmm { + gpio-reserved-ranges = <8 4>; + + mdss_dsi_active: mdss_dsi_active { + function = "gpio"; + pins = "gpio53"; + drive-strength = <8>; + bias-disable; + }; + + mdss_te_active: mdss_te_active { + pins = "gpio59"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_pins_active: ts-pins-active-state { + pins = "gpio66", "gpio67"; + function = "gpio"; + drive-strength = <16>; + bias-pull-up; + }; + + ts_rst_sleep: ts-rst-sleep-state { + pins = "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_int_sleep: ts-int-sleep-state { + pins = "gpio67"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; +}; + +&usb3 { + qcom,select-utmi-as-pipe-clk; + + status = "okay"; +}; + +&usb3_dwc3 { + status = "okay"; + dr_mode = "peripheral"; + extcon = <&extcon_usb>; + + maximum-speed = "high-speed"; + phys = <&qusb2phy0>; + phy-names = "usb2-phy"; +}; + +&venus { + status = "okay"; + firmware-name = "qcom/venus-4.4/venus.mdt"; +}; + +&wifi { + vdd-1.8-xo-supply = <&vreg_l9a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l6a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l19a_3p3>; + + status = "okay"; +}; From 9eddba3630bb40d536717cbb8878648e5f6e8abe Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 5 Aug 2021 15:34:21 +0200 Subject: [PATCH 27/65] arm64: dts: qcom: Introduce SDM660 Xiaomi Mi 8 Lite (platina) Add support for the SDM660 Xiaomi Platina (Mi 8 Lite). Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/sdm660-xiaomi-platina.dts | 723 ++++++++++++++++++ 2 files changed, 724 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index fa1b6252c29972..705caee76625f3 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -196,6 +196,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm632-motorola-ocean.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-asus-x00td.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-sony-xperia-ganges-mermaid.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-lavender.dtb +dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-platina.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm670-google-sargo.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r2.dtb diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts new file mode 100644 index 00000000000000..77f5523071116f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts @@ -0,0 +1,723 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, AngeloGioacchino Del Regno + * + */ + +/dts-v1/; + +#include "sdm660.dtsi" +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include +#include +#include +#include +#include + +/ { + model = "Xiaomi Mi 8 Lite"; + compatible = "xiaomi,platina", "qcom,sdm660"; + + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ramoops@ffc00000 { + compatible = "ramoops"; + reg = <0x0 0xffc00000 0x0 0x100000>; + record-size = <0x10000>; + console-size = <0x60000>; + ftrace-size = <0x10000>; + pmsg-size = <0x20000>; + ecc-size = <16>; + status = "okay"; + }; + + debug_region@ffb00000 { + reg = <0x00 0xffb00000 0x00 0x100000>; + no-map; + }; + + cdsp-region@94e00000 { + reg = <0x00 0x94e00000 0x00 0x600000>; + no-map; + }; + + removed_region@85800000 { + reg = <0x00 0x85800000 0x00 0x3700000>; + no-map; + }; + }; + + board_vbat: vbat-regulator { + compatible = "regulator-fixed"; + regulator-name = "VBAT"; + + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <4000000>; + regulator-always-on; + regulator-boot-on; + }; + + cam_avdd_front_vreg: cam-avdd-front-vreg { + compatible = "regulator-fixed"; + regulator-name = "cam-avdd-front-vreg"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 49 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_avdd_front_default>; + vin-supply = <&vreg_bob>; + }; + + cam_actuator_rear_vreg: cam-actuator-rear-vreg { + compatible = "regulator-fixed"; + regulator-name = "cam-actuator-rear-vreg"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 50 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_actuator_rear_default>; + vin-supply = <&vreg_bob>; + }; + + cam_avdd_rear_vreg: cam-avdd-rear-vreg { + compatible = "regulator-fixed"; + regulator-name = "cam-avdd-rear-vreg"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 51 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_avdd_rear_default>; + vin-supply = <&vreg_bob>; + }; + + cam_dvdd_front_vreg: cam-dvdd-front-vreg { + compatible = "regulator-fixed"; + regulator-name = "cam-dvdd-front-vreg"; + + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + startup-delay-us = <0>; + enable-active-high; + gpio = <&pm660l_gpios 3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_dvdd_front_default>; + vin-supply = <&vreg_s5a_1p35>; + }; + + cam_dvdd_rear_vreg: cam-dvdd-rear-vreg { + compatible = "regulator-fixed"; + regulator-name = "cam-dvdd-rear-vreg"; + + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + startup-delay-us = <0>; + enable-active-high; + gpio = <&pm660l_gpios 4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_dvdd_rear_default>; + vin-supply = <&vreg_s5a_1p35>; + }; + + disp_vdd_vreg: disp-vdd-vreg { + compatible = "regulator-fixed"; + regulator-name = "display-vdd"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ts_vdd_vreg: ts-vdd-vreg { + compatible = "regulator-fixed"; + regulator-name = "ts-vdd"; + + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + startup-delay-us = <4000>; + enable-active-high; + regulator-boot-on; + gpio = <&tlmm 73 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_vdd_default>; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + + regulator-always-on; + regulator-boot-on; + }; + + gpio_keys { + status = "okay"; + compatible = "gpio-keys"; + input-name = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + vol_up { + label = "Volume Up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + wakeup-source; + debounce-interval = <15>; + }; + }; + + gpio-hall-sensor { + compatible = "gpio-keys"; + label = "Hall effect sensor"; + + pinctrl-names = "default"; + pinctrl-0 = <&hall_sensor_default>; + + hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 75 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + linux,can-disable; + wakeup-source; + }; + }; + + + /* + * Until we hook up type-c detection, we + * have to stick with this. But it works. + */ + extcon_usb: extcon-usb { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&tlmm 58 GPIO_ACTIVE_HIGH>; + }; +}; + +&blsp_i2c2 { + status = "okay"; + + /* + * Two instances of SMB1355 charger: 0x8, 0xc but only + * one SMB1355 chip is present on board. What's the + * right address? + */ +}; + +&blsp1_uart2 { + status = "okay"; +}; + +&rpm_requests { + pm660l-regulators { + compatible = "qcom,rpm-pm660l-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l9_l10-supply = <&vreg_s2b_1p05>; + vdd_l2-supply = <&vreg_bob>; + vdd_l3_l5_l7_l8-supply = <&vreg_bob>; + vdd_l4_l6-supply = <&vreg_bob>; + vdd_bob-supply = <&vph_pwr>; + + vreg_s1b_1p125: s1 { + regulator-min-microvolt = <1125000>; + regulator-max-microvolt = <1125000>; + regulator-enable-ramp-delay = <200>; + regulator-ramp-delay = <0>; + }; + + vreg_s2b_1p05: s2 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <200>; + regulator-ramp-delay = <0>; + }; + + /* + * At least on Nile's configuration, S3B/S4B (VDD_CX) and + * S5B (VDD_MX) are managed only through RPM Power Domains. + * Trying to set a voltage on the main supply will create + * havoc and freeze the SoC. + * In any case, reference voltages for these regulators are: + * S3B/S4B: 0.870V + * S5B: 0.915V + */ + + /* LDOs */ + vreg_l1b_0p925: l1 { + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <928000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + + vreg_l2b_2p95: l2 { + /* + * This regulator supports 1.648 - 3.104V on this board + * but we set a max voltage of anything less than 2.7V + * to satisfy a condition in sdhci.c that will disable + * 3.3V SDHCI signaling, which happens to be not really + * supported on the Xperia Nile/Ganges platform. + */ + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2696000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + + vreg_l3b_3p3: l3 { + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3312000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-min-microamp = <200>; + regulator-max-microamp = <600000>; + regulator-system-load = <100000>; + regulator-allow-set-load; + }; + + vreg_l4b_2p95: l4 { + regulator-min-microvolt = <2944000>; + regulator-max-microvolt = <2952000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + + regulator-min-microamp = <200>; + regulator-max-microamp = <600000>; + regulator-system-load = <570000>; + regulator-allow-set-load; + }; + + /* + * Downstream specifies a range of 1721-3600mV, + * but the only assigned consumers are SDHCI2 VMMC + * and Coresight QPDI that both request pinned 2.95V. + * Tighten the range to 1.8-3.328 (closest to 3.3) to + * make the mmc driver happy. + */ + vreg_l5b_29p5: l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3328000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + regulator-system-load = <800000>; + }; + + vreg_l7b_3p125: l7 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3128000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l8b_3p3: l8 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3400000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + /* L9B (870mV) is currently unused */ + /* L10B (915mV) is currently unused */ + + vreg_bob: bob { + regulator-min-microvolt = <3304000>; + regulator-max-microvolt = <3624000>; + regulator-enable-ramp-delay = <500>; + regulator-ramp-delay = <0>; + }; + }; + + + pm660-regulators { + compatible = "qcom,rpm-pm660-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3-supply = <&vph_pwr>; + vdd_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l6_l7-supply = <&vreg_s5a_1p35>; + vdd_l2_l3-supply = <&vreg_s2b_1p05>; + vdd_l5-supply = <&vreg_s2b_1p05>; + vdd_l8_l9_l10_l11_l12_l13_l14-supply = <&vreg_s4a_2p04>; + vdd_l15_l16_l17_l18_l19-supply = <&vreg_bob>; + + /* + * S1A (FTAPC0), S2A (FTAPC1), S3A (HFAPC1) are managed + * by the Core Power Reduction hardened (CPRh) and the + * Operating State Manager (OSM) HW automatically. + */ + + vreg_s4a_2p04: s4 { + regulator-min-microvolt = <2040000>; + regulator-max-microvolt = <2040000>; + regulator-enable-ramp-delay = <200>; + regulator-ramp-delay = <0>; + regulator-always-on; + }; + + vreg_s5a_1p35: s5 { + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1350000>; + regulator-enable-ramp-delay = <200>; + regulator-ramp-delay = <0>; + }; + + vreg_s6a_0p87: s6 { + regulator-min-microvolt = <504000>; + regulator-max-microvolt = <992000>; + regulator-enable-ramp-delay = <150>; + regulator-ramp-delay = <0>; + }; + + /* LDOs */ + vreg_l1a_1p225: l1 { + regulator-min-microvolt = <1226000>; + regulator-max-microvolt = <1250000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + + vreg_l2a_1p0: l2 { + regulator-min-microvolt = <944000>; + regulator-max-microvolt = <1008000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l3a_1p0: l3 { + regulator-min-microvolt = <944000>; + regulator-max-microvolt = <1008000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l5a_0p848: l5 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <952000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l6a_1p3: l6 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1368000>; + regulator-allow-set-load; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l7a_1p2: l7 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l8a_1p8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-system-load = <325000>; + regulator-allow-set-load; + }; + + + vreg_l9a_1p8: l9 { + regulator-min-microvolt = <1804000>; + regulator-max-microvolt = <1896000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + + vreg_l10a_1p8: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1944000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + + vreg_l11a_1p8: l11 { + regulator-min-microvolt = <1784000>; + regulator-max-microvolt = <1944000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l12a_1p8: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1944000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l13a_1p8: l13 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1944000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_l14a_1p8: l14 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1952000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l15a_1p8: l15 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2952000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + /* DRX: QM13111 */ + vreg_l16a_2p7: l16 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2712000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + vreg_l17a_1p8: l17 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2952000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + }; + + /* L18A (2.7V) is unused */ + + vreg_l19a_3p3: l19 { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3328000>; + regulator-enable-ramp-delay = <250>; + regulator-ramp-delay = <0>; + regulator-allow-set-load; + }; + }; +}; + +&sdhc_1 { + status = "okay"; + supports-cqe; + + mmc-ddr-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + + vmmc-supply = <&vreg_l4b_2p95>; + vqmmc-supply = <&vreg_l8a_1p8>; +}; + +&sdhc_2 { + status = "disabled"; + + vmmc-supply = <&vreg_l5b_29p5>; + vqmmc-supply = <&vreg_l2b_2p95>; +}; + +&pm660_gpios { + nfc_clk_req_n: nfc-clkreq-n { + pins = "gpio4"; + function = PMIC_GPIO_FUNC_NORMAL; + bias-disable; + input-enable; + power-source = <1>; + }; +}; + +&pm660l_gpios { + cam_dvdd_front_default: cam-dvdd-front-default { + pins = "gpio3"; + function = "normal"; + output-low; + power-source = <0>; + }; + + cam_dvdd_rear_default: cam-dvdd-rear-default { + pins = "gpio4"; + function = "normal"; + output-low; + power-source = <0>; + }; + + vol_key_gpio_default: vol-key-gpio-default { + pins = "gpio7"; + function = "normal"; + bias-pull-up; + input-enable; + qcom,drive-strength = ; + }; +}; + +&tlmm { + gpio-reserved-ranges = <8 4>; + + camera_rear_default: camera-rear-default { + mclk0 { + pins = "gpio32"; + function = "cam_mclk"; + drive-strength = <4>; + bias-disable; + }; + + rst { + pins = "gpio46"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + camera_front_default: camera-front-default { + mclk1 { + pins = "gpio33"; + function = "cam_mclk"; + drive-strength = <4>; + bias-disable; + }; + + rst { + pins = "gpio47"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + camera_front_iris_default: camera-front-iris-default { + mclk1 { + pins = "gpio35"; + function = "cam_mclk"; + drive-strength = <4>; + bias-disable; + }; + + rst { + pins = "gpio52"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + }; + + cam_avdd_front_default: cam-avdd-front-default { + pins = "gpio49"; + function = "gpio"; + bias-disable; + drive-strength = <2>; + }; + + cam_actuator_rear_default: cam-actuator-rear-default { + pins = "gpio50"; + function = "gpio"; + bias-disable; + drive-strength = <2>; + }; + + cam_avdd_rear_default: cam-avdd-rear-default { + pins = "gpio51"; + function = "gpio"; + bias-disable; + drive-strength = <2>; + }; + + panel_reset_n: panel-rst-n { + pins = "gpio53"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + mdp_vsync_n: mdp-vsync-n { + pins = "gpio59"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_rst_n: ts-rst-n { + pins = "gpio66"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + }; + + ts_int_active: ts-int-active { + pins = "gpio67"; + drive-strength = <16>; + bias-pull-up; + }; + + ts_vdd_default: ts-vdd-default { + pins = "gpio73"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + }; + + hall_sensor_default: hall-sensor-default { + pins = "gpio75"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + +}; + +&usb3 { + qcom,select-utmi-as-pipe-clk; + + status = "okay"; +}; + +&usb3_dwc3 { + maximum-speed = "high-speed"; + phys = <&qusb2phy0>; + phy-names = "usb2-phy"; + + dr_mode = "peripheral"; + extcon = <&extcon_usb>; +}; From 975ec2f226ddf956e3609de91d324811bfa65799 Mon Sep 17 00:00:00 2001 From: Molly Sophia Date: Mon, 17 Jan 2022 10:02:59 +0300 Subject: [PATCH 28/65] arm64: dts: qcom: sdm660-platina: Add several more features * Add simple framebuffer display node and reserve memory for it. * Enable qusb2phy0 and its vdd supplies * Disable gpucc and mmcc, simplefb stops working after few seconds when these are enabled. * Add node for touchscreen * Fix volume keys Signed-off-by: Molly Sophia --- .../boot/dts/qcom/sdm660-xiaomi-platina.dts | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts index 77f5523071116f..26fa4c7fe24cfe 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-platina.dts @@ -2,6 +2,7 @@ /* * Copyright (c) 2021, AngeloGioacchino Del Regno * + * Copyright (c) 2022, Molly Sophia */ /dts-v1/; @@ -25,6 +26,19 @@ chosen { stdout-path = "serial0:115200n8"; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer@9d400000 { + compatible = "simple-framebuffer"; + reg = <0x0 0x9d400000 0x0 (1080 * 2280 * 4)>; + width = <1080>; + height = <2280>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + }; }; reserved-memory { @@ -57,6 +71,11 @@ reg = <0x00 0x85800000 0x00 0x3700000>; no-map; }; + + framebuffer_memory@9d400000 { + reg = <0x0 0x9d400000 0x0 (1080 * 2280 * 4)>; + no-map; + }; }; board_vbat: vbat-regulator { @@ -174,16 +193,15 @@ gpio_keys { status = "okay"; compatible = "gpio-keys"; - input-name = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; + label = "Volume up"; + pinctrl-names = "default"; + pinctrl-0 = <&vol_up_gpio_default>; vol_up { label = "Volume Up"; gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; - linux,input-type = <1>; + linux,input-type = ; linux,code = ; - wakeup-source; debounce-interval = <15>; }; }; @@ -226,6 +244,23 @@ */ }; +&blsp_i2c4 { + status = "okay"; + /* Novatek device tree node */ + novatek@62 { + compatible = "novatek,nt36525"; + reg = <0x62>; + vcc-supply = <&vreg_l11a_1p8>; + pinctrl-0 = <&ts_int_active &ts_rst_n>; + pinctrl-names = "default"; + interrupt-parent = <&tlmm>; + interrupts = <67 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 66 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <2280>; + }; +}; + &blsp1_uart2 { status = "okay"; }; @@ -582,7 +617,7 @@ power-source = <0>; }; - vol_key_gpio_default: vol-key-gpio-default { + vol_up_gpio_default: vol-up-gpio-default { pins = "gpio7"; function = "normal"; bias-pull-up; @@ -591,6 +626,15 @@ }; }; +&pon_resin { + linux,code = ; + status = "okay"; +}; + +&pon_pwrkey { + status = "okay"; +}; + &tlmm { gpio-reserved-ranges = <8 4>; @@ -707,6 +751,26 @@ }; +&adreno_gpu { + status = "disabled"; +}; + +&gpucc { + status = "disabled"; +}; + +&mmcc { + status = "disabled"; +}; + +&qusb2phy0 { + status = "okay"; + + vdd-supply = <&vreg_l1b_0p925>; + vdda-pll-supply = <&vreg_l10a_1p8>; + vdda-phy-dpdm-supply = <&vreg_l7b_3p125>; +}; + &usb3 { qcom,select-utmi-as-pipe-clk; From 8c2a3f5b711d6a52c8e3707ba24354d8ba2f1081 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Wed, 21 Jun 2023 20:31:40 +0300 Subject: [PATCH 29/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Enable radio interfaces Enable support for modem remote processor, WCN3990 Wi-Fi and bluetooth on Xiaomi Redmi Note 7 (lavender). Durig probe chip is identified as: qmi chip_id 0x140 chip_family 0x4002 board_id 0xff soc_id 0x40050000 Signed-off-by: Alexey Minnekhanov --- .../boot/dts/qcom/sdm660-xiaomi-lavender.dts | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index 7167f75bced3fd..4d90c3c02f722d 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -18,7 +18,8 @@ chassis-type = "handset"; aliases { - serial0 = &blsp1_uart2; + serial0 = &blsp1_uart2; /* Debug UART */ + serial1 = &blsp2_uart1; /* Bluetooth UART */ }; chosen { @@ -89,10 +90,33 @@ }; }; +&anoc2_smmu { + status = "okay"; +}; + &blsp1_uart2 { status = "okay"; }; +&blsp2_uart1 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3990-bt"; + vddxo-supply = <&vreg_l9a_1p8>; // downstream: vdd-core-supply + vddrf-supply = <&vreg_l6a_1p3>; // vdd-pa-supply + vddch0-supply = <&vreg_l19a_3p3>; // vdd-ldo-supply + vddio-supply = <&vreg_l13a_1p8>; // chip-pwd-supply ? // TODO: check + max-speed = <3200000>; + /* Path is relative to the qca/ subdir in lib/firmware. */ + /* firmware-name = "crnv21.bin"; */ // default + }; +}; + +&lpass_smmu { + status = "okay"; +}; + &pon_pwrkey { status = "okay"; }; @@ -110,6 +134,11 @@ vdda-phy-dpdm-supply = <&vreg_l7b_3p125>; }; +&remoteproc_mss { + firmware-name = "mba.mbn", "modem.mdt"; + status = "okay"; +}; + &rpm_requests { regulators-0 { compatible = "qcom,rpm-pm660l-regulators"; @@ -426,3 +455,12 @@ dr_mode = "peripheral"; extcon = <&extcon_usb>; }; + +&wifi { + vdd-0.8-cx-mx-supply = <&vreg_l5a_0p848>; + vdd-1.8-xo-supply = <&vreg_l9a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l6a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l19a_3p3>; + + status = "okay"; +}; From d5f93b0bc3cb87678bf9bc46494b6ac4429c85fc Mon Sep 17 00:00:00 2001 From: Dang Huynh Date: Mon, 25 Apr 2022 10:21:41 +0700 Subject: [PATCH 30/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Add Touchscreen The Xiaomi Redmi Note 7 uses a Novatek NT36672A touchscreen, so add support for it. Signed-off-by: Dang Huynh [alexey: added power supply and pinctrl] Signed-off-by: Alexey Minnekhanov --- .../boot/dts/qcom/sdm660-xiaomi-lavender.dts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index 4d90c3c02f722d..15769c6537fd03 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -94,6 +94,25 @@ status = "okay"; }; +&blsp_i2c1 { + status = "okay"; + + /* Novatek NT36672A touchscreen */ + touchscreen@62 { + compatible = "novatek,nt36525"; + reg = <0x62>; + vdd-supply = <&vreg_l11a_1p8>; + interrupt-parent = <&tlmm>; + interrupts = <67 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&ts_pins_active>; + pinctrl-1 = <&ts_int_sleep &ts_rst_sleep>; + reset-gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <2340>; + }; +}; + &blsp1_uart2 { status = "okay"; }; @@ -439,6 +458,27 @@ &tlmm { gpio-reserved-ranges = <8 4>; + + ts_pins_active: ts-pins-active-state { + pins = "gpio66", "gpio67"; + function = "gpio"; + drive-strength = <16>; + bias-pull-up; + }; + + ts_rst_sleep: ts-rst-sleep-state { + pins = "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_int_sleep: ts-int-sleep-state { + pins = "gpio67"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; }; &usb3 { From ab2294749213253ce8387f190a5e264fbdbbdca1 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Fri, 17 Nov 2023 11:41:07 +0300 Subject: [PATCH 31/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Mark l3b as always-on vreg_l3b_3p3 is marked as always-on in downstream device tree. Also since l3b is supplied by vreg_bob, move bob definition up above l3b, so that regulator core succeeds in resolving supplies and does not fall into endless -EPROBE_DEFER loop. Signed-off-by: Alexey Minnekhanov --- arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index 15769c6537fd03..ca77ea692da3e3 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -174,6 +174,12 @@ vdd_l4_l6-supply = <&vreg_bob>; vdd_bob-supply = <&vph_pwr>; + vreg_bob: bob { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <500>; + }; + vreg_s1b_1p125: s1 { regulator-min-microvolt = <1125000>; regulator-max-microvolt = <1125000>; @@ -207,6 +213,7 @@ regulator-max-microvolt = <3300000>; regulator-enable-ramp-delay = <250>; regulator-allow-set-load; + regulator-always-on; }; vreg_l4b_2p95: l4 { @@ -246,12 +253,6 @@ regulator-max-microvolt = <3400000>; regulator-enable-ramp-delay = <250>; }; - - vreg_bob: bob { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3600000>; - regulator-enable-ramp-delay = <500>; - }; }; regulators-1 { From 516382cea17c4a1c82f03f4baec67ef4b1a1eedd Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Mon, 1 Jan 2024 01:08:27 +0300 Subject: [PATCH 32/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Add support for battery Add support for battery, fuelgauge and charger. Also reorder pm660l_wled alphabetcally, and enable power key. Signed-off-by: Alexey Minnekhanov --- .../boot/dts/qcom/sdm660-xiaomi-lavender.dts | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index ca77ea692da3e3..e754b979aa786e 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -39,6 +39,14 @@ }; }; + battery: battery { + compatible = "simple-battery"; + + charge-full-design-microamp-hours = <4000000>; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4400000>; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -136,6 +144,33 @@ status = "okay"; }; +&pm660_charger { + monitored-battery = <&battery>; + + status = "okay"; +}; + +&pm660_fg { + monitored-battery = <&battery>; + qcom,battery-capacity-ua = <4000000>; + qcom,min-voltage-uv= <3400000>; + qcom,max-voltage-uv= <4408000>; + + status = "okay"; +}; + +&pm660_rradc { + status = "okay"; +}; + +&pm660l_wled { + status = "okay"; + + qcom,switching-freq = <800>; + qcom,current-limit-microamp = <20000>; + qcom,num-strings = <2>; +}; + &pon_pwrkey { status = "okay"; }; @@ -412,14 +447,6 @@ }; }; -&pm660l_wled { - status = "okay"; - - qcom,switching-freq = <800>; - qcom,current-limit-microamp = <20000>; - qcom,num-strings = <2>; -}; - &sdc2_state_on { sd-cd-pins { pins = "gpio54"; From 23f6de644c09051d896de6ac011e3bf49f1b20c1 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sun, 7 Jan 2024 00:16:26 +0300 Subject: [PATCH 33/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Add support for venus Signed-off-by: Alexey Minnekhanov --- arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index e754b979aa786e..dc60d4e980f018 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -524,6 +524,11 @@ extcon = <&extcon_usb>; }; +&venus { + firmware-name = "qcom/venus-4.4/venus.mdt"; + status = "okay"; +}; + &wifi { vdd-0.8-cx-mx-supply = <&vreg_l5a_0p848>; vdd-1.8-xo-supply = <&vreg_l9a_1p8>; From cbba9010745788235a6e059b81485ff8c9349402 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Sat, 27 Apr 2024 22:07:10 +0300 Subject: [PATCH 34/65] arm64: dts: qcom: sdm660-xiaomi-lavender: Add support for haptics Enable support for haptics node located on PMIC. Signed-off-by: Alexey Minnekhanov --- arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts index dc60d4e980f018..1f197b3ae5cc1c 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts @@ -159,6 +159,10 @@ status = "okay"; }; +&pm660_haptics { + status = "okay"; +}; + &pm660_rradc { status = "okay"; }; From 6e07c7a0457d50bede074c1c578b95e7ae490aff Mon Sep 17 00:00:00 2001 From: M0Rf30 Date: Sat, 26 Nov 2022 12:09:18 +0100 Subject: [PATCH 35/65] arm64: dts: qcom: add device-tree for Redmi Note 6 Pro (tulip) Commit 1: Initial support Commit 2: enable touchscreen input and panel Commit 3: Enable bluetooth Add support for HCI wcn3990-bt on Xiaomi Redmi Note 6 Pro tulip. Commit 4: enable touchscreen input and bluetooth Signed-off-by: Gianluca Boiano --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/sdm636-xiaomi-tulip.dts | 606 ++++++++++++++++++ 2 files changed, 607 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm636-xiaomi-tulip.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 705caee76625f3..186a62c93cd96e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -195,6 +195,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm632-fairphone-fp3.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm632-motorola-ocean.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-asus-x00td.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm636-sony-xperia-ganges-mermaid.dtb +dtb-$(CONFIG_ARCH_QCOM) += sdm636-xiaomi-tulip.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-lavender.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm660-xiaomi-platina.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm670-google-sargo.dtb diff --git a/arch/arm64/boot/dts/qcom/sdm636-xiaomi-tulip.dts b/arch/arm64/boot/dts/qcom/sdm636-xiaomi-tulip.dts new file mode 100644 index 00000000000000..8222e5ee4a79ac --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm636-xiaomi-tulip.dts @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2022 Gianluca Boiano + +/dts-v1/; + +#include "sdm636.dtsi" +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include +#include +#include + +/delete-node/ &tz_mem; + +/ { + model = "Xiaomi Redmi Note 6 Pro"; + compatible = "xiaomi,tulip", "qcom,sdm660", "qcom,sdm636"; + chassis-type = "handset"; + + aliases { + serial0 = &blsp1_uart2; /* Debug UART */ + serial1 = &blsp2_uart1; /* Bluetooth UART */ + }; + + battery: battery { + compatible = "simple-battery"; + + charge-full-design-microamp-hours = <4000000>; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4408000>; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0:115200n8"; + + framebuffer0: framebuffer@9d400000 { + compatible = "simple-framebuffer"; + reg = <0 0x9d400000 0x0 (1080 * 2280 * 4)>; + width = <1080>; + height = <2280>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + + /* In order to allow simple-framebuffer to know + * physical dimensions */ + panel = <&fb_panel>; + + fb_panel: fb-panel { + width-mm = <68>; + height-mm = <143>; + }; + }; + }; + + gpio-hall-sensor { + compatible = "gpio-keys"; + label = "Hall effect sensor"; + + pinctrl-names = "default"; + pinctrl-0 = <&hall_sensor_default>; + + hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 75 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + linux,can-disable; + wakeup-source; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + key-volup { + label = "Volume Up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ramoops@a0000000 { + compatible = "ramoops"; + reg = <0x0 0xa0000000 0x0 0x400000>; + console-size = <0x20000>; + record-size = <0x20000>; + ftrace-size = <0x0>; + pmsg-size = <0x20000>; + }; + + framebuffer_mem: memory@9d400000 { + reg = <0x0 0x9d400000 0x0 (1080 * 2280 * 4)>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&adsp_pil { + firmware-name = "adsp.mdt"; + + status = "okay"; +}; + +&anoc2_smmu { + status = "okay"; +}; + +&blsp_i2c1 { + status = "okay"; + + /* Novatek NT36672A touchscreen */ + touchscreen@62 { + compatible = "novatek,nt36525"; + reg = <0x62>; + interrupt-parent = <&tlmm>; + vdd-supply = <&vreg_l11a_1p8>; + vio-supply = <&vreg_l11a_1p8>; + interrupts = <67 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&ts_pins_active>; + pinctrl-1 = <&ts_int_sleep &ts_rst_sleep>; + reset-gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <2280>; + }; +}; + +&blsp_i2c2 { + status = "okay"; +}; + +&blsp_i2c6 { + status = "okay"; +}; + +&blsp1_uart2 { + status = "okay"; +}; + +&blsp2_uart1 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3990-bt"; + vddxo-supply = <&vreg_l9a_1p8>; // downstream: vdd-core-supply + vddrf-supply = <&vreg_l6a_1p3>; // vdd-pa-supply + vddch0-supply = <&vreg_l19a_3p3>; // vdd-ldo-supply + vddio-supply = <&vreg_l13a_1p8>; // chip-pwd-supply ? // TODO: check + max-speed = <3200000>; + }; +}; + +&lpass_smmu { + status = "okay"; +}; + +&mdss_dsi0 { + #address-cells = <1>; + #size-cells = <0>; + + panel: panel@0 { + compatible = "tianma,nt36672a-xiaomi-tulip-simple"; + reg = <0>; + + reset-gpios = <&tlmm 53 GPIO_ACTIVE_LOW>; + + backlight = <&pm660l_wled>; + + pinctrl-names = "default"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + }; +}; + +&pm660_charger { + monitored-battery = <&battery>; + + status = "okay"; +}; + +&pm660_fg { + monitored-battery = <&battery>; + qcom,battery-capacity-ua = <4000000>; + qcom,min-voltage-uv= <3400000>; + qcom,max-voltage-uv= <4408000>; + + status = "okay"; +}; + +&pm660_haptics { + status = "okay"; +}; + +&pm660_rradc { + status = "okay"; +}; + +&pm660l_wled { + status = "okay"; + + qcom,switching-freq = <800>; + qcom,current-limit-microamp = <20000>; + qcom,num-strings = <2>; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + status = "okay"; + + linux,code = ; +}; + +&qusb2phy0 { + status = "okay"; + + vdd-supply = <&vreg_l1b_0p925>; + vdda-pll-supply = <&vreg_l10a_1p8>; + vdda-phy-dpdm-supply = <&vreg_l7b_3p125>; +}; + +&remoteproc_mss { + firmware-name = "mba.mbn", "modem.mdt"; + status = "okay"; +}; + +&rpm_requests { + regulators-0 { + compatible = "qcom,rpm-pm660l-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l9_l10-supply = <&vreg_s2b_1p05>; + vdd_l2-supply = <&vreg_bob>; + vdd_l3_l5_l7_l8-supply = <&vreg_bob>; + vdd_l4_l6-supply = <&vreg_bob>; + vdd_bob-supply = <&vph_pwr>; + + vreg_bob: bob { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <500>; + }; + + vreg_s1b_1p125: s1 { + regulator-min-microvolt = <1125000>; + regulator-max-microvolt = <1125000>; + regulator-enable-ramp-delay = <200>; + }; + + vreg_s2b_1p05: s2 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <200>; + }; + + /* LDOs */ + vreg_l1b_0p925: l1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <925000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + /* SDHCI 3.3V signal doesn't seem to be supported. */ + vreg_l2b_2p95: l2 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <2696000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l3b_3p3: l3 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + regulator-always-on; + }; + + vreg_l4b_2p95: l4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2950000>; + regulator-enable-ramp-delay = <250>; + + regulator-min-microamp = <200>; + regulator-max-microamp = <600000>; + regulator-system-load = <570000>; + regulator-allow-set-load; + }; + + /* + * Downstream specifies a range of 1721-3600mV, + * but the only assigned consumers are SDHCI2 VMMC + * and Coresight QPDI that both request pinned 2.95V. + * Tighten the range to 1.8-3.328 (closest to 3.3) to + * make the mmc driver happy. + */ + vreg_l5b_2p95: l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3328000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + regulator-system-load = <800000>; + }; + + vreg_l7b_3p125: l7 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3125000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l8b_3p3: l8 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + regulator-enable-ramp-delay = <250>; + }; + }; + + regulators-1 { + compatible = "qcom,rpm-pm660-regulators"; + + vdd_s1-supply = <&vph_pwr>; + vdd_s2-supply = <&vph_pwr>; + vdd_s3-supply = <&vph_pwr>; + vdd_s4-supply = <&vph_pwr>; + vdd_s5-supply = <&vph_pwr>; + vdd_s6-supply = <&vph_pwr>; + + vdd_l1_l6_l7-supply = <&vreg_s5a_1p35>; + vdd_l2_l3-supply = <&vreg_s2b_1p05>; + vdd_l5-supply = <&vreg_s2b_1p05>; + vdd_l8_l9_l10_l11_l12_l13_l14-supply = <&vreg_s4a_2p04>; + vdd_l15_l16_l17_l18_l19-supply = <&vreg_bob>; + + /* + * S1A (FTAPC0), S2A (FTAPC1), S3A (HFAPC1) are managed + * by the Core Power Reduction hardened (CPRh) and the + * Operating State Manager (OSM) HW automatically. + */ + + vreg_s4a_2p04: s4 { + regulator-min-microvolt = <1805000>; + regulator-max-microvolt = <2040000>; + regulator-enable-ramp-delay = <200>; + regulator-always-on; + }; + + vreg_s5a_1p35: s5 { + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1350000>; + regulator-enable-ramp-delay = <200>; + }; + + vreg_s6a_0p87: s6 { + regulator-min-microvolt = <504000>; + regulator-max-microvolt = <992000>; + regulator-enable-ramp-delay = <150>; + }; + + /* LDOs */ + vreg_l1a_1p225: l1 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1250000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l2a_1p0: l2 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l3a_1p0: l3 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l5a_0p848: l5 { + regulator-min-microvolt = <525000>; + regulator-max-microvolt = <950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l6a_1p3: l6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1370000>; + regulator-allow-set-load; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l7a_1p2: l7 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l8a_1p8: l8 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <250>; + regulator-system-load = <325000>; + regulator-allow-set-load; + }; + + vreg_l9a_1p8: l9 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l10a_1p8: l10 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + + vreg_l11a_1p8: l11 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l12a_1p8: l12 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + }; + + /* This gives power to the LPDDR4: never turn it off! */ + vreg_l13a_1p8: l13 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + regulator-enable-ramp-delay = <250>; + regulator-boot-on; + regulator-always-on; + }; + + vreg_l14a_1p8: l14 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l15a_1p8: l15 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l17a_1p8: l17 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + regulator-enable-ramp-delay = <250>; + }; + + vreg_l19a_3p3: l19 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + regulator-enable-ramp-delay = <250>; + regulator-allow-set-load; + }; + }; +}; + +&sdc2_state_on { + sd-cd-pins { + pins = "gpio54"; + function = "gpio"; + bias-pull-up; + drive-strength = <2>; + }; +}; + +&sdc2_state_off { + sd-cd-pins { + pins = "gpio54"; + function = "gpio"; + bias-disable; + drive-strength = <2>; + }; +}; + +&sdhc_1 { + status = "okay"; + supports-cqe; + + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + + vmmc-supply = <&vreg_l4b_2p95>; + vqmmc-supply = <&vreg_l8a_1p8>; +}; + +&sdhc_2 { + status = "okay"; + + vmmc-supply = <&vreg_l5b_2p95>; + vqmmc-supply = <&vreg_l2b_2p95>; +}; + +&tlmm { + gpio-reserved-ranges = <8 4>; + + hall_sensor_default: hall-sensor-state { + pins = "gpio75"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + + mdss_dsi_active: mdss_dsi_active { + function = "gpio"; + pins = "gpio53"; + drive-strength = <8>; + bias-disable; + }; + + mdss_te_active: mdss_te_active { + pins = "gpio59"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_pins_active: ts-pins-active-state { + pins = "gpio66", "gpio67"; + function = "gpio"; + drive-strength = <16>; + bias-pull-up; + }; + + ts_rst_sleep: ts-rst-sleep-state { + pins = "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_int_sleep: ts-int-sleep-state { + pins = "gpio67"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; +}; + +&usb3 { + qcom,select-utmi-as-pipe-clk; + + status = "okay"; +}; + +&usb3_dwc3 { + maximum-speed = "high-speed"; + phys = <&qusb2phy0>; + phy-names = "usb2-phy"; + dr_mode = "peripheral"; + + status = "okay"; +}; + +&venus { + status = "okay"; +}; + +&wifi { + vdd-0.8-cx-mx-supply = <&vreg_l5a_0p848>; + vdd-1.8-xo-supply = <&vreg_l9a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l6a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l19a_3p3>; + vdd-3.3-ch1-supply = <&vreg_l19a_3p3>; + + status = "okay"; +}; From 652009c54feeadffe08af4e7d1d68d317ad61007 Mon Sep 17 00:00:00 2001 From: Joe Mason Date: Sat, 26 Nov 2022 06:47:07 -0500 Subject: [PATCH 36/65] drm/panel: Add support for xiaomi-jasmine nt36672 panel alexeymin: TODO: this needs to be integrated into panel-novatek-nt36672a.c as variation with its own compatible string and own init sequences. [1] https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-novatek-nt36672a.c Signed-off-by: Joe Mason --- drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + .../panel-novatek-nt36672-tianma-jasmine.c | 253 ++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36672-tianma-jasmine.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 4e352c60b3e812..44aafa946119ed 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -488,6 +488,15 @@ config DRM_PANEL_NOVATEK_NT36672E LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit RGB per pixel. +config DRM_PANEL_NOVATEK_NT36672_TIANMA_JASMINE + tristate "Novatek NT36672 Tianma panel for xiaomi-jasmine" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Tianma nt36672 + command mode panel used in Xiaomi Mi A2 phone (codename jasmine) + config DRM_PANEL_NOVATEK_NT36672_TXD tristate "Novatek NT36672 TXD panel for asus-x00td" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index bbb8e4b85ce4d9..72747afad0d762 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672_TIANMA_JASMINE) += panel-novatek-nt36672-tianma-jasmine.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672_TXD) += panel-novatek-nt36672-txd.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672-tianma-jasmine.c b/drivers/gpu/drm/panel/panel-novatek-nt36672-tianma-jasmine.c new file mode 100644 index 00000000000000..94f6e259437ca5 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672-tianma-jasmine.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2024 FIXME +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME) + +#include +#include +#include +#include +#include + +#include