diff --git a/config/kernel/linux-rk322x-current.config b/config/kernel/linux-rk322x-current.config index 90e90ddbf9..8c7b9ff081 100644 --- a/config/kernel/linux-rk322x-current.config +++ b/config/kernel/linux-rk322x-current.config @@ -1,18 +1,20 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 6.1.4 Kernel Configuration +# Linux/arm 6.1.57 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36)) 8.3.0" +CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=80300 +CONFIG_GCC_VERSION=110300 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=23200 +CONFIG_AS_VERSION=23800 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=23200 +CONFIG_LD_VERSION=23800 CONFIG_LLD_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y CONFIG_PAHOLE_VERSION=122 @@ -158,7 +160,8 @@ CONFIG_GENERIC_SCHED_CLOCK=y # end of Scheduler features CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_GCC12_NO_ARRAY_BOUNDS=y +CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_CC_NO_ARRAY_BOUNDS=y CONFIG_CGROUPS=y CONFIG_PAGE_COUNTER=y # CONFIG_CGROUP_FAVOR_DYNMODS is not set @@ -608,6 +611,7 @@ CONFIG_GENERIC_IDLE_POLL_SETUP=y CONFIG_ARCH_HAS_FORTIFY_SOURCE=y CONFIG_ARCH_HAS_KEEPINITRD=y CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y CONFIG_ARCH_32BIT_OFF_T=y CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y @@ -666,7 +670,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling CONFIG_HAVE_GCC_PLUGINS=y -# CONFIG_GCC_PLUGINS is not set # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -847,6 +850,7 @@ CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY=y CONFIG_LRU_GEN=y CONFIG_LRU_GEN_ENABLED=y # CONFIG_LRU_GEN_STATS is not set +CONFIG_LOCK_MM_AND_FIND_VMA=y # # Data Access Monitoring @@ -1493,14 +1497,11 @@ CONFIG_DEFAULT_NET_SCH="pfifo_fast" # CONFIG_NET_CLS=y CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_FW=m CONFIG_NET_CLS_U32=m CONFIG_CLS_U32_PERF=y CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_FLOW=m CONFIG_NET_CLS_CGROUP=m CONFIG_NET_CLS_BPF=m @@ -2432,6 +2433,7 @@ CONFIG_MT7615_COMMON=m CONFIG_MT7663_USB_SDIO_COMMON=m CONFIG_MT7663U=m # CONFIG_MT7663S is not set +CONFIG_MT7921_COMMON=m # CONFIG_MT7921S is not set CONFIG_MT7921U=m # CONFIG_WLAN_VENDOR_MICROCHIP is not set @@ -2468,6 +2470,14 @@ CONFIG_RTL8192C_COMMON=m CONFIG_RTL8XXXU=m # CONFIG_RTL8XXXU_UNTESTED is not set CONFIG_RTW88=m +# CONFIG_RTW88_8822BS is not set +# CONFIG_RTW88_8822BU is not set +# CONFIG_RTW88_8822CS is not set +# CONFIG_RTW88_8822CU is not set +# CONFIG_RTW88_8723DS is not set +# CONFIG_RTW88_8723DU is not set +# CONFIG_RTW88_8821CS is not set +# CONFIG_RTW88_8821CU is not set # CONFIG_RTW89 is not set CONFIG_WLAN_VENDOR_RSI=y # CONFIG_RSI_91X is not set @@ -2482,7 +2492,6 @@ CONFIG_WLAN_VENDOR_TI=y # CONFIG_WLCORE is not set CONFIG_RTL8723DU=m # CONFIG_RTL8723DS is not set -# CONFIG_RTL8822CS is not set CONFIG_RTL8822BU=m CONFIG_RTL8821CU=m CONFIG_88XXAU=m @@ -3318,7 +3327,6 @@ CONFIG_SENSORS_GPIO_FAN=y # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_NTC_THERMISTOR is not set # CONFIG_SENSORS_NCT6683 is not set -# CONFIG_SENSORS_NCT6775 is not set # CONFIG_SENSORS_NCT6775_I2C is not set # CONFIG_SENSORS_NCT7802 is not set # CONFIG_SENSORS_NCT7904 is not set @@ -3662,6 +3670,7 @@ CONFIG_IR_GPIO_CIR=m # CONFIG_IR_MCEUSB is not set # CONFIG_IR_PWM_TX is not set # CONFIG_IR_REDRAT3 is not set +CONFIG_IR_ROCKCHIP_CIR=m # CONFIG_IR_SERIAL is not set CONFIG_IR_SPI=m # CONFIG_IR_STREAMZAP is not set @@ -3711,8 +3720,8 @@ CONFIG_VIDEO_TUNER=m CONFIG_V4L2_H264=m CONFIG_V4L2_VP9=m CONFIG_V4L2_MEM2MEM_DEV=m -CONFIG_V4L2_FWNODE=m -CONFIG_V4L2_ASYNC=m +CONFIG_V4L2_FWNODE=y +CONFIG_V4L2_ASYNC=y # end of Video4Linux options # @@ -4034,10 +4043,7 @@ CONFIG_VIDEOBUF2_DMA_SG=y # CONFIG_MEDIA_ATTACH=y CONFIG_VIDEO_IR_I2C=m - -# -# Camera sensor devices -# +CONFIG_VIDEO_CAMERA_SENSOR=y # CONFIG_VIDEO_AR0521 is not set # CONFIG_VIDEO_HI556 is not set # CONFIG_VIDEO_HI846 is not set @@ -4104,7 +4110,6 @@ CONFIG_VIDEO_IR_I2C=m # CONFIG_VIDEO_CCS is not set # CONFIG_VIDEO_ET8EK8 is not set # CONFIG_VIDEO_M5MOLS is not set -# end of Camera sensor devices # # Lens drivers @@ -4593,8 +4598,6 @@ CONFIG_DRM_DW_HDMI_CEC=y # CONFIG_DRM_STI is not set # CONFIG_DRM_ETNAVIV is not set # CONFIG_DRM_LOGICVC is not set -# CONFIG_DRM_MXSFB is not set -# CONFIG_DRM_IMX_LCDIF is not set # CONFIG_DRM_ARCPGU is not set # CONFIG_DRM_GM12U320 is not set # CONFIG_DRM_PANEL_MIPI_DBI is not set @@ -5769,7 +5772,6 @@ CONFIG_STAGING=y # CONFIG_PRISM2_USB is not set # CONFIG_RTLLIB is not set CONFIG_RTL8723BS=m -CONFIG_RTL8723CS=m CONFIG_R8712U=m CONFIG_R8188EU=m # CONFIG_VT6656 is not set @@ -5869,6 +5871,7 @@ CONFIG_FIELDBUS_DEV=m CONFIG_HMS_ANYBUSS_BUS=m CONFIG_ARCX_ANYBUS_CONTROLLER=m CONFIG_HMS_PROFINET=m +CONFIG_RTL8723CS=m # CONFIG_GOLDFISH is not set # CONFIG_CHROME_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set @@ -6041,7 +6044,6 @@ CONFIG_DEVFREQ_GOV_USERSPACE=y # # DEVFREQ Drivers # -# CONFIG_ARM_RK3328_DMC_DEVFREQ is not set CONFIG_ARM_RK3228_DMC_DEVFREQ=y # CONFIG_ARM_RK3399_DMC_DEVFREQ is not set CONFIG_PM_DEVFREQ_EVENT=y @@ -6928,24 +6930,6 @@ CONFIG_PSTORE_RAM=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_EROFS_FS is not set -CONFIG_AUFS_FS=m -CONFIG_AUFS_BRANCH_MAX_127=y -# CONFIG_AUFS_BRANCH_MAX_511 is not set -# CONFIG_AUFS_BRANCH_MAX_1023 is not set -# CONFIG_AUFS_BRANCH_MAX_32767 is not set -CONFIG_AUFS_SBILIST=y -# CONFIG_AUFS_HNOTIFY is not set -# CONFIG_AUFS_EXPORT is not set -# CONFIG_AUFS_XATTR is not set -# CONFIG_AUFS_FHSM is not set -# CONFIG_AUFS_RDU is not set -# CONFIG_AUFS_DIRREN is not set -# CONFIG_AUFS_SHWH is not set -# CONFIG_AUFS_BR_RAMFS is not set -# CONFIG_AUFS_BR_FUSE is not set -CONFIG_AUFS_BR_HFSPLUS=y -CONFIG_AUFS_BDEV_LOOP=y -# CONFIG_AUFS_DEBUG is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V2=m @@ -7006,7 +6990,7 @@ CONFIG_CIFS_FSCACHE=y CONFIG_SMB_SERVER=m CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y # CONFIG_SMB_SERVER_KERBEROS5 is not set -CONFIG_SMBFS_COMMON=m +CONFIG_SMBFS=m # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set CONFIG_NLS=y @@ -7118,6 +7102,8 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity" CONFIG_INIT_STACK_NONE=y # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y +# CONFIG_ZERO_CALL_USED_REGS is not set # end of Memory initialization CONFIG_RANDSTRUCT_NONE=y @@ -7570,6 +7556,7 @@ CONFIG_DEBUG_FS_ALLOW_ALL=y CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set # CONFIG_UBSAN is not set +CONFIG_HAVE_KCSAN_COMPILER=y # end of Generic Kernel Debugging Instruments # diff --git a/config/kernel/linux-rk322x-edge.config b/config/kernel/linux-rk322x-edge.config index eafd306c45..8fdca154bf 100644 --- a/config/kernel/linux-rk322x-edge.config +++ b/config/kernel/linux-rk322x-edge.config @@ -1,21 +1,23 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 6.5.5 Kernel Configuration +# Linux/arm 6.5.7 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" +CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=110400 +CONFIG_GCC_VERSION=110300 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y CONFIG_AS_VERSION=23800 CONFIG_LD_IS_BFD=y CONFIG_LD_VERSION=23800 CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=125 +CONFIG_PAHOLE_VERSION=122 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -1354,6 +1356,7 @@ CONFIG_BRIDGE_EBT_SNAT=m CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m CONFIG_BPFILTER=y +CONFIG_BPFILTER_UMH=m CONFIG_IP_DCCP=m CONFIG_INET_DCCP_DIAG=m @@ -3711,6 +3714,7 @@ CONFIG_IR_GPIO_CIR=m # CONFIG_IR_MCEUSB is not set # CONFIG_IR_PWM_TX is not set # CONFIG_IR_REDRAT3 is not set +CONFIG_IR_ROCKCHIP_CIR=m # CONFIG_IR_SERIAL is not set CONFIG_IR_SPI=m # CONFIG_IR_STREAMZAP is not set diff --git a/patch/kernel/archive/rk322x-6.1/dt/rk322x-box.dts b/patch/kernel/archive/rk322x-6.1/dt/rk322x-box.dts index 732a9dd5d6..ddc25ec77f 100644 --- a/patch/kernel/archive/rk322x-6.1/dt/rk322x-box.dts +++ b/patch/kernel/archive/rk322x-6.1/dt/rk322x-box.dts @@ -119,6 +119,22 @@ linux,rc-map-name = "rc-rk322x-tvbox"; }; + rockchip_ir_receiver: rockchip-ir-receiver { + compatible = "rockchip-ir-receiver"; + reg = <0x110b0030 0x10>; + gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; + clocks = <&cru PCLK_PWM>; + interrupts = ; + linux,rc-map-name = "rc-rk322x-tvbox"; + pinctrl-names = "default", "suspend"; + pinctrl-0 = <&ir_int>; + pinctrl-1 = <&pwm3_pin>; + pwm-id = <3>; + shutdown-is-virtual-poweroff; + wakeup-source; + status = "disabled"; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; diff --git a/patch/kernel/archive/rk322x-6.1/general-rk322x-gpio-ir-driver.patch b/patch/kernel/archive/rk322x-6.1/general-rk322x-gpio-ir-driver.patch new file mode 100644 index 0000000000..25645bad32 --- /dev/null +++ b/patch/kernel/archive/rk322x-6.1/general-rk322x-gpio-ir-driver.patch @@ -0,0 +1,778 @@ +From 13498feb91614d59ebece61d0c278e31529bb8c8 Mon Sep 17 00:00:00 2001 +From: Paolo Sabatino +Date: Tue, 10 Oct 2023 21:54:51 +0200 +Subject: [PATCH] rockchip gpio IR driver + +--- + drivers/media/rc/Kconfig | 11 + + drivers/media/rc/Makefile | 1 + + drivers/media/rc/rockchip-ir.c | 723 +++++++++++++++++++++++++++++++++ + 3 files changed, 735 insertions(+) + create mode 100644 drivers/media/rc/rockchip-ir.c + +diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig +index f560fc38895f..b77fa83e90e8 100644 +--- a/drivers/media/rc/Kconfig ++++ b/drivers/media/rc/Kconfig +@@ -333,6 +333,17 @@ config IR_REDRAT3 + To compile this driver as a module, choose M here: the + module will be called redrat3. + ++config IR_ROCKCHIP_CIR ++ tristate "Rockchip GPIO IR receiver" ++ depends on (OF && GPIOLIB) || COMPILE_TEST ++ help ++ Say Y here if you want to use the Rockchip IR receiver with ++ virtual poweroff features provided by rockchip Trust OS ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rockchip-ir ++ ++ + config IR_RX51 + tristate "Nokia N900 IR transmitter diode" + depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE +diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile +index a9285266e944..057d5b64c121 100644 +--- a/drivers/media/rc/Makefile ++++ b/drivers/media/rc/Makefile +@@ -43,6 +43,7 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o + obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o + obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o + obj-$(CONFIG_IR_REDRAT3) += redrat3.o ++obj-$(CONFIG_IR_ROCKCHIP_CIR) += rockchip-ir.o + obj-$(CONFIG_IR_RX51) += ir-rx51.o + obj-$(CONFIG_IR_SERIAL) += serial_ir.o + obj-$(CONFIG_IR_SPI) += ir-spi.o +diff --git a/drivers/media/rc/rockchip-ir.c b/drivers/media/rc/rockchip-ir.c +new file mode 100644 +index 000000000000..06c483cd8d5b +--- /dev/null ++++ b/drivers/media/rc/rockchip-ir.c +@@ -0,0 +1,723 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ROCKCHIP_IR_DEVICE_NAME "rockchip_ir_recv" ++ ++#ifdef CONFIG_64BIT ++#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name ++#else ++#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name ++#endif ++ ++/* ++* SIP/TEE constants for remote calls ++*/ ++#define SIP_REMOTECTL_CFG 0x8200000b ++#define SIP_SUSPEND_MODE 0x82000003 ++#define SIP_REMOTECTL_CFG 0x8200000b ++#define SUSPEND_MODE_CONFIG 0x01 ++#define WKUP_SOURCE_CONFIG 0x02 ++#define PWM_REGULATOR_CONFIG 0x03 ++#define GPIO_POWER_CONFIG 0x04 ++#define SUSPEND_DEBUG_ENABLE 0x05 ++#define APIOS_SUSPEND_CONFIG 0x06 ++#define VIRTUAL_POWEROFF 0x07 ++ ++#define REMOTECTL_SET_IRQ 0xf0 ++#define REMOTECTL_SET_PWM_CH 0xf1 ++#define REMOTECTL_SET_PWRKEY 0xf2 ++#define REMOTECTL_GET_WAKEUP_STATE 0xf3 ++#define REMOTECTL_ENABLE 0xf4 ++#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf /* wakeup state */ ++ ++/* ++* PWM Registers ++* Each PWM has its own control registers ++*/ ++#define PWM_REG_CNTR 0x00 /* Counter Register */ ++#define PWM_REG_HPR 0x04 /* Period Register */ ++#define PWM_REG_LPR 0x08 /* Duty Cycle Register */ ++#define PWM_REG_CTRL 0x0c /* Control Register */ ++ ++/* ++* PWM General registers ++* Registers shared among PWMs ++*/ ++#define PWM_REG_INT_EN 0x44 ++ ++/*REG_CTRL bits definitions*/ ++#define PWM_ENABLE (1 << 0) ++#define PWM_DISABLE (0 << 0) ++ ++/*operation mode*/ ++#define PWM_MODE_ONESHOT (0x00 << 1) ++#define PWM_MODE_CONTINUMOUS (0x01 << 1) ++#define PWM_MODE_CAPTURE (0x02 << 1) ++ ++/* Channel interrupt enable bit */ ++#define PWM_CH_INT_ENABLE(n) BIT(n) ++ ++enum pwm_div { ++ PWM_DIV1 = (0x0 << 12), ++ PWM_DIV2 = (0x1 << 12), ++ PWM_DIV4 = (0x2 << 12), ++ PWM_DIV8 = (0x3 << 12), ++ PWM_DIV16 = (0x4 << 12), ++ PWM_DIV32 = (0x5 << 12), ++ PWM_DIV64 = (0x6 << 12), ++ PWM_DIV128 = (0x7 << 12), ++}; ++ ++#define PWM_INT_ENABLE 1 ++#define PWM_INT_DISABLE 0 ++ ++struct rockchip_rc_dev { ++ struct rc_dev *rcdev; ++ struct gpio_desc *gpiod; ++ int irq; ++ struct device *pmdev; ++ struct pm_qos_request qos; ++ void __iomem *pwm_base; ++ int pwm_wake_irq; ++ int pwm_id; ++ bool use_shutdown_handler; // if true, installs a shutdown handler and triggers virtual poweroff ++ bool use_suspend_handler; // if true, virtual poweroff is used as suspend mode otherwise use as regular suspend ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pinctrl_state_default; ++ struct pinctrl_state *pinctrl_state_suspend; ++}; ++ ++static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, ++ unsigned long arg0, ++ unsigned long arg1, ++ unsigned long arg2) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); ++ ++ return res; ++} ++ ++int sip_smc_remotectl_config(u32 func, u32 data) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0); ++ ++ return res.a0; ++} ++ ++int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); ++ return res.a0; ++} ++ ++int sip_smc_virtual_poweroff(void) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0); ++ return res.a0; ++} ++ ++static irqreturn_t rockchip_ir_recv_irq(int irq, void *dev_id) ++{ ++ int val; ++ struct rockchip_rc_dev *gpio_dev = dev_id; ++ struct device *pmdev = gpio_dev->pmdev; ++ ++ /* ++ * For some cpuidle systems, not all: ++ * Respond to interrupt taking more latency when cpu in idle. ++ * Invoke asynchronous pm runtime get from interrupt context, ++ * this may introduce a millisecond delay to call resume callback, ++ * where to disable cpuilde. ++ * ++ * Two issues lead to fail to decode first frame, one is latency to ++ * respond to interrupt, another is delay introduced by async api. ++ */ ++ if (pmdev) ++ pm_runtime_get(pmdev); ++ ++ val = gpiod_get_value(gpio_dev->gpiod); ++ if (val >= 0) ++ ir_raw_event_store_edge(gpio_dev->rcdev, val == 1); ++ ++ if (pmdev) { ++ pm_runtime_mark_last_busy(pmdev); ++ pm_runtime_put_autosuspend(pmdev); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void rockchip_pwm_int_ctrl(struct rockchip_rc_dev *gpio_dev, bool enable) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ struct device *dev = &gpio_dev->rcdev->dev; ++ int pwm_id = gpio_dev->pwm_id; ++ ++ void __iomem *reg_int_ctrl; ++ int val; ++ ++ reg_int_ctrl= pwm_base - (0x10 * pwm_id) + PWM_REG_INT_EN; ++ ++ val = readl_relaxed(reg_int_ctrl); ++ ++ if (enable) { ++ val |= PWM_CH_INT_ENABLE(pwm_id); ++ dev_info(dev, "PWM interrupt enabled, register value %x\n", val); ++ } else { ++ val &= ~PWM_CH_INT_ENABLE(pwm_id); ++ dev_info(dev, "PWM interrupt disabled, register value %x\n", val); ++ } ++ ++ writel_relaxed(val, reg_int_ctrl); ++ ++} ++ ++static int rockchip_pwm_hw_init(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ int val; ++ ++ //1. disabled pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_DISABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //2. capture mode ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //set clk div, clk div to 64 ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFF0001FF) | PWM_DIV64; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //4. enabled pwm int ++ rockchip_pwm_int_ctrl(gpio_dev, true); ++ ++ //5. enabled pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_ENABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ return 0; ++ ++} ++ ++static int rockchip_pwm_hw_stop(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ int val; ++ ++ //disable pwm interrupt ++ rockchip_pwm_int_ctrl(gpio_dev, false); ++ ++ //disable pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_DISABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ return 0; ++ ++} ++ ++static int rockchip_pwm_sip_wakeup_init(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ struct device *dev = &gpio_dev->rcdev->dev; ++ ++ struct irq_data *irq_data; ++ long hwirq; ++ int ret; ++ ++ irq_data = irq_get_irq_data(gpio_dev->pwm_wake_irq); ++ if (!irq_data) { ++ dev_err(dev, "could not get irq data\n"); ++ return -1; ++ } ++ ++ hwirq = irq_data->hwirq; ++ dev_info(dev, "use hwirq %ld, pwm chip id %d for PWM SIP wakeup\n", hwirq, gpio_dev->pwm_id); ++ ++ ret = 0; ++ ++ ret |= sip_smc_remotectl_config(REMOTECTL_SET_IRQ, (int)hwirq); ++ ret |= sip_smc_remotectl_config(REMOTECTL_SET_PWM_CH, gpio_dev->pwm_id); ++ ret |= sip_smc_remotectl_config(REMOTECTL_ENABLE, 1); ++ ++ if (ret) { ++ dev_err(dev, "SIP remote controller mode, TEE does not support feature\n"); ++ return ret; ++ } ++ ++ sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, 0x10042, 0); ++ sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, 0x0, 0); ++ sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG, 0x0, 0); ++ //sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, gpio_temp[i]); ++ sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE, 0x1, 0); ++ sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG, 0x0, 0); ++ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1); ++ ++ dev_info(dev, "TEE remote controller wakeup installed\n"); ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_remove(struct platform_device *pdev) ++{ ++ struct rockchip_rc_dev *gpio_dev = platform_get_drvdata(pdev); ++ struct device *pmdev = gpio_dev->pmdev; ++ ++ if (pmdev) { ++ pm_runtime_get_sync(pmdev); ++ cpu_latency_qos_remove_request(&gpio_dev->qos); ++ ++ pm_runtime_disable(pmdev); ++ pm_runtime_put_noidle(pmdev); ++ pm_runtime_set_suspended(pmdev); ++ } ++ ++ // Disable the remote controller handling of the Trust OS ++ sip_smc_remotectl_config(REMOTECTL_ENABLE, 0); ++ ++ // Disable the virtual poweroff of the Trust OS ++ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 0); ++ ++ return 0; ++} ++ ++static int rockchip_ir_register_power_key(struct device *dev) ++{ ++ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ struct rc_map *key_map; ++ struct rc_map_table *key; ++ int idx, scancode; ++ ++ key_map = &gpio_dev->rcdev->rc_map; ++ ++ dev_info(dev, "remote key table %s, key map of %d items\n", key_map->name, key_map->len); ++ ++ for (idx = 0; idx < key_map->len; idx++) { ++ ++ key = &key_map->scan[idx]; ++ ++ if (key->keycode != KEY_POWER) ++ continue; ++ ++ scancode = ((key->scancode & 0xff0000) >> 8) | ((key->scancode & 0xff00) << 8); ++ scancode |= (~key->scancode) & 0xff; ++ scancode <<= 8; ++ ++ sip_smc_remotectl_config(REMOTECTL_SET_PWRKEY, scancode); ++ ++ dev_info(dev, "registered scancode %08llx (SIP: %8x)\n", key->scancode, scancode); ++ ++ } ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_suspend_prepare(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ dev_info(dev, "initialize rockchip SIP virtual poweroff\n"); ++ ret = rockchip_pwm_sip_wakeup_init(gpio_dev); ++ ++ if (ret) ++ return ret; ++ ++ rockchip_ir_register_power_key(dev); ++ ++ disable_irq(gpio_dev->irq); ++ dev_info(dev, "GPIO IRQ disabled\n"); ++ ++ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_suspend); ++ if (ret) { ++ dev_err(dev, "unable to set pin in PWM mode\n"); ++ return ret; ++ } ++ ++ dev_info(dev, "set pin configuration to PWM mode\n"); ++ ++ rockchip_pwm_hw_init(gpio_dev); ++ dev_info(dev, "started pin PWM mode\n"); ++ ++ return 0; ++ ++} ++ ++#ifdef CONFIG_PM ++static int rockchip_ir_recv_suspend(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ /* ++ * if property suspend-is-virtual-poweroff is set, we can disable ++ * the regular gpio wakeup and enable the PWM mode for the Trust OS ++ * to take control and react to remote control. ++ * If the property is not set, we instead enable the wake up for the ++ * regular gpio. ++ */ ++ if (gpio_dev->use_suspend_handler) { ++ ++ rockchip_ir_recv_suspend_prepare(dev); ++ ++ } else { ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(gpio_dev->irq); ++ else ++ disable_irq(gpio_dev->irq); ++ ++ } ++ ++ return 0; ++} ++ ++static int rockchip_ir_recv_resume(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ /* ++ * In case suspend-is-virtual-poweroff property is set, ++ * restore the pin from PWM mode to regular GPIO configuration ++ * and stop the PWM function. ++ * Otherwise, just enable the regular GPIO irq ++ */ ++ if (gpio_dev->use_suspend_handler) { ++ ++ rockchip_pwm_hw_stop(gpio_dev); ++ dev_info(dev, "stopped pin PWM mode\n"); ++ ++ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_default); ++ if (ret) { ++ dev_err(dev, "unable to restore pin in GPIO mode\n"); ++ return ret; ++ } ++ dev_info(dev, "restored pin configuration di GPIO\n"); ++ ++ enable_irq(gpio_dev->irq); ++ dev_info(dev, "restored GPIO IRQ\n"); ++ ++ } else { ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(gpio_dev->irq); ++ else ++ enable_irq(gpio_dev->irq); ++ ++ } ++ ++ return 0; ++} ++ ++static void rockchip_ir_recv_shutdown(struct platform_device *pdev) ++{ ++ ++ struct device *dev = &pdev->dev; ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ if (gpio_dev->use_shutdown_handler) ++ rockchip_ir_recv_suspend_prepare(dev); ++ ++ return; ++ ++} ++ ++static int rockchip_ir_recv_sys_off(struct sys_off_data *data) ++{ ++ ++ sip_smc_virtual_poweroff(); ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_init_sip(void) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2, SECURE_REG_WR, 0, 0, 0, 0, 0, &res); ++ ++ if (res.a0) ++ return 0; ++ ++ return res.a1; ++ ++} ++ ++static int rockchip_ir_recv_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rockchip_rc_dev *gpio_dev; ++ struct rc_dev *rcdev; ++ struct clk *clk; ++ struct clk *p_clk; ++ struct resource *res; ++ u32 period = 0; ++ int rc; ++ int ret; ++ int pwm_wake_irq; ++ int clocks; ++ ++ if (!np) ++ return -ENODEV; ++ ++ gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL); ++ if (!gpio_dev) ++ return -ENOMEM; ++ ++ gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN); ++ if (IS_ERR(gpio_dev->gpiod)) { ++ rc = PTR_ERR(gpio_dev->gpiod); ++ /* Just try again if this happens */ ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "error getting gpio (%d)\n", rc); ++ return rc; ++ } ++ gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod); ++ if (gpio_dev->irq < 0) ++ return gpio_dev->irq; ++ ++ rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); ++ if (!rcdev) ++ return -ENOMEM; ++ ++ rcdev->priv = gpio_dev; ++ rcdev->device_name = ROCKCHIP_IR_DEVICE_NAME; ++ rcdev->input_phys = ROCKCHIP_IR_DEVICE_NAME "/input0"; ++ rcdev->input_id.bustype = BUS_HOST; ++ rcdev->input_id.vendor = 0x0001; ++ rcdev->input_id.product = 0x0001; ++ rcdev->input_id.version = 0x0100; ++ rcdev->dev.parent = dev; ++ rcdev->driver_name = KBUILD_MODNAME; ++ rcdev->min_timeout = 1; ++ rcdev->timeout = IR_DEFAULT_TIMEOUT; ++ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ++ rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ++ rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL); ++ if (!rcdev->map_name) ++ rcdev->map_name = RC_MAP_EMPTY; ++ ++ gpio_dev->rcdev = rcdev; ++ if (of_property_read_bool(np, "wakeup-source")) { ++ ++ ret = device_init_wakeup(dev, true); ++ ++ if (ret) ++ dev_err(dev, "could not init wakeup device\n"); ++ ++ } ++ ++ rc = devm_rc_register_device(dev, rcdev); ++ if (rc < 0) { ++ dev_err(dev, "failed to register rc device (%d)\n", rc); ++ return rc; ++ } ++ ++ of_property_read_u32(np, "linux,autosuspend-period", &period); ++ if (period) { ++ gpio_dev->pmdev = dev; ++ pm_runtime_set_autosuspend_delay(dev, period); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_enable(dev); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(dev, "no memory resources defined\n"); ++ return -ENODEV; ++ } ++ ++ gpio_dev->pwm_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(gpio_dev->pwm_base)) ++ return PTR_ERR(gpio_dev->pwm_base); ++ ++ clocks = of_property_count_strings(np, "clock-names"); ++ if (clocks == 2) { ++ clk = devm_clk_get(dev, "pwm"); ++ p_clk = devm_clk_get(dev, "pclk"); ++ } else { ++ clk = devm_clk_get(dev, NULL); ++ p_clk = clk; ++ } ++ ++ if (IS_ERR(clk)) { ++ ret = PTR_ERR(clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Can't get bus clock: %d\n", ret); ++ return ret; ++ } ++ ++ if (IS_ERR(p_clk)) { ++ ret = PTR_ERR(p_clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Can't get peripheral clock: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(clk); ++ if (ret) { ++ dev_err(dev, "Can't enable bus clk: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(p_clk); ++ if (ret) { ++ dev_err(dev, "Can't enable peripheral clk: %d\n", ret); ++ goto error_clk; ++ } ++ ++ pwm_wake_irq = platform_get_irq(pdev, 0); ++ if (pwm_wake_irq < 0) { ++ dev_err(&pdev->dev, "cannot find PWM wake interrupt\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pwm_wake_irq = pwm_wake_irq; ++ ret = enable_irq_wake(pwm_wake_irq); ++ if (ret) { ++ dev_err(dev, "could not enable IRQ wakeup\n"); ++ } ++ ++ ret = of_property_read_u32(np, "pwm-id", &gpio_dev->pwm_id); ++ if (ret) { ++ dev_err(dev, "missing pwm-id property\n"); ++ goto error_pclk; ++ } ++ ++ if (gpio_dev->pwm_id > 3) { ++ dev_err(dev, "invalid pwm-id property\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->use_shutdown_handler = of_property_read_bool(np, "shutdown-is-virtual-poweroff"); ++ gpio_dev->use_suspend_handler = of_property_read_bool(np, "suspend-is-virtual-poweroff"); ++ ++ gpio_dev->pinctrl = devm_pinctrl_get(dev); ++ if (IS_ERR(gpio_dev->pinctrl)) { ++ dev_err(dev, "Unable to get pinctrl\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pinctrl_state_default = pinctrl_lookup_state(gpio_dev->pinctrl, "default"); ++ if (IS_ERR(gpio_dev->pinctrl_state_default)) { ++ dev_err(dev, "Unable to get default pinctrl state\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pinctrl_state_suspend = pinctrl_lookup_state(gpio_dev->pinctrl, "suspend"); ++ if (IS_ERR(gpio_dev->pinctrl_state_suspend)) { ++ dev_err(dev, "Unable to get suspend pinctrl state\n"); ++ goto error_pclk; ++ } ++ ++ platform_set_drvdata(pdev, gpio_dev); ++ ++ ret = devm_request_irq(dev, gpio_dev->irq, rockchip_ir_recv_irq, ++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, ++ "gpio-ir-recv-irq", gpio_dev); ++ if (ret) { ++ dev_err(dev, "Can't request GPIO interrupt\n"); ++ goto error_pclk; ++ } ++ ++ if (gpio_dev->use_shutdown_handler) { ++ ++ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, ++ SYS_OFF_PRIO_FIRMWARE, rockchip_ir_recv_sys_off, NULL); ++ ++ if (ret) ++ dev_err(dev, "could not register sys_off handler\n"); ++ ++ } ++ ++ ret = rockchip_ir_recv_init_sip(); ++ if (!ret) { ++ dev_err(dev, "Unable to initialize Rockchip SIP v2, virtual poweroff unavailable\n"); ++ gpio_dev->use_shutdown_handler = false; ++ gpio_dev->use_suspend_handler = false; ++ } else { ++ dev_info(dev, "rockchip SIP initialized, version 0x%x\n", ret); ++ } ++ ++ return 0; ++ ++error_pclk: ++ clk_unprepare(p_clk); ++error_clk: ++ clk_unprepare(clk); ++ ++ return -ENODEV; ++ ++} ++ ++static const struct dev_pm_ops rockchip_ir_recv_pm_ops = { ++ .suspend = rockchip_ir_recv_suspend, ++ .resume = rockchip_ir_recv_resume, ++}; ++#endif ++ ++static const struct of_device_id rockchip_ir_recv_of_match[] = { ++ { .compatible = "rockchip-ir", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_ir_recv_of_match); ++ ++static struct platform_driver rockchip_ir_recv_driver = { ++ .probe = rockchip_ir_recv_probe, ++ .remove = rockchip_ir_recv_remove, ++ .shutdown = rockchip_ir_recv_shutdown, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(rockchip_ir_recv_of_match), ++#ifdef CONFIG_PM ++ .pm = &rockchip_ir_recv_pm_ops, ++#endif ++ }, ++}; ++module_platform_driver(rockchip_ir_recv_driver); ++ ++MODULE_DESCRIPTION("Rockchip IR Receiver driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.34.1 + diff --git a/patch/kernel/archive/rk322x-6.1/overlay/Makefile b/patch/kernel/archive/rk322x-6.1/overlay/Makefile index 727c079b15..44ac4d36b7 100755 --- a/patch/kernel/archive/rk322x-6.1/overlay/Makefile +++ b/patch/kernel/archive/rk322x-6.1/overlay/Makefile @@ -14,11 +14,12 @@ dtbo-$(CONFIG_ARCH_ROCKCHIP) += \ rk322x-led-conf5.dtbo \ rk322x-led-conf6.dtbo \ rk322x-led-conf7.dtbo \ - rk322x-led-conf8.dtbo \ + rk322x-led-conf8.dtbo \ rk322x-cpu-hs.dtbo \ rk322x-cpu-hs-lv.dtbo \ rk322x-wlan-alt-wiring.dtbo \ rk322x-cpu-stability.dtbo \ + rk322x-ir-wakeup.dtbo \ rk322x-ddr3-330.dtbo \ rk322x-ddr3-528.dtbo \ rk322x-ddr3-660.dtbo \ diff --git a/patch/kernel/archive/rk322x-6.1/overlay/README.rk322x-overlays b/patch/kernel/archive/rk322x-6.1/overlay/README.rk322x-overlays index 7da47f44b5..3a683edb40 100755 --- a/patch/kernel/archive/rk322x-6.1/overlay/README.rk322x-overlays +++ b/patch/kernel/archive/rk322x-6.1/overlay/README.rk322x-overlays @@ -18,6 +18,7 @@ rk322x (Rockchip) - rk322x-ddr3-* - rk322x-bt-* - rk322x-usb-otg-peripheral +- rk322x-ir-wakeup ### Overlay details: @@ -89,3 +90,10 @@ rk322x-bt-8723cs: enable this overlay for 8723cs and 8703bs wifi/bluetooth Set the OTG USB port to peripheral mode to be used as USB slave instead of USB host + +### rk322x-ir-wakeup + +Enable the rockchip-ir-driver in place of the standard gpio-ir-receiver. +The rockchip-specific driver exploits the Trust OS and Virtual Poweroff mode +to allow power up via remote controller power button. + diff --git a/patch/kernel/archive/rk322x-6.1/overlay/rk322x-ir-wakeup.dts b/patch/kernel/archive/rk322x-6.1/overlay/rk322x-ir-wakeup.dts new file mode 100644 index 0000000000..f479a1e28d --- /dev/null +++ b/patch/kernel/archive/rk322x-6.1/overlay/rk322x-ir-wakeup.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +/* + * Disable regular gpio-ir-receiver and enable + * rockchip-ir-receiver driver; also enables virtual + * poweroff on shutdown to allow restart with power key + * on remote controller + */ +&ir_receiver { + status = "disabled"; +}; + +&rockchip_ir_receiver { + status = "okay"; +}; diff --git a/patch/kernel/archive/rk322x-6.5/dt/rk322x-box.dts b/patch/kernel/archive/rk322x-6.5/dt/rk322x-box.dts index 312e5854a3..ddc25ec77f 100644 --- a/patch/kernel/archive/rk322x-6.5/dt/rk322x-box.dts +++ b/patch/kernel/archive/rk322x-6.5/dt/rk322x-box.dts @@ -119,6 +119,22 @@ linux,rc-map-name = "rc-rk322x-tvbox"; }; + rockchip_ir_receiver: rockchip-ir-receiver { + compatible = "rockchip-ir-receiver"; + reg = <0x110b0030 0x10>; + gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; + clocks = <&cru PCLK_PWM>; + interrupts = ; + linux,rc-map-name = "rc-rk322x-tvbox"; + pinctrl-names = "default", "suspend"; + pinctrl-0 = <&ir_int>; + pinctrl-1 = <&pwm3_pin>; + pwm-id = <3>; + shutdown-is-virtual-poweroff; + wakeup-source; + status = "disabled"; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; pinctrl-names = "default"; @@ -735,14 +751,14 @@ rockchip,hw-tshut-mode = <0>; rockchip,hw-tshut-polarity = <1>; rockchip,hw-tshut-temp = <110000>; - + /* delete the pinctrl-* properties because, on mainline kernel, they (in particular "default") change the GPIO configuration of the associated PIN. On most boards that pin is not connected so it does not do anything, but some other boards (X96-Mini) have that pin connected to - a reset pin of the soc or whatever, thus changing the configuration of the pin at boot + a reset pin of the soc or whatever, thus changing the configuration of the pin at boot causes them to bootloop. We don't really need these ones though, because since hw-tshut-mode is set to 0, the CRU - unit of the SoC does the reboot*/ + unit of the SoC does the reboot*/ /delete-property/ pinctrl-names; /delete-property/ pinctrl-0; /delete-property/ pinctrl-1; diff --git a/patch/kernel/archive/rk322x-6.5/general-rk322x-gpio-ir-driver.patch b/patch/kernel/archive/rk322x-6.5/general-rk322x-gpio-ir-driver.patch new file mode 100644 index 0000000000..25645bad32 --- /dev/null +++ b/patch/kernel/archive/rk322x-6.5/general-rk322x-gpio-ir-driver.patch @@ -0,0 +1,778 @@ +From 13498feb91614d59ebece61d0c278e31529bb8c8 Mon Sep 17 00:00:00 2001 +From: Paolo Sabatino +Date: Tue, 10 Oct 2023 21:54:51 +0200 +Subject: [PATCH] rockchip gpio IR driver + +--- + drivers/media/rc/Kconfig | 11 + + drivers/media/rc/Makefile | 1 + + drivers/media/rc/rockchip-ir.c | 723 +++++++++++++++++++++++++++++++++ + 3 files changed, 735 insertions(+) + create mode 100644 drivers/media/rc/rockchip-ir.c + +diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig +index f560fc38895f..b77fa83e90e8 100644 +--- a/drivers/media/rc/Kconfig ++++ b/drivers/media/rc/Kconfig +@@ -333,6 +333,17 @@ config IR_REDRAT3 + To compile this driver as a module, choose M here: the + module will be called redrat3. + ++config IR_ROCKCHIP_CIR ++ tristate "Rockchip GPIO IR receiver" ++ depends on (OF && GPIOLIB) || COMPILE_TEST ++ help ++ Say Y here if you want to use the Rockchip IR receiver with ++ virtual poweroff features provided by rockchip Trust OS ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rockchip-ir ++ ++ + config IR_RX51 + tristate "Nokia N900 IR transmitter diode" + depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE +diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile +index a9285266e944..057d5b64c121 100644 +--- a/drivers/media/rc/Makefile ++++ b/drivers/media/rc/Makefile +@@ -43,6 +43,7 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o + obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o + obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o + obj-$(CONFIG_IR_REDRAT3) += redrat3.o ++obj-$(CONFIG_IR_ROCKCHIP_CIR) += rockchip-ir.o + obj-$(CONFIG_IR_RX51) += ir-rx51.o + obj-$(CONFIG_IR_SERIAL) += serial_ir.o + obj-$(CONFIG_IR_SPI) += ir-spi.o +diff --git a/drivers/media/rc/rockchip-ir.c b/drivers/media/rc/rockchip-ir.c +new file mode 100644 +index 000000000000..06c483cd8d5b +--- /dev/null ++++ b/drivers/media/rc/rockchip-ir.c +@@ -0,0 +1,723 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ROCKCHIP_IR_DEVICE_NAME "rockchip_ir_recv" ++ ++#ifdef CONFIG_64BIT ++#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name ++#else ++#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name ++#endif ++ ++/* ++* SIP/TEE constants for remote calls ++*/ ++#define SIP_REMOTECTL_CFG 0x8200000b ++#define SIP_SUSPEND_MODE 0x82000003 ++#define SIP_REMOTECTL_CFG 0x8200000b ++#define SUSPEND_MODE_CONFIG 0x01 ++#define WKUP_SOURCE_CONFIG 0x02 ++#define PWM_REGULATOR_CONFIG 0x03 ++#define GPIO_POWER_CONFIG 0x04 ++#define SUSPEND_DEBUG_ENABLE 0x05 ++#define APIOS_SUSPEND_CONFIG 0x06 ++#define VIRTUAL_POWEROFF 0x07 ++ ++#define REMOTECTL_SET_IRQ 0xf0 ++#define REMOTECTL_SET_PWM_CH 0xf1 ++#define REMOTECTL_SET_PWRKEY 0xf2 ++#define REMOTECTL_GET_WAKEUP_STATE 0xf3 ++#define REMOTECTL_ENABLE 0xf4 ++#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf /* wakeup state */ ++ ++/* ++* PWM Registers ++* Each PWM has its own control registers ++*/ ++#define PWM_REG_CNTR 0x00 /* Counter Register */ ++#define PWM_REG_HPR 0x04 /* Period Register */ ++#define PWM_REG_LPR 0x08 /* Duty Cycle Register */ ++#define PWM_REG_CTRL 0x0c /* Control Register */ ++ ++/* ++* PWM General registers ++* Registers shared among PWMs ++*/ ++#define PWM_REG_INT_EN 0x44 ++ ++/*REG_CTRL bits definitions*/ ++#define PWM_ENABLE (1 << 0) ++#define PWM_DISABLE (0 << 0) ++ ++/*operation mode*/ ++#define PWM_MODE_ONESHOT (0x00 << 1) ++#define PWM_MODE_CONTINUMOUS (0x01 << 1) ++#define PWM_MODE_CAPTURE (0x02 << 1) ++ ++/* Channel interrupt enable bit */ ++#define PWM_CH_INT_ENABLE(n) BIT(n) ++ ++enum pwm_div { ++ PWM_DIV1 = (0x0 << 12), ++ PWM_DIV2 = (0x1 << 12), ++ PWM_DIV4 = (0x2 << 12), ++ PWM_DIV8 = (0x3 << 12), ++ PWM_DIV16 = (0x4 << 12), ++ PWM_DIV32 = (0x5 << 12), ++ PWM_DIV64 = (0x6 << 12), ++ PWM_DIV128 = (0x7 << 12), ++}; ++ ++#define PWM_INT_ENABLE 1 ++#define PWM_INT_DISABLE 0 ++ ++struct rockchip_rc_dev { ++ struct rc_dev *rcdev; ++ struct gpio_desc *gpiod; ++ int irq; ++ struct device *pmdev; ++ struct pm_qos_request qos; ++ void __iomem *pwm_base; ++ int pwm_wake_irq; ++ int pwm_id; ++ bool use_shutdown_handler; // if true, installs a shutdown handler and triggers virtual poweroff ++ bool use_suspend_handler; // if true, virtual poweroff is used as suspend mode otherwise use as regular suspend ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pinctrl_state_default; ++ struct pinctrl_state *pinctrl_state_suspend; ++}; ++ ++static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, ++ unsigned long arg0, ++ unsigned long arg1, ++ unsigned long arg2) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); ++ ++ return res; ++} ++ ++int sip_smc_remotectl_config(u32 func, u32 data) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0); ++ ++ return res.a0; ++} ++ ++int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); ++ return res.a0; ++} ++ ++int sip_smc_virtual_poweroff(void) ++{ ++ struct arm_smccc_res res; ++ ++ res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0); ++ return res.a0; ++} ++ ++static irqreturn_t rockchip_ir_recv_irq(int irq, void *dev_id) ++{ ++ int val; ++ struct rockchip_rc_dev *gpio_dev = dev_id; ++ struct device *pmdev = gpio_dev->pmdev; ++ ++ /* ++ * For some cpuidle systems, not all: ++ * Respond to interrupt taking more latency when cpu in idle. ++ * Invoke asynchronous pm runtime get from interrupt context, ++ * this may introduce a millisecond delay to call resume callback, ++ * where to disable cpuilde. ++ * ++ * Two issues lead to fail to decode first frame, one is latency to ++ * respond to interrupt, another is delay introduced by async api. ++ */ ++ if (pmdev) ++ pm_runtime_get(pmdev); ++ ++ val = gpiod_get_value(gpio_dev->gpiod); ++ if (val >= 0) ++ ir_raw_event_store_edge(gpio_dev->rcdev, val == 1); ++ ++ if (pmdev) { ++ pm_runtime_mark_last_busy(pmdev); ++ pm_runtime_put_autosuspend(pmdev); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void rockchip_pwm_int_ctrl(struct rockchip_rc_dev *gpio_dev, bool enable) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ struct device *dev = &gpio_dev->rcdev->dev; ++ int pwm_id = gpio_dev->pwm_id; ++ ++ void __iomem *reg_int_ctrl; ++ int val; ++ ++ reg_int_ctrl= pwm_base - (0x10 * pwm_id) + PWM_REG_INT_EN; ++ ++ val = readl_relaxed(reg_int_ctrl); ++ ++ if (enable) { ++ val |= PWM_CH_INT_ENABLE(pwm_id); ++ dev_info(dev, "PWM interrupt enabled, register value %x\n", val); ++ } else { ++ val &= ~PWM_CH_INT_ENABLE(pwm_id); ++ dev_info(dev, "PWM interrupt disabled, register value %x\n", val); ++ } ++ ++ writel_relaxed(val, reg_int_ctrl); ++ ++} ++ ++static int rockchip_pwm_hw_init(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ int val; ++ ++ //1. disabled pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_DISABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //2. capture mode ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //set clk div, clk div to 64 ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFF0001FF) | PWM_DIV64; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ //4. enabled pwm int ++ rockchip_pwm_int_ctrl(gpio_dev, true); ++ ++ //5. enabled pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_ENABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ return 0; ++ ++} ++ ++static int rockchip_pwm_hw_stop(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ void __iomem *pwm_base = gpio_dev->pwm_base; ++ int val; ++ ++ //disable pwm interrupt ++ rockchip_pwm_int_ctrl(gpio_dev, false); ++ ++ //disable pwm ++ val = readl_relaxed(pwm_base + PWM_REG_CTRL); ++ val = (val & 0xFFFFFFFE) | PWM_DISABLE; ++ writel_relaxed(val, pwm_base + PWM_REG_CTRL); ++ ++ return 0; ++ ++} ++ ++static int rockchip_pwm_sip_wakeup_init(struct rockchip_rc_dev *gpio_dev) ++{ ++ ++ struct device *dev = &gpio_dev->rcdev->dev; ++ ++ struct irq_data *irq_data; ++ long hwirq; ++ int ret; ++ ++ irq_data = irq_get_irq_data(gpio_dev->pwm_wake_irq); ++ if (!irq_data) { ++ dev_err(dev, "could not get irq data\n"); ++ return -1; ++ } ++ ++ hwirq = irq_data->hwirq; ++ dev_info(dev, "use hwirq %ld, pwm chip id %d for PWM SIP wakeup\n", hwirq, gpio_dev->pwm_id); ++ ++ ret = 0; ++ ++ ret |= sip_smc_remotectl_config(REMOTECTL_SET_IRQ, (int)hwirq); ++ ret |= sip_smc_remotectl_config(REMOTECTL_SET_PWM_CH, gpio_dev->pwm_id); ++ ret |= sip_smc_remotectl_config(REMOTECTL_ENABLE, 1); ++ ++ if (ret) { ++ dev_err(dev, "SIP remote controller mode, TEE does not support feature\n"); ++ return ret; ++ } ++ ++ sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, 0x10042, 0); ++ sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, 0x0, 0); ++ sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG, 0x0, 0); ++ //sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, gpio_temp[i]); ++ sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE, 0x1, 0); ++ sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG, 0x0, 0); ++ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1); ++ ++ dev_info(dev, "TEE remote controller wakeup installed\n"); ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_remove(struct platform_device *pdev) ++{ ++ struct rockchip_rc_dev *gpio_dev = platform_get_drvdata(pdev); ++ struct device *pmdev = gpio_dev->pmdev; ++ ++ if (pmdev) { ++ pm_runtime_get_sync(pmdev); ++ cpu_latency_qos_remove_request(&gpio_dev->qos); ++ ++ pm_runtime_disable(pmdev); ++ pm_runtime_put_noidle(pmdev); ++ pm_runtime_set_suspended(pmdev); ++ } ++ ++ // Disable the remote controller handling of the Trust OS ++ sip_smc_remotectl_config(REMOTECTL_ENABLE, 0); ++ ++ // Disable the virtual poweroff of the Trust OS ++ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 0); ++ ++ return 0; ++} ++ ++static int rockchip_ir_register_power_key(struct device *dev) ++{ ++ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ struct rc_map *key_map; ++ struct rc_map_table *key; ++ int idx, scancode; ++ ++ key_map = &gpio_dev->rcdev->rc_map; ++ ++ dev_info(dev, "remote key table %s, key map of %d items\n", key_map->name, key_map->len); ++ ++ for (idx = 0; idx < key_map->len; idx++) { ++ ++ key = &key_map->scan[idx]; ++ ++ if (key->keycode != KEY_POWER) ++ continue; ++ ++ scancode = ((key->scancode & 0xff0000) >> 8) | ((key->scancode & 0xff00) << 8); ++ scancode |= (~key->scancode) & 0xff; ++ scancode <<= 8; ++ ++ sip_smc_remotectl_config(REMOTECTL_SET_PWRKEY, scancode); ++ ++ dev_info(dev, "registered scancode %08llx (SIP: %8x)\n", key->scancode, scancode); ++ ++ } ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_suspend_prepare(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ dev_info(dev, "initialize rockchip SIP virtual poweroff\n"); ++ ret = rockchip_pwm_sip_wakeup_init(gpio_dev); ++ ++ if (ret) ++ return ret; ++ ++ rockchip_ir_register_power_key(dev); ++ ++ disable_irq(gpio_dev->irq); ++ dev_info(dev, "GPIO IRQ disabled\n"); ++ ++ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_suspend); ++ if (ret) { ++ dev_err(dev, "unable to set pin in PWM mode\n"); ++ return ret; ++ } ++ ++ dev_info(dev, "set pin configuration to PWM mode\n"); ++ ++ rockchip_pwm_hw_init(gpio_dev); ++ dev_info(dev, "started pin PWM mode\n"); ++ ++ return 0; ++ ++} ++ ++#ifdef CONFIG_PM ++static int rockchip_ir_recv_suspend(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ /* ++ * if property suspend-is-virtual-poweroff is set, we can disable ++ * the regular gpio wakeup and enable the PWM mode for the Trust OS ++ * to take control and react to remote control. ++ * If the property is not set, we instead enable the wake up for the ++ * regular gpio. ++ */ ++ if (gpio_dev->use_suspend_handler) { ++ ++ rockchip_ir_recv_suspend_prepare(dev); ++ ++ } else { ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(gpio_dev->irq); ++ else ++ disable_irq(gpio_dev->irq); ++ ++ } ++ ++ return 0; ++} ++ ++static int rockchip_ir_recv_resume(struct device *dev) ++{ ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ int ret; ++ ++ /* ++ * In case suspend-is-virtual-poweroff property is set, ++ * restore the pin from PWM mode to regular GPIO configuration ++ * and stop the PWM function. ++ * Otherwise, just enable the regular GPIO irq ++ */ ++ if (gpio_dev->use_suspend_handler) { ++ ++ rockchip_pwm_hw_stop(gpio_dev); ++ dev_info(dev, "stopped pin PWM mode\n"); ++ ++ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_default); ++ if (ret) { ++ dev_err(dev, "unable to restore pin in GPIO mode\n"); ++ return ret; ++ } ++ dev_info(dev, "restored pin configuration di GPIO\n"); ++ ++ enable_irq(gpio_dev->irq); ++ dev_info(dev, "restored GPIO IRQ\n"); ++ ++ } else { ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(gpio_dev->irq); ++ else ++ enable_irq(gpio_dev->irq); ++ ++ } ++ ++ return 0; ++} ++ ++static void rockchip_ir_recv_shutdown(struct platform_device *pdev) ++{ ++ ++ struct device *dev = &pdev->dev; ++ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev); ++ ++ if (gpio_dev->use_shutdown_handler) ++ rockchip_ir_recv_suspend_prepare(dev); ++ ++ return; ++ ++} ++ ++static int rockchip_ir_recv_sys_off(struct sys_off_data *data) ++{ ++ ++ sip_smc_virtual_poweroff(); ++ ++ return 0; ++ ++} ++ ++static int rockchip_ir_recv_init_sip(void) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2, SECURE_REG_WR, 0, 0, 0, 0, 0, &res); ++ ++ if (res.a0) ++ return 0; ++ ++ return res.a1; ++ ++} ++ ++static int rockchip_ir_recv_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rockchip_rc_dev *gpio_dev; ++ struct rc_dev *rcdev; ++ struct clk *clk; ++ struct clk *p_clk; ++ struct resource *res; ++ u32 period = 0; ++ int rc; ++ int ret; ++ int pwm_wake_irq; ++ int clocks; ++ ++ if (!np) ++ return -ENODEV; ++ ++ gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL); ++ if (!gpio_dev) ++ return -ENOMEM; ++ ++ gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN); ++ if (IS_ERR(gpio_dev->gpiod)) { ++ rc = PTR_ERR(gpio_dev->gpiod); ++ /* Just try again if this happens */ ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "error getting gpio (%d)\n", rc); ++ return rc; ++ } ++ gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod); ++ if (gpio_dev->irq < 0) ++ return gpio_dev->irq; ++ ++ rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); ++ if (!rcdev) ++ return -ENOMEM; ++ ++ rcdev->priv = gpio_dev; ++ rcdev->device_name = ROCKCHIP_IR_DEVICE_NAME; ++ rcdev->input_phys = ROCKCHIP_IR_DEVICE_NAME "/input0"; ++ rcdev->input_id.bustype = BUS_HOST; ++ rcdev->input_id.vendor = 0x0001; ++ rcdev->input_id.product = 0x0001; ++ rcdev->input_id.version = 0x0100; ++ rcdev->dev.parent = dev; ++ rcdev->driver_name = KBUILD_MODNAME; ++ rcdev->min_timeout = 1; ++ rcdev->timeout = IR_DEFAULT_TIMEOUT; ++ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ++ rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ++ rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL); ++ if (!rcdev->map_name) ++ rcdev->map_name = RC_MAP_EMPTY; ++ ++ gpio_dev->rcdev = rcdev; ++ if (of_property_read_bool(np, "wakeup-source")) { ++ ++ ret = device_init_wakeup(dev, true); ++ ++ if (ret) ++ dev_err(dev, "could not init wakeup device\n"); ++ ++ } ++ ++ rc = devm_rc_register_device(dev, rcdev); ++ if (rc < 0) { ++ dev_err(dev, "failed to register rc device (%d)\n", rc); ++ return rc; ++ } ++ ++ of_property_read_u32(np, "linux,autosuspend-period", &period); ++ if (period) { ++ gpio_dev->pmdev = dev; ++ pm_runtime_set_autosuspend_delay(dev, period); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_enable(dev); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(dev, "no memory resources defined\n"); ++ return -ENODEV; ++ } ++ ++ gpio_dev->pwm_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(gpio_dev->pwm_base)) ++ return PTR_ERR(gpio_dev->pwm_base); ++ ++ clocks = of_property_count_strings(np, "clock-names"); ++ if (clocks == 2) { ++ clk = devm_clk_get(dev, "pwm"); ++ p_clk = devm_clk_get(dev, "pclk"); ++ } else { ++ clk = devm_clk_get(dev, NULL); ++ p_clk = clk; ++ } ++ ++ if (IS_ERR(clk)) { ++ ret = PTR_ERR(clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Can't get bus clock: %d\n", ret); ++ return ret; ++ } ++ ++ if (IS_ERR(p_clk)) { ++ ret = PTR_ERR(p_clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Can't get peripheral clock: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(clk); ++ if (ret) { ++ dev_err(dev, "Can't enable bus clk: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(p_clk); ++ if (ret) { ++ dev_err(dev, "Can't enable peripheral clk: %d\n", ret); ++ goto error_clk; ++ } ++ ++ pwm_wake_irq = platform_get_irq(pdev, 0); ++ if (pwm_wake_irq < 0) { ++ dev_err(&pdev->dev, "cannot find PWM wake interrupt\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pwm_wake_irq = pwm_wake_irq; ++ ret = enable_irq_wake(pwm_wake_irq); ++ if (ret) { ++ dev_err(dev, "could not enable IRQ wakeup\n"); ++ } ++ ++ ret = of_property_read_u32(np, "pwm-id", &gpio_dev->pwm_id); ++ if (ret) { ++ dev_err(dev, "missing pwm-id property\n"); ++ goto error_pclk; ++ } ++ ++ if (gpio_dev->pwm_id > 3) { ++ dev_err(dev, "invalid pwm-id property\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->use_shutdown_handler = of_property_read_bool(np, "shutdown-is-virtual-poweroff"); ++ gpio_dev->use_suspend_handler = of_property_read_bool(np, "suspend-is-virtual-poweroff"); ++ ++ gpio_dev->pinctrl = devm_pinctrl_get(dev); ++ if (IS_ERR(gpio_dev->pinctrl)) { ++ dev_err(dev, "Unable to get pinctrl\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pinctrl_state_default = pinctrl_lookup_state(gpio_dev->pinctrl, "default"); ++ if (IS_ERR(gpio_dev->pinctrl_state_default)) { ++ dev_err(dev, "Unable to get default pinctrl state\n"); ++ goto error_pclk; ++ } ++ ++ gpio_dev->pinctrl_state_suspend = pinctrl_lookup_state(gpio_dev->pinctrl, "suspend"); ++ if (IS_ERR(gpio_dev->pinctrl_state_suspend)) { ++ dev_err(dev, "Unable to get suspend pinctrl state\n"); ++ goto error_pclk; ++ } ++ ++ platform_set_drvdata(pdev, gpio_dev); ++ ++ ret = devm_request_irq(dev, gpio_dev->irq, rockchip_ir_recv_irq, ++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, ++ "gpio-ir-recv-irq", gpio_dev); ++ if (ret) { ++ dev_err(dev, "Can't request GPIO interrupt\n"); ++ goto error_pclk; ++ } ++ ++ if (gpio_dev->use_shutdown_handler) { ++ ++ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, ++ SYS_OFF_PRIO_FIRMWARE, rockchip_ir_recv_sys_off, NULL); ++ ++ if (ret) ++ dev_err(dev, "could not register sys_off handler\n"); ++ ++ } ++ ++ ret = rockchip_ir_recv_init_sip(); ++ if (!ret) { ++ dev_err(dev, "Unable to initialize Rockchip SIP v2, virtual poweroff unavailable\n"); ++ gpio_dev->use_shutdown_handler = false; ++ gpio_dev->use_suspend_handler = false; ++ } else { ++ dev_info(dev, "rockchip SIP initialized, version 0x%x\n", ret); ++ } ++ ++ return 0; ++ ++error_pclk: ++ clk_unprepare(p_clk); ++error_clk: ++ clk_unprepare(clk); ++ ++ return -ENODEV; ++ ++} ++ ++static const struct dev_pm_ops rockchip_ir_recv_pm_ops = { ++ .suspend = rockchip_ir_recv_suspend, ++ .resume = rockchip_ir_recv_resume, ++}; ++#endif ++ ++static const struct of_device_id rockchip_ir_recv_of_match[] = { ++ { .compatible = "rockchip-ir", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_ir_recv_of_match); ++ ++static struct platform_driver rockchip_ir_recv_driver = { ++ .probe = rockchip_ir_recv_probe, ++ .remove = rockchip_ir_recv_remove, ++ .shutdown = rockchip_ir_recv_shutdown, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(rockchip_ir_recv_of_match), ++#ifdef CONFIG_PM ++ .pm = &rockchip_ir_recv_pm_ops, ++#endif ++ }, ++}; ++module_platform_driver(rockchip_ir_recv_driver); ++ ++MODULE_DESCRIPTION("Rockchip IR Receiver driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.34.1 + diff --git a/patch/kernel/archive/rk322x-6.5/overlay/Makefile b/patch/kernel/archive/rk322x-6.5/overlay/Makefile index 727c079b15..e0bd24c35b 100755 --- a/patch/kernel/archive/rk322x-6.5/overlay/Makefile +++ b/patch/kernel/archive/rk322x-6.5/overlay/Makefile @@ -19,6 +19,7 @@ dtbo-$(CONFIG_ARCH_ROCKCHIP) += \ rk322x-cpu-hs-lv.dtbo \ rk322x-wlan-alt-wiring.dtbo \ rk322x-cpu-stability.dtbo \ + rk322x-ir-wakeup.dtbo \ rk322x-ddr3-330.dtbo \ rk322x-ddr3-528.dtbo \ rk322x-ddr3-660.dtbo \ diff --git a/patch/kernel/archive/rk322x-6.5/overlay/README.rk322x-overlays b/patch/kernel/archive/rk322x-6.5/overlay/README.rk322x-overlays index 7da47f44b5..1d36d17174 100755 --- a/patch/kernel/archive/rk322x-6.5/overlay/README.rk322x-overlays +++ b/patch/kernel/archive/rk322x-6.5/overlay/README.rk322x-overlays @@ -18,6 +18,7 @@ rk322x (Rockchip) - rk322x-ddr3-* - rk322x-bt-* - rk322x-usb-otg-peripheral +- rk322x-ir-wakeup ### Overlay details: @@ -89,3 +90,9 @@ rk322x-bt-8723cs: enable this overlay for 8723cs and 8703bs wifi/bluetooth Set the OTG USB port to peripheral mode to be used as USB slave instead of USB host + +### rk322x-ir-wakeup + +Enable the rockchip-ir-driver in place of the standard gpio-ir-receiver. +The rockchip-specific driver exploits the Trust OS and Virtual Poweroff mode +to allow power up via remote controller power button. diff --git a/patch/kernel/archive/rk322x-6.5/overlay/rk322x-ir-wakeup.dts b/patch/kernel/archive/rk322x-6.5/overlay/rk322x-ir-wakeup.dts new file mode 100644 index 0000000000..f479a1e28d --- /dev/null +++ b/patch/kernel/archive/rk322x-6.5/overlay/rk322x-ir-wakeup.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +/* + * Disable regular gpio-ir-receiver and enable + * rockchip-ir-receiver driver; also enables virtual + * poweroff on shutdown to allow restart with power key + * on remote controller + */ +&ir_receiver { + status = "disabled"; +}; + +&rockchip_ir_receiver { + status = "okay"; +};